diff options
32 files changed, 666 insertions, 23 deletions
diff --git a/assets/Oserif-j98vR.ttf b/assets/Oserif-j98vR.ttf Binary files differnew file mode 100644 index 0000000..ec2b5dd --- /dev/null +++ b/assets/Oserif-j98vR.ttf diff --git a/assets/Oserif-j98vR.ttf.import b/assets/Oserif-j98vR.ttf.import new file mode 100644 index 0000000..fdd9950 --- /dev/null +++ b/assets/Oserif-j98vR.ttf.import @@ -0,0 +1,36 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://bkhmc8y1sdhb1" +path="res://.godot/imported/Oserif-j98vR.ttf-699afbfb4c56b9ebc9e584f218277179.fontdata" + +[deps] + +source_file="res://assets/Oserif-j98vR.ttf" +dest_files=["res://.godot/imported/Oserif-j98vR.ttf-699afbfb4c56b9ebc9e584f218277179.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +modulate_color_glyphs=false +hinting=1 +subpixel_positioning=4 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/assets/definitions/Items/big_potion_of_heals.tres b/assets/definitions/Items/big_potion_of_heals.tres new file mode 100644 index 0000000..81c5e0b --- /dev/null +++ b/assets/definitions/Items/big_potion_of_heals.tres @@ -0,0 +1,23 @@ +[gd_resource type="Resource" script_class="ItemResource" load_steps=7 format=3 uid="uid://dm0v0aoarb4dp"] + +[ext_resource type="Script" uid="uid://bslt4pbvwvsj1" path="res://scripts/Magic/HealEffect.cs" id="1_2x33w"] +[ext_resource type="Script" uid="uid://bybli1lduvm3n" path="res://scripts/Entities/Items/ItemResource.cs" id="1_vsyyt"] +[ext_resource type="Script" uid="uid://b72fwkwul1wet" path="res://scripts/Entities/Items/SpellEffectItemActivation.cs" id="2_l4xm8"] +[ext_resource type="Texture2D" uid="uid://dftr4yuf72gg2" path="res://assets/sprites/items/big_health_potion.png" id="3_4nt2e"] + +[sub_resource type="Resource" id="Resource_8peth"] +script = ExtResource("1_2x33w") +Healing = 20 +metadata/_custom_type_script = "uid://bslt4pbvwvsj1" + +[sub_resource type="Resource" id="Resource_jdsxe"] +script = ExtResource("2_l4xm8") +effect = SubResource("Resource_8peth") +metadata/_custom_type_script = "uid://b72fwkwul1wet" + +[resource] +script = ExtResource("1_vsyyt") +DisplayName = "Poção de cura grande" +Icon = ExtResource("3_4nt2e") +Activation = SubResource("Resource_jdsxe") +metadata/_custom_type_script = "uid://bybli1lduvm3n" diff --git a/assets/definitions/Items/uohhh.tres b/assets/definitions/Items/uohhh.tres new file mode 100644 index 0000000..c48c07a --- /dev/null +++ b/assets/definitions/Items/uohhh.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" script_class="ItemResource" load_steps=6 format=3 uid="uid://otklq7k1tb45"] + +[ext_resource type="Script" uid="uid://bybli1lduvm3n" path="res://scripts/Entities/Items/ItemResource.cs" id="1_6qucm"] +[ext_resource type="Script" uid="uid://bslt4pbvwvsj1" path="res://scripts/Magic/HealEffect.cs" id="1_uvkms"] +[ext_resource type="Script" uid="uid://b72fwkwul1wet" path="res://scripts/Entities/Items/SpellEffectItemActivation.cs" id="2_i5wwe"] + +[sub_resource type="Resource" id="Resource_idx7p"] +script = ExtResource("1_uvkms") +Healing = 89 +metadata/_custom_type_script = "uid://bslt4pbvwvsj1" + +[sub_resource type="Resource" id="Resource_v7ab0"] +script = ExtResource("2_i5wwe") +effect = SubResource("Resource_idx7p") +metadata/_custom_type_script = "uid://b72fwkwul1wet" + +[resource] +script = ExtResource("1_6qucm") +DisplayName = "ojo" +Activation = SubResource("Resource_v7ab0") +metadata/_custom_type_script = "uid://bybli1lduvm3n" diff --git a/assets/definitions/actor/toilet.tres b/assets/definitions/actor/toilet.tres new file mode 100644 index 0000000..f33a878 --- /dev/null +++ b/assets/definitions/actor/toilet.tres @@ -0,0 +1,18 @@ +[gd_resource type="Resource" script_class="EnemyDefinition" load_steps=4 format=3 uid="uid://bbj06osf7pjor"] + +[ext_resource type="Script" uid="uid://dkfdm2m2scyks" path="res://scripts/Entities/Actors/EnemyDefinition.cs" id="1_mh1wq"] +[ext_resource type="Texture2D" uid="uid://w0808ug4al66" path="res://assets/sprites/actors/generic_grave.png" id="1_tv8qd"] +[ext_resource type="Texture2D" uid="uid://j1b2vbolwsch" path="res://assets/sprites/actors/ToiletMan.png" id="3_riy75"] + +[resource] +script = ExtResource("1_mh1wq") +AI = 1 +deathTexture = ExtResource("1_tv8qd") +Hp = 16 +Atk = 6 +Def = 2 +Men = 3 +name = "SKIBIDI" +texture = ExtResource("3_riy75") +Type = 2 +metadata/_custom_type_script = "uid://dkfdm2m2scyks" diff --git a/assets/sprites/actors/ToiletMan.png b/assets/sprites/actors/ToiletMan.png Binary files differnew file mode 100644 index 0000000..a257313 --- /dev/null +++ b/assets/sprites/actors/ToiletMan.png diff --git a/assets/sprites/actors/ToiletMan.png.import b/assets/sprites/actors/ToiletMan.png.import new file mode 100644 index 0000000..9b18b96 --- /dev/null +++ b/assets/sprites/actors/ToiletMan.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://j1b2vbolwsch" +path="res://.godot/imported/ToiletMan.png-f992a71b96595fd93fe0692465c52574.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/actors/ToiletMan.png" +dest_files=["res://.godot/imported/ToiletMan.png-f992a71b96595fd93fe0692465c52574.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/sprites/inter-face/button_texture.png b/assets/sprites/inter-face/button_texture.png Binary files differnew file mode 100644 index 0000000..aca4745 --- /dev/null +++ b/assets/sprites/inter-face/button_texture.png diff --git a/assets/sprites/inter-face/button_texture.png.import b/assets/sprites/inter-face/button_texture.png.import new file mode 100644 index 0000000..00f222d --- /dev/null +++ b/assets/sprites/inter-face/button_texture.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dwg5pwgld1xrr" +path="res://.godot/imported/button_texture.png-6946e2ce5b57b5b0f0334c9bd99a877f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/inter-face/button_texture.png" +dest_files=["res://.godot/imported/button_texture.png-6946e2ce5b57b5b0f0334c9bd99a877f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/sprites/items/big_health_potion.png b/assets/sprites/items/big_health_potion.png Binary files differnew file mode 100644 index 0000000..81e8dbd --- /dev/null +++ b/assets/sprites/items/big_health_potion.png diff --git a/assets/sprites/items/big_health_potion.png.import b/assets/sprites/items/big_health_potion.png.import new file mode 100644 index 0000000..6c59746 --- /dev/null +++ b/assets/sprites/items/big_health_potion.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dftr4yuf72gg2" +path="res://.godot/imported/big_health_potion.png-9796650ac3c4679880ae8cb9cebfbe7c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/items/big_health_potion.png" +dest_files=["res://.godot/imported/big_health_potion.png-9796650ac3c4679880ae8cb9cebfbe7c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/sprites/tiles/floor.png b/assets/sprites/tiles/floor.png Binary files differindex 2f93b12..f0e248e 100644 --- a/assets/sprites/tiles/floor.png +++ b/assets/sprites/tiles/floor.png diff --git a/assets/sprites/tiles/wall.png b/assets/sprites/tiles/wall.png Binary files differindex 3b2e058..2a94ef4 100644 --- a/assets/sprites/tiles/wall.png +++ b/assets/sprites/tiles/wall.png diff --git a/project.godot b/project.godot index 5ee82d7..a2bb69f 100644 --- a/project.godot +++ b/project.godot @@ -20,6 +20,7 @@ config/icon="res://icon.svg" signalBus="*res://scripts/Utils/SignalBus.cs" MessageLogData="*res://scripts/Utils/MessageLogData.cs" +Stats="*res://scripts/Utils/Stats.cs" [display] @@ -29,6 +30,10 @@ window/stretch/mode="canvas_items" project/assembly_name="projeto-fantasia" +[gui] + +theme/custom_font="uid://bkhmc8y1sdhb1" + [input] walk-up={ diff --git a/scenes/GUI/Leaderboard.cs b/scenes/GUI/Leaderboard.cs new file mode 100644 index 0000000..cf126c9 --- /dev/null +++ b/scenes/GUI/Leaderboard.cs @@ -0,0 +1,62 @@ +using System; +using Godot; +using Godot.Collections; +using TheLegendOfGustav.Utils; + +namespace TheLegendOfGustav.GUI; +public partial class Leaderboard : Control +{ + [Signal] + public delegate void MenuRequestedEventHandler(); + private static readonly PackedScene LeaderboardItemScene = GD.Load<PackedScene>("res://scenes/GUI/leaderboard_item.tscn"); + + private VBoxContainer leaderboard; + private Button BackButton; + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + leaderboard = GetNode<VBoxContainer>("VBoxContainer/VBoxContainer"); + BackButton = GetNode<Button>("VBoxContainer/exit"); + + BackButton.Pressed += () => EmitSignal(SignalName.MenuRequested); + + bool hasLeaderboardFile = FileAccess.FileExists("user://placar.json"); + if (hasLeaderboardFile) + { + using var leaderboardFile = FileAccess.Open("user://placar.json", FileAccess.ModeFlags.Read); + string boardString = leaderboardFile.GetLine(); + + Dictionary<string, Variant> leaderBoardData; + + try + { + var parseResult = Json.ParseString(boardString); + if (parseResult.VariantType == Variant.Type.Nil) + { + throw new Exception(); + } + leaderBoardData = (Dictionary<string, Variant>)parseResult; + } + catch (Exception) + { + // Arquivo inválido. + return; + } + + Array<Dictionary<string, Variant>> players = (Array<Dictionary<string, Variant>>)leaderBoardData["placar"]; + + foreach (Dictionary<string, Variant> player in players) + { + LeaderboardItem item = LeaderboardItemScene.Instantiate<LeaderboardItem>(); + + item.PlayerName = (string)player["jogador"]; + item.Floor = (string)player["andar_mais_fundo"]; + item.Kills = (string)player["inimigos_mortos"]; + item.Damage = (string)player["dano_tomado"]; + + leaderboard.AddChild(item); + } + + } + } +} diff --git a/scenes/GUI/Leaderboard.cs.uid b/scenes/GUI/Leaderboard.cs.uid new file mode 100644 index 0000000..4681d98 --- /dev/null +++ b/scenes/GUI/Leaderboard.cs.uid @@ -0,0 +1 @@ +uid://bj6r5oalajbmc diff --git a/scenes/GUI/Leaderboard.tscn b/scenes/GUI/Leaderboard.tscn new file mode 100644 index 0000000..5724e34 --- /dev/null +++ b/scenes/GUI/Leaderboard.tscn @@ -0,0 +1,53 @@ +[gd_scene load_steps=7 format=3 uid="uid://ddxrecok5ctss"] + +[ext_resource type="Script" uid="uid://bj6r5oalajbmc" path="res://scenes/GUI/Leaderboard.cs" id="1_8w6tf"] +[ext_resource type="Texture2D" uid="uid://bxjwbucke02gl" path="res://assets/bg.png" id="1_dlctp"] +[ext_resource type="PackedScene" uid="uid://w4oy340d3ugn" path="res://scenes/GUI/leaderboard_item.tscn" id="2_8w6tf"] +[ext_resource type="StyleBox" uid="uid://krfa04v10vwc" path="res://scenes/GUI/button.tres" id="4_kxih3"] + +[sub_resource type="InputEventKey" id="InputEventKey_8w6tf"] +device = -1 +keycode = 86 +unicode = 118 + +[sub_resource type="Shortcut" id="Shortcut_kxih3"] +events = [SubResource("InputEventKey_8w6tf")] + +[node name="Control" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_8w6tf") + +[node name="TextureRect" type="TextureRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("1_dlctp") +expand_mode = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="Header" parent="VBoxContainer/VBoxContainer" instance=ExtResource("2_8w6tf")] +layout_mode = 2 + +[node name="exit" type="Button" parent="VBoxContainer"] +layout_mode = 2 +theme_override_styles/normal = ExtResource("4_kxih3") +shortcut = SubResource("Shortcut_kxih3") +text = "[V] Voltar" diff --git a/scenes/GUI/button.tres b/scenes/GUI/button.tres new file mode 100644 index 0000000..601c8f7 --- /dev/null +++ b/scenes/GUI/button.tres @@ -0,0 +1,10 @@ +[gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://krfa04v10vwc"] + +[ext_resource type="Texture2D" uid="uid://dwg5pwgld1xrr" path="res://assets/sprites/inter-face/button_texture.png" id="1_dju77"] + +[resource] +texture = ExtResource("1_dju77") +texture_margin_left = 2.0 +texture_margin_top = 2.0 +texture_margin_right = 2.0 +texture_margin_bottom = 2.0 diff --git a/scenes/GUI/leaderboard_item.tscn b/scenes/GUI/leaderboard_item.tscn new file mode 100644 index 0000000..4cee6d3 --- /dev/null +++ b/scenes/GUI/leaderboard_item.tscn @@ -0,0 +1,35 @@ +[gd_scene load_steps=2 format=3 uid="uid://w4oy340d3ugn"] + +[ext_resource type="Script" uid="uid://cbjltiujfsw4v" path="res://scripts/GUI/LeaderboardItem.cs" id="1_ilpit"] + +[node name="HBoxContainer" type="HBoxContainer"] +script = ExtResource("1_ilpit") + +[node name="hdNome" type="Label" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Nome" + +[node name="VSeparator" type="VSeparator" parent="."] +layout_mode = 2 + +[node name="hdAndar" type="Label" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Maior Andar" + +[node name="VSeparator2" type="VSeparator" parent="."] +layout_mode = 2 + +[node name="hdkills" type="Label" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Inimigos Mortos" + +[node name="VSeparator3" type="VSeparator" parent="."] +layout_mode = 2 + +[node name="hddamage" type="Label" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Dano tomado" diff --git a/scenes/GUI/main_menu.tscn b/scenes/GUI/main_menu.tscn index 2794830..95700a0 100644 --- a/scenes/GUI/main_menu.tscn +++ b/scenes/GUI/main_menu.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=10 format=3 uid="uid://cppjdsdfkkxtm"] +[gd_scene load_steps=13 format=3 uid="uid://cppjdsdfkkxtm"] [ext_resource type="Script" uid="uid://dx0fxht2oadb6" path="res://scripts/GUI/MainMenu.cs" id="1_b4h60"] [ext_resource type="Texture2D" uid="uid://bxjwbucke02gl" path="res://assets/bg.png" id="1_tbt31"] +[ext_resource type="StyleBox" uid="uid://krfa04v10vwc" path="res://scenes/GUI/button.tres" id="3_kebck"] [sub_resource type="LabelSettings" id="LabelSettings_b4h60"] font_size = 32 @@ -22,6 +23,14 @@ unicode = 99 [sub_resource type="Shortcut" id="Shortcut_1ei6q"] events = [SubResource("InputEventKey_kebck")] +[sub_resource type="InputEventKey" id="InputEventKey_b4h60"] +device = -1 +keycode = 80 +unicode = 112 + +[sub_resource type="Shortcut" id="Shortcut_kebck"] +events = [SubResource("InputEventKey_b4h60")] + [sub_resource type="InputEventKey" id="InputEventKey_xm7ak"] device = -1 keycode = 83 @@ -71,18 +80,27 @@ label_settings = SubResource("LabelSettings_b4h60") [node name="neogame" type="Button" parent="VBoxContainer/CenterContainer/VBoxContainer"] layout_mode = 2 +theme_override_styles/normal = ExtResource("3_kebck") shortcut = SubResource("Shortcut_b4h60") shortcut_feedback = false text = "[N] Novo jogo" [node name="continue" type="Button" parent="VBoxContainer/CenterContainer/VBoxContainer"] layout_mode = 2 +theme_override_styles/normal = ExtResource("3_kebck") shortcut = SubResource("Shortcut_1ei6q") shortcut_feedback = false text = "[C] Continuar" +[node name="leaderboard" type="Button" parent="VBoxContainer/CenterContainer/VBoxContainer"] +layout_mode = 2 +theme_override_styles/normal = ExtResource("3_kebck") +shortcut = SubResource("Shortcut_kebck") +text = "[P] Placar" + [node name="quit" type="Button" parent="VBoxContainer/CenterContainer/VBoxContainer"] layout_mode = 2 +theme_override_styles/normal = ExtResource("3_kebck") shortcut = SubResource("Shortcut_h03jd") text = "[S] Sair" diff --git a/scenes/name_thyself.tscn b/scenes/name_thyself.tscn index d2c3650..e4f75b3 100644 --- a/scenes/name_thyself.tscn +++ b/scenes/name_thyself.tscn @@ -1,7 +1,17 @@ -[gd_scene load_steps=3 format=3 uid="uid://baio67tv5ifph"] +[gd_scene load_steps=6 format=3 uid="uid://baio67tv5ifph"] [ext_resource type="Texture2D" uid="uid://bxjwbucke02gl" path="res://assets/bg.png" id="1_c644k"] [ext_resource type="Script" uid="uid://cmtn05tqqh0t4" path="res://scripts/GUI/PlayerName.cs" id="1_jhpgh"] +[ext_resource type="Texture2D" uid="uid://dwg5pwgld1xrr" path="res://assets/sprites/inter-face/button_texture.png" id="3_c5fbr"] +[ext_resource type="StyleBox" uid="uid://krfa04v10vwc" path="res://scenes/GUI/button.tres" id="4_jndhp"] + +[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_x2lmy"] +texture = ExtResource("3_c5fbr") +texture_margin_left = 2.0 +texture_margin_top = 2.0 +texture_margin_right = 2.0 +texture_margin_bottom = 2.0 +modulate_color = Color(0.39308554, 0.3930855, 0.39308548, 1) [node name="NameThyself" type="Control"] layout_mode = 3 @@ -42,9 +52,11 @@ text = "Quem é você?" [node name="thename" type="LineEdit" parent="VBoxContainer"] layout_mode = 2 +theme_override_styles/normal = SubResource("StyleBoxTexture_x2lmy") placeholder_text = "Player" expand_to_text_length = true [node name="Button" type="Button" parent="VBoxContainer"] layout_mode = 2 +theme_override_styles/normal = ExtResource("4_jndhp") text = "Iniciar" diff --git a/scripts/Entities/Actions/EscapeAction.cs b/scripts/Entities/Actions/EscapeAction.cs index f0b1ed5..1b3aae2 100644 --- a/scripts/Entities/Actions/EscapeAction.cs +++ b/scripts/Entities/Actions/EscapeAction.cs @@ -1,13 +1,85 @@ +using System; +using Godot; +using Godot.Collections; +using Microsoft.VisualBasic; using TheLegendOfGustav.Entities.Actors; using TheLegendOfGustav.Utils; namespace TheLegendOfGustav.Entities.Actions; -public partial class EscapeAction(Actor actor) : Action(actor) +public partial class EscapeAction(Actor actor, bool should_save = false) : Action(actor) { + private bool should_save = should_save; public override bool Perform() { - Actor.MapData.SaveGame(); + if (should_save) { + Actor.MapData.SaveGame(); + } else { + // game over + bool hasLeaderboardFile = FileAccess.FileExists("user://placar.json"); + if (hasLeaderboardFile) { + using var leaderboardFile = FileAccess.Open("user://placar.json", FileAccess.ModeFlags.ReadWrite); + string boardString = leaderboardFile.GetLine(); + + Dictionary<string, Variant> leaderBoardData; + + try { + var parseResult = Json.ParseString(boardString); + if (parseResult.VariantType == Variant.Type.Nil) { + throw new Exception(); + } + leaderBoardData = (Dictionary<string, Variant>)parseResult; + } catch (Exception) + { + leaderboardFile.Resize(0); + leaderboardFile.Seek(0); + + leaderBoardData = new() + { + {"placar", new Array<Dictionary<string, Variant>>() {Stats.Instance.Serialize()}} + }; + boardString = Json.Stringify(leaderBoardData); + + leaderboardFile.StoreLine(boardString); + + SignalBus.Instance.EmitSignal(SignalBus.SignalName.EscapeRequested); + return false; + } + + Array<Dictionary<string, Variant>> players = (Array<Dictionary<string, Variant>>)leaderBoardData["placar"]; + + players.Add(Stats.Instance.Serialize()); + + for (int i = 0; i < players.Count; i++) { + for (int j = 0; j < players.Count - 1 - i; j++) { + if ((int)players[j]["andar_mais_fundo"] < (int)players[j + 1]["andar_mais_fundo"]) { + Dictionary<string, Variant> tmp = players[j]; + players[j] = players[j + 1]; + players[j + 1] = tmp; + } + } + } + + if (players.Count > 10) { + players = players.GetSliceRange(0, 10); + } + + leaderBoardData["placar"] = players; + + leaderboardFile.Resize(0); + leaderboardFile.Seek(0); + leaderboardFile.StoreLine(Json.Stringify(leaderBoardData)); + } else { + using var leaderboardFile = FileAccess.Open("user://placar.json", FileAccess.ModeFlags.Write); + Dictionary<string, Variant> leaderBoardData = new() + { + {"placar", new Array<Dictionary<string, Variant>>() {Stats.Instance.Serialize()}} + }; + string boardString = Json.Stringify(leaderBoardData); + + leaderboardFile.StoreLine(boardString); + } + } SignalBus.Instance.EmitSignal(SignalBus.SignalName.EscapeRequested); return false; } diff --git a/scripts/Entities/Actors/Actor.cs b/scripts/Entities/Actors/Actor.cs index c68cc2b..e6b8867 100644 --- a/scripts/Entities/Actors/Actor.cs +++ b/scripts/Entities/Actors/Actor.cs @@ -101,6 +101,9 @@ public partial class Actor : Entity, ISaveable get => hp; set { + if (MapData != null && MapData.Player == this && hp > value) { + Stats.Instance.DamageTaken += (hp - value); + } // Esta propriedade impede que o HP seja maior que o máximo. hp = int.Clamp(value, 0, MaxHp); EmitSignal(SignalName.HealthChanged, Hp, MaxHp); @@ -280,6 +283,9 @@ public partial class Actor : Entity, ISaveable else { deathMessage = $"{DisplayName} morreu!"; + if (!inLoading) { + Stats.Instance.EnemiesKilled++; + } } diff --git a/scripts/GUI/LeaderboardItem.cs b/scripts/GUI/LeaderboardItem.cs new file mode 100644 index 0000000..c05bf58 --- /dev/null +++ b/scripts/GUI/LeaderboardItem.cs @@ -0,0 +1,41 @@ +using Godot; + +namespace TheLegendOfGustav.GUI; + +public partial class LeaderboardItem : HBoxContainer +{ + [Export] + public string PlayerName { get; set; } = "Jogador"; + [Export] + public string Floor { get; set; } = "Andar Máximo"; + [Export] + public string Kills { get; set; } = "Inimigos Mortos"; + [Export] + public string Damage { get; set; } = "Dano tomado"; + + private Label nameLabel; + private Label floorLabel; + private Label killsLabel; + private Label damageLabel; + + + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + nameLabel = GetNode<Label>("hdNome"); + floorLabel = GetNode<Label>("hdAndar"); + killsLabel = GetNode<Label>("hdkills"); + damageLabel = GetNode<Label>("hddamage"); + + + UpdateLabels(); + } + + public void UpdateLabels() + { + nameLabel.Text = PlayerName; + floorLabel.Text = Floor; + killsLabel.Text = Kills; + damageLabel.Text = Damage; + } +} diff --git a/scripts/GUI/LeaderboardItem.cs.uid b/scripts/GUI/LeaderboardItem.cs.uid new file mode 100644 index 0000000..ddac2bd --- /dev/null +++ b/scripts/GUI/LeaderboardItem.cs.uid @@ -0,0 +1 @@ +uid://cbjltiujfsw4v diff --git a/scripts/GUI/MainMenu.cs b/scripts/GUI/MainMenu.cs index fc46cd2..0d6c8c6 100644 --- a/scripts/GUI/MainMenu.cs +++ b/scripts/GUI/MainMenu.cs @@ -7,9 +7,12 @@ public partial class MainMenu : Control private Button newGameButton; private Button loadGameButton; private Button quitButton; + private Button leaderboardButton; [Signal] public delegate void GameRequestEventHandler(bool load); + [Signal] + public delegate void LeaderboardRequestEventHandler(); public override void _Ready() { @@ -18,14 +21,18 @@ public partial class MainMenu : Control newGameButton = GetNode<Button>("VBoxContainer/CenterContainer/VBoxContainer/neogame"); loadGameButton = GetNode<Button>("VBoxContainer/CenterContainer/VBoxContainer/continue"); quitButton = GetNode<Button>("VBoxContainer/CenterContainer/VBoxContainer/quit"); + leaderboardButton = GetNode<Button>("VBoxContainer/CenterContainer/VBoxContainer/leaderboard"); newGameButton.Pressed += OnNewGameButtonPressed; loadGameButton.Pressed += OnLoadGameButtonPressed; quitButton.Pressed += OnQuitButtonPressed; + leaderboardButton.Pressed += OnLeaderBoardRequest; newGameButton.GrabFocus(); bool hasSaveFile = FileAccess.FileExists("user://save_game.json"); + bool hasLeaderboard = FileAccess.FileExists("user://placar.json"); loadGameButton.Disabled = !hasSaveFile; + leaderboardButton.Disabled = !hasLeaderboard; } private void OnNewGameButtonPressed() @@ -38,6 +45,11 @@ public partial class MainMenu : Control EmitSignal(SignalName.GameRequest, true); } + private void OnLeaderBoardRequest() + { + EmitSignal(SignalName.LeaderboardRequest); + } + private void OnQuitButtonPressed() { GetTree().Quit(); diff --git a/scripts/Game.cs b/scripts/Game.cs index e55b937..cc86928 100644 --- a/scripts/Game.cs +++ b/scripts/Game.cs @@ -90,6 +90,8 @@ public partial class Game : Node player.AddChild(camera); + Stats.Instance.PlayerName = player.DisplayName; + if (!map.LoadGame(player)) { return false; diff --git a/scripts/GameManager.cs b/scripts/GameManager.cs index 5898744..4215475 100644 --- a/scripts/GameManager.cs +++ b/scripts/GameManager.cs @@ -10,6 +10,7 @@ public partial class GameManager : Node private PackedScene mainMenuScene = GD.Load<PackedScene>("res://scenes/GUI/main_menu.tscn"); private PackedScene gameScene = GD.Load<PackedScene>("res://scenes/Game.tscn"); private PackedScene nameScene = GD.Load<PackedScene>("res://scenes/name_thyself.tscn"); + private PackedScene leaderboardScene = GD.Load<PackedScene>("res://scenes/GUI/Leaderboard.tscn"); private Node currentScene; @@ -42,7 +43,9 @@ public partial class GameManager : Node private void LoadMainMenu() { MainMenu menu = (MainMenu)SwitchToScene(mainMenuScene); + Stats.Instance.Clear(); menu.GameRequest += OnGameRequest; + menu.LeaderboardRequest += OnLeaderboardRequest; } private void LoadGame() @@ -72,6 +75,7 @@ public partial class GameManager : Node private void OnNameSelect(string name) { + Stats.Instance.PlayerName = name; NewGame(name); } @@ -86,4 +90,10 @@ public partial class GameManager : Node LoadGame(); } } + + private void OnLeaderboardRequest() + { + Leaderboard scene = (Leaderboard)SwitchToScene(leaderboardScene); + scene.MenuRequested += LoadMainMenu; + } } diff --git a/scripts/InputHandling/MainGameInputHandler.cs b/scripts/InputHandling/MainGameInputHandler.cs index a18bd73..d1b5818 100644 --- a/scripts/InputHandling/MainGameInputHandler.cs +++ b/scripts/InputHandling/MainGameInputHandler.cs @@ -60,7 +60,7 @@ public partial class MainGameInputHandler : BaseInputHandler if (Input.IsActionJustPressed("quit")) { - action = new EscapeAction(player); + action = new EscapeAction(player, true); } if (Input.IsActionJustPressed("descend")) diff --git a/scripts/Map/DungeonGenerator.cs b/scripts/Map/DungeonGenerator.cs index 31dcffe..cce693a 100644 --- a/scripts/Map/DungeonGenerator.cs +++ b/scripts/Map/DungeonGenerator.cs @@ -3,6 +3,9 @@ using TheLegendOfGustav.Entities.Actors; using TheLegendOfGustav.Entities; using TheLegendOfGustav.Entities.Items; using System; +using Godot.Collections; +using System.Diagnostics.Metrics; +using System.Numerics; namespace TheLegendOfGustav.Map; @@ -14,18 +17,41 @@ public partial class DungeonGenerator : Node { #region Fields /// <summary> + /// Chave: Andar mínimo + /// Valor: Número de máximo de monstros por sala + /// </summary> + private static readonly Dictionary<int, int> maxMonstersByFloor = new() + { + {1, 2}, + {4, 3}, + {6, 4}, + {10, 8} + }; + /// <summary> + /// Chave: Andar mínimo + /// Valor: Número de máximo de itens por sala + /// </summary> + private static readonly Dictionary<int, int> maxItemsByFloor = new() + { + {1, 1}, + {4, 2}, + {6, 3}, + }; + /// <summary> /// Coleção de todos os inimigos que o gerador tem acesso. /// </summary> private static readonly Godot.Collections.Array<EnemyDefinition> enemies = [ GD.Load<EnemyDefinition>("res://assets/definitions/actor/Skeleton.tres"), GD.Load<EnemyDefinition>("res://assets/definitions/actor/morcegao.tres"), GD.Load<EnemyDefinition>("res://assets/definitions/actor/Shadow.tres"), - GD.Load<EnemyDefinition>("res://assets/definitions/actor/omal.tres") + GD.Load<EnemyDefinition>("res://assets/definitions/actor/omal.tres"), + GD.Load<EnemyDefinition>("res://assets/definitions/actor/toilet.tres") ]; private static readonly Godot.Collections.Array<ItemResource> items = [ GD.Load<ItemResource>("res://assets/definitions/Items/small_healing_potion.tres"), - GD.Load<ItemResource>("res://assets/definitions/Items/mana_bolt_grimoire.tres") + GD.Load<ItemResource>("res://assets/definitions/Items/mana_bolt_grimoire.tres"), + GD.Load<ItemResource>("res://assets/definitions/Items/big_potion_of_heals.tres") ]; /// <summary> @@ -48,24 +74,30 @@ public partial class DungeonGenerator : Node /// </summary> [ExportCategory("RNG")] private RandomNumberGenerator rng = new(); - - /// <summary> - /// Quantidade máxima de inimigos por sala. - /// </summary> - [ExportCategory("Monster RNG")] - [Export] - private int maxMonstersPerRoom = 2; - - /// <summary> - /// Quantidade máxima de itens por sala. - /// </summary> - [ExportCategory("Loot RNG")] - [Export] - private int maxItemsPerRoom = 2; #endregion #region Methods + private int GetMaxIValueForFloor(Dictionary<int, int> valueTable, int currentFloor) { + int currentValue = 0; + + int? key = null; + + foreach (int theKey in valueTable.Keys) { + if (theKey > currentFloor) { + break; + } else { + key = theKey; + } + } + + if (key.HasValue) { + currentValue = valueTable[key.Value]; + } + + return currentValue; + } + /// <summary> /// Gera um andar da masmorra. /// Inimigos são colocados conforme configurações. @@ -230,9 +262,9 @@ public partial class DungeonGenerator : Node private void PlaceEntities(MapData data, Rect2I room) { // Define quantos monstros serão colocados na sala - int monsterAmount = rng.RandiRange(0, maxMonstersPerRoom); + int monsterAmount = rng.RandiRange(0, GetMaxIValueForFloor(maxMonstersByFloor, data.CurrentFloor)); // Define quantos itens serão colocados na sala. - int itemAmount = rng.RandiRange(0, maxItemsPerRoom); + int itemAmount = rng.RandiRange(0, GetMaxIValueForFloor(maxItemsByFloor, data.CurrentFloor)); for (int i = 0; i < monsterAmount; i++) { diff --git a/scripts/Utils/Stats.cs b/scripts/Utils/Stats.cs new file mode 100644 index 0000000..d3c4aa3 --- /dev/null +++ b/scripts/Utils/Stats.cs @@ -0,0 +1,52 @@ +using Godot; +using Godot.Collections; +using TheLegendOfGustav.Utils; + +namespace TheLegendOfGustav.Utils; + +public partial class Stats : Node +{ + public static Stats Instance { get; set; } + + public string PlayerName { get; set; } + public int MaxFloor { get; set; } = 0; + + public int EnemiesKilled { get; set; } = 0; + + public int DamageTaken { get; set; } = 0; + + public override void _Ready() + { + base._Ready(); + Instance = this; + + SignalBus.Instance.DungeonFloorChanged += OnFloorChange; + } + + public void Clear() + { + PlayerName = ""; + MaxFloor = 0; + EnemiesKilled = 0; + DamageTaken = 0; + } + + void OnFloorChange(int floor) + { + if (floor > MaxFloor) + { + MaxFloor = floor; + } + } + + public Dictionary<string, Variant> Serialize() + { + return new() + { + {"jogador", PlayerName}, + {"andar_mais_fundo", MaxFloor}, + {"inimigos_mortos", EnemiesKilled}, + {"dano_tomado", DamageTaken} + }; + } +}
\ No newline at end of file diff --git a/scripts/Utils/Stats.cs.uid b/scripts/Utils/Stats.cs.uid new file mode 100644 index 0000000..a93778d --- /dev/null +++ b/scripts/Utils/Stats.cs.uid @@ -0,0 +1 @@ +uid://eg7t08o6wpxb |
