├── .gitignore ├── index.html ├── travellercharacter.css ├── README.md └── travellercharacter.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Classic Traveller Character Generator 7 | 8 | 9 | 10 | 11 | 12 | 13 |

Classic Traveller Character Generator

14 | 15 |
16 | 17 |
18 | 19 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /travellercharacter.css: -------------------------------------------------------------------------------- 1 | @media screen { 2 | body { 3 | background: #000; 4 | color: #fff; 5 | } 6 | hr { 7 | background: red; 8 | border: 0; 9 | height: 1px; 10 | margin: 1em 0em 1.5em -10em; 11 | } 12 | } 13 | @media print { 14 | body { 15 | background: #fff; 16 | color: #000; 17 | } 18 | hr { 19 | display: none; 20 | } 21 | #noprintheader { 22 | display: none; 23 | } 24 | } 25 | body { 26 | background: #000; 27 | color: #fff; 28 | font-family: "Dejavu Sans Mono", Inconsolata, Monaco, Courier, monospace; 29 | font-size: 12pt; 30 | padding: 1em 4em 1em 4em; 31 | } 32 | #travchar { 33 | white-space: pre-wrap; 34 | width: 45em; 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Classic Traveller Character Generator # 2 | 3 | This JavaScript character generator for the classic Traveller sci-fi roleplaying game follows the character creation rules in The Traveller Book ([available in PDF](https://www.rpgnow.com/product/80192/CTTTBThe-Traveller-Book)). 4 | 5 | Yes, characters _can_ die during character creation! 6 | 7 | [Play with it now.](https://devilghost.com/software/travellercharacter/) 8 | 9 | (Reload the page to generate another character.) 10 | 11 | Thanks to a contribution from Frank Filz, a [verbose mode](https://devilghost.com/software/travellercharacter/index.html?history=verbose) adds behind-the-scenes character creation details. 12 | 13 | ## License (2-Clause BSD License) ## 14 | 15 | Copyright © 2015, Paul Gorman 16 | All rights reserved. 17 | 18 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 19 | 20 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 21 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /travellercharacter.js: -------------------------------------------------------------------------------- 1 | // Classic Traveller RPG character generator 2 | // Paul Gorman 2015 3 | // https://devilghost.com/software/travellercharacter/ 4 | // https://github.com/pgorman/travellercharactergenerator 5 | // 6 | // Additional Contributors 7 | // Frank Filz 8 | // 9 | // URL Parameters ?param=value¶m=value 10 | // 11 | // history= 12 | // verbose - show all the rolls 13 | // none - don't show the history at all 14 | // any other value results in a simplified history 15 | // 16 | // service= 17 | // specify a preferred service instead of random 18 | // 19 | // minscore= 20 | // specify the minimum score for the preferred service (applies to the 21 | // random service if a preferred service is not specified). A minscore 22 | // of 9999 overrides the enlistment roll. A minscore of 8888 overrides 23 | // the draft with the preferred service (the character is still treated 24 | // as having been drafted, but the preferred service is chosen). These 25 | // special values allow generating characters that are a specific 26 | // service. 27 | // 28 | // muster= 29 | // ship - don't roll for cash until a ship is acquired if possible 30 | // TAS - don't roll for cash until Travellers' is acquired if possible 31 | // special - combination of above 32 | // split - alternate cash and material benefits rolls (until mmaximum 33 | // number of cash rolls have been taken). 34 | // 35 | // maxcash= 36 | // The maximum number of cash rolls to make, if not combined with 37 | // muster, any cash rolls will be taken first. 38 | // 39 | // 40 | // hunt= 41 | // ship - keep rolling characters until a ship is acquired 42 | // TAS - keep rolling characters until Travellers' is acquired 43 | // special - keep rolling until ship or TAS is acquired 44 | // skill - keep rolling until skill is acquired 45 | // 46 | // level= 47 | // when used with hunt=skill, specifies the level of skill sought 48 | // 49 | // 50 | // vehicles= 51 | // dole out vehicle skills as one of 1977, 1981, TTB, or ST 52 | // default is as TTB 53 | function travellerCharacter(output) { 54 | // output is 'text', 'html', or 'JSON'. 55 | 56 | String.prototype.capitalize = function() { 57 | // Accept "word" and return "Word". 58 | return this.charAt(0).toUpperCase() + this.slice(1); 59 | }; 60 | 61 | function rndInt(min, max) { 62 | return Math.floor(Math.random() * (max - min + 1)) + min; 63 | } 64 | 65 | function arnd(a) { 66 | // Return random element of array a. 67 | var i = Math.floor(Math.random() * (a.length)); 68 | if (typeof a[i] === 'function') { 69 | return a[i](); 70 | } 71 | return a[i]; 72 | } 73 | 74 | function roll(rolls) { 75 | // Return total of six-sided dice rolls. 76 | var total = 0; 77 | for (var i = 0; i < rolls; i++) { 78 | total += Math.floor(Math.random() * 6 + 1); 79 | } 80 | return total; 81 | } 82 | 83 | function decToHex(n) { 84 | // Convert decimal number to hexadecimal. 85 | return n.toString(16).toUpperCase(); 86 | } 87 | 88 | function numCommaSep(n) { 89 | // Format numbers like 1,000,000. 90 | return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); 91 | } 92 | 93 | function intToOrdinal(i) { 94 | switch (i) { 95 | case 1: return 'first'; 96 | case 2: return 'second'; 97 | case 3: return 'third'; 98 | case 4: return 'fourth'; 99 | case 5: return 'fifth'; 100 | case 6: return 'sixth'; 101 | case 7: return 'seventh'; 102 | case 8: return 'eighth'; 103 | case 9: return 'ninth'; 104 | case 10: return 'tenth'; 105 | default: return i + 'th'; 106 | } 107 | } 108 | 109 | function generateName(gender) { 110 | var given = []; 111 | if (gender == 'female') { // Female names 112 | given = ['Alice', 'Ananya', 'Beatriz', 'Cai', 'Chloe', 'Darpana', 'Elena', 'Emily', 'Emma', 'Esperanza', 'Fang', 'Fatima', 'Freja', 'Harper', 'Ida', 'Isidora', 'Kana', 'Kayla', 'Khadija', 'Lena', 'Malika', 'Manon', 'Mariam', 'Marie', 'Mary', 'Martha', 'Milagrosa', 'Nadia', 'Nina', 'Olivia', 'Petra', 'Rin', 'Rosalie', 'Sara', 'Shu', 'Sophia', 'Trisha', 'Valentina', 'Victoria', 'Vivien', 'Xia', 'Yan', 'Zhen', 'Zoe']; 113 | } else { 114 | given = ['Adam', 'Ahmed', 'Ali', 'An', 'Andrew', 'Antonio', 'Aarav', 'Aziz', 'Bartholomew', 'Ben', 'Bo', 'Brom', 'Bruno', 'Charles', 'Cheng', 'Daniel', 'David', 'Diego', 'Feng', 'Finn', 'Gabriel', 'George', 'Hamza', 'Haruto', 'Hiroto', 'Hugo', 'Jack', 'Jacob', 'James', 'John', 'Juan', 'Judas', 'Leo', 'Logan', 'Luis', 'Luke', 'Magnus', 'Mark', 'Mehmet', 'Mohamed', 'Nicolas', 'Noam', 'Oliver', 'Omar', 'Paul', 'Peng', 'Philip', 'Quentin', 'Rachid', 'Ren', 'Said', 'Santino', 'Simon', 'Stanisław', 'Stefan', 'Thaddaeus', 'Thomas', 'Victor', 'William', 'Wei', 'Wen', 'Yi', 'Youssef']; 115 | } 116 | var family = ['Abe', 'Anderson', 'Bautista', 'Bauer', 'Becker', 'Brown', 'Chang', 'Chen', 'Chu', 'Cohen', 'Colombo', 'Cruz', 'Das', 'Das', 'Davies', 'Díaz', 'Dubois', 'Esposito', 'Evans', 'Fernandes', 'Fontana', 'Fujii', 'García', 'Gazi', 'Green', 'Gruber', 'Hall', 'Han', 'Hernández', 'Hoffmann', 'Hon', 'Hong', 'Itō', 'Ivanov', 'Jensen', 'Jones', 'Kask', 'Katz', 'Kelly', 'Khan', 'Kim', 'Klein', 'Kowalski', 'Larsen', 'Lee', 'Li', 'Lin', 'Ma', 'Martin', 'Mirza', 'Moreau', 'Murphy', 'Nakamura', 'Novák', 'Ota', 'Papadopoulos', 'Pérez', 'Petrov', 'Pavlov', 'Popov', 'Quinn', 'Reyes', 'Rizzo', 'Robinson', 'Rodríguez', 'Rossi', 'Saar', 'Santos', 'Satō', 'Schmidt', 'Shin', 'Silva', 'Sokolov', 'Sullivan', 'Sun', 'Suzuki', 'Singh', 'Smith', 'Tamm', 'Tanaka', 'Taylor', 'Varga', 'Wagner', 'Wang', 'Watanabe', 'Weber', 'Wen', 'White', 'Williams', 'Wilson', 'Wood', 'Wu', 'Yamamoto', 'Yamazaki', 'Yang', 'Zhang']; 117 | return arnd(given) + ' ' + arnd(family); 118 | } 119 | 120 | function generateGender() { 121 | if (roll(1) <= 2) { 122 | return 'female'; 123 | } else { 124 | return 'male'; 125 | } 126 | } 127 | 128 | //------------------------ Cascade Skills ------------------------// 129 | function cascadeBlade() { 130 | // Call like cascadeBlade.call(t) 131 | var blades = ['Dagger', 'Foil', 'Sword', 'Cutlass', 'Broadsword', 'Bayonet', 'Spear', 'Halberd', 'Pike', 'Cudgel']; 132 | var knownBlades = []; 133 | if (this.urlParam('cascade') == 'skip') { 134 | return 'Blade'; 135 | } 136 | for (var i = 0, limit = this.skills.length; i < limit; i++) { 137 | if (blades.indexOf(this.skills[i][0]) > -1) { 138 | knownBlades.push(this.skills[i][0]); 139 | } 140 | } 141 | if (knownBlades.length > 0) { 142 | return arnd(knownBlades); 143 | } else { 144 | return arnd(blades); 145 | } 146 | } 147 | function cascadeBow() { 148 | // Call like cascadeBlade.call(t) 149 | var bows = ['Sling', 'Short Bow', 'Long Bow', 'Sporting Crossbow', 'Military Crossbow', 'Repeating Crossbow']; 150 | var knownBows = []; 151 | if (this.urlParam('cascade') == 'skip') { 152 | return 'Blade'; 153 | } 154 | for (var i = 0, limit = this.skills.length; i < limit; i++) { 155 | if (bows.indexOf(this.skills[i][0]) > -1) { 156 | knownBows.push(this.skills[i][0]); 157 | } 158 | } 159 | if (knownBows.length > 0) { 160 | return arnd(knownBows); 161 | } else { 162 | return arnd(bows); 163 | } 164 | } 165 | function cascadeGun() { 166 | // Call like cascadeGun.call(t) 167 | var guns = ['Body Pistol', 'Auto Pistol', 'Revolver', 'Carbine', 'Rifle', 'Auto Rifle', 'Shotgun', 'SMG', 'Laser Carbine', 'Laser Rifle']; 168 | var knownGuns = []; 169 | if (this.urlParam('cascade') == 'skip') { 170 | return 'Gun'; 171 | } 172 | for (var i = 0, limit = this.skills.length; i < limit; i++) { 173 | if (guns.indexOf(this.skills[i][0]) > -1) { 174 | knownGuns.push(this.skills[i][0]); 175 | } 176 | } 177 | if (knownGuns.length > 0) { 178 | return arnd(knownGuns); 179 | } else { 180 | return arnd(guns); 181 | } 182 | } 183 | function cascadeVehicle() { 184 | // Call like cascadeVehicle.call(t) 185 | var vehicles = ['Prop-Driven Aircraft', 'Jet-Driven Aircraft', 'Helicopter', 'Grav Vehicle', 'Tracked Vehicle', 'Wheeled Vehicle', 'Large Watercraft', 'Small Watercraft', 'Hovercraft', 'Submersible']; 186 | var knownVehicles = []; 187 | if (this.urlParam('cascade') == 'skip') { 188 | return 'Vehicle'; 189 | } 190 | for (var i = 0, limit = this.skills.length; i < limit; i++) { 191 | if (vehicles.indexOf(this.skills[i][0]) > -1) { 192 | knownVehicles.push(this.skills[i][0]); 193 | } 194 | } 195 | if (knownVehicles.length > 0) { 196 | return arnd(knownVehicles); 197 | } else { 198 | return arnd(vehicles); 199 | } 200 | } 201 | function cascadeAircraft() { 202 | // Call like cascadeVehicle.call(t) 203 | var aircrafts = ['Prop-Driven Aircraft', 'Jet-Driven Aircraft', 'Helicopter', 'Grav Vehicle']; 204 | var knownAircrafts = []; 205 | if (this.urlParam('cascade') == 'skip') { 206 | return 'Aircraft'; 207 | } 208 | for (var i = 0, limit = this.skills.length; i < limit; i++) { 209 | if (aircrafts.indexOf(this.skills[i][0]) > -1) { 210 | knownAircrafts.push(this.skills[i][0]); 211 | } 212 | } 213 | if (knownAircrafts.length > 0) { 214 | return arnd(knownAircrafts); 215 | } else { 216 | return arnd(aircrafts); 217 | } 218 | } 219 | function cascadeServiceAircraft() { 220 | // Call like cascadeVehicle.call(t) 221 | var aircrafts = ['Prop-Driven Aircraft', 'Jet-Driven Aircraft', 'Helicopter', 'Grav Vehicle']; 222 | return arnd(aircrafts); 223 | } 224 | function cascadeWatercraft() { 225 | // Call like cascadeWatercraft.call(t) 226 | var watercrafts = ['Small Watercraft', 'Hovercraft']; 227 | var knownWatercrafts = []; 228 | if (this.urlParam('cascade') == 'skip') { 229 | return 'Watercraft'; 230 | } 231 | for (var i = 0, limit = this.skills.length; i < limit; i++) { 232 | if (watercrafts.indexOf(this.skills[i][0]) > -1) { 233 | knownWatercrafts.push(this.skills[i][0]); 234 | } 235 | } 236 | if (knownWatercrafts.length > 0) { 237 | return arnd(knownWatercrafts); 238 | } else { 239 | return arnd(watercrafts); 240 | } 241 | } 242 | 243 | //---------------- "s" object holds service definitions ----------------// 244 | var s = {}; 245 | s.services = ['navy', 'marines', 'army', 'scouts', 'merchants', 'pirates', 'other', 'belters', 'sailors', 'diplomats', 'doctors', 'flyers', 'barbarians', 'bureaucrats', 'rogues', 'scientists', 'hunters']; 246 | s.draftservices = ['navy', 'marines', 'army', 'scouts', 'sailors', 'flyers']; 247 | s.draft = function () { 248 | return arnd(this.draftservices); 249 | }; 250 | //---------------- Define "Navy" service ----------------// 251 | s.navy = { 252 | serviceName: 'Navy', // like "in the Navy" 253 | memberName: 'Navy', // like "Navy Admiral Nelson" 254 | adjName: "Naval", // like "the Naval service" 255 | enlistmentThrow: 8, 256 | enlistmentDM: function (attributes) { 257 | var dm = 0; 258 | if (attributes.intelligence >= 8) { dm += 1; } 259 | if (attributes.education >= 9) { dm += 2; } 260 | return dm; 261 | }, 262 | survivalThrow: 5, 263 | survivalDM: function (attributes) { 264 | var dm = 0; 265 | if (attributes.intelligence >= 7) { dm += 2; } 266 | return dm; 267 | }, 268 | commissionThrow: 10, 269 | commissionDM: function (attributes) { 270 | var dm = 0; 271 | if (attributes.social >= 9) { dm += 1; } 272 | return dm; 273 | }, 274 | promotionThrow: 8, 275 | promotionDM: function (attributes) { 276 | var dm = 0; 277 | if (attributes.education >= 8) { dm += 1; } 278 | return dm; 279 | }, 280 | getServiceSkills: function () { return []; }, 281 | checkSurvival: function () { 282 | var dm = 0; 283 | var sv = roll(2); 284 | if (this.attributes.intelligence >= 7) { dm += 2; } 285 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 286 | if ((sv + dm) >= 5) { 287 | return true; 288 | } else { 289 | return false; 290 | } 291 | }, 292 | reenlistThrow: 6, 293 | ranks: { 294 | 0: 'Starman', 295 | 1: 'Ensign', 296 | 2: 'Lieutenant', 297 | 3: 'Lt Cmdr', 298 | 4: 'Commander', 299 | 5: 'Captain', 300 | 6: 'Admiral' 301 | }, 302 | checkPromotion: function () { 303 | var dm = 0; 304 | var sv = roll(2); 305 | if (this.attributes.education >= 8) { dm += 1; } 306 | this.verboseHistory('Promotion roll ' + sv + ' + ' + dm + ' vs ' + 8); 307 | if ((sv + dm) >= 8) { 308 | return true; 309 | } else { 310 | return false; 311 | } 312 | }, 313 | checkCommission: function() { 314 | var dm = 0; 315 | var sv = roll(2); 316 | if (this.attributes.social >= 9) { dm += 1; } 317 | this.verboseHistory('Commission roll ' + sv + ' + ' + dm + ' vs ' + 10); 318 | if ((sv + dm) >= 10) { 319 | return true; 320 | } else { 321 | return false; 322 | } 323 | }, 324 | doPromotion: function() { 325 | if (this.rank == 5 || this.rank == 6) { 326 | this.improveAttribute('social', 1); 327 | } 328 | }, 329 | musterCash: { 330 | 1: 1000, 331 | 2: 5000, 332 | 3: 5000, 333 | 4: 10000, 334 | 5: 20000, 335 | 6: 50000, 336 | 7: 50000 337 | }, 338 | musterBenefits: function (dm) { 339 | switch(roll(1) + dm) { 340 | case 1: 341 | this.addBenefit.call(t, 'Low Passage'); 342 | break; 343 | case 2: 344 | this.improveAttribute('intelligence', 1); 345 | break; 346 | case 3: 347 | this.improveAttribute('education', 1); 348 | break; 349 | case 4: 350 | this.doBladeBenefit.call(t); 351 | break; 352 | case 5: 353 | if (this.benefits.indexOf("Travellers' Aide Society") > -1) { 354 | break; 355 | } 356 | this.addBenefit.call(t, "Travellers' Aid Society"); 357 | this.TAS = true; 358 | break; 359 | case 6: 360 | this.addBenefit.call(t, 'High Passage'); 361 | break; 362 | default: 363 | this.improveAttribute('social', 2); 364 | } 365 | }, 366 | canMuster: function (strategy) { 367 | return strategy == 'TAS' || strategy == 'special'; 368 | }, 369 | acquireSkill: function () { 370 | // Skills acquired during a term of service. 371 | switch(this.whichSkillTable.call(this)) { 372 | case 1: 373 | switch(roll(1)) { 374 | case 1: this.improveAttribute('strength', 1); break; 375 | case 2: this.improveAttribute('dexterity', 1); break; 376 | case 3: this.improveAttribute('endurance', 1); break; 377 | case 4: this.improveAttribute('intelligence', 1); break; 378 | case 5: this.improveAttribute('education', 1); break; 379 | default: this.improveAttribute('social', 1); 380 | } 381 | break; 382 | case 2: 383 | switch(roll(1)) { 384 | case 1: this.addSkill("Ship's Boat"); break; 385 | case 2: this.addSkill('Vacc Suit'); break; 386 | case 3: this.addSkill('Fwd Obsvr'); break; 387 | case 4: this.addSkill('Gunnery'); break; 388 | case 5: this.addSkill(cascadeBlade.call(this)); break; 389 | default: this.addSkill(cascadeGun.call(this)); 390 | } 391 | break; 392 | case 3: 393 | switch(roll(1)) { 394 | case 1: this.addSkill('Vacc Suit'); break; 395 | case 2: this.addSkill('Mechanical'); break; 396 | case 3: this.addSkill('Electronics'); break; 397 | case 4: this.addSkill('Engineering'); break; 398 | case 5: this.addSkill('Gunnery'); break; 399 | default: this.addSkill('Jack-o-T'); 400 | } 401 | break; 402 | case 4: 403 | switch(roll(1)) { 404 | case 1: this.addSkill('Medical'); break; 405 | case 2: this.addSkill('Navigation'); break; 406 | case 3: this.addSkill('Engineering'); break; 407 | case 4: this.addSkill('Computer'); break; 408 | case 5: this.addSkill('Pilot'); break; 409 | default: this.addSkill('Admin'); 410 | } 411 | break; 412 | } 413 | } 414 | }; 415 | //---------------- Define "Marines" service ----------------// 416 | s.marines = { 417 | serviceName: 'Marines', // like "in the Navy" 418 | memberName: 'Marine', // like "Navy Admiral Nelson" 419 | adjName: 'Marines', // like "the Naval service" 420 | enlistmentThrow: 9, 421 | enlistmentDM: function (attributes) { 422 | var dm = 0; 423 | if (attributes.intelligence >= 8) { dm += 1; } 424 | if (attributes.strength >= 8) { dm += 2; } 425 | return dm; 426 | }, 427 | survivalThrow: 6, 428 | survivalDM: function (attributes) { 429 | var dm = 0; 430 | if (attributes.endurance >= 8) { dm += 2; } 431 | return dm; 432 | }, 433 | commissionThrow: 9, 434 | commissionDM: function (attributes) { 435 | var dm = 0; 436 | if (attributes.education >= 7) { dm += 1; } 437 | return dm; 438 | }, 439 | promotionThrow: 9, 440 | promotionDM: function (attributes) { 441 | var dm = 0; 442 | if (attributes.social >= 8) { dm += 1; } 443 | return dm; 444 | }, 445 | getServiceSkills: function () { return ['Cutlass']; }, 446 | checkSurvival: function () { 447 | var dm = 0; 448 | var sv = roll(2); 449 | if (this.attributes.endurance >= 8) { dm += 2; } 450 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 6); 451 | if ((sv + dm) >= 6) { 452 | return true; 453 | } else { 454 | return false; 455 | } 456 | }, 457 | reenlistThrow: 6, 458 | ranks: { 459 | 0: '', 460 | 1: 'Lieutenant', 461 | 2: 'Captain', 462 | 3: 'Force Comdr', 463 | 4: 'Lt Colonel', 464 | 5: 'Colonel', 465 | 6: 'Brigadier' 466 | }, 467 | checkPromotion: function () { 468 | var dm = 0; 469 | var sv = roll(2); 470 | if (this.attributes.social >= 8) { dm += 1; } 471 | this.verboseHistory('Promotion roll ' + sv + ' + ' + dm + ' vs ' + 9); 472 | if ((sv + dm) >= 9) { 473 | return true; 474 | } else { 475 | return false; 476 | } 477 | }, 478 | checkCommission: function() { 479 | var dm = 0; 480 | var sv = roll(2); 481 | if (this.attributes.education >= 7) { dm += 1; } 482 | this.verboseHistory('Commission roll ' + sv + ' + ' + dm + ' vs ' + 9); 483 | if ((sv + dm) >= 9) { 484 | return true; 485 | } else { 486 | return false; 487 | } 488 | }, 489 | doPromotion: function() { 490 | if (this.rank == 1) { 491 | this.addSkill('Revolver'); 492 | } 493 | }, 494 | musterCash: { 495 | 1: 2000, 496 | 2: 5000, 497 | 3: 5000, 498 | 4: 10000, 499 | 5: 20000, 500 | 6: 30000, 501 | 7: 40000 502 | }, 503 | musterBenefits: function (dm) { 504 | switch(roll(1) + dm) { 505 | case 1: 506 | this.addBenefit.call(t, 'Low Passage'); 507 | break; 508 | case 2: 509 | this.improveAttribute('intelligence', 1); 510 | break; 511 | case 3: 512 | this.improveAttribute('education', 1); 513 | break; 514 | case 4: 515 | this.doBladeBenefit.call(t); 516 | break; 517 | case 5: 518 | if (this.benefits.indexOf("Travellers' Aide Society") > -1) { 519 | break; 520 | } 521 | this.addBenefit.call(t, "Travellers' Aid Society"); 522 | this.TAS = true; 523 | break; 524 | case 6: 525 | this.addBenefit.call(t, 'High Passage'); 526 | break; 527 | default: 528 | this.improveAttribute('social', 2); 529 | } 530 | }, 531 | canMuster: function (strategy) { 532 | return strategy == 'TAS' || strategy == 'special'; 533 | }, 534 | acquireSkill: function () { 535 | switch(this.whichSkillTable.call(this)) { 536 | case 1: 537 | switch(roll(1)) { 538 | case 1: this.improveAttribute('strength', 1); break; 539 | case 2: this.improveAttribute('dexterity', 1); break; 540 | case 3: this.improveAttribute('endurance', 1); break; 541 | case 4: this.addSkill('Gambling'); break; 542 | case 5: this.addSkill('Brawling'); break; 543 | default: this.addSkill(cascadeBlade.call(this)); 544 | } 545 | break; 546 | case 2: 547 | switch(roll(1)) { 548 | case 1: if (this.vehicles != '1981') { 549 | this.addSkill('ATV'); 550 | } else { 551 | this.addSkill(cascadeVehicle.call(this)); 552 | } 553 | break; 554 | case 2: this.addSkill('Vacc Suit'); break; 555 | case 3: this.addSkill(cascadeBlade.call(this)); break; 556 | case 4: this.addSkill(cascadeGun.call(this)); break; 557 | case 5: this.addSkill(cascadeBlade.call(this)); break; 558 | default: this.addSkill(cascadeGun.call(this)); 559 | } 560 | break; 561 | case 3: 562 | switch(roll(1)) { 563 | case 1: if (this.vehicles == '1977') { 564 | this.addSkill('ATV'); 565 | } else { 566 | this.addSkill(cascadeVehicle.call(this)); 567 | } 568 | break; 569 | case 2: this.addSkill('Mechanical'); break; 570 | case 3: this.addSkill('Electronics'); break; 571 | case 4: this.addSkill('Tactics'); break; 572 | case 5: this.addSkill(cascadeBlade.call(this)); break; 573 | default: this.addSkill(cascadeGun.call(this)); 574 | } 575 | break; 576 | case 4: 577 | switch(roll(1)) { 578 | case 1: this.addSkill('Medical'); break; 579 | case 2: this.addSkill('Tactics'); break; 580 | case 3: this.addSkill('Tactics'); break; 581 | case 4: this.addSkill('Computer'); break; 582 | case 5: this.addSkill('Leader'); break; 583 | default: this.addSkill('Admin'); 584 | } 585 | break; 586 | } 587 | } 588 | }; 589 | //---------------- Define "Army" service ----------------// 590 | s.army = { 591 | serviceName: 'Army', // like "in the Navy" 592 | memberName: 'Army', // like "Navy Admiral Nelson" 593 | adjName: 'Army', // like "the Naval service" 594 | enlistmentThrow: 5, 595 | enlistmentDM: function (attributes) { 596 | var dm = 0; 597 | if (attributes.dexterity >= 6) { dm += 1; } 598 | if (attributes.endurance >= 5) { dm += 2; } 599 | return dm; 600 | }, 601 | survivalThrow: 5, 602 | survivalDM: function (attributes) { 603 | var dm = 0; 604 | if (attributes.education >= 5) { dm += 2; } 605 | return dm; 606 | }, 607 | commissionThrow: 5, 608 | commissionDM: function (attributes) { 609 | var dm = 0; 610 | if (attributes.endurance >= 7) { dm += 1; } 611 | return dm; 612 | }, 613 | promotionThrow: 6, 614 | promotionDM: function (attributes) { 615 | var dm = 0; 616 | if (attributes.education >= 7) { dm += 1; } 617 | return dm; 618 | }, 619 | getServiceSkills: function () { return ['Rifle']; }, 620 | checkSurvival: function () { 621 | var dm = 0; 622 | var sv = roll(2); 623 | if (this.attributes.education >= 5) { dm += 2; } 624 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 625 | if ((sv + dm) >= 5) { 626 | return true; 627 | } else { 628 | return false; 629 | } 630 | }, 631 | reenlistThrow: 7, 632 | ranks: { 633 | 0: 'Trooper', 634 | 1: 'Lieutenant', 635 | 2: 'Captain', 636 | 3: 'Major', 637 | 4: 'Lt Colonel', 638 | 5: 'Colonel', 639 | 6: 'General' 640 | }, 641 | checkPromotion: function () { 642 | var dm = 0; 643 | var sv = roll(2); 644 | if (this.attributes.education >= 7) { dm += 1; } 645 | this.verboseHistory('Promotion roll ' + sv + ' + ' + dm + ' vs ' + 6); 646 | if ((sv + dm) >= 6) { 647 | return true; 648 | } else { 649 | return false; 650 | } 651 | }, 652 | checkCommission: function() { 653 | var dm = 0; 654 | var sv = roll(2); 655 | if (this.attributes.endurance >= 7) { dm += 1; } 656 | this.verboseHistory('Commission roll ' + sv + ' + ' + dm + ' vs ' + 5); 657 | if ((sv + dm) >= 5) { 658 | return true; 659 | } else { 660 | return false; 661 | } 662 | }, 663 | doPromotion: function() { 664 | if (this.rank == 1) { 665 | this.addSkill('SMG'); 666 | } 667 | }, 668 | musterCash: { 669 | 1: 2000, 670 | 2: 5000, 671 | 3: 10000, 672 | 4: 10000, 673 | 5: 10000, 674 | 6: 20000, 675 | 7: 30000 676 | }, 677 | musterBenefits: function (dm) { 678 | switch(roll(1) + dm) { 679 | case 1: 680 | this.addBenefit.call(t, 'Low Passage'); 681 | break; 682 | case 2: 683 | this.improveAttribute('intelligence', 1); 684 | break; 685 | case 3: 686 | this.improveAttribute('education', 1); 687 | break; 688 | case 4: 689 | this.doGunBenefit.call(t); 690 | break; 691 | case 5: 692 | this.addBenefit.call(t, 'High Passage'); 693 | break; 694 | case 6: 695 | this.addBenefit.call(t, 'Middle Passage'); 696 | break; 697 | default: 698 | this.improveAttribute('social', 1); 699 | } 700 | }, 701 | canMuster: function (strategy) { 702 | return false; 703 | }, 704 | acquireSkill: function () { 705 | switch(this.whichSkillTable.call(this)) { 706 | case 1: 707 | switch(roll(1)) { 708 | case 1: this.improveAttribute('strength', 1); break; 709 | case 2: this.improveAttribute('dexterity', 1); break; 710 | case 3: this.improveAttribute('endurance', 1); break; 711 | case 4: this.addSkill('Gambling'); break; 712 | case 5: this.improveAttribute('education', 1); break; 713 | default: this.addSkill('Brawling'); 714 | } 715 | break; 716 | case 2: 717 | switch(roll(1)) { 718 | case 1: if (this.vehicles != '1981') { 719 | this.addSkill('ATV'); 720 | } else { 721 | this.addSkill(cascadeVehicle.call(this)); 722 | } 723 | break; 724 | case 2: this.addSkill('Air/Raft'); break; 725 | case 3: this.addSkill(cascadeGun.call(this)); break; 726 | case 4: this.addSkill('Fwd Obsvr'); break; 727 | case 5: this.addSkill(cascadeBlade.call(this)); break; 728 | default: this.addSkill(cascadeGun.call(this)); 729 | } 730 | break; 731 | case 3: 732 | switch(roll(1)) { 733 | case 1: if (this.vehicles == '1977') { 734 | this.addSkill('ATV'); 735 | } else { 736 | this.addSkill(cascadeVehicle.call(this)); 737 | } 738 | break; 739 | case 2: this.addSkill('Mechanical'); break; 740 | case 3: this.addSkill('Electronics'); break; 741 | case 4: this.addSkill('Tactics'); break; 742 | case 5: this.addSkill(cascadeBlade.call(this)); break; 743 | default: this.addSkill(cascadeGun.call(this)); 744 | } 745 | break; 746 | case 4: 747 | switch(roll(1)) { 748 | case 1: this.addSkill('Medical'); break; 749 | case 2: this.addSkill('Tactics'); break; 750 | case 3: this.addSkill('Tactics'); break; 751 | case 4: this.addSkill('Computer'); break; 752 | case 5: this.addSkill('Leader'); break; 753 | default: this.addSkill('Admin'); 754 | } 755 | break; 756 | } 757 | } 758 | }; 759 | //---------------- Define "Scouts" service ----------------// 760 | s.scouts = { 761 | serviceName: 'Scouts', // like "in the Navy" 762 | memberName: 'Scout', // like "Navy Admiral Nelson" 763 | adjName: 'Scout', // like "the Naval service" 764 | enlistmentThrow: 7, 765 | enlistmentDM: function (attributes) { 766 | var dm = 0; 767 | if (attributes.intelligence >= 6) { dm += 1; } 768 | if (attributes.strength >= 8) { dm += 2; } 769 | return dm; 770 | }, 771 | survivalThrow: 7, 772 | survivalDM: function (attributes) { 773 | var dm = 0; 774 | if (attributes.endurance >= 9) { dm += 2; } 775 | return dm; 776 | }, 777 | getServiceSkills: function () { return ['Pilot']; }, 778 | checkSurvival: function () { 779 | var dm = 0; 780 | var sv = roll(2); 781 | if (this.attributes.endurance >= 9) { dm += 2; } 782 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 7); 783 | if ((sv + dm) >= 7) { 784 | return true; 785 | } else { 786 | return false; 787 | } 788 | }, 789 | reenlistThrow: 3, 790 | ranks: { 0: '', 1: '', 2: '', 3: '', 4: '', 5: '', 6: '' }, 791 | checkPromotion: function () { 792 | return false; 793 | }, 794 | checkCommission: function() { 795 | return false; 796 | }, 797 | doPromotion: function() { return; }, 798 | musterCash: { 799 | 1: 20000, 800 | 2: 20000, 801 | 3: 30000, 802 | 4: 30000, 803 | 5: 50000, 804 | 6: 50000, 805 | 7: 50000 806 | }, 807 | musterBenefits: function (dm) { 808 | switch(roll(1) + dm) { 809 | case 1: 810 | this.addBenefit.call(t, 'Low Passage'); 811 | break; 812 | case 2: 813 | this.improveAttribute('intelligence', 2); 814 | break; 815 | case 3: 816 | this.improveAttribute('education', 2); 817 | break; 818 | case 4: 819 | this.doBladeBenefit.call(t); 820 | break; 821 | case 5: 822 | this.doGunBenefit.call(t); 823 | break; 824 | case 6: 825 | if (this.benefits.indexOf('Scout Ship') > -1) { 826 | this.debugHistory('No benefit'); 827 | break; 828 | } 829 | this.addBenefit.call(t, 'Scout Ship'); 830 | this.ship = true; 831 | break; 832 | default: 833 | this.improveAttribute('social', 1); 834 | } 835 | }, 836 | canMuster: function (strategy) { 837 | return strategy == 'ship' || strategy == 'special'; 838 | }, 839 | acquireSkill: function () { 840 | switch(this.whichSkillTable.call(this)) { 841 | case 1: 842 | switch(roll(1)) { 843 | case 1: this.improveAttribute('strength', 1); break; 844 | case 2: this.improveAttribute('dexterity', 1); break; 845 | case 3: this.improveAttribute('endurance', 1); break; 846 | case 4: this.improveAttribute('intelligence', 1); break; 847 | case 5: this.improveAttribute('education', 1); break; 848 | default: this.addSkill(cascadeGun.call(this)); 849 | } 850 | break; 851 | case 2: 852 | switch(roll(1)) { 853 | case 1: this.addSkill('Air/Raft'); break; 854 | case 2: this.addSkill('Vacc Suit'); break; 855 | case 3: this.addSkill('Mechanical'); break; 856 | case 4: this.addSkill('Navigation'); break; 857 | case 5: this.addSkill('Electronics'); break; 858 | default: this.addSkill('Jack-o-T'); 859 | } 860 | break; 861 | case 3: 862 | switch(roll(1)) { 863 | case 1: if (this.vehicles == '1977') { 864 | this.addSkill('Air/Raft'); 865 | } else { 866 | this.addSkill(cascadeVehicle.call(this)); 867 | } 868 | break; 869 | case 2: this.addSkill('Mechanical'); break; 870 | case 3: this.addSkill('Electronics'); break; 871 | case 4: this.addSkill('Jack-o-T'); break; 872 | case 5: this.addSkill('Gunnery'); break; 873 | default: this.addSkill('Medical'); 874 | } 875 | break; 876 | case 4: 877 | switch(roll(1)) { 878 | case 1: this.addSkill('Medical'); break; 879 | case 2: this.addSkill('Navigation'); break; 880 | case 3: this.addSkill('Engineering'); break; 881 | case 4: this.addSkill('Computer'); break; 882 | case 5: this.addSkill('Pilot'); break; 883 | default: this.addSkill('Jack-o-T'); 884 | } 885 | break; 886 | } 887 | } 888 | }; 889 | //---------------- Define "Merchant" service ----------------// 890 | s.merchants = { 891 | serviceName: 'Merchants', // like "in the Navy" 892 | memberName: 'Merchant', // like "Navy Admiral Nelson" 893 | adjName: 'Merchant', // like "the Naval service" 894 | enlistmentThrow: 7, 895 | enlistmentDM: function (attributes) { 896 | var dm = 0; 897 | if (attributes.strength >= 7) { dm += 1; } 898 | if (attributes.intelligence >= 6) { dm += 2; } 899 | return dm; 900 | }, 901 | survivalThrow: 5, 902 | survivalDM: function (attributes) { 903 | var dm = 0; 904 | if (attributes.intelligence >= 7) { dm += 2; } 905 | return dm; 906 | }, 907 | commissionThrow: 4, 908 | commissionDM: function (attributes) { 909 | var dm = 0; 910 | if (attributes.intelligence >= 6) { dm += 1; } 911 | return dm; 912 | }, 913 | promotionThrow: 10, 914 | promotionDM: function (attributes) { 915 | var dm = 0; 916 | if (attributes.intelligence >= 9) { dm += 1; } 917 | return dm; 918 | }, 919 | getServiceSkills: function () { return []; }, 920 | checkSurvival: function () { 921 | var dm = 0; 922 | var sv = roll(2); 923 | if (this.attributes.intelligence >= 7) { dm += 2; } 924 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 925 | if ((sv + dm) >= 5) { 926 | return true; 927 | } else { 928 | return false; 929 | } 930 | }, 931 | reenlistThrow: 4, 932 | ranks: { 933 | 0: '', 934 | 1: '4th Officer', 935 | 2: '3rd Officer', 936 | 3: '2nd Officer', 937 | 4: '1st Officer', 938 | 5: 'Captain', 939 | 6: 'Senior Captain' 940 | }, 941 | checkPromotion: function() { 942 | var dm = 0; 943 | var sv = roll(2); 944 | if (this.attributes.intelligence >= 9) { dm += 1; } 945 | this.verboseHistory('Promotion roll ' + sv + ' + ' + dm + ' vs ' + 10); 946 | if ((sv + dm) >= 10) { 947 | return true; 948 | } else { 949 | return false; 950 | } 951 | }, 952 | checkCommission: function() { 953 | var dm = 0; 954 | var sv = roll(2); 955 | if (this.attributes.intelligence >= 6) { dm += 1; } 956 | this.verboseHistory('Commission roll ' + sv + ' + ' + dm + ' vs ' + 4); 957 | if ((sv + dm) >= 4) { 958 | return true; 959 | } else { 960 | return false; 961 | } 962 | }, 963 | doPromotion: function() { 964 | if (this.rank == 4) { 965 | this.addSkill('Pilot'); 966 | } 967 | }, 968 | musterCash: { 969 | 1: 1000, 970 | 2: 5000, 971 | 3: 10000, 972 | 4: 20000, 973 | 5: 20000, 974 | 6: 40000, 975 | 7: 40000 976 | }, 977 | musterBenefits: function (dm) { 978 | switch(roll(1) + dm) { 979 | case 1: 980 | this.addBenefit.call(t, 'Low Passage'); 981 | break; 982 | case 2: 983 | this.improveAttribute('intelligence', 1); 984 | break; 985 | case 3: 986 | this.improveAttribute('education', 1); 987 | break; 988 | case 4: 989 | this.doGunBenefit.call(t); 990 | break; 991 | case 5: 992 | this.doBladeBenefit.call(t); 993 | break; 994 | case 6: 995 | this.addBenefit.call(t, 'Low Passage'); 996 | break; 997 | default: 998 | if (this.benefits.indexOf('Free Trader') > -1) { 999 | this.mortgages += 1; 1000 | if (this.mortgage > 0) { 1001 | this.mortgage -= 10; 1002 | this.verboseHistory('10 years of mortgage paid off'); 1003 | } else { 1004 | this.debugHistory('No benefit'); 1005 | } 1006 | } else { 1007 | this.addBenefit.call(t, 'Free Trader'); 1008 | this.ship = true; 1009 | } 1010 | } 1011 | }, 1012 | canMuster: function (strategy) { 1013 | return strategy == 'ship' || strategy == 'special'; 1014 | }, 1015 | acquireSkill: function () { 1016 | switch(this.whichSkillTable.call(this)) { 1017 | case 1: 1018 | switch(roll(1)) { 1019 | case 1: this.improveAttribute('strength', 1); break; 1020 | case 2: this.improveAttribute('dexterity', 1); break; 1021 | case 3: this.improveAttribute('endurance', 1); break; 1022 | case 4: this.improveAttribute('strength', 1); break; 1023 | case 5: this.addSkill(cascadeBlade.call(this)); break; 1024 | default: this.addSkill('Bribery'); 1025 | } 1026 | break; 1027 | case 2: 1028 | switch(roll(1)) { 1029 | case 1: if (this.vehicles == '1977') { 1030 | this.improveAttribute('strength', 1); 1031 | } else { 1032 | this.addSkill(cascadeVehicle.call(this)); 1033 | } 1034 | break; 1035 | case 2: this.addSkill('Vacc Suit'); break; 1036 | case 3: this.addSkill('Jack-o-T'); break; 1037 | case 4: this.addSkill('Steward'); break; 1038 | case 5: this.addSkill('Electronics'); break; 1039 | default: this.addSkill(cascadeGun.call(this)); 1040 | } 1041 | break; 1042 | case 3: 1043 | switch(roll(1)) { 1044 | case 1: this.addSkill('Streetwise'); break; 1045 | case 2: this.addSkill('Mechanical'); break; 1046 | case 3: this.addSkill('Electronics'); break; 1047 | case 4: this.addSkill('Navigation'); break; 1048 | case 5: this.addSkill('Gunnery'); break; 1049 | default: this.addSkill('Medical'); 1050 | } 1051 | break; 1052 | case 4: 1053 | switch(roll(1)) { 1054 | case 1: this.addSkill('Medical'); break; 1055 | case 2: this.addSkill('Navigation'); break; 1056 | case 3: this.addSkill('Engineering'); break; 1057 | case 4: this.addSkill('Computer'); break; 1058 | case 5: this.addSkill('Pilot'); break; 1059 | default: this.addSkill('Admin'); 1060 | } 1061 | break; 1062 | } 1063 | } 1064 | }; 1065 | //---------------- Define "Other" service ----------------// 1066 | s.other = { 1067 | serviceName: 'other service', // like "in the Navy" 1068 | memberName: '', // like "Navy Admiral Nelson" 1069 | adjName: 'other', // like "the Naval service" 1070 | enlistmentThrow: 3, 1071 | enlistmentDM: function (attributes) { 1072 | var dm = 0; 1073 | return dm; 1074 | }, 1075 | survivalThrow: 5, 1076 | survivalDM: function (attributes) { 1077 | var dm = 0; 1078 | if (attributes.intelligence >= 9) { dm += 2; } 1079 | return dm; 1080 | }, 1081 | getServiceSkills: function () { return []; }, 1082 | checkSurvival: function () { 1083 | var dm = 0; 1084 | var sv = roll(2); 1085 | if (this.attributes.intelligence >= 9) { dm += 2; } 1086 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 1087 | if ((sv + dm) >= 5) { 1088 | return true; 1089 | } else { 1090 | return false; 1091 | } 1092 | }, 1093 | reenlistThrow: 5, 1094 | ranks: { 0: '', 1: '', 2: '', 3: '', 4: '', 5: '', 6: '' }, 1095 | checkPromotion: function () { 1096 | return false; 1097 | }, 1098 | checkCommission: function () { 1099 | return false; 1100 | }, 1101 | doPromotion: function() { return; }, 1102 | musterCash: { 1103 | 1: 1000, 1104 | 2: 5000, 1105 | 3: 10000, 1106 | 4: 10000, 1107 | 5: 10000, 1108 | 6: 50000, 1109 | 7: 100000 1110 | }, 1111 | musterBenefits: function (dm) { 1112 | switch(roll(1) + dm) { 1113 | case 1: 1114 | this.addBenefit.call(t, 'Low Passage'); 1115 | break; 1116 | case 2: 1117 | this.improveAttribute('intelligence', 1); 1118 | break; 1119 | case 3: 1120 | this.improveAttribute('education', 1); 1121 | break; 1122 | case 4: 1123 | this.doGunBenefit.call(t); 1124 | break; 1125 | case 5: 1126 | this.addBenefit.call(t, 'High Passage'); 1127 | break; 1128 | default: 1129 | this.debugHistory('No benefit'); 1130 | break; 1131 | } 1132 | }, 1133 | canMuster: function (strategy) { 1134 | return false; 1135 | }, 1136 | acquireSkill: function () { 1137 | switch(this.whichSkillTable.call(this)) { 1138 | case 1: 1139 | switch(roll(1)) { 1140 | case 1: this.improveAttribute('strength', 1); break; 1141 | case 2: this.improveAttribute('dexterity', 1); break; 1142 | case 3: this.improveAttribute('endurance', 1); break; 1143 | case 4: this.addSkill(cascadeBlade.call(this)); break; 1144 | case 5: this.addSkill('Brawling'); break; 1145 | default: this.improveAttribute('social', -1); 1146 | } 1147 | break; 1148 | case 2: 1149 | switch(roll(1)) { 1150 | case 1: if (this.vehicles == '1977') { 1151 | this.addSkill('Forgery'); 1152 | } else { 1153 | this.addSkill(cascadeVehicle.call(this)); 1154 | } 1155 | break; 1156 | case 2: this.addSkill('Gambling'); break; 1157 | case 3: this.addSkill('Brawling'); break; 1158 | case 4: this.addSkill('Bribery'); break; 1159 | case 5: this.addSkill(cascadeBlade.call(this)); break; 1160 | default: this.addSkill(cascadeGun.call(this)); 1161 | } 1162 | break; 1163 | case 3: 1164 | switch(roll(1)) { 1165 | case 1: this.addSkill('Streetwise'); break; 1166 | case 2: this.addSkill('Mechanical'); break; 1167 | case 3: this.addSkill('Electronics'); break; 1168 | case 4: this.addSkill('Gambling'); break; 1169 | case 5: this.addSkill('Brawling'); break; 1170 | default: this.addSkill('Forgery'); 1171 | } 1172 | break; 1173 | case 4: 1174 | switch(roll(1)) { 1175 | case 1: this.addSkill('Medical'); break; 1176 | case 2: this.addSkill('Forgery'); break; 1177 | case 3: this.addSkill('Electronics'); break; 1178 | case 4: this.addSkill('Computer'); break; 1179 | case 5: this.addSkill('Streetwise'); break; 1180 | default: this.addSkill('Jack-o-T'); 1181 | } 1182 | break; 1183 | } 1184 | } 1185 | }; 1186 | //---------------- Define "Pirate" service ----------------// 1187 | s.pirates = { 1188 | serviceName: 'Pirate', // like "in the Navy" 1189 | memberName: 'Pirate', // like "Navy Admiral Nelson" 1190 | adjName: "Pirate", // like "the Naval service" 1191 | enlistmentThrow: 7, 1192 | enlistmentDM: function (attributes) { 1193 | var dm = 0; 1194 | if (attributes.social <= 7) { dm += 1; } 1195 | if (attributes.endurance >= 9) { dm += 2; } 1196 | return dm; 1197 | }, 1198 | survivalThrow: 6, 1199 | survivalDM: function (attributes) { 1200 | var dm = 0; 1201 | if (attributes.intelligence >= 8) { dm += 2; } 1202 | return dm; 1203 | }, 1204 | commissionThrow: 9, 1205 | commissionDM: function (attributes) { 1206 | var dm = 0; 1207 | if (attributes.strength >= 10) { dm += 1; } 1208 | return dm; 1209 | }, 1210 | promotionThrow: 8, 1211 | promotionDM: function (attributes) { 1212 | var dm = 0; 1213 | if (attributes.intelligence >= 9) { dm += 1; } 1214 | return dm; 1215 | }, 1216 | getServiceSkills: function () { return ['Brawling']; }, 1217 | checkSurvival: function () { 1218 | var dm = 0; 1219 | var sv = roll(2); 1220 | if (this.attributes.intelligence >= 8) { dm += 2; } 1221 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 1222 | if ((sv + dm) >= 5) { 1223 | return true; 1224 | } else { 1225 | return false; 1226 | } 1227 | }, 1228 | reenlistThrow: 7, 1229 | ranks: { 1230 | 0: 'Henchmen', 1231 | 1: 'Corporal', 1232 | 2: 'Sergeant', 1233 | 3: 'Lt Cmdr', 1234 | 4: 'Leuitenant', 1235 | 5: 'Leader', 1236 | 6: 'Leader' 1237 | }, 1238 | checkPromotion: function () { 1239 | var dm = 0; 1240 | var sv = roll(2); 1241 | if (this.attributes.intelligence >= 9) { dm += 1; } 1242 | this.verboseHistory('Promotion roll ' + sv + ' + ' + dm + ' vs ' + 8); 1243 | if ((sv + dm) >= 8) { 1244 | return true; 1245 | } else { 1246 | return false; 1247 | } 1248 | }, 1249 | checkCommission: function() { 1250 | var dm = 0; 1251 | var sv = roll(2); 1252 | if (this.attributes.strength >= 10) { dm += 1; } 1253 | this.verboseHistory('Commission roll ' + sv + ' + ' + dm + ' vs ' + 10); 1254 | if ((sv + dm) >= 10) { 1255 | return true; 1256 | } else { 1257 | return false; 1258 | } 1259 | }, 1260 | doPromotion: function() { 1261 | if (this.rank == 4) { 1262 | this.addSkill('Pilot'); 1263 | } 1264 | }, 1265 | musterCash: { 1266 | 1: 0, 1267 | 2: 0, 1268 | 3: 1000, 1269 | 4: 10000, 1270 | 5: 50000, 1271 | 6: 50000, 1272 | 7: 50000 1273 | }, 1274 | musterBenefits: function (dm) { 1275 | switch(roll(1) + dm) { 1276 | case 1: 1277 | this.addBenefit.call(t, 'Low Passage'); 1278 | break; 1279 | case 2: 1280 | this.improveAttribute('intelligence', 1); 1281 | break; 1282 | case 3: 1283 | this.doGunBenefit.call(t); 1284 | break; 1285 | case 4: 1286 | break; 1287 | case 5: 1288 | this.improveAttribute('social', -1); 1289 | break; 1290 | case 6: 1291 | this.addBenefit.call(t, 'Mid Passage'); 1292 | break; 1293 | default: 1294 | if (this.benefits.indexOf('Corsair') > -1) { 1295 | this.debugHistory('No benefit'); 1296 | break; 1297 | } 1298 | this.addBenefit.call(t, 'Corsair'); 1299 | this.ship = true; 1300 | } 1301 | }, 1302 | canMuster: function (strategy) { 1303 | return strategy == 'ship' || strategy == 'special'; 1304 | }, 1305 | acquireSkill: function () { 1306 | // Skills acquired during a term of service. 1307 | switch(this.whichSkillTable.call(this)) { 1308 | case 1: 1309 | switch(roll(1)) { 1310 | case 1: this.improveAttribute('strength', 1); break; 1311 | case 2: this.improveAttribute('dexterity', 1); break; 1312 | case 3: this.improveAttribute('endurance', 1); break; 1313 | case 4: this.addSkill('Gambling'); break; 1314 | case 5: this.addSkill('Brawling'); break; 1315 | default: this.addSkill(cascadeBlade.call(this)); 1316 | } 1317 | break; 1318 | case 2: 1319 | switch(roll(1)) { 1320 | case 1: this.addSkill(cascadeBlade.call(this)); break; 1321 | case 2: this.addSkill('Vacc Suit'); break; 1322 | case 3: this.addSkill(cascadeGun.call(this)); break; 1323 | case 4: this.addSkill('Gunnery'); break; 1324 | case 5: this.addSkill('Zero-G Cbt'); break; 1325 | default: this.addSkill(cascadeGun.call(this)); 1326 | } 1327 | break; 1328 | case 3: 1329 | switch(roll(1)) { 1330 | case 1: this.addSkill('Streetwise'); break; 1331 | case 2: this.addSkill('Gunnery'); break; 1332 | case 3: this.addSkill('Engineering'); break; 1333 | case 4: this.addSkill('Ship Tactic'); break; 1334 | case 5: this.addSkill('Tactics'); break; 1335 | default: this.addSkill('Mechanical'); 1336 | } 1337 | break; 1338 | case 4: 1339 | switch(roll(1)) { 1340 | case 1: this.addSkill('Navigation'); break; 1341 | case 2: this.addSkill('Pilot'); break; 1342 | case 3: this.addSkill('Forgery'); break; 1343 | case 4: this.addSkill('Computer'); break; 1344 | case 5: this.addSkill('Leader'); break; 1345 | default: this.addSkill('Electronics'); 1346 | } 1347 | break; 1348 | } 1349 | } 1350 | }; 1351 | //---------------- Define "Belter" service ----------------// 1352 | s.belters = { 1353 | serviceName: 'Belter', // like "in the Navy" 1354 | memberName: 'Belter', // like "Navy Admiral Nelson" 1355 | adjName: "Belt", // like "the Naval service" 1356 | enlistmentThrow: 7, 1357 | enlistmentDM: function (attributes) { 1358 | var dm = 0; 1359 | if (attributes.dexterity >= 10) { dm += 1; } 1360 | if (attributes.strength >= 8) { dm += 2; } 1361 | return dm; 1362 | }, 1363 | survivalThrow: 9, 1364 | survivalDM: function (attributes) { 1365 | var dm = 0; 1366 | if (attributes.intelligence >= 8) { dm += 2; } 1367 | return dm; 1368 | }, 1369 | commissionThrow: 9, 1370 | commissionDM: function (attributes) { 1371 | var dm = 0; 1372 | if (attributes.strength >= 10) { dm += 1; } 1373 | return dm; 1374 | }, 1375 | promotionThrow: 8, 1376 | promotionDM: function (attributes) { 1377 | var dm = 0; 1378 | if (attributes.intelligence >= 9) { dm += 1; } 1379 | return dm; 1380 | }, 1381 | getServiceSkills: function () { return ['Vacc Suit']; }, 1382 | checkSurvival: function () { 1383 | var dm = 0; 1384 | var sv = roll(2); 1385 | if (this.age = 22) { 1386 | dm += 1; 1387 | } else if (this.age = 26) { 1388 | dm += 2; 1389 | } else if (this.age = 30) { 1390 | dm += 3; 1391 | } else if (this.age = 34) { 1392 | dm += 4; 1393 | } else if (this.age = 38) { 1394 | dm += 5; 1395 | } else if (this.age = 42) { 1396 | dm += 6; 1397 | } else if (this.age = 46) { 1398 | dm += 7; 1399 | } else if (this.age = 50) { 1400 | dm += 8; 1401 | } else { 1402 | dm += 9; 1403 | } 1404 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 1405 | if ((sv + dm) >= 5) { 1406 | return true; 1407 | } else { 1408 | return false; 1409 | } 1410 | }, 1411 | reenlistThrow: 7, 1412 | ranks: { 1413 | 0: '', 1414 | 1: '', 1415 | 2: '', 1416 | 3: '', 1417 | 4: '', 1418 | 5: '', 1419 | 6: '' 1420 | }, 1421 | checkPromotion: function () { 1422 | return false; 1423 | }, 1424 | checkCommission: function() { 1425 | return false; 1426 | }, 1427 | doPromotion: function() { 1428 | return; 1429 | }, 1430 | musterCash: { 1431 | 1: 0, 1432 | 2: 0, 1433 | 3: 1000, 1434 | 4: 10000, 1435 | 5: 100000, 1436 | 6: 100000, 1437 | 7: 100000 1438 | }, 1439 | musterBenefits: function (dm) { 1440 | switch(roll(1) + dm) { 1441 | case 1: 1442 | this.addBenefit.call(t, 'Low Passage'); 1443 | break; 1444 | case 2: 1445 | this.improveAttribute('intelligence', 1); 1446 | break; 1447 | case 3: 1448 | this.doGunBenefit.call(t); 1449 | break; 1450 | case 4: 1451 | this.addBenefit.call(t, 'High Passage'); 1452 | break; 1453 | case 5: 1454 | if (this.benefits.indexOf("Travellers' Aide Society") > -1) { 1455 | break; 1456 | } 1457 | this.addBenefit.call(t, "Travellers' Aid Society"); 1458 | this.TAS = true; 1459 | break; 1460 | case 6: 1461 | if (this.benefits.indexOf('Seeker') > -1) { 1462 | this.debugHistory('No benefit'); 1463 | break; 1464 | } 1465 | this.addBenefit.call(t, 'Seeker'); 1466 | this.ship = true; 1467 | default: 1468 | break; 1469 | } 1470 | }, 1471 | canMuster: function (strategy) { 1472 | return strategy == 'ship' || strategy == 'special'; 1473 | }, 1474 | acquireSkill: function () { 1475 | // Skills acquired during a term of service. 1476 | switch(this.whichSkillTable.call(this)) { 1477 | case 1: 1478 | switch(roll(1)) { 1479 | case 1: this.improveAttribute('strength', 1); break; 1480 | case 2: this.improveAttribute('dexterity', 1); break; 1481 | case 3: this.improveAttribute('endurance', 1); break; 1482 | case 4: this.addSkill('Gambling'); break; 1483 | case 5: this.addSkill('Brawling'); break; 1484 | default: this.addSkill('Vacc Suit'); 1485 | } 1486 | break; 1487 | case 2: 1488 | switch(roll(1)) { 1489 | case 1: this.addSkill('Vacc Suit'); break; 1490 | case 2: this.addSkill('Vacc Suit'); break; 1491 | case 3: this.addSkill('Prospecting'); break; 1492 | case 4: this.addSkill('Fwd Obsvr'); break; 1493 | case 5: this.addSkill('Prospecting'); break; 1494 | default: this.addSkill("Ship's Boat"); 1495 | } 1496 | break; 1497 | case 3: 1498 | switch(roll(1)) { 1499 | case 1: this.addSkill("Ship's Boat"); break; 1500 | case 2: this.addSkill('Electronics'); break; 1501 | case 3: this.addSkill('Prospecting'); break; 1502 | case 4: this.addSkill('Mechanical'); break; 1503 | case 5: this.addSkill('Prospecting'); break; 1504 | default: this.addSkill('Instruction'); 1505 | } 1506 | break; 1507 | case 4: 1508 | switch(roll(1)) { 1509 | case 1: this.addSkill('Navigation'); break; 1510 | case 2: this.addSkill('Medical'); break; 1511 | case 3: this.addSkill('Pilot'); break; 1512 | case 4: this.addSkill('Computer'); break; 1513 | case 5: this.addSkill('Engineering'); break; 1514 | default: this.addSkill('Jack-o-T'); 1515 | } 1516 | break; 1517 | } 1518 | } 1519 | }; 1520 | //---------------- Define "Sailor" service ----------------// 1521 | s.sailors = { 1522 | serviceName: 'Wet Navy', // like "in the Navy" 1523 | memberName: 'Wet Navy', // like "Navy Admiral Nelson" 1524 | adjName: "Wet Naval", // like "the Naval service" 1525 | enlistmentThrow: 6, 1526 | enlistmentDM: function (attributes) { 1527 | var dm = 0; 1528 | if (attributes.endurance >= 10) { dm += 1; } 1529 | if (attributes.strength >= 8) { dm += 2; } 1530 | return dm; 1531 | }, 1532 | survivalThrow: 5, 1533 | survivalDM: function (attributes) { 1534 | var dm = 0; 1535 | if (attributes.intelligence >= 8) { dm += 2; } 1536 | return dm; 1537 | }, 1538 | commissionThrow: 9, 1539 | commissionDM: function (attributes) { 1540 | var dm = 0; 1541 | if (attributes.strength >= 10) { dm += 1; } 1542 | return dm; 1543 | }, 1544 | promotionThrow: 8, 1545 | promotionDM: function (attributes) { 1546 | var dm = 0; 1547 | if (attributes.intelligence >= 9) { dm += 1; } 1548 | return dm; 1549 | }, 1550 | getServiceSkills: function () { return ['Liaison']; }, 1551 | checkSurvival: function () { 1552 | var dm = 0; 1553 | var sv = roll(2); 1554 | if (this.attributes.endurance >= 5) { dm += 2; } 1555 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 1556 | if ((sv + dm) >= 5) { 1557 | return true; 1558 | } else { 1559 | return false; 1560 | } 1561 | }, 1562 | reenlistThrow: 6, 1563 | ranks: { 1564 | 0: 'Sailor', 1565 | 1: 'Ensign', 1566 | 2: 'Lieutenant', 1567 | 3: 'Lt Cmdr', 1568 | 4: 'Commander', 1569 | 5: 'Captain', 1570 | 6: 'Admiral' 1571 | }, 1572 | checkPromotion: function () { 1573 | var dm = 0; 1574 | var sv = roll(2); 1575 | if (this.attributes.intelligence >= 9) { dm += 1; } 1576 | this.verboseHistory('Promotion roll ' + sv + ' + ' + dm + ' vs ' + 8); 1577 | if ((sv + dm) >= 5) { 1578 | return true; 1579 | } else { 1580 | return false; 1581 | } 1582 | }, 1583 | checkCommission: function() { 1584 | var dm = 0; 1585 | var sv = roll(2); 1586 | if (this.attributes.education >= 8) { dm += 1; } 1587 | this.verboseHistory('Commission roll ' + sv + ' + ' + dm + ' vs ' + 10); 1588 | if ((sv + dm) >= 6) { 1589 | return true; 1590 | } else { 1591 | return false; 1592 | } 1593 | }, 1594 | doPromotion: function() { 1595 | return; 1596 | }, 1597 | musterCash: { 1598 | 1: 2000, 1599 | 2: 5000, 1600 | 3: 10000, 1601 | 4: 10000, 1602 | 5: 10000, 1603 | 6: 20000, 1604 | 7: 30000 1605 | }, 1606 | musterBenefits: function (dm) { 1607 | switch(roll(1) + dm) { 1608 | case 1: 1609 | this.addBenefit.call(t, 'Low Passage'); 1610 | break; 1611 | case 2: 1612 | this.improveAttribute('education', 1); 1613 | break; 1614 | case 3: 1615 | this.doGunBenefit.call(t); 1616 | break; 1617 | case 4: 1618 | this.doGunBenefit.call(t); 1619 | break; 1620 | case 5: 1621 | this.addBenefit.call(t, 'High Passage'); 1622 | break; 1623 | case 6: 1624 | this.addBenefit.call(t, 'High Passage'); 1625 | break; 1626 | default: 1627 | this.improveAttribute('social', 1); 1628 | } 1629 | }, 1630 | canMuster: function (strategy) { 1631 | return false; 1632 | }, 1633 | acquireSkill: function () { 1634 | // Skills acquired during a term of service. 1635 | switch(this.whichSkillTable.call(this)) { 1636 | case 1: 1637 | switch(roll(1)) { 1638 | case 1: this.improveAttribute('strength', 1); break; 1639 | case 2: this.improveAttribute('dexterity', 1); break; 1640 | case 3: this.improveAttribute('endurance', 1); break; 1641 | case 4: this.addSkill('Gambling'); break; 1642 | case 5: this.addSkill('Brawling'); break; 1643 | default: this.addSkill('Carousing'); 1644 | } 1645 | break; 1646 | case 2: 1647 | switch(roll(1)) { 1648 | case 1: this.addSkill(cascadeGun.call(this)); break; 1649 | case 2: this.addSkill('Commo'); break; 1650 | case 3: this.addSkill('Fwd Obsvr'); break; 1651 | case 4: this.addSkill(cascadeVehicle.call(this)); break; 1652 | case 5: this.addSkill(cascadeVehicle.call(this)); break; 1653 | default: this.addSkill('Battle Dress'); 1654 | } 1655 | break; 1656 | case 3: 1657 | switch(roll(1)) { 1658 | case 1: this.addSkill(cascadeWatercraft.call(this)); break; 1659 | case 2: this.addSkill('Electronics'); break; 1660 | case 3: this.addSkill('Mechanical'); break; 1661 | case 4: this.addSkill('Gravitics'); break; 1662 | case 5: this.addSkill('Navigation'); break; 1663 | default: this.addSkill('Demolition'); 1664 | } 1665 | break; 1666 | case 4: 1667 | switch(roll(1)) { 1668 | case 1: this.addSkill('Medical'); break; 1669 | case 2: this.addSkill('Vehicle'); break; 1670 | case 3: this.addSkill('Streetwise'); break; 1671 | case 4: this.addSkill('Computer'); break; 1672 | case 5: this.addSkill('Admin'); break; 1673 | default: this.addSkill('Jack-o-T'); 1674 | } 1675 | break; 1676 | } 1677 | } 1678 | }; 1679 | //---------------- Define "Diplomat" service ----------------// 1680 | s.diplomats = { 1681 | serviceName: 'Diplomat Service', // like "in the Navy" 1682 | memberName: 'Diplomat', // like "Navy Admiral Nelson" 1683 | adjName: "Diplomat", // like "the Naval service" 1684 | enlistmentThrow: 8, 1685 | enlistmentDM: function (attributes) { 1686 | var dm = 0; 1687 | if (attributes.education >= 8) { dm += 1; } 1688 | if (attributes.social >= 9) { dm += 2; } 1689 | return dm; 1690 | }, 1691 | survivalThrow: 3, 1692 | survivalDM: function (attributes) { 1693 | var dm = 0; 1694 | if (attributes.education >= 9) { dm += 2; } 1695 | return dm; 1696 | }, 1697 | commissionThrow: 5, 1698 | commissionDM: function (attributes) { 1699 | var dm = 0; 1700 | if (attributes.intelligence >= 8) { dm += 1; } 1701 | return dm; 1702 | }, 1703 | promotionThrow: 10, 1704 | promotionDM: function (attributes) { 1705 | var dm = 0; 1706 | if (attributes.social >= 10) { dm += 1; } 1707 | return dm; 1708 | }, 1709 | getServiceSkills: function () { return ['Liaison']; }, 1710 | checkSurvival: function () { 1711 | var dm = 0; 1712 | var sv = roll(2); 1713 | if (this.attributes.education >= 9) { dm += 2; } 1714 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 1715 | if ((sv + dm) >= 3) { 1716 | return true; 1717 | } else { 1718 | return false; 1719 | } 1720 | }, 1721 | reenlistThrow: 5, 1722 | ranks: { 1723 | 0: 'Attache', 1724 | 1: '3rd Secretary', 1725 | 2: '2nd Secretary', 1726 | 3: '1st Secretary', 1727 | 4: 'Counselor', 1728 | 5: 'Minister', 1729 | 6: 'Ambassador' 1730 | }, 1731 | checkPromotion: function () { 1732 | var dm = 0; 1733 | var sv = roll(2); 1734 | if (this.attributes.social >= 10) { dm += 1; } 1735 | this.verboseHistory('Promotion roll ' + sv + ' + ' + dm + ' vs ' + 8); 1736 | if ((sv + dm) >= 10) { 1737 | return true; 1738 | } else { 1739 | return false; 1740 | } 1741 | }, 1742 | checkCommission: function() { 1743 | var dm = 0; 1744 | var sv = roll(2); 1745 | if (this.attributes.education >= 9) { dm += 1; } 1746 | this.verboseHistory('Commission roll ' + sv + ' + ' + dm + ' vs ' + 10); 1747 | if ((sv + dm) >= 5) { 1748 | return true; 1749 | } else { 1750 | return false; 1751 | } 1752 | }, 1753 | doPromotion: function() { 1754 | return; 1755 | }, 1756 | musterCash: { 1757 | 1: 10000, 1758 | 2: 10000, 1759 | 3: 10000, 1760 | 4: 20000, 1761 | 5: 50000, 1762 | 6: 60000, 1763 | 7: 70000 1764 | }, 1765 | musterBenefits: function (dm) { 1766 | switch(roll(1) + dm) { 1767 | case 1: 1768 | this.addBenefit.call(t, 'Low Passage'); 1769 | break; 1770 | case 2: 1771 | this.improveAttribute('intelligence', 1); 1772 | break; 1773 | case 3: 1774 | this.improveAttribute('education', 2); 1775 | break; 1776 | case 4: 1777 | this.doGunBenefit.call(t); 1778 | break; 1779 | case 5: 1780 | this.improveAttribute('social', 1); 1781 | break; 1782 | case 6: 1783 | this.addBenefit.call(t, 'High Passage'); 1784 | break; 1785 | default: 1786 | if (this.benefits.indexOf("Travellers' Aide Society") > -1) { 1787 | break; 1788 | } 1789 | this.addBenefit.call(t, "Travellers' Aid Society"); 1790 | this.TAS = true; 1791 | break; 1792 | } 1793 | }, 1794 | canMuster: function (strategy) { 1795 | return false; 1796 | }, 1797 | acquireSkill: function () { 1798 | // Skills acquired during a term of service. 1799 | switch(this.whichSkillTable.call(this)) { 1800 | case 1: 1801 | switch(roll(1)) { 1802 | case 1: this.improveAttribute('strength', 1); break; 1803 | case 2: this.improveAttribute('dexterity', 1); break; 1804 | case 3: this.improveAttribute('intelligence', 1); break; 1805 | case 4: this.addSkill(cascadeBlade.call(this)); break; 1806 | case 5: this.addSkill(cascadeGun.call(this)); break; 1807 | default: this.addSkill('Carousing'); 1808 | } 1809 | break; 1810 | case 2: 1811 | switch(roll(1)) { 1812 | case 1: this.improveAttribute('intelligence', 1); break; 1813 | case 2: this.addSkill('Vacc Suit'); break; 1814 | case 3: this.addSkill(cascadeVehicle.call(this)); break; 1815 | case 4: this.addSkill(cascadeVehicle.call(this)); break; 1816 | case 5: this.addSkill('Gambling'); break; 1817 | default: this.addSkill('Computer'); 1818 | } 1819 | break; 1820 | case 3: 1821 | switch(roll(1)) { 1822 | case 1: this.addSkill('Forgery'); break; 1823 | case 2: this.addSkill('Streetwise'); break; 1824 | case 3: this.addSkill('Interrogation'); break; 1825 | case 4: this.addSkill('Recruiting'); break; 1826 | case 5: this.addSkill('Instruction'); break; 1827 | default: this.addSkill('Admin'); 1828 | } 1829 | break; 1830 | case 4: 1831 | switch(roll(1)) { 1832 | case 1: this.addSkill('Liaison'); break; 1833 | case 2: this.addSkill('Liaison'); break; 1834 | case 3: this.addSkill('Admin'); break; 1835 | case 4: this.addSkill('Computer'); break; 1836 | case 5: this.improveAttribute('social', 1); break; 1837 | default: this.addSkill('Jack-o-T'); 1838 | } 1839 | break; 1840 | } 1841 | } 1842 | }; 1843 | //---------------- Define "Doctors" service ----------------// 1844 | s.doctors = { 1845 | serviceName: 'Medical Field', // like "in the Navy" 1846 | memberName: 'Doctor', // like "Navy Admiral Nelson" 1847 | adjName: 'Medical', // like "the Naval service" 1848 | enlistmentThrow: 9, 1849 | enlistmentDM: function (attributes) { 1850 | var dm = 0; 1851 | if (attributes.intelligence >= 8) { dm += 1; } 1852 | if (attributes.dexterity >= 9) { dm += 2; } 1853 | return dm; 1854 | }, 1855 | survivalThrow: 5, 1856 | survivalDM: function (attributes) { 1857 | var dm = 0; 1858 | if (attributes.intelligence>= 8) { dm += 2; } 1859 | return dm; 1860 | }, 1861 | getServiceSkills: function () { return ['Medical']; }, 1862 | checkSurvival: function () { 1863 | var dm = 0; 1864 | var sv = roll(2); 1865 | if (this.attributes.intelligence >= 8) { dm += 2; } 1866 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 7); 1867 | if ((sv + dm) >= 7) { 1868 | return true; 1869 | } else { 1870 | return false; 1871 | } 1872 | }, 1873 | reenlistThrow: 3, 1874 | ranks: { 0: '', 1: '', 2: '', 3: '', 4: '', 5: '', 6: '' }, 1875 | checkPromotion: function () { 1876 | return false; 1877 | }, 1878 | checkCommission: function() { 1879 | return false; 1880 | }, 1881 | doPromotion: function() { return; }, 1882 | musterCash: { 1883 | 1: 20000, 1884 | 2: 20000, 1885 | 3: 20000, 1886 | 4: 30000, 1887 | 5: 40000, 1888 | 6: 60000, 1889 | 7: 1000000 1890 | }, 1891 | musterBenefits: function (dm) { 1892 | switch(roll(1) + dm) { 1893 | case 1: 1894 | this.addBenefit.call(t, 'Low Passage'); 1895 | break; 1896 | case 2: 1897 | this.improveAttribute('education', 1); 1898 | break; 1899 | case 3: 1900 | this.improveAttribute('education', 1); 1901 | break; 1902 | case 4: 1903 | this.doGunBenefit.call(t); 1904 | break; 1905 | case 5: 1906 | if (this.benefits.indexOf('Instruments') > -1) { 1907 | this.debugHistory('No benefit'); 1908 | break; 1909 | } 1910 | this.addBenefit.call(t, 'Instruments'); 1911 | break; 1912 | case 6: 1913 | this.addBenefit.call(t, 'Mid Passage'); 1914 | break; 1915 | default: 1916 | this.improveAttribute('social', 1); 1917 | } 1918 | }, 1919 | canMuster: function (strategy) { 1920 | return strategy == 'ship' || strategy == 'special'; 1921 | }, 1922 | acquireSkill: function () { 1923 | switch(this.whichSkillTable.call(this)) { 1924 | case 1: 1925 | switch(roll(1)) { 1926 | case 1: this.improveAttribute('strength', 1); break; 1927 | case 2: this.improveAttribute('dexterity', 1); break; 1928 | case 3: this.improveAttribute('endurance', 1); break; 1929 | case 4: this.improveAttribute('intelligence', 1); break; 1930 | case 5: this.improveAttribute('education', 1); break; 1931 | default: this.improveAttribute('social', 1); 1932 | } 1933 | break; 1934 | case 2: 1935 | switch(roll(1)) { 1936 | case 1: this.improveAttribute('dexterity', 1); break; 1937 | case 2: this.addSkill('Electronics'); break; 1938 | case 3: this.addSkill('Medical'); break; 1939 | case 4: this.addSkill('Streetwise'); break; 1940 | case 5: this.addSkill('Medical'); break; 1941 | default: this.addSkill(cascadeBlade.call(this)); 1942 | } 1943 | break; 1944 | case 3: 1945 | switch(roll(1)) { 1946 | case 1: this.addSkill('Medical'); break; 1947 | case 2: this.addSkill('Medical'); break; 1948 | case 3: this.addSkill('Mechanical'); break; 1949 | case 4: this.addSkill('Electronics'); break; 1950 | case 5: this.addSkill('Computer'); break; 1951 | default: this.addSkill('Admin'); 1952 | } 1953 | break; 1954 | case 4: 1955 | switch(roll(1)) { 1956 | case 1: this.addSkill('Medical'); break; 1957 | case 2: this.addSkill('Medical'); break; 1958 | case 3: this.addSkill('Admin'); break; 1959 | case 4: this.addSkill('Computer'); break; 1960 | case 5: this.improveAttribute('intelligence',1); break; 1961 | default: this.improveAttribute('education',1); 1962 | } 1963 | break; 1964 | } 1965 | } 1966 | }; 1967 | //---------------- Define "Flyer" service ----------------// 1968 | s.flyers = { 1969 | serviceName: 'Aerospace Force', // like "in the Navy" 1970 | memberName: 'Aerospace', // like "Navy Admiral Nelson" 1971 | adjName: "Aerospace", // like "the Naval service" 1972 | enlistmentThrow: 6, 1973 | enlistmentDM: function (attributes) { 1974 | var dm = 0; 1975 | if (attributes.strength >= 7) { dm += 1; } 1976 | if (attributes.dexterity >= 9) { dm += 2; } 1977 | return dm; 1978 | }, 1979 | survivalThrow: 5, 1980 | survivalDM: function (attributes) { 1981 | var dm = 0; 1982 | if (attributes.dexterity >= 8) { dm += 2; } 1983 | return dm; 1984 | }, 1985 | commissionThrow: 5, 1986 | commissionDM: function (attributes) { 1987 | var dm = 0; 1988 | if (attributes.education >= 6) { dm += 1; } 1989 | return dm; 1990 | }, 1991 | promotionThrow: 8, 1992 | promotionDM: function (attributes) { 1993 | var dm = 0; 1994 | if (attributes.education >= 8) { dm += 1; } 1995 | return dm; 1996 | }, 1997 | getServiceSkills: function () { 1998 | result = ''; 1999 | result = cascadeServiceAircraft.call(this); 2000 | return [result]; 2001 | }, 2002 | checkSurvival: function () { 2003 | var dm = 0; 2004 | var sv = roll(2); 2005 | if (this.attributes.dexterity >= 8) { dm += 2; } 2006 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 2007 | if ((sv + dm) >= 5) { 2008 | return true; 2009 | } else { 2010 | return false; 2011 | } 2012 | }, 2013 | reenlistThrow: 6, 2014 | ranks: { 2015 | 0: 'Airmen', 2016 | 1: 'Pilot', 2017 | 2: 'Flight Leader', 2018 | 3: 'Sqdrn Leader', 2019 | 4: 'Staff Major', 2020 | 5: 'Group Leader', 2021 | 6: 'Air Marshal' 2022 | }, 2023 | checkPromotion: function () { 2024 | var dm = 0; 2025 | var sv = roll(2); 2026 | if (this.attributes.education >= 8) { dm += 1; } 2027 | this.verboseHistory('Promotion roll ' + sv + ' + ' + dm + ' vs ' + 8); 2028 | if ((sv + dm) >= 8) { 2029 | return true; 2030 | } else { 2031 | return false; 2032 | } 2033 | }, 2034 | checkCommission: function() { 2035 | var dm = 0; 2036 | var sv = roll(2); 2037 | if (this.attributes.education >= 5) { dm += 1; } 2038 | this.verboseHistory('Commission roll ' + sv + ' + ' + dm + ' vs ' + 10); 2039 | if ((sv + dm) >= 5) { 2040 | return true; 2041 | } else { 2042 | return false; 2043 | } 2044 | }, 2045 | doPromotion: function() { 2046 | return; 2047 | }, 2048 | musterCash: { 2049 | 1: 2000, 2050 | 2: 5000, 2051 | 3: 10000, 2052 | 4: 10000, 2053 | 5: 10000, 2054 | 6: 20000, 2055 | 7: 30000 2056 | }, 2057 | musterBenefits: function (dm) { 2058 | switch(roll(1) + dm) { 2059 | case 1: 2060 | this.addBenefit.call(t, 'Low Passage'); 2061 | break; 2062 | case 2: 2063 | this.improveAttribute('education', 1); 2064 | break; 2065 | case 3: 2066 | this.doGunBenefit.call(t); 2067 | break; 2068 | case 4: 2069 | this.doGunBenefit.call(t); 2070 | break; 2071 | case 5: 2072 | this.addBenefit.call(t, 'High Passage'); 2073 | break; 2074 | case 6: 2075 | this.addBenefit.call(t, 'Mid Passage'); 2076 | break; 2077 | default: 2078 | this.improveAttribute('social', 1); 2079 | } 2080 | }, 2081 | canMuster: function (strategy) { 2082 | return false; 2083 | }, 2084 | acquireSkill: function () { 2085 | // Skills acquired during a term of service. 2086 | switch(this.whichSkillTable.call(this)) { 2087 | case 1: 2088 | switch(roll(1)) { 2089 | case 1: this.improveAttribute('strength', 1); break; 2090 | case 2: this.improveAttribute('dexterity', 1); break; 2091 | case 3: this.improveAttribute('endurance', 1); break; 2092 | case 4: this.addSkill('Gambling'); break; 2093 | case 5: this.addSkill('Brawling'); break; 2094 | default: this.addSkill('Carousing'); 2095 | } 2096 | break; 2097 | case 2: 2098 | switch(roll(1)) { 2099 | case 1: this.addSkill('Brawling'); break; 2100 | case 2: this.addSkill('Vacc Suit'); break; 2101 | case 3: this.addSkill(cascadeGun.call(this)); break; 2102 | case 4: this.addSkill(cascadeVehicle.call(this)); break; 2103 | case 5: this.addSkill(cascadeVehicle.call(this)); break; 2104 | default: this.addSkill(cascadeVehicle.call(this)); 2105 | } 2106 | break; 2107 | case 3: 2108 | switch(roll(1)) { 2109 | case 1: this.addSkill(cascadeAircraft.call(this)); break; 2110 | case 2: this.addSkill('Mechanical'); break; 2111 | case 3: this.addSkill('Electronics'); break; 2112 | case 4: this.addSkill('Gravitics'); break; 2113 | case 5: this.addSkill(cascadeGun.call(this)); break; 2114 | default: this.addSkill('Survival'); 2115 | } 2116 | break; 2117 | case 4: 2118 | switch(roll(1)) { 2119 | case 1: this.addSkill('Medical'); break; 2120 | case 2: this.addSkill('Leader'); break; 2121 | case 3: this.addSkill('Pilot'); break; 2122 | case 4: this.addSkill('Computer'); break; 2123 | case 5: this.addSkill('Admin'); break; 2124 | default: this.addSkill('Jack-o-T'); 2125 | } 2126 | break; 2127 | } 2128 | } 2129 | }; 2130 | //---------------- Define "Barbarians" service ----------------// 2131 | s.barbarians = { 2132 | serviceName: 'Barbarian', // like "in the Navy" 2133 | memberName: 'Barbarian', // like "Navy Admiral Nelson" 2134 | adjName: "Barbarian", // like "the Naval service" 2135 | enlistmentThrow: 5, 2136 | enlistmentDM: function (attributes) { 2137 | var dm = 0; 2138 | if (attributes.endurance >= 9) { dm += 1; } 2139 | if (attributes.strength >= 10) { dm += 2; } 2140 | return dm; 2141 | }, 2142 | survivalThrow: 6, 2143 | survivalDM: function (attributes) { 2144 | var dm = 0; 2145 | if (attributes.strength >= 8) { dm += 2; } 2146 | return dm; 2147 | }, 2148 | commissionThrow: 6, 2149 | commissionDM: function (attributes) { 2150 | var dm = 0; 2151 | if (attributes.strength >= 10) { dm += 1; } 2152 | return dm; 2153 | }, 2154 | promotionThrow: 9, 2155 | promotionDM: function (attributes) { 2156 | var dm = 0; 2157 | if (attributes.intelligence >= 6) { dm += 1; } 2158 | return dm; 2159 | }, 2160 | getServiceSkills: function () { 2161 | result = 'Sword'; 2162 | return [result]; 2163 | }, 2164 | checkSurvival: function () { 2165 | var dm = 0; 2166 | var sv = roll(2); 2167 | if (this.attributes.strength >= 8) { dm += 2; } 2168 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 2169 | if ((sv + dm) >= 6) { 2170 | return true; 2171 | } else { 2172 | return false; 2173 | } 2174 | }, 2175 | reenlistThrow: 6, 2176 | ranks: { 2177 | 0: 'Barbarian', 2178 | 1: 'Barbarian', 2179 | 2: 'Warrior', 2180 | 3: 'Warrior', 2181 | 4: 'Warrior', 2182 | 5: 'Chief', 2183 | 6: 'Chief' 2184 | }, 2185 | checkPromotion: function () { 2186 | var dm = 0; 2187 | var sv = roll(2); 2188 | if (this.attributes.intelligence >= 6) { dm += 1; } 2189 | this.verboseHistory('Promotion roll ' + sv + ' + ' + dm + ' vs ' + 8); 2190 | if ((sv + dm) >= 9) { 2191 | return true; 2192 | } else { 2193 | return false; 2194 | } 2195 | }, 2196 | checkCommission: function() { 2197 | var dm = 0; 2198 | var sv = roll(2); 2199 | if (this.attributes.strength >= 8) { dm += 1; } 2200 | this.verboseHistory('Commission roll ' + sv + ' + ' + dm + ' vs ' + 10); 2201 | if ((sv + dm) >= 6) { 2202 | return true; 2203 | } else { 2204 | return false; 2205 | } 2206 | }, 2207 | doPromotion: function() { 2208 | if (this.rank == 2) { 2209 | this.addSkill(cascadeBlade.call(this)); 2210 | } else if (this.rank == 5) { 2211 | this.addSkill('leader'); 2212 | } 2213 | return; 2214 | }, 2215 | musterCash: { 2216 | 1: 0, 2217 | 2: 0, 2218 | 3: 1000, 2219 | 4: 2000, 2220 | 5: 3000, 2221 | 6: 4000, 2222 | 7: 5000 2223 | }, 2224 | musterBenefits: function (dm) { 2225 | switch(roll(1) + dm) { 2226 | case 1: 2227 | this.addBenefit.call(t, 'Low Passage'); 2228 | break; 2229 | case 2: 2230 | this.doBladeBenefit.call(t); 2231 | break; 2232 | case 3: 2233 | this.doBladeBenefit.call(t); 2234 | break; 2235 | case 4: 2236 | this.doBladeBenefit.call(t); 2237 | break; 2238 | case 5: 2239 | break; 2240 | case 6: 2241 | this.addBenefit.call(t, 'High Passage'); 2242 | break; 2243 | default: 2244 | this.addBenefit.call(t, 'High Passage'); 2245 | } 2246 | }, 2247 | canMuster: function (strategy) { 2248 | return false; 2249 | }, 2250 | acquireSkill: function () { 2251 | // Skills acquired during a term of service. 2252 | switch(this.whichSkillTable.call(this)) { 2253 | case 1: 2254 | switch(roll(1)) { 2255 | case 1: this.improveAttribute('strength', 1); break; 2256 | case 2: this.improveAttribute('strength', 2); break; 2257 | case 3: this.improveAttribute('strength', 1); break; 2258 | case 4: this.addSkill('Carousing'); break; 2259 | case 5: this.improveAttribute('dexterity',1); break; 2260 | default: this.improveAttribute('endurance',1); 2261 | } 2262 | break; 2263 | case 2: 2264 | switch(roll(1)) { 2265 | case 1: this.addSkill('Brawling'); break; 2266 | case 2: this.addSkill(cascadeBlade.call(this)); break; 2267 | case 3: this.addSkill(cascadeBlade.call(this)); break; 2268 | case 4: this.addSkill(cascadeBow.call(this)); break; 2269 | case 5: this.addSkill(cascadeBow.call(this)); break; 2270 | default: this.addSkill(cascadeGun.call(this)); 2271 | } 2272 | break; 2273 | case 3: 2274 | switch(roll(1)) { 2275 | case 1: this.addSkill(cascadeBlade.call(this)); break; 2276 | case 2: this.addSkill('Mechanical'); break; 2277 | case 3: this.addSkill('Survival'); break; 2278 | case 4: this.addSkill('Recon'); break; 2279 | case 5: this.addSkill('Streetwise'); break; 2280 | default: this.addSkill(cascadeBow.call(this)); 2281 | } 2282 | break; 2283 | case 4: 2284 | switch(roll(1)) { 2285 | case 1: this.addSkill('Medical'); break; 2286 | case 2: this.addSkill('Interrogation'); break; 2287 | case 3: this.addSkill('Tactics'); break; 2288 | case 4: this.addSkill('Leader'); break; 2289 | case 5: this.addSkill('Instruction'); break; 2290 | default: this.addSkill('Jack-o-T'); 2291 | } 2292 | break; 2293 | } 2294 | } 2295 | }; 2296 | //---------------- Define "Bureaucrats" service ----------------// 2297 | s.bureaucrats = { 2298 | serviceName: 'Bureaucracy', // like "in the Navy" 2299 | memberName: 'Bureaucrat', // like "Navy Admiral Nelson" 2300 | adjName: "Bureaucracy", // like "the Naval service" 2301 | enlistmentThrow: 5, 2302 | enlistmentDM: function (attributes) { 2303 | var dm = 0; 2304 | if (attributes.education >= 8) { dm += 1; } 2305 | if (attributes.strength <= 8) { dm += 2; } 2306 | return dm; 2307 | }, 2308 | survivalThrow: 4, 2309 | survivalDM: function (attributes) { 2310 | var dm = 0; 2311 | if (attributes.education >= 10) { dm += 2; } 2312 | return dm; 2313 | }, 2314 | commissionThrow: 6, 2315 | commissionDM: function (attributes) { 2316 | var dm = 0; 2317 | if (attributes.social >= 9) { dm += 1; } 2318 | return dm; 2319 | }, 2320 | promotionThrow: 7, 2321 | promotionDM: function (attributes) { 2322 | var dm = 0; 2323 | if (attributes.intelligence >= 9) { dm += 1; } 2324 | return dm; 2325 | }, 2326 | getServiceSkills: function () { return []; }, 2327 | checkSurvival: function () { 2328 | var dm = 0; 2329 | var sv = roll(2); 2330 | if (this.attributes.education >= 10) { dm += 2; } 2331 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 2332 | if ((sv + dm) >= 4) { 2333 | return true; 2334 | } else { 2335 | return false; 2336 | } 2337 | }, 2338 | reenlistThrow: 7, 2339 | ranks: { 2340 | 0: 'Bureaucrat', 2341 | 1: 'Clerk', 2342 | 2: 'Supervisor', 2343 | 3: 'Asst Manager', 2344 | 4: 'Manager', 2345 | 5: 'Executive', 2346 | 6: 'Director' 2347 | }, 2348 | checkPromotion: function () { 2349 | var dm = 0; 2350 | var sv = roll(2); 2351 | if (this.attributes.intelligence >= 9) { dm += 1; } 2352 | this.verboseHistory('Promotion roll ' + sv + ' + ' + dm + ' vs ' + 8); 2353 | if ((sv + dm) >= 7) { 2354 | return true; 2355 | } else { 2356 | return false; 2357 | } 2358 | }, 2359 | checkCommission: function() { 2360 | var dm = 0; 2361 | var sv = roll(2); 2362 | if (this.attributes.social >= 9) { dm += 1; } 2363 | this.verboseHistory('Commission roll ' + sv + ' + ' + dm + ' vs ' + 10); 2364 | if ((sv + dm) >= 6) { 2365 | return true; 2366 | } else { 2367 | return false; 2368 | } 2369 | }, 2370 | doPromotion: function() { 2371 | return; 2372 | }, 2373 | musterCash: { 2374 | 1: 0, 2375 | 2: 0, 2376 | 3: 10000, 2377 | 4: 10000, 2378 | 5: 40000, 2379 | 6: 40000, 2380 | 7: 80000 2381 | }, 2382 | musterBenefits: function (dm) { 2383 | switch(roll(1) + dm) { 2384 | case 1: 2385 | this.addBenefit.call(t, 'Low Passage'); 2386 | break; 2387 | case 2: 2388 | this.addBenefit.call(t, 'Mid Passage'); 2389 | break; 2390 | case 3: 2391 | break; 2392 | case 4: 2393 | if (this.benefits.indexOf("Watch") > -1) { 2394 | break; 2395 | } 2396 | this.addBenefit.call(t, "Watch"); 2397 | break; 2398 | case 5: 2399 | break; 2400 | case 6: 2401 | this.addBenefit.call(t, 'High Passage'); 2402 | break; 2403 | default: 2404 | this.improveAttribute('social', 1); 2405 | break; 2406 | } 2407 | }, 2408 | canMuster: function (strategy) { 2409 | return false; 2410 | }, 2411 | acquireSkill: function () { 2412 | // Skills acquired during a term of service. 2413 | switch(this.whichSkillTable.call(this)) { 2414 | case 1: 2415 | switch(roll(1)) { 2416 | case 1: this.improveAttribute('endurance', 1); break; 2417 | case 2: this.improveAttribute('education', 1); break; 2418 | case 3: this.improveAttribute('intelligence', 1); break; 2419 | case 4: this.addSkill('Brawling'); break; 2420 | case 5: this.addSkill('Carousing'); break; 2421 | default: this.improveAttribute('dexterity', 1); 2422 | } 2423 | break; 2424 | case 2: 2425 | switch(roll(1)) { 2426 | case 1: this.addSkill(cascadeGun.call(this)); break; 2427 | case 2: this.addSkill(cascadeVehicle.call(this)); break; 2428 | case 3: this.addSkill(cascadeBlade.call(this)); break; 2429 | case 4: this.addSkill('Instruction'); break; 2430 | case 5: this.addSkill(cascadeVehicle.call(this)); break; 2431 | default: this.improveAttribute('education',1); 2432 | } 2433 | break; 2434 | case 3: 2435 | switch(roll(1)) { 2436 | case 1: this.addSkill('Recruiting'); break; 2437 | case 2: this.addSkill(cascadeVehicle.call(this)); break; 2438 | case 3: this.addSkill('Liaison'); break; 2439 | case 4: this.addSkill('Interrogation'); break; 2440 | case 5: this.addSkill('Admin'); break; 2441 | default: this.addSkill('Admin'); 2442 | } 2443 | break; 2444 | case 4: 2445 | switch(roll(1)) { 2446 | case 1: this.addSkill('Admin'); break; 2447 | case 2: this.addSkill('Admin'); break; 2448 | case 3: this.addSkill('Computer'); break; 2449 | case 4: this.addSkill('Computer'); break; 2450 | case 5: this.addSkill('Admin'); break; 2451 | default: this.addSkill('Jack-o-T'); 2452 | } 2453 | break; 2454 | } 2455 | } 2456 | }; 2457 | //---------------- Define "Rogue" service ----------------// 2458 | s.rogues = { 2459 | serviceName: 'criminal life', // like "in the Navy" 2460 | memberName: 'Rogue', // like "Navy Admiral Nelson" 2461 | adjName: 'criminal', // like "the Naval service" 2462 | enlistmentThrow: 6, 2463 | enlistmentDM: function (attributes) { 2464 | var dm = 0; 2465 | if (attributes.social <= 8) { dm += 1; } 2466 | if (attributes.endurance >= 7) { dm += 2; } 2467 | return dm; 2468 | }, 2469 | survivalThrow: 6, 2470 | survivalDM: function (attributes) { 2471 | var dm = 0; 2472 | if (attributes.intelligence >= 9) { dm += 2; } 2473 | return dm; 2474 | }, 2475 | getServiceSkills: function () { return ['Streetwise']; }, 2476 | checkSurvival: function () { 2477 | var dm = 0; 2478 | var sv = roll(2); 2479 | if (this.attributes.intelligence >= 9) { dm += 2; } 2480 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 2481 | if ((sv + dm) >= 6) { 2482 | return true; 2483 | } else { 2484 | return false; 2485 | } 2486 | }, 2487 | reenlistThrow: 6, 2488 | ranks: { 0: '', 1: '', 2: '', 3: '', 4: '', 5: '', 6: '' }, 2489 | checkPromotion: function () { 2490 | return false; 2491 | }, 2492 | checkCommission: function () { 2493 | return false; 2494 | }, 2495 | doPromotion: function() { return; }, 2496 | musterCash: { 2497 | 1: 0, 2498 | 2: 0, 2499 | 3: 10000, 2500 | 4: 10000, 2501 | 5: 50000, 2502 | 6: 100000, 2503 | 7: 100000 2504 | }, 2505 | musterBenefits: function (dm) { 2506 | switch(roll(1) + dm) { 2507 | case 1: 2508 | this.addBenefit.call(t, 'Low Passage'); 2509 | break; 2510 | case 2: 2511 | this.improveAttribute('social', 1); 2512 | break; 2513 | case 3: 2514 | this.doGunBenefit.call(t); 2515 | break; 2516 | case 4: 2517 | this.doBladeBenefit.call(t); 2518 | break; 2519 | case 5: 2520 | this.addBenefit.call(t, 'High Passage'); 2521 | break; 2522 | default: 2523 | if (this.benefits.indexOf("Travellers' Aide Society") > -1) { 2524 | break; 2525 | } 2526 | this.addBenefit.call(t, "Travellers' Aid Society"); 2527 | this.TAS = true; 2528 | break; 2529 | } 2530 | }, 2531 | canMuster: function (strategy) { 2532 | return false; 2533 | }, 2534 | acquireSkill: function () { 2535 | switch(this.whichSkillTable.call(this)) { 2536 | case 1: 2537 | switch(roll(1)) { 2538 | case 1: this.improveAttribute('strength', 1); break; 2539 | case 2: this.improveAttribute('dexterity', 1); break; 2540 | case 3: this.improveAttribute('endurance', 1); break; 2541 | case 4: this.improveAttribute('intelligence', 1); break; 2542 | case 5: this.addSkill('Brawling'); break; 2543 | default: this.addSkill('Carousing'); 2544 | } 2545 | break; 2546 | case 2: 2547 | switch(roll(1)) { 2548 | case 1: this.addSkill(cascadeBlade.call(this)); break; 2549 | case 2: this.addSkill(cascadeGun.call(this)); break; 2550 | case 3: this.addSkill('Demolition'); break; 2551 | case 4: this.addSkill(cascadeVehicle.call(this)); break; 2552 | case 5: this.improveAttribute('education',1); break; 2553 | default: this.addSkill(cascadeVehicle.call(this)); 2554 | } 2555 | break; 2556 | case 3: 2557 | switch(roll(1)) { 2558 | case 1: this.addSkill('Streetwise'); break; 2559 | case 2: this.addSkill('Forgery'); break; 2560 | case 3: this.addSkill('Bribery'); break; 2561 | case 4: this.addSkill('Carousing'); break; 2562 | case 5: this.addSkill('Liaison'); break; 2563 | default: this.addSkill('Ship Tactics'); 2564 | } 2565 | break; 2566 | case 4: 2567 | switch(roll(1)) { 2568 | case 1: this.addSkill('Medical'); break; 2569 | case 2: this.addSkill('Bribery'); break; 2570 | case 3: this.addSkill('Electronics'); break; 2571 | case 4: this.addSkill('Forgery'); break; 2572 | case 5: this.addSkill('Computer'); break; 2573 | default: this.addSkill('Jack-o-T'); 2574 | } 2575 | break; 2576 | } 2577 | } 2578 | }; 2579 | //---------------- Define "Noble" service ----------------// 2580 | s.nobles = { 2581 | serviceName: 'Nobility', // like "in the Navy" 2582 | memberName: 'Noble', // like "Navy Admiral Nelson" 2583 | adjName: "Nobility", // like "the Naval service" 2584 | enlistmentThrow: 3, 2585 | enlistmentDM: function (attributes) { 2586 | var dm = 0; 2587 | if (attributes.social <= 9) { dm -= 12; } 2588 | if (attributes.social >= 10) { dm += 12; } 2589 | return dm; 2590 | }, 2591 | survivalThrow: 3, 2592 | survivalDM: function (attributes) { 2593 | return 0; 2594 | }, 2595 | commissionThrow: 5, 2596 | commissionDM: function (attributes) { 2597 | var dm = 0; 2598 | if (attributes.education >= 9) { dm += 1; } 2599 | return dm; 2600 | }, 2601 | promotionThrow: 12, 2602 | promotionDM: function (attributes) { 2603 | var dm = 0; 2604 | if (attributes.intelligence >= 10) { dm += 1; } 2605 | return dm; 2606 | }, 2607 | getServiceSkills: function () { 2608 | return []; 2609 | }, 2610 | checkSurvival: function () { 2611 | var dm = 0; 2612 | var sv = roll(2); 2613 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 2614 | if ((sv + dm) >= 3) { 2615 | return true; 2616 | } else { 2617 | return false; 2618 | } 2619 | }, 2620 | reenlistThrow: 5, 2621 | ranks: { 2622 | 0: 'Noble', 2623 | 1: 'B Baron', 2624 | 2: 'C Baron', 2625 | 3: 'D Marquis', 2626 | 4: 'E Count', 2627 | 5: 'F Duke', 2628 | 6: 'F Duke (sector)' 2629 | }, 2630 | checkPromotion: function () { 2631 | var dm = 0; 2632 | var sv = roll(2); 2633 | if (this.attributes.int >= 10) { dm += 1; } 2634 | this.verboseHistory('Promotion roll ' + sv + ' + ' + dm + ' vs ' + 8); 2635 | if ((sv + dm) >= 12) { 2636 | if (this.social < 12) { 2637 | this.improveAttribute('social',1); 2638 | } 2639 | return true; 2640 | } else { 2641 | return false; 2642 | } 2643 | }, 2644 | checkCommission: function() { 2645 | var dm = 0; 2646 | var sv = roll(2); 2647 | if (this.attributes.education >= 9) { dm += 1; } 2648 | this.verboseHistory('Commission roll ' + sv + ' + ' + dm + ' vs ' + 10); 2649 | if ((sv + dm) >= 5) { 2650 | return true; 2651 | } else { 2652 | return false; 2653 | } 2654 | }, 2655 | doPromotion: function() { 2656 | var rank_social = this.rank + 10; 2657 | if (this.attributes['social'] < rank_social) { 2658 | this.attributes['social'] = rank_social; 2659 | } 2660 | }, 2661 | musterCash: { 2662 | 1: 10000, 2663 | 2: 50000, 2664 | 3: 50000, 2665 | 4: 100000, 2666 | 5: 100000, 2667 | 6: 100000, 2668 | 7: 200000 2669 | }, 2670 | musterBenefits: function (dm) { 2671 | switch(roll(1) + dm) { 2672 | case 1: 2673 | this.addBenefit.call(t, 'High Passage'); 2674 | break; 2675 | case 2: 2676 | this.addBenefit.call(t, 'High Passage'); 2677 | break; 2678 | case 3: 2679 | this.doGunBenefit.call(t); 2680 | break; 2681 | case 4: 2682 | this.doBladeBenefit.call(t); 2683 | break; 2684 | case 5: 2685 | if (this.benefits.indexOf("Travellers' Aide Society") > -1) { 2686 | break; 2687 | } 2688 | this.addBenefit.call(t, "Travellers' Aid Society"); 2689 | this.TAS = true; 2690 | break; 2691 | default: 2692 | if (this.benefits.indexOf('Yacht') > -1) { 2693 | this.debugHistory('No benefit'); 2694 | break; 2695 | } 2696 | this.addBenefit.call(t, 'Yacht'); 2697 | this.ship = true; 2698 | break; 2699 | } 2700 | }, 2701 | canMuster: function (strategy) { 2702 | return strategy == 'ship' || strategy == 'special'; 2703 | }, 2704 | acquireSkill: function () { 2705 | // Skills acquired during a term of service. 2706 | switch(this.whichSkillTable.call(this)) { 2707 | case 1: 2708 | switch(roll(1)) { 2709 | case 1: this.improveAttribute('strength', 1); break; 2710 | case 2: this.improveAttribute('dexterity', 1); break; 2711 | case 3: this.improveAttribute('endurance', 1); break; 2712 | case 4: this.improveAttribute('intelligence',1); break; 2713 | case 5: this.addSkill('Carousing'); break; 2714 | default: this.addSkill('Brawling'); 2715 | } 2716 | break; 2717 | case 2: 2718 | switch(roll(1)) { 2719 | case 1: this.addSkill(cascadeGun.call(this)); break; 2720 | case 2: this.addSkill(cascadeBlade.call(this)); break; 2721 | case 3: this.addSkill('Hunting'); break; 2722 | case 4: this.addSkill(cascadeVehicle.call(this)); break; 2723 | case 5: this.addSkill('Bribery'); break; 2724 | default: this.improveAttribute('dexterity',1); 2725 | } 2726 | break; 2727 | case 3: 2728 | switch(roll(1)) { 2729 | case 1: this.addSkill('Pilot'); break; 2730 | case 2: this.addSkill("Ship's Boat"); break; 2731 | case 3: this.addSkill(cascadeVehicle.call(this)); break; 2732 | case 4: this.addSkill('Navigation'); break; 2733 | case 5: this.addSkill('Engineering'); break; 2734 | default: this.addSkill('Leader'); 2735 | } 2736 | break; 2737 | case 4: 2738 | switch(roll(1)) { 2739 | case 1: this.addSkill('Medical'); break; 2740 | case 2: this.addSkill('Computer'); break; 2741 | case 3: this.addSkill('Admin'); break; 2742 | case 4: this.addSkill('Liaison'); break; 2743 | case 5: this.addSkill('Leader'); break; 2744 | default: this.addSkill('Jack-o-T'); 2745 | } 2746 | break; 2747 | } 2748 | } 2749 | }; 2750 | //---------------- Define "Scientists" service ----------------// 2751 | s.scientists = { 2752 | serviceName: 'field of science', // like "in the Navy" 2753 | memberName: 'Scientist', // like "Navy Admiral Nelson" 2754 | adjName: 'scientific study', // like "the Naval service" 2755 | enlistmentThrow: 6, 2756 | enlistmentDM: function (attributes) { 2757 | var dm = 0; 2758 | if (attributes.intelligence >= 9) { dm += 1; } 2759 | if (attributes.education >= 10) { dm += 2; } 2760 | return dm; 2761 | }, 2762 | survivalThrow: 5, 2763 | survivalDM: function (attributes) { 2764 | var dm = 0; 2765 | if (attributes.education >= 9) { dm += 2; } 2766 | return dm; 2767 | }, 2768 | getServiceSkills: function () { return ['Computer']; }, 2769 | checkSurvival: function () { 2770 | var dm = 0; 2771 | var sv = roll(2); 2772 | if (this.attributes.education >= 9) { dm += 2; } 2773 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 5); 2774 | if ((sv + dm) >= 5) { 2775 | return true; 2776 | } else { 2777 | return false; 2778 | } 2779 | }, 2780 | reenlistThrow: 4, 2781 | ranks: { 0: '', 1: '', 2: '', 3: '', 4: '', 5: '', 6: '' }, 2782 | checkPromotion: function () { 2783 | return false; 2784 | }, 2785 | checkCommission: function () { 2786 | return false; 2787 | }, 2788 | doPromotion: function() { return; }, 2789 | musterCash: { 2790 | 1: 1000, 2791 | 2: 2000, 2792 | 3: 5000, 2793 | 4: 10000, 2794 | 5: 20000, 2795 | 6: 30000, 2796 | 7: 40000 2797 | }, 2798 | musterBenefits: function (dm) { 2799 | switch(roll(1) + dm) { 2800 | case 1: 2801 | this.addBenefit.call(t, 'Low Passage'); 2802 | break; 2803 | case 2: 2804 | this.addBenefit.call(t, 'Mid Passage'); 2805 | break; 2806 | case 3: 2807 | this.addBenefit.call(t, 'High Passage'); 2808 | break; 2809 | case 4: 2810 | this.improveAttribute('social', 1); 2811 | break; 2812 | case 5: 2813 | this.doGunBenefit.call(t); 2814 | break; 2815 | default: 2816 | if (this.benefits.indexOf('Lab Ship') > -1) { 2817 | this.debugHistory('No benefit'); 2818 | break; 2819 | } 2820 | this.addBenefit.call(t, 'Lab Ship'); 2821 | this.ship = true; 2822 | break; 2823 | } 2824 | }, 2825 | canMuster: function (strategy) { 2826 | return strategy == 'ship' || strategy == 'special'; 2827 | }, 2828 | acquireSkill: function () { 2829 | switch(this.whichSkillTable.call(this)) { 2830 | case 1: 2831 | switch(roll(1)) { 2832 | case 1: this.improveAttribute('strength', 1); break; 2833 | case 2: this.improveAttribute('dexterity', 1); break; 2834 | case 3: this.improveAttribute('endurance', 1); break; 2835 | case 4: this.improveAttribute('intelligence', 1); break; 2836 | case 5: this.improveAttribute('education', 1); break; 2837 | default: this.addSkill('Carousing'); 2838 | } 2839 | break; 2840 | case 2: 2841 | switch(roll(1)) { 2842 | case 1: this.addSkill(cascadeGun.call(this)); break; 2843 | case 2: this.addSkill(cascadeBlade.call(this)); break; 2844 | case 3: this.addSkill(cascadeVehicle.call(this)); break; 2845 | case 4: this.addSkill('Jack-o-T'); break; 2846 | case 5: this.addSkill('Navigation'); break; 2847 | default: this.addSkill('Survival'); 2848 | } 2849 | break; 2850 | case 3: 2851 | switch(roll(1)) { 2852 | case 1: this.addSkill('Mechanical'); break; 2853 | case 2: this.addSkill('Electronics'); break; 2854 | case 3: this.addSkill('Gravitics'); break; 2855 | case 4: this.addSkill('Computer'); break; 2856 | case 5: this.improveAttribute('intelligence',1); break; 2857 | default: this.improveAttribute('education',1); 2858 | } 2859 | break; 2860 | case 4: 2861 | switch(roll(1)) { 2862 | case 1: this.addSkill('Medical'); break; 2863 | case 2: this.addSkill('Computer'); break; 2864 | case 3: this.addSkill('Admin'); break; 2865 | case 4: this.addSkill('Leader'); break; 2866 | case 5: this.improveAttribute('intelligence',1); break; 2867 | default: this.addSkill('Jack-o-T'); 2868 | } 2869 | break; 2870 | } 2871 | } 2872 | }; 2873 | //---------------- Define "Hunters" service ----------------// 2874 | s.hunters = { 2875 | serviceName: 'Hunters', // like "in the Navy" 2876 | memberName: 'Hunter', // like "Navy Admiral Nelson" 2877 | adjName: 'Hunting business', // like "the Naval service" 2878 | enlistmentThrow: 9, 2879 | enlistmentDM: function (attributes) { 2880 | var dm = 0; 2881 | if (attributes.dexterity >= 10) { dm += 1; } 2882 | if (attributes.endurance >= 9) { dm += 2; } 2883 | return dm; 2884 | }, 2885 | survivalThrow: 6, 2886 | survivalDM: function (attributes) { 2887 | var dm = 0; 2888 | if (attributes.strength >= 10) { dm += 2; } 2889 | return dm; 2890 | }, 2891 | getServiceSkills: function () { return ['Hunting']; }, 2892 | checkSurvival: function () { 2893 | var dm = 0; 2894 | var sv = roll(2); 2895 | if (this.attributes.strength >= 10) { dm += 2; } 2896 | this.verboseHistory('Survival roll ' + sv + ' + ' + dm + ' vs ' + 7); 2897 | if ((sv + dm) >= 6) { 2898 | return true; 2899 | } else { 2900 | return false; 2901 | } 2902 | }, 2903 | reenlistThrow: 3, 2904 | ranks: { 0: '', 1: '', 2: '', 3: '', 4: '', 5: '', 6: '' }, 2905 | checkPromotion: function () { 2906 | return false; 2907 | }, 2908 | checkCommission: function() { 2909 | return false; 2910 | }, 2911 | doPromotion: function() { return; }, 2912 | musterCash: { 2913 | 1: 1000, 2914 | 2: 1000, 2915 | 3: 5000, 2916 | 4: 5000, 2917 | 5: 10000, 2918 | 6: 100000, 2919 | 7: 100000 2920 | }, 2921 | musterBenefits: function (dm) { 2922 | switch(roll(1) + dm) { 2923 | case 1: 2924 | this.addBenefit.call(t, 'Low Passage'); 2925 | break; 2926 | case 2: 2927 | this.addBenefit.call(t, 'High Passage'); 2928 | break; 2929 | case 3: 2930 | this.doGunBenefit.call(t); 2931 | break; 2932 | case 4: 2933 | this.doGunBenefit.call(t); 2934 | break; 2935 | case 5: 2936 | this.doGunBenefit.call(t); 2937 | break; 2938 | default: 2939 | if (this.benefits.indexOf('Safari Ship') > -1) { 2940 | this.debugHistory('No benefit'); 2941 | break; 2942 | } 2943 | this.addBenefit.call(t, 'Safari Ship'); 2944 | this.ship = true; 2945 | break; 2946 | } 2947 | }, 2948 | canMuster: function (strategy) { 2949 | return strategy == 'ship' || strategy == 'special'; 2950 | }, 2951 | acquireSkill: function () { 2952 | switch(this.whichSkillTable.call(this)) { 2953 | case 1: 2954 | switch(roll(1)) { 2955 | case 1: this.improveAttribute('strength', 1); break; 2956 | case 2: this.improveAttribute('dexterity', 1); break; 2957 | case 3: this.improveAttribute('endurance', 1); break; 2958 | case 4: this.improveAttribute('intelligence', 1); break; 2959 | case 5: this.addSkill(cascadeGun.call(this)); break; 2960 | default: this.addSkill(cascadeBlade.call(this)); 2961 | } 2962 | break; 2963 | case 2: 2964 | switch(roll(1)) { 2965 | case 1: this.addSkill(cascadeGun.call(this)); break; 2966 | case 2: this.addSkill(cascadeBlade.call(this)); break; 2967 | case 3: this.addSkill('Survival'); break; 2968 | case 4: this.addSkill('Hunting'); break; 2969 | case 5: this.addSkill(cascadeVehicle.call(this)); break; 2970 | default: this.addSkill('Hunting'); 2971 | } 2972 | break; 2973 | case 3: 2974 | switch(roll(1)) { 2975 | case 1: this.addSkill('Mechanical'); break; 2976 | case 2: this.addSkill('Electronics'); break; 2977 | case 3: this.addSkill('Gravitics'); break; 2978 | case 4: this.addSkill('Computer'); break; 2979 | case 5: this.addSkill('Hunting'); break; 2980 | default: this.addSkill('Admin'); 2981 | } 2982 | break; 2983 | case 4: 2984 | switch(roll(1)) { 2985 | case 1: this.addSkill('Medical'); break; 2986 | case 2: this.addSkill('Computer'); break; 2987 | case 3: this.addSkill('Hunting'); break; 2988 | case 4: this.addSkill('Leader'); break; 2989 | case 5: this.addSkill('Survival'); break; 2990 | default: this.addSkill('Admin'); 2991 | } 2992 | break; 2993 | } 2994 | } 2995 | }; 2996 | 2997 | //------------ "t" object holds Traveller character definitions ------------// 2998 | var t = {}; 2999 | t.cheat = false; 3000 | t.urlParam = function(name, w){ 3001 | w = w || window; 3002 | var rx = new RegExp('[\&|\?]'+name+'=([^\&\#]+)'), 3003 | val = w.location.search.match(rx); 3004 | return !val ? '':val[1]; 3005 | } 3006 | t.urlParams = function(w){ 3007 | w = w || window; 3008 | var rx = new RegExp('[\?]([^\#]+)'), 3009 | val = w.location.search.match(rx); 3010 | return !val ? '':val[1]; 3011 | } 3012 | t.age = 18; 3013 | t.gender = generateGender(); 3014 | t.name = generateName(t.gender); 3015 | t.showHistory = 'simple'; 3016 | t.terms = 0; 3017 | t.credits = 0; 3018 | t.history = []; 3019 | t.benefits = []; 3020 | t.ship = false; 3021 | t.TAS = false; 3022 | t.mortgage = 40; 3023 | t.bladeBenefit = ''; 3024 | t.gunBenefit = ''; 3025 | t.vehicles = 'TTB'; 3026 | t.doBladeBenefit = function () { 3027 | if (t.bladeBenefit == '') { 3028 | t.bladeBenefit = cascadeBlade.call(t); 3029 | t.addBenefit(t.bladeBenefit); 3030 | } else { 3031 | t.addSkill(t.bladeBenefit); 3032 | } 3033 | } 3034 | t.doGunBenefit = function () { 3035 | if (t.gunBenefit == '') { 3036 | t.gunBenefit = cascadeGun.call(t); 3037 | t.addBenefit(t.gunBenefit); 3038 | } else { 3039 | t.addSkill(t.gunBenefit); 3040 | } 3041 | } 3042 | t.attributes = { 3043 | strength: roll(2), 3044 | dexterity: roll(2), 3045 | endurance: roll(2), 3046 | intelligence: roll(2), 3047 | education: roll(2), 3048 | social: roll(2), 3049 | }; 3050 | t.extendedHex = function (val) { 3051 | var xhex = '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ'.split(''); 3052 | if (val < 34) { 3053 | return xhex[val]; 3054 | } else { 3055 | return '?'; 3056 | } 3057 | } 3058 | t.getAttrString = function () { 3059 | return t.extendedHex(t.attributes.strength) + 3060 | t.extendedHex(t.attributes.dexterity) + 3061 | t.extendedHex(t.attributes.endurance) + 3062 | t.extendedHex(t.attributes.intelligence) + 3063 | t.extendedHex(t.attributes.education) + 3064 | t.extendedHex(t.attributes.social); 3065 | }; 3066 | t.skillPoints = 0; 3067 | t.skills = []; 3068 | t.checkSkill = function (skill) { 3069 | for (var i = 0, limit = t.skills.length; i < limit; i++) { 3070 | if (t.skills[i][0] == skill) { 3071 | return i; 3072 | } 3073 | } 3074 | return -1; 3075 | }; 3076 | t.checkSkillLevel = function (skill, level) { 3077 | i = t.checkSkill(skill); 3078 | if (i < 0) { 3079 | return false; 3080 | } 3081 | return t.skills[i][1] >= level; 3082 | } 3083 | t.tables = ['personal development', 'service skills', 'advanced education', 3084 | 'advanced education 8+']; 3085 | t.whichSkillTable = function() { 3086 | var table; 3087 | if (this.urlParam('personal') == 'always') { 3088 | table = rndInt(1, 3 + (this.attributes.education >= 8 ? 1 : 0)); 3089 | } else { 3090 | table = rndInt(1, 3) + (this.attributes.education >= 8 ? 1 : 0); 3091 | } 3092 | this.debugHistory('Skill from table ' + table + ' ' + 3093 | this.tables[table - 1]); 3094 | return table; 3095 | } 3096 | t.addSkill = function (skill, skillLevel) { 3097 | var i = t.checkSkill(skill); 3098 | if (! skillLevel) { 3099 | skillLevel = 1; 3100 | } 3101 | if (i >= 0) { 3102 | t.skills[i][1] += skillLevel; 3103 | t.verboseHistory('Improved ' + skill + '-' + t.skills[i][1]); 3104 | } else { 3105 | t.skills.push([skill, skillLevel]); 3106 | t.verboseHistory('Learned ' + skill + '-' + skillLevel); 3107 | } 3108 | }; 3109 | t.improveAttribute = function (attrib, delta) { 3110 | if (! delta) { 3111 | delta = 1; 3112 | } 3113 | t.attributes[attrib] += delta; 3114 | if (t.attributes[attrib] < 1 && attrib == 'social') { 3115 | // Don't let other social reduction take below 1 3116 | t.verboseHistory('Decreased ' + attrib + 3117 | ' below 1, keeping it at 1'); 3118 | t.attributes[attrib] = 1; 3119 | } else { 3120 | if (t.attributes[attrib] < 0) { 3121 | // Don't let reduction take below 0. 3122 | t.attributes[attrib] = 0; 3123 | } 3124 | t.verboseHistory((delta > 0 ? 'Increased ' : 'Decreased ') + 3125 | attrib + ' by ' + delta + ' to ' + 3126 | t.extendedHex(t.attributes[attrib])); 3127 | } 3128 | } 3129 | t.addBenefit = function (benefit) { 3130 | t.benefits.push(benefit); 3131 | t.verboseHistory(benefit); 3132 | } 3133 | t.verboseHistory = function(text) { 3134 | if (t.showHistory == 'verbose' || t.showHistory == 'debug') { 3135 | t.history.push(text); 3136 | } 3137 | } 3138 | t.debugHistory = function(text) { 3139 | if (t.showHistory == 'debug') { 3140 | t.history.push(text); 3141 | } 3142 | } 3143 | t.drafted = false; 3144 | t.minTerms = 1; 3145 | t.maxTerms = 99; 3146 | t.determineService = function() { 3147 | if (t.urlParam('history') == 'verbose') { 3148 | t.showHistory = 'verbose'; 3149 | } else if (t.urlParam('history') == 'debug') { 3150 | t.showHistory = 'debug'; 3151 | } else if (t.urlParam('history') == 'none') { 3152 | t.showHistory = 'none'; 3153 | } 3154 | if (t.urlParam('vehicles') != '') { 3155 | t.vehicles = t.urlParam('vehicles'); 3156 | } 3157 | if (t.urlParam('minterms') != '') { 3158 | t.minTerms = +t.urlParam('minterms'); 3159 | t.debugHistory('Min terms ' + t.minTerms); 3160 | } 3161 | if (t.urlParam('maxterms') != '') { 3162 | t.maxTerms = +t.urlParam('maxterms'); 3163 | t.debugHistory('Max terms ' + t.maxTerms); 3164 | } 3165 | t.verboseHistory('Rolled attributes: ' + t.getAttrString()); 3166 | // In which service should we try to enlist? 3167 | var preferredService; 3168 | var preferredServiceScore; 3169 | var thisService; 3170 | var thisServiceScore; 3171 | var minscore = +t.urlParam('minscore'); 3172 | if (minscore == 0) { 3173 | minscore = 1; 3174 | } 3175 | if (t.urlParam('service') !== '') { 3176 | // preferred service is given in the URL 3177 | preferredService = t.urlParam('service'); 3178 | } else { 3179 | // Initially pick a random service 3180 | preferredService = arnd(s.services); 3181 | } 3182 | if (t.attributes['social'] >= 10) { 3183 | var noble_roll = roll(1); 3184 | if (noble_roll <= 2) { 3185 | preferredService = 'nobles'; 3186 | } 3187 | } 3188 | 3189 | // Compute the initial service pick's DM, if it's less than minscore, 3190 | // bump it to minscore to favor the chosen service. 3191 | preferredServiceScore = s[preferredService].enlistmentDM(t.attributes); 3192 | if (preferredServiceScore < minscore) { 3193 | preferredServiceScore = minscore; 3194 | } 3195 | 3196 | t.debugHistory('Starting with ' + s[preferredService].serviceName + 3197 | ' score ' + preferredServiceScore); 3198 | for (var i = 0, limit = s.services.length; i < limit; i++) { 3199 | thisService = s.services[i]; 3200 | thisServiceScore = s[thisService].enlistmentDM(t.attributes); 3201 | if (thisServiceScore > preferredServiceScore) { 3202 | t.debugHistory('Switching to ' + 3203 | s[thisService].serviceName + ' because score ' + 3204 | thisServiceScore + ' > ' + preferredServiceScore); 3205 | preferredService = thisService; 3206 | preferredServiceScore = thisServiceScore; 3207 | } else if (thisServiceScore == preferredServiceScore) { 3208 | if (roll(2) > 7) { 3209 | t.debugHistory('Switching to ' + 3210 | s[thisService].serviceName + ' because score ' + 3211 | thisServiceScore + ' == ' + 3212 | preferredServiceScore); 3213 | preferredService = thisService; 3214 | preferredServiceScore = thisServiceScore; 3215 | } 3216 | } 3217 | } 3218 | // Now we need to make sure we use the correct service DM 3219 | preferredServiceDM = s[preferredService].enlistmentDM(t.attributes); 3220 | // Attempt to enlist 3221 | var serviceSkills = []; 3222 | var en = roll(2); 3223 | if (minscore == 9999) { 3224 | t.cheat = true; 3225 | t.history.push('Automatic enlistment in ' + 3226 | s[preferredService].serviceName); 3227 | serviceSkills = s[preferredService].getServiceSkills(); 3228 | for (var i = 0, limit = serviceSkills.length; i < limit; i++) { 3229 | t.addSkill(serviceSkills[i]); 3230 | } 3231 | return preferredService; 3232 | } 3233 | t.history.push('Attempted to enlist in ' + s[preferredService].serviceName + '.'); 3234 | t.verboseHistory('Enlistment roll ' + en + ' + ' + preferredServiceDM + ' vs ' + s[preferredService].enlistmentThrow); 3235 | if ((en + preferredServiceDM) >= s[preferredService].enlistmentThrow) { 3236 | t.history.push('Enlistment accepted.'); 3237 | serviceSkills = s[preferredService].getServiceSkills(); 3238 | for (var i = 0, limit = serviceSkills.length; i < limit; i++) { 3239 | t.addSkill(serviceSkills[i]); 3240 | } 3241 | return preferredService; 3242 | } else { 3243 | var draftService; 3244 | t.drafted = true; 3245 | t.history.push('Enlistment denied.'); 3246 | if (minscore == 8888) { 3247 | t.cheat = true; 3248 | draftService = preferredService; 3249 | } else { 3250 | draftService = s.draft(); 3251 | } 3252 | t.history.push('Drafted into ' + draftService + '.'); 3253 | serviceSkills = s[draftService].getServiceSkills(); 3254 | for (var i = 0, limit = serviceSkills.length; i < limit; i++) { 3255 | t.addSkill(serviceSkills[i]); 3256 | } 3257 | return draftService; 3258 | } 3259 | }; 3260 | t.service = t.determineService.call(); 3261 | t.deceased = false; 3262 | t.commissioned = false; 3263 | t.rank = 0; 3264 | t.activeDuty = true; 3265 | t.retired = false; 3266 | t.retirementPay = 0; 3267 | t.doServiceTerm = function () { 3268 | t.terms += 1; 3269 | t.age += 4; 3270 | t.verboseHistory('--------------------------------------------'); 3271 | t.verboseHistory('Term ' + 3272 | t.terms + ' age ' + t.age); 3273 | if (t.service == 'scouts') { 3274 | t.skillPoints += 2; 3275 | } else if (t.service == 'belters') { 3276 | t.skillPoints += 2; 3277 | } else if (t.service == 'doctors') { 3278 | t.skillPoints += 2; 3279 | } else if (t.service == 'rogues') { 3280 | t.skillPoints += 2; 3281 | } else if (t.service == 'scientists') { 3282 | t.skillPoints += 2; 3283 | } else if (t.service == 'hunters') { 3284 | t.skillPoints += 2; 3285 | } else if (t.terms == 1) { 3286 | t.skillPoints += 2; 3287 | } else { 3288 | t.skillPoints += 1; 3289 | } 3290 | // Check commission: 3291 | if (t.drafted && t.terms == 1) { 3292 | t.verboseHistory('Skipping commision because of draft.'); 3293 | } else if (! t.commissioned) { 3294 | if (s[t.service].checkCommission.call(t)) { 3295 | t.commissioned = true; 3296 | t.rank += 1; 3297 | t.skillPoints += 1; 3298 | s[t.service].doPromotion.call(t); 3299 | t.history.push('Commissioned during ' + 3300 | intToOrdinal(t.terms) + ' term of service as ' + 3301 | s[t.service].ranks[t.rank] + '.'); 3302 | } 3303 | } 3304 | // Try for promotion: 3305 | if (t.commissioned && (t.rank < 6)) { 3306 | if (s[t.service].checkPromotion.call(t)) { 3307 | t.rank += 1; 3308 | t.skillPoints += 1; 3309 | s[t.service].doPromotion.call(t); 3310 | t.history.push('Promoted to ' + s[t.service].ranks[t.rank] + '.'); 3311 | } 3312 | } 3313 | for (var i = 0, limit = t.skillPoints; i < limit; i++) { 3314 | s[t.service].acquireSkill.call(t); 3315 | t.skillPoints -= 1; 3316 | } 3317 | // Check survival: 3318 | if (! s[t.service].checkSurvival.call(t)) { 3319 | t.history.push('Death in service.'); 3320 | t.deceased = true; 3321 | t.activeDuty = false; 3322 | } 3323 | }; 3324 | t.musterStrategy = ''; 3325 | t.found = false; 3326 | t.musterOut = function () { 3327 | // What cash and non-cash benefits do we get when mustering out? 3328 | var cashDM = 0; 3329 | var benefitsDM = 0; 3330 | var musterRolls = t.terms; 3331 | var maxCash = 3; 3332 | var cashUsed = 0; 3333 | var looking = false; 3334 | var found = false; 3335 | t.musterStrategy = t.urlParam('muster'); 3336 | if (t.urlParam('maxcash') !== '') { 3337 | maxCash = t.urlParam('maxcash'); 3338 | if (maxCash > 3) { 3339 | t.cheat |= true; 3340 | } 3341 | } 3342 | t.verboseHistory('--------------------------------------------'); 3343 | t.verboseHistory('Mustered Out'); 3344 | if ((t.rank == 1) || (t.rank == 2)) { 3345 | musterRolls += 1; 3346 | } else if ((t.rank == 3) || (t.rank == 4)) { 3347 | musterRolls += 2; 3348 | } else if (t.rank >= 5) { 3349 | benefitsDM += 1; 3350 | musterRolls += 3; 3351 | } 3352 | if (t.checkSkill('Gambling') >= 0) { 3353 | cashDM += 1; 3354 | } 3355 | if (t.musterStrategy != '') { 3356 | looking = s[t.service].canMuster(t.musterStrategy) || 3357 | t.musterStrategy == 'split'; 3358 | } 3359 | for (var i = 1, limit = musterRolls; i <= limit; i++) { 3360 | if (cashUsed < maxCash && (!looking || t.found || found || 3361 | (t.musterStrategy == 'split' && (i % 2) == 1))) { 3362 | var cash = s[t.service].musterCash[roll(1) + cashDM] 3363 | t.credits += cash; 3364 | t.verboseHistory(numCommaSep(cash) + ' credits'); 3365 | cashUsed += 1; 3366 | } else { 3367 | s[t.service].musterBenefits.call(t, benefitsDM); 3368 | if (t.hunt == 'special') { 3369 | t.found = t.ship | t.TAS; 3370 | } else if (t.hunt == 'ship') { 3371 | t.found = t.ship; 3372 | } else if (t.hunt == 'TAS') { 3373 | t.found = t.TAS; 3374 | } 3375 | if (t.musterStrategy == 'special') { 3376 | found = t.ship | t.TAS; 3377 | } else if (t.musterStrategy == 'ship') { 3378 | found = t.ship; 3379 | } else if (t.musterStrategy == 'TAS') { 3380 | found = t.TAS; 3381 | } 3382 | } 3383 | } 3384 | // Figure annual retirement pay: 3385 | if (t.terms >= 5 && t.service !== 'scouts' && t.service !== 'other') { 3386 | switch(t.terms) { 3387 | case 5: 3388 | t.retirementPay = 4000; 3389 | break; 3390 | case 6: 3391 | t.retirementPay = 6000; 3392 | break; 3393 | case 7: 3394 | t.retirementPay = 8000; 3395 | break; 3396 | case 8: 3397 | t.retirementPay = 10000; 3398 | break; 3399 | case 9: 3400 | t.retirementPay = 12000; 3401 | break; 3402 | default: 3403 | t.retirementPay = ((t.terms - 9) * 2000) + 12000; 3404 | } 3405 | t.benefits.push(numCommaSep(t.retirementPay) + '/yr Retirement Pay'); 3406 | } 3407 | }; 3408 | t.doReenlistment = function () { 3409 | var reenlistRoll = roll(2); 3410 | t.verboseHistory('Reenlistment roll ' + reenlistRoll + ' vs ' + 3411 | s[t.service].reenlistThrow); 3412 | if (t.terms == t.maxTerms) { 3413 | t.history.push('Reached selected maximum number of terms, skipping re-enlistment'); 3414 | t.activeDuty = false; 3415 | } else if (reenlistRoll == 12) { 3416 | t.history.push('Mandatory reenlistment for ' + 3417 | intToOrdinal(t.terms + 1) + ' term.'); 3418 | } else if (t.terms >= 7) { 3419 | t.activeDuty = false; 3420 | t.history.push('Mandatory retirement after ' + 3421 | intToOrdinal(t.terms) + ' term.'); 3422 | } else if (reenlistRoll < s[t.service].reenlistThrow) { 3423 | t.activeDuty = false; 3424 | t.history.push('Denied reenlistment after ' + 3425 | intToOrdinal(t.terms) + ' term.'); 3426 | } else if (t.terms >= t.minTerms && roll(2) >= 10 && 3427 | (t.hunt !== 'skill' || t.found)) { 3428 | if (t.terms < 5) { 3429 | t.activeDuty = false; 3430 | t.history.push('Chose not to reenlist after ' + 3431 | intToOrdinal(t.terms) + ' term.'); 3432 | } else { 3433 | t.activeDuty = false; 3434 | t.retired = true; 3435 | t.history.push('Retired after ' + 3436 | intToOrdinal(t.terms) + ' term.'); 3437 | } 3438 | } else { 3439 | t.history.push('Voluntarily reenlisted for ' + 3440 | intToOrdinal(t.terms + 1) + ' term.'); 3441 | } 3442 | }; 3443 | t.ageAttribute = function(attrib, req, reduction) { 3444 | var agingRoll = roll(2); 3445 | t.verboseHistory('Aging ' + attrib + ' throw ' + agingRoll + ' vs ' + req); 3446 | if (agingRoll < req) { 3447 | t.improveAttribute(attrib, reduction); 3448 | } 3449 | } 3450 | t.doAging = function () { 3451 | // Age-related attribute loss? 3452 | if (t.age < 34) { 3453 | return; 3454 | } else if (t.age <= 46) { 3455 | t.ageAttribute('strength', 8, -1); 3456 | t.ageAttribute('dexterity', 7, -1); 3457 | t.ageAttribute('endurance', 8, -1); 3458 | } else if (t.age <= 62) { 3459 | t.ageAttribute('strength', 9, -1); 3460 | t.ageAttribute('dexterity', 8, -1); 3461 | t.ageAttribute('endurance', 9, -1); 3462 | } else { 3463 | t.ageAttribute('strength', 9, -2); 3464 | t.ageAttribute('dexterity', 9, -2); 3465 | t.ageAttribute('endurance', 9, -2); 3466 | t.ageAttribute('intelligence', 9, -1); 3467 | } 3468 | // Aging crisis? 3469 | for (var a in t.attributes) { 3470 | if (t.attributes[a] < 1) { 3471 | var cr = roll(2); 3472 | t.verboseHistory('Aging crisis due to ' + a + 3473 | ' dropping below 1 roll ' + cr + ' vs 8'); 3474 | if (cr < 8) { 3475 | t.history.push("Died of illness."); 3476 | t.deceased = true; 3477 | t.activeDuty = false; 3478 | } else { 3479 | t.attributes[a] = 1; 3480 | } 3481 | } 3482 | } 3483 | }; 3484 | t.getNobleTitle = function () { 3485 | switch (t.attributes.social) { 3486 | case 11: 3487 | if (t.gender == 'female') { 3488 | return 'Dame'; 3489 | } else { 3490 | return 'Sir'; 3491 | } 3492 | break; 3493 | case 12: 3494 | if (t.gender == 'female') { 3495 | return 'Baroness'; 3496 | } else { 3497 | return 'Baron'; 3498 | } 3499 | break; 3500 | case 13: 3501 | if (t.gender == 'female') { 3502 | return 'Marchioness'; 3503 | } else { 3504 | return 'Marquis'; 3505 | } 3506 | break; 3507 | case 14: 3508 | if (t.gender == 'female') { 3509 | return 'Countess'; 3510 | } else { 3511 | return 'Count'; 3512 | } 3513 | break; 3514 | case 15: 3515 | if (t.gender == 'female') { 3516 | return 'Duchess'; 3517 | } else { 3518 | return 'Duke'; 3519 | } 3520 | break; 3521 | default: 3522 | return ''; 3523 | } 3524 | }; 3525 | t.toStringFail = function () { 3526 | return (function() { 3527 | return 'Failed to generate after ' + t.maxchars + ' attempts\n'; 3528 | }).call(this); 3529 | }; 3530 | t.toString = function () { 3531 | return (function() { 3532 | var parms = t.urlParams(); 3533 | if (t.cheat || t.showHistory == 'debug') { 3534 | return 'URL Parms: ' + parms + '\n\n'; 3535 | } else { 3536 | return ''; 3537 | } 3538 | }).call(this) + 3539 | (function() { 3540 | if (this.deceased) { 3541 | return '† '; 3542 | } else { 3543 | return ''; 3544 | } 3545 | }).call(this) + 3546 | (function () { 3547 | if (this.service == 'other') { return ''; } 3548 | return s[this.service].memberName + ' '; 3549 | }).call(this) + 3550 | (function () { 3551 | if (s[this.service].ranks[this.rank] !== '') { 3552 | return s[this.service].ranks[this.rank] + ' '; 3553 | } else { 3554 | return ''; 3555 | } 3556 | }).call(this) + 3557 | (function () { 3558 | if (this.attributes.social > 10) { 3559 | return this.getNobleTitle() + ' '; 3560 | } else { 3561 | return ''; 3562 | } 3563 | }).call(this) + 3564 | this.name + 3565 | ' ' + this.getAttrString() + ' Age ' + this.age + "\n" + 3566 | (function () { 3567 | if (this.terms == 1) { 3568 | return this.terms + ' term'; 3569 | } else { 3570 | return this.terms + ' terms'; 3571 | } 3572 | }).call(this) + 3573 | (function () { 3574 | if (! this.deceased) { 3575 | return " Cr" + numCommaSep(this.credits); 3576 | } else { 3577 | return ''; 3578 | } 3579 | }).call(this) + "\n" + 3580 | (function () { 3581 | if ((t.skills.length < 1) || (t.deceased)) { return ''; } 3582 | var skills = []; 3583 | for (var i = 0, limit = t.skills.length; i < limit; i++) { 3584 | skills.push(t.skills[i][0] + '-' + t.skills[i][1]); 3585 | } 3586 | skills.sort(); 3587 | var skillString = "\nSkills: "; 3588 | for (var i = 0, limit = skills.length; i < limit; i++) { 3589 | skillString += skills[i]; 3590 | if (i !== limit - 1) { 3591 | skillString += ', '; 3592 | } 3593 | } 3594 | return skillString + "\n"; 3595 | }).call(this) + 3596 | (function () { 3597 | if (this.benefits.length > 0) { 3598 | this.benefits.sort(); 3599 | var benefits = "\nBenefits: "; 3600 | for (var i = 0, limit = this.benefits.length; i < limit; i++) { 3601 | benefits += this.benefits[i]; 3602 | if (this.benefits[i] == 'Free Trader') { 3603 | if (this.mortgage == 0) { 3604 | benefits += ' (paid off - 40 years old)'; 3605 | } else if (this.mortgage == 40) { 3606 | benefits += ' (new with a 40 year mortgage)'; 3607 | } else { 3608 | benefits += ' (' + (40 - this.mortgage) + 3609 | ' years old, ' + this.mortgage + 3610 | ' years mortgage remaining)'; 3611 | } 3612 | } 3613 | if (i < limit - 1) { 3614 | benefits += ', '; 3615 | } else { 3616 | benefits += "\n"; 3617 | } 3618 | } 3619 | return benefits; 3620 | } else { return ''; } 3621 | }).call(this) + 3622 | (function () { 3623 | if (this.showHistory == 'none') { 3624 | return ""; 3625 | } 3626 | var history = "Service History:\n"; 3627 | for (var i = 0, limit = this.history.length; i < limit; i++) { 3628 | history = history + this.history[i] + "\n"; 3629 | } 3630 | return "\n" + history; 3631 | }).call(this) 3632 | ; 3633 | }; 3634 | t.numresets = 0; 3635 | t.reset = function() { 3636 | t.numresets += 1; 3637 | t.history = []; 3638 | if (t.ship) { 3639 | t.ships2 += 1; 3640 | } 3641 | t.history.push('Number of resets ' + t.numresets); 3642 | t.age = 18; 3643 | t.gender = generateGender(); 3644 | t.name = generateName(t.gender); 3645 | t.terms = 0; 3646 | t.credits = 0; 3647 | t.benefits = []; 3648 | t.ship = false; 3649 | t.TAS = false; 3650 | t.mortgage = 40; 3651 | t.bladeBenefit = ''; 3652 | t.gunBenefit = ''; 3653 | t.attributes.strength = roll(2); 3654 | t.attributes.dexterity = roll(2); 3655 | t.attributes.endurance = roll(2); 3656 | t.attributes.intelligence = roll(2); 3657 | t.attributes.education = roll(2); 3658 | t.attributes.social = roll(2); 3659 | t.skillPoints = 0; 3660 | t.skills = []; 3661 | t.drafted = false; 3662 | t.service = t.determineService(); 3663 | t.deceased = false; 3664 | t.commissioned = false; 3665 | t.rank = 0; 3666 | t.activeDuty = true; 3667 | t.retired = false; 3668 | t.retirementPay = 0; 3669 | } 3670 | 3671 | t.hunt = t.urlParam('hunt'); 3672 | t.failed = false; 3673 | t.string = ''; 3674 | t.maxchars = 10000; 3675 | 3676 | if (t.urlParam('maxchars') != '') { 3677 | t.maxchars = +t.urlParam('maxchars'); 3678 | } 3679 | 3680 | while (t.activeDuty && (! t.deceased)) { 3681 | if (t.service == 'nobles') { 3682 | if (t.attributes['social'] < 10) { 3683 | t.attributes['social'] = 10; 3684 | } 3685 | if (t.attributes['social'] == 11) { 3686 | t.rank = 1; 3687 | } 3688 | if (t.attributes['social'] == 12) { 3689 | t.rank = 2; 3690 | } 3691 | } 3692 | t.doServiceTerm(); 3693 | t.doAging(); 3694 | if (! t.deceased) { 3695 | if (t.hunt == 'skill') { 3696 | var level = 1; 3697 | var skill = t.urlParam('skill'); 3698 | if (t.urlParam('level') !== '') { 3699 | level = t.urlParam('level'); 3700 | } 3701 | t.found = t.checkSkillLevel(skill, level); 3702 | t.debugHistory('Hunting for ' + skill + '-' + level + 3703 | (t.found ? '' : ' not') + ' found'); 3704 | } 3705 | t.doReenlistment(); 3706 | } else { 3707 | t.found = false; 3708 | if (t.minTerms > 1) { 3709 | // don't keep this one if looking for min terms 3710 | t.terms = 0; 3711 | } 3712 | } 3713 | if (!t.activeDuty && !t.deceased) { 3714 | t.musterOut(); 3715 | } 3716 | if (!t.activeDuty) { 3717 | if (t.numresets >= t.maxchars) { 3718 | t.failed = true; 3719 | break; 3720 | } 3721 | if (t.terms < t.minTerms || t.urlParam('hunt') !== '' && !t.found) { 3722 | t.verboseHistory('Resetting'); 3723 | t.reset(); 3724 | t.cheat = true; 3725 | } 3726 | } 3727 | } 3728 | 3729 | if (!t.failed) { 3730 | console.log(t.toString()); 3731 | return t.toString(); 3732 | } else { 3733 | console.log(t.toStringFail()); 3734 | return t.toStringFail(); 3735 | } 3736 | 3737 | } // End wrapper function travellerCharacterGenerator() 3738 | --------------------------------------------------------------------------------