Skip to content

Instantly share code, notes, and snippets.

@kyrsideris
Last active February 14, 2016 12:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kyrsideris/d97a8c043860ab9e1660 to your computer and use it in GitHub Desktop.
Save kyrsideris/d97a8c043860ab9e1660 to your computer and use it in GitHub Desktop.
Configurable character statistics form for D&D 5.
<!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