Advertisement
krusader74

BootHill.html

Oct 18th, 2016
495
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 5 35.21 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <!--
  3.  
  4. ---
  5. Title:        Boot Hill 1E character generator
  6. Author:       krusader74
  7. Version:      0.3
  8. Date:         2016-10-18
  9. Copyright:    Public Domain
  10. Description:  >-
  11.              Boot Hill is a western-themed RPG written by Brian Blume &amp;
  12.              Gary Gygax in 1975. This code may be used to generate chracters
  13.              and simulate gunfights.
  14. Discussion:   http://odd74.proboards.com/thread/12032/boot-hill-1e-character-generator
  15. JSFiddle:     https://jsfiddle.net/krusader74/zLopw8k2
  16. Pastebin:     http://pastebin.com/Zy5UfD85
  17. Screenshot:   http://i.imgur.com/O1GYMym.png
  18. ...
  19.  
  20. # NAME
  21.  
  22. BootHill.html - Boot Hill 1E character generator
  23.  
  24. # SYNOPSIS
  25.  
  26.        BootHill.html [QueryString]
  27.  
  28. # DESCRIPTION
  29.  
  30. The simplest use is to load the page into a web browser without a QueryString. If you are loading it from your local filesystem, you will likely be using a URL like so:
  31.  
  32.        file:///C:/Users/krusader74/Downloads/BootHill.html
  33.  
  34. Then follow these instructions:
  35.  
  36. 1. Hit the Generate Character button to randomly create a new character.
  37. 2. If desired, increase the experience with the + Won / + Lost buttons.
  38. 3. Choose a weapon from the drop down list.
  39.    a. This makes a stat block for the weapon with its range, rate, speed, etc.
  40.    b. It also computes First Shot and To Hit
  41.    c. You can add modifiers like movement, surprise, range, etc.
  42. 4. To attack an opponent, click the Attack button. This randomly determines if you hit. If you hit, then it rolls randomly for
  43.    a. Hit Location
  44.    b. Wound Severity
  45. 5. To defend against an attack, input your opponent's chance to hit and damage modifiers, then click the Defend button. It randomly determines if you're hit. If you are, then it determines
  46.    a. Hit Location: If you are hit in your right arm, then the program automatically switches to the left arm and applies the wrong hand penalty, unless your left arm is equally or more severely wounded then the right. Damage to arms affects your chances to hit. If both arms are severely damaged, then you cannot attack anymore.
  47.    b. Wound Severity subtracts from your Strength. If Strength falls to 0 or less, you're unconscious and can't attack any more. A mortal wound kills your character and he can't attack anymore either.
  48. 6. Click the Reset Wounds button to erase any wounds (including a mortal wound) and reset your Strength to its original value.
  49.  
  50. # OPTIONS
  51.  
  52. Instead of randomly generating a character, you may specify his abilities in the QueryString like so:
  53.  
  54.        BootHill.html?GunAccuracy=80&ThrowingAccuracy=75&Bravery=52&Speed=22&Strength=57
  55.  
  56. You must supply integer values between 1 and 100 for *all* 5 abilities:
  57.  
  58. * GunAccuracy
  59. * ThrowingAccuracy
  60. * Bravery
  61. * Speed
  62. * Strength
  63.  
  64. Additionally, you may specify your character's Experience like so:
  65.  
  66.        BootHill.html?GunAccuracy=80&ThrowingAccuracy=75&Bravery=52&Speed=22&Strength=57&Won=2&Lost=1
  67.  
  68. by supplying *both* the number of gunfights he's
  69.  
  70. * Won
  71. * Lost
  72.  
  73. Options are case sensitive.
  74.  
  75. **NOTE:** To use a QueryString with the JSFiddle-hosted code, modify this URL:
  76.  
  77.        http://fiddle.jshell.net/krusader74/zLopw8k2/show/?GunAccuracy=80&ThrowingAccuracy=75&Bravery=52&Speed=22&Strength=57&Won=2&Lost=1
  78.  
  79. Notice we've changed the URL structure:
  80.  
  81. * fiddle.jshell.net instead of jsfiddle.net
  82. * *show* added to the end of the URL before the query string
  83.  
  84. **NOTE:** The QueryString is parsed when the body is loaded. So, to use different parameters, alter the URL and then reload the page.
  85.  
  86. # AUTHORS
  87.  
  88. *   [krusader74](http://odd74.proboards.com/user/2141)
  89.  
  90. # COPYRIGHT
  91.  
  92. This software has been released by its author into the public domain.
  93.  
  94. # SEE ALSO
  95.  
  96. * Source code on [JSFiddle](https://jsfiddle.net/krusader74/zLopw8k2)
  97. * Source code on [Pastebin](http://pastebin.com/Zy5UfD85)
  98. * Screenshot on [Imgur](http://i.imgur.com/O1GYMym.png)
  99. * Example of making a custom character using a [QueryString on JSFiddle](http://fiddle.jshell.net/krusader74/zLopw8k2/show/?GunAccuracy=80&ThrowingAccuracy=75&Bravery=52&Speed=22&Strength=57&Won=2&Lost=1)
  100. * Discussion on the [Original D&amp;D Discussion](http://odd74.proboards.com/thread/12032/boot-hill-1e-character-generator) message board
  101.  
  102. # HISTORY
  103.  
  104. Version       Date           Description
  105. ---------     -----------    ---------------------------------------------------
  106. 0.1           2016-10-14     Initial release
  107. 0.2           2016-10-17     Added wound tracking
  108. 0.3           2016-10-18     Added QueryString processing and documentation
  109.  
  110. -->
  111. <html>
  112. <head>
  113.  
  114. <meta name="description" content="Boot Hill 1E character generator" />
  115. <meta name="author" content="krusader74" />
  116. <meta name="copyright" content="Public Domain" />
  117. <meta name="language" content="EN" />
  118. <meta name="revised" content="2016-10-18" />
  119. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  120.  
  121. <link rel="author" href="http://odd74.proboards.com/user/2141" />
  122.  
  123. <title>Boot Hill 1E character generator</title>
  124.  
  125. <style>
  126. body {
  127.   font-family: Arial, Helvetica, sans-serif;
  128. }
  129.  
  130. th, td {
  131.     padding: 10px;
  132. }
  133. </style>
  134. <script>
  135. // TABLES ----------------------------------------------------------------------
  136.  
  137. var Accuracy = [
  138. [01, 05,  "Very Poor",      -9],
  139. [06, 15,  "Poor",           -6],
  140. [16, 25,  "Below Average",  -3],
  141. [26, 35,  "Average",         0],
  142. [36, 50,  "Above Average",   2],
  143. [51, 65,  "Fair",            5],
  144. [66, 75,  "Good",            7],
  145. [76, 85,  "Very Good",      10],
  146. [86, 95,  "Excellent",      15],
  147. [96, 98,  "Crack Shot",     18],
  148. [99, 100, "Dead Eye",       20]];
  149.  
  150. var Bravery = [
  151. [01, 10,  "Coward",         -6],
  152. [11, 20,  "Cowardly",       -3],
  153. [21, 35,  "Average",         0],
  154. [36, 65,  "Above Average",   3],
  155. [66, 80,  "Brave",           6],
  156. [81, 90,  "Very Brave",     10],
  157. [91, 98,  "Fearless",       15],
  158. [99, 100, "Foolhardy",      15]];
  159.  
  160. var Speed = [
  161. [01,   05, "Slow",                  -5],
  162. [06,   10, "Below Average",         -2],
  163. [11,   20, "Average",                0],
  164. [21,   35, "Above Average",          2],
  165. [36,   50, "Quick",                  4],
  166. [51,   65, "Very Quick",             6],
  167. [66,   80, "Fast",                   9],
  168. [81,   90, "Very Fast",             12],
  169. [91,   95, "Lightning",             15],
  170. [96,   96, "Greased Lightning 96",  18],
  171. [97,   97, "Greased Lightning 97",  19],
  172. [98,   98, "Greased Lightning 98",  20],
  173. [99,   99, "Greased Lightning 99",  21],
  174. [100, 100, "Greased Lightning 100", 22]];
  175.  
  176. var Strength = [
  177. [01, 02,   8, "Feeble"],
  178. [03, 05,   9, "Puny"],
  179. [06, 10,  10, "Frail"],
  180. [11, 17,  11, "Weakling"],
  181. [18, 25,  12, "Sickly"],
  182. [26, 40,  13, "Average"],
  183. [41, 60,  14, "Above Average"],
  184. [61, 75,  15, "Sturdy"],
  185. [76, 83,  16, "Hardy"],
  186. [84, 90,  17, "Strong"],
  187. [91, 95,  18, "Very Strong"],
  188. [96, 98,  19, "Powerful"],
  189. [99, 100, 20, "Mighty"]];
  190.  
  191. var Weapons = [
  192. // Weapon, Short Range, Medium Range, Long Range, Rate, Speed, Ammunition, Reload first turn, Reload following turns
  193. ["Choose a weapon"],
  194. ["Thrown knife or tommahawk",   1,   2,   4,   1,   "A"],
  195. ["Bow and arrows",              8,  20,  40,   1,   "BA"],
  196. ["Thrown lance",                3,   6,  12,   1,   "BA"],
  197. ["Derringer",                   2,   4,  10,   1,   "A",   1,  1, 1],
  198. ["Derringer, double barreled",  2,   4,  10,   2,   "A",   2,  1, 1],
  199. ["Cap and ball revolver",       5,  10,  24,   3,   "BA",  6,  0, 1],
  200. ["Std single action revolver",  6,  12,  30,   3,   "F",   6,  1, 2],
  201. ["Double action revolver",      6,  12,  30,   3,   "A",   6,  1, 2],
  202. ["Modified fast draw revolver", 4,   8,  18,   3,   "VF",  6,  1, 2],
  203. ["Long barrel revolver",        8,  16,  36,   1,   "BA",  6,  1, 2],
  204. ["Scatter gun",                 4,   6,  10,   1,   "BA",  1,  1, 1],
  205. ["Scatter gun, double barreled",4,   6,  10,   2,   "BA",  2,  1, 1],
  206. ["Shotgun",                     6,  10,  24,   1,   "S",   1,  1, 1],
  207. ["Shotgun, double barreled",    6,  10,  24,   2,   "S",   2,  1, 1],
  208. ["Civil war carbine",          12,  36, 100,   1,   "S",   1,  1, 1],
  209. ["Civil war rifle",            18,  46, 130,   1,   "VS",  1,  1, 1],
  210. ["Civil war repeating rifle",  15,  40, 120,   3,   "S",   7,  1, 1],
  211. ["Standard rifle",             20,  50, 150,   3,   "S",  15,  2, 2],
  212. ["Standard carbine",           12,  36, 100,   3,   "BA", 12,  2, 2],
  213. ["Buffalo rifle",              30,  60, 120,   1,   "VS",  1,  1, 1]];
  214.  
  215. var WeaponSpeed = {
  216. "VS": -10,
  217. "S":   -5,
  218. "BA":   0,
  219. "A":    5,
  220. "F":    8,
  221. "VF":  10};
  222.  
  223. var Wounds = [
  224. ["None", 0],
  225. ["Wounds totalling less than 50% of Strength (-5 to hit)", -5],
  226. ["Wounds totalling 50% or more of Strength (-20 to hit)",  -20]];
  227.  
  228. var Surprise = [
  229. ["None", 0],
  230. ["Giving opponent first move", -3],
  231. ["Surprised", -5],
  232. ["Completely Surprised", -10]];
  233.  
  234. var Range = [
  235. ["Short",   10],
  236. ["Medium",   0],
  237. ["Long",   -20]];
  238.  
  239. var Movement = [
  240. //  Description,           Adj Speed, Adj Firer, Adj Target
  241. ["None",                           0,         0,          0],
  242. ["On foot --  Walk",               0,        -5,         -5],
  243. ["On foot --  Crawl",              0,       -10,         -5],
  244. ["On foot --  Run &amp; Dodge",  -20,       -30,        -20],
  245. ["On foot --  Run",              -20,       -20,        -10],
  246. ["On horse -- Trot",             -10,       -15,        -10],
  247. ["On horse -- Gallop",           -10,       -25,        -15]];
  248.  
  249. var Miscellaneous = [
  250. // Description                                 speedAdj, toHitAdj
  251. ["Weapon at rest on solid object",                    0,      20],
  252. ["More than one shot being fired by same figure",     0,     -10],
  253. ["Scattergun at short range",                         0,      20],
  254. ["Shotgun at short range",                            0,      10],
  255. ["Wrong hand shooting",                               0,     -10],
  256. ["Drawing two guns",                                 -5,       0],
  257. ["Firing two pistols",                                0,     -10],
  258. ["Hip shooting",                                     -3,     -10],
  259. ["Concealment (1/2 or more)",                         0,     -10],
  260. ["Already Aimed",                                    15,       0]];
  261.  
  262. var Exact_Hit_Location = [
  263. [01,  10, "Left leg",       0, [[01, 40, "Light Wound, -3 from Strength"], [41, 100, "Serious Wound, -7 from Strength"], [0,   0,  "Mortal Wound, figure hit is dead"]]],
  264. [11,  20, "Right leg",      1, [[01, 40, "Light Wound, -3 from Strength"], [41, 100, "Serious Wound, -7 from Strength"], [0,   0,  "Mortal Wound, figure hit is dead"]]],
  265. [21,  25, "Left arm/hand",  2, [[01, 75, "Light Wound, -3 from Strength"], [76, 100, "Serious Wound, -7 from Strength"], [0,   0,  "Mortal Wound, figure hit is dead"]]],
  266. [26,  30, "Right arm/hand", 3, [[01, 30, "Light Wound, -3 from Strength"], [31, 100, "Serious Wound, -7 from Strength"], [0,   0,  "Mortal Wound, figure hit is dead"]]],
  267. [31,  40, "Right shoulder", 4, [[01, 40, "Light Wound, -3 from Strength"], [41,  90, "Serious Wound, -7 from Strength"], [91, 100, "Mortal Wound, figure hit is dead"]]],
  268. [41,  50, "Left shoulder",  5, [[01, 40, "Light Wound, -3 from Strength"], [41,  80, "Serious Wound, -7 from Strength"], [81, 100, "Mortal Wound, figure hit is dead"]]],
  269. [51,  70, "Abdomen/groin",  6, [[01, 40, "Light Wound, -3 from Strength"], [41,  80, "Serious Wound, -7 from Strength"], [81, 100, "Mortal Wound, figure hit is dead"]]],
  270. [71,  85, "Chest",          7, [[01, 20, "Light Wound, -3 from Strength"], [21,  60, "Serious Wound, -7 from Strength"], [61, 100, "Mortal Wound, figure hit is dead"]]],
  271. [86, 115, "Head",           8, [[01, 20, "Light Wound, -3 from Strength"], [21,  40, "Serious Wound, -7 from Strength"], [41, 100, "Mortal Wound, figure hit is dead"]]]];
  272.  
  273. var Experience = [
  274. [0, 0,  -10],
  275. [1, 2,   -5],
  276. [3, 4,    0],
  277. [5, 6,    2],
  278. [7, 8,    6],
  279. [9, 10,   8],
  280. [11, Number.MAX_SAFE_INTEGER, 20]];
  281.  
  282. // XP for successful showdown. Double for 1 against 2. Halve for 2 against 1.
  283.  
  284. var XP_Speed = [
  285. [01, 50,  2],
  286. [51, 80,  1],
  287. [81, 100, 0]];
  288.  
  289. var XP_Bravery = [
  290. [01, 65,  2],
  291. [66, 90,  1],
  292. [91, 100, 0]];
  293.  
  294. var XP_Accuracy = [
  295. [01, 25,  3],
  296. [26, 50,  2],
  297. [51, 85,  1],
  298. [86, 100, 0]];
  299.  
  300. // VARIABLES -------------------------------------------------------------------
  301.  
  302. var query_string = {};
  303.  
  304. var
  305. accuracyWithGunsPercentile,
  306. accuracyWithGunsName,
  307. accuracyWithGunsToHitAdj,
  308. accuracyWithThrownWeaponsPercentile,
  309. accuracyWithThrownWeaponsName,
  310. accuracyWithThrownWeaponsToHitAdj,
  311. braveryPercentile,
  312. braveryName,
  313. braveryToHitAdj,
  314. speedPercentile,
  315. speedName,
  316. speedFirstShotAdj,
  317. strengthPercentile,
  318. strengthName,
  319. strengthScore,
  320. origStrengthScore,
  321. Won,
  322. Lost,
  323. firstShot,
  324. toHit,
  325. LightWoundLeftArm,
  326. SeriousWoundLeftArm,
  327. LightWoundRightArm,
  328. SeriousWoundRightArm,
  329. armSpeedAdj,
  330. armToHitAdj,
  331. Unconscious,
  332. Dead;
  333.  
  334. // CODE ------------------------------------------------------------------------
  335.  
  336. // Percentile Dice
  337. function d100() {
  338.     return 1 + Math.floor(Math.random() * 100);
  339. }
  340.  
  341. // Function: getValue
  342. // Description: Used to extract info from tables given characteristic percentile
  343. // E.g., to hit adjustment for Accuracy: getValue(Accuracy, percentile, 3, 0);
  344. // E.g., name for Accuracy: getValue(Accuracy, percentile, 2, "");
  345. function getValue(table, percentile, col, neutral){
  346.     return table.map(function(row){return (percentile>=row[0]&&percentile<=row[1])?row[col]:neutral;}).reduce(function(a,b){return a+b;});
  347. }
  348.  
  349. // HTML helper functions
  350. function tbl(rows){
  351.     return "<table>"+rows.join("\n")+"</table>";
  352. }
  353. function row(cols){
  354.     return "<tr>"+cols.join("")+"</tr>";
  355. }
  356. function hdr(text){
  357.     return "<th>"+text+"</th>";
  358. }
  359. function col(text){
  360.     return "<td>"+text+"</td>";
  361. }
  362. function bold(text){
  363.     return "<b>"+text+"</b>";
  364. }
  365. function sel(opts,id,onchange){
  366.     return "<select id=\""+id+"\" onchange=\""+onchange+"\">"+opts.join("\n")+"</select>";
  367. }
  368. function opt(num,text){
  369.     return "<option value=\""+num+"\">"+text+"</option>";
  370. }
  371. function span(id,text){
  372.     return "<span id=\""+id+"\">"+text+"</span>";
  373. }
  374. function button(procname, text){
  375.     return "<button onclick=\""+procname+"()\">"+text+"</button>";
  376. }
  377. function br(){
  378.     return "<br/>";
  379. }
  380.  
  381. function generateCharacter() {
  382.     accuracyWithGunsPercentile = d100();
  383.     accuracyWithGunsPercentile += bonus(accuracyWithGunsPercentile);
  384.     accuracyWithGunsName = getValue(Accuracy, accuracyWithGunsPercentile, 2, "");
  385.     accuracyWithGunsToHitAdj = getValue(Accuracy, accuracyWithGunsPercentile, 3, 0);
  386.  
  387.     accuracyWithThrownWeaponsPercentile = d100();
  388.     accuracyWithThrownWeaponsPercentile += bonus(accuracyWithThrownWeaponsPercentile);
  389.     accuracyWithThrownWeaponsName = getValue(Accuracy, accuracyWithThrownWeaponsPercentile, 2, "");
  390.     accuracyWithThrownWeaponsToHitAdj = getValue(Accuracy, accuracyWithThrownWeaponsPercentile, 3, 0);
  391.  
  392.     braveryPercentile = d100();
  393.     braveryPercentile += bonus(braveryPercentile);
  394.     braveryName = getValue(Bravery, braveryPercentile, 2, "");
  395.     braveryToHitAdj = getValue(Bravery, braveryPercentile, 3, 0);
  396.  
  397.     speedPercentile = d100();
  398.     speedPercentile += bonus(speedPercentile);
  399.     speedName = getValue(Speed, speedPercentile, 2, "");
  400.     speedFirstShotAdj = getValue(Speed, speedPercentile, 3, 0);
  401.  
  402.     strengthPercentile = d100();
  403.     strengthPercentile += bonus(strengthPercentile);
  404.     strengthName = getValue(Strength, strengthPercentile, 3, "");
  405.     strengthScore = getValue(Strength, strengthPercentile, 2, 0);
  406.     origStrengthScore = strengthScore;
  407.  
  408.     Won = 0;
  409.     Lost = 0;
  410.  
  411.     resetWounds();
  412.     showWeaponList();
  413.     showExperience();
  414. }
  415.  
  416. function bonus(percentile) {
  417.     var bonus;
  418.     if(percentile>=01&&percentile<=50){
  419.        bonus = 10;
  420.     } else if (percentile>=51&&percentile<=70){
  421.        bonus = 5;
  422.     } else if (percentile>=71&&percentile<=100) {
  423.        bonus = 0;
  424.     } else {
  425.         throw "bonus: percentile must be between 1 and 100";
  426.     }
  427.     return bonus;
  428. }
  429.  
  430. function resetWounds() {
  431.     strengthScore = origStrengthScore;
  432.     firstShot = 0;
  433.     toHit = 0;
  434.     LightWoundLeftArm = false;
  435.     SeriousWoundLeftArm = false;
  436.     LightWoundRightArm = false;
  437.     SeriousWoundRightArm = false;
  438.     armSpeedAdj = 0;
  439.     armToHitAdj = 0;
  440.     Unconscious = false;
  441.     Dead = false;
  442.  
  443.     document.getElementById('AttackResult').innerHTML = "";
  444.     document.getElementById('DefenseResult').innerHTML = "";
  445.     document.getElementById('Wounds').innerHTML = "";
  446.     document.getElementById('WoundsList').innerHTML = "";
  447.     if(document.getElementById('check4')!==null) {
  448.         document.getElementById('check4').checked = false;
  449.     }
  450.  
  451.     showCharacter();
  452.     showBonusesAndPenalties();
  453. }
  454.  
  455. function arm() {
  456.     document.getElementById('check4').checked = false;
  457.     armSpeedAdj = 0;
  458.     armToHitAdj = 0;
  459.     if(SeriousWoundRightArm){ // Must use wrong hand
  460.         if(SeriousWoundLeftArm){
  461.             // Can't shoot at all
  462.             armSpeedAdj = -100;
  463.             armToHitAdj = -100;
  464.         } else if(LightWoundLeftArm) {
  465.             // -25 Speed, -25 To Hit
  466.             armSpeedAdj = -25;
  467.             armToHitAdj = -25;
  468.         } else {
  469.             // Wrong hand shooting, -10 To Hit
  470.             document.getElementById('check4').checked = true;
  471.             armToHitAdj = -10;
  472.         }
  473.     } else if(LightWoundRightArm) { // Attempts to use wrong hand
  474.         if(SeriousWoundLeftArm){
  475.             // Can't use wrong hand
  476.             // -25 Speed, -25 To Hit
  477.             armSpeedAdj = -25;
  478.             armToHitAdj = -25;
  479.         } else if(LightWoundLeftArm) {
  480.             // -25 Speed, -25 To Hit
  481.             armSpeedAdj = -25;
  482.             armToHitAdj = -25;
  483.         } else {
  484.             // Wrong hand shooting, -10 To Hit
  485.             document.getElementById('check4').checked = true;
  486.             armToHitAdj = -10;
  487.         }
  488.     } else {
  489.         // No penalties to speed or to hit
  490.     }
  491. }
  492.  
  493. function showCharacter() {
  494.     document.getElementById('CharacterSheet').innerHTML =
  495.         tbl([
  496.         row([hdr("&nbsp;"),                  hdr("Roll"),                              hdr("Rating"),                      hdr("Modifier")]),
  497.         row([col(bold("Gun Accuracy")),      col(accuracyWithGunsPercentile),          col(accuracyWithGunsName),          col(accuracyWithGunsToHitAdj)]),
  498.         row([col(bold("Throwing Accuracy")), col(accuracyWithThrownWeaponsPercentile), col(accuracyWithThrownWeaponsName), col(accuracyWithThrownWeaponsToHitAdj)]),
  499.         row([col(bold("Bravery")),           col(braveryPercentile),                   col(braveryName),                   col(braveryToHitAdj)]),
  500.         row([col(bold("Speed")),             col(speedPercentile),                     col(speedName),                     col(speedFirstShotAdj)]),
  501.         row([col(bold("Strength")),          col(strengthPercentile),                  col(strengthName),                  col(strengthScore)])
  502.         ]);
  503. }
  504.  
  505. function showWeaponList() {
  506.     var n = 0;
  507.     document.getElementById('Weapon').innerHTML =
  508.         bold("Weapon: ") +
  509.         sel( Weapons.map(function(w){return opt(n++,w[0]);}), "WeaponList", "doWeapon()" );
  510.     document.getElementById('WeaponDetail').innerHTML = "&nbsp;";
  511. }
  512.  
  513. function showBonusesAndPenalties() {
  514.     var sn = 0, fn = 0, tn = 0, rn = 0;
  515.     var sl, fl, tl, rl;
  516.  
  517.     fl = sel( Movement.map(function(m){return opt(fn++,m[0]);}), "MovementFirer",  "doWeapon()" );
  518.     tl = sel( Movement.map(function(m){return opt(tn++,m[0]);}), "MovementTarget", "doWeapon()" );
  519.     sl = sel( Surprise.map(function(s){return opt(sn++,s[0]);}), "Surprise",       "doWeapon()" );
  520.     rl = sel( Range.map(function(r){return opt(rn++,r[0]);}),    "Range",          "doWeapon()" );
  521.  
  522.     document.getElementById('BonusesAndPenalties').innerHTML =
  523.         bold("Combat Bonuses and Penalties") +
  524.         br() +
  525.         tbl([
  526.             row([col(bold("Movement/Firer")),  col(fl)]),
  527.             row([col(bold("Movement/Target")), col(tl)]),
  528.             row([col(bold("Surprise")),        col(sl)]),
  529.             row([col(bold("Range")),           col(rl)])
  530.         ]) +
  531.         br() +
  532.         checkboxes();
  533. }
  534.  
  535. function checkStatus(){
  536.     if(Dead){
  537.         alert("Your character is DEAD!!! R.I.P. Pardner!");
  538.         return false;
  539.     }
  540.     if(Unconscious){
  541.         alert("Your character is unconscious!");
  542.         return false;
  543.     }
  544.     if(SeriousWoundLeftArm&&SeriousWoundRightArm){
  545.        alert("Both your character's arms are shot off, so he can't fight!");
  546.         return false;
  547.     }
  548.     return true;
  549. }
  550.  
  551. function doWeapon() {
  552.     var idx = document.getElementById('WeaponList').value;
  553.     var mf = document.getElementById('MovementFirer').value;
  554.     var mt = document.getElementById('MovementTarget').value;
  555.     var surprise = document.getElementById('Surprise').value;
  556.     var range = document.getElementById('Range').value;
  557.     var toHitExperienceAdj = getValue(Experience, Won+Lost, 2, 0);
  558.     var w;
  559.     var speedMovementAdj, toHitMovementFirerAdj, toHitMovementTargetAdj, woundAdj, surpriseAdj, rangeAdj;
  560.     var i, miscSpeedAdj = 0, miscToHitAdj = 0;
  561.  
  562.     arm();
  563.  
  564.     checkShotOrScatterGunAtShortRange();
  565.  
  566.     if(strengthScore<0.5*origStrengthScore) {
  567.        document.getElementById('Wounds').innerHTML = Wounds[2][0];
  568.        woundAdj = Wounds[2][1];
  569.    } else if(strengthScore<origStrengthScore&&strengthScore>=0.5*origStrengthScore) {
  570.         document.getElementById('Wounds').innerHTML = Wounds[1][0];
  571.         woundAdj = Wounds[1][1];
  572.     } else {
  573.         document.getElementById('Wounds').innerHTML = Wounds[0][0];
  574.         woundAdj = Wounds[0][1];
  575.     }
  576.  
  577.     if(mf>=0&&mf<Movement.length) {
  578.        speedMovementAdj = Movement[mf][1];
  579.         toHitMovementFirerAdj = Movement[mf][2];
  580.     } else {
  581.         speedMovementAdj = 0;
  582.         toHitMovementFirerAdj = 0;
  583.     }
  584.  
  585.     if(mt>=0&&mt<Movement.length) {
  586.        toHitMovementTargetAdj = Movement[mt][3];
  587.     } else {
  588.         toHitMovementTargetAdj = 0;
  589.     }
  590.  
  591.     if(surprise>=0&&surprise<Surprise.length) {
  592.        surpriseAdj = Surprise[surprise][1];
  593.     } else {
  594.         surpriseAdj = 0;
  595.     }
  596.  
  597.     if(range>=0&&range<Range.length) {
  598.        rangeAdj = Range[range][1];
  599.     } else {
  600.         rangeAdj = 0;
  601.     }
  602.  
  603.     // Miscellaneous Adj
  604.     for(i=0; i<Miscellaneous.length; i++) {
  605.        if( document.getElementById('check'+i).checked ) {
  606.            miscSpeedAdj += Miscellaneous[i][1];
  607.            miscToHitAdj += Miscellaneous[i][2];
  608.        }
  609.    }
  610.  
  611.    if(idx==0){ // No Weapon
  612.        document.getElementById('WeaponDetail').innerHTML = "&nbsp;";
  613.        firstShot = 0;
  614.        toHit = 0;
  615.    } else if(idx>=1&&idx<=3){ // Thrown Weapon
  616.        w = Weapons[idx];
  617.         firstShot = speedFirstShotAdj + WeaponSpeed[w[5]] + speedMovementAdj +
  618.             woundAdj + surpriseAdj + miscSpeedAdj + armSpeedAdj;
  619.         toHit = 50 + accuracyWithThrownWeaponsToHitAdj + braveryToHitAdj +
  620.             toHitMovementFirerAdj + toHitMovementTargetAdj + woundAdj +
  621.             rangeAdj + miscToHitAdj + toHitExperienceAdj + armToHitAdj;
  622.         document.getElementById('WeaponDetail').innerHTML =
  623.                 bold(col(w[0]));
  624.         document.getElementById('WeaponDetail').innerHTML +=
  625.             tbl([
  626.                 row([col("Short Range"), col(w[1]), col("inches")]),
  627.                 row([col("Medium Range"), col(w[2]), col("inches")]),
  628.                 row([col("Long Range"), col(w[3]), col("inches")]),
  629.                 row([col("Rate"), col(w[4]), col("Note that if more than one shot is fired, 10% is subtracted from the accuracy of each shot")]),
  630.                 row([col("Speed"), col(w[5]), col("&nbsp;")]),
  631.                 row([col("First Shot"), col(firstShot), col("&nbsp;")]),
  632.                 row([col("To Hit"), col(toHit), col("&nbsp;")])
  633.             ]);
  634.     } else { // Gun
  635.         w = Weapons[idx];
  636.         firstShot = speedFirstShotAdj + WeaponSpeed[w[5]] + speedMovementAdj +
  637.             woundAdj + surpriseAdj + miscSpeedAdj + armSpeedAdj;
  638.         toHit = 50 + accuracyWithGunsToHitAdj + braveryToHitAdj +
  639.             toHitMovementFirerAdj + toHitMovementTargetAdj + woundAdj +
  640.             rangeAdj + miscToHitAdj + toHitExperienceAdj + armToHitAdj;
  641.         document.getElementById('WeaponDetail').innerHTML =
  642.                 bold(col(w[0]));
  643.         document.getElementById('WeaponDetail').innerHTML +=
  644.             tbl([
  645.                 row([col("Short Range"), col(w[1]), col("inches")]),
  646.                 row([col("Medium Range"), col(w[2]), col("inches")]),
  647.                 row([col("Long Range"), col(w[3]), col("inches")]),
  648.                 row([col("Rate"), col(w[4]), col("Note that if more than one shot is fired, 10% is subtracted from the accuracy of each shot")]),
  649.                 row([col("Speed"), col(w[5]), col("&nbsp;")]),
  650.                 row([col("Ammunition"), col(w[6]), col("&nbsp;")]),
  651.                 row([col("Reload"), col(w[7]), col("first turn")]),
  652.                 row([col("Reload"), col(w[8]), col("following turns")]),
  653.                 row([col("First Shot"), col(firstShot), col("&nbsp;")]),
  654.                 row([col("To Hit"), col(toHit), col("&nbsp;")])
  655.             ]);
  656.     }
  657. }
  658.  
  659. function checkShotOrScatterGunAtShortRange() {
  660.     if(document.getElementById('Range').value==0) {
  661.         if(document.getElementById('WeaponList').value==11||
  662.            document.getElementById('WeaponList').value==12){
  663.                 document.getElementById('check2').checked = true;
  664.         } else {
  665.                 document.getElementById('check2').checked = false;
  666.         }
  667.         if(document.getElementById('WeaponList').value==13||
  668.            document.getElementById('WeaponList').value==14){
  669.                 document.getElementById('check3').checked = true;
  670.         } else {
  671.                 document.getElementById('check3').checked = false;
  672.         }
  673.     } else {
  674.             document.getElementById('check2').checked = false;
  675.             document.getElementById('check3').checked = false;
  676.     }
  677. }
  678.  
  679. function checkboxes() {
  680.     var i, j, checkbox, table = [], rho;
  681.     for(i=0; i<4; i++){
  682.        rho = [];
  683.        for(j=0; j<3; j++){
  684.            if(3*i+j>=Miscellaneous.length) break;
  685.             checkbox = "<input type=\"checkbox\" id=\"check"+(3*i+j)+"\" onchange=\"doWeapon()\">"+Miscellaneous[3*i+j][0]+"</input>";
  686.             rho = rho.concat(col(checkbox));
  687.         }
  688.         rho = row(rho); // your boat, gently down the stream
  689.         table = table.concat(rho);
  690.     }
  691.     table = tbl(table);
  692.     return table;
  693. }
  694.  
  695. function isShotOrScatterGunAtShortRange() {
  696.     if(document.getElementById('Range')!==null&&
  697.        document.getElementById('Range').value==0&&
  698.          (document.getElementById('WeaponList').value==11||
  699.           document.getElementById('WeaponList').value==12||
  700.           document.getElementById('WeaponList').value==13||
  701.           document.getElementById('WeaponList').value==14))
  702.    {
  703.            return true;
  704.     }
  705.     return false;
  706. }
  707.  
  708. function isShotOrScatterGunAtLongRange() {
  709.     if(document.getElementById('Range')!==null&&
  710.        document.getElementById('Range').value==2&&
  711.          (document.getElementById('WeaponList').value==11||
  712.           document.getElementById('WeaponList').value==12||
  713.           document.getElementById('WeaponList').value==13||
  714.           document.getElementById('WeaponList').value==14))
  715.    {
  716.            return true;
  717.     }
  718.     return false;
  719. }
  720.  
  721. function attack(){
  722.     if( checkStatus() ){
  723.         doWeapon();
  724.         if(d100()<=toHit) {
  725.            woundOpponent();
  726.        } else {
  727.            document.getElementById('AttackResult').innerHTML =
  728.                "Your shot misses your opponent.";
  729.        }
  730.    }
  731. }
  732.  
  733. function defend(){
  734.    var oppToHit, roll;
  735.    oppToHit = document.getElementById('OppToHit').value;
  736.    roll = d100();
  737.    console.log("oppToHit="+oppToHit);
  738.    console.log("roll="+roll);
  739.    if(roll<=oppToHit) {
  740.        woundSelf();
  741.    } else {
  742.        document.getElementById('DefenseResult').innerHTML =
  743.            "Your opponent's shot misses you!";
  744.    }
  745. }
  746.  
  747. function woundOpponent(){
  748.    var rollAdj = 0, locationRoll, woundRoll, idx, locationName, woundTable, wound;
  749.    if(isShotOrScatterGunAtShortRange()){
  750.        rollAdj = 15;
  751.    } else if(isShotOrScatterGunAtLongRange()) {
  752.        rollAdj = -20;
  753.    }
  754.    locationRoll = d100() + rollAdj;
  755.    woundRoll = d100() + rollAdj;
  756.    if(locationRoll<1||woundRoll<1) {
  757.        document.getElementById('AttackResult').innerHTML = "No damage.";
  758.        return;
  759.    }
  760.    if(locationRoll>100){
  761.         locationRoll = 100;
  762.     }
  763.     if(woundRoll>100) {
  764.         woundRoll = 100;
  765.     }
  766.     idx = getValue(Exact_Hit_Location, locationRoll, 3, 0);
  767.     locationName = Exact_Hit_Location[idx][2];
  768.     woundTable = Exact_Hit_Location[idx][4];
  769.     wound = getValue(woundTable, woundRoll, 2, "");
  770.     document.getElementById('AttackResult').innerHTML =
  771.         "You successfully shoot your opponent in the " +
  772.         locationName +
  773.         " causing a " +
  774.         wound;
  775. }
  776.  
  777. function woundSelf(){
  778.     var rollAdj, locationRoll, woundRoll, idx, locationName, woundTable, wound;
  779.     rollAdj = parseInt(document.getElementById('DamageMod').value);
  780.     locationRoll = d100() + rollAdj;
  781.     woundRoll = d100() + rollAdj;
  782.     if(locationRoll<1||woundRoll<1) {
  783.        document.getElementById('DefenseResult').innerHTML = "No damage.";
  784.        return;
  785.    }
  786.    if(locationRoll>100){
  787.         locationRoll = 100;
  788.     }
  789.     if(woundRoll>100) {
  790.         woundRoll = 100;
  791.     }
  792.     idx = getValue(Exact_Hit_Location, locationRoll, 3, 0);
  793.     locationName = Exact_Hit_Location[idx][2];
  794.     woundTable = Exact_Hit_Location[idx][4];
  795.     wound = getValue(woundTable, woundRoll, 2, "");
  796.     if(wound.match(/^Mortal/)){
  797.         Dead = true;
  798.         strengthScore = 0;
  799.     } else if(wound.match(/^Serious/)){
  800.         if(idx==2) {
  801.             SeriousWoundLeftArm = true;
  802.         } else if(idx==3) {
  803.             SeriousWoundRightArm = true;
  804.         }
  805.         strengthScore -= 7;
  806.     } else {
  807.         if(idx==2) {
  808.             LightWoundLeftArm = true;
  809.         } else if(idx==3) {
  810.             LightWoundRightArm = true;
  811.         }
  812.         strengthScore -= 3;
  813.     }
  814.     if(strengthScore<=0){
  815.        Unconscious = true;
  816.    }
  817.    document.getElementById('DefenseResult').innerHTML =
  818.        "Your opponent shoots you in the " +
  819.        locationName +
  820.        " causing a " +
  821.        wound;
  822.    document.getElementById('WoundsList').innerHTML +=
  823.        "<li>" +
  824.         locationName +
  825.         " : " +
  826.         wound +
  827.         "</li>";
  828.  
  829.     showCharacter();
  830.     doWeapon();
  831.     checkStatus();
  832. }
  833.  
  834. function showExperience() {
  835.     document.getElementById('Experience').innerHTML =
  836.         bold("Experience: ") +
  837.         span("xp",Won+Lost) + " Total Gunfights: " +
  838.         span("won", Won) + " Won " + button("incWon", "+") +
  839.         " / " +
  840.         span("lost", Lost) + " Lost " + button("incLost", "+");
  841. }
  842.  
  843. function incWon() {
  844.     Won++;
  845.     document.getElementById('won').innerHTML = Won;
  846.     document.getElementById('xp').innerHTML = Won + Lost;
  847.  
  848.     accuracyWithGunsPercentile += getValue(XP_Accuracy, accuracyWithGunsPercentile, 2, 0);
  849.     accuracyWithGunsName = getValue(Accuracy, accuracyWithGunsPercentile, 2, "");
  850.     accuracyWithGunsToHitAdj = getValue(Accuracy, accuracyWithGunsPercentile, 3, 0);
  851.  
  852.     braveryPercentile += getValue(XP_Bravery, braveryPercentile, 2, 0);
  853.     braveryName = getValue(Bravery, braveryPercentile, 2, "");
  854.     braveryToHitAdj = getValue(Bravery, braveryPercentile, 3, 0);
  855.  
  856.     speedPercentile += getValue(XP_Speed, speedPercentile, 2, 0);
  857.     speedName = getValue(Speed, speedPercentile, 2, "");
  858.     speedFirstShotAdj = getValue(Speed, speedPercentile, 3, 0);
  859.  
  860.     showCharacter();
  861.     doWeapon();
  862. }
  863.  
  864. function incLost() {
  865.     Lost++;
  866.     document.getElementById('lost').innerHTML = Lost;
  867.     document.getElementById('xp').innerHTML = Won + Lost;
  868.     doWeapon();
  869. }
  870.  
  871. function setCharacter() {
  872.     accuracyWithGunsPercentile = parseInt(query_string.GunAccuracy);
  873.     accuracyWithGunsPercentile += bonus(accuracyWithGunsPercentile);
  874.     accuracyWithGunsName = getValue(Accuracy, accuracyWithGunsPercentile, 2, "");
  875.     accuracyWithGunsToHitAdj = getValue(Accuracy, accuracyWithGunsPercentile, 3, 0);
  876.  
  877.     accuracyWithThrownWeaponsPercentile = parseInt(query_string.ThrowingAccuracy);
  878.     accuracyWithThrownWeaponsName = getValue(Accuracy, accuracyWithThrownWeaponsPercentile, 2, "");
  879.     accuracyWithThrownWeaponsToHitAdj = getValue(Accuracy, accuracyWithThrownWeaponsPercentile, 3, 0);
  880.  
  881.     braveryPercentile = parseInt(query_string.Bravery);
  882.     braveryName = getValue(Bravery, braveryPercentile, 2, "");
  883.     braveryToHitAdj = getValue(Bravery, braveryPercentile, 3, 0);
  884.  
  885.     speedPercentile = parseInt(query_string.Speed);
  886.     speedName = getValue(Speed, speedPercentile, 2, "");
  887.     speedFirstShotAdj = getValue(Speed, speedPercentile, 3, 0);
  888.  
  889.     strengthPercentile = parseInt(query_string.Strength);
  890.     strengthName = getValue(Strength, strengthPercentile, 3, "");
  891.     strengthScore = getValue(Strength, strengthPercentile, 2, 0);
  892.     origStrengthScore = strengthScore;
  893.  
  894.     if(query_string.Won&&query_string.Lost) {
  895.        Won = parseInt(query_string.Won);
  896.         Lost = parseInt(query_string.Lost);
  897.     }
  898.  
  899.     resetWounds();
  900.     showWeaponList();
  901.     showExperience();
  902. }
  903.  
  904. function doQueryString() {
  905.     var query = top.location.search.substring(1);
  906.     var vars = query.split("&");
  907.     for (var i=0;i<vars.length;i++) {
  908.      var pair = vars[i].split("=");
  909.      if (typeof query_string[pair[0]] === "undefined") {
  910.        query_string[pair[0]] = decodeURIComponent(pair[1]);
  911.      } else if (typeof query_string[pair[0]] === "string") {
  912.        var arr = [ query_string[pair[0]],decodeURIComponent(pair[1]) ];
  913.        query_string[pair[0]] = arr;
  914.      } else {
  915.        query_string[pair[0]].push(decodeURIComponent(pair[1]));
  916.      }
  917.    }
  918.    if(query_string.GunAccuracy&&query_string.ThrowingAccuracy&&query_string.Bravery&&query_string.Speed&&query_string.Strength) {
  919.        setCharacter();
  920.        document.getElementById('QueryString').innerHTML = button("setCharacter", "Reset character using query string");
  921.  }
  922. }
  923. </script>
  924. </head>
  925. <body onload="doQueryString()">
  926. <div><img src="http://fontmeme.com/freefonts/img.php?f=194637&s=65&t=Boot%20Hill&c=000000" alt="Boot Hill"></div>
  927. <div><i>Character generator for the 1975 edition of the Western-themed RPG by Brian Blume &amp; Gary Gygax.</i></div>
  928. <div id="CharacterSheet"></div>
  929. <div><button onclick="generateCharacter()">Generate Character</button></div>
  930. <div id="QueryString"></div>
  931. <div id="Experience"></div>
  932. <hr>
  933. <div id="Weapon"></div>
  934. <div id="BonusesAndPenalties"></div>
  935. <div id="WeaponDetail"></div>
  936. <div id="Attack"><button onclick="attack()">Attack</button><span id="AttackResult"></span></div>
  937. <hr>
  938. <div id="Defend">Opponent's chance to hit you (01--100): <input id="OppToHit" type="number" value="50"/> %
  939.     <br/>Damage modifiers: <input type="radio" id="DamageMod" value="15"/> Shot/Scatter Gun at Long Range
  940.     <input type="radio" id="DamageMod" value="20"/> Shot/Scatter Gun at Short Range
  941.     <input type="radio" id="DamageMod" value="0" checked="checked"/> Neither
  942.     <br/><button onclick="defend()">Defend</button> <span id="DefenseResult"></span>
  943.     <br/><b>Wounds:</b> <span id="Wounds">None</span>
  944.     <br/><ol id="WoundsList"></ol>
  945.     <br/><button onclick="resetWounds()">Reset Wounds</button>
  946. </div>
  947. </body>
  948. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement