Initial commit
4
.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Normalize EOL for all files that Git considers text files.
|
||||||
|
* text=auto eol=lf
|
||||||
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Godot 4+ specific ignores
|
||||||
|
.godot/
|
||||||
|
/android/
|
||||||
BIN
assets/editor/unit_node.bmp
Normal file
|
After Width: | Height: | Size: 822 B |
40
assets/editor/unit_node.bmp.import
Normal file
@@ -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
|
||||||
BIN
assets/editor/unit_node.png
Normal file
|
After Width: | Height: | Size: 232 B |
40
assets/editor/unit_node.png.import
Normal file
@@ -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
|
||||||
BIN
assets/fonts/Minecraft.ttf
Normal file
36
assets/fonts/Minecraft.ttf.import
Normal file
@@ -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={}
|
||||||
BIN
assets/music/combat_bgm_01.OGG
Normal file
19
assets/music/combat_bgm_01.OGG.import
Normal file
@@ -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
|
||||||
BIN
assets/music/menu_theme.OGG
Normal file
19
assets/music/menu_theme.OGG.import
Normal file
@@ -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
|
||||||
BIN
assets/sprites/castle_spritesheet.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
40
assets/sprites/castle_spritesheet.png.import
Normal file
@@ -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
|
||||||
BIN
assets/sprites/character.bmp
Normal file
|
After Width: | Height: | Size: 5.4 MiB |
40
assets/sprites/character.bmp.import
Normal file
@@ -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
|
||||||
BIN
assets/sprites/flag.png
Normal file
|
After Width: | Height: | Size: 182 B |
40
assets/sprites/flag.png.import
Normal file
@@ -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
|
||||||
BIN
assets/sprites/grey_castle_spritesheet_mask.bmp
Normal file
|
After Width: | Height: | Size: 59 KiB |
40
assets/sprites/grey_castle_spritesheet_mask.bmp.import
Normal file
@@ -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
|
||||||
BIN
assets/sprites/grid_highlight.png
Normal file
|
After Width: | Height: | Size: 291 B |
40
assets/sprites/grid_highlight.png.import
Normal file
@@ -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
|
||||||
BIN
assets/sprites/map1.bmp
Normal file
|
After Width: | Height: | Size: 5.4 MiB |
40
assets/sprites/map1.bmp.import
Normal file
@@ -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
|
||||||
BIN
assets/sprites/selector.png
Normal file
|
After Width: | Height: | Size: 137 B |
40
assets/sprites/selector.png.import
Normal file
@@ -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
|
||||||
77
code_review_findings.md
Normal file
@@ -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 |
|
||||||
205
docs/superpowers/plans/2026-04-01-combat-ui-unit-panel.md
Normal file
@@ -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"
|
||||||
|
```
|
||||||
@@ -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.
|
||||||
1
icon.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 995 B |
43
icon.svg.import
Normal file
@@ -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
|
||||||
39
nodes/combat_map.gd
Normal file
@@ -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)
|
||||||
1
nodes/combat_map.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bks7uplgjjdg0
|
||||||
80
nodes/player_controller.gd
Normal file
@@ -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
|
||||||
1
nodes/player_controller.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dfojm3n0em4ef
|
||||||
23
nodes/unit.gd
Normal file
@@ -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)
|
||||||
1
nodes/unit.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://c016mxgatcpse
|
||||||
54
prefabs/combat_map.tscn
Normal file
@@ -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"]
|
||||||
42
prefabs/combat_ui.tscn
Normal file
@@ -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
|
||||||
57
prefabs/unit.tscn
Normal file
@@ -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"]
|
||||||
26
project.godot
Normal file
@@ -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"
|
||||||
9
resources/allegiance_types/enemy_allegiance.tres
Normal file
@@ -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"
|
||||||
8
resources/allegiance_types/player_allegiance.tres
Normal file
@@ -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"
|
||||||
836
resources/combat_tileset.tres
Normal file
@@ -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")
|
||||||
6
resources/main_ui_theme.tres
Normal file
@@ -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")
|
||||||
4
resources/resource_definitions/dl_tileset.gd
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
class_name DLTileset extends Resource
|
||||||
|
|
||||||
|
@export var floor_tile_coords: Vector2i
|
||||||
|
@export var wall_tile_coords: Vector2i
|
||||||
1
resources/resource_definitions/dl_tileset.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://c6701vy8h5rfx
|
||||||
12
resources/resource_definitions/unit_allegiance.gd
Normal file
@@ -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
|
||||||
1
resources/resource_definitions/unit_allegiance.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bhglsexm8dtpj
|
||||||
3
resources/resource_definitions/unit_info.gd
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
class_name UnitInfo extends Resource
|
||||||
|
|
||||||
|
@export var name: String = "Unit"
|
||||||
1
resources/resource_definitions/unit_info.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://d37ulss2k0bq5
|
||||||
17
resources/resource_definitions/unit_stats.gd
Normal file
@@ -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
|
||||||
1
resources/resource_definitions/unit_stats.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cydoey8a8nmb8
|
||||||
36
scenes/combat_test.tscn
Normal file
@@ -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
|
||||||
59
scenes/main_menu.tscn
Normal file
@@ -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"]
|
||||||
20
scenes/test_scene.tscn
Normal file
@@ -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")
|
||||||
42
scripts/camera_controller.gd
Normal file
@@ -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()
|
||||||
1
scripts/camera_controller.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://csdcbi2gtwrly
|
||||||
33
scripts/combat_ui.gd
Normal file
@@ -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
|
||||||
1
scripts/combat_ui.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://w2wh6gtv3u2l
|
||||||
16
scripts/grid_overlay.gd
Normal file
@@ -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
|
||||||
1
scripts/grid_overlay.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cxl38x2m6sj3w
|
||||||
38
scripts/test_map_generator.gd
Normal file
@@ -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)
|
||||||
1
scripts/test_map_generator.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://c8xb86ty7rduf
|
||||||
37
scripts/tile_highlight.gd
Normal file
@@ -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
|
||||||
1
scripts/tile_highlight.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://b31eyqov8w7bm
|
||||||
12
shaders/chroma_key.gdshader
Normal file
@@ -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;
|
||||||
|
}
|
||||||
1
shaders/chroma_key.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bd8ki8xwym5nc
|
||||||
16
shaders/masked_palette_swap.gdshader
Normal file
@@ -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);
|
||||||
|
}
|
||||||
1
shaders/masked_palette_swap.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dakre5usldk6r
|
||||||