Game Off 2021 - YourWaifuIsALie

Blog and documentation for Game Off 2021 attempt.


Project maintained by YourWaifuIsALie Hosted on GitHub Pages — Theme by mattgraham

Game Off 2021 - Day 6

November 07, 2021

Study

Battle structures plan

Just going to program as it comes naturally to me.

Overarching BattleManager which will keep track of things like the actors involved, turn order, and UI updates.

BattleActor which implements some stat-line (imported from JSON), tags, and actions that can be taken.

Actions are some simple composition of targets and effects (which may have some conditional component).

Remember to have all the control objects separate from the graphical implementations (generally that means empty parent objects with graphical child objects?).

Progress

Actions and effects

Just started programming with the “goal” in mind. I ended up with several micro-refactors as I went along, implementing small toy examples to keep things in mind. For example I started with:

BattleActor target = targets[0];
int damage = ((EffectBasicAttackDamage)effects[0]).effect(origin, target);
if (damage > 0)
{
    if (((EffectReduceAttackDamage)effects[1]).effect(origin, target))
        damage /= 2;
    target.currentHealth -= damage;
}

As a method to calculate basic attack damage with a possible 50% damage reduction modifier.

Looking at this, it’s obvious it doesn’t scale well. I don’t ever want to specify certain subclasses in the source code. If the effects are composable and can be specified by JSON files outside the source, it becomes much easier for me to add new effects to the game. This led to:

BattleActor target = targets[0];
int damage = 0;
foreach (var effect in effects)
    damage = effect.process(origin, target, damage);
if (damage > 0)
    target.currentHealth = target.currentHealth - damage;

Every effect involved in the “BasicAttack” action will affect the damage dealt in some way, so now I can use a different loading process to grab all the effects that specify themselves as attack damage modifiers.

That led me to changing around the effects (which themselves went through several revisions abstraction) to:

public class EffectBasicAttack : AttackDamageEffect
{
    // Calculate damage from attack and defense values
    public EffectBasicAttack() { }

    public override int effect(BattleActor origin, BattleActor target, int damage)
    {
        int moreDamage = origin.currentAttack - target.currentDefense;
        if (moreDamage > 0)
            return damage + moreDamage;
        else
            return damage;
    }
}

public class EffectPercentModifyDamage : AttackDamageEffect
{
    public float percentReduction { get; set; }
    public string targetTag { get; set; }

    // Modify current damage based on percentage if tags match  
    public EffectPercentModifyDamage(float in_percent, string in_tag)
    {
        percentReduction = in_percent;
        targetTag = in_tag;
    }

    public override int effect(BattleActor origin, BattleActor target, int damage)
    {
        int index = target.tags.FindIndex(tag => tag.name == targetTag);

        if (index != -1)
            return damage * percentReduction;
        else
            return damage;
    }
}

In this way, a “multi-attack” could just be the same EffectBasicAttack applied three times in a row.

However, why limit the effect to a single tag on the target? This led to some thought on using a JSON file to specify the possible effect conditions. At first I began by adding extra fields to EffectPercentModifyDamage like originTags and targetTags but then I decided that was dumb and should just use boolean logic defined in the JSON.

public class EffectPercentModifyDamage : AttackDamageEffect
{
    // TODO: Figure out set values of effectValues and use that
    public float percentChange { get; set; }

    // Modify current damage based on percentage if tags match 
    public EffectPercentModifyDamage() { }

    public override int process(BattleActor origin, BattleActor target, int damage)
    {
        if (this.evaluateCondition(origin, target))
            return (int)(damage * percentChange);  // TODO: determinism worries? non-float ways to calculate?
        else
            return damage;
    }
}

As can be seen, I’m not done with setting up loading data from JSON files yet. I don’t need variables in the subclass if the JSON data model has a well-defined place for “values” that are used in the effects.

JSON boolean logic

I also haven’t implemented the boolean logic parser (the this.evaluateCondition method) but it should be straightforward.

Given a field:

"condition": {"and": {"target": ["light"], "origin": ["heavy"]}}

It should parse the rule as:

True if "light" in target.tags and "heavy" in origin.tags

From the top-level condition key, there will only ever be one or two fields and those fields will have one of four keys (and, or, target, and origin). The value of the fields will be either another dictionary or a list of strings.

TODO

Time Spent

10.75 + 5hr