GreenyRepublic's (Very Rudimentary) Age of Sigmar BattleSim!

Discussion in 'General Hobby/Tabletop Chat' started by GreenyRepublic, Jun 21, 2017.

  1. GreenyRepublic
    Temple Guard

    GreenyRepublic Well-Known Member

    Messages:
    212
    Likes Received:
    992
    Trophy Points:
    93
    So, those of you who've been following my profile status updates closely may have picked up on the fact that I've made myself a new toy to play with. Having been wanting to give Age of Sigmar a go for a while (on the sole condition that I can still call my lizzies Lizardmen) and also wanting to know how well my army will stack up against the other races out there, I decided to put my expensive university education to use and write a little text-based application to test things.

    Ladies and Gentleslann, I present...

    The Age of Sigmar Fight-O-Matic 0.6!


    Download/Clone/Fork it on GitHub!
    Or just download the .exe and data folder!

    Okay, let's get the boring stuff out the way first: this is very much in the early stages, the Fight-O-Matic can functionally simulate melee combat (ranged combat to come very soon) between two units to its end (one side entirely eliminated), and run a user-defined number of repetitions in order to crunch out some averages and other interesting numbers (average number of units left after a win, etc.).

    There are currently no special abilities or upgrades (including weapons with weird rules), though I will try and include these at a later date. It also makes some big simplifications with regards to things like unit positioning/front size, as adding things like model positions and actual range checks would also mean having to program things like movement, pile-ins, etc. Basically it would be a nightmare, so I've kind of abstract-ified it so only a maximum number of models from each side can fight at a time.

    I will stress that as a result of the above, the Fight-O-Matic is really only intended as a rough guide - something that gives you a general idea of 'how does unit x stack up against unit y'? I will accept no liability in the event of chronic embarrassment and/or upstaging at tournaments, nor the wetting of the floor at your local Gee-Dubs as a result of the Stormcast Goldfags having a super special wank ability that drowns your models in Holy Sigmajizz(tm), that the Fight-O-Matic didn't include in its calculations.

    Finally (finally) I'll add that the program is, at the moment, a bit of a mess and the output it produces may not be sparklingly formatted, and it'll crash if you do some bad input. I do very much intend to tidy things up soon though.


    'Alright how do I use this thing?'


    To run the simulator, run the .exe, making absolutely sure you've extracted the files from the .zip and placed the 'data' folder and the .exe in the same directory. Simply enter the name of a unit (no prefixes/faction names required), the number of models you want, and repeat for the second side. Enter the number of battles you'd like to run and whack enter. The FOM will do its thing and spit out some tidy statistics at the end. Neat, right?

    As-is, the FOM reads faction/model/weapon data from a series of Lua files (stored in the 'factiondata' directory), adding new models, weapons, or entirely new factions can be done yourself if you're familiar with it, and even if you aren't I've tried to make the layout as intuitive as possible. As I sadly don't have the time to add every single model myself, right now there are only a very few models from the Seraphon faction. I've linked the GitHub repository so we can turn this into a collaborative effort if anybody fancies adding their own data.

    In the meantime, if you want two units to be tested against one another but don't know how to do XML Lua or any of that wank, then please leave a reply to this thread with your request and I'll sort it all out for you and post the results!


    Here are some features I'm planning to add soon, in rough order of priority.
    1. Ranged combat.
    2. Selector for batch/individual battles. (DONE)
    3. Unit upgrades.
    4. Special weapons and abilities.
    5. Build a GUI-based version off of the current logic.

    Do have fun, and if you have any suggestions or bug reports (besides the obvious) or whatever then please let me know. Again, any contributions of model/weapon XML files would really be appreciated, both by myself, and anybody else who wants to use this thing.
     
    Last edited: Jul 22, 2019
  2. Aginor
    Slann

    Aginor Fifth Spawning Staff Member

    Messages:
    12,249
    Likes Received:
    20,160
    Trophy Points:
    113
    Hmmmm..... interesting. Although I fear that some abilities (useful ones to boot) will be VERY hard to simulate halfway accurately, especially those that are either dependent on movement or cause it.

    btw: which version of Visual Studio does it work with best? Any of the free ones?
     
    LizardWizard and Ritual like this.
  3. GreenyRepublic
    Temple Guard

    GreenyRepublic Well-Known Member

    Messages:
    212
    Likes Received:
    992
    Trophy Points:
    93
    Oh man, doing any of the ones like 'wary fighters' or those things would kind of require me to add actual unit positions and the ability for the user to set them. In fact it would be easier for me just to write a full-fledged graphical AoS tabletop simulator-y thing. I'm keeping the scope of this to straight-up combat, so I'll stick to implementing any upgrades/abilities that directly affect melee combat - re-rolls, rend ignores, etc, since those are still pretty important I think.

    I used Visual Studio Community 2017, haven't tried it with any other versions.
     
    LizardWizard and Ritual like this.
  4. The Red Devil
    Stegadon

    The Red Devil Defender of Hexoatl Staff Member

    Messages:
    995
    Likes Received:
    1,513
    Trophy Points:
    93
    @GreenyRepublic interesting project! Looks great so far.

    Its a good idea to keep it MVP (minimal viable product) and flesh it out with more features like you plan, this allow for feedback from users, and a faster development cycle between releases.
     
    LizardWizard and Ritual like this.
  5. pendrake
    Skink Priest

    pendrake Well-Known Member

    Messages:
    3,764
    Likes Received:
    5,023
    Trophy Points:
    113
    @GreenyRepublic if you try adding calculations having to do with "unit positions" maybe limit the scope of this to a specific and admittedly rare positional situation:

    A Bridge Fight

    Assume that both units are facing each other on a bridge that is table length long and 1 to 10 inches wide. Maybe the user could set the width (?) That constraint ought to simplify a few things...the numbers that can pile in and such.
     
    Aginor and Ritual like this.
  6. Nefertem
    Temple Guard

    Nefertem Well-Known Member

    Messages:
    232
    Likes Received:
    501
    Trophy Points:
    63
    Hi there,
    great thing to start programming such a combat simulator. I added some units (ironjawz), run some fights, and thought it would be very useful to implement "ignore rend" in the program. I saw your list of "things yet to do" and think this would be a major point, as actually the outcome of the calculated fights are quiet ... disappointing, as long as enemy's rend is not negated.
    All in all a cool thing, glad you made it!
     
    LizardWizard, Ritual and Aginor like this.
  7. GreenyRepublic
    Temple Guard

    GreenyRepublic Well-Known Member

    Messages:
    212
    Likes Received:
    992
    Trophy Points:
    93
    Yeah, there are some fairly important things that aren't yet in place, however they are definitely on the way. I just can't say exactly when I'll have them done.

    Would you be interested in contributing your Ironjawz XML files to the project? If you don't use GitHub then feel free to just attach them here in a .zip or something.
     
    LizardWizard and Ritual like this.
  8. Nefertem
    Temple Guard

    Nefertem Well-Known Member

    Messages:
    232
    Likes Received:
    501
    Trophy Points:
    63
    I don't use/have github. I could mail them to you, just pm me. As I'm on a business trip earliest by Saturday this week.

    Another thing I came across :
    In the data files you already implement unit sizes. When running the program you still have to enter the "Number of Models".

    A) is this number n for multiples of the chosen unit's size (n=2, so 2*10 saurus warriors), or
    B) is n the number of models in the unit (n=6, 6 saures warriors)?

    Proposal: hitting return tells the program to use the standard value of the unit size as in the data file, whereas entering a number tells the program to use n models to calculate combat.
     
    Last edited: Jun 29, 2017
    LizardWizard and Ritual like this.
  9. Boboassa
    Saurus

    Boboassa Active Member

    Messages:
    61
    Likes Received:
    139
    Trophy Points:
    33
    Pretty good project!
    Some abilities will be I nightmare to implement though...
     
    LizardWizard, Ritual and Aginor like this.
  10. Nefertem
    Temple Guard

    Nefertem Well-Known Member

    Messages:
    232
    Likes Received:
    501
    Trophy Points:
    63
    @GreenyRepublic : if I can further assist you just let me know. In dem Sinne...
     
  11. GreenyRepublic
    Temple Guard

    GreenyRepublic Well-Known Member

    Messages:
    212
    Likes Received:
    992
    Trophy Points:
    93
    @Nefertem Vielen Dank! Ich werde Sie mitteile. :)
     
    Nefertem, Aginor and Ritual like this.
  12. GreenyRepublic
    Temple Guard

    GreenyRepublic Well-Known Member

    Messages:
    212
    Likes Received:
    992
    Trophy Points:
    93
    Big-ass update!
    I rewrote the entire app in C++, made a fancy menu, and did some other shizzle. Still a heavy WIP but give it a look! Batch battle number crunches will now be outputted to a .txt file in a folder in whichever directory you put the program.

    Enjoy!

    EDIT: There's no direct .exe download link for this one, just the GitHub page link. Download it as a .zip and run the .exe if you want to use it.
     
    Last edited: Aug 11, 2017
    Aginor and Ritual like this.
  13. GreenyRepublic
    Temple Guard

    GreenyRepublic Well-Known Member

    Messages:
    212
    Likes Received:
    992
    Trophy Points:
    93
    BIG UPDATE

    We're in the Lua world now, so all of this:

    Code:
    <faction name = "Seraphon">
    <model name = "Saurus Warriors (Spears)">
    <stats>
    <move>5</move>
    <save>5</save>
    <bravery>10</bravery>
    <wounds>1</wounds>
    </stats>
    <size>10</size>
    <cost>100</cost>
    <weapons>
    <weapon type ="melee">Celestite Spear</weapon>
    <weapon type ="melee">Powerful Jaws and Stardrake Shield</weapon>
    </weapons>
    <upgrades></upgrades>
    <abilities></abilities>
    </model>
    
    <model name = "Saurus Warriors (Clubs)">
    <stats>
    <move>5</move>
    <save>5</save>
    <bravery>10</bravery>
    <wounds>1</wounds>
    </stats>
    <size>10</size>
    <cost>100</cost>
    <weapons>
    <weapon type ="melee">Celestite Club</weapon>
    <weapon type ="melee">Powerful Jaws and Stardrake Shield</weapon>
    </weapons>
    <upgrades></upgrades>
    <abilities></abilities>
    </model>
    
    <model name = "Saurus Guard">
    <stats>
    <move>5</move>
    <save>4</save>
    <bravery>10</bravery>
    <wounds>1</wounds>
    </stats>
    <size>5</size>
    <cost>100</cost>
    <weapons>
    <weapon type ="melee">Celestite Polearm</weapon>
    <weapon type ="melee">Powerful Jaws and Stardrake Shield</weapon>
    </weapons>
    <upgrades></upgrades>
    <abilities></abilities>
    </model>
    
    <model name = "Skinks (Javelins)">
    <stats>
    <move>8</move>
    <save>6</save>
    <bravery>10</bravery>
    <wounds>1</wounds>
    </stats>
    <size>10</size>
    <cost>80</cost>
    <weapons>
    <weapon type ="ranged">Meteoric Javelin</weapon>
    <weapon type ="ranged">Boltspitter</weapon>
    <weapon type ="melee">Meteoric Javelin (M)</weapon>
    <!--weapon type ="melee">Boltspitter (M)</weapon-->
    <!--weapon type ="melee">Moonstone Club</weapon-->
    </weapons>
    <upgrades></upgrades>
    <abilities></abilities>
    </model>
    
    <model name = "Skinks (Boltspitters)">
    <stats>
    <move>8</move>
    <save>6</save>
    <bravery>10</bravery>
    <wounds>1</wounds>
    </stats>
    <size>10</size>
    <cost>80</cost>
    <weapons>
    <weapon type ="ranged">Boltspitter</weapon>
    <weapon type ="melee">Boltspitter (M)</weapon>
    <!--weapon type ="melee">Moonstone Club</weapon-->
    </weapons>
    <upgrades></upgrades>
    <abilities></abilities>
    </model>
    
    <model name = "Kroxigor">
    <stats>
    <move>8</move>
    <save>4</save>
    <bravery>10</bravery>
    <wounds>4</wounds>
    </stats>
    <size>3</size>
    <cost>180</cost>
    <weapons>
    <weapon type ="melee">Drakebite Maul</weapon>
    <weapon type ="melee">Vice-Like Jaws</weapon>
    </weapons>
    <upgrades></upgrades>
    <abilities></abilities>
    </model>
    </faction>
    

    Now looks a bit like this:

    Code:
    --Abilities declared globally as most are used multiple times
    -- These are all incomplete and unimplemented as the mechanisms need to be added to the cpp side
    StardrakeIcon = {}
    Wardrum = {}
    StardrakeShield =
    {
    name = "Stardrake Shield",
    type = "",
    effect =
    function ()
    end
    }
    StarBuckler = StardrakeShield
    
    OrderedCohort =
    {
    name = "OrderedCohort",
    type = "",
    effect =
    function ()
    end
    }
    EnergyTransference = {}
    
    SwornGuardians =
    {
    name = "Sworn Guardians",
    type = "",
    effect =
    function ()
    end
    }
    
    faction =
    {
    name = "Seraphon",
    models =
    {
    --[[{
    name = "Sample Model",
    stats =
    {
    move = 4,
    save = 4,
    bravery = 8,
    wounds = 2
    },
    matchedData =
    {
    unitSize = 5,
    unitCost = 100
    },
    keywords =
    {
    "ORDER",
    "SOMETHING",
    "LOOKAKEYWORD"
    },
    meleeWeapons =
    {
    {
    name = "Sword",
    range = 1,
    attacks = 1,
    toHit = 3,
    toWound = 4,
    rend = -1,
    damage = 2
    }
    },--]]
    
    {
    name = "Saurus Warriors (Clubs)",
    stats =
    {
    move = 5,
    save = 5,
    bravery = 10,
    wounds = 1
    },
    matchedData =
    {
    unitSize = 10,
    unitCost = 90
    },
    keywords =
    {
    "ORDER",
    "DAEMON",
    "CELESTIAL",
    "SERAPHON",
    "SAURUS",
    "SAURUS WARRIORS"
    },
    meleeWeapons =
    {
    {
    name = "Celestite Club",
    range = 1,
    attacks = 1,
    toHit = 4,
    toWound = 3,
    rend = 0,
    damage = 1
    } ,
    {
    name = "Powerful Jaws and Stardrake Shield",
    range = 1,
    attacks = 1,
    toHit = 5,
    toWound = 4,
    rend = 0,
    damage = 1
    }
    },
    
    abilities =
    {
    StardrakeIcon,
    Wardrum,
    StardrakeShield,
    OrderedCohort
    }
    },
    
    {
    name = "Saurus Warriors (Spears)",
    stats =
    {
    move = 5,
    save = 5,
    bravery = 10,
    wounds = 1
    },
    matchedData =
    {
    unitSize = 10,
    unitCost = 90
    },
    keywords =
    {
    "ORDER",
    "DAEMON",
    "CELESTIAL",
    "SERAPHON",
    "SAURUS",
    "SAURUS WARRIORS"
    },
    meleeWeapons =
    {
    {
    name = "Celestite Spear",
    range = 2,
    attacks = 1,
    toHit = 4,
    toWound = 4,
    rend = 0,
    damage = 1
    } ,
    {
    name = "Powerful Jaws and Stardrake Shield",
    range = 1,
    attacks = 1,
    toHit = 5,
    toWound = 4,
    rend = 0,
    damage = 1
    }
    },
    
    abilities =
    {
    StardrakeIcon,
    Wardrum,
    StardrakeShield,
    OrderedCohort
    }
    },
    
    {
    name = "Saurus Guard",
    stats =
    {
    move = 5,
    save = 4,
    bravery = 10,
    wounds = 1
    },
    matchedData =
    {
    unitSize = 5,
    unitCost = 100
    },
    keywords =
    {
    "ORDER",
    "DAEMON",
    "CELESTIAL",
    "SERAPHON",
    "SAURUS",
    "SAURUS GUARD"
    },
    meleeWeapons =
    {
    {
    name = "Celestite Polearm",
    range = 1,
    attacks = 2,
    toHit = 3,
    toWound = 3,
    rend = -1,
    damage = 1
    } ,
    {
    name = "Powerful Jaws and Stardrake Shield",
    range = 1,
    attacks = 1,
    toHit = 5,
    toWound = 4,
    rend = 0,
    damage = 1
    }
    },
    
    abilities =
    {
    StardrakeIcon,
    Wardrum,
    StardrakeShield,
    SwornGuardians
    }
    },
    
    {
    name = "Skinks (Javelins and Shields)",
    stats =
    {
    move = 8,
    save = 6,
    bravery = 10,
    wounds = 1
    },
    
    matchedData =
    {
    unitSize = 10,
    unitCost = 80
    },
    keywords =
    {
    "ORDER",
    "DAEMON",
    "CELESTIAL",
    "SERAPHON",
    "SKINKS"
    },
    meleeWeapons =
    {
    {
    name = "Meteoric Javelin",
    range = 1,
    attacks = 1,
    toHit = 6,
    toWound = 5,
    rend = -1,
    damage = 1
    }
    },
    rangedWeapons =
    {
    {
    name = "Meteoric Javelin",
    range = 8,
    attacks = 1,
    toHit = 5,
    toWound = 4,
    rend = 0,
    damage = 1
    }
    },
    abilities =
    {
    CelestialCohort,
    StarBuckler
    }
    },
    {
    name = "Kroxigor",
    stats =
    {
    move = 8,
    save = 4,
    bravery = 10,
    wounds = 4
    },
    matchedData =
    {
    unitSize = 3,
    unitCost = 180
    },
    keywords =
    {
    "ORDER",
    "DAEMON",
    "CELESTIAL",
    "SERAPHON",
    "KROXIGOR",
    },
    meleeWeapons =
    {
    {
    name = "Drakebite Maul",
    range = 2,
    attacks = 4,
    toHit = 4,
    toWound = 3,
    rend = 0,
    damage = 2
    } ,
    {
    name = "Vice-like Jaws",
    range = 1,
    attacks = 1,
    toHit = 4,
    toWound = 3,
    rend = -1,
    damage = 1
    }
    },
    abilities =
    {
    EnergyTransference
    }
    },
    }
    }
    
    
    

    Unfortunately code formatting on XenForo is a bit rudimentary so that all looks messier than it would do in a proper editor. Hopefully you'll all find the Lua format less cluttered and a bit more intuitive, and whilst I can't commit the time to converting all of the existing faction data, I hope to provide a comprehensive Seraphon document over time as a reference, and I will of course be here to answer any and all questions you may have about how things need to be laid out.

    However there's more to the motivation for this than just having more readable data - implementing the facility to handle any one of Age of Sigmar's wacky-ass abilities was going to be really, REALLY difficult in an XML format for reasons that should be obvious, and having a domain-specific-language like Lua allows us to write our own ability definitions in a reasonably intuitive manner, for example our Stardrake Shield ability may look something like this:

    Code:
    StardrakeShield =
    {
    ability =
    function()
        if getIncomingAttack().rend =< -1
            getIncomingAttack().rend = 0
        end
    end
    }
    
    Now here's the catch: none of this works yet, and so far all I have is model/weapon data being correctly parsed from Lua files (provided the data matches the naming conventions I've set), the C++ code is not in place to handle abilities, in fact to get this working I'll need to be doing a tonne more design groundwork than I had originally anticipated (talk about opening a can of worms).

    As I go down that rabbit hole I'll make a few posts here about it sharing my thought process, hopefully you'll all find that interesting! In the meantime please feel free to ask about the new format and for help with getting data files together, I appreciate any and all contributions!

    - GreenyRepublic
     

Share This Page