Protobound Day 5: Stats

Stats are pretty simple and straight-forward as far as RPGs go. They are a set of numbers that increase or decrease based on levels and modifiers. Each character would have base stats and modified stats which are applied to attacks and defense calculations based on the types of attacks (in this case magic/physical). The stat system will need a way of tracking time/turn-based modifiers so it will need a turn counter. Do stat mods clear after current combat? If not the mods and counters need to persist through different combat encounters.

Each character needs their own stats, but I only want to write the script once. One idea I have is to load the stats based on the character name from a JSON file. The JSON file will contain stat gains based on each level for each character, looked up by loading the file into a dict, finding the key based on the level of the character and then adding the stats into the base stats.

Modified stats could either be calculated on application of modifier or each time the stat is needed. I would prefer the former, as there is less resource use and that means I wont have to think as much to speed up the game logic if I do resume this project at some later date.

The main issue with this is; How do I handle the modifiers? I suppose what I could do is have a class for modifiers as a prefab that can be constructed and added as a child to the Stats node. They would need to construct themselves with counters and a bool for enabling the counter. On the counter running out (after X combat turns) they would remove their modification from the parent node (Stats) and self destruct. This way equipment can be treated as a modifier that on unequip calls the destruct function of the node. Each time a modifier node is added or removed we just have to recalculate modified stats rather than each time an attack is made or received.

So, what I need is a folder called Stats with the JSON files required for each character, a node called Stats which I guess I can construct as a Scene... though it will be needing to get data from it's parent so we'll see how that goes. A prefab called Modifier that can be instantiated as a child of Stats and cause a recalculation in Modified stats on creation and destruction. Basically need a Ctor and Dtor with a timer and a bool. Does Godot have built in Ctors? enter_tree and exit_tree look like they might be what I am looking for.

Alright, planning done. Lunch, dog walk, then execution and iteration.

Right, let's get this done because I gotta build a water temperature monitoring system before the day is out.

I know that I could work without 2 values for base_stats and modified_stats but I want to know both for debug reasons. Make sure values get applied properly.

I've got 5 levels per character.

{
    "1": {
        "speed": 3,
	    "strength": 3,
	    "magic": 1,
	    "physical_defense": 2,
	    "magic_defense": 2,
	    "agility": 2,
	    "dexterity": 3
    },
    "2": {
        "speed": 1,
	    "strength": 2,
	    "magic": 0,
	    "physical_defense": 1,
	    "magic_defense": 1,
	    "agility": 1,
	    "dexterity": 1
    },
    "3": {
        "speed": 2,
	    "strength": 2,
	    "magic": 1,
	    "physical_defense": 1,
	    "magic_defense": 2,
	    "agility": 2,
	    "dexterity": 2
    },
    "4": {
        "speed": 1,
	    "strength": 2,
	    "magic": 0,
	    "physical_defense": 2,
	    "magic_defense": 1,
	    "agility": 1,
	    "dexterity": 3
    },
    "5": {
        "speed": 2,
	    "strength": 3,
	    "magic": 1,
	    "physical_defense": 1,
	    "magic_defense": 1,
	    "agility": 2,
	    "dexterity": 2
    }
}

There's no method to this madness, what I could do is decide an arbitrary amount of stats to distribute each level but I am just winging it here, I will likely adjust it when I add combat anyway. Also somehow the formatting gets busted when I paste into my editor here but I got more important things to do.

func read_stats(level):
	var file = File.new()
	file.open("res://Characters/Stats/"+character_name+".json", File.READ)
	var stats = parse_json(file.get_as_text())
	file.close()
	return stats[level]

Above should... in theory read the file into memory, get the stats for the level in question, then close the file and return them. I'm sure there is a more efficient way to do this when the file gets large but I don't think I have the time today to be exploring that avenue. Next I need to make sure the base stats are loaded properly on startup.

Yep. There's our stats loading in all nice and stat..y? Uh anyway, now for leveling up.

There's leveling up handled. I will need to check if the character level is 1 in the _ready function before calling the stats initialization or it will happen every time the character is loaded. Alternately I could re-level up the character every single load but that's inefficient and dumb and I should feel bad for thinking of it at all.

On to the modifiers. I wonder if there's a way to flip a sign in GDscript easily? Guess I will handle it with an if, I didn't find any methods on int in the docs that could be useful. If modifier value > 0 subtract modifier on destruction, else add.

Got the modifiers actually getting created and modifying stats. Now I need to make sure they go back when the modifier is destroyed.

I had to change how the mod interacted with the stats, not sure what I was thinking with the If/else statement looking for positive and negative. Now I have the node track whether it is a positive or negative mod, then in the stats where I handle addition/removal of the mod I will add or subtract the stat mod accordingly.

Tested and working for party members. Glad I didn't screw that up. Alright, I think that's it right? The stats increase on level up and are changed properly with modifiers. There are functions in the modifiers for equipment, ready to go.

Tomorrow I need to add equipment. Then the next day shops. I also need to create the UI for the party equipment and stats. ( I figure I should have both on one panel since there are 2 equip slots and having a dedicated UI for that would be sparse and unnecessary.

On to the water temperature probe and display system using an ESP32 I guess. I can't find my spare arduino and my arduino minis have some shoddy header soldering. I suppose I could use an 8266 for this. I also need a breadboard... time to hunt for parts in the office. Time to break out the magnifying glass and detective hat and start tracking em down.

Assembled the parts, having a bit of trouble dialing out to my ESP32 over serial from the OS and don't have time to fix it so going to the living room to finish up. Gonna need it out there anyway. Off we go.

Cheers.