Compare commits

..

10 Commits

Author SHA1 Message Date
bf11d6a9cb Add new components: BrickThrowComponent, BulletComponent, CageComponent, ChaseLevelComponent, CleanupComponent, and ThrowInputResource classes; implement game saving and loading logic in SaveSystem 2025-08-12 13:12:16 +02:00
dfa8a17ba1 Add new components: CannotStompComponent, SkillUnlockedComponent, SpaceshipEnterComponent, SpaceshipExitComponent, SpinComponent, StompDamageComponent, StraightMotionComponent, TerrainHitFx, TooltipComponent, TrailComponent, and UnlockOnRequirementComponent 2025-08-12 12:19:18 +02:00
ef4d128869 Refactor GameManager session state handling and add new components: CanBeLaunchedComponent, IceEffectComponent, JumpPadComponent, KillPlayerOutOfScreenComponent, KnockbackComponent, LifetimeComponent, MagneticSkillComponent, OutOfScreenComponent, PeriodicShootingComponent, PlayerDeathComponent, ProgressiveDamageComponent, ProjectileComponent, ProjectileInitComponent, RequirementComponent, ScoreComponent, ShipMovementComponent, ShipShooterComponent, and SideToSideMovementComponent 2025-08-12 03:38:23 +02:00
f3aa2631f2 Add new components: HealComponent, HitComponent, HomingMissileMotionComponent, LeverComponent, and TriggerLeverComponent 2025-08-10 22:38:19 +02:00
54ffa8a42c Add new components: ExplosiveComponent, FadeAwayComponent, FireEffectComponent, FlipComponent, GravityMotionComponent, LaunchComponent, and update PlatformMovement with LastDirection property 2025-08-10 17:53:06 +02:00
ac477115c5 Add new components: EnemyDeathComponent, EnemyWaveTriggerComponent, and ExitDoorComponent 2025-08-10 14:50:18 +02:00
99473d1295 Add new components: CanPickUpComponent, CollapsableComponent, DestroyableComponent, EffectInflictorComponent, StatusEffectComponent, and StatusEffectDataResource 2025-08-10 12:57:58 +02:00
5dbf04cc5f cleanup 2025-08-10 01:36:13 +02:00
4098d192af Add core game components including ConfigFileHandler, GameManager, SaveSystem, and UIManager 2025-08-10 01:35:35 +02:00
8467f67090 Implement BeamComponent in C# and enhance marketplace button functionality 2025-07-21 22:02:05 +02:00
147 changed files with 191 additions and 1605 deletions

View File

@@ -5,9 +5,7 @@ namespace Mr.BrickAdventures.Autoloads;
public partial class ConfigFileHandler : Node
{
private ConfigFile _settingsConfig = new();
public const string SettingsPath = "user://settings.ini";
public ConfigFile SettingsConfig => _settingsConfig;
private const string SettingsPath = "user://settings.ini";
public override void _Ready()
{

View File

@@ -1 +0,0 @@
uid://8cyvbeyd13cj

View File

@@ -1,8 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Godot;
using Godot.Collections;
using Mr.BrickAdventures.scripts.components;
using Mr.BrickAdventures.scripts.Resources;
namespace Mr.BrickAdventures.Autoloads;
@@ -10,10 +7,6 @@ namespace Mr.BrickAdventures.Autoloads;
public partial class GameManager : Node
{
[Export] public Array<PackedScene> LevelScenes { get; set; } = new();
public PlayerController Player { get; set; }
private List<Node> _sceneNodes = new();
public Dictionary PlayerState { get; set; } = new()
{
@@ -31,29 +24,6 @@ public partial class GameManager : Node
{ "skills_unlocked", new Array<SkillData>() }
};
public override void _EnterTree()
{
GetTree().NodeAdded += OnNodeAdded;
GetTree().NodeRemoved += OnNodeRemoved;
}
public override void _ExitTree()
{
GetTree().NodeAdded -= OnNodeAdded;
GetTree().NodeRemoved -= OnNodeRemoved;
_sceneNodes.Clear();
}
private void OnNodeAdded(Node node)
{
_sceneNodes.Add(node);
}
private void OnNodeRemoved(Node node)
{
_sceneNodes.Remove(node);
}
public void AddCoins(int amount)
{
PlayerState["coins"] = Mathf.Max(0, (int)PlayerState["coins"] + amount);
@@ -211,31 +181,15 @@ public partial class GameManager : Node
GetNode<SaveSystem>("/root/SaveSystem").SaveGame();
}
public Array<SkillData> GetUnlockedSkills()
public Array GetUnlockedSkills()
{
var unlocked = (Array<SkillData>)PlayerState["unlocked_skills"];
var session = (Array<SkillData>)CurrentSessionState["skills_unlocked"];
if (session!.Count == 0) return unlocked;
if (unlocked!.Count == 0) return session;
var joined = new Array<SkillData>();
joined.AddRange(unlocked);
joined.AddRange(session);
if ((((Array)session)!).Count == 0) return (Array)unlocked;
if ((((Array)unlocked)!).Count == 0) return (Array)session;
var joined = new Array();
joined.AddRange((Array)unlocked ?? new Array());
joined.AddRange((Array)session ?? new Array());
return joined;
}
public PlayerController GetPlayer()
{
if (Player != null) return Player;
foreach (var node in _sceneNodes)
{
if (node is not PlayerController player) continue;
Player = player;
return Player;
}
GD.PrintErr("PlayerController not found in the scene tree.");
return null;
}
}

View File

@@ -1 +0,0 @@
uid://c6eoi3ymefc0x

View File

@@ -1 +0,0 @@
uid://bh20fqbyifidc

View File

@@ -1 +0,0 @@
uid://c3ldmnrwperr4

View File

@@ -5,9 +5,137 @@
<RootNamespace>Mr.BrickAdventures</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Chickensoft.AutoInject" Version="2.8.21" />
<PackageReference Include="Chickensoft.GodotNodeInterfaces" Version="2.4.31" />
<PackageReference Include="Chickensoft.Introspection" Version="3.0.2" />
<PackageReference Include="Chickensoft.Introspection.Generator" Version="3.0.2" PrivateAssets="all" OutputItemType="analyzer" />
<Content Include="scripts\components\.idea\.gitignore" />
<Content Include="scripts\components\.idea\encodings.xml" />
<Content Include="scripts\components\.idea\indexLayout.xml" />
<Content Include="scripts\components\.idea\inspectionProfiles\Project_Default.xml" />
<Content Include="scripts\components\.idea\projectSettingsUpdater.xml" />
<Content Include="scripts\components\.idea\vcs.xml" />
<Content Include="scripts\components\.idea\workspace.xml" />
<Content Include="scripts\components\BeamComponent.cs.uid" />
<Content Include="scripts\components\beam_component.gd" />
<Content Include="scripts\components\beam_component.gd.uid" />
<Content Include="scripts\components\brick_throw.gd" />
<Content Include="scripts\components\brick_throw.gd.uid" />
<Content Include="scripts\components\bullet_component.gd" />
<Content Include="scripts\components\bullet_component.gd.uid" />
<Content Include="scripts\components\cage_component.gd" />
<Content Include="scripts\components\cage_component.gd.uid" />
<Content Include="scripts\components\cannot_stomp_component.gd" />
<Content Include="scripts\components\cannot_stomp_component.gd.uid" />
<Content Include="scripts\components\can_be_launched_component.gd" />
<Content Include="scripts\components\can_be_launched_component.gd.uid" />
<Content Include="scripts\components\can_pickup.gd" />
<Content Include="scripts\components\can_pickup.gd.uid" />
<Content Include="scripts\components\charge_throw_component.gd" />
<Content Include="scripts\components\charge_throw_component.gd.uid" />
<Content Include="scripts\components\chase_level_component.gd" />
<Content Include="scripts\components\chase_level_component.gd.uid" />
<Content Include="scripts\components\cleanup_component.gd" />
<Content Include="scripts\components\cleanup_component.gd.uid" />
<Content Include="scripts\components\collapsable.gd" />
<Content Include="scripts\components\collapsable.gd.uid" />
<Content Include="scripts\components\collectable.gd" />
<Content Include="scripts\components\collectable.gd.uid" />
<Content Include="scripts\components\damage_component.gd" />
<Content Include="scripts\components\damage_component.gd.uid" />
<Content Include="scripts\components\destroyable_component.gd" />
<Content Include="scripts\components\destroyable_component.gd.uid" />
<Content Include="scripts\components\effect_inflictor_component.gd" />
<Content Include="scripts\components\effect_inflictor_component.gd.uid" />
<Content Include="scripts\components\enemy_death.gd" />
<Content Include="scripts\components\enemy_death.gd.uid" />
<Content Include="scripts\components\enemy_wave_trigger.gd" />
<Content Include="scripts\components\enemy_wave_trigger.gd.uid" />
<Content Include="scripts\components\exit_door_component.gd" />
<Content Include="scripts\components\exit_door_component.gd.uid" />
<Content Include="scripts\components\explosive_component.gd" />
<Content Include="scripts\components\explosive_component.gd.uid" />
<Content Include="scripts\components\fade_away.gd" />
<Content Include="scripts\components\fade_away.gd.uid" />
<Content Include="scripts\components\fire_effect_component.gd" />
<Content Include="scripts\components\fire_effect_component.gd.uid" />
<Content Include="scripts\components\flashing_component.gd" />
<Content Include="scripts\components\flashing_component.gd.uid" />
<Content Include="scripts\components\flip_player.gd" />
<Content Include="scripts\components\flip_player.gd.uid" />
<Content Include="scripts\components\gravity_motion_component.gd" />
<Content Include="scripts\components\gravity_motion_component.gd.uid" />
<Content Include="scripts\components\health.gd" />
<Content Include="scripts\components\health.gd.uid" />
<Content Include="scripts\components\heal_component.gd" />
<Content Include="scripts\components\heal_component.gd.uid" />
<Content Include="scripts\components\hit_component.gd" />
<Content Include="scripts\components\hit_component.gd.uid" />
<Content Include="scripts\components\homing_missile_motion.gd" />
<Content Include="scripts\components\homing_missile_motion.gd.uid" />
<Content Include="scripts\components\ice_effect_component.gd" />
<Content Include="scripts\components\ice_effect_component.gd.uid" />
<Content Include="scripts\components\invulnerability_component.gd" />
<Content Include="scripts\components\invulnerability_component.gd.uid" />
<Content Include="scripts\components\jump_pad_component.gd" />
<Content Include="scripts\components\jump_pad_component.gd.uid" />
<Content Include="scripts\components\kill_player_out_of_screen.gd" />
<Content Include="scripts\components\kill_player_out_of_screen.gd.uid" />
<Content Include="scripts\components\knockback.gd" />
<Content Include="scripts\components\knockback.gd.uid" />
<Content Include="scripts\components\launch_component.gd" />
<Content Include="scripts\components\launch_component.gd.uid" />
<Content Include="scripts\components\lever_component.gd" />
<Content Include="scripts\components\lever_component.gd.uid" />
<Content Include="scripts\components\lifetime_component.gd" />
<Content Include="scripts\components\lifetime_component.gd.uid" />
<Content Include="scripts\components\magnetic_skill.gd" />
<Content Include="scripts\components\magnetic_skill.gd.uid" />
<Content Include="scripts\components\out_of_screen_component.gd" />
<Content Include="scripts\components\out_of_screen_component.gd.uid" />
<Content Include="scripts\components\periodic_shooting.gd" />
<Content Include="scripts\components\periodic_shooting.gd.uid" />
<Content Include="scripts\components\PlatformMovementComponent.cs.uid" />
<Content Include="scripts\components\PlayerController.cs.uid" />
<Content Include="scripts\components\player_death.gd" />
<Content Include="scripts\components\player_death.gd.uid" />
<Content Include="scripts\components\player_movement.gd" />
<Content Include="scripts\components\player_movement.gd.uid" />
<Content Include="scripts\components\progressive_damage_component.gd" />
<Content Include="scripts\components\progressive_damage_component.gd.uid" />
<Content Include="scripts\components\projectile_component.gd" />
<Content Include="scripts\components\projectile_component.gd.uid" />
<Content Include="scripts\components\projectile_init_component.gd" />
<Content Include="scripts\components\projectile_init_component.gd.uid" />
<Content Include="scripts\components\requirement_component.gd" />
<Content Include="scripts\components\requirement_component.gd.uid" />
<Content Include="scripts\components\score.gd" />
<Content Include="scripts\components\score.gd.uid" />
<Content Include="scripts\components\ship_movement.gd" />
<Content Include="scripts\components\ship_movement.gd.uid" />
<Content Include="scripts\components\ship_shooter.gd" />
<Content Include="scripts\components\ship_shooter.gd.uid" />
<Content Include="scripts\components\side_to_side_movement.gd" />
<Content Include="scripts\components\side_to_side_movement.gd.uid" />
<Content Include="scripts\components\skill_unlocker_component.gd" />
<Content Include="scripts\components\skill_unlocker_component.gd.uid" />
<Content Include="scripts\components\spaceship_enter_component.gd" />
<Content Include="scripts\components\spaceship_enter_component.gd.uid" />
<Content Include="scripts\components\spaceship_exit_component.gd" />
<Content Include="scripts\components\spaceship_exit_component.gd.uid" />
<Content Include="scripts\components\spin_component.gd" />
<Content Include="scripts\components\spin_component.gd.uid" />
<Content Include="scripts\components\status_effect_component.gd" />
<Content Include="scripts\components\status_effect_component.gd.uid" />
<Content Include="scripts\components\stomp_damage_component.gd" />
<Content Include="scripts\components\stomp_damage_component.gd.uid" />
<Content Include="scripts\components\straight_motion_component.gd" />
<Content Include="scripts\components\straight_motion_component.gd.uid" />
<Content Include="scripts\components\terrain_hit_fx.gd" />
<Content Include="scripts\components\terrain_hit_fx.gd.uid" />
<Content Include="scripts\components\tooltip_component.gd" />
<Content Include="scripts\components\tooltip_component.gd.uid" />
<Content Include="scripts\components\trail_component.gd" />
<Content Include="scripts\components\trail_component.gd.uid" />
<Content Include="scripts\components\trigger_lever_component.gd" />
<Content Include="scripts\components\trigger_lever_component.gd.uid" />
<Content Include="scripts\components\unlock_on_requirement_component.gd" />
<Content Include="scripts\components\unlock_on_requirement_component.gd.uid" />
</ItemGroup>
</Project>

View File

@@ -1,72 +0,0 @@
# Przygody Pana Cegły
[![Steam Wishlist](https://img.shields.io/badge/🎮%20PLAY%20NOW%20on%20Steam-FF4C4C?style=for-the-badge&logo=steam&logoColor=white)](https://store.steampowered.com/app/3575090/Mr_Brick_Adventures/)
![Made With Godot](https://img.shields.io/badge/Made%20With-Godot-478CBF?style=for-the-badge&logo=godot-engine&logoColor=white)
![Lines of Code](https://tokei.rs/b1/github/GKaszewski/ppc_v2?style=for-the-badge&category=code)
![Last Commit](https://img.shields.io/github/last-commit/GKaszewski/ppc_v2?style=for-the-badge)
![Stars](https://img.shields.io/github/stars/GKaszewski/ppc_v2?style=for-the-badge)
*"The worlds only brick-throwing dad simulator (probably)."*
---
## The Story
Disaster has struck!
Mr. Bricks kids have gone missing, scattered across mysterious lands filled with treacherous traps, cranky critters, and more collapsing bridges than an OSHA nightmare.
Armed with nothing but his legs, his wits, and an infinite supply of throwable bricks (dont ask where he keeps them), Mr. Brick will stop at nothing to bring his children home.
---
## The Mission
Run, jump, and hurl bricks with pinpoint accuracy as you navigate dangerous worlds. Smash enemies, trigger ancient mechanisms, and uncover hidden treasures, all while dodging hazards that seem designed specifically to ruin your day.
---
## Features Thatll Knock Your Bricks Off
* **Tight, Classic Platforming**
Leap over pits, time your jumps, and try not to land in something unpleasant.
* **Brick-Fu Combat**
Toss bricks to flatten foes, flip switches, and solve puzzles in the most dad-like way possible.
* **Secrets & Collectibles**
Hunt for coins, discover hidden rooms, and find upgrades to make you just a *little* less fragile.
* **NES-Inspired Pixel Art**
All the charm of an 8-bit classic, no cartridge blowing required.
---
## Play It Here
[**Wishlist on Steam**](https://store.steampowered.com/app/3575090/Mr_Brick_Adventures/) so youre ready for launch day.
---
## 📊 Project Stats
📦 **Lines of Code:**
![Lines of code](https://tokei.rs/b1/github/GKaszewski/ppc_v2)
📈 **Repo Activity:**
![Commit activity](https://img.shields.io/github/commit-activity/m/GKaszewski/ppc_v2)
---
## License
Check the [LICENSE](./LICENSE) for the legal stuff.
---
## Contributing
Not open to code contributions right now but you *can* help by:
* Reporting bugs
* Suggesting evil new trap ideas
* Spreading the word so Mr. Brick can find his kids faster

View File

@@ -1,10 +0,0 @@
using Godot;
namespace Mr.BrickAdventures.app;
public interface IGameScenes
{
void Load(PackedScene scene);
void Restart();
void ReturnToMain(PackedScene mainMenu);
}

View File

@@ -1 +0,0 @@
uid://b7d1ospa5p4nx

View File

@@ -1,11 +0,0 @@
using Godot;
namespace Mr.BrickAdventures.app;
public interface ILevelCatalog
{
int Count { get; }
PackedScene? Get(int index);
PackedScene First { get; }
PackedScene MainMenu { get; }
}

View File

@@ -1 +0,0 @@
uid://b2sxttgvk6nuq

View File

@@ -1,70 +0,0 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
using Godot.Collections;
using Mr.BrickAdventures.app;
using Mr.BrickAdventures.data;
using Mr.BrickAdventures.game.repositories;
using Mr.BrickAdventures.game.services;
namespace Mr.BrickAdventures.common;
[Meta(typeof(IAutoNode))]
public partial class AppRoot : Node2D,
IProvide<PlayerRepository>,
IProvide<LevelRepository>,
IProvide<SaveClient>,
IProvide<SaveService>,
IProvide<LevelService>,
IProvide<IGameScenes>,
IProvide<ILevelCatalog>,
IGameScenes
{
public override void _Notification(int what) => this.Notify(what);
[Export] private Array<PackedScene> _levels = [];
[Export] private PackedScene _mainMenu = null!;
private readonly SaveClient _save = new("user://savegame.save", version: 2);
private readonly PlayerRepository _players = new();
private readonly LevelRepository _levelsRepo = new();
private SaveService _saveService = null!;
private LevelService _levelService = null!;
private ILevelCatalog _catalog = null!;
PlayerRepository IProvide<PlayerRepository>.Value() => _players;
LevelRepository IProvide<LevelRepository>.Value() => _levelsRepo;
SaveClient IProvide<SaveClient>.Value() => _save;
SaveService IProvide<SaveService>.Value() => _saveService;
LevelService IProvide<LevelService>.Value() => _levelService;
ILevelCatalog IProvide<ILevelCatalog>.Value() => _catalog;
IGameScenes IProvide<IGameScenes>.Value() => this;
public void OnReady()
{
_saveService = new SaveService(_players, _levelsRepo, _save);
_levelService = new LevelService(_levelsRepo);
_catalog = new ExportedLevelCatalog(_levels, _mainMenu);
_saveService.TryLoad();
this.Provide();
}
public void Load(PackedScene scene) => GetTree().ChangeSceneToPacked(scene);
public void Restart() => GetTree().ReloadCurrentScene();
public void ReturnToMain(PackedScene mainMenu) => GetTree().ChangeSceneToPacked(mainMenu);
private sealed class ExportedLevelCatalog : ILevelCatalog
{
private readonly Array<PackedScene> _levels;
public PackedScene MainMenu { get; }
public ExportedLevelCatalog(Array<PackedScene> levels, PackedScene mainMenu) {
_levels = levels; MainMenu = mainMenu;
}
public int Count => _levels.Count;
public PackedScene? Get(int index) => (index >= 0 && index < _levels.Count) ? _levels[index] : null;
public PackedScene First => _levels.Count > 0 ? _levels[0] : MainMenu;
}
}

View File

@@ -1 +0,0 @@
uid://dg2l7cw6da4vb

View File

@@ -1,6 +0,0 @@
namespace Mr.BrickAdventures.data;
public class ConfigClient
{
}

View File

@@ -1 +0,0 @@
uid://d3s774lnoljcu

View File

@@ -1,103 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Godot;
using Godot.Collections;
using Mr.BrickAdventures.game.repositories;
namespace Mr.BrickAdventures.data;
public sealed class SaveClient
{
private readonly string _path;
private readonly int _version;
public SaveClient(string path, int version) { _path = path; _version = version; }
public bool Exists() => FileAccess.FileExists(_path);
public bool TryLoad(out PlayerState player, out LevelState level) {
player = null!; level = null!;
if (!Exists()) return false;
using var f = FileAccess.Open(_path, FileAccess.ModeFlags.Read);
var dict = (Dictionary)f.GetVar();
if ((int)dict.GetValueOrDefault("version", -1) != _version) return false;
player = ToPlayer((Dictionary)dict["player"]);
level = ToLevel((Dictionary)dict["level"]);
return true;
}
// Strict load: requires version + player_state + level_state.
// If anything is off, delete the file and act as "no save".
public bool TryLoadStrict(out PlayerState player, out LevelState level) {
player = default!;
level = default!;
if (!Exists()) return false;
try {
using var f = FileAccess.Open(_path, FileAccess.ModeFlags.Read);
if (f == null) { Delete(); return false; }
var dictionary = (Dictionary)f.GetVar();
if (!dictionary.TryGetValue("version", out var v) || (int)v != _version) { Delete(); return false; }
if (!dictionary.TryGetValue("player_state", out var pObj) || (Dictionary)pObj is not { } p) { Delete(); return false; }
if (!dictionary.TryGetValue("level_state", out var lObj) || (Dictionary)lObj is not { } l) { Delete(); return false; }
player = ToPlayer(p);
level = ToLevel(l);
return true;
}
catch (Exception e) {
GD.PushWarning($"SaveClient: load failed — deleting bad save. {e.GetType().Name}: {e.Message}");
Delete();
return false;
}
}
public void Save(PlayerState player, LevelState level) {
using var f = FileAccess.Open(_path, FileAccess.ModeFlags.Write);
var dict = new Dictionary {
{ "version", _version },
{ "player", FromPlayer(player) },
{ "level", FromLevel(level) }
};
f.StoreVar(dict);
}
public void Delete() {
if (!Exists()) return;
var abs = ProjectSettings.GlobalizePath(_path);
var ok = DirAccess.RemoveAbsolute(abs);
if (ok != Error.Ok) GD.PushWarning($"SaveClient: failed to delete {_path}: {ok}");
}
private static Dictionary FromPlayer(PlayerState s) => new() { { "coins", s.Coins }, { "lives", s.Lives } };
private static PlayerState ToPlayer(Dictionary d) => new() {
Coins = d.TryGetValue("coins", out var c) ? (int)c : 0,
Lives = d.TryGetValue("lives", out var l) ? (int)l : 3
};
private static Dictionary FromLevel(LevelState s) => new() {
{ "current", s.Current },
{ "unlocked", new Array<int>(s.Unlocked) },
{ "completed", new Array<int>(s.Completed) },
};
private static LevelState ToLevel(Dictionary d) => new() {
Current = d.TryGetValue("current", out var cur) ? (int)cur : 0,
Unlocked = d.TryGetValue("unlocked", out var ul) && (Array<int>)ul is { } a1 ? a1.ToArray() : [0],
Completed = d.TryGetValue("completed", out var cl) && (Array<int>)cl is { } a2 ? a2.ToArray() : [],
};
}
public record SaveSnapshot {
public required PlayerState PlayerState { get; init; }
public required LevelState LevelState { get; init; }
}

View File

@@ -1 +0,0 @@
uid://bsf45t7m2wa07

View File

@@ -1,40 +0,0 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
using Mr.BrickAdventures.app;
using Mr.BrickAdventures.game.services;
namespace Mr.BrickAdventures.features.level;
[Meta(typeof(IAutoNode))]
public partial class ExitDoorComponent : Area2D
{
public override void _Notification(int what) => this.Notify(what);
[Export] public CollisionShape2D UnlockIndicator { get; set; } = null!;
[Export] public bool Unlocked { get; set; } = false;
[Dependency] public LevelService Levels => this.DependOn<LevelService>();
[Dependency] public ILevelCatalog Catalog => this.DependOn<ILevelCatalog>();
[Dependency] public IGameScenes Scenes => this.DependOn<IGameScenes>();
public void OnReady() {
BodyEntered += OnBodyEntered;
UpdateVisuals();
}
private void OnBodyEntered(Node body) {
if (!Unlocked) return;
if (body is not CharacterBody2D) return;
var nextIdx = Levels.CompleteAndAdvance();
var next = Catalog.Get(nextIdx);
if (next != null) Scenes.Load(next); else Scenes.ReturnToMain(Catalog.MainMenu);
}
private void UpdateVisuals() {
if (UnlockIndicator != null) UnlockIndicator.Disabled = !Unlocked;
}
public void SetUnlocked(bool value) { Unlocked = value; UpdateVisuals(); }
}

View File

@@ -1 +0,0 @@
uid://ddh0jm0heqtc3

View File

@@ -1,34 +0,0 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
using Mr.BrickAdventures.game.repositories;
using Mr.BrickAdventures.scripts.components;
namespace Mr.BrickAdventures.features.ui.hud;
[Meta(typeof(IAutoNode))]
public partial class Hud : Node
{
public override void _Notification(int what) => this.Notify(what);
[Export] public HealthComponent Health { get; set; } = null!;
[Node] public Label CoinsLabel { get; set; } = null!;
[Node] public ProgressBar HealthBar { get; set; } = null!;
[Node] public Label LivesLabel { get; set; } = null!;
[Dependency] public PlayerRepository Player => this.DependOn<PlayerRepository>();
public void OnResolved() {
CoinsLabel.Text = $"{Tr("COINS_LABEL")}: {Player.Coins}";
LivesLabel.Text = $"{Tr("LIVES_LABEL")}: {Player.Lives}";
Player.CoinsChanged += c => CoinsLabel.Text = $"{Tr("COINS_LABEL")}: {c}";
Player.LivesChanged += l => LivesLabel.Text = $"{Tr("LIVES_LABEL")}: {l}";
if (Health != null) {
HealthBar.MaxValue = Health.MaxHealth;
HealthBar.Value = Health.Health;
Health.HealthChanged += (_, total) => { HealthBar.Value = total; };
}
}
}

View File

@@ -1 +0,0 @@
uid://c1uwe5e1cfdxl

View File

@@ -1,26 +0,0 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
using Mr.BrickAdventures.app;
namespace Mr.BrickAdventures.features.ui.menus;
[Meta(typeof(IAutoNode))]
public partial class GameOverScreen : Control
{
public override void _Notification(int what) => this.Notify(what);
[Export] public Button RestartButton { get; set; } = null!;
[Export] public Button MainMenuButton { get; set; } = null!;
[Export] public PackedScene MainMenuScene { get; set; } = null!;
[Dependency] public IGameScenes Scenes => this.DependOn<IGameScenes>();
public void OnReady() {
Visible = false;
RestartButton.Pressed += () => Scenes.Restart();
MainMenuButton.Pressed += () => Scenes.ReturnToMain(MainMenuScene);
}
public void ShowGameOver() => Show();
}

View File

@@ -1 +0,0 @@
uid://b36jv878751ta

View File

@@ -1,57 +0,0 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
using Mr.BrickAdventures.app;
using Mr.BrickAdventures.game.repositories;
using Mr.BrickAdventures.game.services;
namespace Mr.BrickAdventures.features.ui.menus;
[Meta(typeof(IAutoNode))]
public partial class MainMenu : Control
{
public override void _Notification(int what) => this.Notify(what);
[Node] public Button NewGameButton { get; set; } = null!;
[Node] public Button ContinueButton { get; set; } = null!;
[Node] public Button SettingsButton { get; set; } = null!;
[Node] public Button CreditsButton { get; set; } = null!;
[Node] public Button ExitButton { get; set; } = null!;
[Node] public Label VersionLabel { get; set; } = null!;
[Export] public Control SettingsControl { get; set; } = null!;
[Export] public Control CreditsControl { get; set; } = null!;
[Dependency] public SaveService Save => this.DependOn<SaveService>();
[Dependency] public LevelRepository Levels => this.DependOn<LevelRepository>();
[Dependency] public IGameScenes Scenes => this.DependOn<IGameScenes>();
[Dependency] public ILevelCatalog Catalog => this.DependOn<ILevelCatalog>();
public void OnReady() {
VersionLabel.Text = $"v. {ProjectSettings.GetSetting("application/config/version")}";
NewGameButton.Pressed += OnNewGamePressed;
ContinueButton.Pressed += OnContinuePressed;
SettingsButton.Pressed += () => SettingsControl.Show();
CreditsButton.Pressed += () => CreditsControl.Show();
ExitButton.Pressed += () => GetTree().Quit();
}
public void OnResolved()
{
ContinueButton.Disabled = !Save.Exists();
(ContinueButton.Disabled ? NewGameButton : ContinueButton).GrabFocus();
}
private void OnNewGamePressed() {
Save.NewGame();
Levels.SetCurrent(0);
var first = Catalog.First;
Scenes.Load(first);
}
private void OnContinuePressed() {
if (!Save.TryLoad()) { OnNewGamePressed(); return; }
var scene = Catalog.Get(Levels.Current) ?? Catalog.First;
Scenes.Load(scene);
}
}

View File

@@ -1 +0,0 @@
uid://fcsg0e8s36in

View File

@@ -1,33 +0,0 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
using Mr.BrickAdventures.app;
using Mr.BrickAdventures.game.services;
namespace Mr.BrickAdventures.features.ui.menus;
[Meta(typeof(IAutoNode))]
public partial class PauseMenu : Control
{
public override void _Notification(int what) => this.Notify(what);
[Export] public Button ResumeButton { get; set; } = null!;
[Export] public Button RestartButton { get; set; } = null!;
[Export] public Button MainMenuButton { get; set; } = null!;
[Dependency] public IGameScenes Scenes => this.DependOn<IGameScenes>();
[Dependency] public ILevelCatalog Catalog => this.DependOn<ILevelCatalog>();
[Dependency] public LevelService Levels => this.DependOn<LevelService>();
public void OnReady() {
Visible = false;
ResumeButton.Pressed += () => { GetTree().Paused = false; Hide(); };
RestartButton.Pressed += () => { GetTree().Paused = false; Scenes.Restart(); };
MainMenuButton.Pressed += () => { GetTree().Paused = false; Scenes.ReturnToMain(Catalog.MainMenu); };
}
public void Toggle() {
if (Visible) { GetTree().Paused = false; Hide(); }
else { Show(); GetTree().Paused = true; }
}
}

View File

@@ -1 +0,0 @@
uid://bwgs02wcfnm8u

View File

@@ -1,6 +0,0 @@
namespace Mr.BrickAdventures.features.ui.settings;
public class AudioSettings
{
}

View File

@@ -1 +0,0 @@
uid://bnj36dhskiem

View File

@@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Mr.BrickAdventures.game.repositories;
public sealed class LevelRepository
{
public int Current { get; private set; } = 0;
public HashSet<int> Unlocked { get; } = new() { 0 };
public HashSet<int> Completed { get; } = new();
public event Action<int>? CurrentChanged;
public void SetCurrent(int idx) { Current = idx; CurrentChanged?.Invoke(Current); }
public void Unlock(int idx) => Unlocked.Add(idx);
public void Complete(int idx) { Completed.Add(idx); Unlock(idx + 1); }
public LevelState Export() => new() {
Current = Current, Unlocked = [..Unlocked], Completed = [..Completed]
};
public void Load(LevelState s) {
Current = s.Current;
Unlocked.Clear(); foreach (var i in s.Unlocked) Unlocked.Add(i);
Completed.Clear(); foreach (var i in s.Completed) Completed.Add(i);
CurrentChanged?.Invoke(Current);
}
}
public record LevelState {
public int Current;
public int[] Unlocked = [];
public int[] Completed = [];
}

View File

@@ -1 +0,0 @@
uid://d0604lmwpadt5

View File

@@ -1,25 +0,0 @@
using System;
namespace Mr.BrickAdventures.game.repositories;
public sealed class PlayerRepository
{
public int Coins { get; private set; } = 0;
public int Lives { get; private set; } = 3;
public event Action<int>? CoinsChanged;
public event Action<int>? LivesChanged;
public void SetCoins(int value) { Coins = Math.Max(0, value); CoinsChanged?.Invoke(Coins); }
public void AddCoins(int amount) { SetCoins(Coins + amount); }
public void RemoveCoins(int amount){ SetCoins(Coins - amount); }
public void SetLives(int value) { Lives = value; LivesChanged?.Invoke(Lives); }
public void AddLives(int amount) { SetLives(Lives + amount); }
public void RemoveLives(int amount){ SetLives(Lives - amount); }
public PlayerState Export() => new() { Coins = Coins, Lives = Lives };
public void Load(PlayerState s) { SetCoins(s.Coins); SetLives(s.Lives); }
}
public record PlayerState { public int Coins; public int Lives; }

View File

@@ -1 +0,0 @@
uid://d1dijkt574x4b

View File

@@ -1,6 +0,0 @@
namespace Mr.BrickAdventures.game.repositories;
public sealed class SessionRepository
{
}

View File

@@ -1 +0,0 @@
uid://b550hcqugygv0

View File

@@ -1,6 +0,0 @@
namespace Mr.BrickAdventures.game.repositories;
public class SettingsRepository
{
}

View File

@@ -1 +0,0 @@
uid://bk11iduo7bg2h

View File

@@ -1,6 +0,0 @@
namespace Mr.BrickAdventures.game.repositories;
public class SkillsRepository
{
}

View File

@@ -1 +0,0 @@
uid://cymx7mtmdblun

View File

@@ -1,21 +0,0 @@
using Mr.BrickAdventures.game.repositories;
namespace Mr.BrickAdventures.game.services;
public sealed class LevelService
{
private readonly LevelRepository _levels;
public LevelService(LevelRepository levels) => _levels = levels;
public int CompleteAndAdvance() {
var cur = _levels.Current;
_levels.Complete(cur);
var next = cur + 1;
_levels.SetCurrent(next);
return next;
}
public void StartNew() {
_levels.Load(new LevelState { Current = 0, Unlocked = new [] { 0 }, Completed = [] });
}
}

View File

@@ -1 +0,0 @@
uid://b2tsi3cjnh5xq

View File

@@ -1,32 +0,0 @@
using Mr.BrickAdventures.data;
using Mr.BrickAdventures.game.repositories;
namespace Mr.BrickAdventures.game.services;
public sealed class SaveService
{
private readonly PlayerRepository _players;
private readonly LevelRepository _levels;
private readonly SaveClient _save;
public SaveService(PlayerRepository players, LevelRepository levels, SaveClient save) {
_players = players; _levels = levels; _save = save;
}
public bool TryLoad() {
if (!_save.TryLoad(out var p, out var l)) return false;
_players.Load(p);
_levels.Load(l);
return true;
}
public void Save() => _save.Save(_players.Export(), _levels.Export());
public bool Exists() => _save.Exists();
public void NewGame() {
_players.Load(new PlayerState { Coins = 0, Lives = 3 });
_levels.Load(new LevelState { Current = 0, Unlocked = [0], Completed = [] });
Save();
}
}

View File

@@ -1 +0,0 @@
uid://dxqkxlkkivxog

View File

@@ -1,6 +0,0 @@
namespace Mr.BrickAdventures.game.services;
public sealed class SkillService
{
}

View File

@@ -1 +0,0 @@
uid://dim21hs12wdi5

View File

@@ -32,7 +32,7 @@
[ext_resource type="PackedScene" uid="uid://bg76mtpcmfm2j" path="res://objects/ui/charging_bar_layer.tscn" id="28_3f5nm"]
[ext_resource type="PackedScene" uid="uid://b12tppjkkqpt4" path="res://objects/fxs/hit_particles.tscn" id="28_jh5m0"]
[ext_resource type="Script" uid="uid://ceq8n7yw7qxpi" path="res://scripts/components/hit_component.gd" id="29_jh5m0"]
[ext_resource type="Script" uid="uid://cflncpa377l8l" path="res://scripts/components/platform_movement.gd" id="31_xoue7"]
[ext_resource type="Script" uid="uid://c1wtrgw0x77xo" path="res://scripts/components/platform_movement.gd" id="31_xoue7"]
[ext_resource type="AudioStream" uid="uid://dyev46uqusimi" path="res://sfx/shoot.wav" id="32_x2b7c"]
[ext_resource type="Script" uid="uid://d1ctdx52gskv1" path="res://scripts/components/ship_shooter.gd" id="34_gwc8i"]
[ext_resource type="PackedScene" uid="uid://dtem8jgcyoqar" path="res://objects/entities/green_laser.tscn" id="36_oxudy"]

View File

@@ -62,6 +62,9 @@ process_material = SubResource("ParticleProcessMaterial_lgb3u")
[node name="UI Layer" parent="." instance=ExtResource("2_lbnsn")]
[node name="HUD" parent="UI Layer" index="0" node_paths=PackedStringArray("player_health")]
player_health = NodePath("../../Brick Player/HealthComponent")
[node name="DeathScreen" parent="UI Layer" index="1" node_paths=PackedStringArray("nodes_to_disable")]
current_level = ExtResource("4_c2yv5")
nodes_to_disable = [NodePath("../../Brick Player")]

View File

@@ -1,6 +1,6 @@
[gd_scene load_steps=11 format=3 uid="uid://6foggu31cu14"]
[ext_resource type="PackedScene" uid="uid://byxf45ukq82pe" path="res://features/ui/hud/hud.tscn" id="1_tgtfe"]
[ext_resource type="PackedScene" uid="uid://byxf45ukq82pe" path="res://objects/ui/hud.tscn" id="1_tgtfe"]
[ext_resource type="PackedScene" uid="uid://dulkm3ah4tm0u" path="res://objects/ui/death_screen.tscn" id="2_ln68j"]
[ext_resource type="Script" uid="uid://cp68km8bykymb" path="res://scripts/resources/level_resource.gd" id="3_5kt5k"]
[ext_resource type="PackedScene" uid="uid://wmw6gaisyrvx" path="res://objects/ui/game_over_screen.tscn" id="4_11xmk"]
@@ -34,8 +34,9 @@ visible = false
offset_top = 32.0
components_to_disable = [null]
[node name="Pause menu" parent="." instance=ExtResource("6_1q4vn")]
[node name="Pause menu" parent="." node_paths=PackedStringArray("settings_menu") instance=ExtResource("6_1q4vn")]
visible = false
settings_menu = NodePath("../Settings menu")
[node name="Settings menu" parent="." node_paths=PackedStringArray("input_settings", "audio_settings") instance=ExtResource("7_hkjav")]
visible = false

View File

@@ -1,7 +1,7 @@
[gd_scene load_steps=8 format=3 uid="uid://byxf45ukq82pe"]
[ext_resource type="LabelSettings" uid="uid://rvn5ivivfvv6" path="res://resources/ui/hud_label_settings.tres" id="1_4dsh5"]
[ext_resource type="Script" uid="uid://c1uwe5e1cfdxl" path="res://features/ui/hud/Hud.cs" id="1_m4pq7"]
[ext_resource type="Script" uid="uid://c3pde84b3kdco" path="res://scripts/ui/hud.gd" id="1_ueofj"]
[ext_resource type="FontFile" uid="uid://xm0vbusjr7b7" path="res://fonts/PressStart2P-Regular.ttf" id="1_ygmwt"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mmcdi"]
@@ -16,7 +16,7 @@ bg_color = Color(0.47451, 0.47451, 0.47451, 1)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_22dp1"]
bg_color = Color(0.858824, 0.254902, 0.380392, 1)
[node name="HUD" type="Control"]
[node name="HUD" type="Control" node_paths=PackedStringArray("coins_label", "health_progressbar", "lives_label")]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
@@ -25,7 +25,10 @@ grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 4
size_flags_vertical = 4
script = ExtResource("1_m4pq7")
script = ExtResource("1_ueofj")
coins_label = NodePath("PanelContainer/MarginContainer/HBoxContainer/Coins label")
health_progressbar = NodePath("PanelContainer/MarginContainer/HBoxContainer/ProgressBar")
lives_label = NodePath("PanelContainer/MarginContainer/HBoxContainer/Lives")
[node name="PanelContainer" type="PanelContainer" parent="."]
layout_mode = 1
@@ -54,8 +57,7 @@ text = "HEALTH_LABEL"
label_settings = ExtResource("1_4dsh5")
uppercase = true
[node name="HealthBar" type="ProgressBar" parent="PanelContainer/MarginContainer/HBoxContainer"]
unique_name_in_owner = true
[node name="ProgressBar" type="ProgressBar" parent="PanelContainer/MarginContainer/HBoxContainer"]
visible = false
layout_mode = 2
size_flags_horizontal = 3
@@ -67,8 +69,7 @@ step = 0.1
value = 60.0
show_percentage = false
[node name="LivesLabel" type="Label" parent="PanelContainer/MarginContainer/HBoxContainer"]
unique_name_in_owner = true
[node name="Lives" type="Label" parent="PanelContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "LIVES_LABEL"
@@ -76,8 +77,7 @@ label_settings = ExtResource("1_4dsh5")
horizontal_alignment = 1
uppercase = true
[node name="CoinsLabel" type="Label" parent="PanelContainer/MarginContainer/HBoxContainer"]
unique_name_in_owner = true
[node name="Coins label" type="Label" parent="PanelContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "COINS_LABEL"

View File

@@ -1,18 +1,25 @@
[gd_scene load_steps=3 format=3 uid="uid://8b6ol5sssbgo"]
[ext_resource type="Script" uid="uid://fcsg0e8s36in" path="res://features/ui/menus/MainMenu.cs" id="1_q8hru"]
[ext_resource type="Script" uid="uid://hyfvthdbgjbc" path="res://scripts/ui/main_menu.gd" id="1_epxpl"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_qv2q0"]
bg_color = Color(0, 0, 0, 1)
[node name="MainMenu" type="Control"]
[node name="MainMenu" type="Control" node_paths=PackedStringArray("main_menu_control", "new_game_button", "continue_button", "settings_button", "credits_button", "exit_button", "version_label")]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_q8hru")
script = ExtResource("1_epxpl")
main_menu_control = NodePath(".")
new_game_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/NewGameButton")
continue_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/ContinueButton")
settings_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/SettingsButton")
credits_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/CreditsButton")
exit_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/QuitButton")
version_label = NodePath("PanelContainer/MarginContainer/VBoxContainer/version")
[node name="PanelContainer" type="PanelContainer" parent="."]
layout_mode = 1
@@ -46,37 +53,31 @@ layout_mode = 2
size_flags_vertical = 3
[node name="ContinueButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "CONTINUE_BUTTON"
flat = true
[node name="NewGameButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "NEW_GAME_BUTTON"
flat = true
[node name="SettingsButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "SETTINGS_BUTTON"
flat = true
[node name="CreditsButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "CREDITS_BUTTON"
flat = true
[node name="ExitButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
[node name="QuitButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "QUIT_BUTTON"
flat = true
[node name="VersionLabel" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
[node name="version" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 8

View File

@@ -1,11 +1,12 @@
[gd_scene load_steps=3 format=3 uid="uid://i6mnjbjcoqe5"]
[gd_scene load_steps=4 format=3 uid="uid://i6mnjbjcoqe5"]
[ext_resource type="Script" uid="uid://bwgs02wcfnm8u" path="res://features/ui/menus/PauseMenu.cs" id="1_ljtns"]
[ext_resource type="Script" uid="uid://cugifchx6jhuk" path="res://scripts/ui/pause_menu.gd" id="1_aktha"]
[ext_resource type="PackedScene" uid="uid://cl00e2ocomk3m" path="res://scenes/main_menu.tscn" id="2_h4pd5"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_g4ivv"]
bg_color = Color(0, 0, 0, 1)
[node name="Pause menu" type="Control" node_paths=PackedStringArray("ResumeButton", "RestartButton", "MainMenuButton")]
[node name="Pause menu" type="Control" node_paths=PackedStringArray("pause_menu_control", "resume_button", "quit_button", "settings_button", "exit_to_menu_button")]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
@@ -14,10 +15,13 @@ grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 6
size_flags_vertical = 6
script = ExtResource("1_ljtns")
ResumeButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Resume Button")
RestartButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Settings Button")
MainMenuButton = NodePath("PanelContainer/MarginContainer/VBoxContainer/Exit to menu Button")
script = ExtResource("1_aktha")
pause_menu_control = NodePath(".")
resume_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/Resume Button")
quit_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/Quit game Button")
settings_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/Settings Button")
exit_to_menu_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/Exit to menu Button")
exit_to_menu_scene = ExtResource("2_h4pd5")
[node name="PanelContainer" type="PanelContainer" parent="."]
layout_mode = 1

View File

@@ -66,6 +66,9 @@ process_material = SubResource("ParticleProcessMaterial_lgb3u")
[node name="UI Layer" parent="." instance=ExtResource("3_4fsls")]
[node name="HUD" parent="UI Layer" index="0" node_paths=PackedStringArray("player_health")]
player_health = NodePath("../../Brick Player/HealthComponent")
[node name="DeathScreen" parent="UI Layer" index="1" node_paths=PackedStringArray("nodes_to_disable")]
current_level = ExtResource("4_onnch")
nodes_to_disable = [NodePath("../../Brick Player")]

View File

@@ -1,38 +1,27 @@
[gd_scene load_steps=12 format=3 uid="uid://cl00e2ocomk3m"]
[gd_scene load_steps=6 format=3 uid="uid://cl00e2ocomk3m"]
[ext_resource type="PackedScene" uid="uid://8b6ol5sssbgo" path="res://features/ui/menus/main_menu.tscn" id="1_ekxnf"]
[ext_resource type="Script" uid="uid://dg2l7cw6da4vb" path="res://common/AppRoot.cs" id="1_rtw2f"]
[ext_resource type="PackedScene" uid="uid://8b6ol5sssbgo" path="res://objects/ui/main_menu.tscn" id="1_ekxnf"]
[ext_resource type="PackedScene" uid="uid://y0ae6e7t70fj" path="res://objects/ui/settings_menu.tscn" id="2_bqqt6"]
[ext_resource type="PackedScene" uid="uid://bwgmrcyj4mvu" path="res://objects/ui/credits.tscn" id="3_bqqt6"]
[ext_resource type="PackedScene" uid="uid://chqb11pfoqmeb" path="res://scenes/level_village_2.tscn" id="3_lgwnu"]
[ext_resource type="PackedScene" uid="uid://bol7g83v2accs" path="res://scenes/level_village_1.tscn" id="3_oa1go"]
[ext_resource type="PackedScene" uid="uid://b5fx1vdfky307" path="res://objects/ui/audio_settings.tscn" id="4_8ln24"]
[ext_resource type="PackedScene" uid="uid://h60obxmju6mo" path="res://scenes/level_village_3.tscn" id="4_flqon"]
[ext_resource type="PackedScene" uid="uid://bhad760x3vvco" path="res://scenes/level_village_4.tscn" id="5_rcqid"]
[ext_resource type="PackedScene" uid="uid://cvfsbiy5ggrpg" path="res://objects/ui/input_settings.tscn" id="5_rtw2f"]
[ext_resource type="PackedScene" uid="uid://dagpmlgvr262d" path="res://scenes/level_forest_5.tscn" id="6_1ajci"]
[node name="AppRoot" type="Node2D"]
script = ExtResource("1_rtw2f")
_levels = Array[PackedScene]([ExtResource("3_oa1go"), ExtResource("3_lgwnu"), ExtResource("4_flqon"), ExtResource("5_rcqid"), ExtResource("6_1ajci")])
_mainMenu = null
[node name="Main menu" type="CanvasLayer"]
[node name="Main menu" type="CanvasLayer" parent="."]
[node name="MainMenu" parent="." node_paths=PackedStringArray("settings_control", "credits_control") instance=ExtResource("1_ekxnf")]
settings_control = NodePath("../Settings menu")
credits_control = NodePath("../Credits")
[node name="MainMenu" parent="Main menu" node_paths=PackedStringArray("SettingsControl", "CreditsControl") instance=ExtResource("1_ekxnf")]
SettingsControl = NodePath("../Settings menu")
CreditsControl = NodePath("../Credits")
[node name="Settings menu" parent="Main menu" node_paths=PackedStringArray("input_settings", "audio_settings") instance=ExtResource("2_bqqt6")]
[node name="Settings menu" parent="." node_paths=PackedStringArray("input_settings", "audio_settings") instance=ExtResource("2_bqqt6")]
visible = false
input_settings = NodePath("../Input Settings")
audio_settings = NodePath("../Audio settings")
[node name="Credits" parent="Main menu" instance=ExtResource("3_bqqt6")]
[node name="Credits" parent="." instance=ExtResource("3_bqqt6")]
visible = false
[node name="Audio settings" parent="Main menu" instance=ExtResource("4_8ln24")]
[node name="Audio settings" parent="." instance=ExtResource("4_8ln24")]
visible = false
[node name="Input Settings" parent="Main menu" instance=ExtResource("5_rtw2f")]
[node name="Input Settings" parent="." instance=ExtResource("5_rtw2f")]
visible = false

View File

@@ -1 +0,0 @@
uid://dtpdh4jp51jis

View File

@@ -1 +0,0 @@
uid://gptsgaw3agkf

View File

@@ -1 +0,0 @@
uid://2ql8wj3vfeke

View File

@@ -1 +0,0 @@
uid://d4crrfmbgxnqf

View File

@@ -1 +0,0 @@
uid://sma20qug2r0q

View File

@@ -1 +0,0 @@
uid://pw0pu6gb21y2

View File

@@ -1 +0,0 @@
uid://b0a7k7mse3l68

View File

@@ -1 +0,0 @@
uid://cx7ryqxemgs56

View File

@@ -1 +0,0 @@
uid://mnn5wy5cyr4m

View File

@@ -1 +0,0 @@
uid://chrhjch4ymfvr

View File

@@ -1 +0,0 @@
uid://di572axt0c3s8

View File

@@ -1,102 +0,0 @@
using Godot;
using Mr.BrickAdventures.Autoloads;
namespace Mr.BrickAdventures.scripts.UI;
public partial class AudioSettings : Node
{
[Export] public Slider MasterVolumeSlider { get; set; }
[Export] public Slider MusicVolumeSlider { get; set; }
[Export] public Slider SfxVolumeSlider { get; set; }
[Export] public Control AudioSettingsControl { get; set; }
[Export] public float MuteThreshold { get; set; } = -20f;
private UIManager _uiManager;
private ConfigFileHandler _configFileHandler;
public override void _Ready()
{
_uiManager = GetNode<UIManager>("/root/UIManager");
_configFileHandler = GetNode<ConfigFileHandler>("/root/ConfigFileHandler");
Initialize();
MasterVolumeSlider.ValueChanged += OnMasterVolumeChanged;
MusicVolumeSlider.ValueChanged += OnMusicVolumeChanged;
SfxVolumeSlider.ValueChanged += OnSfxVolumeChanged;
}
public override void _UnhandledInput(InputEvent @event)
{
if (!@event.IsActionReleased("ui_cancel")) return;
if (!_uiManager.IsScreenOnTop(AudioSettingsControl)) return;
SaveSettings();
_uiManager.PopScreen();
}
private void OnSfxVolumeChanged(double value)
{
AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("sfx"), (float)value);
HandleMute(AudioServer.GetBusIndex("sfx"), (float)value);
}
private void OnMusicVolumeChanged(double value)
{
AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("music"), (float)value);
HandleMute(AudioServer.GetBusIndex("music"), (float)value);
}
private void OnMasterVolumeChanged(double value)
{
AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Master"), (float)value);
HandleMute(AudioServer.GetBusIndex("Master"), (float)value);
}
private void Initialize()
{
var volumeDb = AudioServer.GetBusVolumeDb(AudioServer.GetBusIndex("Master"));
MasterVolumeSlider.Value = volumeDb;
MasterVolumeSlider.MinValue = MuteThreshold;
MasterVolumeSlider.MaxValue = 0f;
var musicVolumeDb = AudioServer.GetBusVolumeDb(AudioServer.GetBusIndex("music"));
MusicVolumeSlider.Value = musicVolumeDb;
MusicVolumeSlider.MinValue = MuteThreshold;
MusicVolumeSlider.MaxValue = 0f;
var sfxVolumeDb = AudioServer.GetBusVolumeDb(AudioServer.GetBusIndex("sfx"));
SfxVolumeSlider.Value = sfxVolumeDb;
SfxVolumeSlider.MinValue = MuteThreshold;
SfxVolumeSlider.MaxValue = 0f;
}
private void HandleMute(int busIndex, float value)
{
AudioServer.SetBusMute(busIndex, value <= MuteThreshold);
}
private void SaveSettings()
{
var settingsConfig = _configFileHandler.SettingsConfig;
settingsConfig.SetValue("audio_settings", "master_volume", MasterVolumeSlider.Value);
settingsConfig.SetValue("audio_settings", "music_volume", MusicVolumeSlider.Value);
settingsConfig.SetValue("audio_settings", "sfx_volume", SfxVolumeSlider.Value);
settingsConfig.SetValue("audio_settings", "mute_threshold", MuteThreshold);
settingsConfig.Save(ConfigFileHandler.SettingsPath);
}
private void LoadSettings()
{
var settingsConfig = _configFileHandler.SettingsConfig;
if (!settingsConfig.HasSection("audio_settings")) return;
var masterVolume = (float)settingsConfig.GetValue("audio_settings", "master_volume", MasterVolumeSlider.Value);
var musicVolume = (float)settingsConfig.GetValue("audio_settings", "music_volume", MusicVolumeSlider.Value);
var sfxVolume = (float)settingsConfig.GetValue("audio_settings", "sfx_volume", SfxVolumeSlider.Value);
var muteThreshold = (float)settingsConfig.GetValue("audio_settings", "mute_threshold", MuteThreshold);
MasterVolumeSlider.Value = masterVolume;
MusicVolumeSlider.Value = musicVolume;
SfxVolumeSlider.Value = sfxVolume;
MuteThreshold = muteThreshold;
}
}

View File

@@ -1 +0,0 @@
uid://g61qqsymqfxd

View File

@@ -1,81 +0,0 @@
using Godot;
using Mr.BrickAdventures.scripts.components;
using Mr.BrickAdventures.scripts.Resources;
namespace Mr.BrickAdventures.scripts.UI;
public partial class ChargeProgressBar : Node
{
[Export] public ProgressBar ProgressBar { get; set; }
[Export] public BrickThrowComponent ThrowComponent { get; set; }
private ChargeThrowInputResource _throwInput;
public override void _Ready()
{
Owner.ChildEnteredTree += OnNodeEntered;
ProgressBar.Hide();
SetupDependencies();
}
private void OnNodeEntered(Node node)
{
if (node is not BrickThrowComponent throwComponent || ThrowComponent != null) return;
ThrowComponent = throwComponent;
SetupDependencies();
}
private void SetupDependencies()
{
if (ThrowComponent.ThrowInputBehavior is ChargeThrowInputResource throwInput)
{
_throwInput = throwInput;
}
else
{
_throwInput = null;
}
if (_throwInput == null)
{
return;
}
if (!_throwInput.SupportsCharging())
{
ProgressBar.Hide();
return;
}
SetupProgressBar();
_throwInput.ChargeStarted += OnChargeStarted;
_throwInput.ChargeStopped += OnChargeStopped;
_throwInput.ChargeUpdated += OnChargeUpdated;
}
private void SetupProgressBar()
{
ProgressBar.MinValue = _throwInput.MinPower;
ProgressBar.MaxValue = _throwInput.MaxPower;
ProgressBar.Value = _throwInput.MinPower;
ProgressBar.Step = 0.01f;
ProgressBar.Hide();
}
private void OnChargeStarted()
{
ProgressBar.Show();
}
private void OnChargeStopped()
{
ProgressBar.Hide();
}
private void OnChargeUpdated(float chargeRatio)
{
ProgressBar.Value = chargeRatio;
ProgressBar.Show();
}
}

View File

@@ -1 +0,0 @@
uid://dev2q1228otm2

View File

@@ -1,23 +0,0 @@
using Godot;
using Mr.BrickAdventures.Autoloads;
namespace Mr.BrickAdventures.scripts.UI;
public partial class Credits : Control
{
private UIManager _uiManager;
public override void _Ready()
{
_uiManager = GetNode<UIManager>("/root/UIManager");
}
public override void _UnhandledInput(InputEvent @event)
{
if (!@event.IsActionPressed("ui_cancel")) return;
if (_uiManager != null && _uiManager.IsScreenOnTop(this))
{
_uiManager.PopScreen();
}
}
}

View File

@@ -1 +0,0 @@
uid://daevj4uootmcw

View File

@@ -1,39 +0,0 @@
using Godot;
using Mr.BrickAdventures.Autoloads;
namespace Mr.BrickAdventures.scripts.UI;
public partial class GameOverScreen : Node
{
[Export] public Control GameOverPanel { get; set; }
[Export] public Button RestartButton { get; set; }
[Export] public Button MainMenuButton { get; set; }
[Export] public PackedScene MainMenuScene { get; set; }
private GameManager _gameManager;
public override void _Ready()
{
_gameManager = GetNode<GameManager>("/root/GameManager");
RestartButton.Pressed += OnRestartClicked;
MainMenuButton.Pressed += OnMainMenuClicked;
}
private void OnMainMenuClicked()
{
_gameManager.ResetPlayerState();
GetTree().ChangeSceneToPacked(MainMenuScene);
}
private void OnRestartClicked()
{
_gameManager.RestartGame();
}
public void OnPlayerDeath()
{
if (_gameManager == null || _gameManager.GetLives() != 0) return;
GameOverPanel.Show();
}
}

View File

@@ -1 +0,0 @@
uid://u4qfsx4w72dv

View File

@@ -1,67 +0,0 @@
using Godot;
using Mr.BrickAdventures.Autoloads;
namespace Mr.BrickAdventures.scripts.UI;
public partial class MainMenu : Node
{
[Export] public Control MainMenuControl { get; set; }
[Export] public Button NewGameButton { get; set; }
[Export] public Button ContinueButton { get; set; }
[Export] public Button SettingsButton { get; set; }
[Export] public Button CreditsButton { get; set; }
[Export] public Button ExitButton { get; set; }
[Export] public Label VersionLabel { get; set; }
[Export] public Control SettingsControl { get; set; }
[Export] public Control CreditsControl { get; set; }
private SaveSystem _saveSystem;
private GameManager _gameManager;
private UIManager _uiManager;
public override void _Ready()
{
_saveSystem = GetNode<SaveSystem>("/root/SaveSystem");
_gameManager = GetNode<GameManager>("/root/GameManager");
_uiManager = GetNode<UIManager>("/root/UIManager");
NewGameButton.Pressed += OnNewGamePressed;
ContinueButton.Pressed += OnContinuePressed;
SettingsButton.Pressed += OnSettingsPressed;
CreditsButton.Pressed += OnCreditsPressed;
ExitButton.Pressed += OnExitPressed;
VersionLabel.Text = $"v. {ProjectSettings.GetSetting("application/config/version")}";
ContinueButton.Disabled = !_saveSystem.CheckSaveExists();
if (_saveSystem.CheckSaveExists())
ContinueButton.GrabFocus();
else
NewGameButton.GrabFocus();
}
private void OnExitPressed()
{
_gameManager.QuitGame();
}
private void OnCreditsPressed()
{
_uiManager.PushScreen(CreditsControl);
}
private void OnSettingsPressed()
{
_uiManager.PushScreen(SettingsControl);
}
private void OnContinuePressed()
{
_gameManager.ContinueGame();
}
private void OnNewGamePressed()
{
_gameManager.StartNewGame();
}
}

View File

@@ -1 +0,0 @@
uid://bna3ggr6n7ycr

View File

@@ -1,142 +0,0 @@
using System.Collections.Generic;
using Godot;
using Godot.Collections;
using Mr.BrickAdventures.Autoloads;
using Mr.BrickAdventures.scripts.components;
using Mr.BrickAdventures.scripts.Resources;
namespace Mr.BrickAdventures.scripts.UI;
public partial class Marketplace : Node
{
[Export] public Array<SkillData> Skills { get; set; } = [];
[Export] public GridContainer ToUnlockGrid { get; set; }
[Export] public GridContainer UnlockedGrid { get; set; }
[Export] public Font Font { get; set; }
[Export] public SkillUnlockedComponent SkillUnlockedComponent { get; set; }
[Export] public Array<Node> ComponentsToDisable { get; set; } = [];
[Export] public PackedScene MarketplaceButtonScene { get; set; }
[Export] public PackedScene SkillButtonScene { get; set; }
private GameManager _gameManager;
private readonly List<Button> _unlockButtons = [];
private readonly List<SkillButton> _skillButtons = [];
public override void _Ready()
{
var skillsToUnlock = new List<SkillData>();
foreach (var skill in Skills) skillsToUnlock.Add(skill);
foreach (var skill in skillsToUnlock) CreateUpgradeButton(skill);
var unlockedSkills = _gameManager.GetUnlockedSkills();
foreach (var skill in unlockedSkills) CreateSkillButton(skill);
SkillUnlockedComponent.SkillUnlocked += OnSkillUnlocked;
}
public override void _ExitTree()
{
SkillUnlockedComponent.SkillUnlocked -= OnSkillUnlocked;
}
public override void _Input(InputEvent @event)
{
var root = Owner as Control;
if (!@event.IsActionPressed("show_marketplace")) return;
if (root != null && root.IsVisible())
{
root.Hide();
foreach (var c in ComponentsToDisable) c.ProcessMode = ProcessModeEnum.Inherit;
}
else
{
root?.Show();
foreach (var c in ComponentsToDisable) c.ProcessMode = ProcessModeEnum.Disabled;
}
}
private string GetButtonText(SkillData skill)
{
return $"{Tr(skill.Name)} {skill.Cost}";
}
private void OnSkillUnlocked(SkillData skill)
{
if (_skillButtons.Count == 0) CreateSkillButton(skill);
foreach (var btn in _skillButtons)
{
if (btn.Data.IsActive)
btn.Activate();
else
btn.Deactivate();
}
}
private void CreateSkillButton(SkillData skill)
{
var button = SkillButtonScene.Instantiate<SkillButton>();
button.Data = skill;
button.Setup();
button.Pressed += () => OnSkillButtonPressed(button);
button.Activate();
_skillButtons.Add(button);
UnlockedGrid.AddChild(button);
UnlockedGrid.QueueSort();
}
private void CreateUpgradeButton(SkillData skill)
{
var button = MarketplaceButtonScene.Instantiate<MarketplaceButton>();
button.Text = GetButtonText(skill);
button.Data = skill;
button.Icon = skill.Icon;
button.Pressed += () => OnUpgradeButtonPressed(skill);
_unlockButtons.Add(button);
UnlockedGrid.AddChild(button);
UnlockedGrid.QueueSort();
}
private void OnUpgradeButtonPressed(SkillData skill)
{
if (_gameManager.IsSkillUnlocked(skill))
{
if (skill.Level < skill.MaxLevel)
{
SkillUnlockedComponent.TryUpgradeSkill(skill);
if (!skill.IsActive) SkillUnlockedComponent.SkillManager.ToggleSkillActivation(skill);
}
else
{
SkillUnlockedComponent.SkillManager.ToggleSkillActivation(skill);
}
}
else
{
SkillUnlockedComponent.TryUnlockSkill(skill);
}
}
private void RemoveButton(SkillData skill)
{
foreach (var node in ToUnlockGrid.GetChildren())
{
var child = (Button)node;
if (child.Text != GetButtonText(skill)) continue;
child.QueueFree();
break;
}
}
private void OnSkillButtonPressed(SkillButton button)
{
SkillUnlockedComponent.SkillManager.ToggleSkillActivation(button.Data);
}
}

View File

@@ -1 +0,0 @@
uid://bnc16gndpl87i

View File

@@ -1,62 +0,0 @@
using Godot;
using Mr.BrickAdventures.Autoloads;
using Mr.BrickAdventures.scripts.components;
using Mr.BrickAdventures.scripts.Resources;
namespace Mr.BrickAdventures.scripts.UI;
public partial class MarketplaceButton : Button
{
[Export] public SkillData Data { get; set; }
[Export] public Texture2D UnlockedSkillIcon { get; set; }
[Export] public Texture2D LockedSkillIcon { get; set; }
[Export] public Container SkillLevelContainer { get; set; }
private GameManager _gameManager;
private SkillUnlockedComponent _skillUnlockedComponent;
public override void _Ready()
{
_gameManager = GetNode<GameManager>("/root/GameManager");
Setup();
var player = _gameManager.Player;
var skillUnlockerComponent = player?.GetNodeOrNull<SkillUnlockedComponent>("SkillUnlockerComponent");
if (skillUnlockerComponent == null) return;
skillUnlockerComponent.SkillUnlocked += OnSkillUnlock;
}
public override void _ExitTree()
{
_skillUnlockedComponent.SkillUnlocked -= OnSkillUnlock;
}
private void Setup()
{
if (Data == null) return;
for (var i = 0; i < Data.MaxLevel; i++)
{
var icon = new TextureRect()
{
Texture = i < Data.Level ? UnlockedSkillIcon : LockedSkillIcon,
};
SkillLevelContainer.AddChild(icon);
}
}
private void OnSkillUnlock(SkillData skill)
{
if (skill.Name != Data.Name) return;
for (var i = 0; i < Data.MaxLevel; i++)
{
var icon = SkillLevelContainer.GetChildOrNull<TextureRect>(i);
if (icon == null) continue;
icon.Texture = i < Data.Level ? UnlockedSkillIcon : LockedSkillIcon;
Disabled = i >= Data.Level;
}
}
}

View File

@@ -1 +0,0 @@
uid://vokgv56bjpf1

View File

@@ -1,67 +0,0 @@
using Godot;
using Mr.BrickAdventures.Autoloads;
namespace Mr.BrickAdventures.scripts.UI;
public partial class PauseMenu : Node
{
[Export] public Control PauseMenuControl { get; set; }
[Export] public Control SettingsControl { get; set; }
[Export] public Button ResumeButton { get; set; }
[Export] public Button MainMenuButton { get; set; }
[Export] public Button QuitButton { get; set; }
[Export] public Button SettingsButton { get; set; }
[Export] public PackedScene MainMenuScene { get; set; }
private GameManager _gameManager;
private UIManager _uiManager;
public override void _Ready()
{
_gameManager = GetNode<GameManager>("/root/GameManager");
_uiManager = GetNode<UIManager>("/root/UIManager");
ResumeButton.Pressed += OnResumePressed;
MainMenuButton.Pressed += OnMainMenuPressed;
QuitButton.Pressed += OnQuitPressed;
SettingsButton.Pressed += OnSettingsPressed;
PauseMenuControl.Hide();
}
public override void _UnhandledInput(InputEvent @event)
{
if (!@event.IsActionPressed("pause")) return;
if (_uiManager.IsVisibleOnStack(PauseMenuControl))
OnResumePressed();
else
{
_uiManager.PushScreen(PauseMenuControl);
_gameManager.PauseGame();
}
}
private void OnSettingsPressed()
{
_uiManager.PushScreen(SettingsControl);
_gameManager.PauseGame();
}
private void OnQuitPressed()
{
_gameManager.QuitGame();
}
private void OnMainMenuPressed()
{
_gameManager.ResumeGame();
_gameManager.ResetCurrentSessionState();
GetTree().ChangeSceneToPacked(MainMenuScene);
}
private void OnResumePressed()
{
_uiManager.PopScreen();
_gameManager.ResumeGame();
}
}

View File

@@ -1 +0,0 @@
uid://cakgxndurgfa3

View File

@@ -1,60 +0,0 @@
using Godot;
using Mr.BrickAdventures.Autoloads;
namespace Mr.BrickAdventures.scripts.UI;
public partial class SettingsMenu : Node
{
[Export] public Control InputSettingsControl { get; set; }
[Export] public Control AudioSettingsControl { get; set; }
[Export] public Control DisplaySettingsControl { get; set; }
[Export] public Control GameplaySettingsControl { get; set; }
[Export] public Control SettingsMenuControl { get; set; }
[Export] public Button InputSettingsButton { get; set; }
[Export] public Button AudioSettingsButton { get; set; }
[Export] public Button DisplaySettingsButton { get; set; }
[Export] public Button GameplaySettingsButton { get; set; }
private UIManager _uiManager;
public override void _Ready()
{
_uiManager = GetNode<UIManager>("/root/UIManager");
InputSettingsButton.Pressed += OnInputSettingsPressed;
AudioSettingsButton.Pressed += OnAudioSettingsPressed;
DisplaySettingsButton.Pressed += OnDisplaySettingsPressed;
GameplaySettingsButton.Pressed += OnGameplaySettingsPressed;
InputSettingsControl.Hide();
AudioSettingsControl.Hide();
DisplaySettingsControl.Hide();
GameplaySettingsControl.Hide();
}
public override void _UnhandledInput(InputEvent @event)
{
if (!@event.IsActionPressed("ui_cancel")) return;
if (_uiManager.IsScreenOnTop(SettingsMenuControl)) _uiManager.PopScreen();
}
private void OnInputSettingsPressed()
{
_uiManager.PushScreen(InputSettingsControl);
}
private void OnAudioSettingsPressed()
{
_uiManager.PushScreen(AudioSettingsControl);
}
private void OnDisplaySettingsPressed()
{
_uiManager.PushScreen(DisplaySettingsControl);
}
private void OnGameplaySettingsPressed()
{
_uiManager.PushScreen(GameplaySettingsControl);
}
}

View File

@@ -1 +0,0 @@
uid://i8j47qnrytuo

View File

@@ -1,25 +0,0 @@
using Godot;
using Mr.BrickAdventures.scripts.Resources;
namespace Mr.BrickAdventures.scripts.UI;
public partial class SkillButton : Button
{
[Export] public SkillData Data { get; set; }
public void Setup()
{
Icon = Data?.Icon;
Text = Tr(Data?.Name) ?? string.Empty;
}
public void Activate()
{
Set("theme_override_colors/font_color", new Color("#49aa10"));
}
public void Deactivate()
{
Set("theme_override_colors/font_color", new Color("#ffffff"));
}
}

View File

@@ -1 +0,0 @@
uid://bw8dlgq86jrtt

View File

@@ -1 +0,0 @@
uid://b0bv8kw5w5037

View File

@@ -1 +0,0 @@
uid://cfw8nbrarex0i

View File

@@ -1 +0,0 @@
uid://dojn0gw8hsv02

View File

@@ -1 +0,0 @@
uid://cjcc7fia15wu3

View File

@@ -1 +0,0 @@
uid://mnjg3p0aw1ow

View File

@@ -1 +0,0 @@
uid://dh67n16bnl838

View File

@@ -1 +0,0 @@
uid://dnpj72mfi1ywl

View File

@@ -1 +0,0 @@
uid://v7tt4w6bejux

View File

@@ -1 +0,0 @@
uid://xqhrb1c7f6y4

View File

@@ -1 +0,0 @@
uid://r4jybneigfcn

View File

@@ -1 +0,0 @@
uid://2i7p7v135u7c

View File

@@ -1 +0,0 @@
uid://ctfrbj52ejay4

View File

@@ -1 +0,0 @@
uid://xjq33vj0rol0

View File

@@ -1 +0,0 @@
uid://cfdugoeduudar

View File

@@ -1 +0,0 @@
uid://d3fpwddc2j41x

Some files were not shown because too many files have changed in this diff Show More