diff --git a/Shadowrun5th/Shadowrun5th.css b/Shadowrun5th/Shadowrun5th.css index 47cf399ebb..c24434e3a2 100644 --- a/Shadowrun5th/Shadowrun5th.css +++ b/Shadowrun5th/Shadowrun5th.css @@ -1744,6 +1744,13 @@ div.spacer { color: #aaaaee; } +.weapon .heading4 { + font-size: 16px; + line-height: 24px; + margin-top: 1em; + color: #aaaaee; +} + input[type="checkbox"].invisiblecheckbox { display: none } diff --git a/Shadowrun5th/Shadowrun5th.html b/Shadowrun5th/Shadowrun5th.html index a3164566fc..4249b8be91 100644 --- a/Shadowrun5th/Shadowrun5th.html +++ b/Shadowrun5th/Shadowrun5th.html @@ -435,1290 +435,66 @@ Can lift overhead (Strength + Nethits) x 5kg}}">
-

Weapons

-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- -
- -
-
X
-
-
- -
-
- - -
-
- -
-
X
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- -
- -
-
X
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
- - -
- -
- -
-
X
-
-
- -
-
- - -
-
- -
-
X
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- -
- -
-
X
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
- - -
- -
- -
-
X
-
-
- -
-
- - -
-
- -
-
X
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- -
- -
-
X
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
- - -
- -
- -
-
X
-
-
- -
-
- - -
-
- -
-
X
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- -
- -
-
X
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
- - -
- -
- -
-
X
-
-
- -
-
- - -
-
- -
-
X
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- -
- -
-
X
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
- - -
- -
- -
-
X
-
-
- -
-
- - -
-
- -
-
X
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- -
- -
-
X
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
- - -
- -
- -
-
X
-
-
- -
-
- - -
-
- -
-
X
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- -
- -
-
X
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
- - -
- -
- -
-
X
-
-
- -
-
- - -
-
- -
-
X
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- -
- -
-
X
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
-
- + + +
-
- + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
X
- +
- @@ -1733,61 +509,61 @@ Can lift overhead (Strength + Nethits) x 5kg}}"> - +
- +
X
- +
- +
- +
-
- +
- +
- - +
- +
- +
- +
- +
X
- +
-
+
@@ -1797,6 +573,9 @@ Can lift overhead (Strength + Nethits) x 5kg}}">
+
+ +
@@ -1806,9 +585,6 @@ Can lift overhead (Strength + Nethits) x 5kg}}">
-
- -
@@ -1819,115 +595,2444 @@ Can lift overhead (Strength + Nethits) x 5kg}}">
-
-
-
- +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
+
- + +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
+ + +
+
+ +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
@@ -10322,222 +11427,1331 @@ Click again to switch to Manual and Remote">
-
- -
- -
- -
-
X
-
-
- -
-
- - -
-
- -
-
X
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- -
- -
-
X
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
- + + +
+
+ +
+ +
+ +
+
X
-
- +
+
-
- +
+ +
-
- +
+ +
+
X
-
- +
+
-
- +
+
+ +
+
+
-
- +
+
-
- +
+
-
- +
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+
-
+
- +
- +
- +
- +
- +
- +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+
-
- +
+
-
- +
+
-
- +
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+
-
+
- +
- +
- +
- +
- +
- +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+
-
- +
+
-
- +
+
-
- +
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+
-
-
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+
X
+
+
+ +
+
+ + +
+
+ +
+
X
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+
X
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
@@ -11899,6 +14113,36 @@ function clearSheet(attributes, experimental) { } }); + getSectionIDs("repeating_pistols", function(idarray) { + for(var j=0; j < idarray.length; j++) { + removeRepeatingRow("repeating_pistols_"+idarray[j]); + } + }); + + getSectionIDs("repeating_automatics", function(idarray) { + for(var j=0; j < idarray.length; j++) { + removeRepeatingRow("repeating_automatics_"+idarray[j]); + } + }); + + getSectionIDs("repeating_longarms", function(idarray) { + for(var j=0; j < idarray.length; j++) { + removeRepeatingRow("repeating_longarms_"+idarray[j]); + } + }); + + getSectionIDs("repeating_heavyweapons", function(idarray) { + for(var j=0; j < idarray.length; j++) { + removeRepeatingRow("repeating_heavyweapons_"+idarray[j]); + } + }); + + getSectionIDs("repeating_closecombat", function(idarray) { + for(var j=0; j < idarray.length; j++) { + removeRepeatingRow("repeating_closecombat_"+idarray[j]); + } + }); + //removing ammo getSectionIDs("repeating_ammotype1", function(idarray) { for(var j=0; j < idarray.length; j++) { @@ -12309,9 +14553,8 @@ on("change:chummercheckbox", async function(){ try{ if(i < 9) { importSingleWeapon(text, chummerfile.characters.character.weapons.weapon[i-1], i, ammunition, attributes); - } else { - await importSingleRepeatingWeapon(text, chummerfile.characters.character.weapons.weapon[i-1], ammunition, attributes); } + await importSingleRepeatingWeapon(text, chummerfile.characters.character.weapons.weapon[i-1], ammunition, attributes); } catch(err) { goodcode=false; @@ -12847,12 +15090,45 @@ function importRepeatingAmmo(ammunition, number, attributes) { attributes["repeating_ammotype"+number+"_"+newrowid+"_ammoacc"] = ammo.weaponbonusacc != null ? ammo.weaponbonusacc : 0; } +function provideRepeatingWeaponRowName(weapon) { + + var weaponrow = "weapons"; + + switch(weapon.skill) { + case "Pistols": + weaponrow = weapon.skill.replaceAll(' ', '').toLowerCase(); + break; + case "Automatics": + weaponrow = weapon.skill.replaceAll(' ', '').toLowerCase(); + break; + case "Longarms": + weaponrow = weapon.skill.replaceAll(' ', '').toLowerCase(); + break; + case "Heavy Weapons": + weaponrow = weapon.skill.replaceAll(' ', '').toLowerCase(); + break; + case "Unarmed Combat": + weaponrow = "closecombat" + break; + case "Blades": + weaponrow = "closecombat" + break; + case "Clubs": + weaponrow = "closecombat" + break; + } + + var row = "repeating_" + weaponrow + "_" + generateRowID() + "_"; + + return row; +} + async function importSingleRepeatingWeapon(text, weapon, ammunition, attributes) { - var row = "repeating_weapons" + "_" + generateRowID() + "_"; + var row = provideRepeatingWeaponRowName(weapon); if(weapon.type == "Ranged"){ attributes[row + "weaponismelee"] = 0; attributes[row + "weaponrc"] = weapon.rc.match(/\d+/g).pop()-Math.ceil((parseInt(attributes.str_base) + parseInt(attributes.str_aug))/3)- 1; - if(!weapon.rawdamage.includes("STR") &&weapon.rawdamage.match(/\d+/) !== null) { + if(!weapon.rawdamage.includes("STR") && weapon.rawdamage.match(/\d+/) !== null) { attributes[row + "weapondv"] = weapon.rawdamage.match(/\d+/)[0]; } else { @@ -13638,6 +15914,66 @@ on("change:repeating_weapons:weaponcategory", function() { }); }); +on("change:repeating_pistols:weaponcategory", function() { + getAttrs(["repeating_pistols_weaponcategory"], function(value) { + var numb=value.repeating_pistols_weaponcategory.match(/(\d*)}$/); + var name='skillname'+numb[1]; + getAttrs([name], function(values) { + setAttrs({ + repeating_pistols_weaponskillname: values[name] + }); + }); + }); +}); + +on("change:repeating_automatics:weaponcategory", function() { + getAttrs(["repeating_automatics_weaponcategory"], function(value) { + var numb=value.repeating_automatics_weaponcategory.match(/(\d*)}$/); + var name='skillname'+numb[1]; + getAttrs([name], function(values) { + setAttrs({ + repeating_automatics_weaponskillname: values[name] + }); + }); + }); +}); + +on("change:repeating_longarms:weaponcategory", function() { + getAttrs(["repeating_longarms_weaponcategory"], function(value) { + var numb=value.repeating_longarms_weaponcategory.match(/(\d*)}$/); + var name='skillname'+numb[1]; + getAttrs([name], function(values) { + setAttrs({ + repeating_longarms_weaponskillname: values[name] + }); + }); + }); +}); + +on("change:repeating_heavyweapons:weaponcategory", function() { + getAttrs(["repeating_heavyweapons_weaponcategory"], function(value) { + var numb=value.repeating_heavyweapons_weaponcategory.match(/(\d*)}$/); + var name='skillname'+numb[1]; + getAttrs([name], function(values) { + setAttrs({ + repeating_heavyweapons_weaponskillname: values[name] + }); + }); + }); +}); + +on("change:repeating_closecombat:weaponcategory", function() { + getAttrs(["repeating_closecombat_weaponcategory"], function(value) { + var numb=value.repeating_closecombat_weaponcategory.match(/(\d*)}$/); + var name='skillname'+numb[1]; + getAttrs([name], function(values) { + setAttrs({ + repeating_closecombat_weaponskillname: values[name] + }); + }); + }); +}); + on("change:weaponcategory1", function() { getAttrs(["weaponcategory1"], function(value) { var numb=value.weaponcategory1.match(/(\d*)}$/); @@ -14123,7 +16459,9 @@ on('clicked:rollWeapon', async (event) => { await rollDogableAttack(rollPart, dmgType); }); -on('clicked:repeating_weapons:rollweapon', async (event) => { +on('clicked:repeating_weapons:rollweapon ' + + 'clicked:repeating_pistols:rollweapon clicked:repeating_automatics:rollweapon clicked:repeating_longarms:rollweapon clicked:repeating_heavyweapons:rollweapon clicked:repeating_closecombat:rollweapon' + , async (event) => { // prefix gets an empty string for normal attributes, and repeating_section_ID_ for repeating attributes var trigger = event.triggerName.slice(8); // this always starts with 'clicked:' @@ -14138,7 +16476,8 @@ on('clicked:repeating_weapons:rollweapon', async (event) => { }); on('clicked:repeating_ammotype1:roll clicked:repeating_ammotype2:roll clicked:repeating_ammotype3:roll clicked:repeating_ammotype4:roll clicked:repeating_ammotype5:roll ' + - 'clicked:repeating_ammotype6:roll clicked:repeating_ammotype7:roll clicked:repeating_ammotype8:roll clicked:repeating_weapons:rollammo', + 'clicked:repeating_ammotype6:roll clicked:repeating_ammotype7:roll clicked:repeating_ammotype8:roll clicked:repeating_weapons:rollammo ' + + 'clicked:repeating_pistols:rollammo clicked:repeating_automatics:rollammo clicked:repeating_longarms:rollammo clicked:repeating_heavyweapons:rollammo clicked:repeating_closecombat:rollammo', async (event) => { // prefix gets an empty string for normal attributes, and repeating_section_ID_ for repeating attributes @@ -14148,7 +16487,7 @@ on('clicked:repeating_ammotype1:roll clicked:repeating_ammotype2:roll clicked:re let rollPart = event.htmlAttributes.value.replaceAll('prefix-', `${prefix}`); let dmgType; - if(trigger.includes('weapon')) { + if(trigger.includes('weapon') || trigger.includes('pistols') || trigger.includes('automatics') || trigger.includes('longarms') || trigger.includes('heavyweapons') || trigger.includes('closecomba')) { let dmgTypeName = `${prefix}` + rollPart.substring(rollPart.indexOf("ammodmgtype"), rollPart.indexOf("ammodmgtype")+12); dmgType = await asw.getAttrs([dmgTypeName]); if(dmgType[Object.keys(dmgType)[0]].includes("@")) { diff --git a/Shadowrun5th/js/customRollParsing.js b/Shadowrun5th/js/customRollParsing.js index 10beb7dded..e03f3def84 100644 --- a/Shadowrun5th/js/customRollParsing.js +++ b/Shadowrun5th/js/customRollParsing.js @@ -1,3 +1,4 @@ + /////////////////////////// // // // CUSTOM ROLL PARSING // @@ -5,7 +6,7 @@ /////////////////////////// on('clicked:roll', async (event) => { - await startRoll(event.htmlAttributes.value + "{{glitch=[[0]]}}", (results) => { + await startRoll( event.htmlAttributes.value + "{{glitch=[[0]]}}", (results) => { var glitchComputed = 0; var amount = results.results.result.dice.filter(x => x == 1).length; @@ -60,7 +61,9 @@ on('clicked:repeating_knowledge:roll clicked:repeating_alchemy:roll clicked:repe }); }); +///////////////////////////////// // Things with Hits => drain // +///////////////////////////////// on('clicked:repeating_rituals:roll clicked:rollSummoning', async (event) => { @@ -71,7 +74,7 @@ on('clicked:repeating_rituals:roll clicked:rollSummoning', let rollPart = event.htmlAttributes.value.replaceAll('prefix-', `${prefix}`); - await startRoll("{{glitch=[[0]]}}{{nethits=[[0]]}}{{drain_num=[[0]]}}" + rollPart, (results) => { + await startRoll(rollPart + "{{glitch=[[0]]}}{{nethits=[[0]]}}{{drain_num=[[0]]}}" , (results) => { var glitchComputed = 0; var amount = results.results.result.dice.filter(x => x == 1).length; @@ -99,7 +102,76 @@ on('clicked:repeating_rituals:roll clicked:rollSummoning', }); }); +///////////////////// +// Extended Rolls // +///////////////////// + +on('clicked:extendedroll', async (event) => { + let results = await startRoll( event.htmlAttributes.value + "{{passthrough=[[0]]}}{{glitch=[[0]]}} {{sumhits=[[0]]}}"); + + var glitchComputed = 0; + var amount = results.results.result.dice.filter(x => x == 1).length; + + if(amount > results.results.result.dice.length/2) { + glitchComputed = 1; + + if(results.results.result.dice.filter(x => x >= 6).length == 0) { + glitchComputed = 2; + } + } + + // Storing all the passthrough data required for the next roll in an Object helps for larger rolls + let rollData = { + dice: results.results.dice_num.result, + limit: results.results.limit_num.result, + totalhits: results.results.result.result, + wounds: results.results.wounds_num != null ? results.results.wounds_num.result : 0, + sustainedspells: results.results.sustainedspells != null ? results.results.sustainedspells.result : 0, + } + + finishRoll( + results.rollId, + { + glitch: glitchComputed, + passthrough: rollEscape.escape(rollData), + sumhits: results.results.result.result, + } + ); +}); + +on('clicked:rollextended', async (ev) => { + await rollExtended(ev); +}); + +const rollExtended = async (ev) => { + // The data we passed into the button will be stored in the originalRollId key + let previousRoll = rollEscape.unescape(ev.originalRollId); + let attrs = await asw.getAttrs(['character_name', 'gmroll', 'edgeroll','edg_total','edgn','standardroll']); + + let rollBase = `${attrs.gmroll}&{template:extendedRoll}{{passthrough=[[0]]}}{{glitch=[[0]]}}{{sumhits=[[0]]}}{{tries=[[0]]}}{{name=${attrs.character_name}}}{{roll_name=again}}{{limit_num=${previousRoll.limit}}}{{edge=${attrs.edgeroll}}}{{edge_num=[[${attrs.edg_total}]]}}{{wounds_num=[[${previousRoll.wounds}]]}}{{sustainedspells=[[${previousRoll.sustainedspells}]]}}{{dice_num=[[${previousRoll.dice}-1]]}}{{result=[[(${previousRoll.dice}-1-[[${previousRoll.wounds}]]-[[${previousRoll.sustainedspells}]]+[[${attrs.edgn}*${attrs.edg_total}]])${attrs.standardroll}${attrs.edgeroll}kh${previousRoll.limit}]]}}`; + let results = await startRoll(rollBase); + + let sumHits = previousRoll.totalhits + results.results.result.result; + + let rollData = { + dice: results.results.dice_num.result, + limit: previousRoll.limit, + totalhits: sumHits, + wounds: previousRoll.wounds, + sustainedspells: previousRoll.sustainedspells, + } + + + finishRoll(results.rollId, { + sumhits: sumHits, + passthrough: rollEscape.escape(rollData), + }); +} + + +////////////////////////////// // Dogable weapon attacks // +////////////////////////////// on('clicked:rollWeapon', async (event) => { let rollPart = event.htmlAttributes.value; @@ -109,7 +181,9 @@ on('clicked:rollWeapon', async (event) => { await rollDogableAttack(rollPart, dmgType); }); -on('clicked:repeating_weapons:rollweapon', async (event) => { +on('clicked:repeating_weapons:rollweapon ' + + 'clicked:repeating_pistols:rollweapon clicked:repeating_automatics:rollweapon clicked:repeating_longarms:rollweapon clicked:repeating_heavyweapons:rollweapon clicked:repeating_closecombat:rollweapon' + , async (event) => { // prefix gets an empty string for normal attributes, and repeating_section_ID_ for repeating attributes var trigger = event.triggerName.slice(8); // this always starts with 'clicked:' @@ -124,7 +198,8 @@ on('clicked:repeating_weapons:rollweapon', async (event) => { }); on('clicked:repeating_ammotype1:roll clicked:repeating_ammotype2:roll clicked:repeating_ammotype3:roll clicked:repeating_ammotype4:roll clicked:repeating_ammotype5:roll ' + - 'clicked:repeating_ammotype6:roll clicked:repeating_ammotype7:roll clicked:repeating_ammotype8:roll clicked:repeating_weapons:rollammo', + 'clicked:repeating_ammotype6:roll clicked:repeating_ammotype7:roll clicked:repeating_ammotype8:roll clicked:repeating_weapons:rollammo ' + + 'clicked:repeating_pistols:rollammo clicked:repeating_automatics:rollammo clicked:repeating_longarms:rollammo clicked:repeating_heavyweapons:rollammo clicked:repeating_closecombat:rollammo', async (event) => { // prefix gets an empty string for normal attributes, and repeating_section_ID_ for repeating attributes @@ -134,8 +209,7 @@ on('clicked:repeating_ammotype1:roll clicked:repeating_ammotype2:roll clicked:re let rollPart = event.htmlAttributes.value.replaceAll('prefix-', `${prefix}`); let dmgType; - if(trigger.includes('weapon')) { - console.log(rollPart); + if(trigger.includes('weapon') || trigger.includes('pistols') || trigger.includes('automatics') || trigger.includes('longarms') || trigger.includes('heavyweapons') || trigger.includes('closecomba')) { let dmgTypeName = `${prefix}` + rollPart.substring(rollPart.indexOf("ammodmgtype"), rollPart.indexOf("ammodmgtype")+12); dmgType = await asw.getAttrs([dmgTypeName]); if(dmgType[Object.keys(dmgType)[0]].includes("@")) { @@ -158,7 +232,7 @@ on('clicked:repeating_ammotype1:roll clicked:repeating_ammotype2:roll clicked:re const rollDogableAttack = async (rollPart, dmgType) => { - let attackRoll = await startRoll(" {{passthrough=[[0]]}}{{glitch=[[0]]}} " + rollPart ); + let attackRoll = await startRoll( rollPart + " {{passthrough=[[0]]}}{{glitch=[[0]]}} "); var glitchComputed = 0; var amount = attackRoll.results.result.dice.filter(x => x == 1).length; @@ -231,7 +305,10 @@ const rollReactSoak = async (ev) => { let dmgRoll = rollEscape.unescape(ev.originalRollId); let attrs = await asw.getAttrs(['gmroll','character_name','bod_total', 'armor_total', 'soak_bonus', 'edgeroll','edg_total','edgn','standardroll']); - let rollBase = `${attrs.gmroll}&{template:reactsoak}{{dmgTaken=[[0]]}}{{dmgType=[[0]]}}{{name=${attrs.character_name}}}{{body=[[${attrs.bod_total}}]]}}{{armor=[[${attrs.armor_total}]]}}{{ap=[[${dmgRoll.attackAp}]]}}{{bonus=[[${attrs.soak_bonus}]]}}{{mod=[[?{Situational Modifiers|0}]]}}{{edge=${attrs.edgeroll}}}{{edge_num=[[${attrs.edg_total}]]}}{{result=[[([[${attrs.bod_total}}]]+[[${attrs.armor_total}]]+[[${attrs.soak_bonus}]]+[[${dmgRoll.attackAp}]]+[[?{Situational Modifiers}]]+[[${attrs.edgn}*${attrs.edg_total}]])${attrs.standardroll}${attrs.edgeroll}]]}}`; + //AP only reduces armor + let armorPenetration = attrs.armor_total + dmgRoll.attackAp < 0 ? -attrs.armor_total : dmgRoll.attackAp; + + let rollBase = `${attrs.gmroll}&{template:reactsoak}{{dmgTaken=[[0]]}}{{dmgType=[[0]]}}{{name=${attrs.character_name}}}{{body=[[${attrs.bod_total}}]]}}{{armor=[[${attrs.armor_total}]]}}{{ap=[[${armorPenetration}]]}}{{bonus=[[${attrs.soak_bonus}]]}}{{mod=[[?{Situational Modifiers|0}]]}}{{edge=${attrs.edgeroll}}}{{edge_num=[[${attrs.edg_total}]]}}{{result=[[([[${attrs.bod_total}}]]+[[${attrs.armor_total}]]+[[${attrs.soak_bonus}]]+[[${armorPenetration}]]+[[?{Situational Modifiers}]]+[[${attrs.edgn}*${attrs.edg_total}]])${attrs.standardroll}${attrs.edgeroll}]]}}`; let soakRoll = await startRoll(rollBase); let soakSuccesses = soakRoll.results.result.result; @@ -239,11 +316,57 @@ const rollReactSoak = async (ev) => { let dmgType = dmgRoll.attackDmgType; if(dmgType.includes('P')) { - dmgType = dmgRoll.attackDamage > (attrs.armor_total - dmgRoll.attackAp + soakRoll.results.mod.result) ? dmgRoll.attackDmgType : 'S'; + dmgType = dmgRoll.attackDamage > (attrs.armor_total + armorPenetration + soakRoll.results.mod.result) ? dmgRoll.attackDmgType : 'S'; } finishRoll(soakRoll.rollId, { dmgTaken: dmgTaken, dmgType: dmgType }); -} \ No newline at end of file +} + + +const rollEscape = { + chars: { + '"': '%quot;', + ',': '%comma;', + ':': '%colon;', + '}': '%rcub;', + '{': '%lcub;', + }, + escape(str) { + str = (typeof(str) === 'object') ? JSON.stringify(str) : (typeof(str) === 'string') ? str : null; + return (str) ? `${str}`.replace(new RegExp(`[${Object.keys(this.chars)}]`, 'g'), (r) => this.chars[r]) : null; + }, + unescape(str) { + str = `${str}`.replace(new RegExp(`(${Object.values(this.chars).join('|')})`, 'g'), (r) => Object.entries(this.chars).find(e=>e[1]===r)[0]); + return JSON.parse(str); + } +} + +const asw = (() => { + const setActiveCharacterId = function(charId){ + let oldAcid=getActiveCharacterId(); + let ev = new CustomEvent("message"); + ev.data={"id":"0", "type":"setActiveCharacter", "data":charId}; + self.dispatchEvent(ev); + return oldAcid; + }; + const promisifyWorker = (worker, parameters) => { + let acid=getActiveCharacterId(); + let prevAcid=null; + return new Promise((res,rej)=>{ + prevAcid=setActiveCharacterId(acid); + try {if (worker===0) getAttrs(parameters[0]||[],(v)=>res(v)); + else if (worker===1) setAttrs(parameters[0]||{}, parameters[1]||{},(v)=>res(v)); + else if (worker===2) getSectionIDs(parameters[0]||'',(v)=>res(v)); + } catch(err) {rej(console.error(err))} + }).finally(()=>setActiveCharacterId(prevAcid)); + } + return { + getAttrs(attrArray) {return promisifyWorker(0, [attrArray])}, + setAttrs(attrObj, options) {return promisifyWorker(1, [attrObj, options])}, + getSectionIDs(section) {return promisifyWorker(2, [section])}, + setActiveCharacterId, + } +})(); \ No newline at end of file diff --git a/Shadowrun5th/js/importSingleRepeatingWeapon.js b/Shadowrun5th/js/importSingleRepeatingWeapon.js index 91e026cf5d..bd0fd0a731 100644 --- a/Shadowrun5th/js/importSingleRepeatingWeapon.js +++ b/Shadowrun5th/js/importSingleRepeatingWeapon.js @@ -1,14 +1,44 @@ +function provideRepeatingWeaponRowName(weapon) { + + var weaponrow = "weapons"; + + switch(weapon.skill) { + case "Pistols": + weaponrow = weapon.skill.replaceAll(' ', '').toLowerCase(); + break; + case "Automatics": + weaponrow = weapon.skill.replaceAll(' ', '').toLowerCase(); + break; + case "Longarms": + weaponrow = weapon.skill.replaceAll(' ', '').toLowerCase(); + break; + case "Heavy Weapons": + weaponrow = weapon.skill.replaceAll(' ', '').toLowerCase(); + break; + case "Unarmed Combat": + weaponrow = "closecombat" + break; + case "Blades": + weaponrow = "closecombat" + break; + case "Clubs": + weaponrow = "closecombat" + break; + } + + var row = "repeating_" + weaponrow + "_" + generateRowID() + "_"; + + return row; +} + async function importSingleRepeatingWeapon(text, weapon, ammunition, attributes) { - var row = "repeating_weapons" + "_" + generateRowID() + "_"; + var row = provideRepeatingWeaponRowName(weapon); + console.log(row); if(weapon.type == "Ranged"){ attributes[row + "weaponismelee"] = 0; attributes[row + "weaponrc"] = weapon.rc.match(/\d+/g).pop()-Math.ceil((parseInt(attributes.str_base) + parseInt(attributes.str_aug))/3)- 1; - - if(weapon.rawdamage.match(/\d+/) !== null && !weapon.rawdamage.includes("STR")) { - a attributes[row + "weapondv"] = weapon.rawdamage.match(/\d+/)[0]; - } - else if(weapon.rawdamage.includes("STR")) { - attributes[row + "weapondv"] = weapon.damage.match(/\d+/)[0]; + if(!weapon.rawdamage.includes("STR") && weapon.rawdamage.match(/\d+/) !== null) { + attributes[row + "weapondv"] = weapon.rawdamage.match(/\d+/)[0]; } else { attributes[row + "weapondv"] = weapon.damage.match(/\d+/) != null ? weapon.damage.match(/\d+/)[0] : 0; @@ -18,7 +48,7 @@ async function importSingleRepeatingWeapon(text, weapon, ammunition, attributes) }else{ attributes[row + "weaponismelee"] = "on"; attributes[row + "weaponreach"] = weapon.reach; - attributes[row + "weapondv"] = weapon.damage_english.match(/\d+/)[0]; + attributes[row + "weapondv"] = weapon.damage_english.match(/\d+/) != null ? weapon.damage_english.match(/\d+/)[0] : 0; attributes[row + "weapondmgtype"] = weapon.damage_english.match(/S\(e\)|S\b|P|Special\b/) != null ? weapon.damage_english.match(/S\(e\)|S\b|P|Special\b/)[0] : 0; } @@ -105,30 +135,21 @@ async function importSingleRepeatingWeapon(text, weapon, ammunition, attributes) } } } + async function importRepeatingWeaponAmmo(row, ammunition, number, attributes) { attributes[row + "ammoname"+number] = ammo.name; - if(ammo.weaponbonusdamage_english != null && ammo.weaponbonusap != null && ammo.weaponbonusacc != null) { - attributes[row + "ammodv" + number] = ammo.weaponbonusdamage_english.substring(0,2); - attributes[row + "ammodmgtype" + number] = ammo.weaponbonusdamage_english.substring(2); - if(ammo.name_english === "Ammo: Stick-n-Shock") { - attributes[row + "_ammoap" + number] = -5 - attributes[row + "weaponap"] - } - else { - attributes[row + "ammoap" + number] = ammo.weaponbonusap; - } - attributes[row + "ammoacc" + number] = ammo.weaponbonusacc; + attributes[row + "ammodv" + number] = ammo.weaponbonusdamage_english != null ? ammo.weaponbonusdamage_english.substring(0,2) : 0; + if(ammo.weaponbonusdamage_english != null) { + attributes[row + "ammodmgtype" + number] = ammo.weaponbonusdamage_english.substring(2); + } + + if(ammo.name_english === "Ammo: Stick-n-Shock") { + attributes[row + "_ammoap" + number] = -5 - attributes[row + "weaponap"] } else { - attributes[row + "ammodv" + number] = 0; - attributes[row + "ammodmgtype" + number] = 0; - if(ammo.name_english === "Ammo: Stick-n-Shock") { - attributes[row + "ammoap" + number] = -5 - attributes[row + "weaponap"] - } - else { - attributes[row + "ammoap" + number] = 0; - } - attributes[row + "ammoacc" + number] = 0; + attributes[row + "ammoap" + number] = ammo.weaponbonusap != null? ammo.weaponbonusap : 0; } + attributes[row + "ammoacc" + number] = ammo.weaponbonusacc != null ? ammo.weaponbonusacc : 0; } \ No newline at end of file