From 7d5455fdfdb7302deeaf50c42f28c50d1f6691ce Mon Sep 17 00:00:00 2001 From: Tobias Date: Tue, 7 Feb 2023 11:29:29 +0100 Subject: [PATCH] - added damage monitor functionality to track stun/phys damage levels and automatically apply ini penalties accordingly - mostly working, but there's now way yet to enter/edit damage levels in the add/edit modal - changed some of the icons --- css/custom.css | 48 ++++++++ img/002-dead-body.png | Bin 750 -> 0 bytes img/003-shooting.png | Bin 580 -> 0 bytes img/{005-add.png => add.png} | Bin img/check.png | Bin 0 -> 411 bytes img/{006-dice.png => dice.png} | Bin img/{004-edit-button.png => edit.png} | Bin img/explosion.png | Bin 0 -> 735 bytes img/{001-refresh.png => refresh.png} | Bin img/skull.png | Bin 0 -> 827 bytes img/zzz.png | Bin 0 -> 719 bytes index.html | 19 ++- js/sr2ini.js | 161 +++++++++++++++++++++----- 13 files changed, 189 insertions(+), 39 deletions(-) delete mode 100644 img/002-dead-body.png delete mode 100644 img/003-shooting.png rename img/{005-add.png => add.png} (100%) create mode 100644 img/check.png rename img/{006-dice.png => dice.png} (100%) rename img/{004-edit-button.png => edit.png} (100%) create mode 100644 img/explosion.png rename img/{001-refresh.png => refresh.png} (100%) create mode 100644 img/skull.png create mode 100644 img/zzz.png diff --git a/css/custom.css b/css/custom.css index 7e9203c..25a011b 100644 --- a/css/custom.css +++ b/css/custom.css @@ -8,3 +8,51 @@ input:invalid { border: 2px solid red; } + +/* Dropdown Content (Hidden by Default) */ +.damage-monitor { + display: none; + position: absolute; + z-index: 20; + + top: 40px; + right: -8px; + width: 60px; +} + +.damage-monitor th { + width: 30px; + height: 30px; + background-color: white; + border: solid darkgray 1px; + padding: 3px; +} + +.damage-monitor td { + width: 30px; + height: 24px; + border: solid darkgray 1px; + font-size: smaller; + user-select: none; + +} +.damage-monitor td::selection { background: none; } +.damage-monitor td::-moz-selection { background: none; } + +td.damage-stun { background-color: cornflowerblue; } +/*td.damage-stun:hover { background-color: steelblue; }*/ +td.damage-stun.selected { background-color: dodgerblue; } +td.damage-physical { background-color: indianred; } +/*td.damage-physical:hover { background-color: coral; }*/ +td.damage-physical.selected { background-color: tomato; } + +/* bgcolors: default, active, hover + phys: darkred, red, tomato, coral, lightcoral, indianred, orangered + stun: cornflowerblue, lightskyblue, mediumlateblue, steelblue, royalblue +*/ + +/* Change color of dropdown links on hover */ +.damage-monitor td:hover { + background-color: gray; +} + diff --git a/img/002-dead-body.png b/img/002-dead-body.png deleted file mode 100644 index 20b4a7bc90f4b4d0c8979cee142241834e40cb9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 750 zcmVL}MN92wE$v3@ zVpA^UQn?^)ZEY#y%AKTev&fc}wne#^okk<923ySBh=gI+c-xhf#gMTV=lM@Rf4~3V zNWM4EbKaiwob#M>9zHN?EAT(YDm=zhjKY&LonaWjOe{xlfsVQ|dIx5t122ibEia*eXCY(t81DKxnZ8`n+w9d!Qv_B^@avGgEzRz$8 z&A5*Jc!<4e9Z}$*wErmG`X@ZXA>6`b+`wY^69;h?-z6g$n^N&RmS9`rH;RMBaR~77PGEq)bsvJH>Jm#?+?-lw)dEdcF)RfsZpugl`auo+V z@Pp{s68i80%WxUTMXK_ch`X7XA(b2~!&T8MdGumxj&8-gGMyIOu9l((tizT9+4V99 zH!-Owg1QPqVuYN;vjW+9k-Gk5yAT@-BIwOTlazNN(Xp2b_;5`$XT7Md2V&IZ(TqD; zg#(C3`=^S$2S1CE&{QBFd;?-?j($f6Z^L-}TXJy2n-4usggz7uc=LD6@UrCK9KOs6 zYsGNu8=`}5e4eA5mHlXSIE?S{wfMCueWzCmg3W-aPb`+5FgPJ g(LWuAp5FJv|4Y@4?*HGN8UO$Q07*qoM6N<$f+tH`?*IS* diff --git a/img/003-shooting.png b/img/003-shooting.png deleted file mode 100644 index 4296651dddfc4aeb1913bd92ca22ffa754734731..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 580 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 SR2 Initiative Tracker
-
+
- + @@ -81,12 +81,11 @@
-
-
- - D+ - -
+
+ + D+ + +
diff --git a/js/sr2ini.js b/js/sr2ini.js index d0e33e9..84baf6e 100644 --- a/js/sr2ini.js +++ b/js/sr2ini.js @@ -2,6 +2,28 @@ * helper functions */ +const penalty = [0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4]; + +const damageMonitorHTML = ['
Name Ini+R+R Actions
\n', + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', +'
00
LL
MM
SS
DD
'].join(""); + + // roll for initiative with the given reaction and number of ini dice function rollForInitiative(dice, rea) { let ini = 0; @@ -62,6 +84,28 @@ function sortTable() { } +// returns a combatant's effective ini value (modified by wound penalties) +function getEffectiveIni(value, dmgLvl1, dmgLvl2) { + let effectiveIni; + + // was function called with 1 argument (tr jQuery object)? + if ( arguments.length == 1 && $(value).is("tr.combatantRow") ) { + let trueIni = parseInt($(value).attr("data-true-ini")); + let dmgStun = parseInt($(value).attr("data-damage-stun")) || 0; + let dmgPhysical = parseInt($(value).attr("data-damage-physical")) || 0; + effectiveIni = trueIni - penalty[dmgStun] - penalty[dmgPhysical]; + } + // or with 3 arguments (ini and dmg levels)? + else if ( arguments.length == 3 ) { + effectiveIni = parseInt(value) - penalty[parseInt(dmgLvl1)] - penalty[parseInt(dmgLvl2)]; + } + // + else { return NaN; } +console.log("effectiveIni is ", effectiveIni); + return effectiveIni < 0 ? 0 : effectiveIni; +} + + /* * Event handler functions */ @@ -70,13 +114,14 @@ function sortTable() { function handleActButtonClick (e) { // find current table row let $tr = $(e.target).parents(".combatantRow"); - let ini = $tr.find(".combatantIni").text(); + let ini = $tr.attr("data-true-ini"); // reduce ini by 10 but not lower than 0 ini = Math.max(parseInt(ini) - 10, 0); // set new ini value - $tr.find(".combatantIni").text(ini); + $tr.attr("data-true-ini", ini); + $tr.find(".combatantIni").text(getEffectiveIni($tr)); // resort table sortTable(); @@ -103,12 +148,49 @@ function handleAddButtonClick (e) { $("#combatantModal").modal("show"); } - -function handleDamageButtonHover (e) { - +// click handler for damage buttons +function handleDamageButtonClick (e) { + let display = $(e.target).parents(".damage-dropdown").find(".damage-monitor").css("display"); + $(e.target).parents(".damage-dropdown").find(".damage-monitor").css("display", display == "block" ? "none" : "block"); + return false; } +// click handler for damage monitor fields +function handleDamageMonitorClick (e) { + let $td = $(e.target); + let $tr = $td.parents("tr.combatantRow"); + let damageType; + let otherDamageLevel + + // calculate new damage level and type + let damageLevel = $td.parent().index(); + if ( $td.hasClass("damage-stun") ) { + damageType = "stun"; + otherDamageLevel = $tr.attr("data-damage-physical") ? parseInt($tr.attr("data-damage-physical")) : 0; + } else if ( $td.hasClass("damage-physical") ) { + damageType = "physical"; + otherDamageLevel = $tr.attr("data-damage-stun") ? parseInt($tr.attr("data-damage-stun")) : 0; + } else { + return false; + } + + // add damage level to table row as as data attribute + $tr.attr("data-damage-" + damageType, damageLevel); + + // select/unselect damage boxes + $td.addClass("selected"); + $td.parent().nextAll().children("td.damage-" + damageType).removeClass("selected"); + $td.parent().prevAll().children("td.damage-" + damageType).addClass("selected"); + + // recalculate effective ini and resort + $tr.find(".combatantIni").text(getEffectiveIni($tr)); + sortTable(); + + + return false; +} + // click handler for edit buttons function handleEditButtonClick (e) { // find current table row @@ -123,7 +205,8 @@ function handleEditButtonClick (e) { $("#combatantModalName").val($tr.find(".combatantName").text()); $("#combatantModalDice").val($tr.find(".combatantDice").text()); $("#combatantModalRea").val($tr.find(".combatantRea").text()); - $("#combatantModalIni").val($tr.find(".combatantIni").text()); + $("#combatantModalIni").val($tr.attr("data-true-ini")); + //TODO: show effective ini in modal // mark which row is being edited $("#combatantModal").attr("data-row", $(".combatantRow").index($tr)); @@ -223,34 +306,48 @@ function addCombatant (e) { let ini = $("#combatantModalIni").val().trim(); let dice = $("#combatantModalDice").val().trim(); let rea = $("#combatantModalRea").val().trim(); + //TODO: retrieve initial damage levels - // roll for initiative if ini is empty + // roll for initiative if necessary ini = (ini != "") ? ini : rollForInitiative(dice, rea); + // TODO: actually calculate effective ini + let effectiveIni = getEffectiveIni(ini, 0, 0); +console.log("effective ini = ", effectiveIni); + // construct jQuery object for table row let $tr = $($.parseHTML( [ - '\n', - '', name, '\n', - '', ini, '\n', - '', dice, 'D+', rea, '\n', - '\n', - '
\n', - '\n', - '\n', - '\n', - '
\n', - '\n', - ''].join("") +'\n', //TODO: add data-damage-* attributes with initial damage levels + '', name, '\n', + '', effectiveIni, '\n', + '', dice, 'D+', rea, '\n', + '\n', + '
\n', + '\n', + '\n', + '
\n', + '\n', + damageMonitorHTML + "\n", + '
\n', + '
\n', + '\n', +''].join("") )); +//TODO: mark initial damage levels with .selected class + // add handlers to table row buttons $tr.find("button.edit-button").on("click", handleEditButtonClick); $tr.find("button.act-button").on("click", handleActButtonClick); $tr.find("button.remove-button").on("click", handleRemoveButtonClick); + $tr.find("button.damage-button").on("click", handleDamageButtonClick); - // add handlers to table cells (click to edit) + // add handler to table cells (click to edit) $tr.find(".combatantName, .combatantIni, .combatantDiceAndRea").on("click", handleEditButtonClick); + // add handler to damage monitor + $tr.find(".damage-stun, .damage-physical").on("click", handleDamageMonitorClick); + // add row to table and sort $("#combatantsTable").append($tr); sortTable(); @@ -286,7 +383,8 @@ function editCombatant (e) { $tr.find(".combatantName").text(name); $tr.find(".combatantDice").text(dice); $tr.find(".combatantRea").text(rea); - $tr.find(".combatantIni").text(ini); + $tr.attr("data-true-ini", ini); + $tr.find(".combatantIni").text(getEffectiveIni($tr)); // sort table sortTable(); @@ -305,13 +403,14 @@ function newRound() { // reset ini values $(".combatantRow").each( function() { - let $ini = $(this).find(".combatantIni"); - let $dice = $(this).find(".combatantDice"); - if ( $dice.text() == "" ) { - $ini.text(1); + let effectiveIni = $(this).find(".combatantIni").text(); + let dice = $(this).find(".combatantDice").text(); + if ( dice == "" ) { + $(this).attr("data-true-ini", "1"); } else { - $ini.text(rollForInitiative($dice.text(), $(this).find(".combatantRea").text())); + $(this).attr("data-true-ini", rollForInitiative(dice, $(this).find(".combatantRea").text())); } + $(this).find(".combatantIni").text(getEffectiveIni($(this))); }); // resort table @@ -348,12 +447,16 @@ $(document).ready(function(){ // always focus name input field when combatant modal appears $('#combatantModal').on('shown.bs.modal', function() { $('#combatantModalName').focus(); - }) - + }); // always empty input fields when combatant modal disappears $("#combatantModal").on('hidden.bs.modal', function (e) { $("#combatantModal input[id*='combatantModal']").val(""); - }) + }); + + // Hide damage monitors if mouse is clicked outside + $("html").on("click", function(e) { + $(".damage-monitor:visible").css("display", "none"); + }); addTestCombatant();