lib/vhyl-rpg-lite-catalogue.t

Reference index ยท View on GitHub

   1  /** Numeric trait, skill, armor and shield catalogue from Lite; factories create independent owned objects. */
   2  rpgLiteCatalogue: object
   3      traits = [
   4          ['acute-hearing', 2, 100, nil], ['acute-vision', 2, 100, nil],
   5          ['acute-touch', 2, 100, nil], ['acute-taste-smell', 2, 100, nil],
   6          ['ambidexterity', 5, 1, nil], ['animal-empathy', 5, 1, nil],
   7          ['catfall', 10, 1, nil], ['combat-reflexes', 15, 1, nil],
   8          ['danger-sense', 15, 1, nil], ['daredevil', 15, 1, nil],
   9          ['empathy', 15, 1, nil], ['enhanced-block', 5, 1, nil],
  10          ['enhanced-dodge', 15, 1, nil], ['enhanced-parry', 5, 1, nil],
  11          ['enhanced-parry-all', 10, 1, nil], ['fearlessness', 2, 100, nil],
  12          ['flexibility', 5, 1, nil], ['double-jointed', 15, 1, nil],
  13          ['hard-to-kill', 2, 100, nil], ['high-pain-threshold', 10, 1, nil],
  14          ['jumper-time', 100, 1, nil], ['jumper-world', 100, 1, nil],
  15          ['language-talent', 10, 1, nil], ['luck', 15, 1, nil],
  16          ['extraordinary-luck', 30, 1, nil], ['ridiculous-luck', 60, 1, nil],
  17          ['night-vision', 1, 9, nil], ['perfect-balance', 15, 1, nil],
  18          ['resistant-disease-3', 3, 1, nil], ['resistant-disease-8', 5, 1, nil],
  19          ['resistant-poison-3', 5, 1, nil], ['artificer', 10, 4, nil],
  20          ['outdoorsman', 10, 4, nil], ['smooth-operator', 15, 4, nil],
  21          ['bad-sight-correctable', -10, 1, nil], ['bad-sight', -25, 1, nil],
  22          ['bad-temper', -10, 1, true], ['bloodlust', -10, 1, true],
  23          ['code-of-honor', -5, 3, nil], ['curious', -5, 1, true],
  24          ['delusions', -5, 3, nil], ['gluttony', -5, 1, true],
  25          ['greed', -15, 1, true], ['hard-of-hearing', -10, 1, nil],
  26          ['honesty', -10, 1, true], ['impulsiveness', -10, 1, true],
  27          ['intolerance', -1, 10, nil], ['jealousy', -10, 1, nil],
  28          ['lecherousness', -15, 1, true], ['obsession', -5, 2, true],
  29          ['overconfidence', -5, 1, true], ['reluctant-killer', -5, 1, nil],
  30          ['cannot-harm-innocents', -10, 1, nil], ['phobia-blood', -10, 1, true],
  31          ['phobia-darkness', -15, 1, true], ['phobia-heights', -10, 1, true],
  32          ['phobia-thirteen', -5, 1, true], ['phobia-spiders', -5, 1, true],
  33          ['duty-individual', -2, 1, nil], ['duty-small-group', -5, 1, nil],
  34          ['duty-large-group', -10, 1, nil], ['duty-race', -15, 1, nil],
  35          ['duty-all-life', -20, 1, nil], ['truthfulness', -5, 1, true],
  36          ['unluckiness', -10, 1, nil], ['vow', -5, 3, nil], ['quirk', -1, 1, nil],
  37          ['hideous', -16, 1, nil], ['ugly', -8, 1, nil], ['unattractive', -4, 1, nil],
  38          ['attractive', 4, 1, nil], ['handsome', 12, 1, nil], ['very-handsome', 16, 1, nil],
  39          ['charisma', 5, 100, nil], ['voice', 10, 1, nil], ['odious-habits', -5, 3, nil],
  40          ['status', 5, 8, nil], ['low-status', -5, 2, nil],
  41          ['reputation', 5, 4, nil], ['bad-reputation', -5, 4, nil],
  42          ['dead-broke', -25, 1, nil], ['poor', -15, 1, nil], ['struggling', -10, 1, nil],
  43          ['comfortable', 10, 1, nil], ['wealthy', 20, 1, nil],
  44          ['very-wealthy', 30, 1, nil], ['filthy-rich', 50, 1, nil]
  45      ]
  46      skills = [
  47          ['acrobatics', rpgDX, 2, -6, nil], ['acting', rpgIQ, 1, -5, nil],
  48          ['animal-handling', rpgIQ, 1, -5, nil], ['area-knowledge', rpgIQ, 0, -4, nil],
  49          ['armoury', rpgIQ, 1, -5, true], ['brawling', rpgDX, 0, nil, nil],
  50          ['camouflage', rpgIQ, 0, -4, nil], ['carousing', rpgHT, 0, -4, nil],
  51          ['climbing', rpgDX, 1, -5, nil], ['computer-operation', rpgIQ, 0, -4, true],
  52          ['computer-programming', rpgIQ, 2, nil, true], ['crewman', rpgIQ, 0, -4, true],
  53          ['criminology', rpgIQ, 1, -5, true], ['diagnosis', rpgIQ, 2, -6, true],
  54          ['disguise', rpgIQ, 1, -5, true], ['electronics-operation', rpgIQ, 1, -5, true],
  55          ['electronics-repair', rpgIQ, 1, -5, true], ['engineer', rpgIQ, 2, nil, true],
  56          ['environment-suit', rpgDX, 1, -5, true], ['escape', rpgDX, 2, -6, nil],
  57          ['explosives', rpgIQ, 1, -5, true], ['first-aid', rpgIQ, 0, -4, true],
  58          ['forgery', rpgIQ, 2, -6, true], ['gambling', rpgIQ, 1, -5, nil],
  59          ['hiking', rpgHT, 1, -5, nil], ['holdout', rpgIQ, 1, -5, nil],
  60          ['humanities', rpgIQ, 2, -6, nil], ['diplomacy', rpgIQ, 2, -6, nil],
  61          ['fast-talk', rpgIQ, 1, -5, nil], ['intimidation', rpgIQ, 1, -5, nil],
  62          ['savoir-faire', rpgIQ, 0, -4, nil], ['sex-appeal', rpgHT, 1, -3, nil],
  63          ['streetwise', rpgIQ, 1, -5, nil], ['interrogation', rpgIQ, 1, -5, nil],
  64          ['jumping', rpgDX, 0, nil, nil], ['karate', rpgDX, 2, nil, nil],
  65          ['law', rpgIQ, 2, -6, nil], ['leadership', rpgIQ, 1, -5, nil],
  66          ['lockpicking', rpgIQ, 1, -5, true], ['mathematics', rpgIQ, 2, -6, true],
  67          ['mechanic', rpgIQ, 1, -5, true], ['rapier', rpgDX, 1, -5, nil],
  68          ['smallsword', rpgDX, 1, -5, nil], ['flail', rpgDX, 2, -6, nil],
  69          ['axe-mace', rpgDX, 1, -5, nil], ['polearm', rpgDX, 1, -5, nil],
  70          ['spear', rpgDX, 1, -5, nil], ['staff', rpgDX, 1, -5, nil],
  71          ['broadsword', rpgDX, 1, -5, nil], ['knife', rpgDX, 0, -4, nil],
  72          ['shortsword', rpgDX, 1, -5, nil], ['two-handed-sword', rpgDX, 1, -5, nil],
  73          ['merchant', rpgIQ, 1, -5, nil], ['gunner', rpgDX, 0, -4, true],
  74          ['guns', rpgDX, 0, -4, true], ['flamethrower', rpgDX, 0, -4, nil],
  75          ['blowpipe', rpgDX, 2, -6, nil], ['bow', rpgDX, 1, -5, nil],
  76          ['crossbow', rpgDX, 0, -4, nil], ['natural-sciences', rpgIQ, 2, -6, true],
  77          ['naturalist', rpgIQ, 2, -6, nil], ['navigation', rpgIQ, 1, -5, true],
  78          ['observation', rpgIQ, 1, -5, nil], ['occultism', rpgIQ, 1, -5, nil],
  79          ['photography', rpgIQ, 1, -5, true], ['physician', rpgIQ, 2, -7, true],
  80          ['pickpocket', rpgDX, 2, -6, nil], ['public-speaking', rpgIQ, 1, -5, nil],
  81          ['research', rpgIQ, 1, -5, true], ['riding', rpgDX, 1, -5, nil],
  82          ['scrounging', rpgIQ, 0, -4, nil], ['search', rpgIQ, 1, -5, nil],
  83          ['shadowing', rpgIQ, 1, -5, nil], ['shield', rpgDX, 0, -4, nil],
  84          ['social-sciences', rpgIQ, 2, -6, nil], ['smuggling', rpgIQ, 1, -5, nil],
  85          ['stealth', rpgDX, 1, -5, nil], ['survival', rpgIQ, 1, -5, nil],
  86          ['swimming', rpgHT, 0, -4, nil], ['tactics', rpgIQ, 2, -6, nil],
  87          ['throwing', rpgDX, 1, -3, nil], ['thrown-weapon', rpgDX, 0, -4, nil],
  88          ['tracking', rpgIQ, 1, -5, nil], ['traps', rpgIQ, 1, -5, true],
  89          ['bicycling', rpgDX, 0, -4, nil], ['boating', rpgDX, 1, -5, nil],
  90          ['driving', rpgDX, 1, -5, nil], ['piloting', rpgDX, 1, -5, nil],
  91          ['submarine', rpgDX, 1, -5, nil], ['writing', rpgIQ, 1, -5, nil]
  92      ]
  93      armor = [
  94          ['cloth', 1, 150, 1200], ['leather', 2, 340, 1950], ['light-scale', 3, 610, 4900],
  95          ['mail', 4, 645, 5800], ['steel-laminate', 5, 1360, 6400], ['plate', 6, 4040, 8950],
  96          ['flak-jacket', 7, 500, 2000], ['ballistic-vest', 8, 400, 200], ['tactical-vest', 12, 900, 900]
  97      ]
  98      shields = [['small-shield', 1, 40, 800], ['medium-shield', 2, 60, 1500], ['large-shield', 3, 90, 2500]]
  99  ;
 100  
 101  /** Create a catalogue trait at a legal level and authored scope; unknown IDs throw. */
 102  rpgLiteMakeTrait(id, level, scope)
 103  {
 104      foreach (local row in rpgLiteCatalogue.traits)
 105          if (row[1] == id)
 106          {
 107              rpgInteger(level, 1, row[3]);
 108              local trait = new RpgLiteTrait(); trait.id = id; trait.labelId = id;
 109              trait.points = row[2]; trait.level = level; trait.controlled = row[4]; trait.scope = scope;
 110              return trait;
 111          }
 112      throw new RpgError();
 113  }
 114  
 115  /** Create a catalogue skill. Supply TL only for technological skills and a specialty where appropriate. */
 116  rpgLiteMakeSkill(id, techLevel, specialty)
 117  {
 118      foreach (local row in rpgLiteCatalogue.skills)
 119          if (row[1] == id)
 120          {
 121              if (row[5]) rpgInteger(techLevel, 0, 12);
 122              else if (techLevel != nil) throw new RpgError();
 123              local skill = new RpgLiteSkill(); skill.id = id; skill.labelId = id;
 124              skill.attribute = row[2]; skill.difficulty = row[3]; skill.defaultPenalty = row[4];
 125              skill.techLevel = techLevel; skill.specialty = specialty;
 126              skill.influence = holds(['diplomacy', 'fast-talk', 'intimidation', 'savoir-faire', 'sex-appeal', 'streetwise'], id);
 127              skill.voice = skill.influence || holds(['acting', 'public-speaking', 'leadership'], id);
 128              if (holds(['driving', 'piloting', 'submarine'], id)) skill.alternateAttribute = rpgIQ;
 129              return skill;
 130          }
 131      throw new RpgError();
 132  }
 133  
 134  /** Find the matching owned skill or create a default-only skill with the requested identity. */
 135  rpgLiteTraining(profile, id, techLevel, specialty)
 136  {
 137      foreach (local training in profile.skills)
 138          if (training.skill.ofKind(RpgLiteSkill) && training.skill.id == id
 139              && training.skill.techLevel == techLevel && training.skill.specialty == specialty) return training.skill;
 140      return rpgLiteMakeSkill(id, techLevel, specialty);
 141  }
 142  
 143  /** Calculate TL and wealth-adjusted starting money; mobile selects the full rather than 20% allowance. */
 144  rpgLiteStartingWealth(profile, mobile)
 145  {
 146      local amounts = [250, 500, 750, 1000, 2000, 5000, 10000, 15000, 20000, 30000, 50000, 75000, 100000];
 147      local amount = amounts[profile.campaignTL + 1];
 148      if (profile.level('dead-broke') > 0) return 0;
 149      if (profile.level('poor') > 0) amount /= 5;
 150      if (profile.level('struggling') > 0) amount /= 2;
 151      if (profile.level('comfortable') > 0) amount *= 2;
 152      if (profile.level('wealthy') > 0) amount *= 5;
 153      if (profile.level('very-wealthy') > 0) amount *= 20;
 154      if (profile.level('filthy-rich') > 0) amount *= 100;
 155      return mobile ? amount : amount / 5;
 156  }