diff --git a/Shadowrun5th/Shadowrun5th.css b/Shadowrun5th/Shadowrun5th.css index 8501b2a56e..d579dacdea 100644 --- a/Shadowrun5th/Shadowrun5th.css +++ b/Shadowrun5th/Shadowrun5th.css @@ -40,7 +40,6 @@ input[type=number]::-webkit-inner-spin-button { } .tabs .tab{ - margin-left:-11%; text-align:center; color:#eeeeee; background-color: #550000; @@ -1774,6 +1773,8 @@ div.collapsible { color: #aaaaee; font-weight: normal; font-size: 13px; + width: fit-content; + min-width: 25%; } .settings span { @@ -1781,6 +1782,17 @@ div.collapsible { font-size: 13px; } +.sub-settings { + padding-left: 10px; +} + +.setting-select { + width: fit-content; + margin-left: 10px; + padding-left: 10px; + padding-right: 10px; +} + summary{ display:list-item; } @@ -1815,17 +1827,42 @@ label.settings-checkbox { text-align:center; } +.settings-counterstrike { + display: none; +} + +.counterstrikeToggle[value="on"] ~ .settings-counterstrike +{ + display:flex; +} + +.settings-parry { + display: none; +} + +.parryToggle[value="on"] ~ .settings-parry +{ + display:flex; +} + +.settings-riposte { + display: none; +} + +.riposteToggle[value="on"] ~ .settings-riposte +{ + display:flex; +} + .settings select, .settings input[type=number] { - vertical-align:top; background-color:#444444; color:inherit; border:none; box-shadow:none; height:100%; box-sizing:border-box; - margin:0px; text-align:center; } diff --git a/Shadowrun5th/Shadowrun5th.html b/Shadowrun5th/Shadowrun5th.html index 20071be99d..2179958d76 100644 --- a/Shadowrun5th/Shadowrun5th.html +++ b/Shadowrun5th/Shadowrun5th.html @@ -13161,21 +13161,82 @@ Click again to switch to Manual and Remote">
Defense settings -
- - +
+ Melee +
+ + + + +
+ +
+ + + +
-
+ +
+ + +
+ + +
+ + + +
+
@@ -13406,8 +13467,13 @@ Click again to switch to Manual and Remote"> + + + + +
@@ -16992,6 +17058,54 @@ const rollReactDodge = async (ev) => { }); } +///////////////////// +// Melee Defense // +///////////////////// + +on('clicked:reactmelee', async (ev) => { + await rollMelee(ev); +}); +const rollMelee = async (ev) => { + let character = await asw.getAttrs(['character_name']); + let defendOption = await asw.getAttrs(['showBlock', 'showCounterstrike', 'showParry', 'showRiposte']); + + console.log(defendOption); + + if(defendOption.showBlock == "on" && defendOption.showCounterstrike == 0 && defendOption.showParry == 0 && defendOption.showRiposte == 0) { + await rollReactBlock(ev); + return; + } + + if(defendOption.showBlock == 0 && defendOption.showCounterstrike == "on" && defendOption.showParry == 0 && defendOption.showRiposte == 0) { + await rollReactCounterstrike(ev); + return; + } + + if(defendOption.showBlock == 0 && defendOption.showCounterstrike == 0 && defendOption.showParry == "on" && defendOption.showRiposte == 0) { + await rollReactParry(ev); + return; + } + + if(defendOption.showBlock == 0 && defendOption.showCounterstrike == 0 && defendOption.showParry == 0 && defendOption.showRiposte == "on") { + await rollReactRiposte(ev); + return; + } + + let rollBase = `/w ${character.character_name} &{template:meleedefend}{{passthrough=[[0]]}}{{showBlock=[[0]]}}{{showCounterstrike=[[0]]}}{{showParry=[[0]]}}{{showRiposte=[[0]]}}`; + if(defendOption.showBlock == 0 && defendOption.showCounterstrike == 0 && defendOption.showParry == 0 && defendOption.showRiposte == 0) { + rollBase += '{{configuration= Melee Defense is not configured. Set it under Character -> Defense Settings -> Melee}}' + } + let defendRoll = await startRoll(rollBase); + + finishRoll(defendRoll.rollId, { + passthrough: ev.originalRollId, + showBlock: defendOption.showBlock == "on" ? 1 : 0, + showCounterstrike: defendOption.showCounterstrike == "on" ? 1 : 0, + showParry: defendOption.showParry == "on" ? 1 : 0, + showRiposte: defendOption.showRiposte == "on" ? 1 : 0, + }); +} + on('clicked:reactparry', async (ev) => { await rollReactParry(ev); }); @@ -17008,7 +17122,7 @@ const rollReactParry = async (ev) => { let rollBase = `${attrs.gmroll}&{template:reactdefend}{{defend=Parry}}{{nethits=[[0]]}}{{attackAp=[[0]]}}{{attackDamage=[[0]]}}{{attackDmgType=[[0]]}}{{passthrough=[[0]]}}{{name=${attrs.character_name}}}{{attacker_name=${attackRoll.attacker}}}{{rea=[[${attrs.rea_total}}]]}}{{int=[[${attrs.int_total}]]}}{{bonus=[[${attrs.avoid_bonus}]]}}{{skill=${skill[Object.keys(skill)[0]]}}}{{skilldice=[[${skill[Object.keys(skill)[1]]}+${skill[Object.keys(skill)[2]]}]]}}{{mod=[[?{Situational Modifiers|0}]]}}{{edge=${attrs.edgeroll}}}{{edge_num=[[${attrs.edg_total}]]}}{{limit=[[${limit.parryAccuracy}]]}}{{wounds_num=[[${attrs.wound_total}]]}}{{sustainedspells=[[${attrs.sustainedspells}*2]]}}{{result=[[(${attrs.avoid_total}+[[${skill[Object.keys(skill)[1]]}+${skill[Object.keys(skill)[2]]}]]+?{Situational Modifiers}-[[${attrs.wound_total}]]-[[${attrs.sustainedspells}*2]]+[[${attrs.edgn}*${attrs.edg_total}]])${attrs.standardroll}${attrs.edgeroll}kh[[${limit.parryAccuracy}]] ]]}}{{description= -5 Initiative}}`; if(limit.parryAccuracy == 0) { - rollBase += '{{configuration= Set Limit under Character -> Defense Settings}}' + rollBase += '{{configuration= Set Limit under Character -> Defense Settings -> Melee}}' } let defendRoll = await startRoll(rollBase); @@ -17032,6 +17146,69 @@ const rollReactParry = async (ev) => { }); } +on('clicked:reactriposte', async (ev) => { + await rollReactRiposte(ev); +}); +const rollReactRiposte = async (ev) => { + // The data we passed into the button will be stored in the originalRollId key + let attackRoll = rollEscape.unescape(ev.originalRollId); + let attrs = await asw.getAttrs(['gmroll','character_name','rea_total', 'edgeroll','edg_total','wound_total','sustainedspells','edgn','standardroll']); + + let choosenSkill = await asw.getAttrs(['parrySkill']); + let skill = await asw.getAttrs(['skillname' + choosenSkill.parrySkill, 'skillrating' + choosenSkill.parrySkill, 'skillbonus' + choosenSkill.parrySkill]); + let limit = await asw.getAttrs(['parryAccuracy']); + let riposte = await asw.getAttrs(['riposteDamage', 'riposteAp', 'riposteWeaponDmgtype']); + + let rollBase = `${attrs.gmroll}&{template:reactdefend}{{defend=Riposte}}{{nethits=[[0]]}}{{counterhits=[[0]]}}{{attackAp=[[0]]}}{{attackDamage=[[0]]}}{{attackDmgType=[[0]]}}{{passthrough=[[0]]}}{{name=${attrs.character_name}}}{{attacker_name=${attackRoll.attacker}}}{{rea=[[${attrs.rea_total}}]]}}{{skill=${skill[Object.keys(skill)[0]]}}}{{skilldice=[[${skill[Object.keys(skill)[1]]}+${skill[Object.keys(skill)[2]]}]]}}{{mod=[[?{Situational Modifiers|0}]]}}{{edge=${attrs.edgeroll}}}{{edge_num=[[${attrs.edg_total}]]}}{{limit=[[${limit.parryAccuracy}]]}}{{wounds_num=[[${attrs.wound_total}]]}}{{sustainedspells=[[${attrs.sustainedspells}*2]]}}{{result=[[(${attrs.rea_total}+[[${skill[Object.keys(skill)[1]]}+${skill[Object.keys(skill)[2]]}]]+?{Situational Modifiers}-[[${attrs.wound_total}]]-[[${attrs.sustainedspells}*2]]+[[${attrs.edgn}*${attrs.edg_total}]])${attrs.standardroll}${attrs.edgeroll}kh[[${limit.parryAccuracy}]] ]]}}{{description= -7 Initiative, +2 DV taken (already included)}}`; + + if(limit.parryAccuracy == 0 || riposte.riposteDamage == 0) { + rollBase += '{{configuration= Configure Riposte under Character -> Defense Settings -> Melee}}' + } + + let defendRoll = await startRoll(rollBase); + + let defendSuccesses = defendRoll.results.result.result; + let nethits = attackRoll.attackHits - defendSuccesses; + let counterhits = defendSuccesses - attackRoll.attackHits; + + let attackDamage; + if(nethits > counterhits) { + attackDamage = attackRoll.attackDV + nethits + 2; + } else { + attackDamage = parseInt(riposte.riposteDamage) + parseInt(counterhits); + } + + let attackAp; + if(nethits > counterhits) { + attackAp = attackRoll.attackAp; + } else { + attackAp = riposte.riposteAp; + } + + let attackDmgType; + if(nethits > counterhits) { + attackDmgType = attackRoll.attackDmgType; + } else { + attackDmgType = riposte.riposteWeaponDmgtype; + } + + + let rollData = { + attackAp: attackAp, + attackDamage: attackDamage, + attackDmgType: attackDmgType, + } + + finishRoll(defendRoll.rollId, { + nethits: nethits, + counterhits: counterhits, + attackAp: attackAp, + attackDamage: attackDamage, + attackDmgType: attackDmgType, + passthrough: rollEscape.escape(rollData), + }); +} + on('clicked:reactblock', async (ev) => { await rollReactBlock(ev); }); @@ -17064,6 +17241,66 @@ const rollReactBlock = async (ev) => { }); } +on('clicked:reactcounterstrike', async (ev) => { + await rollReactCounterstrike(ev); +}); +const rollReactCounterstrike = async (ev) => { + // The data we passed into the button will be stored in the originalRollId key + let attackRoll = rollEscape.unescape(ev.originalRollId); + let attrs = await asw.getAttrs(['gmroll','character_name','rea_total', 'edgeroll','edg_total','wound_total','sustainedspells','edgn','standardroll']); + let skill = await asw.getAttrs(['skillrating51', 'skillbonus51']); + let limit = await asw.getAttrs(['skilllimitbonus51', 'physical_total']); + let counterstrike = await asw.getAttrs(['counterstrikeDamage', 'counterstrikeAp', 'counterstrikeWeaponDmgtype']); + + let rollBase = `${attrs.gmroll}&{template:reactdefend}{{defend=Block}}{{nethits=[[0]]}}{{counterhits=[[0]]}}{{attackAp=[[0]]}}{{attackDamage=[[0]]}}{{attackDmgType=[[0]]}}{{passthrough=[[0]]}}{{name=${attrs.character_name}}}{{attacker_name=${attackRoll.attacker}}}{{rea=[[${attrs.rea_total}}]]}}{{skill=@{skillname51}}}{{skilldice=[[${skill.skillrating51}+${skill.skillbonus51}]]}}{{mod=[[?{Situational Modifiers|0}]]}}{{edge=${attrs.edgeroll}}}{{edge_num=[[${attrs.edg_total}]]}}{{limit=[[${limit.physical_total}+${limit.skilllimitbonus51}]]}}{{wounds_num=[[${attrs.wound_total}]]}}{{sustainedspells=[[${attrs.sustainedspells}*2]]}}{{result=[[(${attrs.rea_total}+[[${skill.skillrating51}+${skill.skillbonus51}]]+?{Situational Modifiers}-[[${attrs.wound_total}]]-[[${attrs.sustainedspells}*2]]+[[${attrs.edgn}*${attrs.edg_total}]])${attrs.standardroll}${attrs.edgeroll}kh[[${limit.physical_total}+${limit.skilllimitbonus51}]] ]]}}{{description= -7 Initiative}}`; + if(counterstrike.counterstrikeDamage == 0) { + rollBase += '{{configuration= Configure Counterstrike under Character -> Defense Settings -> Melee}}' + } + console.log(rollBase); + let defendRoll = await startRoll(rollBase); + + let defendSuccesses = defendRoll.results.result.result; + let nethits = attackRoll.attackHits - defendSuccesses; + let counterhits = defendSuccesses - attackRoll.attackHits; + + let attackDamage; + if(nethits > counterhits) { + attackDamage = attackRoll.attackDV + nethits + 2; + } else { + attackDamage = parseInt(counterstrike.counterstrikeDamage) + parseInt(counterhits); + } + + let attackAp; + if(nethits > counterhits) { + attackAp = attackRoll.attackAp; + } else { + attackAp = counterstrike.counterstrikeAp; + } + + let attackDmgType; + if(nethits > counterhits) { + attackDmgType = attackRoll.attackDmgType; + } else { + attackDmgType = counterstrike.counterstrikeWeaponDmgtype; + } + + + let rollData = { + attackAp: attackAp, + attackDamage: attackDamage, + attackDmgType: attackDmgType, + } + + finishRoll(defendRoll.rollId, { + nethits: nethits, + counterhits: counterhits, + attackAp: attackAp, + attackDamage: attackDamage, + attackDmgType: attackDmgType, + passthrough: rollEscape.escape(rollData), + }); +} + on('clicked:reactsoak', async (ev) => { await rollReactSoak(ev); }); @@ -17074,7 +17311,8 @@ const rollReactSoak = async (ev) => { let attrs = await asw.getAttrs(['gmroll','character_name','bod_total', 'armor_total', 'soak_bonus', 'edgeroll','edg_total','edgn','standardroll']); //AP only reduces armor - let armorPenetration = attrs.armor_total + dmgRoll.attackAp < 0 ? -attrs.armor_total : dmgRoll.attackAp; + let armorPenetration = parseInt(attrs.armor_total) + parseInt(dmgRoll.attackAp) < 0 ? -attrs.armor_total : dmgRoll.attackAp; + console.log(armorPenetration); if(attrs.armor_total == 0){ armorPenetration = 0; @@ -18078,10 +18316,7 @@ var TAS = TAS || (function(){ [Dodge](~selected|reactdodge||{{computed::passthrough}})
- [Parry](~selected|reactparry||{{computed::passthrough}}) -
-
- [Block](~selected|reactblock||{{computed::passthrough}}) + [Melee](~selected|reactmelee||{{computed::passthrough}})
@@ -18592,9 +18827,11 @@ var TAS = TAS || (function(){ > Reaction({{rea}}) - - > Intuition({{int}}) - + {{#int}} + + > Intuition({{int}}) + + {{/int}} {{#^rollTotal() bonus 0}} > Bonus({{bonus}}) @@ -18650,125 +18887,195 @@ var TAS = TAS || (function(){ {{/edge}} {{^edge}} {{#limit}} - - -
- - - - -
Limit
- - - - -
> Limit({{limit}})
- - + + +
+ + + + +
Limit
+ + + + +
> Limit({{limit}})
+ + {{/limit}} {{/edge}} {{#result}} - - -
- - - - -
Result
- - - {{#rollGreater() result 1}} - - {{result}} Successes - - {{/rollGreater() result 1}} - {{#rollTotal() result 1}} - - {{result}} Success - - {{/rollTotal() result 1}} - {{#rollTotal() result 0}} - - {{result}} Successes - - {{/rollTotal() result 0}} + + +
+ + + + +
Result
+ + + {{#rollGreater() result 1}} + + {{result}} Successes + + {{/rollGreater() result 1}} + {{#rollTotal() result 1}} + + {{result}} Success + + {{/rollTotal() result 1}} + {{#rollTotal() result 0}} + + {{result}} Successes + + {{/rollTotal() result 0}} {{/result}} + {{#nethits}} - - -
- - - - -
Attacker Nethits
- - - {{#rollGreater() computed::nethits 0}} - - {{computed::nethits}} Nethits - - - -
Damage taken
- - - - AP({{computed::attackAp}}) ~ DV({{computed::attackDamage}}{{computed::attackDmgType}}) - - {{/rollGreater() computed::nethits 0}} - {{#^rollGreater() computed::nethits 0}} - - 0 Nethits - - {{/^rollGreater() computed::nethits 0}} + + +
+ + + + +
Attacker Nethits
+ + + {{#rollGreater() computed::nethits 0}} + + {{computed::nethits}} Nethits + + + +
Damage taken
+ + + + AP({{computed::attackAp}}) ~ DV({{computed::attackDamage}}{{computed::attackDmgType}}) + + {{/rollGreater() computed::nethits 0}} + {{#^rollGreater() computed::nethits 0}} + + 0 Nethits + + {{/^rollGreater() computed::nethits 0}} {{/nethits}} + {{#counterhits}} + {{#rollGreater() computed::counterhits 0}} + + +
+ + + + +
Defender Nethits
+ + + + {{computed::counterhits}} Nethits + + + +
Damage taken
+ + + + AP({{computed::attackAp}}) ~ DV({{computed::attackDamage}}{{computed::attackDmgType}}) + + {{/rollGreater() computed::counterhits 0}} + {{/counterhits}} + {{#description}} - - -
- - - - -
Description
- - - - -
{{description}}
- - + + +
+ + + + +
Description
+ + + + +
{{description}}
+ + {{/description}} {{#configuration}} - - -
- - - - -
Configuration
- - - - -
{{configuration}}
- - + + +
+ + + + +
Configuration
+ + + + +
{{configuration}}
+ + {{/configuration}} {{#rollGreater() computed::nethits 0}} + {{#^rollTotal() computed::passthrough 0}} +
+
+ [Soak](~{{name}}|reactsoak||{{computed::passthrough}}) +
+
+ {{/^rollTotal() computed::passthrough 0}} + {{/rollGreater() computed::nethits 0}} + + {{#rollGreater() computed::counterhits 0}} {{#^rollTotal() computed::passthrough 0}}
- [Soak](~{{name}}|reactsoak||{{computed::passthrough}}) + [Counter-Soak](~{{attacker_name}}|reactsoak||{{computed::passthrough}})
{{/^rollTotal() computed::passthrough 0}} - {{/rollGreater() computed::nethits 0}} + {{/rollGreater() computed::counterhits 0}} + + + +
+ {{#configuration}} + {{configuration}} + {{/configuration}} +
+
+ {{#rollGreater() computed::showBlock 0}} +
+ [Block](~selected|reactblock||{{computed::passthrough}}) +
+ {{/rollGreater() computed::showBlock 0}} + + {{#rollGreater() computed::showCounterstrike 0}} +
+ [Counterstrike](~selected|reactcounterstrike||{{computed::passthrough}}) +
+ {{/rollGreater() computed::showCounterstrike 0}} + + {{#rollGreater() computed::showParry 0}} +
+ [Parry](~selected|reactparry||{{computed::passthrough}}) +
+ {{/rollGreater() computed::showParry 0}} + + {{#rollGreater() computed::showRiposte 0}} +
+ [Riposte](~selected|reactriposte||{{computed::passthrough}}) +
+ {{/rollGreater() computed::showRiposte 0}} +