Compare commits

...

4 Commits

30 changed files with 520 additions and 10 deletions

BIN
Fonts/COMIC.TTF Normal file

Binary file not shown.

35
Fonts/COMIC.TTF.import Normal file
View File

@@ -0,0 +1,35 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://b8tf6dbm2j0ju"
path="res://.godot/imported/COMIC.TTF-856a12f50d25f6c40b9b7475a5a3c8de.fontdata"
[deps]
source_file="res://Fonts/COMIC.TTF"
dest_files=["res://.godot/imported/COMIC.TTF-856a12f50d25f6c40b9b7475a5a3c8de.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
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
Fonts/ComicSansMS3.ttf Normal file

Binary file not shown.

View File

@@ -0,0 +1,35 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://bns5c6hocyjua"
path="res://.godot/imported/ComicSansMS3.ttf-96b759465ff31d11f80283a7c12539ca.fontdata"
[deps]
source_file="res://Fonts/ComicSansMS3.ttf"
dest_files=["res://.godot/imported/ComicSansMS3.ttf-96b759465ff31d11f80283a7c12539ca.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
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
Fonts/comici.ttf Normal file

Binary file not shown.

35
Fonts/comici.ttf.import Normal file
View File

@@ -0,0 +1,35 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://bn4w716pu11lj"
path="res://.godot/imported/comici.ttf-66bd62e0af47442ee6f5c29193ae1405.fontdata"
[deps]
source_file="res://Fonts/comici.ttf"
dest_files=["res://.godot/imported/comici.ttf-66bd62e0af47442ee6f5c29193ae1405.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
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
Fonts/comicz.ttf Normal file

Binary file not shown.

35
Fonts/comicz.ttf.import Normal file
View File

@@ -0,0 +1,35 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://cxiv86ha7xb6"
path="res://.godot/imported/comicz.ttf-66a741130a0c8d7e12d809da56e73bbf.fontdata"
[deps]
source_file="res://Fonts/comicz.ttf"
dest_files=["res://.godot/imported/comicz.ttf-66a741130a0c8d7e12d809da56e73bbf.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
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={}

Binary file not shown.

View File

@@ -0,0 +1,35 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://cqj7ianpr6jau"
path="res://.godot/imported/design.graffiti.comicsansms.ttf-6b5fd3e9dc5336099f793666df4ffc33.fontdata"
[deps]
source_file="res://Fonts/design.graffiti.comicsansms.ttf"
dest_files=["res://.godot/imported/design.graffiti.comicsansms.ttf-6b5fd3e9dc5336099f793666df4ffc33.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
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={}

Binary file not shown.

View File

@@ -0,0 +1,35 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://cafeq0txk8o1p"
path="res://.godot/imported/design.graffiti.comicsansmsgras.ttf-ab7fcd3a4b4dcda31884c957a19862a4.fontdata"
[deps]
source_file="res://Fonts/design.graffiti.comicsansmsgras.ttf"
dest_files=["res://.godot/imported/design.graffiti.comicsansmsgras.ttf-ab7fcd3a4b4dcda31884c957a19862a4.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
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={}

View File

@@ -0,0 +1,7 @@
[gd_scene load_steps=2 format=3 uid="uid://c2baysanqtp8g"]
[ext_resource type="Texture2D" uid="uid://c46t8kj1gb5qd" path="res://Sprites/castle.png" id="1_42k1r"]
[node name="CastleTier1" type="Sprite2D"]
scale = Vector2(0.03, 0.03)
texture = ExtResource("1_42k1r")

View File

@@ -0,0 +1,7 @@
[gd_scene load_steps=2 format=3 uid="uid://cg5mdwkf7fxqn"]
[ext_resource type="Texture2D" uid="uid://c61h7a8byuyeu" path="res://Sprites/house.png" id="1_ub3ef"]
[node name="HouseTier1" type="Sprite2D"]
scale = Vector2(0.02, 0.02)
texture = ExtResource("1_ub3ef")

View File

@@ -0,0 +1,11 @@
[gd_scene load_steps=2 format=3 uid="uid://bi6053qjm60vt"]
[ext_resource type="Texture2D" uid="uid://c61h7a8byuyeu" path="res://Sprites/house.png" id="1_8opcd"]
[node name="HouseTier2" type="Sprite2D"]
scale = Vector2(0.02, 0.02)
texture = ExtResource("1_8opcd")
[node name="Sprite2D" type="Sprite2D" parent="."]
position = Vector2(450, 0)
texture = ExtResource("1_8opcd")

View File

@@ -0,0 +1,15 @@
[gd_scene load_steps=2 format=3 uid="uid://ctqgx6alvxci0"]
[ext_resource type="Texture2D" uid="uid://c61h7a8byuyeu" path="res://Sprites/house.png" id="1_rp41l"]
[node name="HouseTier2" type="Sprite2D"]
scale = Vector2(0.02, 0.02)
texture = ExtResource("1_rp41l")
[node name="Sprite2D2" type="Sprite2D" parent="."]
position = Vector2(-550, 0)
texture = ExtResource("1_rp41l")
[node name="Sprite2D" type="Sprite2D" parent="."]
position = Vector2(450, 0)
texture = ExtResource("1_rp41l")

View File

@@ -1,5 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using Godot;
using ParasiticGod.Scripts.Core;
using ParasiticGod.Scripts.Core.Effects;
using ParasiticGod.Scripts.Singletons;
namespace ParasiticGod.Scenes.Main;
@@ -27,11 +30,19 @@ public partial class MiracleButton : Button
}
Pressed += OnPressed;
GameBus.Instance.StateChanged += UpdateAvailability;
UpdateAvailability(GameBus.Instance.CurrentState);
}
public override void _ExitTree()
{
Pressed -= OnPressed;
if (GameBus.Instance != null)
{
GameBus.Instance.StateChanged -= UpdateAvailability;
}
}
private void OnPressed()
@@ -43,25 +54,95 @@ public partial class MiracleButton : Button
public void SetMiracle(MiracleDefinition miracle)
{
_miracle = miracle;
Text = BuildText();
TooltipText = BuildTooltipText();
}
public MiracleDefinition GetMiracle() { return _miracle; }
/// <summary>
/// Checks the miracle's requirements against the current game state
/// and updates the button's disabled status and tooltip.
/// </summary>
private void UpdateAvailability(GameState state)
{
if (_miracle == null) return;
var missingRequirements = new List<string>();
if (state.Get(Stat.Faith) < _miracle.FaithCost)
{
missingRequirements.Add($"Not enough Faith ({state.Get(Stat.Faith):F0} / {_miracle.FaithCost})");
}
if (state.Get(Stat.Followers) < _miracle.FollowersRequired)
{
missingRequirements.Add($"Not enough Followers ({(long)state.Get(Stat.Followers)} / {_miracle.FollowersRequired})");
}
if (state.Get(Stat.Production) < _miracle.ProductionRequired)
{
missingRequirements.Add($"Not enough Production ({state.Get(Stat.Production):F0} / {_miracle.ProductionRequired})");
}
if (AreAllUnlocksAlreadyPresent(state))
{
missingRequirements.Add("Already unlocked subsequent powers.");
}
if (missingRequirements.Any())
{
Disabled = true;
TooltipText = string.Join("\n", missingRequirements);
}
else
{
Disabled = false;
TooltipText = BuildTooltipText();
}
}
private string BuildText()
{
return $"{_miracle.Name}\nCost: {_miracle.FaithCost} Faith";
string costText;
if (_miracle.ProductionRequired > 0 && _miracle.FaithCost <= 0)
{
costText = $"Cost: {_miracle.ProductionRequired:F0} Prod";
}
else
{
costText = $"Cost: {_miracle.FaithCost:F0} Faith";
}
return $"{_miracle.Name}\n{costText}";
}
private string BuildTooltipText()
{
var tooltip = $"Cost: {_miracle.FaithCost} Faith\nRequires: {_miracle.FollowersRequired} Followers\nEffects:\n";
var tooltip = "";
if (_miracle.FaithCost > 0)
tooltip += $"Cost: {_miracle.FaithCost:F0} Faith\n";
if (_miracle.ProductionRequired > 0)
tooltip += $"Cost: {_miracle.ProductionRequired:F0} Production\n";
if (_miracle.FollowersRequired > 0)
tooltip += $"Requires: {_miracle.FollowersRequired} Followers\n";
tooltip += "\nEffects:\n";
foreach (var effect in _miracle.Effects)
{
if (effect.ToString() == string.Empty) continue;
if (string.IsNullOrEmpty(effect.ToString())) continue;
tooltip += $"- {effect}\n";
}
return tooltip.TrimEnd();
}
private bool AreAllUnlocksAlreadyPresent(GameState state)
{
var unlockEffect = _miracle.Effects.OfType<UnlockMiracleEffect>().FirstOrDefault();
if (unlockEffect == null || unlockEffect.MiraclesToUnlock.Count == 0)
{
return false;
}
return unlockEffect.MiraclesToUnlock.All(state.IsMiracleUnlocked);
}
}

View File

@@ -27,6 +27,7 @@ public partial class MiraclePanel : GridContainer
{
if (miracle.UnlockedByDefault)
{
GameBus.Instance.CurrentState.AddUnlockedMiracle(miracle.Id);
AddButtonForMiracle(miracle);
}
}

View File

@@ -1,10 +1,42 @@
[gd_scene load_steps=2 format=3 uid="uid://crpf0llofg0sc"]
[gd_scene load_steps=3 format=3 uid="uid://crpf0llofg0sc"]
[ext_resource type="Script" uid="uid://drx8lqcjq5khj" path="res://Scripts/NotificationLabel.cs" id="1_x4sn4"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_4bx8n"]
bg_color = Color(0.187176, 0.187176, 0.187176, 1)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
border_color = Color(1, 0.759215, 0.00113704, 1)
corner_radius_top_left = 2
corner_radius_top_right = 2
corner_radius_bottom_right = 2
corner_radius_bottom_left = 2
[node name="NotificationLabel" type="Label"]
offset_right = 40.0
offset_bottom = 23.0
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -20.0
offset_top = -11.5
offset_right = 20.0
offset_bottom = 11.5
grow_horizontal = 2
grow_vertical = 2
horizontal_alignment = 1
vertical_alignment = 1
script = ExtResource("1_x4sn4")
[node name="Panel" type="Panel" parent="."]
z_index = -1
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_4bx8n")
metadata/_edit_group_ = true

View File

@@ -7,12 +7,12 @@ namespace ParasiticGod.Scripts.Core;
public class GameState
{
private readonly Dictionary<Stat, StatData> _stats = new();
private readonly HashSet<string> _unlockedMiracleIds = [];
public List<Buff> ActiveBuffs { get; } = [];
public GameState()
{
// Initialize all stats with their default values
foreach (Stat stat in Enum.GetValues(typeof(Stat)))
{
_stats[stat] = new StatData();
@@ -34,4 +34,8 @@ public class GameState
public void Subscribe(Stat stat, Action<double> listener) => _stats[stat].OnChanged += listener;
public void Unsubscribe(Stat stat, Action<double> listener) => _stats[stat].OnChanged -= listener;
public bool IsMiracleUnlocked(string miracleId) => _unlockedMiracleIds.Contains(miracleId);
public void AddUnlockedMiracle(string miracleId) => _unlockedMiracleIds.Add(miracleId);
public void RemoveUnlockedMiracle(string miracleId) => _unlockedMiracleIds.Remove(miracleId);
}

View File

@@ -63,15 +63,17 @@ public partial class GameBus : Node
{
foreach (var id in unlockEffect.MiraclesToUnlock)
{
if (AllMiracles.TryGetValue(id, out var def))
if (AllMiracles.TryGetValue(id, out var def) && !_gameState.IsMiracleUnlocked(id))
{
miraclesToUnlock.Add(def);
_gameState.AddUnlockedMiracle(id);
}
}
}
else if (effect is DestroySelfEffect)
{
MiracleCompleted?.Invoke(miracle);
_gameState.RemoveUnlockedMiracle(miracle.Id);
}
}

BIN
Sprites/Skyscraper_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://co1y3dsxcfnpn"
path="res://.godot/imported/Skyscraper_.png-ec868c9b8a39b17bf1b69670855d6c65.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Sprites/Skyscraper_.png"
dest_files=["res://.godot/imported/Skyscraper_.png-ec868c9b8a39b17bf1b69670855d6c65.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
Sprites/Temple.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

34
Sprites/Temple.png.import Normal file
View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://0kdbw1wq84cy"
path="res://.godot/imported/Temple.png-bbfd6e2acabd3b07b72f1721088a689b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Sprites/Temple.png"
dest_files=["res://.godot/imported/Temple.png-bbfd6e2acabd3b07b72f1721088a689b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
Sprites/castle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

34
Sprites/castle.png.import Normal file
View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c46t8kj1gb5qd"
path="res://.godot/imported/castle.png-097c4f1f7de5632f56fc5c5655dd5ba7.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Sprites/castle.png"
dest_files=["res://.godot/imported/castle.png-097c4f1f7de5632f56fc5c5655dd5ba7.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
Sprites/house.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

34
Sprites/house.png.import Normal file
View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c61h7a8byuyeu"
path="res://.godot/imported/house.png-1067fa9882230073ba8664adfd8b09b2.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Sprites/house.png"
dest_files=["res://.godot/imported/house.png-1067fa9882230073ba8664adfd8b09b2.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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

View File

@@ -30,6 +30,10 @@ window/stretch/mode="canvas_items"
project/assembly_name="ParasiticGod"
[gui]
theme/custom_font="uid://b8tf6dbm2j0ju"
[rendering]
renderer/rendering_method="gl_compatibility"