Refactor Debug menu, and add Party Menu for saves

This commit is contained in:
Luke Hubmayer-Werner 2023-12-06 16:32:40 +10:30
parent 48c6ed2c3b
commit 923e2f463e
22 changed files with 306 additions and 145 deletions

View File

@ -16,7 +16,7 @@ script_encryption_key=""
custom_template/debug="" custom_template/debug=""
custom_template/release="" custom_template/release=""
variant/export_type=0 variant/export_type=0
vram_texture_compression/for_desktop=true vram_texture_compression/for_desktop=false
vram_texture_compression/for_mobile=false vram_texture_compression/for_mobile=false
html/export_icon=true html/export_icon=true
html/custom_html_shell="" html/custom_html_shell=""

View File

@ -2,6 +2,43 @@ extends Node
const INDEX_FORMAT := Image.FORMAT_L8 const INDEX_FORMAT := Image.FORMAT_L8
enum Menu {
LOADER,
MAIN,
LOAD_SAVE,
WORLD_MAP,
FIELD_MAP,
PARTY,
SHOP,
BATTLE,
DEBUG,
DEBUG_AUDIO_SYSTEM,
DEBUG_BATTLE_SPRITES,
}
const MENUS = {
Menu.PARTY: ['res://widgets/PartyMenu.tscn', 'Party Menu'],
Menu.BATTLE: ['res://widgets/BattleScene.tscn', 'Battle'],
Menu.LOAD_SAVE: ['res://widgets/SaveSlotSelect.tscn', 'Load Save'],
Menu.DEBUG: ['res://test/debug_menu.tscn', 'Debug Menu'],
Menu.DEBUG_BATTLE_SPRITES: ['res://test/battle_sprites.tscn', 'Battle Sprites'],
Menu.DEBUG_AUDIO_SYSTEM: ['res://test/audio_system.tscn', 'Audio'],
Menu.WORLD_MAP: ['res://test/worldmap_system.tscn', 'World Map'],
}
const INITIAL_MENUS = [
Menu.LOAD_SAVE,
]
const POST_ROM_MENUS = [
Menu.DEBUG,
Menu.WORLD_MAP,
Menu.PARTY,
Menu.BATTLE,
Menu.DEBUG_BATTLE_SPRITES,
Menu.DEBUG_AUDIO_SYSTEM,
]
const FOLDER_ICON := preload('res://theme/icons/file_folder.tres') const FOLDER_ICON := preload('res://theme/icons/file_folder.tres')
const ALLOWED_EXTS := PoolStringArray(['bin', 'iso', 'sfc', 'smc', 'srm', 'gba']) const ALLOWED_EXTS := PoolStringArray(['bin', 'iso', 'sfc', 'smc', 'srm', 'gba'])
const CD_EXTS := PoolStringArray(['bin', 'iso']) # If you have a weird disc image format, you can mount it yourself, leave me out of it const CD_EXTS := PoolStringArray(['bin', 'iso']) # If you have a weird disc image format, you can mount it yourself, leave me out of it

55
main.gd
View File

@ -1,43 +1,46 @@
extends Control extends Control
#warning-ignore-all:return_value_discarded
enum Menu { const globals = preload('res://globals.gd') # Make LSP shut up about non-const
LOADER, const Menu = globals.Menu
MAIN, var packed_menus = {}
LOAD_SAVE,
WORLD_MAP,
FIELD_MAP,
PARTY,
SHOP,
BATTLE,
DEBUG,
DEBUG_AUDIO_SYSTEM,
DEBUG_BATTLE_SPRITES,
}
var menus = {} var menus = {}
var active_menu_stack = [] var active_menu_stack = []
func instantiate_menu_list(menu_list) -> void:
for key in menu_list:
packed_menus[key] = load(globals.MENUS[key][0])
menus[key] = packed_menus[key].instance()
var is_rom_loaded := false var is_rom_loaded := false
func _rom_loaded() -> void: func _on_rom_loaded() -> void:
menus[Menu.PARTY] = preload('res://widgets/PartyMenu.tscn').instance() instantiate_menu_list(globals.POST_ROM_MENUS)
menus[Menu.WORLD_MAP] = preload('res://test/worldmap_system.tscn').instance() menus[Menu.DEBUG].connect('button_pressed', self, 'push_menu')
menus[Menu.DEBUG] = preload('res://test/debug_menu.tscn').instance()
menus[Menu.DEBUG].connect('pressed_worldmap', self, 'push_menu', [Menu.WORLD_MAP])
menus[Menu.DEBUG].connect('pressed_party', self, 'push_menu', [Menu.PARTY])
menus[Menu.DEBUG].connect('pressed_battle_sprites', self, 'push_menu', [Menu.DEBUG_BATTLE_SPRITES])
menus[Menu.DEBUG].connect('pressed_audio', self, 'push_menu', [Menu.DEBUG_AUDIO_SYSTEM])
menus[Menu.DEBUG_AUDIO_SYSTEM] = preload('res://test/audio_system.tscn').instance()
menus[Menu.DEBUG_BATTLE_SPRITES] = preload('res://test/battle_sprites.tscn').instance()
is_rom_loaded = true is_rom_loaded = true
var is_savefile_loaded := false
func _on_savefile_loaded(dicts) -> void:
push_menu(Menu.LOAD_SAVE)
menus[Menu.LOAD_SAVE].set_data(dicts)
menus[Menu.LOAD_SAVE].connect('slot_activated', self, '_on_saveslot_loaded')
func _on_saveslot_loaded(dict) -> void:
push_menu(Menu.PARTY)
menus[Menu.PARTY].update_labels(dict)
func _ready() -> void: func _ready() -> void:
if OS.get_name() != 'HTML5' or !OS.has_feature('JavaScript'): if OS.get_name() != 'HTML5' or !OS.has_feature('JavaScript'):
menus[Menu.LOADER] = preload('res://widgets/RomSelect.tscn').instance() packed_menus[Menu.LOADER] = preload('res://widgets/RomSelect.tscn')
else: else:
menus[Menu.LOADER] = preload('res://widgets/WebFileSelect.tscn').instance() packed_menus[Menu.LOADER] = preload('res://widgets/WebFileSelect.tscn')
menus[Menu.LOADER] = packed_menus[Menu.LOADER].instance()
push_menu(Menu.LOADER) push_menu(Menu.LOADER)
RomLoader.connect('rom_loaded', self, '_rom_loaded') instantiate_menu_list(globals.INITIAL_MENUS)
RomLoader.connect('rom_loaded', self, '_on_rom_loaded')
menus[Menu.LOADER].connect('continue_pressed', self, 'push_debug_menu') menus[Menu.LOADER].connect('continue_pressed', self, 'push_debug_menu')
menus[Menu.LOADER].connect('savefile_loaded', self, '_on_savefile_loaded')
Common.update_window_scale() Common.update_window_scale()
func push_debug_menu(): func push_debug_menu():

View File

@ -1,7 +1,6 @@
[gd_scene load_steps=4 format=2] [gd_scene load_steps=3 format=2]
[ext_resource path="res://theme/menu_theme.tres" type="Theme" id=1] [ext_resource path="res://theme/menu_theme.tres" type="Theme" id=1]
[ext_resource path="res://widgets/ColorMenu.tscn" type="PackedScene" id=4]
[ext_resource path="res://main.gd" type="Script" id=5] [ext_resource path="res://main.gd" type="Script" id=5]
[node name="main" type="Control"] [node name="main" type="Control"]
@ -11,7 +10,3 @@ margin_right = -640.0
margin_bottom = -360.0 margin_bottom = -360.0
theme = ExtResource( 1 ) theme = ExtResource( 1 )
script = ExtResource( 5 ) script = ExtResource( 5 )
[node name="ColorMenu" parent="." instance=ExtResource( 4 )]
margin_left = 384.0
margin_right = 469.0

View File

@ -66,5 +66,7 @@ texture={
quality/driver/driver_name="GLES2" quality/driver/driver_name="GLES2"
2d/snapping/use_gpu_pixel_snap=true 2d/snapping/use_gpu_pixel_snap=true
vram_compression/import_s3tc=false
vram_compression/import_etc2=false
environment/default_clear_color=Color( 0, 0, 0, 1 ) environment/default_clear_color=Color( 0, 0, 0, 1 )
environment/default_environment="res://default_env.tres" environment/default_environment="res://default_env.tres"

View File

@ -1,4 +1,5 @@
extends Node extends Node
#warning-ignore-all:return_value_discarded
signal rom_loaded signal rom_loaded

View File

@ -121,6 +121,39 @@ func get_save_slot(sram: File, slot_id: int) -> StreamPeerBuffer:
buffer.set_data_array(sram.get_buffer(0x700)) buffer.set_data_array(sram.get_buffer(0x700))
return buffer return buffer
func load_save_dicts_from_buffer(sram: StreamPeerBuffer) -> Array:
# Pulls four lots of 0x700 bytes from the current buffer position
var dicts := []
var slot_buffer := StreamPeerBuffer.new()
for slot_id in 4:
slot_buffer.set_data_array(sram.get_data(0x700)[1])
slot_buffer.seek(0)
dicts.append(load_save_slot(slot_buffer))
# Won't seek just in case
sram.get_data(0x1FF8-0x1C00)
for slot_id in 4:
dicts[slot_id].slot_in_use = (sram.get_u16() == SLOT_IN_USE)
return dicts
func load_save_dicts_from_bytes(sram: PoolByteArray) -> Array:
var buffer := StreamPeerBuffer.new()
buffer.set_data_array(sram)
return load_save_dicts_from_buffer(buffer)
func load_save_dicts_from_file(sram: File) -> Array:
# Pulls four lots of 0x700 bytes from the current buffer position
var dicts := []
var slot_buffer := StreamPeerBuffer.new()
for slot_id in 4:
slot_buffer.set_data_array(sram.get_buffer(0x700))
slot_buffer.seek(0)
dicts.append(load_save_slot(slot_buffer))
# Won't seek just in case
sram.get_buffer(0x1FF8-0x1C00)
for slot_id in 4:
dicts[slot_id].slot_in_use = (sram.get_16() == SLOT_IN_USE)
return dicts
func save_slot(sram: File, slot_id: int, slot: StreamPeerBuffer): func save_slot(sram: File, slot_id: int, slot: StreamPeerBuffer):
sram.seek(0x700 * slot_id) sram.seek(0x700 * slot_id)
sram.store_buffer(slot.data_array) sram.store_buffer(slot.data_array)

View File

@ -1,4 +1,5 @@
extends Node extends Node
const globals = preload('res://globals.gd') # Make LSP shut up about non-const
# Portability for GLES2 vs GLES3 stuff # Portability for GLES2 vs GLES3 stuff
const INDEX_FORMAT := globals.INDEX_FORMAT const INDEX_FORMAT := globals.INDEX_FORMAT

View File

@ -1,3 +1,4 @@
const globals = preload('res://globals.gd') # Make LSP shut up about non-const
const INDEX_FORMAT := globals.INDEX_FORMAT const INDEX_FORMAT := globals.INDEX_FORMAT
static func ByteArray(size: int) -> PoolByteArray: static func ByteArray(size: int) -> PoolByteArray:

View File

@ -1,3 +1,4 @@
const globals = preload('res://globals.gd') # Make LSP shut up about non-const
var INDEX_FORMAT := globals.INDEX_FORMAT var INDEX_FORMAT := globals.INDEX_FORMAT
static func ByteArray(size: int) -> PoolByteArray: static func ByteArray(size: int) -> PoolByteArray:

View File

@ -1,18 +1,18 @@
extends Control extends Control
#warning-ignore-all:return_value_discarded
signal pressed_worldmap signal button_pressed(menu)
signal pressed_party
signal pressed_battle_sprites
signal pressed_audio
func _on_btn_worldmap_pressed() -> void: onready var buttons := $'%buttons'
emit_signal('pressed_worldmap') func _ready() -> void:
for key in globals.POST_ROM_MENUS:
if key == globals.Menu.DEBUG:
continue
var menu = globals.MENUS[key]
var btn := Button.new()
btn.text = menu[1]
btn.connect('pressed', self, '_on_btn_pressed', [key])
buttons.add_child(btn)
func _on_btn_party_pressed() -> void: func _on_btn_pressed(menu) -> void:
emit_signal('pressed_party') emit_signal('button_pressed', menu)
func _on_btn_battle_sprites_pressed() -> void:
emit_signal('pressed_battle_sprites')
func _on_btn_audio_pressed() -> void:
emit_signal('pressed_audio')

View File

@ -16,9 +16,9 @@ anchor_bottom = 1.0
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"] [node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
margin_left = 110.0 margin_left = 110.0
margin_top = 45.0 margin_top = 101.0
margin_right = 273.0 margin_right = 273.0
margin_bottom = 194.0 margin_bottom = 138.0
[node name="Label" type="Label" parent="CenterContainer/VBoxContainer"] [node name="Label" type="Label" parent="CenterContainer/VBoxContainer"]
margin_right = 163.0 margin_right = 163.0
@ -27,31 +27,9 @@ text = "DEBUG MENU
Press [backspace] to return" Press [backspace] to return"
align = 1 align = 1
[node name="btn_worldmap" type="Button" parent="CenterContainer/VBoxContainer"] [node name="buttons" type="GridContainer" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
margin_top = 37.0 margin_top = 37.0
margin_right = 163.0 margin_right = 163.0
margin_bottom = 59.0 margin_bottom = 37.0
text = "World Map" columns = 2
[node name="btn_party" type="Button" parent="CenterContainer/VBoxContainer"]
margin_top = 67.0
margin_right = 163.0
margin_bottom = 89.0
text = "Party Menu"
[node name="btn_battle_sprites" type="Button" parent="CenterContainer/VBoxContainer"]
margin_top = 97.0
margin_right = 163.0
margin_bottom = 119.0
text = "Battle Sprites"
[node name="btn_audio" type="Button" parent="CenterContainer/VBoxContainer"]
margin_top = 127.0
margin_right = 163.0
margin_bottom = 149.0
text = "Audio"
[connection signal="pressed" from="CenterContainer/VBoxContainer/btn_worldmap" to="." method="_on_btn_worldmap_pressed"]
[connection signal="pressed" from="CenterContainer/VBoxContainer/btn_party" to="." method="_on_btn_party_pressed"]
[connection signal="pressed" from="CenterContainer/VBoxContainer/btn_battle_sprites" to="." method="_on_btn_battle_sprites_pressed"]
[connection signal="pressed" from="CenterContainer/VBoxContainer/btn_audio" to="." method="_on_btn_audio_pressed"]

View File

@ -1,10 +1,26 @@
extends Control extends Control
#warning-ignore-all:return_value_discarded
const palette_mat := preload('res://palette_mat.tres') const palette_mat := preload('res://palette_mat.tres')
var save_slots = [] var save_slots = []
var save_slot_dicts = [] var save_slot_dicts = []
func _ready(): func _ready():
Engine.set_target_fps(60) RomLoader.connect('rom_loaded', self, '_on_rom_loaded')
# RomLoader.load_snes_rom('/home/luke/code/FF/ffv romhacks/Final Fantasy V (Japan).sfc')
RomLoader.load_snes_rom('/home/luke/code/FF/ffv romhacks/Final Fantasy V (Japan) [En by RPGe v1.1].sfc')
func _on_rom_loaded():
party_menu()
# monster_sprites()
# battle_bgs()
# jobs_and_abilities()
func party_menu():
var PartyMenu = preload('res://widgets/PartyMenu.tscn').instance()
# PartyMenu.margin_right = 320.0
PartyMenu.margin_right = 384.0
add_child(PartyMenu)
var save_file := File.new() var save_file := File.new()
#var error := save_file.open('test.srm', File.READ) #var error := save_file.open('test.srm', File.READ)
var error := save_file.open('/home/luke/.config/Mesen2/Saves/FF5_SCC_WepTweaks_Inus_Dash.srm', File.READ) var error := save_file.open('/home/luke/.config/Mesen2/Saves/FF5_SCC_WepTweaks_Inus_Dash.srm', File.READ)
@ -22,9 +38,10 @@ func _ready():
# save_slot_dicts.append(SaveLoader.get_struct(buffer, 'Save_slot')) # save_slot_dicts.append(SaveLoader.get_struct(buffer, 'Save_slot'))
var data = save_slot_dicts[0] var data = save_slot_dicts[0]
data.characters[2].equipped_abilities[3] = 0x9B data.characters[2].equipped_abilities[3] = 0x9B
$PartyMenu.update_labels(data) PartyMenu.update_labels(data)
ThemeManager.set_menu_color_555(data.config.menu_color_r, data.config.menu_color_g, data.config.menu_color_b) ThemeManager.set_menu_color_555(data.config.menu_color_r, data.config.menu_color_g, data.config.menu_color_b)
func monster_sprites():
var monster_box := GridContainer.new() var monster_box := GridContainer.new()
monster_box.columns = 8 monster_box.columns = 8
add_child(monster_box) add_child(monster_box)
@ -35,6 +52,7 @@ func _ready():
t.material.set_shader_param('palette', mon.palette) t.material.set_shader_param('palette', mon.palette)
monster_box.add_child(t) monster_box.add_child(t)
func battle_bgs():
var bbg := SpinBox.new() var bbg := SpinBox.new()
bbg.max_value = len(SpriteLoader.battle_backgrounds) - 1 bbg.max_value = len(SpriteLoader.battle_backgrounds) - 1
bbg.connect('value_changed', $BattleScene, 'set_bg') bbg.connect('value_changed', $BattleScene, 'set_bg')
@ -43,13 +61,12 @@ func _ready():
bbg.align = LineEdit.ALIGN_RIGHT bbg.align = LineEdit.ALIGN_RIGHT
add_child(bbg) add_child(bbg)
# var lbl = Label.new() func jobs_and_abilities():
# for i in 22: var lbl = Label.new()
# lbl.text = lbl.text + '%s - %s\n' % [StringLoader.get_job_name(i), StringLoader.get_job_desc(i)] for i in 22:
# for i in 78: lbl.text = lbl.text + '%s - %s\n' % [StringLoader.get_job_name(i), StringLoader.get_job_desc(i)]
# lbl.text = lbl.text + '\n%s - %s' % [StringLoader.get_ability_name(i), StringLoader.get_ability_desc(i)] for i in 78:
# for i in range(128, 161): lbl.text = lbl.text + '\n%s - %s' % [StringLoader.get_ability_name(i), StringLoader.get_ability_desc(i)]
# lbl.text = lbl.text + '\n%s - %s' % [StringLoader.get_ability_name(i), StringLoader.get_ability_desc(i)] for i in range(128, 161):
# add_child(lbl) lbl.text = lbl.text + '\n%s - %s' % [StringLoader.get_ability_name(i), StringLoader.get_ability_desc(i)]
add_child(lbl)

View File

@ -1,32 +1,10 @@
[gd_scene load_steps=8 format=2] [gd_scene load_steps=3 format=2]
[ext_resource path="res://widgets/PartyMenu.tscn" type="PackedScene" id=1]
[ext_resource path="res://test/worldmap_system.tscn" type="PackedScene" id=2]
[ext_resource path="res://test_scene.gd" type="Script" id=3] [ext_resource path="res://test_scene.gd" type="Script" id=3]
[ext_resource path="res://test/battle_sprites.tscn" type="PackedScene" id=4]
[ext_resource path="res://test/audio_system.tscn" type="PackedScene" id=5]
[ext_resource path="res://theme/menu_theme.tres" type="Theme" id=6] [ext_resource path="res://theme/menu_theme.tres" type="Theme" id=6]
[ext_resource path="res://widgets/BattleScene.tscn" type="PackedScene" id=7]
[node name="Control" type="Control"] [node name="test_scene" type="Control"]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
theme = ExtResource( 6 ) theme = ExtResource( 6 )
script = ExtResource( 3 ) script = ExtResource( 3 )
[node name="audio_system" parent="." instance=ExtResource( 5 )]
position = Vector2( 0, 160 )
[node name="worldmap_system" parent="." instance=ExtResource( 2 )]
visible = false
position = Vector2( -600, -550 )
[node name="battle_sprites" parent="." instance=ExtResource( 4 )]
visible = false
[node name="PartyMenu" parent="." instance=ExtResource( 1 )]
visible = false
margin_right = 320.0
[node name="BattleScene" parent="." instance=ExtResource( 7 )]
visible = false

View File

@ -37,15 +37,15 @@ margin_bottom = 224.0
anchor_left = 1.0 anchor_left = 1.0
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
margin_left = -72.0 margin_left = -64.0
size_flags_horizontal = 8 size_flags_horizontal = 8
size_flags_vertical = 8 size_flags_vertical = 8
custom_constants/separation = 0 custom_constants/separation = 0
alignment = 2 alignment = 2
[node name="panel_menu" type="PanelContainer" parent="rightside"] [node name="panel_menu" type="PanelContainer" parent="rightside"]
margin_left = 16.0 margin_left = 8.0
margin_right = 72.0 margin_right = 64.0
margin_bottom = 36.0 margin_bottom = 36.0
rect_min_size = Vector2( 56, 0 ) rect_min_size = Vector2( 56, 0 )
size_flags_horizontal = 8 size_flags_horizontal = 8
@ -69,9 +69,9 @@ margin_bottom = 28.0
text = "Ability" text = "Ability"
[node name="panel_menu2" type="PanelContainer" parent="rightside"] [node name="panel_menu2" type="PanelContainer" parent="rightside"]
margin_left = 16.0 margin_left = 8.0
margin_top = 36.0 margin_top = 36.0
margin_right = 72.0 margin_right = 64.0
margin_bottom = 128.0 margin_bottom = 128.0
rect_min_size = Vector2( 56, 0 ) rect_min_size = Vector2( 56, 0 )
size_flags_horizontal = 8 size_flags_horizontal = 8
@ -120,14 +120,13 @@ text = "Save"
[node name="spacer" type="Control" parent="rightside"] [node name="spacer" type="Control" parent="rightside"]
margin_top = 128.0 margin_top = 128.0
margin_right = 72.0 margin_right = 64.0
margin_bottom = 168.0 margin_bottom = 168.0
size_flags_vertical = 3 size_flags_vertical = 3
[node name="panel_time" type="PanelContainer" parent="rightside"] [node name="panel_time" type="PanelContainer" parent="rightside"]
margin_left = 8.0
margin_top = 168.0 margin_top = 168.0
margin_right = 72.0 margin_right = 64.0
margin_bottom = 204.0 margin_bottom = 204.0
rect_min_size = Vector2( 64, 0 ) rect_min_size = Vector2( 64, 0 )
size_flags_horizontal = 8 size_flags_horizontal = 8
@ -149,32 +148,32 @@ unique_name_in_owner = true
margin_top = 14.0 margin_top = 14.0
margin_right = 56.0 margin_right = 56.0
margin_bottom = 28.0 margin_bottom = 28.0
text = "0:00" text = "000:00:00"
align = 2 align = 2
[node name="panel_gil" type="PanelContainer" parent="rightside"] [node name="panel_gil" type="PanelContainer" parent="rightside"]
margin_top = 204.0 margin_top = 204.0
margin_right = 72.0 margin_right = 64.0
margin_bottom = 240.0 margin_bottom = 240.0
rect_min_size = Vector2( 72, 0 ) rect_min_size = Vector2( 64, 0 )
[node name="VBoxContainer" type="VBoxContainer" parent="rightside/panel_gil"] [node name="VBoxContainer" type="VBoxContainer" parent="rightside/panel_gil"]
margin_left = 4.0 margin_left = 4.0
margin_top = 4.0 margin_top = 4.0
margin_right = 68.0 margin_right = 60.0
margin_bottom = 32.0 margin_bottom = 32.0
custom_constants/separation = 0 custom_constants/separation = 0
[node name="lbl_gilcount" type="Label" parent="rightside/panel_gil/VBoxContainer"] [node name="lbl_gilcount" type="Label" parent="rightside/panel_gil/VBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
margin_right = 64.0 margin_right = 56.0
margin_bottom = 14.0 margin_bottom = 14.0
text = "0" text = "0000000"
align = 2 align = 2
[node name="GIL" type="Label" parent="rightside/panel_gil/VBoxContainer"] [node name="GIL" type="Label" parent="rightside/panel_gil/VBoxContainer"]
margin_top = 14.0 margin_top = 14.0
margin_right = 64.0 margin_right = 56.0
margin_bottom = 28.0 margin_bottom = 28.0
text = "Gil" text = "Gil"
align = 2 align = 2

View File

@ -129,9 +129,9 @@ text = "LV"
[node name="lbl_lv_cur" type="Label" parent="ref0"] [node name="lbl_lv_cur" type="Label" parent="ref0"]
unique_name_in_owner = true unique_name_in_owner = true
margin_left = 32.0 margin_left = 24.0
margin_top = 12.0 margin_top = 12.0
margin_right = 56.0 margin_right = 48.0
margin_bottom = 26.0 margin_bottom = 26.0
text = "26" text = "26"
align = 2 align = 2
@ -149,9 +149,9 @@ border_color = Color( 1, 0.501961, 0, 1 )
unique_name_in_owner = true unique_name_in_owner = true
anchor_top = 1.0 anchor_top = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
margin_left = 40.0 margin_left = 32.0
margin_top = -24.0 margin_top = -24.0
margin_right = 56.0 margin_right = 48.0
border_color = Color( 0, 1, 0, 1 ) border_color = Color( 0, 1, 0, 1 )
[node name="PC" parent="ref0" instance=ExtResource( 2 )] [node name="PC" parent="ref0" instance=ExtResource( 2 )]
@ -162,6 +162,14 @@ margin_left = 168.0
margin_right = 252.0 margin_right = 252.0
margin_bottom = 50.0 margin_bottom = 50.0
[node name="Panel" type="Panel" parent="ref_commands"]
modulate = Color( 1, 1, 1, 0.501961 )
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -4.0
margin_top = -3.0
margin_bottom = 3.0
[node name="l1" type="Label" parent="ref_commands"] [node name="l1" type="Label" parent="ref_commands"]
margin_left = 12.0 margin_left = 12.0
margin_right = 84.0 margin_right = 84.0

View File

@ -2,13 +2,18 @@ extends PanelContainer
#warning-ignore-all:return_value_discarded #warning-ignore-all:return_value_discarded
signal continue_pressed signal continue_pressed
signal savefile_loaded(dicts)
const globals = preload('res://globals.gd') # Make LSP shut up about non-const
const FOLDER_ICON := globals.FOLDER_ICON const FOLDER_ICON := globals.FOLDER_ICON
const ALLOWED_EXTS := globals.ALLOWED_EXTS const ALLOWED_EXTS := globals.ALLOWED_EXTS
const CD_EXTS := globals.CD_EXTS const CD_EXTS := globals.CD_EXTS
const EXT_ICONS := globals.EXT_ICONS const EXT_ICONS := globals.EXT_ICONS
const TYPE_DESCS := globals.TYPE_DESCS const TYPE_DESCS := globals.TYPE_DESCS
enum {SELECT_ROM, SELECT_SAVE, COMPLETE}
var current_mode = SELECT_ROM
var cached_cd_bin_paths := {} var cached_cd_bin_paths := {}
var dir := Directory.new() var dir := Directory.new()
var home_path := '' var home_path := ''
@ -109,7 +114,18 @@ func load_file(entry: String):
var ext = entry.rsplit('.', true, 1)[1].to_lower() var ext = entry.rsplit('.', true, 1)[1].to_lower()
match ext: match ext:
'sfc', 'smc': 'sfc', 'smc':
RomLoader.load_snes_rom(filename) if current_mode == SELECT_ROM:
RomLoader.load_snes_rom(filename)
'srm':
if current_mode == SELECT_ROM:
return
var file := File.new()
match file.open(filename, File.READ):
OK:
emit_signal('savefile_loaded', SaveLoader.load_save_dicts_from_file(file))
_set_mode(COMPLETE)
var err:
print_debug('Error loading savefile: %s - %d'%[filename, err])
func activate_entry(entry: String, _index: int = -1): func activate_entry(entry: String, _index: int = -1):
var curr_dir := dir.get_current_dir() var curr_dir := dir.get_current_dir()
@ -168,7 +184,11 @@ func view_entry(entry: String, index: int = -1):
lbl_filesize_content.text = human_size lbl_filesize_content.text = human_size
lbl_fileinfo_header.modulate = active_modulate_color if prodcode else inactive_modulate_color lbl_fileinfo_header.modulate = active_modulate_color if prodcode else inactive_modulate_color
lbl_fileinfo_content.text = prodcode lbl_fileinfo_content.text = prodcode
btn_ok.disabled = (ext != 'sfc' and ext != 'smc') # Only allow opening snes roms for now match current_mode:
SELECT_ROM:
btn_ok.disabled = (ext != 'sfc' and ext != 'smc') # Only allow opening snes roms for now
SELECT_SAVE, COMPLETE:
btn_ok.disabled = (ext != 'srm')
func init_labels(): func init_labels():
lbl_filename_header.modulate = inactive_modulate_color lbl_filename_header.modulate = inactive_modulate_color
@ -197,6 +217,20 @@ func _ready() -> void:
print(ProjectSettings.globalize_path('user://')) print(ProjectSettings.globalize_path('user://'))
print(ProjectSettings.globalize_path(dir.get_current_dir())) print(ProjectSettings.globalize_path(dir.get_current_dir()))
func _set_mode(new_mode) -> void:
match new_mode:
SELECT_ROM:
$'%lbl_prompt'.text = "Select a ROM from your device's storage"
btn_continue.disabled = true
SELECT_SAVE:
$'%lbl_prompt'.text = "Select a save file from your device's storage"
btn_continue.disabled = false
COMPLETE:
$'%lbl_prompt'.text = "Save file loaded, press Continue"
btn_continue.disabled = false
current_mode = new_mode
update_view()
init_labels()
func _on_ItemList_item_activated(index: int) -> void: func _on_ItemList_item_activated(index: int) -> void:
activate_entry(itemlist.get_item_text(index), index) activate_entry(itemlist.get_item_text(index), index)
@ -205,8 +239,7 @@ func _on_ItemList_item_selected(index: int) -> void:
view_entry(itemlist.get_item_text(index), index) view_entry(itemlist.get_item_text(index), index)
func _on_rom_loaded() -> void: func _on_rom_loaded() -> void:
$'%lbl_prompt'.text = "Select a save file from your device's storage" _set_mode(SELECT_SAVE)
btn_continue.disabled = false
func _on_continue_pressed() -> void: func _on_continue_pressed() -> void:
emit_signal('continue_pressed') emit_signal('continue_pressed')

View File

@ -1,7 +1,12 @@
extends PanelContainer extends PanelContainer
#warning-ignore-all:shadowed_variable
signal clicked
const PC := preload('res://PC.tscn') const PC := preload('res://PC.tscn')
var PCs = [] var PCs = []
var data := {}
var dummy_data := { var dummy_data := {
'characters': [ 'characters': [
{'character_id': 0}, {'character_id': 0},
@ -10,8 +15,9 @@ var dummy_data := {
{'character_id': 3}, {'character_id': 3},
], ],
'game_time_frames': randi() % 0x01000000, 'game_time_frames': randi() % 0x01000000,
'character_names': ['Butz', 'Lenna', 'Galuf', 'Faris', 'Krile'], 'character_names_decoded': ['Butz', 'Lenna', 'Galuf', 'Faris', 'Krile'],
'config': {'menu_color_r': randi()%32, 'menu_color_g': randi()%32, 'menu_color_b': randi()%32} 'config': {'menu_color_r': randi()%32, 'menu_color_g': randi()%32, 'menu_color_b': randi()%32},
'slot_in_use': true,
} }
func _init_dummy(): func _init_dummy():
@ -24,6 +30,7 @@ func _init_dummy():
dummy_data.characters.shuffle() dummy_data.characters.shuffle()
func set_data(data: Dictionary): func set_data(data: Dictionary):
self.data = data
self.material.set_shader_param('MenuBGColour', Color(data.config.menu_color_r/31.0, data.config.menu_color_g/31.0, data.config.menu_color_b/31.0)) self.material.set_shader_param('MenuBGColour', Color(data.config.menu_color_r/31.0, data.config.menu_color_g/31.0, data.config.menu_color_b/31.0))
for i in 4: for i in 4:
var char_id: int = data.characters[i].character_id var char_id: int = data.characters[i].character_id
@ -33,8 +40,10 @@ func set_data(data: Dictionary):
PCs[i].texture = SpriteLoader.strip_textures[sprite_id] PCs[i].texture = SpriteLoader.strip_textures[sprite_id]
$'%lbl_level_num'.text = '%d' % data.characters[0].level $'%lbl_level_num'.text = '%d' % data.characters[0].level
$'%lbl_gametime'.text = Common.game_time_frames_to_hhmm(data.game_time_frames) $'%lbl_gametime'.text = Common.game_time_frames_to_hhmm(data.game_time_frames)
$'%lbl_name'.text = data.character_names[data.characters[0].character_id] $'%lbl_name'.text = data.character_names_decoded[data.characters[0].character_id]
$'%lbl_hp'.text = '%d/%4d' % [data.characters[0].hp_current, data.characters[0].hp_max] $'%lbl_hp'.text = '%d/%4d' % [data.characters[0].hp_current, data.characters[0].hp_max]
$HBoxContainer.visible = data.slot_in_use
$lbl_not_in_use.visible = !data.slot_in_use
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
@ -48,6 +57,9 @@ func _ready() -> void:
set_data(dummy_data) set_data(dummy_data)
# Called every frame. 'delta' is the elapsed time since the previous frame. func _input(event: InputEvent) -> void:
#func _process(delta: float) -> void: if (event is InputEventMouseButton or event is InputEventScreenTouch) and event.pressed:
# pass if get_rect().has_point(event.position):
# print(event.position)
get_tree().set_input_as_handled()
emit_signal('clicked')

View File

@ -92,3 +92,14 @@ margin_bottom = 36.0
size_flags_vertical = 9 size_flags_vertical = 9
text = "1345/1345" text = "1345/1345"
align = 2 align = 2
[node name="lbl_not_in_use" type="Label" parent="."]
visible = false
margin_left = 4.0
margin_top = 15.0
margin_right = 220.0
margin_bottom = 29.0
rect_min_size = Vector2( 0, 36 )
text = "Not In Use"
align = 1
valign = 1

17
widgets/SaveSlotSelect.gd Normal file
View File

@ -0,0 +1,17 @@
extends PanelContainer
#warning-ignore-all:shadowed_variable
signal slot_activated(dict)
onready var slots := [$'%SaveSlot1', $'%SaveSlot2', $'%SaveSlot3', $'%SaveSlot4']
var dicts := []
func set_data(dicts: Array) -> void:
self.dicts = dicts
for i in 4:
slots[i].set_data(dicts[i])
slots[i].connect('clicked', self, 'load_slot', [i])
func load_slot(id: int) -> void:
var dict = self.dicts[id]
if dict.slot_in_use:
emit_signal('slot_activated', dict)

View File

@ -1,10 +1,12 @@
[gd_scene load_steps=3 format=2] [gd_scene load_steps=4 format=2]
[ext_resource path="res://theme/menu_theme.tres" type="Theme" id=1] [ext_resource path="res://theme/menu_theme.tres" type="Theme" id=1]
[ext_resource path="res://widgets/SaveSlot.tscn" type="PackedScene" id=2] [ext_resource path="res://widgets/SaveSlot.tscn" type="PackedScene" id=2]
[ext_resource path="res://widgets/SaveSlotSelect.gd" type="Script" id=3]
[node name="SaveSlotSelect" type="PanelContainer"] [node name="SaveSlotSelect" type="PanelContainer"]
theme = ExtResource( 1 ) theme = ExtResource( 1 )
script = ExtResource( 3 )
[node name="VBoxContainer" type="VBoxContainer" parent="."] [node name="VBoxContainer" type="VBoxContainer" parent="."]
margin_left = 4.0 margin_left = 4.0
@ -19,21 +21,25 @@ margin_bottom = 22.0
text = "New Game" text = "New Game"
[node name="SaveSlot1" parent="VBoxContainer" instance=ExtResource( 2 )] [node name="SaveSlot1" parent="VBoxContainer" instance=ExtResource( 2 )]
unique_name_in_owner = true
margin_top = 22.0 margin_top = 22.0
margin_right = 224.0 margin_right = 224.0
margin_bottom = 66.0 margin_bottom = 66.0
[node name="SaveSlot2" parent="VBoxContainer" instance=ExtResource( 2 )] [node name="SaveSlot2" parent="VBoxContainer" instance=ExtResource( 2 )]
unique_name_in_owner = true
margin_top = 66.0 margin_top = 66.0
margin_right = 224.0 margin_right = 224.0
margin_bottom = 110.0 margin_bottom = 110.0
[node name="SaveSlot3" parent="VBoxContainer" instance=ExtResource( 2 )] [node name="SaveSlot3" parent="VBoxContainer" instance=ExtResource( 2 )]
unique_name_in_owner = true
margin_top = 110.0 margin_top = 110.0
margin_right = 224.0 margin_right = 224.0
margin_bottom = 154.0 margin_bottom = 154.0
[node name="SaveSlot4" parent="VBoxContainer" instance=ExtResource( 2 )] [node name="SaveSlot4" parent="VBoxContainer" instance=ExtResource( 2 )]
unique_name_in_owner = true
margin_top = 154.0 margin_top = 154.0
margin_right = 224.0 margin_right = 224.0
margin_bottom = 198.0 margin_bottom = 198.0

View File

@ -2,13 +2,18 @@ extends PanelContainer
#warning-ignore-all:return_value_discarded #warning-ignore-all:return_value_discarded
signal continue_pressed signal continue_pressed
signal savefile_loaded(dicts)
const globals = preload('res://globals.gd') # Make LSP shut up about non-const
const FOLDER_ICON := globals.FOLDER_ICON const FOLDER_ICON := globals.FOLDER_ICON
const ALLOWED_EXTS := globals.ALLOWED_EXTS const ALLOWED_EXTS := globals.ALLOWED_EXTS
const CD_EXTS := globals.CD_EXTS const CD_EXTS := globals.CD_EXTS
const EXT_ICONS := globals.EXT_ICONS const EXT_ICONS := globals.EXT_ICONS
const TYPE_DESCS := globals.TYPE_DESCS const TYPE_DESCS := globals.TYPE_DESCS
enum {SELECT_ROM, SELECT_SAVE, COMPLETE}
var current_mode = SELECT_ROM
var uploaded_files := {} # filename: data var uploaded_files := {} # filename: data
var uploaded_files_types := {} # filename: type var uploaded_files_types := {} # filename: type
@ -68,7 +73,12 @@ func load_file(entry: String):
var ext = entry.rsplit('.', true, 1)[1].to_lower() var ext = entry.rsplit('.', true, 1)[1].to_lower()
match ext: match ext:
'sfc', 'smc': 'sfc', 'smc':
RomLoader.load_snes_rom_from_bytes(uploaded_files[entry]) if current_mode == SELECT_ROM:
RomLoader.load_snes_rom_from_bytes(uploaded_files[entry])
'srm':
if current_mode != SELECT_ROM:
emit_signal('savefile_loaded', SaveLoader.load_save_dicts_from_bytes(uploaded_files[entry]))
_set_mode(COMPLETE)
func activate_entry(entry: String, _index: int = -1): func activate_entry(entry: String, _index: int = -1):
load_file(entry) load_file(entry)
@ -108,7 +118,11 @@ func view_entry(entry: String, _index: int = -1):
lbl_filesize_content.text = human_size lbl_filesize_content.text = human_size
lbl_fileinfo_header.modulate = active_modulate_color if prodcode else inactive_modulate_color lbl_fileinfo_header.modulate = active_modulate_color if prodcode else inactive_modulate_color
lbl_fileinfo_content.text = prodcode lbl_fileinfo_content.text = prodcode
btn_ok.disabled = (ext != 'sfc' and ext != 'smc') # Only allow opening snes roms for now match current_mode:
SELECT_ROM:
btn_ok.disabled = (ext != 'sfc' and ext != 'smc') # Only allow opening snes roms for now
SELECT_SAVE, COMPLETE:
btn_ok.disabled = (ext != 'srm')
func init_labels(): func init_labels():
lbl_filename_header.modulate = inactive_modulate_color lbl_filename_header.modulate = inactive_modulate_color
@ -123,6 +137,7 @@ func init_labels():
func _upload_file(filename: String, file_type: String, data): # data is Javascript ArrayBuffer, which should be castable to PoolByteArray func _upload_file(filename: String, file_type: String, data): # data is Javascript ArrayBuffer, which should be castable to PoolByteArray
uploaded_files[filename] = data uploaded_files[filename] = data
uploaded_files_types[filename] = file_type uploaded_files_types[filename] = file_type
print('uploaded "%s" with filesize %d bytes'%[filename, len(data)])
update_view() update_view()
func _ready() -> void: func _ready() -> void:
@ -135,6 +150,20 @@ func _ready() -> void:
RomLoader.connect('rom_loaded', self, '_on_rom_loaded') RomLoader.connect('rom_loaded', self, '_on_rom_loaded')
HTML5.connect('uploaded_file', self, '_upload_file') HTML5.connect('uploaded_file', self, '_upload_file')
func _set_mode(new_mode) -> void:
match new_mode:
SELECT_ROM:
$'%lbl_prompt'.text = "Select a ROM from your device's storage"
btn_continue.disabled = true
SELECT_SAVE:
$'%lbl_prompt'.text = "Select a save file from your device's storage"
btn_continue.disabled = false
COMPLETE:
$'%lbl_prompt'.text = "Save file loaded, press Continue"
btn_continue.disabled = false
current_mode = new_mode
update_view()
init_labels()
func _on_ItemList_item_activated(index: int) -> void: func _on_ItemList_item_activated(index: int) -> void:
activate_entry(itemlist.get_item_text(index), index) activate_entry(itemlist.get_item_text(index), index)
@ -146,8 +175,7 @@ func _on_btn_upload_pressed() -> void:
HTML5.upload_file() HTML5.upload_file()
func _on_rom_loaded() -> void: func _on_rom_loaded() -> void:
$'%lbl_prompt'.text = "Select a save file from your device's storage" _set_mode(SELECT_SAVE)
btn_continue.disabled = false
func _on_continue_pressed() -> void: func _on_continue_pressed() -> void:
emit_signal('continue_pressed') emit_signal('continue_pressed')