Compare commits
10 commits
e1f636d40e
...
b48e9e6ad1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b48e9e6ad1 | ||
|
|
ba85df9e54 | ||
|
|
f8a0930645 | ||
|
|
809e9b5b27 | ||
|
|
e981ced75d | ||
|
|
3ca785a753 | ||
|
|
259203c16b | ||
|
|
8147733336 | ||
|
|
3c27d645dd | ||
|
|
9b8d23d7b2 |
31 changed files with 602294 additions and 587358 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
71202
aeldari/Aeldari.manifest
71202
aeldari/Aeldari.manifest
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
26552
necrons/Necrons.manifest
26552
necrons/Necrons.manifest
File diff suppressed because it is too large
Load diff
|
|
@ -1,11 +1,12 @@
|
|||
{
|
||||
"name": "Officio Assassinorum",
|
||||
"revision": "0.0.8",
|
||||
"game": "Warhammer 40,000",
|
||||
"genre": "sci-fi",
|
||||
"publisher": "Games Workshop",
|
||||
"url": "https://warhammer40000.com/",
|
||||
"notes": "This manifest is provided for the purposes of testing the features of *Rosterizer* and is not intended for distribution.",
|
||||
"revision": "0.0.5",
|
||||
"notes": "0.0.8: dynamic damage min/max variable type\n\n0.0.7: single-model units no longer have any \"model\" asssets\n\n0.0.6: \"source\" keyword category\n\n0.0.5: add relics\n\nThis manifest is provided for the purposes of testing the features of *Rosterizer* and is not intended for distribution.\n\nThe data included herein was programatically compiled from freely-available sources on the internet and likely contains some errors. Use with caution.",
|
||||
"wip": true,
|
||||
"dependencies": [
|
||||
{
|
||||
"slug": "123456",
|
||||
|
|
@ -16,225 +17,373 @@
|
|||
"manifest": {
|
||||
"assetTaxonomy": {},
|
||||
"assetCatalog": {
|
||||
"Roster§Army": {},
|
||||
"Model§Vindicare Assassin": {
|
||||
"stats": {
|
||||
"Points": {
|
||||
"value": 100
|
||||
"Ability§Abomination": {
|
||||
"text": "This model can never be targeted or affected by psychic powers in any way. [PSYKER](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#PSYCHIC-PHASE) units that are within 18″ of any **CULEXUS ASSASSINS** must subtract 2 from [Psychic tests](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Psychic-Tests) and [Deny the Witch tests](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Deny-the-Witch) they take."
|
||||
},
|
||||
"M": {
|
||||
"value": "7"
|
||||
"Ability§Agent of the Imperium": {
|
||||
"text": "If your army is [Battle-forged](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#BATTLE-FORGED-ARMIES), you can include 1 **AGENT OF** THE** IMPERIUM** unit in each IMPERIUM (excluding FALLEN**) [Patrol](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Patrol-Detachment), [Battalion](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Battalion-Detachment) and [Brigade Detachment](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Brigade-Detachment) in your army without those units taking up slots in those Detachments. The inclusion of an AGENT OF THE IMPERIUM unit does not prevent other units from their Detachment from benefiting from Detachment abilities (e.g. Chapter Tactics**, Defenders of Humanity** etc.), and it does not prevent other units from your army benefiting from abilities that require every model in your army to have that ability (e.g. Combat Doctrines**). An AGENT OF THE IMPERIUM unit included in a Patrol, Battalion or Brigade Detachment in this manner is ignored for any rules that state all units from that Detachment must have at least one Faction keyword in common (e.g. in a [matched play](https://wahapedia.ru/wh40k9ed/the-rules/matched-play) game) and when determining your Army Faction."
|
||||
},
|
||||
"WS": {
|
||||
"value": 2
|
||||
},
|
||||
"BS": {
|
||||
"value": 2
|
||||
},
|
||||
"S": {
|
||||
"value": 4
|
||||
},
|
||||
"T": {
|
||||
"value": 4
|
||||
},
|
||||
"W": {
|
||||
"value": 5
|
||||
},
|
||||
"A": {
|
||||
"value": "5"
|
||||
},
|
||||
"Ld": {
|
||||
"value": 9
|
||||
},
|
||||
"Sv": {
|
||||
"value": 6
|
||||
},
|
||||
"Base": {
|
||||
"value": "32mm"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Model§Callidus Assassin": {
|
||||
"stats": {
|
||||
"Points": {
|
||||
"value": 100
|
||||
},
|
||||
"M": {
|
||||
"value": "7"
|
||||
},
|
||||
"WS": {
|
||||
"value": 2
|
||||
},
|
||||
"BS": {
|
||||
"value": 2
|
||||
},
|
||||
"S": {
|
||||
"value": 4
|
||||
},
|
||||
"T": {
|
||||
"value": 4
|
||||
},
|
||||
"W": {
|
||||
"value": 5
|
||||
},
|
||||
"A": {
|
||||
"value": "5"
|
||||
},
|
||||
"Ld": {
|
||||
"value": 9
|
||||
},
|
||||
"Sv": {
|
||||
"value": 6
|
||||
},
|
||||
"Base": {
|
||||
"value": "32mm"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Model§Eversor Assassin": {
|
||||
"stats": {
|
||||
"Points": {
|
||||
"value": 100
|
||||
},
|
||||
"M": {
|
||||
"value": "7"
|
||||
},
|
||||
"WS": {
|
||||
"value": 2
|
||||
},
|
||||
"BS": {
|
||||
"value": 2
|
||||
},
|
||||
"S": {
|
||||
"value": 4
|
||||
},
|
||||
"T": {
|
||||
"value": 4
|
||||
},
|
||||
"W": {
|
||||
"value": 6
|
||||
},
|
||||
"A": {
|
||||
"value": "6"
|
||||
},
|
||||
"Ld": {
|
||||
"value": 9
|
||||
},
|
||||
"Sv": {
|
||||
"value": 6
|
||||
},
|
||||
"Base": {
|
||||
"value": "32mm"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Model§Culexus Assassin": {
|
||||
"stats": {
|
||||
"Points": {
|
||||
"value": 100
|
||||
},
|
||||
"M": {
|
||||
"value": "7"
|
||||
},
|
||||
"WS": {
|
||||
"value": 2
|
||||
},
|
||||
"BS": {
|
||||
"value": 2
|
||||
},
|
||||
"S": {
|
||||
"value": 4
|
||||
},
|
||||
"T": {
|
||||
"value": 4
|
||||
},
|
||||
"W": {
|
||||
"value": 5
|
||||
},
|
||||
"A": {
|
||||
"value": "4"
|
||||
},
|
||||
"Ld": {
|
||||
"value": 9
|
||||
},
|
||||
"Sv": {
|
||||
"value": 6
|
||||
},
|
||||
"Base": {
|
||||
"value": "32mm"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Ability§Independent Operative": {
|
||||
"text": "This model can never have a [Warlord Trait](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Warlord-Traits). During deployment, you can set this model up in concealment instead of placing it on the battlefield. At the end of any of your [Movement phases](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#MOVEMENT-PHASE), this model can reveal its position – set it up anywhere on the battlefield that is more than 9\" away from any enemy models."
|
||||
},
|
||||
"Ability§Lightning Reflexes": {
|
||||
"text": "This model has a 4+ [invulnerable save](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Invulnerable-Saves)."
|
||||
"Ability§Bio-meltdown": {
|
||||
"text": "If this model is destroyed, before removing the model from the battlefield, roll one D6 for each enemy unit that is within 6″ of this model. On a 4+ that enemy unit suffers D3 [mortal wounds](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Mortal-Wounds)."
|
||||
},
|
||||
"Ability§Deadshot": {
|
||||
"text": "Each time you select a target for a weapon this model is making an attack with, you can ignore the [Look Out, Sir](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Look-out-Sir) rule. In addition, on an unmodified [wound roll](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#2.-Wound-Roll) of 6 for an attack made with an exitus pistol or exitus rifle, change the Damage characteristic of that weapon to D6 for that attack."
|
||||
},
|
||||
"Ability§Spymask": {
|
||||
"text": "When resolving an attack made with a ranged weapon by this model, the target does not receive the [benefit of cover](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Terrain-and-Cover) to its [saving throw](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#4.-Saving-Throw)."
|
||||
},
|
||||
"Ability§Stealth Suit": {
|
||||
"text": "When resolving an attack made with a ranged weapon against this model, subtract 1 from the [hit roll](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#1.-Hit-Roll). If this model is on or in a [terrain](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Terrain-Features-1) feature, subtract 2 from the hit roll instead."
|
||||
},
|
||||
"Ability§Polymorphine": {
|
||||
"text": "During deployment, you can set up this model in disguise instead of setting it up on the battlefield. At the end of any of your [Movement phases](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#MOVEMENT-PHASE), this model can revert to its true form – set it up anywhere on the battlefield that is more than D6+3\" away from any enemy models. For example, if you roll a 4, the model can be set up anywhere that is more than 7\" away from any enemy model."
|
||||
},
|
||||
"Ability§Hit and Run": {
|
||||
"text": "This model can shoot and charge in a turn in which it [Fell Back](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Fall-Back)."
|
||||
},
|
||||
"Ability§Reign of Confusion": {
|
||||
"text": "If you have any models with this ability in your army, then in the first battle round, roll one D6 each time your opponent spends [Command Points](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Command-Points) (CPs) to use a Stratagem. On a 4+ your opponent must spend one additional CP to use that Stratagem, or else it has no effect (any CPs spent so far are lost). This ability cannot affect Stratagems used before the battle."
|
||||
},
|
||||
"Ability§Bio-meltdown": {
|
||||
"text": "If this model is destroyed, before removing the model from the battlefield, roll one D6 for each enemy unit that is within 6\" of this model. On a 4+ that enemy unit suffers D3 [mortal wounds](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Mortal-Wounds)."
|
||||
},
|
||||
"Ability§Frenzon": {
|
||||
"text": "When making a [charge roll](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Charging-with-a-Unit) for this model, roll 3D6 rather than 2D6. In addition, add 2 to this model’s Attacks characteristic if it charged or made a [Heroic Intervention](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Performing-a-Heroic-Intervention) this turn."
|
||||
},
|
||||
"Ability§Sentinel Array": {
|
||||
"text": "Each time an enemy unit [Falls Back](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Fall-Back) whilst within 1\" of this model, before moving any models, this model can shoot as if it were its [Shooting phase](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#SHOOTING-PHASE). These attacks must target the unit that is Falling Back."
|
||||
},
|
||||
"Ability§Abomination": {
|
||||
"text": "This model can never be targeted or affected by psychic powers in any way. [PSYKER](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#PSYCHIC-PHASE) units that are within 18\" of any **CULEXUS ASSASSINS** must subtract 2 from [Psychic tests](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Psychic-Tests) and [Deny the Witch tests](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Deny-the-Witch) they take."
|
||||
},
|
||||
"Ability§Life Drain": {
|
||||
"text": "When resolving an attack made with a melee weapon by this model, a [saving throw](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#4.-Saving-Throw) cannot be made unless it is an [invulnerable saving throw](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Invulnerable-Saves)."
|
||||
},
|
||||
"Ability§Etherium": {
|
||||
"text": "When resolving an attack that targets this model, the attacking model is treated as having a Weapon Skill and Ballistic Skill characteristic of 6+."
|
||||
},
|
||||
"Ability§Psychic Assassin": {
|
||||
"text": "Attacks made by this model can target a [PSYKER](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#PSYCHIC-PHASE) [CHARACTER](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Characters) even if it is not the closest enemy unit. In addition, this model can shoot with its psyk-out grenades in the same phase that it shoots with its animus speculum."
|
||||
},
|
||||
"Ability§Execution Force": {
|
||||
"text": "If your [Warlord](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#The-Warlord) has the IMPERIUM keyword (excluding **FALLEN**), you can include this unit in your army as part of a [Vanguard Detachment](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Vanguard-Detachment) even if that Detachment contains no HQ units. If you do so, that Detachment’s [Command Benefits](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Command-Benefits) are changed to ‘None’ and its [Restrictions](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Restrictions) are changed to ‘This Detachment cannot include the same datasheet more than once.’"
|
||||
},
|
||||
"Ability§Faultless Aim": {
|
||||
"text": "Attacks made with ranged weapons by this model always hit on a 2+ if this model did not move this turn ([hit rolls](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#1.-Hit-Roll) of 6 are still required when firing [Overwatch](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Overwatch))."
|
||||
},
|
||||
"Ability§Frenzon": {
|
||||
"text": "When making a [charge roll](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Charging-with-a-Unit) for this model, roll 3D6 rather than 2D6. In addition, add 2 to this model’s Attacks characteristic if it charged or made a [Heroic Intervention](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Performing-a-Heroic-Intervention) this turn."
|
||||
},
|
||||
"Ability§Head Shot": {
|
||||
"text": "If, after resolving an attack with an exitus pistol or exitus rifle by this model, a model in an enemy unit lost any wounds as a result of that attack but was not destroyed, roll one D6; on a 3+ that model suffers 1 [mortal wound](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Mortal-Wounds) and, if that model is not destroyed, you can roll one more D6. This time, that model suffers 1 mortal wound on a 4+. Keep rolling one D6, increasing the result required to cause a mortal wound by 1 each time, until the model in the enemy unit being rolled for is destroyed or the roll is failed."
|
||||
},
|
||||
"Ability§Hit and Run": {
|
||||
"text": "This model can shoot and charge in a turn in which it [Fell Back](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Fall-Back)."
|
||||
},
|
||||
"Ability§Independent Operative": {
|
||||
"text": "This model can never have a [Warlord Trait](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Warlord-Traits). During deployment, you can set this model up in concealment instead of placing it on the battlefield. At the end of any of your [Movement phases](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#MOVEMENT-PHASE), this model can reveal its position – set it up anywhere on the battlefield that is more than 9″ away from any enemy models."
|
||||
},
|
||||
"Ability§Killing Rampage": {
|
||||
"text": "Each time a model in an enemy unit is destroyed as the result of an attack made with a melee weapon by this model, you can immediately make one additional attack with a melee weapon this model is equipped with against the same unit. These additional attacks cannot themselves generate further attacks. In addition, this model can [consolidate](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Consolidate) up to 6\" instead of up to 3\"."
|
||||
"text": "Each time a model in an enemy unit is destroyed as the result of an attack made with a melee weapon by this model, you can immediately make one additional attack with a melee weapon this model is equipped with against the same unit. These additional attacks cannot themselves generate further attacks. In addition, this model can [consolidate](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Consolidate) up to 6″ instead of up to 3\"."
|
||||
},
|
||||
"Ability§Agent of the Imperium": {
|
||||
"text": "If your army is [Battle-forged](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#BATTLE-FORGED-ARMIES), you can include 1 **AGENT OF** THE** IMPERIUM** unit in each IMPERIUM (excluding FALLEN**) [Patrol](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Patrol-Detachment), [Battalion](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Battalion-Detachment) and [Brigade Detachment](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Brigade-Detachment) in your army without those units taking up slots in those Detachments. The inclusion of an AGENT OF THE IMPERIUM unit does not prevent other units from their Detachment from benefiting from Detachment abilities (e.g. Chapter Tactics**, Defenders of Humanity** etc.), and it does not prevent other units from your army benefiting from abilities that require every model in your army to have that ability (e.g. Combat Doctrines**). An AGENT OF THE IMPERIUM unit included in a Patrol, Battalion or Brigade Detachment in this manner is ignored for any rules that state all units from that Detachment must have at least one Faction keyword in common (e.g. in a [matched play](https://wahapedia.ru/wh40k9ed/the-rules/matched-play) game) and when determining your Army Faction."
|
||||
"Ability§Life Drain": {
|
||||
"text": "When resolving an attack made with a melee weapon by this model, a [saving throw](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#4.-Saving-Throw) cannot be made unless it is an [invulnerable saving throw](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Invulnerable-Saves)."
|
||||
},
|
||||
"Ability§Lightning Reflexes": {
|
||||
"text": "This model has a 4+ [invulnerable save](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Invulnerable-Saves)."
|
||||
},
|
||||
"Ability§Polymorphine": {
|
||||
"text": "During deployment, you can set up this model in disguise instead of setting it up on the battlefield. At the end of any of your [Movement phases](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#MOVEMENT-PHASE), this model can revert to its true form – set it up anywhere on the battlefield that is more than D6+3\" away from any enemy models. For example, if you roll a 4, the model can be set up anywhere that is more than 7″ away from any enemy model."
|
||||
},
|
||||
"Ability§Psychic Assassin": {
|
||||
"text": "Attacks made by this model can target a [PSYKER](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#PSYCHIC-PHASE) [CHARACTER](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Characters) even if it is not the closest enemy unit. In addition, this model can shoot with its psyk-out grenades in the same phase that it shoots with its animus speculum."
|
||||
},
|
||||
"Ability§Reign of Confusion": {
|
||||
"text": "If you have any models with this ability in your army, then in the first battle round, roll one D6 each time your opponent spends [Command Points](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Command-Points) (CPs) to use a Stratagem. On a 4+ your opponent must spend one additional CP to use that Stratagem, or else it has no effect (any CPs spent so far are lost). This ability cannot affect Stratagems used before the battle."
|
||||
},
|
||||
"Ability§Sentinel Array": {
|
||||
"text": "Each time an enemy unit [Falls Back](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Fall-Back) whilst within 1″ of this model, before moving any models, this model can shoot as if it were its [Shooting phase](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#SHOOTING-PHASE). These attacks must target the unit that is Falling Back."
|
||||
},
|
||||
"Ability§Spymask": {
|
||||
"text": "When resolving an attack made with a ranged weapon by this model, the target does not receive the [benefit of cover](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Terrain-and-Cover) to its [saving throw](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#4.-Saving-Throw)."
|
||||
},
|
||||
"Ability§Stealth Suit": {
|
||||
"text": "When resolving an attack made with a ranged weapon against this model, subtract 1 from the [hit roll](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#1.-Hit-Roll). If this model is on or in a [terrain](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Terrain-Features-1) feature, subtract 2 from the hit roll instead."
|
||||
},
|
||||
"Elites§Callidus Assassin": {
|
||||
"stats": {
|
||||
"Power Level": {
|
||||
"value": 5
|
||||
},
|
||||
"Points": {
|
||||
"value": 100
|
||||
},
|
||||
"M": {
|
||||
"value": 7
|
||||
},
|
||||
"WS": {
|
||||
"value": 2
|
||||
},
|
||||
"BS": {
|
||||
"value": 2
|
||||
},
|
||||
"S": {
|
||||
"value": 4
|
||||
},
|
||||
"T": {
|
||||
"value": 4
|
||||
},
|
||||
"W": {
|
||||
"value": 5
|
||||
},
|
||||
"A": {
|
||||
"value": 5
|
||||
},
|
||||
"Ld": {
|
||||
"value": 9
|
||||
},
|
||||
"Sv": {
|
||||
"value": 6
|
||||
},
|
||||
"Base": {
|
||||
"value": "32mm"
|
||||
}
|
||||
},
|
||||
"keywords": {
|
||||
"Source": [
|
||||
"Expansion—Psychic Awakening: War of the Spider—Indomitus 1.4"
|
||||
],
|
||||
"Edition": [
|
||||
"8th"
|
||||
],
|
||||
"Keywords": [
|
||||
"Agent of the Imperium",
|
||||
"Callidus Assassin",
|
||||
"Character",
|
||||
"Infantry"
|
||||
],
|
||||
"Faction": [
|
||||
"Imperium",
|
||||
"Officio Assassinorum"
|
||||
]
|
||||
},
|
||||
"assets": {
|
||||
"traits": [
|
||||
"Ability§Agent of the Imperium",
|
||||
"Ability§Execution Force",
|
||||
"Ability§Independent Operative",
|
||||
"Ability§Lightning Reflexes",
|
||||
"Ability§Polymorphine",
|
||||
"Ability§Hit and Run",
|
||||
"Ability§Reign of Confusion"
|
||||
]
|
||||
},
|
||||
"text": "A Callidus Assassin is a single model equipped with: neural shredder; phase sword; poison blades.\n\n\n\nnull",
|
||||
"meta": {
|
||||
"Publication": "[Psychic Awakening: War of the Spider (Expansion) 8th ed. – Indomitus 1.4 @2022-02-04](https://www.warhammer-community.com/wp-content/uploads/2020/07/VXO1CdVZDRexbsb1.pdf)"
|
||||
}
|
||||
},
|
||||
"Elites§Culexus Assassin": {
|
||||
"stats": {
|
||||
"Power Level": {
|
||||
"value": 5
|
||||
},
|
||||
"Points": {
|
||||
"value": 100
|
||||
},
|
||||
"M": {
|
||||
"value": 7
|
||||
},
|
||||
"WS": {
|
||||
"value": 2
|
||||
},
|
||||
"BS": {
|
||||
"value": 2
|
||||
},
|
||||
"S": {
|
||||
"value": 4
|
||||
},
|
||||
"T": {
|
||||
"value": 4
|
||||
},
|
||||
"W": {
|
||||
"value": 5
|
||||
},
|
||||
"A": {
|
||||
"value": 4
|
||||
},
|
||||
"Ld": {
|
||||
"value": 9
|
||||
},
|
||||
"Sv": {
|
||||
"value": 6
|
||||
},
|
||||
"Base": {
|
||||
"value": "32mm"
|
||||
}
|
||||
},
|
||||
"keywords": {
|
||||
"Source": [
|
||||
"Expansion—Psychic Awakening: War of the Spider—Indomitus 1.4"
|
||||
],
|
||||
"Edition": [
|
||||
"8th"
|
||||
],
|
||||
"Keywords": [
|
||||
"Agent of the Imperium",
|
||||
"Character",
|
||||
"Culexus Assassin",
|
||||
"Infantry"
|
||||
],
|
||||
"Faction": [
|
||||
"Imperium",
|
||||
"Officio Assassinorum"
|
||||
]
|
||||
},
|
||||
"assets": {
|
||||
"traits": [
|
||||
"Ability§Agent of the Imperium",
|
||||
"Ability§Execution Force",
|
||||
"Ability§Independent Operative",
|
||||
"Ability§Lightning Reflexes",
|
||||
"Ability§Abomination",
|
||||
"Ability§Life Drain",
|
||||
"Ability§Etherium",
|
||||
"Ability§Psychic Assassin"
|
||||
]
|
||||
},
|
||||
"text": "A Culexus Assassin is a single model equipped with: animus speculum; psyk-out grenades.\n\n\n\nnull",
|
||||
"meta": {
|
||||
"Publication": "[Psychic Awakening: War of the Spider (Expansion) 8th ed. – Indomitus 1.4 @2022-02-04](https://www.warhammer-community.com/wp-content/uploads/2020/07/VXO1CdVZDRexbsb1.pdf)"
|
||||
}
|
||||
},
|
||||
"Elites§Eversor Assassin": {
|
||||
"stats": {
|
||||
"Power Level": {
|
||||
"value": 5
|
||||
},
|
||||
"Points": {
|
||||
"value": 100
|
||||
},
|
||||
"M": {
|
||||
"value": 7
|
||||
},
|
||||
"WS": {
|
||||
"value": 2
|
||||
},
|
||||
"BS": {
|
||||
"value": 2
|
||||
},
|
||||
"S": {
|
||||
"value": 4
|
||||
},
|
||||
"T": {
|
||||
"value": 4
|
||||
},
|
||||
"W": {
|
||||
"value": 6
|
||||
},
|
||||
"A": {
|
||||
"value": 6
|
||||
},
|
||||
"Ld": {
|
||||
"value": 9
|
||||
},
|
||||
"Sv": {
|
||||
"value": 6
|
||||
},
|
||||
"Base": {
|
||||
"value": "32mm"
|
||||
}
|
||||
},
|
||||
"keywords": {
|
||||
"Source": [
|
||||
"Expansion—Psychic Awakening: War of the Spider—Indomitus 1.4"
|
||||
],
|
||||
"Edition": [
|
||||
"8th"
|
||||
],
|
||||
"Keywords": [
|
||||
"Agent of the Imperium",
|
||||
"Character",
|
||||
"Eversor Assassin",
|
||||
"Infantry"
|
||||
],
|
||||
"Faction": [
|
||||
"Imperium",
|
||||
"Officio Assassinorum"
|
||||
]
|
||||
},
|
||||
"assets": {
|
||||
"traits": [
|
||||
"Ability§Agent of the Imperium",
|
||||
"Ability§Execution Force",
|
||||
"Ability§Independent Operative",
|
||||
"Ability§Lightning Reflexes",
|
||||
"Ability§Bio-meltdown",
|
||||
"Ability§Sentinel Array",
|
||||
"Ability§Frenzon",
|
||||
"Ability§Killing Rampage"
|
||||
]
|
||||
},
|
||||
"text": "An Eversor Assassin is a single model equipped with: executioner pistol; neuro-gauntlet; power sword; melta bombs.\n\n\n\nnull",
|
||||
"meta": {
|
||||
"Publication": "[Psychic Awakening: War of the Spider (Expansion) 8th ed. – Indomitus 1.4 @2022-02-04](https://www.warhammer-community.com/wp-content/uploads/2020/07/VXO1CdVZDRexbsb1.pdf)"
|
||||
}
|
||||
},
|
||||
"Elites§Vindicare Assassin": {
|
||||
"stats": {
|
||||
"Power Level": {
|
||||
"value": 5
|
||||
},
|
||||
"Points": {
|
||||
"value": 100
|
||||
},
|
||||
"M": {
|
||||
"value": 7
|
||||
},
|
||||
"WS": {
|
||||
"value": 2
|
||||
},
|
||||
"BS": {
|
||||
"value": 2
|
||||
},
|
||||
"S": {
|
||||
"value": 4
|
||||
},
|
||||
"T": {
|
||||
"value": 4
|
||||
},
|
||||
"W": {
|
||||
"value": 5
|
||||
},
|
||||
"A": {
|
||||
"value": 5
|
||||
},
|
||||
"Ld": {
|
||||
"value": 9
|
||||
},
|
||||
"Sv": {
|
||||
"value": 6
|
||||
},
|
||||
"Base": {
|
||||
"value": "32mm"
|
||||
}
|
||||
},
|
||||
"keywords": {
|
||||
"Source": [
|
||||
"Expansion—Psychic Awakening: War of the Spider—Indomitus 1.4"
|
||||
],
|
||||
"Edition": [
|
||||
"8th"
|
||||
],
|
||||
"Keywords": [
|
||||
"Agent of the Imperium",
|
||||
"Character",
|
||||
"Infantry",
|
||||
"Vindicare Assassin"
|
||||
],
|
||||
"Faction": [
|
||||
"Imperium",
|
||||
"Officio Assassinorum"
|
||||
]
|
||||
},
|
||||
"assets": {
|
||||
"traits": [
|
||||
"Ability§Agent of the Imperium",
|
||||
"Ability§Execution Force",
|
||||
"Ability§Independent Operative",
|
||||
"Ability§Lightning Reflexes",
|
||||
"Ability§Deadshot",
|
||||
"Ability§Faultless Aim",
|
||||
"Ability§Head Shot",
|
||||
"Ability§Spymask",
|
||||
"Ability§Stealth Suit"
|
||||
]
|
||||
},
|
||||
"text": "A Vindicare Assassin is a single model equipped with: exitus pistol; exitus rifle; blind grenades.\n\n\n\nnull",
|
||||
"meta": {
|
||||
"Publication": "[Psychic Awakening: War of the Spider (Expansion) 8th ed. – Indomitus 1.4 @2022-02-04](https://www.warhammer-community.com/wp-content/uploads/2020/07/VXO1CdVZDRexbsb1.pdf)"
|
||||
}
|
||||
},
|
||||
"Roster§Army": {},
|
||||
"Weapon§Animus speculum": {
|
||||
"stats": {
|
||||
"AP": {
|
||||
"value": "-4"
|
||||
"value": -4
|
||||
},
|
||||
"D": {
|
||||
"value": "1"
|
||||
"value": 1
|
||||
},
|
||||
"S": {
|
||||
"value": "5"
|
||||
"value": 5
|
||||
},
|
||||
"Type": {
|
||||
"value": "Assault D3"
|
||||
|
|
@ -243,7 +392,7 @@
|
|||
"value": "18″"
|
||||
}
|
||||
},
|
||||
"text": "Whilst there are any enemy [PSYKER](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#PSYCHIC-PHASE) units within 18\" of the bearer, change this weapon’s Type characteristic to [Assault D6](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#ASSAULT)."
|
||||
"text": "Whilst there are any enemy [PSYKER](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#PSYCHIC-PHASE) units within 18″ of the bearer, change this weapon’s Type characteristic to [Assault D6](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#ASSAULT)."
|
||||
},
|
||||
"Weapon§Blind grenade": {
|
||||
"stats": {
|
||||
|
|
@ -268,13 +417,13 @@
|
|||
"Weapon§Executioner pistol": {
|
||||
"stats": {
|
||||
"AP": {
|
||||
"value": "-1"
|
||||
"value": -1
|
||||
},
|
||||
"D": {
|
||||
"value": "1"
|
||||
"value": 1
|
||||
},
|
||||
"S": {
|
||||
"value": "4"
|
||||
"value": 4
|
||||
},
|
||||
"Type": {
|
||||
"value": "Pistol 4"
|
||||
|
|
@ -288,13 +437,13 @@
|
|||
"Weapon§Exitus pistol": {
|
||||
"stats": {
|
||||
"AP": {
|
||||
"value": "-3"
|
||||
"value": -3
|
||||
},
|
||||
"D": {
|
||||
"value": "D3"
|
||||
},
|
||||
"S": {
|
||||
"value": "4"
|
||||
"value": 4
|
||||
},
|
||||
"Type": {
|
||||
"value": "Pistol 1"
|
||||
|
|
@ -308,13 +457,13 @@
|
|||
"Weapon§Exitus rifle": {
|
||||
"stats": {
|
||||
"AP": {
|
||||
"value": "-3"
|
||||
"value": -3
|
||||
},
|
||||
"D": {
|
||||
"value": "D3"
|
||||
},
|
||||
"S": {
|
||||
"value": "5"
|
||||
"value": 5
|
||||
},
|
||||
"Type": {
|
||||
"value": "Heavy 1"
|
||||
|
|
@ -328,13 +477,13 @@
|
|||
"Weapon§Melta bombs": {
|
||||
"stats": {
|
||||
"AP": {
|
||||
"value": "-4"
|
||||
"value": -4
|
||||
},
|
||||
"D": {
|
||||
"value": "D6"
|
||||
},
|
||||
"S": {
|
||||
"value": "8"
|
||||
"value": 8
|
||||
},
|
||||
"Type": {
|
||||
"value": "Grenade 1"
|
||||
|
|
@ -365,36 +514,16 @@
|
|||
},
|
||||
"text": "When resolving an attack with this weapon, if a hit is scored, do not make a [wound roll](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#2.-Wound-Roll): instead roll 3D6; if the result is equal to or greater than the target unit’s highest Leadership characteristic, it suffers D3 [mortal wounds](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Mortal-Wounds)."
|
||||
},
|
||||
"Weapon§Psyk-out grenades": {
|
||||
"stats": {
|
||||
"AP": {
|
||||
"value": "0"
|
||||
},
|
||||
"D": {
|
||||
"value": "1"
|
||||
},
|
||||
"S": {
|
||||
"value": "2"
|
||||
},
|
||||
"Type": {
|
||||
"value": "Grenade D3"
|
||||
},
|
||||
"Range": {
|
||||
"value": "6″"
|
||||
}
|
||||
},
|
||||
"text": "[Blast](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Blast-Weapons). When resolving an attack made with this weapon against a [PSYKER](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#PSYCHIC-PHASE) or DAEMON unit, a [hit roll](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#1.-Hit-Roll) of 6+ inflicts 1 [mortal wound](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Mortal-Wounds) on the target and the attack sequence ends."
|
||||
},
|
||||
"Weapon§Neuro-gauntlet": {
|
||||
"stats": {
|
||||
"AP": {
|
||||
"value": "-1"
|
||||
"value": -1
|
||||
},
|
||||
"D": {
|
||||
"value": "1"
|
||||
"value": 1
|
||||
},
|
||||
"S": {
|
||||
"value": "+1"
|
||||
"value": 1
|
||||
},
|
||||
"Type": {
|
||||
"value": "Melee"
|
||||
|
|
@ -408,10 +537,10 @@
|
|||
"Weapon§Phase sword": {
|
||||
"stats": {
|
||||
"AP": {
|
||||
"value": "-3"
|
||||
"value": -3
|
||||
},
|
||||
"D": {
|
||||
"value": "2"
|
||||
"value": 2
|
||||
},
|
||||
"S": {
|
||||
"value": "User"
|
||||
|
|
@ -428,13 +557,13 @@
|
|||
"Weapon§Poison blades": {
|
||||
"stats": {
|
||||
"AP": {
|
||||
"value": "-1"
|
||||
"value": -1
|
||||
},
|
||||
"D": {
|
||||
"value": "1"
|
||||
"value": 1
|
||||
},
|
||||
"S": {
|
||||
"value": "2"
|
||||
"value": 2
|
||||
},
|
||||
"Type": {
|
||||
"value": "Melee"
|
||||
|
|
@ -448,13 +577,13 @@
|
|||
"Weapon§Power sword": {
|
||||
"stats": {
|
||||
"AP": {
|
||||
"value": "-3"
|
||||
"value": -3
|
||||
},
|
||||
"D": {
|
||||
"value": "1"
|
||||
"value": 1
|
||||
},
|
||||
"S": {
|
||||
"value": "+1"
|
||||
"value": 1
|
||||
},
|
||||
"Type": {
|
||||
"value": "Melee"
|
||||
|
|
@ -464,177 +593,25 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Elites§Vindicare Assassin": {
|
||||
"Weapon§Psyk-out grenades": {
|
||||
"stats": {
|
||||
"Power Level": {
|
||||
"value": 5
|
||||
"AP": {
|
||||
"value": 0
|
||||
},
|
||||
"D": {
|
||||
"value": 1
|
||||
},
|
||||
"S": {
|
||||
"value": 2
|
||||
},
|
||||
"Type": {
|
||||
"value": "Grenade D3"
|
||||
},
|
||||
"Range": {
|
||||
"value": "6″"
|
||||
}
|
||||
},
|
||||
"keywords": {
|
||||
"Keywords": [
|
||||
"Agent of the Imperium",
|
||||
"Character",
|
||||
"Infantry",
|
||||
"Vindicare Assassin"
|
||||
],
|
||||
"Faction": [
|
||||
"Imperium",
|
||||
"Officio Assassinorum"
|
||||
]
|
||||
},
|
||||
"assets": {
|
||||
"traits": [
|
||||
"Ability§Agent of the Imperium",
|
||||
"Ability§Execution Force",
|
||||
"Ability§Independent Operative",
|
||||
"Ability§Lightning Reflexes",
|
||||
"Ability§Deadshot",
|
||||
"Ability§Faultless Aim",
|
||||
"Ability§Head Shot",
|
||||
"Ability§Spymask",
|
||||
"Ability§Stealth Suit",
|
||||
{
|
||||
"item": "Model§Vindicare Assassin",
|
||||
"stats": {
|
||||
"Points": {
|
||||
"visibility": "hidden"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"text": "A Vindicare Assassin is a single model equipped with: exitus pistol; exitus rifle; blind grenades.\n\n\n\nnull",
|
||||
"meta": {
|
||||
"Publication": "[Psychic Awakening: War of the Spider (Expansion) 8th ed. – Indomitus 1.4 @2022-02-04](https://www.warhammer-community.com/wp-content/uploads/2020/07/VXO1CdVZDRexbsb1.pdf)"
|
||||
}
|
||||
},
|
||||
"Elites§Callidus Assassin": {
|
||||
"stats": {
|
||||
"Power Level": {
|
||||
"value": 5
|
||||
}
|
||||
},
|
||||
"keywords": {
|
||||
"Keywords": [
|
||||
"Agent of the Imperium",
|
||||
"Callidus Assassin",
|
||||
"Character",
|
||||
"Infantry"
|
||||
],
|
||||
"Faction": [
|
||||
"Imperium",
|
||||
"Officio Assassinorum"
|
||||
]
|
||||
},
|
||||
"assets": {
|
||||
"traits": [
|
||||
"Ability§Agent of the Imperium",
|
||||
"Ability§Execution Force",
|
||||
"Ability§Independent Operative",
|
||||
"Ability§Lightning Reflexes",
|
||||
"Ability§Polymorphine",
|
||||
"Ability§Hit and Run",
|
||||
"Ability§Reign of Confusion",
|
||||
{
|
||||
"item": "Model§Callidus Assassin",
|
||||
"stats": {
|
||||
"Points": {
|
||||
"visibility": "hidden"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"text": "A Callidus Assassin is a single model equipped with: neural shredder; phase sword; poison blades.\n\n\n\nnull",
|
||||
"meta": {
|
||||
"Publication": "[Psychic Awakening: War of the Spider (Expansion) 8th ed. – Indomitus 1.4 @2022-02-04](https://www.warhammer-community.com/wp-content/uploads/2020/07/VXO1CdVZDRexbsb1.pdf)"
|
||||
}
|
||||
},
|
||||
"Elites§Eversor Assassin": {
|
||||
"stats": {
|
||||
"Power Level": {
|
||||
"value": 5
|
||||
}
|
||||
},
|
||||
"keywords": {
|
||||
"Keywords": [
|
||||
"Agent of the Imperium",
|
||||
"Character",
|
||||
"Eversor Assassin",
|
||||
"Infantry"
|
||||
],
|
||||
"Faction": [
|
||||
"Imperium",
|
||||
"Officio Assassinorum"
|
||||
]
|
||||
},
|
||||
"assets": {
|
||||
"traits": [
|
||||
"Ability§Agent of the Imperium",
|
||||
"Ability§Execution Force",
|
||||
"Ability§Independent Operative",
|
||||
"Ability§Lightning Reflexes",
|
||||
"Ability§Bio-meltdown",
|
||||
"Ability§Sentinel Array",
|
||||
"Ability§Frenzon",
|
||||
"Ability§Killing Rampage",
|
||||
{
|
||||
"item": "Model§Eversor Assassin",
|
||||
"stats": {
|
||||
"Points": {
|
||||
"visibility": "hidden"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"text": "An Eversor Assassin is a single model equipped with: executioner pistol; neuro-gauntlet; power sword; melta bombs.\n\n\n\nnull",
|
||||
"meta": {
|
||||
"Publication": "[Psychic Awakening: War of the Spider (Expansion) 8th ed. – Indomitus 1.4 @2022-02-04](https://www.warhammer-community.com/wp-content/uploads/2020/07/VXO1CdVZDRexbsb1.pdf)"
|
||||
}
|
||||
},
|
||||
"Elites§Culexus Assassin": {
|
||||
"stats": {
|
||||
"Power Level": {
|
||||
"value": 5
|
||||
}
|
||||
},
|
||||
"keywords": {
|
||||
"Keywords": [
|
||||
"Agent of the Imperium",
|
||||
"Character",
|
||||
"Culexus Assassin",
|
||||
"Infantry"
|
||||
],
|
||||
"Faction": [
|
||||
"Imperium",
|
||||
"Officio Assassinorum"
|
||||
]
|
||||
},
|
||||
"assets": {
|
||||
"traits": [
|
||||
"Ability§Agent of the Imperium",
|
||||
"Ability§Execution Force",
|
||||
"Ability§Independent Operative",
|
||||
"Ability§Lightning Reflexes",
|
||||
"Ability§Abomination",
|
||||
"Ability§Life Drain",
|
||||
"Ability§Etherium",
|
||||
"Ability§Psychic Assassin",
|
||||
{
|
||||
"item": "Model§Culexus Assassin",
|
||||
"stats": {
|
||||
"Points": {
|
||||
"visibility": "hidden"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"text": "A Culexus Assassin is a single model equipped with: animus speculum; psyk-out grenades.\n\n\n\nnull",
|
||||
"meta": {
|
||||
"Publication": "[Psychic Awakening: War of the Spider (Expansion) 8th ed. – Indomitus 1.4 @2022-02-04](https://www.warhammer-community.com/wp-content/uploads/2020/07/VXO1CdVZDRexbsb1.pdf)"
|
||||
}
|
||||
"text": "[Blast](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Blast-Weapons). When resolving an attack made with this weapon against a [PSYKER](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#PSYCHIC-PHASE) or DAEMON unit, a [hit roll](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#1.-Hit-Roll) of 6+ inflicts 1 [mortal wound](https://wahapedia.ru/wh40k9ed/the-rules/core-rules/#Mortal-Wounds) on the target and the attack sequence ends."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
67258
orks/Orks.manifest
67258
orks/Orks.manifest
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
|
@ -13,6 +13,7 @@ const subFacNames = {
|
|||
DRU: 'Kabal', // Wych Cult, Haemunculous Coven
|
||||
GC: 'Cult',
|
||||
GK: 'Brotherhood',
|
||||
LoV: 'League',
|
||||
QI: 'Noble Household', // Questor Allegiance
|
||||
NEC: 'Dynasty',
|
||||
ORK: 'Clan',
|
||||
|
|
@ -29,8 +30,9 @@ processInfo = (data,factionKey) => {
|
|||
genre: 'sci-fi',
|
||||
publisher: 'Games Workshop',
|
||||
url: 'https://warhammer40000.com/',
|
||||
notes: 'This manifest is provided for the purposes of testing the features of *Rosterizer* and is not intended for distribution.',
|
||||
revision: '0.0.5',
|
||||
notes: '0.0.8: dynamic damage min/max variable type\n\n0.0.7: single-model units no longer have any "model" asssets\n\n0.0.6: "source" keyword category\n\n0.0.5: add relics\n\nThis manifest is provided for the purposes of testing the features of *Rosterizer* and is not intended for distribution.\n\nThe data included herein was programatically compiled from freely-available sources on the internet and likely contains some errors. Use with caution.',
|
||||
revision: '0.0.8',
|
||||
wip: true,
|
||||
dependencies: [
|
||||
{
|
||||
slug: "123456",
|
||||
|
|
@ -99,6 +101,12 @@ processModels = (data,assetCatalog) => {
|
|||
// console.log(modelItemKey)
|
||||
});
|
||||
}
|
||||
numerize = (value) => {
|
||||
let initialValue = (value + '').replace(/^([0-9]*)"/g,'$1″').replace(/^([0-9]*)\+/g,'$1');
|
||||
let numberTest = Number(initialValue);
|
||||
if(numberTest + '' !== initialValue) return initialValue
|
||||
return numberTest
|
||||
}
|
||||
dedupModels = (dupModels) => {
|
||||
let deduped = dupModels[0];
|
||||
let props = ['attacks','ballistic_skill','base_size','cost','leadership','movement','save','strength','toughness','weapon_skill','wounds'];
|
||||
|
|
@ -108,17 +116,17 @@ dedupModels = (dupModels) => {
|
|||
});
|
||||
return {
|
||||
stats: {
|
||||
Points: {value: deduped.cost},
|
||||
M: {value: deduped.movement},
|
||||
WS: {value: deduped.weapon_skill},
|
||||
BS: {value: deduped.ballistic_skill},
|
||||
S: {value: deduped.strength},
|
||||
T: {value: deduped.toughness},
|
||||
W: {value: deduped.wounds},
|
||||
A: {value: deduped.attacks},
|
||||
Ld: {value: deduped.leadership},
|
||||
Sv: {value: deduped.save},
|
||||
Base: {value: deduped.base_size},
|
||||
Points: {value: numerize(deduped.cost)},
|
||||
M: {value: numerize(deduped.movement)},
|
||||
WS: {value: numerize(deduped.weapon_skill)},
|
||||
BS: {value: numerize(deduped.ballistic_skill)},
|
||||
S: {value: numerize(deduped.strength)},
|
||||
T: {value: numerize(deduped.toughness)},
|
||||
W: {value: numerize(deduped.wounds)},
|
||||
A: {value: numerize(deduped.attacks)},
|
||||
Ld: {value: numerize(deduped.leadership)},
|
||||
Sv: {value: numerize(deduped.save)},
|
||||
Base: {value: numerize(deduped.base_size)},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -165,14 +173,14 @@ processAbilities = (data,assetCatalog) => {
|
|||
if(!ability.is_other_wargear){
|
||||
itemKey = 'Ability§' + ability.name;
|
||||
if(!assetCatalog[itemKey]) assetCatalog[itemKey] = tempAbility;
|
||||
else assetCatalog[itemKey].text += '\n\nERROR: The following text was found on another ability with the same name.\n\n' + formatText(ability.description,shouldLog);
|
||||
else assetCatalog[itemKey].text += '\n\n***ERROR***—*The following text was found on another ability with the same name:* \n' + formatText(ability.description,shouldLog);
|
||||
}else{
|
||||
itemKey = 'Wargear§' + ability.name;
|
||||
let abilityCostArr = data.abilities.datasheets_abilities.filter(datasheets_ability => datasheets_ability.ability_id === ability.ability_id).map(datasheets_ability => datasheets_ability.cost);
|
||||
let costMode = findMode(abilityCostArr);
|
||||
if(costMode) tempAbility.stats = {Points: {value: costMode}};
|
||||
if(costMode) tempAbility.stats = {Points: {value: numerize(costMode)}};
|
||||
if(!assetCatalog[itemKey]) assetCatalog[itemKey] = tempAbility;
|
||||
else assetCatalog[itemKey].text += '\n\nERROR: The following text was found on another wargear with the same name.\n\n' + formatText(ability.description,shouldLog);
|
||||
else assetCatalog[itemKey].text += '\n\n***ERROR***—*The following text was found on another wargear with the same name:* \n' + formatText(ability.description,shouldLog);
|
||||
}
|
||||
let subFactTest = new RegExp(`<${data.factCurrent}>`, 'gi');
|
||||
if(subFactTest.test(assetCatalog[itemKey].text)){
|
||||
|
|
@ -204,11 +212,11 @@ processWargear = (data,assetCatalog) => {
|
|||
data.wargear.wargear_list.forEach(wargear => {
|
||||
let weapName = wargear.name.replace(/(1: |2: |3: )/,'').replace(/в/g,'d');
|
||||
let tempWeapon = {stats:{
|
||||
AP: {value: wargear.armor_piercing},
|
||||
D: {value: wargear.damage},
|
||||
S: {value: wargear.strength},
|
||||
Type: {value: wargear.type},
|
||||
Range: {value: wargear.weapon_range},
|
||||
AP: {value: numerize(wargear.armor_piercing)},
|
||||
D: {value: numerize(wargear.damage)},
|
||||
S: {value: numerize(wargear.strength)},
|
||||
Type: {value: numerize(wargear.type)},
|
||||
Range: {value: numerize(wargear.weapon_range)},
|
||||
}};
|
||||
if(wargear.abilities) tempWeapon.text = formatText(wargear.abilities);
|
||||
let wargearArr = data.wargear.wargear_list.filter(wargear_list => wargear_list.wargear_id == wargear.wargear_id).map(wargear => 'Weapon§' + wargear.name);
|
||||
|
|
@ -216,7 +224,7 @@ processWargear = (data,assetCatalog) => {
|
|||
let cost = findMode(costArr);
|
||||
// console.log(wargear.wargear_id,cost,costArr)
|
||||
if(wargearArr.length == 1 && cost){
|
||||
tempWeapon.stats.Points = {value: cost};
|
||||
tempWeapon.stats.Points = {value: numerize(cost)};
|
||||
}
|
||||
assetCatalog['Weapon§' + weapName] = tempWeapon;
|
||||
if(wargearArr.length > 1){
|
||||
|
|
@ -227,7 +235,7 @@ processWargear = (data,assetCatalog) => {
|
|||
assetCatalog[itemKey].assets.traits = assetCatalog[itemKey].assets.traits || [];
|
||||
assetCatalog[itemKey].assets.traits.push('Weapon§' + weapName);
|
||||
if(cost){
|
||||
assetCatalog[itemKey].stats = {Points: {value: cost}};
|
||||
assetCatalog[itemKey].stats = {Points: {value: numerize(cost)}};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -285,7 +293,7 @@ createWargearStat = (i,wargearArr,modelLoadout,assetCatalog) => {
|
|||
let actualTrait = assetCatalog[wargear.itemKey];
|
||||
let assignedTrait = (actualTrait?.stats?.Points?.value === undefined && !wargear.cost) || actualTrait?.stats?.Points?.value == wargear.cost ? wargear.itemKey : {
|
||||
item: wargear.itemKey,
|
||||
stats: {Points: {value: Number(wargear.cost)}}
|
||||
stats: {Points: {value: numerize(wargear.cost)}}
|
||||
}
|
||||
tempStat.ranks[wargearName] = {
|
||||
order: i+1,
|
||||
|
|
@ -295,15 +303,15 @@ createWargearStat = (i,wargearArr,modelLoadout,assetCatalog) => {
|
|||
return tempStat
|
||||
}
|
||||
processRelics = (data,assetCatalog) => {
|
||||
console.log(data.relics.relic_list)
|
||||
// console.log(data.relics.relic_list)
|
||||
data.relics.relic_list?.forEach(relic => {
|
||||
let weapName = relic.name.replace(/(1: |2: |3: )/,'').replace(/в/g,'d').replace(/^"*(.*[^"])"*$/g,'$1').replace(/^\s*(.*[^\s])\s*$/g,'$1');
|
||||
let tempWeapon = {stats:{
|
||||
AP: {value: relic.armor_piercing},
|
||||
D: {value: relic.damage},
|
||||
S: {value: relic.strength},
|
||||
Type: {value: relic.type},
|
||||
Range: {value: relic.weapon_range},
|
||||
AP: {value: numerize(relic.armor_piercing)},
|
||||
D: {value: numerize(relic.damage)},
|
||||
S: {value: numerize(relic.strength)},
|
||||
Type: {value: numerize(relic.type)},
|
||||
Range: {value: numerize(relic.weapon_range)},
|
||||
}};
|
||||
if(relic.abilities) tempWeapon.text = formatText(relic.abilities);
|
||||
let relicsArr = data.relics.relic_list.filter(relic_list => relic_list.wargear_id == relic.wargear_id).map(relic => 'Relic Weapon§' + relic.name);
|
||||
|
|
@ -356,7 +364,7 @@ processPsychicPowers = (data,assetCatalog) => {
|
|||
let tempPower = {
|
||||
text: formatText(power.description)
|
||||
};
|
||||
if(power.roll) tempPower.stats = {Roll:{value: power.roll}};
|
||||
if(power.roll) tempPower.stats = {Roll:{value: numerize(power.roll)}};
|
||||
assetCatalog[powerName] = tempPower;
|
||||
}else{
|
||||
let powerName = 'Psychic Power§' + power.name.toLowerCase().split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
||||
|
|
@ -395,6 +403,8 @@ formatText = (text,log = false) => {
|
|||
boldPattern2: [/<span[\s]+class="kwb">((?:.(?!\<\/span\>))*.)<\/span>/g,'<b>$1</b>'],
|
||||
underPattern2: [/<span[\s]+class="kwbu">((?:.(?!\<\/span\>))*.)<\/span>/g,'<i>$1<i>'],
|
||||
ttPattern2: [/<span[\s]+class="tt">((?:.(?!\<\/span\>))*.)<\/span>/g,'<b>$1</b>'],
|
||||
ttPattern3: [/<span[\s]+class="tt kwbu">((?:.(?!\<\/span\>))*.)<\/span>/g,'<b>$1</b>'],
|
||||
ttPattern4: [/<span[\s]+class="tt kwbu">((?:.(?!\<\/span\>))*.)<\/span>/g,'<b>$1</b>'],
|
||||
h_customPattern: [/<span[\s]+class="h_custom">((?:.(?!\<\/span\>))*.)<\/span>/g,'<b>$1</b>'],
|
||||
redfontPattern: [/<span[\s]+class="redfont">((?:.(?!\<\/span\>))*.)<\/span>/g,'<b>$1</b>'],
|
||||
}
|
||||
|
|
@ -406,7 +416,8 @@ formatText = (text,log = false) => {
|
|||
boldTranslationPattern: [/<\/?b>/g,'**'],
|
||||
doubleBoldPattern: [/\*\*\*\*/g,''],
|
||||
doubleBoldPattern2: [/\*\*\s\*\*/g,' '],
|
||||
italicsTranslationPattern: [/<\/?i>/g,'*']
|
||||
italicsTranslationPattern: [/<\/?i>/g,'*'],
|
||||
doublePrime: [/\s([0-9]+)"(\.*)\s/g,' $1″$2 '],
|
||||
}
|
||||
newText = text.replace(/kwb2/g,'kwb');
|
||||
if(log) console.log(newText)
|
||||
|
|
@ -454,95 +465,39 @@ processUnits = (data,assetCatalog) => {
|
|||
let unitId = datasheet.datasheet_id;
|
||||
let tempItem = {stats:{
|
||||
'Power Level': {
|
||||
value: Number(datasheet.power_points)
|
||||
value: numerize(datasheet.power_points)
|
||||
}
|
||||
},keywords:{},assets:{}};
|
||||
|
||||
let models = data.models.filter(model => model.datasheet_id === unitId);
|
||||
// console.log(unitId,models)
|
||||
let singleModelUnit = models[0]?.models_per_unit == 1 && models.length == 1;
|
||||
if(models[0]?.line === 1 && models[0]?.models_per_unit.includes('-')){
|
||||
tempItem.stats.model = {
|
||||
value: 'Model§' + data.models.filter(model => model.datasheet_id === unitId && model.line === 1)[0].name
|
||||
value: data.models.filter(model => model.datasheet_id === unitId && model.line === 1)[0].itemKey
|
||||
}
|
||||
}
|
||||
|
||||
let keywords = data.keywords.filter(keyword => keyword.datasheet_id === unitId && !keyword.is_faction_keyword);
|
||||
if(keywords.length) tempItem.keywords.Keywords = keywords.map(keyword => keyword.keyword);
|
||||
let factionKeywords = data.keywords.filter(keyword => keyword.datasheet_id === unitId && keyword.is_faction_keyword);
|
||||
if(factionKeywords.length) tempItem.keywords.Faction = factionKeywords.map(keyword => keyword.keyword);
|
||||
let modelDamage = data.damage.filter(dmgLine => dmgLine.datasheet_id == unitId);
|
||||
if(modelDamage.length){
|
||||
let modelItemKey = models.filter(model => model.datasheet_id === unitId)[0].itemKey;
|
||||
// console.log(unitId,modelItemKey)
|
||||
assetCatalog[modelItemKey].stats['W'] = {
|
||||
value: numerize(assetCatalog[modelItemKey].stats['W'].value),
|
||||
max: numerize(assetCatalog[modelItemKey].stats['W'].value),
|
||||
min: 1,
|
||||
dynamic: true,
|
||||
increment: {value: 1},
|
||||
statType: 'numeric',
|
||||
visibility: 'always',
|
||||
}
|
||||
assetCatalog[modelItemKey].rules = assetCatalog[modelItemKey].rules || {};
|
||||
assetCatalog[modelItemKey].rules.dynamicDamageMid = generateDamageRule(modelDamage[0],modelDamage[2]);
|
||||
assetCatalog[modelItemKey].rules.dynamicDamageLow = generateDamageRule(modelDamage[0],modelDamage[3]);
|
||||
}
|
||||
|
||||
let options = data.options.filter(option => option.datasheet_id === unitId);
|
||||
tempItem.text = formatText(datasheet.unit_composition + '\n\n' + options.map(option => (option.button || '') + ' ' + option.description).join('\n\n') + '\n\n' + datasheet.psyker);
|
||||
|
||||
if(models[0]?.models_per_unit?.includes('-')){
|
||||
tempItem.stats[datasheet.name] = {
|
||||
statType: 'numeric',
|
||||
dynamic: true,
|
||||
visibility: 'active',
|
||||
};
|
||||
let stat = tempItem.stats[datasheet.name];
|
||||
let range = models[0].models_per_unit.split('-');
|
||||
stat.value = Number(range[0]);
|
||||
stat.min = Number(range[0]);
|
||||
stat.max = Number(range[1]);
|
||||
let basePlThresh = stat.min;
|
||||
if(!(stat.max % stat.min)){
|
||||
// console.log(datasheet.name,'has a clean threshold')
|
||||
stat.increment = {value: stat.min};
|
||||
}
|
||||
else if(!((stat.max + 1) % (stat.min + 1)) && models[1]?.models_per_unit == 1){
|
||||
// console.log(datasheet.name,'has a sergeant')
|
||||
stat.increment = {value: stat.min + 1};
|
||||
// console.log(stat)
|
||||
basePlThresh ++;
|
||||
}else tempItem.text += '\n\nERROR: there might be a problem with incrementation that will require inputting by hand.';
|
||||
let PLArr = datasheet.unit_composition.split(/(\<b\>Power Rating |\<\/b\>)/).map(el => Number(el.replace('+','plus'))).filter(el => !isNaN(el));
|
||||
if(PLArr.length){
|
||||
let tempInc = PLArr[0] - datasheet.power_points;
|
||||
// console.log(datasheet.name,basePlThresh,tempInc,PLArr)
|
||||
for (let i = 0; i < PLArr.length; i++) {
|
||||
if(PLArr[i] !== ((i+1) * tempInc) + Number(datasheet.power_points)){
|
||||
// console.log(PLArr[i],tempInc,Number(datasheet.power_points), ((i+1) * tempInc) + Number(datasheet.power_points))
|
||||
tempItem.text += '\n\nERROR: there might be a problem with Power Rating that will require a custom rule.';
|
||||
tempInc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(tempInc){
|
||||
tempItem.stats.poweri = {value:tempInc};
|
||||
for (let i = 0; i < PLArr.length; i++) {
|
||||
tempItem.stats['power'+(i+1)] = {
|
||||
"value": (basePlThresh * (i + 1)) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if(datasheet.unit_composition.includes('Power Rating')) tempItem.text += '\n\nERROR: there might be a problem with Power Rating that will require a custom rule.';
|
||||
}
|
||||
let modelList = [];
|
||||
models.forEach(model => {
|
||||
let [minQty,maxQty] = model.models_per_unit.split('-').map(qty => Number(qty));
|
||||
if(minQty){
|
||||
let tempTrait = {item: model.itemKey};
|
||||
if(minQty > 1) tempTrait.quantity = minQty;
|
||||
// console.log(datasheet.name,model.name,model.models_per_unit,models.length)
|
||||
if(model.models_per_unit == 1 && models.length == 1){
|
||||
tempTrait.stats = tempTrait.stats || {};
|
||||
tempTrait.stats.Points = tempTrait.stats.Points || {};
|
||||
tempTrait.stats.Points.visibility = 'hidden';
|
||||
}
|
||||
// console.log(tempTrait)
|
||||
if(Object.keys(tempTrait).length === 1) tempTrait = model.itemKey;
|
||||
tempItem.assets.traits = tempItem.assets.traits || [];
|
||||
tempItem.assets.traits.push(tempTrait);
|
||||
modelList.push(model)
|
||||
}
|
||||
if(minQty > 1 || maxQty > 1){
|
||||
tempItem.allowed = tempItem.allowed || {};
|
||||
tempItem.allowed.items = tempItem.allowed.items || [];
|
||||
tempItem.allowed.items.push(model.itemKey)
|
||||
}
|
||||
});
|
||||
|
||||
let abilities = data.abilities.composed.filter(ability => ability.datasheet_id === unitId);
|
||||
let abilityList = abilities.filter(ability => ability.datasheet_id === unitId && !ability.is_other_wargear);
|
||||
let wargearList = abilities.filter(ability => ability.datasheet_id === unitId && ability.is_other_wargear);
|
||||
|
|
@ -557,7 +512,7 @@ processUnits = (data,assetCatalog) => {
|
|||
tempItem.assets.traits.push('Psychic Power§Smite');
|
||||
}
|
||||
const order = ['Ability§', 'Wargear§', 'Psychic Power§', 'Model§'];
|
||||
tempItem.assets.traits.sort((a, b) => stringSimilarity.findBestMatch((a.item || a),order).bestMatchIndex - stringSimilarity.findBestMatch((b.item || b),order).bestMatchIndex);
|
||||
tempItem.assets.traits?.sort((a, b) => stringSimilarity.findBestMatch((a.item || a),order).bestMatchIndex - stringSimilarity.findBestMatch((b.item || b),order).bestMatchIndex);
|
||||
|
||||
Array.from(new Set(data.psychicPowers.map(power => power.type))).forEach(discipline => {
|
||||
// console.log(discipline)
|
||||
|
|
@ -574,7 +529,7 @@ processUnits = (data,assetCatalog) => {
|
|||
let tempWargear = wargear.cost === assetCatalog[wargear.itemKey].stats?.Points?.value ? wargear.itemKey : {
|
||||
item: wargear.itemKey,
|
||||
stats: {
|
||||
Points: {value: wargear.cost}
|
||||
Points: {value: numerize(wargear.cost)}
|
||||
}
|
||||
};
|
||||
tempItem.stats = tempItem.stats || {};
|
||||
|
|
@ -582,6 +537,8 @@ processUnits = (data,assetCatalog) => {
|
|||
value: 0,
|
||||
statType: 'rank',
|
||||
statOrder: 10,
|
||||
group: 'Loadout',
|
||||
groupOrder: 2,
|
||||
ranks: {
|
||||
0: {order: 0,number: 0,icons: ['cancel']},
|
||||
1: {order: 1,number: 1,icons: ['confirmed'],traits: [{trait: tempWargear}]}
|
||||
|
|
@ -632,35 +589,112 @@ processUnits = (data,assetCatalog) => {
|
|||
}
|
||||
});
|
||||
|
||||
if(models[0]?.models_per_unit?.includes('-')){
|
||||
tempItem.stats[datasheet.name] = {
|
||||
statType: 'numeric',
|
||||
dynamic: true,
|
||||
visibility: 'active',
|
||||
group: 'Loadout',
|
||||
groupOrder: 2,
|
||||
};
|
||||
let stat = tempItem.stats[datasheet.name];
|
||||
let range = models[0].models_per_unit.split('-');
|
||||
stat.value = Number(range[0]);
|
||||
stat.min = Number(range[0]);
|
||||
stat.max = Number(range[1]);
|
||||
let basePlThresh = stat.min;
|
||||
if(!(stat.max % stat.min)){
|
||||
// console.log(datasheet.name,'has a clean threshold')
|
||||
stat.increment = {value: numerize(stat.min)};
|
||||
}
|
||||
else if(!((stat.max + 1) % (stat.min + 1)) && models[1]?.models_per_unit == 1){
|
||||
// console.log(datasheet.name,'has a sergeant')
|
||||
stat.increment = {value: numerize(stat.min) + 1};
|
||||
// console.log(stat)
|
||||
basePlThresh ++;
|
||||
}else tempItem.text += '\n\n***ERROR***—*there might be a problem with incrementation that will require inputting by hand.*';
|
||||
let PLArr = datasheet.unit_composition.split(/(\<b\>Power Rating |\<\/b\>)/).map(el => Number(el.replace('+','plus'))).filter(el => !isNaN(el));
|
||||
if(PLArr.length){
|
||||
let tempInc = PLArr[0] - datasheet.power_points;
|
||||
// console.log(datasheet.name,basePlThresh,tempInc,PLArr)
|
||||
for (let i = 0; i < PLArr.length; i++) {
|
||||
if(PLArr[i] !== ((i+1) * tempInc) + Number(datasheet.power_points)){
|
||||
// console.log(PLArr[i],tempInc,Number(datasheet.power_points), ((i+1) * tempInc) + Number(datasheet.power_points))
|
||||
tempItem.text += '\n\n***ERROR***—*there might be a problem with Power Rating that will require a custom rule.*';
|
||||
tempInc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(tempInc){
|
||||
tempItem.stats.poweri = {value:tempInc};
|
||||
for (let i = 0; i < PLArr.length; i++) {
|
||||
tempItem.stats['power'+(i+1)] = {
|
||||
"value": (basePlThresh * (i + 1)) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if(datasheet.unit_composition.includes('Power Rating')) tempItem.text += '\n\n***ERROR***—*there might be a problem with Power Rating that will require a custom rule.*';
|
||||
}
|
||||
models.forEach(model => {
|
||||
let [minQty,maxQty] = model.models_per_unit.split('-').map(qty => Number(qty));
|
||||
if(minQty){
|
||||
// console.log(datasheet.name,model.name,model.models_per_unit,models.length)
|
||||
if(singleModelUnit){
|
||||
let modelAsset = assetCatalog[model.itemKey];
|
||||
// console.log(modelAsset)
|
||||
tempItem = {
|
||||
...tempItem,
|
||||
stats: {
|
||||
...tempItem.stats,
|
||||
...modelAsset.stats,
|
||||
},
|
||||
rules: {
|
||||
...tempItem.rules,
|
||||
...modelAsset.rules,
|
||||
}
|
||||
}
|
||||
if(!Object.keys(tempItem.rules).length) delete tempItem.rules;
|
||||
}else{
|
||||
let tempTrait = {item: model.itemKey};
|
||||
if(minQty > 1) tempTrait.quantity = minQty;
|
||||
// console.log(tempTrait)
|
||||
if(Object.keys(tempTrait).length === 1) tempTrait = model.itemKey;
|
||||
tempItem.assets.traits = tempItem.assets.traits || [];
|
||||
tempItem.assets.traits.push(tempTrait);
|
||||
}
|
||||
}
|
||||
if(minQty > 1 || maxQty > 1 || !minQty){
|
||||
tempItem.allowed = tempItem.allowed || {};
|
||||
tempItem.allowed.items = tempItem.allowed.items || [];
|
||||
tempItem.allowed.items.push(model.itemKey)
|
||||
}
|
||||
});
|
||||
|
||||
let source = data.sources.filter(source => source.source_id == datasheet.source_id)[0];
|
||||
// console.log(source)
|
||||
if(source){
|
||||
let errataDate = source.errata_date.split(' ')[0].split('.').reverse().join('-');
|
||||
tempItem.meta = tempItem.meta || {};
|
||||
tempItem.meta.Publication = `[${source.name} (${source.type}) ${ordinalize(source.edition)} ed. – ${source.version || ''} @${errataDate}](${source.errata_link})`;
|
||||
tempItem.keywords.Source = [`${source.type}—${source.name}${source.version ? ('—'+source.version) : ''}`];
|
||||
if(source.edition) tempItem.keywords.Edition = [ordinalize(source.edition)];
|
||||
}
|
||||
// TODO implement dynamic stats
|
||||
|
||||
let modelDamage = data.damage.filter(dmgLine => dmgLine.datasheet_id == unitId);
|
||||
if(modelDamage.length){
|
||||
let modelItemKey = models.filter(model => model.datasheet_id === unitId)[0].itemKey;
|
||||
// console.log(unitId,modelItemKey)
|
||||
assetCatalog[modelItemKey].stats['W'] = {
|
||||
value: assetCatalog[modelItemKey].stats['W'].value,
|
||||
max: assetCatalog[modelItemKey].stats['W'].value,
|
||||
min: 1,
|
||||
dynamic: true,
|
||||
increment: {value: 1},
|
||||
statType: 'numeric',
|
||||
visibility: 'always',
|
||||
}
|
||||
assetCatalog[modelItemKey].rules = assetCatalog[modelItemKey].rules || {};
|
||||
assetCatalog[modelItemKey].rules.dynamicDamageMid = generateDamageRule(modelDamage[0],modelDamage[2]);
|
||||
assetCatalog[modelItemKey].rules.dynamicDamageLow = generateDamageRule(modelDamage[0],modelDamage[3]);
|
||||
}
|
||||
let keywordList = data.keywords.filter(keyword => keyword.datasheet_id === unitId && !keyword.is_faction_keyword);
|
||||
if(keywordList.length) tempItem.keywords.Keywords = keywordList.map(keyword => keyword.keyword);
|
||||
let factionKeywords = data.keywords.filter(keyword => keyword.datasheet_id === unitId && keyword.is_faction_keyword);
|
||||
if(factionKeywords.length) tempItem.keywords.Faction = factionKeywords.map(keyword => keyword.keyword);
|
||||
|
||||
assetCatalog[datasheet.role + '§' + datasheet.name] = tempItem;
|
||||
});
|
||||
data.datasheets.forEach(datasheet => {
|
||||
let unitId = datasheet.datasheet_id;
|
||||
let models = data.models.filter(model => model.datasheet_id === unitId);
|
||||
// console.log(unitId,data.models,unitId)
|
||||
let modelItemKey = models.filter(model => model.datasheet_id === unitId)[0]?.itemKey;
|
||||
let singleModelUnit = models[0]?.models_per_unit == 1 && models.length == 1;
|
||||
if(singleModelUnit && modelItemKey) delete assetCatalog[modelItemKey];
|
||||
});
|
||||
}
|
||||
generateDamageRule = (damageRows,currentRow) => {
|
||||
// console.log(damageRows,currentRow)
|
||||
|
|
@ -671,8 +705,8 @@ generateDamageRule = (damageRows,currentRow) => {
|
|||
paths: [
|
||||
['{self}','stats','W','value']
|
||||
],
|
||||
max: max,
|
||||
min: min,
|
||||
max: Number(max),
|
||||
min: Number(min),
|
||||
operator: 'AND',
|
||||
not: false,
|
||||
actionable: true
|
||||
|
|
@ -686,7 +720,7 @@ generateDamageRule = (damageRows,currentRow) => {
|
|||
['{self}','stats',damageRows.col2,'value']
|
||||
],
|
||||
actionType: 'set',
|
||||
value: typeof currentRow.col2 === 'number' ? currentRow.col2 : currentRow.col2?.replace('"',''),
|
||||
value: numerize(currentRow.col2),
|
||||
iterations: 1
|
||||
},
|
||||
{
|
||||
|
|
@ -694,7 +728,7 @@ generateDamageRule = (damageRows,currentRow) => {
|
|||
['{self}','stats',damageRows.col3,'value']
|
||||
],
|
||||
actionType: 'set',
|
||||
value: typeof currentRow.col3 === 'number' ? currentRow.col3 : currentRow.col3?.replace('"',''),
|
||||
value: numerize(currentRow.col3),
|
||||
iterations: 1
|
||||
},
|
||||
{
|
||||
|
|
@ -702,7 +736,7 @@ generateDamageRule = (damageRows,currentRow) => {
|
|||
['{self}','stats',damageRows.col4,'value']
|
||||
],
|
||||
actionType: 'set',
|
||||
value: typeof currentRow.col4 === 'number' ? currentRow.col4 : currentRow.col4?.replace('"',''),
|
||||
value: numerize(currentRow.col4),
|
||||
iterations: 1
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -606,11 +606,11 @@ else:
|
|||
data = data + [
|
||||
re.sub("[a-zA-Z]*","",row[indexer["datasheet_id"]]), # datasheet_id
|
||||
row[indexer["line"]], # line
|
||||
row[indexer["col1"]].replace('+', ''), # col1
|
||||
row[indexer["col2"]].replace('+', ''), # col2
|
||||
row[indexer["col3"]].replace('+', ''), # col3
|
||||
row[indexer["col4"]].replace('+', ''), # col4
|
||||
row[indexer["col5"]].replace('+', ''), # col5
|
||||
row[indexer["col1"]].replace('+', '').replace('"',''), # col1
|
||||
row[indexer["col2"]].replace('+', '').replace('"',''), # col2
|
||||
row[indexer["col3"]].replace('+', '').replace('"',''), # col3
|
||||
row[indexer["col4"]].replace('+', '').replace('"',''), # col4
|
||||
row[indexer["col5"]].replace('+', '').replace('"',''), # col5
|
||||
]
|
||||
query = query[:-1] + " ON DUPLICATE KEY UPDATE check_me=1"
|
||||
cur.execute(query,data)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue