@massif/lancer-data 3.1.7 → 4.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/pull_request_template.md +15 -15
- package/.github/workflows/deploy-npm.yml +13 -13
- package/.github/workflows/lcp-version-bump.yml +21 -21
- package/README.md +1373 -1373
- package/index.js +31 -30
- package/lib/actions.json +296 -464
- package/lib/backgrounds.json +221 -221
- package/lib/core_bonuses.json +156 -87
- package/lib/downtime_actions.json +203 -0
- package/lib/frames.json +1844 -1844
- package/lib/glossary.json +157 -157
- package/lib/info.json +7 -7
- package/lib/manufacturers.json +47 -47
- package/lib/mods.json +24 -21
- package/lib/pilot_gear.json +33 -11
- package/lib/rules.json +53 -53
- package/lib/skills.json +155 -155
- package/lib/statuses.json +126 -111
- package/lib/systems.json +191 -61
- package/lib/tables.json +28 -28
- package/lib/tags.json +319 -319
- package/lib/talents.json +1347 -1346
- package/lib/weapons.json +58 -20
- package/package.json +29 -29
- package/scripts/aptitude_export.js +134 -134
- package/scripts/build.js +14 -14
- package/scripts/output/equipment.csv +86 -86
- package/scripts/test.js +19 -19
- package/scripts/util.js +127 -0
- package/scripts/rename.js +0 -74
package/lib/weapons.json
CHANGED
|
@@ -690,7 +690,9 @@
|
|
|
690
690
|
"source": "IPS-N",
|
|
691
691
|
"license": "Blackbeard",
|
|
692
692
|
"license_level": 2,
|
|
693
|
-
"effect":
|
|
693
|
+
"effect": {
|
|
694
|
+
"description": "This weapon ignores ranged penalties from Engaged, and deals 3 Kinetic damage to Grappled or Biological targets, instead of 1."
|
|
695
|
+
},
|
|
694
696
|
"description": "The IPS-N Bristlecrown Flechette Launcher uses a hive-analogous mechanism to project a total soft-target kill zone in a dome around the user, proactively denying hostile infantry-tier actions.",
|
|
695
697
|
"license_id": "mf_blackbeard"
|
|
696
698
|
},
|
|
@@ -938,7 +940,9 @@
|
|
|
938
940
|
"source": "IPS-N",
|
|
939
941
|
"license": "Lancaster",
|
|
940
942
|
"license_level": 3,
|
|
941
|
-
"effect":
|
|
943
|
+
"effect": {
|
|
944
|
+
"description": "This weapon deals 10AP energy to objects, cover, terrain, and the environment."
|
|
945
|
+
},
|
|
942
946
|
"description": "Plasma cutters were tools first: simple blades built to toggle and sustain a plasma sheath, making it easier to cut metal. Repeated ad hoc use of cutters as personal defense weapons against pirate boarding parties convinced IPS-N of the need for a mil-spec variant of the civilian tool – the Cutter, now in its second generation. The Cutter MkII feeds directly from the mech’s power core, with a port to attach power packs in case of cord severance. Although the cutting edge can be shortened to a knife length, its most popular setting is the “cutlass”, a medium-length option perfect for balancing reach and maneuverability in close quarters.",
|
|
943
947
|
"license_id": "mf_lancaster"
|
|
944
948
|
},
|
|
@@ -1281,7 +1285,9 @@
|
|
|
1281
1285
|
"source": "IPS-N",
|
|
1282
1286
|
"license": "Vlad",
|
|
1283
1287
|
"license_level": 3,
|
|
1284
|
-
"effect":
|
|
1288
|
+
"effect": {
|
|
1289
|
+
"description": "When attacking a character that is Prone, Immobilized, or Stunned, this weapon’s Overkill tag does an extra +1d6 bonus damage each time it activates. This can activate indefinitely if the new bonus die result is a 1, triggering Overkill again."
|
|
1290
|
+
},
|
|
1285
1291
|
"description": "The combat drill is a brutal close-combat weapon, powered by a massive external catalyst pack. The bit is tipped with microplasmatic projectors designed to pre-treat the target and ensure drill penetration.",
|
|
1286
1292
|
"license_id": "mf_vlad"
|
|
1287
1293
|
},
|
|
@@ -1404,7 +1410,9 @@
|
|
|
1404
1410
|
"source": "SSC",
|
|
1405
1411
|
"license": "Dusk Wing",
|
|
1406
1412
|
"license_level": 1,
|
|
1407
|
-
"effect":
|
|
1413
|
+
"effect": {
|
|
1414
|
+
"description": "This weapon does not attack allied characters caught in its area of effect; instead, it shrouds them in a field of coruscating energy that throws off targeting systems, giving them soft cover until the end of their next turn."
|
|
1415
|
+
},
|
|
1408
1416
|
"description": "“We made first contact maybe an hour after breaching the vault. I remember nothing of it. I’m told most of my squad was killed outright; all I remember is light – brilliant – and a lightness in my own being.<br>“I do believe that I died in that moment, and yet I’m here, and I can’t square these two realities. Something has gone wrong, something has gone wrong, something has gone–”",
|
|
1409
1417
|
"license_id": "mf_dusk_wing"
|
|
1410
1418
|
},
|
|
@@ -1535,7 +1543,9 @@
|
|
|
1535
1543
|
"source": "SSC",
|
|
1536
1544
|
"license": "Monarch",
|
|
1537
1545
|
"license_level": 1,
|
|
1538
|
-
"effect":
|
|
1546
|
+
"effect": {
|
|
1547
|
+
"description": "This weapon can attack two targets at a time."
|
|
1548
|
+
},
|
|
1539
1549
|
"description": "“It was a duel. This is why they were made: to duel, and in that combat, to shake the pillars of the universe.” — “Notes for Young John”, Ministrations of the Master Teacher",
|
|
1540
1550
|
"license_id": "mf_monarch"
|
|
1541
1551
|
},
|
|
@@ -1607,7 +1617,9 @@
|
|
|
1607
1617
|
"source": "SSC",
|
|
1608
1618
|
"license": "Monarch",
|
|
1609
1619
|
"license_level": 3,
|
|
1610
|
-
"effect":
|
|
1620
|
+
"effect": {
|
|
1621
|
+
"description": "Attacks with this weapon create up to two blast 1 areas, which cannot overlap.<br>You may also delay the impact of attacks made with this weapon. Choose the target area(s), which become visible to all characters: the missiles land at the end of the next round, after all characters have acted, and deal 3d6 explosive damage instead of 2d6, but you become Slowed until the end of your next turn."
|
|
1622
|
+
},
|
|
1611
1623
|
"description": "Pinaka missiles are massive, two-stage missiles typically mounted along a mech’s spine or carried, disassembled, to be launched from a brachial mount. The Pinaka was originally adapted from ship-to-ship missiles; as such, their second stage uses jet-assist repositioning for midflight orientation.",
|
|
1612
1624
|
"license_id": "mf_monarch"
|
|
1613
1625
|
},
|
|
@@ -1823,7 +1835,9 @@
|
|
|
1823
1835
|
"source": "HORUS",
|
|
1824
1836
|
"license": "Goblin",
|
|
1825
1837
|
"license_level": 1,
|
|
1826
|
-
"effect":
|
|
1838
|
+
"effect": {
|
|
1839
|
+
"description": "Instead of using any kind of trigger mechanism, this weapon automatically scans for target locks, firing spinning, razor-sharp disks upon successful IDs. Gain the Autonomous Assault reaction, which is the only way you can attack with the Autopod"
|
|
1840
|
+
},
|
|
1827
1841
|
"actions": [
|
|
1828
1842
|
{
|
|
1829
1843
|
"name": "Autonomous Assault",
|
|
@@ -1858,7 +1872,9 @@
|
|
|
1858
1872
|
"source": "HORUS",
|
|
1859
1873
|
"license": "Gorgon",
|
|
1860
1874
|
"license_level": 3,
|
|
1861
|
-
"effect":
|
|
1875
|
+
"effect": {
|
|
1876
|
+
"description": "Gain the Snicker-Snack reaction, which is the only way you can attack with this weapon."
|
|
1877
|
+
},
|
|
1862
1878
|
"actions": [
|
|
1863
1879
|
{
|
|
1864
1880
|
"name": "Snicker-Snack",
|
|
@@ -1928,7 +1944,9 @@
|
|
|
1928
1944
|
"source": "HORUS",
|
|
1929
1945
|
"license": "Hydra",
|
|
1930
1946
|
"license_level": 2,
|
|
1931
|
-
"effect":
|
|
1947
|
+
"effect": {
|
|
1948
|
+
"description": "This weapon may be used to attack as normal, or deployed as a Drone"
|
|
1949
|
+
},
|
|
1932
1950
|
"deployables": [
|
|
1933
1951
|
{
|
|
1934
1952
|
"name": "Ghast Drone",
|
|
@@ -2108,7 +2126,9 @@
|
|
|
2108
2126
|
"source": "HORUS",
|
|
2109
2127
|
"license": "Pegasus",
|
|
2110
2128
|
"license_level": 2,
|
|
2111
|
-
"effect":
|
|
2129
|
+
"effect": {
|
|
2130
|
+
"description": "This horrifying weapon has no basic form; it constantly contorts itself into different shapes, mimicking the weapons of other combatants. It counts as all ranged weapon types simultaneously (e.g., CQB, Rifle, etc.), but it can’t take Mods or benefit from core bonuses, although it still benefits from talents as normal.<br>At the start of combat, roll 3d20 and note the results in order: X, Y, and Z. X is its starting base Range (before modifications from talents). At the start of each of your turns after the first, the mimic gun cycles to the next result, taking that as its base Range. After Z, it cycles back to X.<br>The mimic gun does kinetic equal to 1 + half of its current base Range.<br>You may provoke the mimic gun as a full action, rolling a new set of 3d20."
|
|
2131
|
+
},
|
|
2112
2132
|
"actions": [
|
|
2113
2133
|
{
|
|
2114
2134
|
"name": "Provoke Mimic Gun",
|
|
@@ -2148,7 +2168,9 @@
|
|
|
2148
2168
|
"detail": "This weapon can’t make normal attacks. Instead, you can attack with it as a free action at the end of your turn. It doesn’t benefit from or trigger your talents."
|
|
2149
2169
|
}
|
|
2150
2170
|
],
|
|
2151
|
-
"effect":
|
|
2171
|
+
"effect": {
|
|
2172
|
+
"description": "This weapon can’t make normal attacks. Instead, you can attack with it as a free action at the end of your turn. It doesn’t benefit from or trigger your talents."
|
|
2173
|
+
},
|
|
2152
2174
|
"description": "As the name implies, autoguns are automated weapons. Similar to point-defense systems, autoguns are chambered to provide effective fire against armored targets. Typically mounted on a stabilized, secondary arm, a reliably tuned autogun can be trusted to track and eliminate designated enemy units while a pilot concentrates on more specialized weapons or processes. Cheap, with malleable codebases, autoguns are common among active, armed HORUS cells.",
|
|
2153
2175
|
"sp": 1,
|
|
2154
2176
|
"license_id": "mf_pegasus"
|
|
@@ -2288,7 +2310,9 @@
|
|
|
2288
2310
|
"source": "HA",
|
|
2289
2311
|
"license": "Genghis",
|
|
2290
2312
|
"license_level": 3,
|
|
2291
|
-
"effect":
|
|
2313
|
+
"effect": {
|
|
2314
|
+
"description": "Can be fired as Cone 7 <i>or</i> Line 10"
|
|
2315
|
+
},
|
|
2292
2316
|
"on_attack": "White-hot flames continue to burn in 3 free spaces of your choice within the affected area, lasting for the rest of the scene. When characters start their turn in one of these spaces or enter one for the first time in a round, they take 1d6 energy damage.",
|
|
2293
2317
|
"description": "The plasma thrower emerged too late in the Hercynian Crisis to see widespread use in the field. The scarce data gathered from the MEF squadrons that used it suggest that plasma throwers would have had a tremendous impact on the outcomes of several major battles that occurred during the bloodiest phase of the Crisis.",
|
|
2294
2318
|
"license_id": "mf_genghis"
|
|
@@ -2418,7 +2442,9 @@
|
|
|
2418
2442
|
"source": "HA",
|
|
2419
2443
|
"license": "Saladin",
|
|
2420
2444
|
"license_level": 1,
|
|
2421
|
-
"effect":
|
|
2445
|
+
"effect": {
|
|
2446
|
+
"description": "The final attack roll for this weapon can never be affected by difficulty."
|
|
2447
|
+
},
|
|
2422
2448
|
"description": "Developed following costly urban and naval boarding engagements in the Interest War, Shatterhead Colony Missiles are now a standard part of the arsenal fielded by Armory interdiction teams. When they reach an optimal distance, Shatterheads break open in a burst of high-catalyst fuel to reveal a cluster of small thermobaric pellets that spread out and ignite, choking the affected area with flame. The effect overloads energy shielding and saturates cover, though only a small percent of the projectiles actually reach their target.",
|
|
2423
2449
|
"sp": 1,
|
|
2424
2450
|
"license_id": "mf_saladin"
|
|
@@ -2681,7 +2707,9 @@
|
|
|
2681
2707
|
"talent_item": true,
|
|
2682
2708
|
"talent_id": "t_engineer",
|
|
2683
2709
|
"talent_rank": 1,
|
|
2684
|
-
"effect":
|
|
2710
|
+
"effect": {
|
|
2711
|
+
"description": "This weapon is an experimental prototype, customized according to your specific requirements.<br>When you install it, or during a Full Repair, you may choose a new weapon type, damage type, and either Threat 1 (melee) or Range 10 (all other types). Additionally, each time you perform a Full Repair, reroll 1d6+2 to determine this weapon’s Limited uses."
|
|
2712
|
+
},
|
|
2685
2713
|
"description": "Gained from the <i>\"Engineer\" Rank I</i> Talent",
|
|
2686
2714
|
"license_id": ""
|
|
2687
2715
|
},
|
|
@@ -2727,7 +2755,9 @@
|
|
|
2727
2755
|
"talent_item": true,
|
|
2728
2756
|
"talent_id": "t_engineer",
|
|
2729
2757
|
"talent_rank": 2,
|
|
2730
|
-
"effect":
|
|
2758
|
+
"effect": {
|
|
2759
|
+
"description": "This weapon is an experimental prototype, customized according to your specific requirements.<br>When you install it, or during a Full Repair, you may choose a new weapon type, damage type, and either Threat 1 (melee) or Range 10 (all other types). Additionally, each time you perform a Full Repair, reroll 1d6+2 to determine this weapon’s Limited uses and choose two:<ul><li><b>Tweaked Optics:</b> Your prototype weapon always gains +1 Accuracy on attacks.</li><li><b>Tweaked Computer:</b> Your prototype weapon is Smart.</li><li><b>Stripped reactor shielding:</b> Each time you attack with your prototype weapon, you may choose – at the cost of 2 Heat – to attack with one of the following options, depending on its weapon type:<ul><li><b>Ranged weapon:</b> Cone 3, Line 5, or [Blast 1, Range 10].</li><li><b>Melee weapon:</b> Burst 1.</li></li></ul></ul>"
|
|
2760
|
+
},
|
|
2731
2761
|
"description": "Gained from the <i>\"Engineer\" Rank II</i> Talent",
|
|
2732
2762
|
"license_id": ""
|
|
2733
2763
|
},
|
|
@@ -2773,7 +2803,9 @@
|
|
|
2773
2803
|
"talent_item": true,
|
|
2774
2804
|
"talent_id": "t_engineer",
|
|
2775
2805
|
"talent_rank": 3,
|
|
2776
|
-
"effect":
|
|
2806
|
+
"effect": {
|
|
2807
|
+
"description": "This weapon is an experimental prototype, customized according to your specific requirements.<br>When you install it, or during a Full Repair, you may choose a new weapon type, damage type, and either Threat 1 (melee) or Range 10 (all other types). Additionally, each time you perform a Full Repair, reroll 2d6 to determine this weapon’s Limited uses and choose two:<ul><li><b>Tweaked Optics:</b> Your prototype weapon always gains +1 Accuracy on attacks.</li><li><b>Tweaked Computer:</b> Your prototype weapon is Smart.</li><li><b>Stripped reactor shielding:</b> Each time you attack with your prototype weapon, you may choose – at the cost of 2 Heat – to attack with one of the following options, depending on its weapon type:<ul><li><b>Ranged weapon:</b> Cone 3, Line 5, or [Blast 1, Range 10].</li><li><b>Melee weapon:</b> Burst 1.</li></li></ul></ul>"
|
|
2808
|
+
},
|
|
2777
2809
|
"description": "Gained from the <i>\"Engineer\" Rank III</i> Talent",
|
|
2778
2810
|
"license_id": ""
|
|
2779
2811
|
},
|
|
@@ -2789,7 +2821,9 @@
|
|
|
2789
2821
|
"val": 8
|
|
2790
2822
|
}
|
|
2791
2823
|
],
|
|
2792
|
-
"effect":
|
|
2824
|
+
"effect": {
|
|
2825
|
+
"description": "This weapon can’t make normal attacks. Instead, choose an allied mech within Range and line of sight and make a ranged attack against Evasion 8. On a hit, either you or your target may spend 1 Repair to restore half your target’s HP."
|
|
2826
|
+
},
|
|
2793
2827
|
"license_id": ""
|
|
2794
2828
|
},
|
|
2795
2829
|
{
|
|
@@ -2813,7 +2847,9 @@
|
|
|
2813
2847
|
"val": 4
|
|
2814
2848
|
}
|
|
2815
2849
|
],
|
|
2816
|
-
"effect":
|
|
2850
|
+
"effect": {
|
|
2851
|
+
"description": "1/round, when you reload any weapon, this weapon can be fired as a free action."
|
|
2852
|
+
},
|
|
2817
2853
|
"license_id": ""
|
|
2818
2854
|
},
|
|
2819
2855
|
{
|
|
@@ -2823,7 +2859,9 @@
|
|
|
2823
2859
|
"type": "Spool Weapon",
|
|
2824
2860
|
"skirmish": false,
|
|
2825
2861
|
"barrage": false,
|
|
2826
|
-
"effect":
|
|
2862
|
+
"effect": {
|
|
2863
|
+
"description": "The Apocalypse Rail must be charged before it can be fired, using the Charge Rail CORE Power.<br>This weapon has different profiles determined by the current value of the APOCALYPSE DIE when you fire it. Each profile replaces the one proceeding it. The Apocalypse Rail cannot be fired at targets within range 5.<br> After an attack with the Apocalypse Rail, the Apocalypse Die resets to 4."
|
|
2864
|
+
},
|
|
2827
2865
|
"actions": [
|
|
2828
2866
|
{
|
|
2829
2867
|
"name": "Fire Apocalypse Rail",
|
|
@@ -2990,4 +3028,4 @@
|
|
|
2990
3028
|
],
|
|
2991
3029
|
"license_id": ""
|
|
2992
3030
|
}
|
|
2993
|
-
]
|
|
3031
|
+
]
|
package/package.json
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@massif/lancer-data",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Data for the LANCER TTRPG",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"build": "node ./scripts/build.js",
|
|
8
|
-
"test": "node ./scripts/test.js"
|
|
9
|
-
},
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "https://github.com/massif-press/lancer-data.git"
|
|
13
|
-
},
|
|
14
|
-
"directories": {
|
|
15
|
-
"lib": "lib"
|
|
16
|
-
},
|
|
17
|
-
"author": "Massif Press",
|
|
18
|
-
"license": "GPL-3.0-or-later",
|
|
19
|
-
"devDependencies": {
|
|
20
|
-
"zip-lib": "^0.7.3"
|
|
21
|
-
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
"lancer",
|
|
24
|
-
"compcon",
|
|
25
|
-
"comp/con",
|
|
26
|
-
"lancerrpg",
|
|
27
|
-
"massif"
|
|
28
|
-
]
|
|
29
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@massif/lancer-data",
|
|
3
|
+
"version": "4.0.0-beta.2",
|
|
4
|
+
"description": "Data for the LANCER TTRPG",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "node ./scripts/build.js",
|
|
8
|
+
"test": "node ./scripts/test.js"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/massif-press/lancer-data.git"
|
|
13
|
+
},
|
|
14
|
+
"directories": {
|
|
15
|
+
"lib": "lib"
|
|
16
|
+
},
|
|
17
|
+
"author": "Massif Press",
|
|
18
|
+
"license": "GPL-3.0-or-later",
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"zip-lib": "^0.7.3"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"lancer",
|
|
24
|
+
"compcon",
|
|
25
|
+
"comp/con",
|
|
26
|
+
"lancerrpg",
|
|
27
|
+
"massif"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -1,134 +1,134 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
|
|
3
|
-
const weapons = require('../lib/weapons.json');
|
|
4
|
-
const systems = require('../lib/systems.json');
|
|
5
|
-
const mods = require('../lib/mods.json');
|
|
6
|
-
const frames = require('../lib/frames.json');
|
|
7
|
-
|
|
8
|
-
// const items = [weapons, systems, mods, frames]
|
|
9
|
-
const items = [weapons];
|
|
10
|
-
|
|
11
|
-
function row(x) {
|
|
12
|
-
if (x.data_type === 'weapon') return weaponRow(x);
|
|
13
|
-
return `${x.source},${x.name},0,0,0,0,0,0\n`;
|
|
14
|
-
// return `${x.data_type},${x.id},${x.source},${x.name},0,0,0,0,0,0\n`
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function weaponRow(x) {
|
|
18
|
-
// return `${x.data_type},${x.id},${x.source},${x.name},0,${rangedAp(x)},0,0,0,0\n`
|
|
19
|
-
return `${x.source},${x.name},${closeAp(x)},${rangedAp(x)},0,0,0,0\n`;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function getDamage(d, tags) {
|
|
23
|
-
let dscore = 0;
|
|
24
|
-
let guaranteed = 0;
|
|
25
|
-
let possible = 0;
|
|
26
|
-
if (typeof d.val === 'string') {
|
|
27
|
-
const dmgArr = d.val.split(/d|\+/g);
|
|
28
|
-
if (dmgArr.length === 1) guaranteed = parseInt(dmgArr[0]); // straight value, no dice
|
|
29
|
-
else {
|
|
30
|
-
if (dmgArr.length === 3) guaranteed = parseInt(dmgArr[2]); // bonus val
|
|
31
|
-
// handle dice
|
|
32
|
-
guaranteed += parseInt(dmgArr[0]); // min number we can get on the dice
|
|
33
|
-
possible = parseInt(dmgArr[0]) * parseInt(dmgArr[1]) - parseInt(dmgArr[0]);
|
|
34
|
-
}
|
|
35
|
-
// guaranteed = 1pt, possible = 0.5
|
|
36
|
-
dscore += guaranteed * (possible / 2);
|
|
37
|
-
} else {
|
|
38
|
-
guaranteed = d.val;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (tags.find((x) => x.id === 'tg_accurate')) dscore += possible * 0.25;
|
|
42
|
-
if (tags.find((x) => x.id === 'tg_inaccurate')) dscore -= possible * 0.25;
|
|
43
|
-
if (tags.find((x) => x.id === 'tg_reliable'))
|
|
44
|
-
dscore += tags.find((x) => x.id === 'tg_reliable').val * 3;
|
|
45
|
-
|
|
46
|
-
return dscore;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function closeAp(x) {
|
|
50
|
-
let score = 0;
|
|
51
|
-
const tags = x.tags || [];
|
|
52
|
-
if (x.type.toLowerCase() !== 'melee' || !x.damage || !x.damage.length) return score.toString();
|
|
53
|
-
|
|
54
|
-
x.damage.forEach((d) => {
|
|
55
|
-
score += getDamage(d, tags);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const threat = x.range.find((y) => y.type.toLowerCase() === 'threat');
|
|
59
|
-
// console.log(threat)
|
|
60
|
-
if (threat) score *= (threat.val + 1) / 2;
|
|
61
|
-
|
|
62
|
-
if (tags.find((x) => x.id === 'tg_ap')) score = score * 1.35;
|
|
63
|
-
if (tags.find((x) => x.id === 'tg_arcing')) score = score * 1.15;
|
|
64
|
-
if (tags.find((x) => x.id === 'tg_smart')) score = score * 1.15;
|
|
65
|
-
if (tags.find((x) => x.id === 'tg_overkill')) score = score * 1.15;
|
|
66
|
-
if (tags.find((x) => x.id === 'tg_loading')) score = score * 0.85;
|
|
67
|
-
|
|
68
|
-
return Math.ceil(score).toString();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function rangedAp(x) {
|
|
72
|
-
let score = 0;
|
|
73
|
-
const tags = x.tags || [];
|
|
74
|
-
if (
|
|
75
|
-
x.type.toLowerCase() === 'melee' ||
|
|
76
|
-
!x.range ||
|
|
77
|
-
!x.range.length ||
|
|
78
|
-
!x.damage ||
|
|
79
|
-
!x.damage.length
|
|
80
|
-
)
|
|
81
|
-
return score.toString();
|
|
82
|
-
x.damage.forEach((d) => {
|
|
83
|
-
score += getDamage(d, tags);
|
|
84
|
-
});
|
|
85
|
-
//collect range pts
|
|
86
|
-
x.range.forEach((r) => {
|
|
87
|
-
let rscore = 0;
|
|
88
|
-
if (typeof r.val === 'string') return 'XXXX';
|
|
89
|
-
if (r.type.toLowerCase() === 'range') {
|
|
90
|
-
if (r.val <= 10) score += r.val / 2;
|
|
91
|
-
else {
|
|
92
|
-
rscore += 5 + (r.val - 10);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (r.type.toLowerCase() === 'blast') {
|
|
96
|
-
rscore += Math.pow(r.val * 3, 2) / 2;
|
|
97
|
-
}
|
|
98
|
-
if (r.type.toLowerCase() === 'burst') {
|
|
99
|
-
rscore += Math.pow(r.val * 3, 2) / 3;
|
|
100
|
-
}
|
|
101
|
-
if (r.type.toLowerCase() === 'cone') {
|
|
102
|
-
rscore += Math.pow(r.val, 2) / 2;
|
|
103
|
-
}
|
|
104
|
-
if (r.type.toLowerCase() === 'line') {
|
|
105
|
-
rscore += r.val * 2;
|
|
106
|
-
}
|
|
107
|
-
if (r.type.toLowerCase() === 'thrown') {
|
|
108
|
-
rscore = score / 3;
|
|
109
|
-
}
|
|
110
|
-
score += rscore;
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
if (tags.find((x) => x.id === 'tg_ap')) score = score * 1.35;
|
|
114
|
-
if (tags.find((x) => x.id === 'tg_arcing')) score = score * 1.15;
|
|
115
|
-
if (tags.find((x) => x.id === 'tg_smart')) score = score * 1.15;
|
|
116
|
-
if (tags.find((x) => x.id === 'tg_overkill')) score = score * 1.15;
|
|
117
|
-
if (tags.find((x) => x.id === 'tg_loading')) score = score * 0.85;
|
|
118
|
-
|
|
119
|
-
return Math.ceil(score).toString();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// let output = 'TYPE,ID,SOURCE,NAME,CQB,RANGED,SURVIVABILITY,MANEUVERABILITY,SUPPORT,CONTROL\n'
|
|
123
|
-
let output = 'SOURCE,NAME,MELEE,RANGED,SURVIVABILITY,MANEUVERABILITY,SUPPORT,CONTROL\n';
|
|
124
|
-
|
|
125
|
-
items.forEach((e) => {
|
|
126
|
-
e.forEach((x) => {
|
|
127
|
-
output += row(x);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
fs.writeFile('./util/output/equipment.csv', output, function (err) {
|
|
132
|
-
if (err) return console.log(err);
|
|
133
|
-
console.log('Export Complete');
|
|
134
|
-
});
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
|
|
3
|
+
const weapons = require('../lib/weapons.json');
|
|
4
|
+
const systems = require('../lib/systems.json');
|
|
5
|
+
const mods = require('../lib/mods.json');
|
|
6
|
+
const frames = require('../lib/frames.json');
|
|
7
|
+
|
|
8
|
+
// const items = [weapons, systems, mods, frames]
|
|
9
|
+
const items = [weapons];
|
|
10
|
+
|
|
11
|
+
function row(x) {
|
|
12
|
+
if (x.data_type === 'weapon') return weaponRow(x);
|
|
13
|
+
return `${x.source},${x.name},0,0,0,0,0,0\n`;
|
|
14
|
+
// return `${x.data_type},${x.id},${x.source},${x.name},0,0,0,0,0,0\n`
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function weaponRow(x) {
|
|
18
|
+
// return `${x.data_type},${x.id},${x.source},${x.name},0,${rangedAp(x)},0,0,0,0\n`
|
|
19
|
+
return `${x.source},${x.name},${closeAp(x)},${rangedAp(x)},0,0,0,0\n`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getDamage(d, tags) {
|
|
23
|
+
let dscore = 0;
|
|
24
|
+
let guaranteed = 0;
|
|
25
|
+
let possible = 0;
|
|
26
|
+
if (typeof d.val === 'string') {
|
|
27
|
+
const dmgArr = d.val.split(/d|\+/g);
|
|
28
|
+
if (dmgArr.length === 1) guaranteed = parseInt(dmgArr[0]); // straight value, no dice
|
|
29
|
+
else {
|
|
30
|
+
if (dmgArr.length === 3) guaranteed = parseInt(dmgArr[2]); // bonus val
|
|
31
|
+
// handle dice
|
|
32
|
+
guaranteed += parseInt(dmgArr[0]); // min number we can get on the dice
|
|
33
|
+
possible = parseInt(dmgArr[0]) * parseInt(dmgArr[1]) - parseInt(dmgArr[0]);
|
|
34
|
+
}
|
|
35
|
+
// guaranteed = 1pt, possible = 0.5
|
|
36
|
+
dscore += guaranteed * (possible / 2);
|
|
37
|
+
} else {
|
|
38
|
+
guaranteed = d.val;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (tags.find((x) => x.id === 'tg_accurate')) dscore += possible * 0.25;
|
|
42
|
+
if (tags.find((x) => x.id === 'tg_inaccurate')) dscore -= possible * 0.25;
|
|
43
|
+
if (tags.find((x) => x.id === 'tg_reliable'))
|
|
44
|
+
dscore += tags.find((x) => x.id === 'tg_reliable').val * 3;
|
|
45
|
+
|
|
46
|
+
return dscore;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function closeAp(x) {
|
|
50
|
+
let score = 0;
|
|
51
|
+
const tags = x.tags || [];
|
|
52
|
+
if (x.type.toLowerCase() !== 'melee' || !x.damage || !x.damage.length) return score.toString();
|
|
53
|
+
|
|
54
|
+
x.damage.forEach((d) => {
|
|
55
|
+
score += getDamage(d, tags);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const threat = x.range.find((y) => y.type.toLowerCase() === 'threat');
|
|
59
|
+
// console.log(threat)
|
|
60
|
+
if (threat) score *= (threat.val + 1) / 2;
|
|
61
|
+
|
|
62
|
+
if (tags.find((x) => x.id === 'tg_ap')) score = score * 1.35;
|
|
63
|
+
if (tags.find((x) => x.id === 'tg_arcing')) score = score * 1.15;
|
|
64
|
+
if (tags.find((x) => x.id === 'tg_smart')) score = score * 1.15;
|
|
65
|
+
if (tags.find((x) => x.id === 'tg_overkill')) score = score * 1.15;
|
|
66
|
+
if (tags.find((x) => x.id === 'tg_loading')) score = score * 0.85;
|
|
67
|
+
|
|
68
|
+
return Math.ceil(score).toString();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function rangedAp(x) {
|
|
72
|
+
let score = 0;
|
|
73
|
+
const tags = x.tags || [];
|
|
74
|
+
if (
|
|
75
|
+
x.type.toLowerCase() === 'melee' ||
|
|
76
|
+
!x.range ||
|
|
77
|
+
!x.range.length ||
|
|
78
|
+
!x.damage ||
|
|
79
|
+
!x.damage.length
|
|
80
|
+
)
|
|
81
|
+
return score.toString();
|
|
82
|
+
x.damage.forEach((d) => {
|
|
83
|
+
score += getDamage(d, tags);
|
|
84
|
+
});
|
|
85
|
+
//collect range pts
|
|
86
|
+
x.range.forEach((r) => {
|
|
87
|
+
let rscore = 0;
|
|
88
|
+
if (typeof r.val === 'string') return 'XXXX';
|
|
89
|
+
if (r.type.toLowerCase() === 'range') {
|
|
90
|
+
if (r.val <= 10) score += r.val / 2;
|
|
91
|
+
else {
|
|
92
|
+
rscore += 5 + (r.val - 10);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (r.type.toLowerCase() === 'blast') {
|
|
96
|
+
rscore += Math.pow(r.val * 3, 2) / 2;
|
|
97
|
+
}
|
|
98
|
+
if (r.type.toLowerCase() === 'burst') {
|
|
99
|
+
rscore += Math.pow(r.val * 3, 2) / 3;
|
|
100
|
+
}
|
|
101
|
+
if (r.type.toLowerCase() === 'cone') {
|
|
102
|
+
rscore += Math.pow(r.val, 2) / 2;
|
|
103
|
+
}
|
|
104
|
+
if (r.type.toLowerCase() === 'line') {
|
|
105
|
+
rscore += r.val * 2;
|
|
106
|
+
}
|
|
107
|
+
if (r.type.toLowerCase() === 'thrown') {
|
|
108
|
+
rscore = score / 3;
|
|
109
|
+
}
|
|
110
|
+
score += rscore;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
if (tags.find((x) => x.id === 'tg_ap')) score = score * 1.35;
|
|
114
|
+
if (tags.find((x) => x.id === 'tg_arcing')) score = score * 1.15;
|
|
115
|
+
if (tags.find((x) => x.id === 'tg_smart')) score = score * 1.15;
|
|
116
|
+
if (tags.find((x) => x.id === 'tg_overkill')) score = score * 1.15;
|
|
117
|
+
if (tags.find((x) => x.id === 'tg_loading')) score = score * 0.85;
|
|
118
|
+
|
|
119
|
+
return Math.ceil(score).toString();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// let output = 'TYPE,ID,SOURCE,NAME,CQB,RANGED,SURVIVABILITY,MANEUVERABILITY,SUPPORT,CONTROL\n'
|
|
123
|
+
let output = 'SOURCE,NAME,MELEE,RANGED,SURVIVABILITY,MANEUVERABILITY,SUPPORT,CONTROL\n';
|
|
124
|
+
|
|
125
|
+
items.forEach((e) => {
|
|
126
|
+
e.forEach((x) => {
|
|
127
|
+
output += row(x);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
fs.writeFile('./util/output/equipment.csv', output, function (err) {
|
|
132
|
+
if (err) return console.log(err);
|
|
133
|
+
console.log('Export Complete');
|
|
134
|
+
});
|
package/scripts/build.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
const zl = require('zip-lib');
|
|
2
|
-
|
|
3
|
-
const info = require('../package.json');
|
|
4
|
-
|
|
5
|
-
const filepath = './' + info.name + '-' + info.version + '.lcp';
|
|
6
|
-
|
|
7
|
-
zl.archiveFolder('./lib', filepath).then(
|
|
8
|
-
function () {
|
|
9
|
-
console.log('done');
|
|
10
|
-
},
|
|
11
|
-
function (err) {
|
|
12
|
-
console.log(err);
|
|
13
|
-
}
|
|
14
|
-
);
|
|
1
|
+
const zl = require('zip-lib');
|
|
2
|
+
|
|
3
|
+
const info = require('../package.json');
|
|
4
|
+
|
|
5
|
+
const filepath = './' + info.name + '-' + info.version + '.lcp';
|
|
6
|
+
|
|
7
|
+
zl.archiveFolder('./lib', filepath).then(
|
|
8
|
+
function () {
|
|
9
|
+
console.log('done');
|
|
10
|
+
},
|
|
11
|
+
function (err) {
|
|
12
|
+
console.log(err);
|
|
13
|
+
}
|
|
14
|
+
);
|