1 /* The person who associated a work with this deed has dedicated the
2 work to the public domain by waiving all of his or her rights to
3 the work worldwide under copyright law, including all related and
4 neighboring rights, to the extent allowed by law.
6 You can copy, modify, distribute and perform the work, even for
7 commercial purposes, all without asking permission.
9 See https://creativecommons.org/publicdomain/zero/1.0/ for details.
14 if (!String
.prototype.repeat
)
15 Object
.defineProperty(String
.prototype, "repeat", {
16 value: function (count
) {
17 var string
= this.toString();
31 if (!Array
.prototype.fill
)
32 Object
.defineProperty(Array
.prototype, "fill", {
33 value: function (value
) {
34 var beg
= arguments
.length
> 1 ? +arguments
[1] : 0;
35 var end
= arguments
.length
> 2 ? +arguments
[2] : this.length
;
36 if (beg
< 0) beg
+= this.length
;
37 if (end
< 0) end
+= this.length
;
38 for (var i
= beg
; i
< end
; ++i
)
44 if (!Element
.prototype.matches
)
45 Object
.defineProperty(Element
.prototype, "matches", {
46 value
: Element
.prototype.matchesSelector
47 || Element
.prototype.mozMatchesSelector
48 || Element
.prototype.webkitMatchesSelector
51 function removeUnit (element
) {
52 element
.parentNode
.removeChild(element
);
57 var FIRST_EMPTY
= /☐/;
58 var LAST_TICKED
= /☒([^☒]*)$/;
61 return a
[(Math
.random() * a
.length
) | 0];
65 return s
&& s
[0].toUpperCase() + s
.slice(1);
68 function letters (n
) {
72 r
+= choice("abcdefghijklmnopqrstuvwxyz");
76 function range (a
, b
) {
77 return a
+ (Math
.random() * (b
- a
)) | 0;
80 function numerals (n
) {
84 r
+= choice("0123456789");
89 return letters(range(1, 4)).toUpperCase()
90 + choice(["‑", "", ".", "/"])
91 + numerals(range(1, 4));
95 return choice(["I", "II", "III", "IV", "V", "VI",
96 "VII", "VIII", "IX", "X", "XI", "XII",
101 return choice([letters(1).toUpperCase() + choice("-./") + numerals(2)]);
104 function randomName (scheme
) {
107 return choice([pid() + " " + cap(choice(NOUNS
))],
108 [cap(choice(NOUNS
)) + " " + pid()]);
111 oid() + " " + cap(choice(ADJECTIVES
)) + " " + cap(choice(BIRDS
)),
112 cap(choice(ADJECTIVES
)) + " " + cap(choice(BIRDS
)) + " " + roman()]);
115 oid() + " " + cap(choice(ADJECTIVES
)) + " " + cap(choice(NOUNS
)),
116 cap(choice(ADJECTIVES
)) + " " + cap(choice(NOUNS
)) + " " + roman()]);
120 var STATS
= ["attack", "range", "defense", "aside"];
121 function createUnit (dfnName
) {
122 var dfn
= UNITS
[dfnName
];
123 var weapons
= dfn
.weapons
|| [];
124 var unit
= document
.getElementById("unit-template").cloneNode(true);
125 unit
.removeAttribute('id');
126 unit
.setAttribute("data-dfn", dfnName
);
127 unit
.querySelector(".name").textContent
= randomName(dfn
.nameScheme
);
128 unit
.querySelector(".type").textContent
= dfnName
;
131 var aside
= unit
.appendChild(document
.createElement("div"));
132 aside
.className
= "aside";
133 aside
.innerHTML
= dfn
.aside
;
135 if (weapons
.length
) {
136 var weaponList
= unit
.appendChild(document
.createElement('ul'));
137 weaponList
.className
= "weapons";
140 weapons
.forEach(function (weaponRef
) {
141 var count
= parseInt(weaponRef
, 10) || 1;
142 var weaponName
= weaponRef
.replace(/^[0-9 ]*/, "");
143 var weapon
= WEAPONS
[weaponName
]
144 || WEAPONS
[weaponName
.replace(/s+$/, "")];
145 var weaponItem
= document
.createElement("li");
146 weaponItem
.setAttribute('data-name', weaponName
);
147 weaponItem
.setAttribute('data-count', count
);
148 weaponItem
.setAttribute('data-remaining', count
);
149 var stats
= document
.createElement('ul');
150 stats
.className
= "stats";
151 for (var j
= 0; j
< STATS
.length
; ++j
) {
152 if (weapon
[STATS
[j
]] !== undefined) {
153 var stat
= document
.createElement('li');
154 stat
.className
= STATS
[j
];
155 stat
.innerHTML
= weapon
[STATS
[j
]];
156 stats
.appendChild(stat
);
159 if (stats
.children
.length
)
160 weaponItem
.appendChild(stats
);
161 var ticks
= document
.createElement('div');
162 ticks
.className
= "ticks";
163 ticks
.innerHTML
= ticksText(count
);
164 weaponItem
.appendChild(ticks
);
165 weaponList
.appendChild(weaponItem
);
169 var move = dfn
.move || 3;
170 var per
= dfn
.tread
/ move;
171 var treads
= document
.createElement('ol');
172 treads
.className
= "treads";
173 treads
.appendChild(document
.createElement("li"));
174 treads
.setAttribute('data-count', dfn
.tread
);
175 treads
.setAttribute('data-remaining', dfn
.tread
);
176 for (var i
= 0; i
< move; ++i
) {
177 var tread
= treads
.appendChild(document
.createElement("li"));
178 tread
.className
= "ticks";
179 tread
.innerHTML
= ticksText(per
);
181 unit
.appendChild(treads
);
183 if (dfn
.propulsion
) {
184 var move = dfn
.move || 3;
185 var per
= dfn
.propulsion
/ move;
186 var treads
= document
.createElement('ol');
187 treads
.className
= "treads propulsion";
188 treads
.appendChild(document
.createElement("li"));
189 treads
.setAttribute('data-count', dfn
.propulsion
);
190 treads
.setAttribute('data-remaining', dfn
.propulsion
);
191 for (var i
= 0; i
< move; ++i
) {
192 var tread
= treads
.appendChild(document
.createElement("li"));
193 tread
.className
= "ticks";
194 tread
.innerHTML
= ticksText(per
);
196 unit
.appendChild(treads
);
202 function addUnit (dfnName
) {
203 document
.querySelector('main').appendChild(createUnit(dfnName
));
207 return new RegExp("(^|\\s+)" + c
+ "(\\s+|$)");
210 function hasClass (e
, n
) {
211 return !!e
.className
.match(spre(n
));
214 function addClass (e
, n
) {
216 e
.className
+= " " + n
;
219 function removeClass (e
, n
) {
220 e
.className
= e
.className
.replace(spre(n
), "");
224 addClass(document
.getElementById(id
.id
|| id
), "visible");
227 removeClass(document
.getElementById(id
.id
|| id
), "visible");
229 function handleTray (evt
) {
230 var id
= this.getAttribute('data-tray');
231 var el
= document
.getElementById(id
);
232 var f
= (hasClass(el
, "visible") ? hide
: show
)
235 evt
.stopPropagation();
238 function ticksText (n
) {
239 var blocks
= [EMPTY
.repeat(n
)];
240 for (var i
= 5; i
>= 2; --i
) {
241 if (n
> i
&& n
% i
=== 0) {
242 blocks
= (new Array(n
/ i
)).fill(EMPTY
.repeat(i
));
246 return "<span>" + blocks
.join("</span><wbr><span>") + "</span>";
249 function rub (content
) {
250 return content
.replace(LAST_TICKED
, EMPTY
+ "$1");
252 function tick (content
) {
253 return content
.replace(FIRST_EMPTY
, CHECK
);
256 function findParent (el
, selector
) {
257 while (el
&& el
!== document
&& !el
.matches(selector
))
259 return el
=== document
? null : el
;
262 function boxes (event
) {
263 var target
= event
.target
;
264 if (!target
.innerHTML
.match(/☐|☒/))
266 var par
= findParent(target
, '[data-count]');
267 var ticks
= findParent(target
, '.ticks');
270 var content
= target
.innerHTML
;
271 var rect
= target
.getBoundingClientRect();
272 var total
= target
.innerHTML
.match(/☐|☒/g);
273 var ticked
= target
.innerHTML
.match(/☒/g);
274 var p
= (event
.clientX
- rect
.left
) / rect
.width
;
275 var pr
= (total
&& total
.length
)
276 ? (ticked
? ticked
.length
: 0) / total
.length
: 0;
277 par
.innerHTML
= ((p
< pr
) ? rub
: tick
)(par
.innerHTML
);
278 var rem
= par
.innerHTML
.match(/☐/g);
279 par
.setAttribute('data-remaining', rem
? rem
.length
: 0);
280 event
.preventDefault();
281 event
.stopPropagation();
285 return p
* p
* p
* (p
* (p
* 6.0 - 15.0) + 10.0);
288 function scroll (y1
, t
) {
289 var y0
= document
.body
.scrollTop
|| document
.documentElement
.scrollTop
;
290 var n
= (t
|| 150) / 15;
292 clearInterval(scroll
.owner
);
293 scroll
.owner
= setInterval(function () {
294 var p
= Math
.max(0, Math
.min(++i
/ n
, 1));
295 document
.body
.scrollTop
296 = document
.documentElement
.scrollTop
297 = y0
+ (y1
- y0
) * fade(p
);
298 if (i
>= n
) clearInterval(scroll
.owner
);
303 scroll(el
.nextElementSibling
.offsetTop
- el
.parentNode
.offsetTop
);
306 function previous (el
) {
307 scroll(el
.previousElementSibling
.offsetTop
- el
.parentNode
.offsetTop
);
310 function autoClose () {
311 var open
= document
.querySelectorAll(".tray.visible");
312 for (var i
= 0; i
< open
.length
; ++i
)
314 return open
&& open
.length
;
317 window
.addEventListener("DOMContentLoaded", function () {
318 if (navigator
.standalone
)
319 document
.body
.className
+= " standalone";
320 var units
= document
.getElementById("addUnit");
321 Object
.keys(UNITS
).sort(function (a
, b
) {
322 return (b
.indexOf("Ogre Mk") - a
.indexOf("Ogre Mk"))
323 || (a
> b
) - (a
< b
);
324 }).forEach(function (unitName
) {
325 var unit
= units
.appendChild(document
.createElement("li"));
326 unit
.textContent
= unitName
;
327 unit
.addEventListener("click", function () {
332 addUnit('Ogre Mk. V');
333 FastClick
.attach(document
.body
, { tapDelay
: 50 });
335 var trays
= document
.querySelectorAll('[data-tray]');
336 for (var i
= 0; i
< trays
.length
; ++i
)
337 trays
[i
].addEventListener('click', handleTray
);
338 window
.addEventListener('click', function (evt
) {
339 if (!findParent(evt
.target
, ".tray.visible"))