- started a complete redesign
- removed zero-row from damage monitor; damage buttons now toggle - added decreasing z-indexes on sorted combatant-rows to mitigate a weird bug where damage monitors would be displayed under instead of over the rows
This commit is contained in:
parent
43a9aef8b1
commit
cb36ae4159
67
TODO.md
Normal file
67
TODO.md
Normal file
@ -0,0 +1,67 @@
|
||||
% sr2ini: Bugs and Features Tracker
|
||||
% Eclipse
|
||||
%
|
||||
|
||||
(Nichts hier ist in "master" gefixt)
|
||||
|
||||
# Bugs
|
||||
|
||||
- x Bug: KO/dead buttons fkt. nicht
|
||||
- applyDamage, ersetze erste Zeile: let $btn = $(e.target).is("button") ? $(e.target) : $(e.target).parents("button")[0];
|
||||
- x Bug: Kann nicht weit genug runterscrollen für remove bzw die unteren schadenskastchen
|
||||
- Footer hatte viel zu großen z-index
|
||||
- x Bug: resort after remove -> einfach eingefügt
|
||||
- x background-image wiederholt sich -> hat sich nach Redesign erledigt
|
||||
- x Habe alle $("…").modal("hide|show") eliminiert; die Sichtbarkeit der Modals wird jetzt ausschließlich durch data-bs-Attribute gesteuert
|
||||
- x add-Button leert die inputs vom Modal nicht mehr
|
||||
- event hidden.bs.modal feuert nicht mehr
|
||||
- zuerst dachte ich, es liegt daran, dass ich das bootstrap js zu Klasse Modal nicht laden konnte. Mittlerweile habe ich es hingekriegr, doch das event feuert trotzdem nicht
|
||||
- hab's hingekriegt, indem ich jquery und bootstrap nun doch wieder in der index.html lade und nicht mehr als import.
|
||||
- x in großer Darstellung bleiben u.U. links und rechts Ränder frei, wo das Hintergrundbild nicht skaliert wird -> background-size: cover
|
||||
- x bei Benutzung von augmented-ui: der Text von .combatant-name ist nach oben verschoben und links+rechts abgeschnitten
|
||||
- grundlegendes Problem: augmented-ui nutzt ::before und ::after, um die Styles zu erzeugen; mein eigenes ::before kollidiert damit
|
||||
- füge den .combatant-name jetzt wieder direkt ein, nicht mehr per Datenattribut
|
||||
- x damit nirgendwo ein Stück border fehlt, müssen die Ecken von zwei benachbarten combatant tablerows nicht gegeneinander verschoben sein
|
||||
- d.h. die beiden linken und die beiden rechten Ecken einer Tablerow müssen jeweils die gleiche X-Position haben
|
||||
- x alles, was vom damage monitor über den unteren Tabellenrand rüberragt, wird abgeschnitten
|
||||
- musste den clip-path von tr und td auf none setzen
|
||||
|
||||
- jetzt kann ich den damage-monitor zwar aufklappen, aber die Buttons der weiter unten liegenden combatant-rows überdecken ihn jedesmal.
|
||||
- wenn ich einen Damage-Button anklicke, beginnt die Transition des damage-monitor von Neuem
|
||||
- Output vom HTML Validator:
|
||||
- img elements müssen alt attributes haben
|
||||
- The form attribute must refer to a form element. (bei den Input Elementen im combatant-modal) -> muss nachsehen, was ich dann genau da eintragen muss
|
||||
- wenn die Navbar borders hat, sollte sie nicht direkt am oberen Bildrand anfangen, sondern ein paar Pixel weiter unten
|
||||
- nach dem Laden passiert es manchmal, dass nach dem Einfügen von testCombatant das add Modal gleich wieder aufgeht
|
||||
- schien die gleiche Sache zu sein wie mit dem hidden.bs.modal event
|
||||
- jetzt kommt es aber trotzdem manchmal wieder
|
||||
- vllt. ein timeout-Problem?
|
||||
- add modal geht bei enter key nicht zu -> liegt daran, dass ich nicht mehr .modal("hide") verwende
|
||||
- ich könnt's umstellen, aber will ich das?
|
||||
- Unterschied zwischen enabled und disabled button nicht gut erkennbar
|
||||
- wenn ein damage monitor offen ist und ich auf add combatant clicke, springt der Fokus nicht zuverlässig ins erste input feld
|
||||
- navbar bei größerem viewport
|
||||
- brand-name nicht mittig
|
||||
- Bug: rea editieren ändert nicht die ini -> da muss ich die Würfelergebnisse für speichern
|
||||
|
||||
|
||||
|
||||
# Feature Requests
|
||||
|
||||
- x nochmal wg. Daten wie name, dice, rea, true-ini und damage-x:
|
||||
- Verwalte sie jetzt komplett mit der data-* API; verwende dafür ausschließlich .attr() als Getter/Setter
|
||||
- Füge die Werte aus dem Attribut per CSS direkt ins Element ein (::after und content).
|
||||
- x prettify code: alle HTML class names von camelCale zu dash-case komvertieren
|
||||
- neue Icons: act add cross damage dice edit newround trash zzz clone
|
||||
- attribution
|
||||
- noun project: Icons by Febrian Hidayat from <a href="https://thenounproject.com/icons" target="_blank" title="Icons">Noun Project</a>
|
||||
- iconfinder: CC4.0
|
||||
- icons8.com:
|
||||
- Im modal, wenn ich die wound penalties anzeige, die Fälle KO und Tod gesondert behandeln
|
||||
- im modal soll man die damage levels einstellen/verändern können
|
||||
- "clone this combatant" button:
|
||||
- Anzeige, wieviele Aktionen einer hat u.d wieviele davon schon verbraucht sind
|
||||
- Design cyberpunkig machen
|
||||
- docstrings
|
||||
- color converter für CSS filter(): https://isotropic.co/tool/hex-color-to-css-filter/
|
||||
|
||||
@ -1,19 +1,190 @@
|
||||
$sr-border: cyan;
|
||||
$sr2-btn: darkcyan;
|
||||
$sr2-fg: deeppink;
|
||||
|
||||
@mixin aug() {
|
||||
--aug-tl: 5px;
|
||||
--aug-l: 5px;
|
||||
--aug-bl: 5px;
|
||||
--aug-tr: 5px;
|
||||
--aug-r: 5px;
|
||||
--aug-br: 5px;
|
||||
}
|
||||
|
||||
@mixin border() {
|
||||
--aug-border-bg: cyan; // "sr2-border doesn't work"
|
||||
--aug-border-opacity: .5;
|
||||
--aug-border-left: 2px;
|
||||
--aug-border-right: 0px;
|
||||
--aug-border-top: 2px;
|
||||
--aug-border-bottom: 0px;
|
||||
}
|
||||
|
||||
@mixin inlay() {
|
||||
--aug-inlay-y: 10%;
|
||||
--aug-inlay-bg: rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
@mixin button() {
|
||||
border: 0;
|
||||
border-radius: none;;
|
||||
background: radial-gradient(circle at center, gold, goldenrod);
|
||||
box-shadow: 0 0 3px gold, 0 0 6px goldenrod, 0 0 12px darkgoldenrod;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
// overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3)), url("../img/circuit_board_by_xxaries1970xx_d9ut9nd.jpg");
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-color: darkslategray;
|
||||
font-family: 'Electrolize', sans-serif !important;
|
||||
|
||||
}
|
||||
|
||||
header.navbar {
|
||||
background-image: url("../img/horizon.png");
|
||||
@include border;
|
||||
--aug-br: 10px;
|
||||
--aug-tl: 10px;
|
||||
--aug-inlay-bg: rgba(0, 0, 0, .3);
|
||||
}
|
||||
|
||||
span.navbar-brand {
|
||||
position: absolute;
|
||||
right: 110px;
|
||||
text-shadow: 2px 0 0 #fff, -2px 0 0 #fff, 0 2px 0 #fff, 0 -2px 0 #fff, 1px 1px #fff, -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff;
|
||||
// position: absolute;
|
||||
// right: 110px;
|
||||
// color: $sr2-fg;
|
||||
// text-shadow: 2px 0 0 #fff, -2px 0 0 #fff, 0 2px 0 #fff, 0 -2px 0 #fff, 1px 1px #fff, -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff;
|
||||
}
|
||||
|
||||
header .btn {
|
||||
--aug-all-width: "42px";
|
||||
div.container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
input:invalid {
|
||||
border: 2px solid red;
|
||||
#combatants-table {
|
||||
margin-top: .5rem;
|
||||
|
||||
tr {
|
||||
@include aug;
|
||||
@include border;
|
||||
@include inlay;
|
||||
}
|
||||
|
||||
.combatant-row {
|
||||
clip-path: none;
|
||||
}
|
||||
|
||||
.th-ini {
|
||||
min-width: 3rem;
|
||||
}
|
||||
.th-dice-and-rea {
|
||||
min-width: 3.75rem;
|
||||
}
|
||||
.th-actions {
|
||||
min-width: 6.5rem;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
@include aug;
|
||||
@include border;
|
||||
@include inlay;
|
||||
background: none !important;
|
||||
// text-shadow: 2px 2px 3px black;
|
||||
}
|
||||
|
||||
th {
|
||||
color: cyan;
|
||||
text-transform: uppercase;
|
||||
// text-shadow: 0 0 3px deeppink, 0 0 6px deeppink, 0 0 12px deeppink, 0 0 24 deeppink;
|
||||
}
|
||||
|
||||
td {
|
||||
color: $sr2-fg;
|
||||
clip-path: none;
|
||||
}
|
||||
|
||||
th:first-of-type,
|
||||
td:first-of-type {
|
||||
padding-left: 1rem !important;
|
||||
}
|
||||
|
||||
th:last-of-type,
|
||||
td:last-of-type {
|
||||
padding-right: .75rem;
|
||||
--aug-border-right: 2px;
|
||||
}
|
||||
|
||||
td.combatant-actions {
|
||||
}
|
||||
|
||||
tr:last-of-type td {
|
||||
--aug-border-bottom: 2px;
|
||||
}
|
||||
|
||||
> tbody > tr > td > button,
|
||||
> tbody > tr > td > div > button, {
|
||||
padding: 0px;
|
||||
padding-right: 2px;
|
||||
padding-left: 2px;
|
||||
|
||||
@include button;
|
||||
|
||||
img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
// filter: invert(34%) sepia(78%) saturate(7014%) hue-rotate(316deg) brightness(75%) contrast(105%) drop-shadow(1 1 1px cyan) drop-shadow(2 2 2px darkcyan);
|
||||
// animation: glitch 1s ease infinite;
|
||||
}
|
||||
|
||||
/* @keyframes glitch {
|
||||
// twitch
|
||||
0%, 33% {
|
||||
transform: scale(.97, 1.01);
|
||||
}
|
||||
18%, 60% {
|
||||
transform: scaleX(.98),
|
||||
}
|
||||
48%, 76% {
|
||||
transform: scaleY(1.02);
|
||||
}
|
||||
68%, 100% {
|
||||
transform: scale(1, .96);
|
||||
}
|
||||
|
||||
// skew
|
||||
20%, 75% {
|
||||
transform: skew(2deg);
|
||||
}
|
||||
12%,80%{
|
||||
transform: skew(1.4deg);
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-of-type(2) img {
|
||||
animation-direction: reverse;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
.combatant-ini {
|
||||
text-align: center;
|
||||
padding-right: 1rem !important;
|
||||
}
|
||||
|
||||
.combatant-dice::before {
|
||||
content: attr(data-combatant-dice);
|
||||
}
|
||||
|
||||
.combatant-rea::before {
|
||||
content: attr(data-combatant-rea);
|
||||
}
|
||||
|
||||
.ko-or-dead {
|
||||
@ -22,61 +193,93 @@ input:invalid {
|
||||
background-color: darkslategray;
|
||||
}
|
||||
|
||||
.table-primary {
|
||||
.max-ini {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.combatant-name::after {
|
||||
content: attr(data-combatant-name);
|
||||
}
|
||||
|
||||
.combatant-dice::after {
|
||||
content: attr(data-combatant-dice);
|
||||
}
|
||||
|
||||
.combatant-rea::after {
|
||||
content: attr(data-combatant-rea);
|
||||
.zero-ini td {
|
||||
color: lightgray !important;
|
||||
}
|
||||
|
||||
.badge.bg-warning {
|
||||
background: radial-gradient(circle at center, cyan, darkcyan);
|
||||
|
||||
left: 12px;
|
||||
bottom: -4px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.badge.bg-danger {
|
||||
background: radial-gradient(circle at center, deeppink, maroon);
|
||||
|
||||
left: 12px;
|
||||
top: 12px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.damage-dropdown {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.damage-monitor {
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
top: 100%;
|
||||
right: -8px;
|
||||
width: 60px;
|
||||
z-index: 200;
|
||||
|
||||
th {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 3px;
|
||||
}
|
||||
top: calc(100% - 2px);
|
||||
right: 10px;
|
||||
|
||||
td {
|
||||
width: 30px;
|
||||
height: 24px;
|
||||
}
|
||||
@include aug;
|
||||
|
||||
--aug-inlay-bg: rgba(0, 0, 0, .5);
|
||||
|
||||
--aug-border-all: 2px;
|
||||
--aug-border-bg: cyan; // "sr2-border doesn't work"
|
||||
--aug-border-opacity: .75;
|
||||
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
|
||||
button {
|
||||
|
||||
font-size: smaller;
|
||||
width: 30px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 2px;
|
||||
|
||||
border: none;
|
||||
margin: 0px 2px;
|
||||
border-radius: none;
|
||||
}
|
||||
|
||||
button.active {
|
||||
filter: brightness(88%);
|
||||
.damage-stun {
|
||||
background: radial-gradient(circle at center, cyan, darkcyan);
|
||||
box-shadow: none;
|
||||
transition: background .5s, box-shadow .5s;
|
||||
}
|
||||
|
||||
.damage-stun.active {
|
||||
background: radial-gradient(circle at center, lightcyan, cyan);
|
||||
box-shadow: 0 0 3px lightcyan, 0 0 6px cyan, 0 0 12px darkcyan;
|
||||
}
|
||||
|
||||
.damage-physical {
|
||||
border-radius: 50%;;
|
||||
background: radial-gradient(circle at center, deeppink, maroon);
|
||||
box-shadow: none;
|
||||
transition: background .5s, box-shadow .5s;
|
||||
}
|
||||
|
||||
.damage-physical.active {
|
||||
background: radial-gradient(circle at center, lightpink, deeppink);
|
||||
box-shadow: 0 0 3px lightpink, 0 0 6px deeppink, 0 0 12px maroon;
|
||||
}
|
||||
|
||||
.remove-button {
|
||||
width: 56px;
|
||||
height: 28px;
|
||||
margin-top: 4px;
|
||||
@include button;
|
||||
// background: radial-gradient(circle at center, gold, goldenrod);
|
||||
// box-shadow: 0 0 3px gold, 0 0 6px goldenrod, 0 0 12px darkgoldenrod;
|
||||
}
|
||||
|
||||
td button img {
|
||||
@ -86,6 +289,33 @@ input:invalid {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
.damage-monitor.d-none {
|
||||
opacity: 0;
|
||||
animation-name: dmg-mon;
|
||||
animation-duration: 1s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
|
||||
.damage-monitor:not(.d-none) {
|
||||
opacity: 1;
|
||||
animation-name: dmg-mon;
|
||||
animation-duration: 1s;
|
||||
animation-direction: normal;
|
||||
}
|
||||
|
||||
@keyframes dmg-mon {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
1% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
footer {
|
||||
z-index: -10 !important;
|
||||
|
||||
@ -98,3 +328,83 @@ footer {
|
||||
margin: .5rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
input:invalid {
|
||||
border: 2px solid red;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
th span{
|
||||
position: absolute;
|
||||
display: block;
|
||||
}
|
||||
th span:nth-child(1){
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg,transparent,darkcyan);
|
||||
animation: animate1 1s linear infinite;
|
||||
}
|
||||
@keyframes animate1{
|
||||
0%{
|
||||
left: -100%;
|
||||
}
|
||||
50%,100%{
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
th span:nth-child(2){
|
||||
top: -100%;
|
||||
right: 0;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background: linear-gradient(180deg,transparent,darkcyan);
|
||||
animation: animate2 1s linear infinite;
|
||||
animation-delay: 0.25s;
|
||||
}
|
||||
@keyframes animate2{
|
||||
0%{
|
||||
top: -100%;
|
||||
}
|
||||
50%,100%{
|
||||
top: 100%;
|
||||
}
|
||||
}
|
||||
th span:nth-child(3){
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: linear-gradient(270deg,transparent,darkcyan);
|
||||
animation: animate3 1s linear infinite;
|
||||
animation-delay: 0.50s;
|
||||
}
|
||||
@keyframes animate3{
|
||||
0%{
|
||||
right: -100%;
|
||||
}
|
||||
50%,100%{
|
||||
right: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
th span:nth-child(4){
|
||||
bottom: -100%;
|
||||
left: 0;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background: linear-gradient(360deg,transparent,darkcyan);
|
||||
animation: animate4 1s linear infinite;
|
||||
animation-delay: 0.75s;
|
||||
}
|
||||
@keyframes animate4{
|
||||
0%{
|
||||
bottom: -100%;
|
||||
}
|
||||
50%,100%{
|
||||
bottom: 100%;
|
||||
}
|
||||
}*/
|
||||
BIN
src/img/001-edit.png
Normal file
BIN
src/img/001-edit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 396 B |
BIN
src/img/002-act.png
Normal file
BIN
src/img/002-act.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 628 B |
BIN
src/img/003-damage.png
Normal file
BIN
src/img/003-damage.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 223 B |
BIN
src/img/circuit_board_by_xxaries1970xx_d9ut9nd.jpg
Normal file
BIN
src/img/circuit_board_by_xxaries1970xx_d9ut9nd.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 47 KiB |
@ -11,32 +11,37 @@
|
||||
<!-- Style sheets -->
|
||||
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@latest/dist/css/bootstrap.min.css" >
|
||||
<link type="text/css" rel="stylesheet" href="https://unpkg.com/augmented-ui@latest/augmented-ui.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="css/custom.scss" />
|
||||
<link type="text/css" rel="stylesheet" href="css/custom.scss">
|
||||
|
||||
<!-- javascript files -->
|
||||
<script type="module" src="https://cdn.jsdelivr.net/npm/bootstrap@latest/dist/js/bootstrap.min.js"></script>
|
||||
<script type="module" src="https://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
|
||||
<script type="module" src="js/sr2ini.js" type="text/javascript"></script>
|
||||
<script type="module" src="https://code.jquery.com/jquery-latest.min.js"></script>
|
||||
<script type="module" src="js/sr2ini.js"></script>
|
||||
|
||||
<!-- web font -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Electrolize&display=swap" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<header class="navbar navbar-expand">
|
||||
<header class="navbar navbar-expand" data-augmented-ui="tl-clip-y br-clip-y both">
|
||||
<span class="navbar-brand text-bold ps-4">SR2 Initiative Tracker</span>
|
||||
<nav class="container-fluid justify-content-end" aria-label="Main navigation">
|
||||
<button type="submit" class="btn btn-light btn-rounded mx-1 p-1" id="add-combatant-button" title="Add combatant" data-bs-toggle="modal" data-bs-target="#combatant-modal"><img src="img/add.png" /></button>
|
||||
<button type="submit" class="btn btn-light btn-rounded mx-1 p-1" id="new-round-button" data-bs-toggle="modal" data-bs-target="#confirm-modal" title="Start new round"><img src="img/newround.png" /></button>
|
||||
<button type="submit" class="" id="add-combatant-button" title="Add combatant" data-bs-toggle="modal" data-bs-target="#combatant-modal"><img src="img/add.png"></button>
|
||||
<button type="submit" class="" id="new-round-button" data-bs-toggle="modal" data-bs-target="#confirm-modal" title="Start new round"><img src="img/newround.png"></button>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="table-responsive overflow-visible">
|
||||
<table class="table table-sm" id="combatants-table">
|
||||
<table class="table table-sm table-borderless" id="combatants-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-4 text-start" title="Name">Name</th>
|
||||
<th class="col-2 text-center" title="Initiative">Ini</th>
|
||||
<th class="col-2 text-center" title="Initiative Dice and Reaction"><img src="img/dice.png" />+R</th>
|
||||
<th class="col-4 text-center" title="Actions">Actions</th>
|
||||
<tr data-augmented-ui="tl-2-clip-y r-clip-y">
|
||||
<th class="col text-start th-name" data-augmented-ui="tl-2-clip-y both" title="Name">Name</th>
|
||||
<th class="col-2 text-center th-ini" data-augmented-ui="both" title="Initiative">Ini</th>
|
||||
<th class="col-2 text-center th-dice-and-rea" data-augmented-ui="both" title="Initiative Dice and Reaction"><img src="img/dice.png">+R</th>
|
||||
<th class="col-3 text-center th-actions" data-augmented-ui="r-clip-y both" title="Actions">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -74,15 +79,15 @@
|
||||
<div class="modal-body">
|
||||
<form id="combatant-form" name="combatant-modal-form" class="was-validated" onsubmit="return false;">
|
||||
<div class="my-2">
|
||||
<input type="text" maxlength="40" class="form-control form-control-sm" id="combatant-modal-name" form="combatant-modal-form" placeholder="Name" required />
|
||||
<input type="text" maxlength="40" class="form-control form-control-sm" id="combatant-modal-name" form="#combatant-modal-form" placeholder="Name" required>
|
||||
</div>
|
||||
<div class="input-group input-group-sm my-2">
|
||||
<input type="number" min="1" max="5" class="form-control form-control-sm" id="combatant-modal-dice" form="combatant-modal-form" placeholder="Dice" />
|
||||
<input type="number" min="1" max="5" class="form-control form-control-sm" id="combatant-modal-dice" form="#combatant-modal-form" placeholder="Dice">
|
||||
<span class="input-group-text">D+</span>
|
||||
<input type="number" min="1" max="25" class="form-control form-control-sm" id="combatant-modal-rea" form="combatant-modal-form" placeholder="REA" />
|
||||
<input type="number" min="1" max="25" class="form-control form-control-sm" id="combatant-modal-rea" form="#combatant-modal-form" placeholder="REA">
|
||||
</div>
|
||||
<div class="my-2">
|
||||
<input type="number" min="0" max="55" class="form-control form-control-sm" id="combatant-modal-ini" form="combatant-modal-form" placeholder="Ini" />
|
||||
<input type="number" min="0" max="55" class="form-control form-control-sm" id="combatant-modal-ini" form="#combatant-modal-form" placeholder="Ini">
|
||||
<label for="combatant-modal-ini" class="form-label">Wound penalties: -<span id="penalty-stun">0</span> (stun) and -<span id="penalty-physical">0</span> (physical)</label>
|
||||
</div>
|
||||
</form>
|
||||
@ -98,9 +103,9 @@
|
||||
|
||||
<div class="container">
|
||||
<footer class="footer fixed-bottom bg-light">
|
||||
<hr />
|
||||
<p class="text-center text-muted">code & design by <a href="https://tobias-radloff.de/">Eclipse</a> | Shadowrun trademarked by <a href="https://www.topps.com/">Topps</a></br>
|
||||
icons by <a href="https://www.freepik.com" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> | banner image from <a href="https://www.pinterest.ph/artstation/">Artstation-HQ</a></p>
|
||||
<hr>
|
||||
<p class="text-center text-muted">code & design by <a href="https://tobias-radloff.de/">Eclipse</a> | Shadowrun trademarked by <a href="https://www.topps.com/">Topps</a><br>
|
||||
icons by <a href="https://www.freepik.com" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> | background by <a href="https://www.deviantart.com/xxaries1970xx">xxAries1970xx</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
@ -4,46 +4,34 @@
|
||||
const DAMAGE_PENALTY = [0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4];
|
||||
const DAMAGE_NIVEAU = ["", "L", "M", "S", "D"];
|
||||
const COMBATANT_TABLE_ROW = [
|
||||
'<tr class="combatant-row align-middle" data-true-ini="">\n', //TODO: add data-damage-* attributes with initial damage levels
|
||||
'<td class="combatant-name" title="Combatant\'s name" data-bs-toggle="modal" data-bs-target="#combatant-modal"></td>\n',
|
||||
'<td class="combatant-ini text-center" title="Effective initiative (w/ wound penalties)" data-bs-toggle="modal" data-bs-target="#combatant-modal"></td>\n',
|
||||
'<td class="text-center combatant-dice-and-rea" title="Iniative dice and reaction" data-bs-toggle="modal" data-bs-target="#combatant-modal"><span class="combatant-dice"></span>D+<span class="combatant-rea"></span></td>\n',
|
||||
'<td class="text-end">\n',
|
||||
'<div class="btn-group">\n',
|
||||
'<button type="button" class="btn btn-light btn-rounded mx-1 p-1 edit-button" title="Edit combatant\'s values" data-bs-toggle="modal" data-bs-target="#combatant-modal"><img src="edit.png" /></button>\n',
|
||||
'<button type="button" class="btn btn-light btn-rounded mx-1 p-1 act-button" title="Act and reduce ini by 10"><img src="act.png" /></button>\n',
|
||||
'<div class="damage-dropdown">\n',
|
||||
'<button type="button" class="btn btn-light btn-rounded mx-1 p-1 damage-button" title="Take damage"><img src="damage.png" /></button>\n',
|
||||
'</div>\n',
|
||||
'<tr class="combatant-row align-middle" data-true-ini="" data-augmented-ui="tl-scoop bl-clip-y tr-clip-y br-scoop">\n', //TODO: add data-damage-* attributes with initial damage levels
|
||||
'<td class="combatant-name" title="Combatant\'s name" data-bs-toggle="modal" data-bs-target="#combatant-modal" data-augmented-ui="tl-scoop bl-clip-y both">Test</td>\n',
|
||||
'<td class="combatant-ini" title="Effective initiative (w/ wound penalties)" data-bs-toggle="modal" data-bs-target="#combatant-modal" data-augmented-ui="both"></td>\n',
|
||||
'<td class="text-center combatant-dice-and-rea" title="Iniative dice and reaction" data-bs-toggle="modal" data-bs-target="#combatant-modal" data-augmented-ui="both"><span class="combatant-dice"></span>D+<span class="combatant-rea"></span></td>\n',
|
||||
'<td class="combatant-actions text-end" data-augmented-ui="tr-clip-y br-scoop both">\n',
|
||||
'<button type="button" class="edit-button" title="Edit combatant\'s values" data-bs-toggle="modal" data-bs-target="#combatant-modal"><img src="001-edit.png"/></button>\n',
|
||||
'<button type="button" class="act-button" title="Act and reduce ini by 10"><img src="002-act.png"/></button>\n',
|
||||
'<div class="damage-dropdown">\n',
|
||||
'<button type="button" class="damage-button" title="Take damage" ><img src="003-damage.png"/></button>\n',
|
||||
'</div>\n',
|
||||
'</td>\n',
|
||||
'</tr>'].join("");
|
||||
const DAMAGE_MONITOR_HTML = [
|
||||
'<table class="bg-light damage-monitor text-center align-middle d-none">\n',
|
||||
'<tr>\n',
|
||||
'<td><button class="btn btn-sm btn-warning damage-stun active" title="+/-0">0</button></td>\n',
|
||||
'<td><button class="btn btn-sm btn-danger damage-physical active" title="+/-0">0</button></td>\n',
|
||||
'</tr>\n',
|
||||
'<tr><td><button class="btn btn-sm btn-warning damage-stun" title="Light stun damage">L</button></td><td><button class="btn btn-sm btn-danger damage-physical" title="Light physical damage">L</button></td></tr>\n',
|
||||
'<tr><td><button class="btn btn-sm btn-warning damage-stun"></button></td><td><button class="btn btn-sm btn-danger damage-physical"></button></td></tr>\n',
|
||||
'<tr><td><button class="btn btn-sm btn-warning damage-stun" title="Medium stun damage">M</button></td><td><button class="btn btn-sm btn-danger damage-physical" title="Medium physical damage">M</button></td></tr>\n',
|
||||
'<tr><td><button class="btn btn-sm btn-warning damage-stun"></button></td><td><button class="btn btn-sm btn-danger damage-physical"></button></td></tr>\n',
|
||||
'<tr><td><button class="btn btn-sm btn-warning damage-stun"></button></td><td><button class="btn btn-sm btn-danger damage-physical"></button></td></tr>\n',
|
||||
'<tr><td><button class="btn btn-sm btn-warning damage-stun" title="Severe stun damage">S</button></td><td><button class="btn btn-sm btn-danger damage-physical" title="Severe physical damage">S</button></td></tr>\n',
|
||||
'<tr><td><button class="btn btn-sm btn-warning damage-stun"></button></td><td><button class="btn btn-sm btn-danger damage-physical"></button></td></tr>\n',
|
||||
'<tr><td><button class="btn btn-sm btn-warning damage-stun"></button></td><td><button class="btn btn-sm btn-danger damage-physical"></button></td></tr>\n',
|
||||
'<tr><td><button class="btn btn-sm btn-warning damage-stun"></button></td><td><button class="btn btn-sm btn-danger damage-physical"></button></td></tr>\n',
|
||||
'<tr><td><button class="btn btn-sm btn-warning damage-stun" title="K.O."><img src="zzz.png" height="16" /></button></td><td><button class="btn btn-sm btn-danger damage-physical" title="dead"><img src="cross.png" height="16"/></button></td></tr>\n',
|
||||
'<tr><th colspan="2"><button type)"submit" class="btn btn-sm btn-light remove-button" title="Remove combatant" data-bs-toggle="modal" data-bs-target="#confirm-modal"><img src="trash.png" /></button></th></tr>\n',
|
||||
'<table class="damage-monitor text-center align-middle d-none" data-augmented-ui="tl-scoop bl-clip-y tr-clip-y br-scoop both">\n',
|
||||
'<tr><td><button class="damage-stun active" title="Light stun damage">L</button></td><td><button class="damage-physical active" title="Light physical damage">L</button></td></tr>\n',
|
||||
'<tr><td><button class="damage-stun active"></button></td><td><button class="damage-physical active"></button></td></tr>\n',
|
||||
'<tr><td><button class="damage-stun active" title="Medium stun damage">M</button></td><td><button class="damage-physical active" title="Medium physical damage">M</button></td></tr>\n',
|
||||
'<tr><td><button class="damage-stun active"></button></td><td><button class="damage-physical active"></button></td></tr>\n',
|
||||
'<tr><td><button class="damage-stun active"></button></td><td><button class="damage-physical active"></button></td></tr>\n',
|
||||
'<tr><td><button class="damage-stun active" title="Severe stun damage">S</button></td><td><button class="damage-physical active" title="Severe physical damage">S</button></td></tr>\n',
|
||||
'<tr><td><button class="damage-stun active"></button></td><td><button class="damage-physical active"></button></td></tr>\n',
|
||||
'<tr><td><button class="damage-stun active"></button></td><td><button class="damage-physical active"></button></td></tr>\n',
|
||||
'<tr><td><button class="damage-stun active"></button></td><td><button class="damage-physical active"></button></td></tr>\n',
|
||||
'<tr><td><button class="damage-stun active" title="K.O."><img src="zzz.png" height="16" /></button></td><td><button class="damage-physical active" title="dead"><img src="cross.png" height="16"/></button></td></tr>\n',
|
||||
'<tr><th colspan="2"><button type)"submit" class="remove-button" title="Remove combatant" data-bs-toggle="modal" data-bs-target="#confirm-modal"><img src="trash.png" /></button></th></tr>\n',
|
||||
'</table>'].join("");
|
||||
const STUN_BADGE_HTML = '<sup><span class="badge bg-warning position-absolute translate-middle stun-badge" title="Stun damage niveau"></span></sup>';
|
||||
const PHYSICAL_BADGE_HTML = '<sub><span class="badge bg-danger position-absolute translate-middle physical-badge" title="Physical damage niveau"></span></sub>';
|
||||
const CONTEXTUAL_CLASSES = {
|
||||
MAX_INI: "table-primary",
|
||||
ZERO_INI: "table-secondary",
|
||||
REGULAR_INI: "table-success",
|
||||
KO_OR_DEAD: "ko-or-dead",
|
||||
};
|
||||
/*
|
||||
* helper functions
|
||||
*/
|
||||
@ -55,8 +43,8 @@ function rollForInitiative(dice, rea) {
|
||||
// figure out whose action comes first out of two combatants a and b
|
||||
function whoGoesFirst(a, b) {
|
||||
// check for K.O./death
|
||||
let tmpA = $(a).hasClass(CONTEXTUAL_CLASSES["KO_OR_DEAD"]) ? -1 : parseInt($(a).find(".combatant-ini").text()) || 0;
|
||||
let tmpB = $(b).hasClass(CONTEXTUAL_CLASSES["KO_OR_DEAD"]) ? -1 : parseInt($(b).find(".combatant-ini").text()) || 0;
|
||||
let tmpA = $(a).hasClass("ko-or-dead") ? -1 : parseInt($(a).find(".combatant-ini").text()) || 0;
|
||||
let tmpB = $(b).hasClass("ko-or-dead") ? -1 : parseInt($(b).find(".combatant-ini").text()) || 0;
|
||||
// compare ini
|
||||
let compIni = tmpB - tmpA;
|
||||
if (compIni != 0) {
|
||||
@ -74,7 +62,7 @@ function whoGoesFirst(a, b) {
|
||||
// returns a combatant's effective ini value (modified by wound penalties)
|
||||
function getEffectiveIni(tr) {
|
||||
// return -1 if combatant is K.O. or dead
|
||||
if ($(tr).hasClass(CONTEXTUAL_CLASSES["KO_OR_DEAD"])) {
|
||||
if ($(tr).hasClass("ko-or-dead")) {
|
||||
return -1;
|
||||
}
|
||||
// otherwise compute effective ini (true ini minus wound penalties)
|
||||
@ -140,7 +128,7 @@ function handleEditButtonClick(e) {
|
||||
$("#combatant-modal-add-ok-button").addClass("d-none");
|
||||
$("#combatant-modal-edit-ok-button").removeClass("d-none");
|
||||
// populate modal with values from row
|
||||
$("#combatant-modal-name").val($tr.find(".combatant-name").attr("data-combatant-name"));
|
||||
$("#combatant-modal-name").val($tr.find(".combatant-name").text());
|
||||
$("#combatant-modal-dice").val($tr.find(".combatant-dice").attr("data-combatant-dice"));
|
||||
$("#combatant-modal-rea").val($tr.find(".combatant-rea").attr("data-combatant-rea"));
|
||||
$("#combatant-modal-ini").val($tr.attr("data-true-ini"));
|
||||
@ -191,7 +179,7 @@ function addCombatant(e) {
|
||||
$tr.find(".damage-dropdown").append($.parseHTML(DAMAGE_MONITOR_HTML));
|
||||
// populate table row with values from modal
|
||||
$tr.attr("data-true-ini", ini);
|
||||
$tr.find(".combatant-name").attr("data-combatant-name", $("#combatant-modal-name").val().trim());
|
||||
$tr.find(".combatant-name").text($("#combatant-modal-name").val().trim());
|
||||
$tr.find(".combatant-dice").attr("data-combatant-dice", $("#combatant-modal-dice").val().trim());
|
||||
$tr.find(".combatant-rea").attr("data-combatant-rea", $("#combatant-modal-rea").val().trim());
|
||||
//TODO: retrieve initial damage levels
|
||||
@ -213,16 +201,22 @@ function applyDamage(e) {
|
||||
let $btn = $(e.target).is("button") ? $(e.target) : $(e.target).parent();
|
||||
// retrieve new damage level and type from button position and "damage-[type]" class
|
||||
let damageLevel = $btn.parent().parent().index();
|
||||
if ( $btn.hasClass("active") ) {
|
||||
damageLevel += 1;
|
||||
}
|
||||
let damageType = $btn.attr("class").split(" ").filter(function (cls) {
|
||||
return cls.substr(0, 7) == "damage-" ? cls : false;
|
||||
}).toString().substr(7);
|
||||
// add damage level to table row as as data attribute
|
||||
$btn.parents("tr.combatant-row").attr("data-damage-" + damageType, damageLevel);
|
||||
// select/unselect damage buttons above/below
|
||||
$btn.addClass("active");
|
||||
$btn.parent().parent().nextAll().find("button.damage-" + damageType).removeClass("active");
|
||||
$btn.parent().parent().prevAll().find("button.damage-" + damageType).addClass("active");
|
||||
$btn.toggleClass("active");
|
||||
$btn.parent().parent().prevAll().find("button.damage-" + damageType).removeClass("active");
|
||||
$btn.parent().parent().nextAll().find("button.damage-" + damageType + ":not(.active)").addClass("active");
|
||||
// resort
|
||||
/* setTimeout(function(){
|
||||
sortTable();
|
||||
},250);*/
|
||||
sortTable();
|
||||
}
|
||||
// edit combatant
|
||||
@ -244,7 +238,7 @@ function editCombatant(e) {
|
||||
$tr = $("tr.combatant-row").eq(index);
|
||||
// set new values
|
||||
$tr.attr("data-true-ini", ini);
|
||||
$tr.find(".combatant-name").attr("data-combatant-name", name);
|
||||
$tr.find(".combatant-name").text(name);
|
||||
$tr.find(".combatant-dice").attr("data-combatant-dice", dice);
|
||||
$tr.find(".combatant-rea").attr("data-combatant-rea", rea);
|
||||
// sort table
|
||||
@ -283,19 +277,19 @@ function startNewRound(e) {
|
||||
// add contextual classes and sort combatants by ini value
|
||||
function sortTable() {
|
||||
// do some clean up: remove previous classes from rows, disable act buttons, remove effective ini and damage badges
|
||||
$(".combatant-row").removeClass(Object.values(CONTEXTUAL_CLASSES).join(" "));
|
||||
$(".combatant-row").removeClass("ko-or-dead max-ini zero-ini"); //REGULAR_INI
|
||||
$(".combatant-row").find(".act-button").prop("disabled", true).attr("aria-disabled", "true");
|
||||
$(".combatant-ini").empty();
|
||||
// mark KO or death with class
|
||||
$(".combatant-row").each(function () {
|
||||
if (parseInt($(this).attr("data-damage-stun")) == 10 || parseInt($(this).attr("data-damage-physical")) == 10) {
|
||||
$(this).addClass(CONTEXTUAL_CLASSES["KO_OR_DEAD"]);
|
||||
$(this).addClass("ko-or-dead");
|
||||
}
|
||||
});
|
||||
// compute highest effective ini
|
||||
let iniMax = Math.max.apply(null, $.map($(".combatant-row"), function (tr, i) {
|
||||
// write current effective ini to table row
|
||||
$(tr).find(".combatant-ini").text($(tr).hasClass(CONTEXTUAL_CLASSES["KO_OR_DEAD"]) ? 0 : getEffectiveIni($(tr)));
|
||||
$(tr).find(".combatant-ini").text($(tr).hasClass("ko-or-dead") ? 0 : getEffectiveIni($(tr)));
|
||||
return $(tr).find(".combatant-ini").text();
|
||||
}));
|
||||
// add damage badges and contextual classes
|
||||
@ -310,26 +304,27 @@ function sortTable() {
|
||||
$(this).find(".physical-badge").append(DAMAGE_NIVEAU[DAMAGE_PENALTY[$(this).attr("data-damage-physical")]]);
|
||||
}
|
||||
// K.O./dead -> don't add anything
|
||||
if ($(this).hasClass(CONTEXTUAL_CLASSES["KO_OR_DEAD"])) {
|
||||
if ($(this).hasClass("ko-or-dead")) {
|
||||
return true;
|
||||
}
|
||||
// ini = zero
|
||||
if (parseInt($(this).find(".combatant-ini").text()) == 0) {
|
||||
$(this).addClass(CONTEXTUAL_CLASSES["ZERO_INI"]);
|
||||
$(this).addClass("zero-ini");
|
||||
return true;
|
||||
}
|
||||
// ini = max and non-zero
|
||||
if (parseInt($(this).find(".combatant-ini").text()) == iniMax && iniMax > 0) {
|
||||
$(this).addClass(CONTEXTUAL_CLASSES["MAX_INI"]).find(".act-button").prop("disabled", false).removeAttr("aria-disabled");
|
||||
$(this).addClass("max-ini").find(".act-button").prop("disabled", false).removeAttr("aria-disabled");
|
||||
return true;
|
||||
}
|
||||
// everything else
|
||||
$(this).addClass(CONTEXTUAL_CLASSES["REGULAR_INI"]);
|
||||
/* // everything else
|
||||
$(this).addClass("REGULAR_INI");*/
|
||||
})
|
||||
// sort rows and append them in new order
|
||||
let $rows = $(".combatant-row").toArray().sort(whoGoesFirst);
|
||||
for (let i = 0; i < $rows.length; i++) {
|
||||
$("#combatants-table").append($rows[i]);
|
||||
$($rows[i]).css("z-index", 50-i).css("position", "relative");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user