Development Log – March 2026: Player Hub System Implementation, Weapon System Overhaul, and Free Movement with Environment Interaction

A foundational camp and hub system has been introduced, alongside a comprehensive weapon system overhaul featuring multi-shot capabilities, heavy weapon mechanics, and refined action point integration. Player exploration is enhanced with a new free movement mode, enabling direct environmental interaction.

Read more

Devlog: Adapting the SteamWorld Heist loot mechanics

In my quest to shamelessy “get inspired by” every mechanic from Steamworld Heist one was missing: The Loot System. Specifically: Delayed Gratification.

The “Mystery Bag” Philosophy

In Diablo, loot is instant. In Into The Deep, you don’t pick up guns; you pick up Loot Tokens. Dirty sacks and heavy crates. You know that you found something, but not what.

This creates immediate tension. When you see a glowing chest across the room while under fire, you have to ask: Is it worth risking my Sniper’s life for a mystery item? (Spoiler: Yes.)

The Logic: Hybrid RNG

To make this fair for hardcore players, I implemented a Hybrid Resolution System in the LootRewardResolver.

  • Quality (Rarity) is influenced by luck and specific difficulty tiers.
  • Quantity (Currency) scales directly with your risk.

Here is the actual C# logic running under the hood when a token is “unwrapped”:

C#
// From LootRewardResolver.cs
public static ILootReward ResolveToken(LootToken token, LootProgressionTable table)
{
    // 1. QUANTITY (Greed): Scales with Difficulty
    // Playing on 'Elite' means 50% more currency in every bag.
    float lootMultiplier = LevelStateManager.GetCurrentLootMultiplier();
    
    // 2. QUALITY (Luck): Biased by Difficulty
    // We use a "Fuzzy Logic" roll that shifts based on the difficulty enum.
    MissionDifficulty difficulty = LevelStateManager.GetCurrentDifficulty();
    int rolledTier = RollTierWithOffset(token.levelTier, difficulty);

    // The Reveal logic
    if (token.rarity == LootRarity.Epic)
    {
        // High Tier Loot!
        var epicItem = GameAssetDatabase.Instance.GetRandomLootItem(rolledTier, LootRarity.Epic);
        return new ItemReward(epicItem, LootRarity.Epic);
    }
    
    // Standard Loot (Currency)
    int baseCurrency = table.RollCurrencyAmount(rolledTier);
    int finalCurrency = Mathf.RoundToInt(baseCurrency * lootMultiplier);
    
    return new CurrencyReward(finalCurrency);
}

The Reveal (The “Juice”)

Since the reward is delayed, the reveal needs to be an event. I sorted the loot queue to open Common items first, building anticipation for the Rares at the end.

Check out the current state of the “Shake & Burst” animation:

It’s a small detail, but getting this right turns the end of a stressful mission into a moment of pure relief. It’s a prototype and needs polishing, but it’s infinitely better than my previous approach, where the chests content showed in a popup and distracted you from the gameplay.

Development Log – October 2025: Turret Combat System Implementation and Player Combat Mechanics Enhancements

A new turret combat system has been implemented, incorporating core functionality, target acquisition, specific variants, and advanced targeting/management mechanics. This update also includes refinements to dash attacks, new critical hit cinematics, a defensive ability, and general system optimizations.

Read more

How I ‘Vibecoded’ a Python App with GitHub Copilot (Without Knowing Python)

As a solo developer and family man, your most valuable resource is time. My daily routine should be about crafting levels, tweaking mechanics, and making dwarves look cool. But being able to debug my game and load different states was getting tedious, the bigger the game and asset database got.

Every time I needed to test a specific scenario lile a late-game weapon, a character at level 5, a boss fight with low health, I had to dive into a raw json file. It was a cycle of manually copy-pasting item IDs, triple checking syntax, and praying I didn’t introduce a typo that would corrupt the whole file. It was an inconvenience that was slowly eating away my will to live, and more importantly, my development time.

There was just one problem: I’m a Unity/C# guy. Python? Might as well be ancient Dwarven runes to me. The thought of spending days or weeks learning a new language and a UI framework just to build a simple internal tool was bad.

So I fired up VS Code, installed Python, installed the GitHub Copilot extension, and decided to see if I could… well, vibe a tool into existence.

The Goal: Make the Computer Understand What I Want

I knew I couldn’t just tell the AI, “make me an editor.” I had to give it the puzzle pieces. Luckily, I had two very clear ones:

  1. The Save File (savegame_999.json): The dynamic state of the player’s game. Full of cryptic stuff like "equippedWeaponID": "ranged_sharpshooter".

  2. The Asset List (GameAssetSummary.json): A clean, simple “dictionary” I exported from Unity, listing all the valid item and character IDs in the game.

JSON
//Example from the savegame. This represents one character. 
//There are also Level States. quest states, general game progress and more.

{
    "saveSlotName": "Debug Save",
    "lastSaveTimestamp": "10/03/2025 13:34:23",
    "currency": 100,
    "rescuedDwarvesCount": 3,
    "lastSceneID": "PC 3 - Demo Collection - 2 - The Corridor",
    "crewStates": [
        {
            "templateID": "dwarf_amos",
            "runtimeName": "Amos",
            "currentLevel": 1,
            "currentXP": 0,
            "maxActionPoints": 2,
            "currentActionPoints": 2,
            "movementRange": 15,
            "currentHP": 8.0,
            "maxHP": 13.0,
            "isDead": false,
            "godMode": false,
            "isSelected": false,
            "isStunned": false,
            "equippedWeaponID": "ranged_sharpshooter",
            "equippedWeaponState": {
                "weaponTemplateID": "ranged_sharpshooter",
                "currentAmmo": 100,
                "maxAmmo": 100,
                "durability": 100.0,
                "maxDurability": 100.0,
                "appliedModifierIDs": [],
                "damageMultiplier": 1.0,
                "firingRateMultiplier": 1.0,
                "spreadMultiplier": 1.0,
                "bulletsPerShotBonus": 0,
                "penetrationBonus": 0
            },
            "equippedWearableSlots": {
                "HeadItemID": "GlassesTypeH"
            },
            "equippedEquipmentIDs": [
                "actionequipment_action_mountain_brew_1",
                ""
            ],
            "learnedAdditionalSkillIDs": [],
            "baseWeaponDamage": 1,
            "baseMeleeDamage": 1,
            "initialBaseWeaponDamage": 1,
            "initialBaseMeleeDamage": 1
        }
        
  //...
  //...
  //...

My idea was simple: a tool that could look at every field like "ranged_sharpshooter" in the save file, check the asset list, and present me with a nice, clean dropdown menu of all available weapons so I could just click on “melee_brodins_axe” instead. No typing, no mistakes. Save the file. Repeat.

The Process: Pair Programming with a Robot Friend

What followed was one of the most productive coding sessions of my life. I was writing instructions in plain English as comments and letting Copilot turn them into actual Python code. And test it. And fix it. All on autopilot. It was really impressive. The simplicity of python and the integration of copilot with the log terminal made it really simple.

1. Make me an App: My first instruction was basically the programming equivalent of “Hey, can you get me a window, that allows me to edit my savegames?”

#Create a GUI with a menu to open, edit and save this Savegame JSON file

…and boom, Copilot spat out the entire boilerplate. It wasn’t pretty, but it was a window. And it worked.

2. The Magic Trick: This was the real test of the vibecoding philosophy. Instead of detailing every step, I gave Copilot a high-level, almost telepathic command:

# Look at both the savegame file and the GameAssetSummary file.

# Find the relationships between them. Let me edit the save file with real references.

I hit Enter, and the AI just… did it. It understood the relationship between the two files. About 95% of the time, Copilot just got it. It correctly inferred that equippedWeaponID should be linked to the Weapons list and a character’s HeadItemID to the Wearables list. I didn’t have to spell it out. It was connecting the dots based on the data’s structure and my high-level intent. This was the moment I truly understood the power of this approach.

3. The Fun Stuff: From there, it was just plain fun. I was basically making wishes in the comments: I can edit any aspect of any character, edit the crew composition, set the level and quest progresses, edit the Inventory, even put on hats and equip items. It felt like cheating, in the best possible way.

The Result: A Tool I Couldn’t Have Built Myself

The final editor is a thing of beauty, not because of how it looks, but because of what it represents. It’s a tool that would have taken me days of frustrating trial-and-error to build, and I got it done in an afternoon. It has everything I need. Really useful tool. I’m even thankful. Thank you Github Copilot and Claude. Good job, team.

Want to try it out? I pushed the results to github with some sample files. For it to be fully production ready I still have to put a bit of work into it. But it’s already very helpful: https://github.com/tobar-io/Into-The-Deep-Save-Game-Editor

Back to developing my game.

Thanks for reading!

Tobi