Last active
February 14, 2016 12:40
-
-
Save kyrsideris/d97a8c043860ab9e1660 to your computer and use it in GitHub Desktop.
Configurable character statistics form for D&D 5.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<style type="text/css"> | |
html { | |
display: table; | |
margin: auto; | |
} | |
body { | |
display: table-cell; | |
vertical-align: middle; | |
} | |
form { | |
width: 300px; | |
margin: 0 auto; | |
} | |
p { | |
color: black; | |
} | |
h3 { | |
background-color:#44c767; | |
-moz-border-radius:28px; | |
-webkit-border-radius:28px; | |
border-radius:28px; | |
border:1px solid #18ab29; | |
/*display:inline-block;*/ | |
color:#ffffff; | |
padding:7px 31px; | |
text-decoration:none; | |
text-shadow:0px 1px 0px #2f6627; | |
text-align: center; | |
} | |
.rememberStatsButton { | |
background-color:#44c767; | |
-moz-border-radius:28px; | |
-webkit-border-radius:28px; | |
border-radius:28px; | |
border:1px solid #18ab29; | |
display:inline-block; | |
cursor:pointer; | |
color:#ffffff; | |
padding:2px 31px; | |
text-decoration:none; | |
text-shadow:0px 1px 0px #2f6627; | |
} | |
.rememberStatsButton:hover { | |
background-color:#5cbf2a; | |
} | |
.rememberStatsButton:active { | |
position:relative; | |
top:1px; | |
} | |
.history { | |
text-align: center; | |
} | |
input[type=number]{ | |
width: 147px; | |
/*width: 30px;*/ | |
} | |
.statsHistory { | |
margin:20px; | |
-moz-border-radius:10px; | |
-webkit-border-radius:10px; | |
border-radius:10px | |
} | |
.statsHistory th {padding:4px 10px} | |
.statsHistory td { | |
background:#fff; | |
padding:2px 10px 4px 10px | |
} | |
.statsHistory tr.even td {background:#eee} | |
.statsHistory td:first-child { | |
-moz-border-radius-bottomleft:10px; | |
-webkit-border-bottom-left-radius:10px; | |
border-bottom-left-radius:10px; | |
border-top-left-radius:10px; | |
} | |
.statsHistory td:last-child { | |
-moz-border-radius-bottomright:10px; | |
-webkit-border-bottom-right-radius:10px; | |
border-bottom-right-radius:10px; | |
border-top-right-radius:10px; | |
} | |
</style> | |
<script type='text/javascript'> | |
var base = 8; | |
var max_points = 27; | |
var player_allocation = 0; | |
var historyEntries = 0; | |
var urlParams; | |
function statsAlgorithm(value){ | |
// You get X points. | |
// All abilities start at 8. | |
// It costs | |
// one point from 9-13, | |
// two points from 14-15, and | |
// three points from 16-17. | |
// For example, an 17 costs 5+4+6=15 points, and a 14 costs 7. | |
if (value <= 13){ return value * 1; } | |
else if (value <= 15){ return 13 + (value-13) * 2; } | |
else if (value <= 17){ return 13 + 2*2 + (value-15) * 3; } | |
else if (value <= 20){ return 13 + 2*2 + 2*3 + (value-17) * 4; } | |
else { return 13 + 2*2 + 2*3 + 3*4 + (value-20) * 5; } | |
} | |
function modAlgorithm(value){ | |
switch (parseFloat(value)){ | |
case 1: return "-5"; | |
case 2: case 3: return "-4"; | |
case 4: case 5: return "-3"; | |
case 6: case 7: return "-2"; | |
case 8: case 9: return "-1"; | |
case 10: case 11: return "+0"; | |
case 12: case 13: return "+1"; | |
case 14: case 15: return "+2"; | |
case 16: case 17: return "+3"; | |
case 18: case 19: return "+4"; | |
case 20: case 21: return "+5"; | |
case 22: case 23: return "+6"; | |
case 24: case 25: return "+7"; | |
case 26: case 27: return "+8"; | |
case 28: case 29: return "+9"; | |
case 30: return "+10"; | |
default: return "+10"; | |
} | |
} | |
function modSetText(modId, value) { | |
document.getElementById(modId).innerHTML = modAlgorithm(value); | |
} | |
function statsCalculator(elem){ | |
if (elem){ | |
modSetText("mod" + elem.id.slice(4,7), elem.value); | |
} | |
player_allocation = -6*base; | |
player_allocation += statsAlgorithm(document.getElementById("statStr").value); | |
player_allocation += statsAlgorithm(document.getElementById("statDex").value); | |
player_allocation += statsAlgorithm(document.getElementById("statCon").value); | |
player_allocation += statsAlgorithm(document.getElementById("statInt").value); | |
player_allocation += statsAlgorithm(document.getElementById("statWis").value); | |
player_allocation += statsAlgorithm(document.getElementById("statCha").value); | |
var ftotal = document.getElementById("statsTotal"); | |
if (player_allocation > max_points){ | |
ftotal.style.color = "red" | |
ftotal.innerHTML = "Points remaining: " + (max_points - player_allocation) + " (max: " + max_points + ")"; | |
} else { | |
ftotal.style.color = "black" | |
ftotal.innerHTML = "Points remaining: " + (max_points - player_allocation); | |
} | |
} | |
function createStatsRow() { | |
var historyTable = document.getElementById("statsHistory"); | |
if (historyTable.tHead.style.visibility == "collapse"){ | |
historyTable.tHead.style.visibility = "visible"; | |
historyTable.style.background = "#ccc"; | |
historyTable.style.border = "#ccc 1px solid"; | |
} | |
var row = historyTable.tBodies[0].insertRow(0); | |
row.insertCell(0).innerHTML = historyEntries; | |
var valStr = parseInt(document.getElementById("statStr").value); | |
var valDex = parseInt(document.getElementById("statDex").value); | |
var valCon = parseInt(document.getElementById("statCon").value); | |
var valInt = parseInt(document.getElementById("statInt").value); | |
var valWis = parseInt(document.getElementById("statWis").value); | |
var valCha = parseInt(document.getElementById("statCha").value); | |
var linkref = window.location + "?base="+base + "&max="+max_points + "&str="+valStr + "&dex="+valDex + "&con="+valCon + "&int="+valInt + "&wis="+valWis + "&cha="+valCha; | |
row.insertCell(1).innerHTML = valStr; | |
row.insertCell(2).innerHTML = valDex; | |
row.insertCell(3).innerHTML = valCon; | |
row.insertCell(4).innerHTML = valInt; | |
row.insertCell(5).innerHTML = valWis; | |
row.insertCell(6).innerHTML = valCha; | |
row.setAttribute("title", "Copy to Address"); | |
row.setAttribute("alt", linkref); | |
row.setAttribute("style", "cursor:pointer"); | |
row.addEventListener('click', function(event) { | |
var lastEntry = event.target.parentElement.children[0].innerHTML.toString(); | |
var newUrl = event.target.parentElement.getAttribute("alt").toString(); | |
window.history.replaceState({ 'last_entry': lastEntry }, "New Character Stats", newUrl); | |
}); | |
historyEntries += 1; | |
} | |
(window.onpopstate = function () { | |
var match, | |
pl = /\+/g, // Regex for replacing addition symbol with a space | |
search = /([^&=]+)=?([^&]*)/g, | |
decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, | |
query = window.location.search.substring(1); | |
urlParams = {}; | |
while (match = search.exec(query)) | |
urlParams[decode(match[1]).toLowerCase()] = decode(match[2]); | |
})(); | |
</script> | |
</head> | |
<body> | |
<h3 class="title" align="center">Character Stats</h3> | |
<form name="stats"> | |
<table align="center"> | |
<tr> | |
<td colspan="2" align="center">Stats</td> | |
<td align="right">Modifiers</td> | |
</tr> | |
<tr> | |
<td width="40%"><label for="statStr">Strength:</label></td> | |
<td width="60%"><input id="statStr" type="number" min="8" max="30" step="1" value="8" onchange="statsCalculator(this)"/></td> | |
<td align="center" id="modStr">0</td> | |
</tr> | |
<tr> | |
<td><label for="statDex">Dexterity:</label></td> | |
<td><input id="statDex" type="number" min="8" max="30" step="1" value="8" onchange="statsCalculator(this)"/></td> | |
<td align="center" id="modDex">0</td> | |
</tr> | |
<tr> | |
<td><label for="statCon">Constitution:</label></td> | |
<td><input id="statCon" type="number" min="8" max="30" step="1" value="8" onchange="statsCalculator(this)"/></td> | |
<td align="center" id="modCon">0</td> | |
</tr> | |
<tr> | |
<td><label for="statInt">Intelligence:</label></td> | |
<td><input id="statInt" type="number" min="8" max="30" step="1" value="8" onchange="statsCalculator(this)"/></td> | |
<td align="center" id="modInt">0</td> | |
</tr> | |
<tr> | |
<td><label for="statWis">Wisdom:</label></td> | |
<td><input id="statWis" type="number" min="8" max="30" step="1" value="8" onchange="statsCalculator(this)"/></td> | |
<td align="center" id="modWis">0</td> | |
</tr> | |
<tr> | |
<td><label for="statCha">Charisma:</label></td> | |
<td><input id="statCha" type="number" min="8" max="30" step="1" value="8" onchange="statsCalculator(this)"/></td> | |
<td align="center" id="modCha">0</td> | |
</tr> | |
</table> | |
<p id="statsTotal">Points remaining: 0</p> | |
</form> | |
<br> | |
<div class="history"> | |
<button class="rememberStatsButton" onclick="createStatsRow()">Remember this configuration!</button> | |
<br> | |
<table id="statsHistory" class="statsHistory"> | |
<thead style="visibility: collapse;"> | |
<tr> | |
<td>Entry</td> | |
<td>Strength</td> | |
<td>Dexterity</td> | |
<td>Constitution</td> | |
<td>Intelligence</td> | |
<td>Wisdom</td> | |
<td>Charisma</td> | |
</tr> | |
</thead> | |
<tbody> | |
</tbody> | |
</table> | |
</div> | |
<script type='text/javascript'> | |
if ("str" in urlParams){ | |
document.getElementById("statStr").value = urlParams["str"]; | |
} | |
if ("dex" in urlParams){ | |
document.getElementById("statDex").value = urlParams["dex"]; | |
} | |
if ("con" in urlParams){ | |
document.getElementById("statCon").value = urlParams["con"]; | |
} | |
if ("int" in urlParams){ | |
document.getElementById("statInt").value = urlParams["int"]; | |
} | |
if ("wis" in urlParams){ | |
document.getElementById("statWis").value = urlParams["wis"]; | |
} | |
if ("cha" in urlParams){ | |
document.getElementById("statCha").value = urlParams["cha"]; | |
} | |
if ("base" in urlParams){ | |
base = parseFloat(urlParams["base"]); | |
var elem; | |
elem = document.getElementById("statStr"); elem.setAttribute("min", base); elem.setAttribute("value", base); | |
elem = document.getElementById("statDex"); elem.setAttribute("min", base); elem.setAttribute("value", base); | |
elem = document.getElementById("statCon"); elem.setAttribute("min", base); elem.setAttribute("value", base); | |
elem = document.getElementById("statInt"); elem.setAttribute("min", base); elem.setAttribute("value", base); | |
elem = document.getElementById("statWis"); elem.setAttribute("min", base); elem.setAttribute("value", base); | |
elem = document.getElementById("statCha"); elem.setAttribute("min", base); elem.setAttribute("value", base); | |
} | |
if ("max" in urlParams){ | |
max_points = parseFloat(urlParams["max"]); | |
} | |
modSetText("modStr", document.getElementById("statStr").value); | |
modSetText("modDex", document.getElementById("statDex").value); | |
modSetText("modCon", document.getElementById("statCon").value); | |
modSetText("modInt", document.getElementById("statInt").value); | |
modSetText("modWis", document.getElementById("statWis").value); | |
modSetText("modCha", document.getElementById("statCha").value); | |
statsCalculator(null); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment