commit 0233cb6f4694cdea377f925fb9923cf10345f8b2 Author: gamer147 Date: Wed Apr 1 17:16:58 2026 -0400 Initial commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f28239b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0af181c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Godot 4+ specific ignores +.godot/ +/android/ diff --git a/assets/editor/unit_node.bmp b/assets/editor/unit_node.bmp new file mode 100644 index 0000000..584c3c5 Binary files /dev/null and b/assets/editor/unit_node.bmp differ diff --git a/assets/editor/unit_node.bmp.import b/assets/editor/unit_node.bmp.import new file mode 100644 index 0000000..7e63635 --- /dev/null +++ b/assets/editor/unit_node.bmp.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://kg0de6r1lsj0" +path="res://.godot/imported/unit_node.bmp-78f7ae8f67af3742e2be442acdff72e7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/editor/unit_node.bmp" +dest_files=["res://.godot/imported/unit_node.bmp-78f7ae8f67af3742e2be442acdff72e7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/editor/unit_node.png b/assets/editor/unit_node.png new file mode 100644 index 0000000..b0eeb49 Binary files /dev/null and b/assets/editor/unit_node.png differ diff --git a/assets/editor/unit_node.png.import b/assets/editor/unit_node.png.import new file mode 100644 index 0000000..212bbad --- /dev/null +++ b/assets/editor/unit_node.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dv8p38jv35ejg" +path="res://.godot/imported/unit_node.png-9b23e77b8d09018da177358cfa433365.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/editor/unit_node.png" +dest_files=["res://.godot/imported/unit_node.png-9b23e77b8d09018da177358cfa433365.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/fonts/Minecraft.ttf b/assets/fonts/Minecraft.ttf new file mode 100644 index 0000000..85c1472 Binary files /dev/null and b/assets/fonts/Minecraft.ttf differ diff --git a/assets/fonts/Minecraft.ttf.import b/assets/fonts/Minecraft.ttf.import new file mode 100644 index 0000000..5489c42 --- /dev/null +++ b/assets/fonts/Minecraft.ttf.import @@ -0,0 +1,36 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://eqhm6gv5p05t" +path="res://.godot/imported/Minecraft.ttf-e1845dfc080db589cd29d952a380f38e.fontdata" + +[deps] + +source_file="res://assets/fonts/Minecraft.ttf" +dest_files=["res://.godot/imported/Minecraft.ttf-e1845dfc080db589cd29d952a380f38e.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +modulate_color_glyphs=false +hinting=1 +subpixel_positioning=4 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/assets/music/combat_bgm_01.OGG b/assets/music/combat_bgm_01.OGG new file mode 100644 index 0000000..aa16087 Binary files /dev/null and b/assets/music/combat_bgm_01.OGG differ diff --git a/assets/music/combat_bgm_01.OGG.import b/assets/music/combat_bgm_01.OGG.import new file mode 100644 index 0000000..5dc56ea --- /dev/null +++ b/assets/music/combat_bgm_01.OGG.import @@ -0,0 +1,19 @@ +[remap] + +importer="oggvorbisstr" +type="AudioStreamOggVorbis" +uid="uid://dsikulned64qt" +path="res://.godot/imported/combat_bgm_01.OGG-6c9a537751cc7bec8580130b48af399c.oggvorbisstr" + +[deps] + +source_file="res://assets/music/combat_bgm_01.OGG" +dest_files=["res://.godot/imported/combat_bgm_01.OGG-6c9a537751cc7bec8580130b48af399c.oggvorbisstr"] + +[params] + +loop=true +loop_offset=0.0 +bpm=0.0 +beat_count=0 +bar_beats=4 diff --git a/assets/music/menu_theme.OGG b/assets/music/menu_theme.OGG new file mode 100644 index 0000000..723c3d7 Binary files /dev/null and b/assets/music/menu_theme.OGG differ diff --git a/assets/music/menu_theme.OGG.import b/assets/music/menu_theme.OGG.import new file mode 100644 index 0000000..bd7a4b4 --- /dev/null +++ b/assets/music/menu_theme.OGG.import @@ -0,0 +1,19 @@ +[remap] + +importer="oggvorbisstr" +type="AudioStreamOggVorbis" +uid="uid://b7dgmblbcm0cj" +path="res://.godot/imported/menu_theme.OGG-70a417a11ba25010cea8e5ee015ba9aa.oggvorbisstr" + +[deps] + +source_file="res://assets/music/menu_theme.OGG" +dest_files=["res://.godot/imported/menu_theme.OGG-70a417a11ba25010cea8e5ee015ba9aa.oggvorbisstr"] + +[params] + +loop=true +loop_offset=0 +bpm=0 +beat_count=0 +bar_beats=4 diff --git a/assets/sprites/castle_spritesheet.png b/assets/sprites/castle_spritesheet.png new file mode 100644 index 0000000..92fc2d1 Binary files /dev/null and b/assets/sprites/castle_spritesheet.png differ diff --git a/assets/sprites/castle_spritesheet.png.import b/assets/sprites/castle_spritesheet.png.import new file mode 100644 index 0000000..525c3c4 --- /dev/null +++ b/assets/sprites/castle_spritesheet.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c7e4jw4xcti0q" +path="res://.godot/imported/castle_spritesheet.png-6ff90c6355eaddab50addab2e87b1f2c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/castle_spritesheet.png" +dest_files=["res://.godot/imported/castle_spritesheet.png-6ff90c6355eaddab50addab2e87b1f2c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/sprites/character.bmp b/assets/sprites/character.bmp new file mode 100644 index 0000000..35b9c6a Binary files /dev/null and b/assets/sprites/character.bmp differ diff --git a/assets/sprites/character.bmp.import b/assets/sprites/character.bmp.import new file mode 100644 index 0000000..8a6b6ea --- /dev/null +++ b/assets/sprites/character.bmp.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c2se5wyly6gr6" +path="res://.godot/imported/character.bmp-cf65b7adb0d5844b4deb09628dc23b0b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/character.bmp" +dest_files=["res://.godot/imported/character.bmp-cf65b7adb0d5844b4deb09628dc23b0b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/sprites/flag.png b/assets/sprites/flag.png new file mode 100644 index 0000000..5157597 Binary files /dev/null and b/assets/sprites/flag.png differ diff --git a/assets/sprites/flag.png.import b/assets/sprites/flag.png.import new file mode 100644 index 0000000..42ed444 --- /dev/null +++ b/assets/sprites/flag.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cw5su6lignryo" +path="res://.godot/imported/flag.png-b8d0210a4bba4a3dc7cd10170df0a728.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/flag.png" +dest_files=["res://.godot/imported/flag.png-b8d0210a4bba4a3dc7cd10170df0a728.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/sprites/grey_castle_spritesheet_mask.bmp b/assets/sprites/grey_castle_spritesheet_mask.bmp new file mode 100644 index 0000000..1626b74 Binary files /dev/null and b/assets/sprites/grey_castle_spritesheet_mask.bmp differ diff --git a/assets/sprites/grey_castle_spritesheet_mask.bmp.import b/assets/sprites/grey_castle_spritesheet_mask.bmp.import new file mode 100644 index 0000000..1ea2c3a --- /dev/null +++ b/assets/sprites/grey_castle_spritesheet_mask.bmp.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8td6sv5re6r8" +path="res://.godot/imported/grey_castle_spritesheet_mask.bmp-194d929eb1771eae4ca4719fb40521c6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/grey_castle_spritesheet_mask.bmp" +dest_files=["res://.godot/imported/grey_castle_spritesheet_mask.bmp-194d929eb1771eae4ca4719fb40521c6.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/sprites/grid_highlight.png b/assets/sprites/grid_highlight.png new file mode 100644 index 0000000..2210abe Binary files /dev/null and b/assets/sprites/grid_highlight.png differ diff --git a/assets/sprites/grid_highlight.png.import b/assets/sprites/grid_highlight.png.import new file mode 100644 index 0000000..eb1fbc0 --- /dev/null +++ b/assets/sprites/grid_highlight.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://sjsl8q7tkx8" +path="res://.godot/imported/grid_highlight.png-bbd56dceab9bd3e965927c9144c4c052.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/grid_highlight.png" +dest_files=["res://.godot/imported/grid_highlight.png-bbd56dceab9bd3e965927c9144c4c052.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/sprites/map1.bmp b/assets/sprites/map1.bmp new file mode 100644 index 0000000..4061ab4 Binary files /dev/null and b/assets/sprites/map1.bmp differ diff --git a/assets/sprites/map1.bmp.import b/assets/sprites/map1.bmp.import new file mode 100644 index 0000000..0dcdc6d --- /dev/null +++ b/assets/sprites/map1.bmp.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://udsusbp3o76m" +path="res://.godot/imported/map1.bmp-9e2f42fc155126c194d55961a68898fc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/map1.bmp" +dest_files=["res://.godot/imported/map1.bmp-9e2f42fc155126c194d55961a68898fc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/sprites/selector.png b/assets/sprites/selector.png new file mode 100644 index 0000000..15d735c Binary files /dev/null and b/assets/sprites/selector.png differ diff --git a/assets/sprites/selector.png.import b/assets/sprites/selector.png.import new file mode 100644 index 0000000..ed8f546 --- /dev/null +++ b/assets/sprites/selector.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://h7nfrjxagqmc" +path="res://.godot/imported/selector.png-d0018707617902c3e886c6fbf4977608.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/selector.png" +dest_files=["res://.godot/imported/selector.png-d0018707617902c3e886c6fbf4977608.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/code_review_findings.md b/code_review_findings.md new file mode 100644 index 0000000..1cb7cbd --- /dev/null +++ b/code_review_findings.md @@ -0,0 +1,77 @@ +# Code Review Findings + +## Fixed + +### 1. Camera and PlayerController input conflict +**Files:** `scripts/camera_controller.gd`, `nodes/player_controller.gd` + +Both scripts used `_unhandled_input` with left mouse button. The camera used left click for dragging and never called `set_input_as_handled()`, so every left click also triggered unit selection/movement. Fixed with a drag threshold and click-on-release pattern. + +--- + +## Outstanding + +### 2. Unit lookup is fragile +**File:** `nodes/player_controller.gd:75` + +`_get_unit_at()` iterates `get_parent().get_children()` to find units. This couples the controller to a specific scene tree layout and will degrade as the scene grows. + +**Fix:** Use a group (`"units"`) or a dedicated unit registry so lookup doesn't depend on parent structure. + +### 3. No pathfinding — movement can skip walls diagonally +**File:** `nodes/player_controller.gd:45-60` + +Step-by-step movement picks one axis per frame. If the goal is diagonally past an L-shaped wall, the unit can path around it depending on approach angle since only the next immediate tile is checked. + +**Fix:** Implement BFS/A* on the grid, or at minimum validate the full path before starting movement. + +### ~~4. CombatMap extends CanvasItem instead of Node2D~~ (fixed) +**File:** `nodes/combat_map.gd:2` + +Changed to extend `Node2D`. + +### ~~5. Inconsistent naming convention~~ (fixed) +**File:** `nodes/combat_map.gd:16` + +Renamed `tileCoords` to `tile_coords`. + +### ~~6. unit_template is a string path, not a PackedScene~~ (fixed) +**File:** `scripts/test_map_generator.gd:7` + +Changed to `@export var unit_template: PackedScene` and removed the `load()` call. **Note:** The scene must be assigned in the Godot inspector on the TestMapGenerator node. + +### ~~7. No current_hp on units~~ (fixed) +**File:** `nodes/unit.gd` + +Added `current_hp` variable, initialized to `max_hp` in `_ready()`. + +### ~~8. Debug print left in production code~~ (fixed) +**File:** `scripts/test_map_generator.gd` + +Removed the debug `print()` call. + +### 9. tile_highlight.gd runs every frame unconditionally +**File:** `scripts/tile_highlight.gd:12-17` + +`_process` updates position and alpha every frame even when the highlight is hidden. Could skip processing when invisible via `set_process(false)` on hide. + +### 10. GridOverlay is wired but unused +**Files:** `scripts/grid_overlay.gd`, `nodes/combat_map.gd:6` + +`highlight_map` reference exists but is never called from any game logic. Dead code at the moment. + +--- + +## Priority + +| Priority | Issue | +|----------|-------| +| ~~High~~ | ~~#1 Input conflict~~ (fixed) | +| High | #3 Wall-skipping movement | +| Medium | #2 Fragile unit lookup | +| ~~Medium~~ | ~~#6 String path instead of PackedScene~~ (fixed) | +| ~~Low~~ | ~~#4 CanvasItem base class~~ (fixed) | +| ~~Low~~ | ~~#5 Inconsistent naming~~ (fixed) | +| ~~Low~~ | ~~#7 No current_hp~~ (fixed) | +| ~~Low~~ | ~~#8 Debug print~~ (fixed) | +| Low | #9, #10 | diff --git a/docs/superpowers/plans/2026-04-01-combat-ui-unit-panel.md b/docs/superpowers/plans/2026-04-01-combat-ui-unit-panel.md new file mode 100644 index 0000000..38690ec --- /dev/null +++ b/docs/superpowers/plans/2026-04-01-combat-ui-unit-panel.md @@ -0,0 +1,205 @@ +# Combat UI Unit Panel Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Replace the exit-button CombatUI with a bottom-left panel that shows the selected unit's name and HP. + +**Architecture:** CombatUI listens to the `unit_selected_changed` signal from units in the `"units"` group. On selection, it populates a name label and HP progress bar and shows the panel. On deselection, it hides the panel. + +**Tech Stack:** Godot 4.6, GDScript, `.tscn` scene files + +--- + +## File Structure + +| File | Action | Responsibility | +|------|--------|----------------| +| `prefabs/unit.tscn` | Modify | Add Unit node to `"units"` group | +| `scripts/combat_ui.gd` | Create | Script that connects to unit signals, shows/hides panel, populates data | +| `prefabs/combat_ui.tscn` | Modify | Remove exit button, add UnitPanel with NameLabel and HPBar, attach new script | + +--- + +### Task 1: Add Unit to the "units" group + +**Files:** +- Modify: `prefabs/unit.tscn` + +- [ ] **Step 1: Add the group to the Unit scene** + +In `prefabs/unit.tscn`, add a `groups` property to the root `Unit` node so every instantiated unit is automatically in the `"units"` group. Add this line to the root `[node name="Unit" ...]` block: + +``` +groups=["units"] +``` + +The full node line becomes: +``` +[node name="Unit" type="Node2D" unique_id=1893234933 groups=["units"]] +``` + +- [ ] **Step 2: Verify in editor** + +Open `scenes/combat_test.tscn` in Godot, run the scene (F5), and use the Remote scene tree to confirm the spawned unit node appears under the `"units"` group. + +- [ ] **Step 3: Commit** + +```bash +git add prefabs/unit.tscn +git commit -m "feat: add Unit to 'units' group for discovery" +``` + +--- + +### Task 2: Create combat_ui.gd script + +**Files:** +- Create: `scripts/combat_ui.gd` + +- [ ] **Step 1: Write the script** + +Create `scripts/combat_ui.gd` with the following content: + +```gdscript +class_name CombatUI extends CanvasLayer + +@onready var unit_panel: PanelContainer = %UnitPanel +@onready var name_label: Label = %NameLabel +@onready var hp_bar: ProgressBar = %HPBar + +func _ready() -> void: + unit_panel.visible = false + for unit: Unit in get_tree().get_nodes_in_group("units"): + unit.unit_selected_changed.connect(_on_unit_selected_changed) + +func _on_unit_selected_changed(unit: Unit, selected: bool) -> void: + if selected: + name_label.text = unit.current_info.name + hp_bar.max_value = unit.current_stats.max_hp + hp_bar.value = unit.current_stats.current_hp + unit_panel.visible = true + else: + unit_panel.visible = false +``` + +- [ ] **Step 2: Commit** + +```bash +git add scripts/combat_ui.gd +git commit -m "feat: add CombatUI script for unit info panel" +``` + +--- + +### Task 3: Rebuild combat_ui.tscn + +**Files:** +- Modify: `prefabs/combat_ui.tscn` + +- [ ] **Step 1: Replace the scene file contents** + +Replace the entire contents of `prefabs/combat_ui.tscn` with: + +``` +[gd_scene format=3 uid="uid://cy7r0udfcsqbn"] + +[ext_resource type="Theme" uid="uid://dx26d6py3n8xi" path="res://resources/main_ui_theme.tres" id="1_2ro41"] +[ext_resource type="Script" path="res://scripts/combat_ui.gd" id="2_ui_script"] + +[node name="CombatUI" type="CanvasLayer" unique_id=1093388037] +script = ExtResource("2_ui_script") + +[node name="UnitPanel" type="PanelContainer" parent="." unique_id=2000000001] +unique_name_in_owner = true +visible = false +anchors_preset = 2 +anchor_top = 1.0 +anchor_bottom = 1.0 +offset_left = 8.0 +offset_top = -78.0 +offset_right = 208.0 +offset_bottom = -8.0 +grow_vertical = 0 +theme = ExtResource("1_2ro41") + +[node name="MarginContainer" type="MarginContainer" parent="UnitPanel"] +layout_mode = 2 +theme_override_constants/margin_left = 8 +theme_override_constants/margin_top = 8 +theme_override_constants/margin_right = 8 +theme_override_constants/margin_bottom = 8 + +[node name="VBoxContainer" type="VBoxContainer" parent="UnitPanel/MarginContainer"] +layout_mode = 2 + +[node name="NameLabel" type="Label" parent="UnitPanel/MarginContainer/VBoxContainer" unique_id=2000000002] +unique_name_in_owner = true +layout_mode = 2 +text = "Unit" + +[node name="HPBar" type="ProgressBar" parent="UnitPanel/MarginContainer/VBoxContainer" unique_id=2000000003] +unique_name_in_owner = true +layout_mode = 2 +max_value = 100.0 +value = 100.0 +show_percentage = false +``` + +Key changes from the old file: +- Removed the exit button, its inline GDScript, the VBoxContainer, and the `[connection]` block. +- Added the `combat_ui.gd` script as an ext_resource and attached it to the root node. +- Added `UnitPanel` (PanelContainer) anchored to bottom-left with 8px margin from edges, 200px wide, ~70px tall. +- `NameLabel` and `HPBar` are marked with `unique_name_in_owner = true` so the script can reference them via `%NameLabel` and `%HPBar`. +- `UnitPanel` is also unique-named for `%UnitPanel` access. +- `show_percentage = false` on HPBar since we just want the bar visual. + +- [ ] **Step 2: Open in Godot and verify scene tree** + +Open `prefabs/combat_ui.tscn` in the Godot editor. Confirm: +1. No errors in the Scene dock. +2. The node tree shows: `CombatUI > UnitPanel > MarginContainer > VBoxContainer > NameLabel + HPBar`. +3. The UnitPanel is positioned at the bottom-left of the viewport. + +- [ ] **Step 3: Commit** + +```bash +git add prefabs/combat_ui.tscn +git commit -m "feat: replace exit button with unit info panel in CombatUI" +``` + +--- + +### Task 4: Integration test — verify end-to-end behavior + +**Files:** +- None (manual verification) + +- [ ] **Step 1: Run the combat test scene** + +Run `scenes/combat_test.tscn` (F5 or F6 from the scene). The test map generator spawns a unit named "Putit" with 50 HP. + +- [ ] **Step 2: Verify panel is hidden on start** + +Confirm the bottom-left corner is empty — no panel visible. + +- [ ] **Step 3: Click the unit to select it** + +Click the "Putit" unit on the map. Confirm: +1. The panel appears in the bottom-left corner. +2. The name label shows "Putit". +3. The HP bar is full (50/50). + +- [ ] **Step 4: Click an empty tile to deselect** + +Click an empty floor tile (this moves the unit, but the unit stays selected). Currently, clicking a different unit would deselect the first — since there's only one test unit, verify that selecting the same unit again keeps the panel visible and data correct. + +- [ ] **Step 5: Verify exit button is gone** + +Confirm there is no "Exit" button anywhere in the UI. + +- [ ] **Step 6: Commit (if any tweaks were needed)** + +```bash +git add -A +git commit -m "fix: adjustments from integration testing" +``` diff --git a/docs/superpowers/specs/2026-04-01-combat-ui-unit-panel-design.md b/docs/superpowers/specs/2026-04-01-combat-ui-unit-panel-design.md new file mode 100644 index 0000000..9cec0e0 --- /dev/null +++ b/docs/superpowers/specs/2026-04-01-combat-ui-unit-panel-design.md @@ -0,0 +1,68 @@ +# Combat UI: Unit Info Panel + +## Overview + +Replace the current exit-button-only CombatUI with a unit info panel that displays the selected unit's name and HP. The panel appears in the bottom-left corner when a unit is selected and hides when deselected. + +## Scene Structure + +``` +CombatUI (CanvasLayer) — script: scripts/combat_ui.gd + └─ UnitPanel (PanelContainer) — anchored bottom-left, hidden by default + └─ MarginContainer + └─ VBoxContainer + ├─ NameLabel (Label) — displays unit name + └─ HPBar (ProgressBar) — displays current_hp / max_hp +``` + +- The existing exit button and its VBoxContainer are removed entirely. +- The CombatUI CanvasLayer is preserved; its theme reference to `main_ui_theme.tres` stays. + +## Layout + +- UnitPanel is anchored to the bottom-left of the viewport. +- Margin of 8px from the left and bottom edges. +- Panel width: ~200px (enough for name and HP bar). +- Height: determined by contents. + +## Behavior + +### Unit Discovery + +CombatUI finds units by looking for nodes in the `"units"` group. Units must be added to this group — this is done in `unit.tscn` (scene-level group assignment) or in `unit.gd`'s `_ready()`. + +### Signal Connection + +On `_ready()`, CombatUI: +1. Calls `get_tree().get_nodes_in_group("units")` to find all current units. +2. Connects each unit's `unit_selected_changed(unit: Unit, selected: bool)` signal to a handler. + +### Selection Handling + +When `unit_selected_changed` is received: +- If `selected == true`: populate NameLabel with `unit.current_info.name`, set HPBar's `max_value` to `unit.current_stats.max_hp` and `value` to `unit.current_stats.current_hp`, show UnitPanel. +- If `selected == false`: hide UnitPanel. + +### Edge Cases + +- If no units exist in the group at ready time, the panel simply stays hidden. +- If a unit is removed from the scene (e.g., defeated), the signal disconnects naturally with the node. The panel hides if that unit was selected. + +## Files Changed + +| File | Change | +|------|--------| +| `prefabs/combat_ui.tscn` | Remove exit button/VBoxContainer. Add UnitPanel with NameLabel and HPBar. Attach new script. | +| `scripts/combat_ui.gd` | New script: connects to unit signals, shows/hides panel, populates data. | +| `prefabs/unit.tscn` | Add the node to the `"units"` group. | + +## Styling + +Uses the existing `main_ui_theme.tres` applied at the CombatUI or UnitPanel level. No new theme resources needed. + +## Out of Scope + +- Full stat display (ATK, DEF, etc.) — future expansion. +- Animations (fade/slide) — instant show/hide only. +- Pause menu / exit button — separate future feature. +- HP bar color theming — uses default ProgressBar style from theme. diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..c6bbb7d --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..c72f0d0 --- /dev/null +++ b/icon.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cpthotfnx5l30" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/nodes/combat_map.gd b/nodes/combat_map.gd new file mode 100644 index 0000000..0dfbf4f --- /dev/null +++ b/nodes/combat_map.gd @@ -0,0 +1,39 @@ +class_name CombatMap +extends Node2D + +signal tile_hovered(coords: Vector2i) + +@export var tile_set: DLTileset +@onready var tile_map: TileMapLayer = %TerrainLayer +@onready var highlight_map: GridOverlay = %OverlayLayer + +const TILE_SIZE := 48.0 +const SOURCE_ID: int = 0 + + +func snap_to_grid(pos: Vector2) -> Vector2: + return Vector2(floorf(pos.x / TILE_SIZE), floorf(pos.y / TILE_SIZE)) * TILE_SIZE + + +func world_to_coords(pos: Vector2) -> Vector2i: + return Vector2i(snap_to_grid(pos) / TILE_SIZE) + + +func coords_to_world(coords: Vector2i) -> Vector2: + return Vector2(coords) * TILE_SIZE + +func draw_wall(coords: Vector2i) -> void: + draw_custom(coords, tile_set.wall_tile_coords) + +func draw_floor(coords: Vector2i) -> void: + draw_custom(coords, tile_set.floor_tile_coords) + +func draw_custom(coords: Vector2i, tile_coords: Vector2i) -> void: + tile_map.set_cell(coords, SOURCE_ID, tile_coords) + +func is_wall(coords: Vector2i) -> bool: + return tile_map.get_cell_atlas_coords(coords) == tile_set.wall_tile_coords + +func target_tile(coords: Vector2i) -> void: + highlight_map.target_tile(coords) + tile_hovered.emit(coords) diff --git a/nodes/combat_map.gd.uid b/nodes/combat_map.gd.uid new file mode 100644 index 0000000..abcd270 --- /dev/null +++ b/nodes/combat_map.gd.uid @@ -0,0 +1 @@ +uid://bks7uplgjjdg0 diff --git a/nodes/player_controller.gd b/nodes/player_controller.gd new file mode 100644 index 0000000..ebb3cc4 --- /dev/null +++ b/nodes/player_controller.gd @@ -0,0 +1,80 @@ +class_name PlayerController extends Node + +const SPEED = 192.0 + +@export var dl_map: CombatMap + +var _selected_unit: Unit = null +var _target_pos: Vector2 +var _goal_pos: Vector2 +var _moving := false + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouseButton and not event.pressed and event.button_index == MOUSE_BUTTON_LEFT: + var world_pos: Vector2 = get_viewport().get_canvas_transform().affine_inverse() * event.position + var clicked_unit := _get_unit_at(world_pos) + + if clicked_unit: + _select_unit(clicked_unit) + get_viewport().set_input_as_handled() + elif _selected_unit: + var snapped_pos := dl_map.snap_to_grid(world_pos) + var grid_coords := dl_map.world_to_coords(world_pos) + if dl_map.is_wall(grid_coords): + return + _goal_pos = snapped_pos + get_viewport().set_input_as_handled() + + +func _physics_process(delta: float) -> void: + if not _selected_unit: + return + + if _moving: + var remaining := _target_pos - _selected_unit.position + var step := SPEED * delta + + if remaining.length() <= step: + _selected_unit.position = _target_pos + _moving = false + else: + _selected_unit.position += remaining.normalized() * step + return + + if _selected_unit.position != _goal_pos: + var diff := _goal_pos - _selected_unit.position + var dir: Vector2 + if absf(diff.x) >= absf(diff.y): + dir = Vector2(signf(diff.x), 0) + else: + dir = Vector2(0, signf(diff.y)) + + var next_pos := _selected_unit.position + dir * dl_map.TILE_SIZE + var grid_coords := dl_map.world_to_coords(next_pos) + if dl_map.is_wall(grid_coords): + _goal_pos = _selected_unit.position + return + + _target_pos = next_pos + _moving = true + + +func _select_unit(unit: Unit) -> void: + if _selected_unit: + _selected_unit.set_selected(false) + _selected_unit = unit + _selected_unit.set_selected(true) + _goal_pos = _selected_unit.position + _target_pos = _selected_unit.position + _moving = false + + +func _get_unit_at(world_pos: Vector2) -> Unit: + var snapped := dl_map.snap_to_grid(world_pos) + for child in get_parent().get_children(): + if child is Unit: + var unit_snapped := dl_map.snap_to_grid(child.global_position) + if unit_snapped == snapped: + return child + return null diff --git a/nodes/player_controller.gd.uid b/nodes/player_controller.gd.uid new file mode 100644 index 0000000..56eba96 --- /dev/null +++ b/nodes/player_controller.gd.uid @@ -0,0 +1 @@ +uid://dfojm3n0em4ef diff --git a/nodes/unit.gd b/nodes/unit.gd new file mode 100644 index 0000000..a59998a --- /dev/null +++ b/nodes/unit.gd @@ -0,0 +1,23 @@ +class_name Unit extends Node2D + +#region Templates +@export var stat_template: UnitStats +@export var info_template: UnitInfo +@export var allegiance_template: UnitAllegiance +#endregion + +var current_stats: UnitStats +var current_info: UnitInfo +var current_allegiance: UnitAllegiance + +signal unit_selected_changed(unit: Unit, selected: bool) +signal unit_allegiance_changed(unit: Unit, allegiance: UnitAllegiance) + +func _ready() -> void: + current_stats = stat_template.duplicate(true) + current_info = info_template.duplicate(true) + current_allegiance = allegiance_template.duplicate(true) + unit_allegiance_changed.emit(self, current_allegiance) + +func set_selected(selected: bool) -> void: + unit_selected_changed.emit(self, selected) diff --git a/nodes/unit.gd.uid b/nodes/unit.gd.uid new file mode 100644 index 0000000..7f8df4d --- /dev/null +++ b/nodes/unit.gd.uid @@ -0,0 +1 @@ +uid://c016mxgatcpse diff --git a/prefabs/combat_map.tscn b/prefabs/combat_map.tscn new file mode 100644 index 0000000..040a44b --- /dev/null +++ b/prefabs/combat_map.tscn @@ -0,0 +1,54 @@ +[gd_scene format=3 uid="uid://dkhyh5ce4iuk3"] + +[ext_resource type="Script" uid="uid://bks7uplgjjdg0" path="res://nodes/combat_map.gd" id="1_jyv1f"] +[ext_resource type="Script" uid="uid://c6701vy8h5rfx" path="res://resources/resource_definitions/dl_tileset.gd" id="2_8rn0j"] +[ext_resource type="TileSet" uid="uid://dm5wl6d4xkstu" path="res://resources/combat_tileset.tres" id="3_8rn0j"] +[ext_resource type="Texture2D" uid="uid://sjsl8q7tkx8" path="res://assets/sprites/grid_highlight.png" id="3_vcj5e"] +[ext_resource type="Script" uid="uid://cxl38x2m6sj3w" path="res://scripts/grid_overlay.gd" id="4_jelju"] +[ext_resource type="Texture2D" uid="uid://h7nfrjxagqmc" path="res://assets/sprites/selector.png" id="5_muxvo"] +[ext_resource type="Script" uid="uid://b31eyqov8w7bm" path="res://scripts/tile_highlight.gd" id="7_tileh"] + +[sub_resource type="Resource" id="Resource_vcj5e"] +script = ExtResource("2_8rn0j") +wall_tile_coords = Vector2i(2, 15) +metadata/_custom_type_script = "uid://c6701vy8h5rfx" + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_jelju"] +texture = ExtResource("3_vcj5e") +texture_region_size = Vector2i(48, 48) +0:0/animation_columns = 6 +0:0/animation_frame_0/duration = 1.0 +0:0/animation_frame_1/duration = 1.0 +0:0/animation_frame_2/duration = 1.0 +0:0/animation_frame_3/duration = 1.0 +0:0/animation_frame_4/duration = 1.0 +0:0/animation_frame_5/duration = 1.0 +0:0/0 = 0 + +[sub_resource type="TileSet" id="TileSet_muxvo"] +tile_size = Vector2i(48, 48) +sources/0 = SubResource("TileSetAtlasSource_jelju") + +[node name="CombatMap" type="Node2D" unique_id=546780706] +script = ExtResource("1_jyv1f") +tile_set = SubResource("Resource_vcj5e") + +[node name="OverlayLayer" type="TileMapLayer" parent="." unique_id=1335660296] +unique_name_in_owner = true +tile_set = SubResource("TileSet_muxvo") +script = ExtResource("4_jelju") + +[node name="TargetingIndicator" type="Sprite2D" parent="OverlayLayer" unique_id=1836328987] +visible = false +z_index = 3 +texture = ExtResource("5_muxvo") +offset = Vector2(24, 24) + +[node name="TerrainLayer" type="TileMapLayer" parent="." unique_id=1201875024] +unique_name_in_owner = true +tile_set = ExtResource("3_8rn0j") + +[node name="TileHighlight" type="ColorRect" parent="." unique_id=211433569] +script = ExtResource("7_tileh") + +[connection signal="tile_hovered" from="TileHighlight" to="." method="target_tile"] diff --git a/prefabs/combat_ui.tscn b/prefabs/combat_ui.tscn new file mode 100644 index 0000000..ec79222 --- /dev/null +++ b/prefabs/combat_ui.tscn @@ -0,0 +1,42 @@ +[gd_scene format=3 uid="uid://cy7r0udfcsqbn"] + +[ext_resource type="Theme" uid="uid://dx26d6py3n8xi" path="res://resources/main_ui_theme.tres" id="1_2ro41"] +[ext_resource type="Script" path="res://scripts/combat_ui.gd" id="2_ui_script"] + +[node name="CombatUI" type="CanvasLayer" unique_id=1093388037] +script = ExtResource("2_ui_script") + +[node name="UnitPanel" type="PanelContainer" parent="." unique_id=2000000001] +unique_name_in_owner = true +visible = false +anchors_preset = 2 +anchor_top = 1.0 +anchor_bottom = 1.0 +offset_left = 8.0 +offset_top = -78.0 +offset_right = 208.0 +offset_bottom = -8.0 +grow_vertical = 0 +theme = ExtResource("1_2ro41") + +[node name="MarginContainer" type="MarginContainer" parent="UnitPanel"] +layout_mode = 2 +theme_override_constants/margin_left = 8 +theme_override_constants/margin_top = 8 +theme_override_constants/margin_right = 8 +theme_override_constants/margin_bottom = 8 + +[node name="VBoxContainer" type="VBoxContainer" parent="UnitPanel/MarginContainer"] +layout_mode = 2 + +[node name="NameLabel" type="Label" parent="UnitPanel/MarginContainer/VBoxContainer" unique_id=2000000002] +unique_name_in_owner = true +layout_mode = 2 +text = "Unit" + +[node name="HPBar" type="ProgressBar" parent="UnitPanel/MarginContainer/VBoxContainer" unique_id=2000000003] +unique_name_in_owner = true +layout_mode = 2 +max_value = 100.0 +value = 100.0 +show_percentage = false diff --git a/prefabs/unit.tscn b/prefabs/unit.tscn new file mode 100644 index 0000000..5ea8b75 --- /dev/null +++ b/prefabs/unit.tscn @@ -0,0 +1,57 @@ +[gd_scene format=3 uid="uid://b6a7nlnf58mc4"] + +[ext_resource type="Script" uid="uid://c016mxgatcpse" path="res://nodes/unit.gd" id="1_cq4v0"] +[ext_resource type="Texture2D" uid="uid://cw5su6lignryo" path="res://assets/sprites/flag.png" id="2_fhs1y"] +[ext_resource type="Texture2D" uid="uid://c2se5wyly6gr6" path="res://assets/sprites/character.bmp" id="2_on614"] +[ext_resource type="Shader" uid="uid://bd8ki8xwym5nc" path="res://shaders/chroma_key.gdshader" id="3_fhs1y"] + +[sub_resource type="GDScript" id="GDScript_fhs1y"] +resource_name = "AllegianceIndicatorManager" +script/source = "extends Sprite2D + + +func _on_unit_unit_allegiance_changed(unit: Unit, allegiance: UnitAllegiance) -> void: + self_modulate = allegiance.color +" + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_4j20j"] +shader = ExtResource("3_fhs1y") +shader_parameter/threshold = 0.01 + +[sub_resource type="AtlasTexture" id="AtlasTexture_on614"] +atlas = ExtResource("2_on614") +region = Rect2(144, 240, 48, 48) + +[sub_resource type="GDScript" id="GDScript_on614"] +resource_name = "UnitSelectorHandler" +script/source = "extends ColorRect + +func _unit_selected_changed(_unit: Unit, selected: bool) -> void: + visible = selected +" + +[node name="Unit" type="Node2D" unique_id=1893234933 groups=["units"]] +script = ExtResource("1_cq4v0") +metadata/_custom_type_script = "uid://c016mxgatcpse" + +[node name="AllegianceIndicator" type="Sprite2D" parent="." unique_id=1567439632] +z_index = 2 +texture = ExtResource("2_fhs1y") +offset = Vector2(24, 24) +script = SubResource("GDScript_fhs1y") + +[node name="UnitSprite" type="Sprite2D" parent="." unique_id=350615297] +z_index = 1 +material = SubResource("ShaderMaterial_4j20j") +texture = SubResource("AtlasTexture_on614") +offset = Vector2(24, 24) + +[node name="ColorRect" type="ColorRect" parent="." unique_id=1313394023] +visible = false +offset_right = 48.0 +offset_bottom = 48.0 +color = Color(1, 1, 0.3019608, 0.36078432) +script = SubResource("GDScript_on614") + +[connection signal="unit_allegiance_changed" from="." to="AllegianceIndicator" method="_on_unit_unit_allegiance_changed"] +[connection signal="unit_selected_changed" from="." to="ColorRect" method="_unit_selected_changed"] diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..47f5dbd --- /dev/null +++ b/project.godot @@ -0,0 +1,26 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="Dungeon Lords" +run/main_scene="uid://dlbuo46n6q238" +config/features=PackedStringArray("4.6", "Mobile") +config/icon="res://icon.svg" + +[physics] + +3d/physics_engine="Jolt Physics" + +[rendering] + +textures/canvas_textures/default_texture_filter=0 +rendering_device/driver.windows="d3d12" +renderer/rendering_method="mobile" diff --git a/resources/allegiance_types/enemy_allegiance.tres b/resources/allegiance_types/enemy_allegiance.tres new file mode 100644 index 0000000..88710c6 --- /dev/null +++ b/resources/allegiance_types/enemy_allegiance.tres @@ -0,0 +1,9 @@ +[gd_resource type="Resource" script_class="UnitAllegiance" format=3 uid="uid://cuc7kkknpsr1g"] + +[ext_resource type="Script" uid="uid://bhglsexm8dtpj" path="res://resources/resource_definitions/unit_allegiance.gd" id="1_40cg2"] + +[resource] +script = ExtResource("1_40cg2") +type = 1 +color = Color(0, 0, 1, 1) +metadata/_custom_type_script = "uid://bhglsexm8dtpj" diff --git a/resources/allegiance_types/player_allegiance.tres b/resources/allegiance_types/player_allegiance.tres new file mode 100644 index 0000000..b4fe455 --- /dev/null +++ b/resources/allegiance_types/player_allegiance.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="UnitAllegiance" format=3 uid="uid://dufi2h00j5vrq"] + +[ext_resource type="Script" uid="uid://bhglsexm8dtpj" path="res://resources/resource_definitions/unit_allegiance.gd" id="1_4mkdx"] + +[resource] +script = ExtResource("1_4mkdx") +color = Color(0.8288101, 2.7193873e-06, 5.7756904e-07, 1) +metadata/_custom_type_script = "uid://bhglsexm8dtpj" diff --git a/resources/combat_tileset.tres b/resources/combat_tileset.tres new file mode 100644 index 0000000..ae305f1 --- /dev/null +++ b/resources/combat_tileset.tres @@ -0,0 +1,836 @@ +[gd_resource type="TileSet" format=3 uid="uid://dm5wl6d4xkstu"] + +[ext_resource type="Texture2D" uid="uid://udsusbp3o76m" path="res://assets/sprites/map1.bmp" id="1_v1d02"] + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_5lppa"] +texture = ExtResource("1_v1d02") +texture_region_size = Vector2i(48, 48) +0:0/0 = 0 +1:0/0 = 0 +2:0/0 = 0 +3:0/0 = 0 +4:0/0 = 0 +5:0/0 = 0 +6:0/0 = 0 +7:0/0 = 0 +8:0/0 = 0 +9:0/0 = 0 +10:0/0 = 0 +11:0/0 = 0 +12:0/0 = 0 +13:0/0 = 0 +14:0/0 = 0 +15:0/0 = 0 +16:0/0 = 0 +17:0/0 = 0 +18:0/0 = 0 +19:0/0 = 0 +20:0/0 = 0 +21:0/0 = 0 +22:0/0 = 0 +23:0/0 = 0 +24:0/0 = 0 +25:0/0 = 0 +26:0/0 = 0 +27:0/0 = 0 +28:0/0 = 0 +29:0/0 = 0 +30:0/0 = 0 +31:0/0 = 0 +32:0/0 = 0 +0:1/0 = 0 +1:1/0 = 0 +2:1/0 = 0 +3:1/0 = 0 +4:1/0 = 0 +5:1/0 = 0 +6:1/0 = 0 +7:1/0 = 0 +8:1/0 = 0 +9:1/0 = 0 +10:1/0 = 0 +11:1/0 = 0 +12:1/0 = 0 +13:1/0 = 0 +14:1/0 = 0 +15:1/0 = 0 +16:1/0 = 0 +17:1/0 = 0 +18:1/0 = 0 +19:1/0 = 0 +20:1/0 = 0 +21:1/0 = 0 +22:1/0 = 0 +23:1/0 = 0 +24:1/0 = 0 +25:1/0 = 0 +26:1/0 = 0 +27:1/0 = 0 +28:1/0 = 0 +29:1/0 = 0 +30:1/0 = 0 +31:1/0 = 0 +32:1/0 = 0 +0:2/0 = 0 +1:2/0 = 0 +2:2/0 = 0 +3:2/0 = 0 +4:2/0 = 0 +5:2/0 = 0 +6:2/0 = 0 +7:2/0 = 0 +8:2/0 = 0 +9:2/0 = 0 +10:2/0 = 0 +11:2/0 = 0 +12:2/0 = 0 +13:2/0 = 0 +14:2/0 = 0 +15:2/0 = 0 +16:2/0 = 0 +17:2/0 = 0 +18:2/0 = 0 +19:2/0 = 0 +20:2/0 = 0 +21:2/0 = 0 +22:2/0 = 0 +23:2/0 = 0 +24:2/0 = 0 +25:2/0 = 0 +26:2/0 = 0 +27:2/0 = 0 +28:2/0 = 0 +29:2/0 = 0 +30:2/0 = 0 +31:2/0 = 0 +32:2/0 = 0 +0:3/0 = 0 +1:3/0 = 0 +2:3/0 = 0 +3:3/0 = 0 +4:3/0 = 0 +5:3/0 = 0 +6:3/0 = 0 +7:3/0 = 0 +8:3/0 = 0 +9:3/0 = 0 +10:3/0 = 0 +11:3/0 = 0 +12:3/0 = 0 +13:3/0 = 0 +14:3/0 = 0 +15:3/0 = 0 +16:3/0 = 0 +17:3/0 = 0 +18:3/0 = 0 +19:3/0 = 0 +20:3/0 = 0 +21:3/0 = 0 +22:3/0 = 0 +23:3/0 = 0 +24:3/0 = 0 +25:3/0 = 0 +26:3/0 = 0 +27:3/0 = 0 +28:3/0 = 0 +29:3/0 = 0 +30:3/0 = 0 +31:3/0 = 0 +32:3/0 = 0 +0:4/0 = 0 +1:4/0 = 0 +2:4/0 = 0 +3:4/0 = 0 +4:4/0 = 0 +5:4/0 = 0 +6:4/0 = 0 +7:4/0 = 0 +8:4/0 = 0 +9:4/0 = 0 +10:4/0 = 0 +11:4/0 = 0 +12:4/0 = 0 +13:4/0 = 0 +14:4/0 = 0 +15:4/0 = 0 +16:4/0 = 0 +17:4/0 = 0 +18:4/0 = 0 +19:4/0 = 0 +20:4/0 = 0 +21:4/0 = 0 +22:4/0 = 0 +23:4/0 = 0 +24:4/0 = 0 +25:4/0 = 0 +26:4/0 = 0 +27:4/0 = 0 +28:4/0 = 0 +29:4/0 = 0 +30:4/0 = 0 +31:4/0 = 0 +32:4/0 = 0 +0:5/0 = 0 +1:5/0 = 0 +2:5/0 = 0 +3:5/0 = 0 +4:5/0 = 0 +5:5/0 = 0 +6:5/0 = 0 +7:5/0 = 0 +8:5/0 = 0 +9:5/0 = 0 +10:5/0 = 0 +11:5/0 = 0 +12:5/0 = 0 +13:5/0 = 0 +14:5/0 = 0 +15:5/0 = 0 +16:5/0 = 0 +17:5/0 = 0 +18:5/0 = 0 +19:5/0 = 0 +20:5/0 = 0 +21:5/0 = 0 +22:5/0 = 0 +23:5/0 = 0 +24:5/0 = 0 +25:5/0 = 0 +26:5/0 = 0 +27:5/0 = 0 +28:5/0 = 0 +29:5/0 = 0 +30:5/0 = 0 +31:5/0 = 0 +32:5/0 = 0 +0:6/0 = 0 +1:6/0 = 0 +2:6/0 = 0 +3:6/0 = 0 +4:6/0 = 0 +5:6/0 = 0 +6:6/0 = 0 +7:6/0 = 0 +8:6/0 = 0 +9:6/0 = 0 +10:6/0 = 0 +11:6/0 = 0 +12:6/0 = 0 +13:6/0 = 0 +14:6/0 = 0 +15:6/0 = 0 +16:6/0 = 0 +17:6/0 = 0 +18:6/0 = 0 +19:6/0 = 0 +20:6/0 = 0 +21:6/0 = 0 +22:6/0 = 0 +23:6/0 = 0 +24:6/0 = 0 +25:6/0 = 0 +26:6/0 = 0 +27:6/0 = 0 +28:6/0 = 0 +29:6/0 = 0 +30:6/0 = 0 +31:6/0 = 0 +32:6/0 = 0 +0:7/0 = 0 +1:7/0 = 0 +2:7/0 = 0 +3:7/0 = 0 +4:7/0 = 0 +5:7/0 = 0 +6:7/0 = 0 +7:7/0 = 0 +8:7/0 = 0 +9:7/0 = 0 +10:7/0 = 0 +11:7/0 = 0 +12:7/0 = 0 +13:7/0 = 0 +14:7/0 = 0 +15:7/0 = 0 +16:7/0 = 0 +17:7/0 = 0 +18:7/0 = 0 +19:7/0 = 0 +20:7/0 = 0 +21:7/0 = 0 +22:7/0 = 0 +23:7/0 = 0 +24:7/0 = 0 +25:7/0 = 0 +26:7/0 = 0 +27:7/0 = 0 +28:7/0 = 0 +29:7/0 = 0 +30:7/0 = 0 +31:7/0 = 0 +32:7/0 = 0 +0:8/0 = 0 +1:8/0 = 0 +2:8/0 = 0 +3:8/0 = 0 +4:8/0 = 0 +5:8/0 = 0 +6:8/0 = 0 +7:8/0 = 0 +8:8/0 = 0 +9:8/0 = 0 +10:8/0 = 0 +11:8/0 = 0 +12:8/0 = 0 +13:8/0 = 0 +14:8/0 = 0 +15:8/0 = 0 +16:8/0 = 0 +17:8/0 = 0 +18:8/0 = 0 +19:8/0 = 0 +20:8/0 = 0 +21:8/0 = 0 +22:8/0 = 0 +23:8/0 = 0 +24:8/0 = 0 +25:8/0 = 0 +26:8/0 = 0 +27:8/0 = 0 +28:8/0 = 0 +29:8/0 = 0 +30:8/0 = 0 +31:8/0 = 0 +32:8/0 = 0 +0:9/0 = 0 +1:9/0 = 0 +2:9/0 = 0 +3:9/0 = 0 +4:9/0 = 0 +5:9/0 = 0 +6:9/0 = 0 +7:9/0 = 0 +8:9/0 = 0 +9:9/0 = 0 +10:9/0 = 0 +11:9/0 = 0 +12:9/0 = 0 +13:9/0 = 0 +14:9/0 = 0 +15:9/0 = 0 +16:9/0 = 0 +17:9/0 = 0 +18:9/0 = 0 +19:9/0 = 0 +20:9/0 = 0 +21:9/0 = 0 +22:9/0 = 0 +23:9/0 = 0 +24:9/0 = 0 +25:9/0 = 0 +26:9/0 = 0 +27:9/0 = 0 +28:9/0 = 0 +29:9/0 = 0 +30:9/0 = 0 +31:9/0 = 0 +32:9/0 = 0 +0:10/0 = 0 +1:10/0 = 0 +2:10/0 = 0 +3:10/0 = 0 +4:10/0 = 0 +5:10/0 = 0 +6:10/0 = 0 +7:10/0 = 0 +8:10/0 = 0 +9:10/0 = 0 +10:10/0 = 0 +11:10/0 = 0 +12:10/0 = 0 +13:10/0 = 0 +14:10/0 = 0 +15:10/0 = 0 +16:10/0 = 0 +17:10/0 = 0 +18:10/0 = 0 +19:10/0 = 0 +20:10/0 = 0 +21:10/0 = 0 +22:10/0 = 0 +23:10/0 = 0 +24:10/0 = 0 +25:10/0 = 0 +26:10/0 = 0 +27:10/0 = 0 +28:10/0 = 0 +29:10/0 = 0 +30:10/0 = 0 +31:10/0 = 0 +32:10/0 = 0 +0:11/0 = 0 +1:11/0 = 0 +2:11/0 = 0 +3:11/0 = 0 +4:11/0 = 0 +5:11/0 = 0 +6:11/0 = 0 +7:11/0 = 0 +8:11/0 = 0 +9:11/0 = 0 +10:11/0 = 0 +11:11/0 = 0 +12:11/0 = 0 +13:11/0 = 0 +14:11/0 = 0 +15:11/0 = 0 +16:11/0 = 0 +17:11/0 = 0 +18:11/0 = 0 +19:11/0 = 0 +20:11/0 = 0 +21:11/0 = 0 +22:11/0 = 0 +23:11/0 = 0 +24:11/0 = 0 +25:11/0 = 0 +26:11/0 = 0 +27:11/0 = 0 +28:11/0 = 0 +29:11/0 = 0 +30:11/0 = 0 +31:11/0 = 0 +32:11/0 = 0 +0:12/0 = 0 +1:12/0 = 0 +2:12/0 = 0 +3:12/0 = 0 +4:12/0 = 0 +5:12/0 = 0 +6:12/0 = 0 +7:12/0 = 0 +8:12/0 = 0 +9:12/0 = 0 +10:12/0 = 0 +11:12/0 = 0 +12:12/0 = 0 +13:12/0 = 0 +14:12/0 = 0 +15:12/0 = 0 +16:12/0 = 0 +17:12/0 = 0 +18:12/0 = 0 +19:12/0 = 0 +20:12/0 = 0 +21:12/0 = 0 +22:12/0 = 0 +23:12/0 = 0 +24:12/0 = 0 +25:12/0 = 0 +26:12/0 = 0 +27:12/0 = 0 +28:12/0 = 0 +29:12/0 = 0 +30:12/0 = 0 +31:12/0 = 0 +32:12/0 = 0 +0:13/0 = 0 +1:13/0 = 0 +2:13/0 = 0 +3:13/0 = 0 +4:13/0 = 0 +5:13/0 = 0 +6:13/0 = 0 +7:13/0 = 0 +8:13/0 = 0 +9:13/0 = 0 +10:13/0 = 0 +11:13/0 = 0 +12:13/0 = 0 +13:13/0 = 0 +14:13/0 = 0 +15:13/0 = 0 +16:13/0 = 0 +17:13/0 = 0 +18:13/0 = 0 +19:13/0 = 0 +20:13/0 = 0 +21:13/0 = 0 +22:13/0 = 0 +23:13/0 = 0 +24:13/0 = 0 +25:13/0 = 0 +26:13/0 = 0 +27:13/0 = 0 +28:13/0 = 0 +29:13/0 = 0 +30:13/0 = 0 +31:13/0 = 0 +32:13/0 = 0 +0:14/0 = 0 +1:14/0 = 0 +2:14/0 = 0 +3:14/0 = 0 +4:14/0 = 0 +5:14/0 = 0 +6:14/0 = 0 +7:14/0 = 0 +8:14/0 = 0 +9:14/0 = 0 +10:14/0 = 0 +11:14/0 = 0 +12:14/0 = 0 +13:14/0 = 0 +14:14/0 = 0 +15:14/0 = 0 +16:14/0 = 0 +17:14/0 = 0 +18:14/0 = 0 +19:14/0 = 0 +20:14/0 = 0 +21:14/0 = 0 +22:14/0 = 0 +23:14/0 = 0 +24:14/0 = 0 +25:14/0 = 0 +26:14/0 = 0 +27:14/0 = 0 +28:14/0 = 0 +29:14/0 = 0 +30:14/0 = 0 +31:14/0 = 0 +32:14/0 = 0 +0:15/0 = 0 +1:15/0 = 0 +2:15/0 = 0 +3:15/0 = 0 +4:15/0 = 0 +5:15/0 = 0 +6:15/0 = 0 +7:15/0 = 0 +8:15/0 = 0 +9:15/0 = 0 +10:15/0 = 0 +11:15/0 = 0 +12:15/0 = 0 +13:15/0 = 0 +14:15/0 = 0 +15:15/0 = 0 +16:15/0 = 0 +17:15/0 = 0 +18:15/0 = 0 +19:15/0 = 0 +20:15/0 = 0 +21:15/0 = 0 +22:15/0 = 0 +23:15/0 = 0 +24:15/0 = 0 +25:15/0 = 0 +26:15/0 = 0 +27:15/0 = 0 +28:15/0 = 0 +29:15/0 = 0 +30:15/0 = 0 +31:15/0 = 0 +32:15/0 = 0 +0:16/0 = 0 +1:16/0 = 0 +2:16/0 = 0 +3:16/0 = 0 +4:16/0 = 0 +5:16/0 = 0 +6:16/0 = 0 +7:16/0 = 0 +8:16/0 = 0 +9:16/0 = 0 +10:16/0 = 0 +11:16/0 = 0 +12:16/0 = 0 +13:16/0 = 0 +14:16/0 = 0 +15:16/0 = 0 +16:16/0 = 0 +17:16/0 = 0 +18:16/0 = 0 +19:16/0 = 0 +20:16/0 = 0 +21:16/0 = 0 +22:16/0 = 0 +23:16/0 = 0 +24:16/0 = 0 +25:16/0 = 0 +26:16/0 = 0 +27:16/0 = 0 +28:16/0 = 0 +29:16/0 = 0 +30:16/0 = 0 +31:16/0 = 0 +32:16/0 = 0 +0:17/0 = 0 +1:17/0 = 0 +2:17/0 = 0 +3:17/0 = 0 +4:17/0 = 0 +5:17/0 = 0 +6:17/0 = 0 +7:17/0 = 0 +8:17/0 = 0 +9:17/0 = 0 +10:17/0 = 0 +11:17/0 = 0 +12:17/0 = 0 +13:17/0 = 0 +14:17/0 = 0 +15:17/0 = 0 +16:17/0 = 0 +17:17/0 = 0 +18:17/0 = 0 +19:17/0 = 0 +20:17/0 = 0 +21:17/0 = 0 +22:17/0 = 0 +23:17/0 = 0 +24:17/0 = 0 +25:17/0 = 0 +26:17/0 = 0 +27:17/0 = 0 +28:17/0 = 0 +29:17/0 = 0 +30:17/0 = 0 +31:17/0 = 0 +32:17/0 = 0 +0:18/0 = 0 +1:18/0 = 0 +2:18/0 = 0 +3:18/0 = 0 +4:18/0 = 0 +5:18/0 = 0 +6:18/0 = 0 +7:18/0 = 0 +8:18/0 = 0 +9:18/0 = 0 +10:18/0 = 0 +11:18/0 = 0 +12:18/0 = 0 +13:18/0 = 0 +14:18/0 = 0 +15:18/0 = 0 +16:18/0 = 0 +17:18/0 = 0 +18:18/0 = 0 +19:18/0 = 0 +20:18/0 = 0 +21:18/0 = 0 +22:18/0 = 0 +23:18/0 = 0 +24:18/0 = 0 +25:18/0 = 0 +26:18/0 = 0 +27:18/0 = 0 +28:18/0 = 0 +29:18/0 = 0 +30:18/0 = 0 +31:18/0 = 0 +32:18/0 = 0 +0:19/0 = 0 +1:19/0 = 0 +2:19/0 = 0 +3:19/0 = 0 +4:19/0 = 0 +5:19/0 = 0 +6:19/0 = 0 +7:19/0 = 0 +8:19/0 = 0 +9:19/0 = 0 +10:19/0 = 0 +11:19/0 = 0 +12:19/0 = 0 +13:19/0 = 0 +14:19/0 = 0 +15:19/0 = 0 +16:19/0 = 0 +17:19/0 = 0 +18:19/0 = 0 +19:19/0 = 0 +20:19/0 = 0 +21:19/0 = 0 +22:19/0 = 0 +23:19/0 = 0 +24:19/0 = 0 +25:19/0 = 0 +26:19/0 = 0 +27:19/0 = 0 +28:19/0 = 0 +29:19/0 = 0 +30:19/0 = 0 +31:19/0 = 0 +32:19/0 = 0 +0:20/0 = 0 +1:20/0 = 0 +2:20/0 = 0 +3:20/0 = 0 +4:20/0 = 0 +5:20/0 = 0 +6:20/0 = 0 +7:20/0 = 0 +8:20/0 = 0 +9:20/0 = 0 +10:20/0 = 0 +11:20/0 = 0 +12:20/0 = 0 +13:20/0 = 0 +14:20/0 = 0 +15:20/0 = 0 +16:20/0 = 0 +17:20/0 = 0 +18:20/0 = 0 +19:20/0 = 0 +20:20/0 = 0 +21:20/0 = 0 +22:20/0 = 0 +23:20/0 = 0 +24:20/0 = 0 +25:20/0 = 0 +26:20/0 = 0 +27:20/0 = 0 +28:20/0 = 0 +29:20/0 = 0 +30:20/0 = 0 +31:20/0 = 0 +32:20/0 = 0 +0:21/0 = 0 +1:21/0 = 0 +2:21/0 = 0 +3:21/0 = 0 +4:21/0 = 0 +5:21/0 = 0 +6:21/0 = 0 +7:21/0 = 0 +8:21/0 = 0 +9:21/0 = 0 +10:21/0 = 0 +11:21/0 = 0 +12:21/0 = 0 +13:21/0 = 0 +14:21/0 = 0 +15:21/0 = 0 +16:21/0 = 0 +17:21/0 = 0 +18:21/0 = 0 +19:21/0 = 0 +20:21/0 = 0 +21:21/0 = 0 +22:21/0 = 0 +23:21/0 = 0 +24:21/0 = 0 +25:21/0 = 0 +26:21/0 = 0 +27:21/0 = 0 +28:21/0 = 0 +29:21/0 = 0 +30:21/0 = 0 +31:21/0 = 0 +32:21/0 = 0 +0:22/0 = 0 +1:22/0 = 0 +2:22/0 = 0 +3:22/0 = 0 +4:22/0 = 0 +5:22/0 = 0 +6:22/0 = 0 +7:22/0 = 0 +8:22/0 = 0 +9:22/0 = 0 +10:22/0 = 0 +11:22/0 = 0 +12:22/0 = 0 +13:22/0 = 0 +14:22/0 = 0 +15:22/0 = 0 +16:22/0 = 0 +17:22/0 = 0 +18:22/0 = 0 +19:22/0 = 0 +20:22/0 = 0 +21:22/0 = 0 +22:22/0 = 0 +23:22/0 = 0 +24:22/0 = 0 +25:22/0 = 0 +26:22/0 = 0 +27:22/0 = 0 +28:22/0 = 0 +29:22/0 = 0 +30:22/0 = 0 +31:22/0 = 0 +32:22/0 = 0 +0:23/0 = 0 +1:23/0 = 0 +2:23/0 = 0 +3:23/0 = 0 +4:23/0 = 0 +5:23/0 = 0 +6:23/0 = 0 +7:23/0 = 0 +8:23/0 = 0 +9:23/0 = 0 +10:23/0 = 0 +11:23/0 = 0 +12:23/0 = 0 +13:23/0 = 0 +14:23/0 = 0 +15:23/0 = 0 +16:23/0 = 0 +17:23/0 = 0 +18:23/0 = 0 +19:23/0 = 0 +20:23/0 = 0 +21:23/0 = 0 +22:23/0 = 0 +23:23/0 = 0 +24:23/0 = 0 +25:23/0 = 0 +26:23/0 = 0 +27:23/0 = 0 +28:23/0 = 0 +29:23/0 = 0 +30:23/0 = 0 +31:23/0 = 0 +32:23/0 = 0 +0:24/0 = 0 +1:24/0 = 0 +2:24/0 = 0 +3:24/0 = 0 +4:24/0 = 0 +5:24/0 = 0 +6:24/0 = 0 +7:24/0 = 0 +8:24/0 = 0 +9:24/0 = 0 +10:24/0 = 0 +11:24/0 = 0 +12:24/0 = 0 +13:24/0 = 0 +14:24/0 = 0 +15:24/0 = 0 +16:24/0 = 0 +17:24/0 = 0 +18:24/0 = 0 +19:24/0 = 0 +20:24/0 = 0 +21:24/0 = 0 +22:24/0 = 0 +23:24/0 = 0 +24:24/0 = 0 +25:24/0 = 0 +26:24/0 = 0 +27:24/0 = 0 +28:24/0 = 0 +29:24/0 = 0 +30:24/0 = 0 +31:24/0 = 0 +32:24/0 = 0 + +[resource] +tile_size = Vector2i(48, 48) +sources/0 = SubResource("TileSetAtlasSource_5lppa") diff --git a/resources/main_ui_theme.tres b/resources/main_ui_theme.tres new file mode 100644 index 0000000..f266a5b --- /dev/null +++ b/resources/main_ui_theme.tres @@ -0,0 +1,6 @@ +[gd_resource type="Theme" format=3 uid="uid://dx26d6py3n8xi"] + +[ext_resource type="FontFile" uid="uid://eqhm6gv5p05t" path="res://assets/fonts/Minecraft.ttf" id="1_nmd6r"] + +[resource] +default_font = ExtResource("1_nmd6r") diff --git a/resources/resource_definitions/dl_tileset.gd b/resources/resource_definitions/dl_tileset.gd new file mode 100644 index 0000000..69c62aa --- /dev/null +++ b/resources/resource_definitions/dl_tileset.gd @@ -0,0 +1,4 @@ +class_name DLTileset extends Resource + +@export var floor_tile_coords: Vector2i +@export var wall_tile_coords: Vector2i diff --git a/resources/resource_definitions/dl_tileset.gd.uid b/resources/resource_definitions/dl_tileset.gd.uid new file mode 100644 index 0000000..b94b9b6 --- /dev/null +++ b/resources/resource_definitions/dl_tileset.gd.uid @@ -0,0 +1 @@ +uid://c6701vy8h5rfx diff --git a/resources/resource_definitions/unit_allegiance.gd b/resources/resource_definitions/unit_allegiance.gd new file mode 100644 index 0000000..84b52b8 --- /dev/null +++ b/resources/resource_definitions/unit_allegiance.gd @@ -0,0 +1,12 @@ +class_name UnitAllegiance extends Resource + +enum AllegianceType { + PLAYER, + ENEMY, + PLAYER_ALLY, + ENEMY_ALLY, + UNAFFILIATED +} + +@export var type: AllegianceType +@export var color: Color diff --git a/resources/resource_definitions/unit_allegiance.gd.uid b/resources/resource_definitions/unit_allegiance.gd.uid new file mode 100644 index 0000000..636cce5 --- /dev/null +++ b/resources/resource_definitions/unit_allegiance.gd.uid @@ -0,0 +1 @@ +uid://bhglsexm8dtpj diff --git a/resources/resource_definitions/unit_info.gd b/resources/resource_definitions/unit_info.gd new file mode 100644 index 0000000..dfe341b --- /dev/null +++ b/resources/resource_definitions/unit_info.gd @@ -0,0 +1,3 @@ +class_name UnitInfo extends Resource + +@export var name: String = "Unit" diff --git a/resources/resource_definitions/unit_info.gd.uid b/resources/resource_definitions/unit_info.gd.uid new file mode 100644 index 0000000..442ec66 --- /dev/null +++ b/resources/resource_definitions/unit_info.gd.uid @@ -0,0 +1 @@ +uid://d37ulss2k0bq5 diff --git a/resources/resource_definitions/unit_stats.gd b/resources/resource_definitions/unit_stats.gd new file mode 100644 index 0000000..f235b8b --- /dev/null +++ b/resources/resource_definitions/unit_stats.gd @@ -0,0 +1,17 @@ +class_name UnitStats extends Resource + +@export var max_hp: int = 10 +@export var current_hp: int +@export var phys_atk: int = 1 +@export var phys_def: int = 1 +@export var magic_atk: int = 0 +@export var magic_def: int = 0 +@export var hit: int = 85 +@export var atk_range: int = 1 +@export var spd: int = 1 +@export var eva: int = 1 +@export var lck: int = 1 + +func _init(max_hp: int = 10) -> void: + self.max_hp = max_hp + current_hp = max_hp diff --git a/resources/resource_definitions/unit_stats.gd.uid b/resources/resource_definitions/unit_stats.gd.uid new file mode 100644 index 0000000..4485918 --- /dev/null +++ b/resources/resource_definitions/unit_stats.gd.uid @@ -0,0 +1 @@ +uid://cydoey8a8nmb8 diff --git a/scenes/combat_test.tscn b/scenes/combat_test.tscn new file mode 100644 index 0000000..eb57cc6 --- /dev/null +++ b/scenes/combat_test.tscn @@ -0,0 +1,36 @@ +[gd_scene format=3 uid="uid://wy7ur5r23ek3"] + +[ext_resource type="PackedScene" uid="uid://cy7r0udfcsqbn" path="res://prefabs/combat_ui.tscn" id="1_5jbmu"] +[ext_resource type="PackedScene" uid="uid://dkhyh5ce4iuk3" path="res://prefabs/combat_map.tscn" id="1_7abyo"] +[ext_resource type="Script" uid="uid://c8xb86ty7rduf" path="res://scripts/test_map_generator.gd" id="2_ekcfv"] +[ext_resource type="Script" uid="uid://csdcbi2gtwrly" path="res://scripts/camera_controller.gd" id="3_cam"] +[ext_resource type="Script" uid="uid://dfojm3n0em4ef" path="res://nodes/player_controller.gd" id="4_s5ga2"] +[ext_resource type="AudioStream" uid="uid://dsikulned64qt" path="res://assets/music/combat_bgm_01.OGG" id="6_0yobm"] +[ext_resource type="PackedScene" uid="uid://b6a7nlnf58mc4" path="res://prefabs/unit.tscn" id="6_rfoto"] +[ext_resource type="Resource" uid="uid://dufi2h00j5vrq" path="res://resources/allegiance_types/player_allegiance.tres" id="7_0wg56"] +[ext_resource type="Resource" uid="uid://cuc7kkknpsr1g" path="res://resources/allegiance_types/enemy_allegiance.tres" id="8_w105o"] + +[node name="CombatTest" type="Node2D" unique_id=855645983] + +[node name="CombatUI" parent="." unique_id=329168107 instance=ExtResource("1_5jbmu")] + +[node name="CombatMap" parent="." unique_id=546780706 instance=ExtResource("1_7abyo")] + +[node name="PlayerController" type="Node" parent="." unique_id=774568109 node_paths=PackedStringArray("dl_map")] +script = ExtResource("4_s5ga2") +dl_map = NodePath("../CombatMap") + +[node name="Camera2D" type="Camera2D" parent="." unique_id=1739569732] +zoom = Vector2(1.5, 1.5) +script = ExtResource("3_cam") + +[node name="TestMapGenerator" type="Node" parent="." unique_id=833658301 node_paths=PackedStringArray("dl_map")] +script = ExtResource("2_ekcfv") +dl_map = NodePath("../CombatMap") +unit_template = ExtResource("6_rfoto") +player_allegiance = ExtResource("7_0wg56") +enemy_allegiance = ExtResource("8_w105o") + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="." unique_id=1057500234] +stream = ExtResource("6_0yobm") +autoplay = true diff --git a/scenes/main_menu.tscn b/scenes/main_menu.tscn new file mode 100644 index 0000000..19b4ba6 --- /dev/null +++ b/scenes/main_menu.tscn @@ -0,0 +1,59 @@ +[gd_scene format=3 uid="uid://dlbuo46n6q238"] + +[ext_resource type="Theme" uid="uid://dx26d6py3n8xi" path="res://resources/main_ui_theme.tres" id="1_ekxnf"] +[ext_resource type="AudioStream" uid="uid://b7dgmblbcm0cj" path="res://assets/music/menu_theme.OGG" id="1_yqeox"] + +[sub_resource type="GDScript" id="GDScript_bqqt6"] +resource_name = "StartButton" +script/source = "extends Button + +func _pressed() -> void: + get_parent().queue_free() + get_tree().change_scene_to_file(\"res://scenes/combat_test.tscn\") +" + +[sub_resource type="GDScript" id="GDScript_ekxnf"] +resource_name = "ExitButton" +script/source = "extends Button + +func _pressed() -> void: + get_tree().quit(0) +" + +[node name="Menu" type="Control" unique_id=528000941] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme = ExtResource("1_ekxnf") + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="." unique_id=1976575731] +stream = ExtResource("1_yqeox") +autoplay = true + +[node name="Buttons" type="VBoxContainer" parent="." unique_id=1869378860] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +alignment = 1 + +[node name="StartButton" type="Button" parent="Buttons" unique_id=734401781] +layout_mode = 2 +text = "Start" +script = SubResource("GDScript_bqqt6") + +[node name="Options" type="Button" parent="Buttons" unique_id=1037030570] +layout_mode = 2 +text = "Options" + +[node name="ExitButton" type="Button" parent="Buttons" unique_id=1205095617] +layout_mode = 2 +text = "Exit" +script = SubResource("GDScript_ekxnf") + +[connection signal="pressed" from="Buttons/Options" to="Buttons/Options" method="_on_pressed"] diff --git a/scenes/test_scene.tscn b/scenes/test_scene.tscn new file mode 100644 index 0000000..0f53f3a --- /dev/null +++ b/scenes/test_scene.tscn @@ -0,0 +1,20 @@ +[gd_scene format=3 uid="uid://b7hhdysqqmx4y"] + +[ext_resource type="Texture2D" uid="uid://c7e4jw4xcti0q" path="res://assets/sprites/castle_spritesheet.png" id="1_g7g4h"] +[ext_resource type="Shader" uid="uid://dakre5usldk6r" path="res://shaders/masked_palette_swap.gdshader" id="1_nd71p"] +[ext_resource type="Texture2D" uid="uid://b8td6sv5re6r8" path="res://assets/sprites/grey_castle_spritesheet_mask.bmp" id="2_7ddre"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_qjeyg"] +shader = ExtResource("1_nd71p") +shader_parameter/flag_mask = ExtResource("2_7ddre") +shader_parameter/team_color = Color(0.84830123, 0.29993045, 0.292207, 1) + +[sub_resource type="AtlasTexture" id="AtlasTexture_j8ivh"] +atlas = ExtResource("1_g7g4h") +region = Rect2(0, 100, 100, 100) + +[node name="TestScene" type="Node2D" unique_id=1687841395] + +[node name="Sprite2D" type="Sprite2D" parent="." unique_id=1997336331] +material = SubResource("ShaderMaterial_qjeyg") +texture = SubResource("AtlasTexture_j8ivh") diff --git a/scripts/camera_controller.gd b/scripts/camera_controller.gd new file mode 100644 index 0000000..5dbfac1 --- /dev/null +++ b/scripts/camera_controller.gd @@ -0,0 +1,42 @@ +class_name CameraController extends Camera2D + +const DRAG_THRESHOLD := 8.0 + +var _dragging := false +var _left_pending := false +var _drag_start := Vector2.ZERO + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouseButton: + match event.button_index: + MOUSE_BUTTON_LEFT: + if event.pressed: + _left_pending = true + _drag_start = event.position + else: + _left_pending = false + if _dragging: + _dragging = false + Input.set_default_cursor_shape(Input.CURSOR_ARROW) + get_viewport().set_input_as_handled() + MOUSE_BUTTON_MIDDLE: + if event.pressed: + _dragging = true + _drag_start = event.position + Input.set_default_cursor_shape(Input.CURSOR_DRAG) + else: + _dragging = false + Input.set_default_cursor_shape(Input.CURSOR_ARROW) + get_viewport().set_input_as_handled() + elif event is InputEventMouseMotion: + if _left_pending and not _dragging: + if event.position.distance_to(_drag_start) >= DRAG_THRESHOLD: + _dragging = true + _left_pending = false + Input.set_default_cursor_shape(Input.CURSOR_DRAG) + if _dragging: + var delta: Vector2 = _drag_start - event.position + _drag_start = event.position + position += delta / zoom + get_viewport().set_input_as_handled() diff --git a/scripts/camera_controller.gd.uid b/scripts/camera_controller.gd.uid new file mode 100644 index 0000000..0937bb3 --- /dev/null +++ b/scripts/camera_controller.gd.uid @@ -0,0 +1 @@ +uid://csdcbi2gtwrly diff --git a/scripts/combat_ui.gd b/scripts/combat_ui.gd new file mode 100644 index 0000000..6b8b53a --- /dev/null +++ b/scripts/combat_ui.gd @@ -0,0 +1,33 @@ +class_name CombatUI extends CanvasLayer + +@onready var unit_panel: PanelContainer = %UnitPanel +@onready var name_label: Label = %NameLabel +@onready var hp_bar: ProgressBar = %HPBar + +var _selected_unit: Unit + +func _ready() -> void: + unit_panel.visible = false + for unit: Unit in get_tree().get_nodes_in_group("units"): + unit.unit_selected_changed.connect(_on_unit_selected_changed) + get_tree().node_added.connect(_on_node_added) + +func _on_node_added(node: Node) -> void: + if node is Unit and node.is_in_group("units"): + node.unit_selected_changed.connect(_on_unit_selected_changed) + +func _process(_delta: float) -> void: + if _selected_unit: + hp_bar.max_value = _selected_unit.current_stats.max_hp + hp_bar.value = _selected_unit.current_stats.current_hp + +func _on_unit_selected_changed(unit: Unit, selected: bool) -> void: + if selected: + _selected_unit = unit + name_label.text = unit.current_info.name + hp_bar.max_value = unit.current_stats.max_hp + hp_bar.value = unit.current_stats.current_hp + unit_panel.visible = true + else: + _selected_unit = null + unit_panel.visible = false diff --git a/scripts/combat_ui.gd.uid b/scripts/combat_ui.gd.uid new file mode 100644 index 0000000..5239432 --- /dev/null +++ b/scripts/combat_ui.gd.uid @@ -0,0 +1 @@ +uid://w2wh6gtv3u2l diff --git a/scripts/grid_overlay.gd b/scripts/grid_overlay.gd new file mode 100644 index 0000000..cb74cbd --- /dev/null +++ b/scripts/grid_overlay.gd @@ -0,0 +1,16 @@ +class_name GridOverlay extends TileMapLayer + +const SOURCE_ID = 0 +const HIGHLIGHT_SPRITE_ID = Vector2i(0,0) + +@onready var targeting_selector: Sprite2D = $TargetingIndicator + +func highlight_tile(coords: Vector2i) -> void: + set_cell(coords, SOURCE_ID, HIGHLIGHT_SPRITE_ID) + +func clear_tile(coords: Vector2i) -> void: + set_cell(coords) + +func target_tile(coords: Vector2i) -> void: + targeting_selector.position = coords * tile_set.tile_size + targeting_selector.visible = true diff --git a/scripts/grid_overlay.gd.uid b/scripts/grid_overlay.gd.uid new file mode 100644 index 0000000..a7d4181 --- /dev/null +++ b/scripts/grid_overlay.gd.uid @@ -0,0 +1 @@ +uid://cxl38x2m6sj3w diff --git a/scripts/test_map_generator.gd b/scripts/test_map_generator.gd new file mode 100644 index 0000000..e461b12 --- /dev/null +++ b/scripts/test_map_generator.gd @@ -0,0 +1,38 @@ +extends Node + +const GRID_SIZE := 5 + +@export var dl_map: CombatMap +@export var unit_template: PackedScene +@export var player_allegiance: UnitAllegiance +@export var enemy_allegiance: UnitAllegiance + +func _ready() -> void: + for x in GRID_SIZE: + for y in GRID_SIZE: + var pos := Vector2i(x, y) + var is_edge := x == 0 or x == GRID_SIZE - 1 or y == 0 or y == GRID_SIZE - 1 + if is_edge: + dl_map.draw_wall(pos) + else: + dl_map.draw_floor(pos) + + # Create a putit at the center belonging to the player + var center := Vector2i(GRID_SIZE / 2, GRID_SIZE / 2) + var unit: Unit = unit_template.instantiate() + unit.stat_template = UnitStats.new(50) + unit.info_template = UnitInfo.new() + unit.allegiance_template = player_allegiance + unit.info_template.name = "Putit" + unit.position = dl_map.coords_to_world(center) + get_parent().add_child.call_deferred(unit) + + # Create a putit at one above the center belonging to the enemy + var center_enemy := Vector2i(GRID_SIZE / 2, (GRID_SIZE / 2) - 1) + var enemy_unit: Unit = unit_template.instantiate() + enemy_unit.stat_template = UnitStats.new(50) + enemy_unit.info_template = UnitInfo.new() + enemy_unit.allegiance_template = enemy_allegiance + enemy_unit.info_template.name = "Putit" + enemy_unit.position = dl_map.coords_to_world(center_enemy) + get_parent().add_child.call_deferred(enemy_unit) diff --git a/scripts/test_map_generator.gd.uid b/scripts/test_map_generator.gd.uid new file mode 100644 index 0000000..060435a --- /dev/null +++ b/scripts/test_map_generator.gd.uid @@ -0,0 +1 @@ +uid://c8xb86ty7rduf diff --git a/scripts/tile_highlight.gd b/scripts/tile_highlight.gd new file mode 100644 index 0000000..bf82c3a --- /dev/null +++ b/scripts/tile_highlight.gd @@ -0,0 +1,37 @@ +extends ColorRect + +signal tile_hovered(coords: Vector2i) + +@export var tile_size: float = 48.0 + +var _time: float = 0.0 +var _previous_coords := Vector2i(INF, INF) + + +func _ready() -> void: + size = Vector2(tile_size, tile_size) + color = Color(1.0, 1.0, 1.0, 0.25) + mouse_filter = Control.MOUSE_FILTER_IGNORE + + +func _process(delta: float) -> void: + _time += delta + color.a = 0.25 + 0.1 * sin(_time * 4.0) + var mouse_pos := get_global_mouse_position() + var snapped_pos := _snap_to_grid(mouse_pos) + global_position = snapped_pos + var coords := Vector2i(snapped_pos / tile_size) + if coords != _previous_coords: + _previous_coords = coords + tile_hovered.emit(coords) + + +func _notification(what: int) -> void: + if what == NOTIFICATION_WM_MOUSE_EXIT: + hide() + elif what == NOTIFICATION_WM_MOUSE_ENTER: + show() + + +func _snap_to_grid(pos: Vector2) -> Vector2: + return Vector2(floorf(pos.x / tile_size), floorf(pos.y / tile_size)) * tile_size diff --git a/scripts/tile_highlight.gd.uid b/scripts/tile_highlight.gd.uid new file mode 100644 index 0000000..df93734 --- /dev/null +++ b/scripts/tile_highlight.gd.uid @@ -0,0 +1 @@ +uid://b31eyqov8w7bm diff --git a/shaders/chroma_key.gdshader b/shaders/chroma_key.gdshader new file mode 100644 index 0000000..dc7aed4 --- /dev/null +++ b/shaders/chroma_key.gdshader @@ -0,0 +1,12 @@ +shader_type canvas_item; + +uniform float threshold : hint_range(0.0, 1.0) = 0.01; + +void fragment() { + vec4 tex_color = texture(TEXTURE, UV); + float brightness = max(tex_color.r, max(tex_color.g, tex_color.b)); + if (brightness < threshold) { + discard; + } + COLOR = tex_color; +} diff --git a/shaders/chroma_key.gdshader.uid b/shaders/chroma_key.gdshader.uid new file mode 100644 index 0000000..da067a1 --- /dev/null +++ b/shaders/chroma_key.gdshader.uid @@ -0,0 +1 @@ +uid://bd8ki8xwym5nc diff --git a/shaders/masked_palette_swap.gdshader b/shaders/masked_palette_swap.gdshader new file mode 100644 index 0000000..05f501e --- /dev/null +++ b/shaders/masked_palette_swap.gdshader @@ -0,0 +1,16 @@ +shader_type canvas_item; + +uniform sampler2D flag_mask : source_color, hint_default_black; +uniform vec4 team_color : source_color = vec4(1.0, 0.0, 0.0, 1.0); // red by default + +void fragment() { + vec4 base = texture(TEXTURE, UV); + float mask = texture(flag_mask, UV).r; // 1.0 on flag pixels, 0.0 on castle + + // Use the grey luminance as a brightness multiplier on the team color + float brightness = base.r; // grey means R == G == B + vec4 tinted = vec4(team_color.rgb * brightness * 2.0, base.a); + + // Blend: castle pixels stay grey, flag pixels get tinted + COLOR = mix(base, tinted, mask); +} \ No newline at end of file diff --git a/shaders/masked_palette_swap.gdshader.uid b/shaders/masked_palette_swap.gdshader.uid new file mode 100644 index 0000000..baa051e --- /dev/null +++ b/shaders/masked_palette_swap.gdshader.uid @@ -0,0 +1 @@ +uid://dakre5usldk6r