DEV Community

Tomasz Wegrzanowski
Tomasz Wegrzanowski

Posted on

Open Source Adventures: Episode 54: BATTLETECH Weapon Ranking App

Let's start coding the app. For now I'll hardcode some static assumptions like:

  • we don't care about crit damage
  • we don't care about stability damage
  • 10 ammo per weapon
  • 100% of heat compensated by single heat sinks, so 1 extra ton per 3 heat

Lodash sortBy

JavaScript standard library has an embarassing lack of a lot of basic functionality. I have little patience for writing it all myself every time, so we'll be using lodash for its sortBy function. Its API is quite inconvenient, but it works.

App.svelte

<script> import data from "./data.json" import Row from "./Row.svelte" import {sortBy} from "lodash" let round100 = (v) => Math.round(v * 100) / 100 for (let row of data) { row.value = row.shots * row.baseDamage row.ammoWeight = round100(10 * row.ammoTonnagePerShot) row.cost = round100(row.tonnage + row.ammoWeight + row.heat/3.0) row.ratio = round100(row.value / row.cost) } let sortedData = sortBy(data, [(x) => -x.ratio, (x) => x.name]) </script> <h1>BATTLETECH Weapons Data</h1> <table> <tr> <th>Name</th> <th>Damage</th> <th>Heat</th> <th>Weight</th> <th>Ammo Weight</th> <th>Range</th> <th>Value</th> <th>Cost</th> <th>Ratio</th> </tr> {#each sortedData as row} <Row data={row} /> {/each} </table> <style> :global(body) { margin: 0; min-height: 100vh; display: flex; flex-direction: column; justify-content: center; align-items: center; } table :global(tr):nth-child(even) { background-color: #f2f2f2; } table :global(tr):nth-child(odd) { background-color: #e0e0e0; } </style> 
Enter fullscreen mode Exit fullscreen mode

Here's the main component. We statically precalculate various derived data here. These assumptions will turn into sliders.

Some other points:

  • there's fairly messy :global to make odd/even shading work with tables across component boundary; it's not the only way, but it will do
  • let sortedData = sortBy(data, [(x) => -x.ratio, (x) => x.name]) is some really awkward API

Row.svelte

This component is much easier. Damage and Range column need some custom formatting. Range column could sure be a lot better with some colored bars instead.

Rounding to 2 decimal places could arguably be handled here instead of in the App component.

<script> export let data let {name, heat, shots, baseDamage, tonnage, minRange, maxRange, value, cost, ratio, ammoWeight} = data let damage if (shots == 1) { damage = baseDamage } else { damage = `${shots}x${baseDamage}` } let range = `${minRange}-${maxRange}` </script> <tr> <td>{name}</td> <td>{damage}</td> <td>{heat}</td> <td>{tonnage}</td> <td>{ammoWeight}</td> <td>{range}</td> <td>{value}</td> <td>{cost}</td> <td>{ratio}</td> </tr> 
Enter fullscreen mode Exit fullscreen mode

Story so far

All the code is on GitHub.

I deployed this on GitHub Pages, you can see it here.

Coming next

In the next episode I'll add some sliders to control assumptions made.

Top comments (0)