lib/vhyl-rpg-expanded-characters.t

Reference index ยท View on GitHub

   1  /* Include after the expanded foundation. Source: full-2008, B14-B17. */
   2  
   3  /** Individual point components; negative entries count separately toward limits. */
   4  rpgExpandedCharacterAmounts(profile)
   5  {
   6      rpgExpandedValidate(profile);
   7      local amounts = [(profile.st - 10) * 10, (profile.dx - 10) * 20,
   8          (profile.iq - 10) * 20, (profile.ht - 10) * 10,
   9          (profile.techLevel - profile.campaignTL) * 5,
  10          profile.hpAdjustment * 2, profile.fpAdjustment * 3,
  11          profile.willAdjustment * 5, profile.perceptionAdjustment * 5,
  12          profile.speedQuarterAdjustment * 5, profile.moveAdjustment * 5];
  13      foreach (local trait in profile.traits) amounts = amounts + [trait.creationCost()];
  14      foreach (local language in profile.languages) amounts = amounts + [language.cost()];
  15      foreach (local training in profile.skills) amounts = amounts + [training.points];
  16      foreach (local contribution in profile.contributions)
  17          amounts = amounts + contribution.amounts(profile);
  18      return amounts;
  19  }
  20  
  21  /** Total creation cost or the sum of negative components, without changing state. */
  22  rpgExpandedCharacterCost(profile, negativeOnly)
  23  {
  24      local total = 0;
  25      foreach (local amount in rpgExpandedCharacterAmounts(profile))
  26      {
  27          rpgInteger(amount, -1000000, 1000000);
  28          if (!negativeOnly || amount < 0) total += amount;
  29      }
  30      return total;
  31  }
  32  
  33  /** Validate purchased secondary characteristics and budgets.
  34   * Exceptional limits are explicit. Catalogue-specific compatibility is separate. */
  35  rpgExpandedValidateCharacter(profile)
  36  {
  37      rpgExpandedValidate(profile);
  38      foreach (local score in [profile.st, profile.dx, profile.iq, profile.ht,
  39          profile.maxHP, profile.maxEnergy, profile.will, profile.perception])
  40          rpgInteger(score, 1, 1000);
  41      foreach (local offset in [profile.hpAdjustment, profile.fpAdjustment,
  42          profile.willAdjustment, profile.perceptionAdjustment,
  43          profile.speedQuarterAdjustment, profile.moveAdjustment])
  44          rpgInteger(offset, -1000, 1000);
  45      rpgInteger(profile.basicSpeedQuarters(), 0, 4000);
  46      rpgInteger(profile.basicMove(), 0, 1000);
  47      rpgInteger(profile.techLevel, 0, 12); rpgInteger(profile.campaignTL, 0, 12);
  48      rpgInteger(profile.pointBudget, 0, 1000000);
  49      rpgInteger(profile.disadvantageLimit, 0, 1000000);
  50      if (!profile.rules.exceptionalCharacteristics)
  51      {
  52          if (profile.hpAdjustment * 10 > profile.st * 3
  53              || profile.hpAdjustment * 10 < -profile.st * 3
  54              || profile.fpAdjustment * 10 > profile.ht * 3
  55              || profile.fpAdjustment * 10 < -profile.ht * 3
  56              || profile.will > 20 || profile.willAdjustment < -4
  57              || profile.perception > 20 || profile.perceptionAdjustment < -4
  58              || profile.speedQuarterAdjustment < -8 || profile.speedQuarterAdjustment > 8
  59              || profile.moveAdjustment < -3 || profile.moveAdjustment > 3)
  60              rpgExpandedReject('secondary-limit');
  61      }
  62      try { rpgLiteValidateTraits(profile); rpgLiteValidateLanguages(profile); }
  63      catch (RpgLiteCharacterError error) { rpgExpandedReject(error.reason); }
  64      local skills = [];
  65      foreach (local training in profile.skills)
  66      {
  67          if (training == nil || !training.ofKind(RpgTraining) || training.skill == nil
  68              || !training.skill.ofKind(RpgSkill) || holds(skills, training.skill)) rpgExpandedReject('duplicate-training');
  69          skills = skills + [training.skill]; rpgInteger(training.points, 0, 1000000);
  70          if (training.points > 0)
  71          {
  72              local reason = profile.skillLearningReason(training.skill);
  73              if (reason != nil) rpgExpandedReject(reason);
  74          }
  75      }
  76      if (rpgExpandedCharacterCost(profile, nil) > profile.pointBudget
  77          || -rpgExpandedCharacterCost(profile, true) > profile.disadvantageLimit)
  78          rpgExpandedReject('point-budget');
  79      return true;
  80  }
  81  
  82  modify RpgExpandedProfile
  83      /** Creation exchanges burn unused budget; they do not add trait value. */
  84      creationMoneyReason(points)
  85      {
  86          rpgExpandedValidateCharacter(self);
  87          return points > self.pointBudget || self.pointBudget - rpgExpandedCharacterCost(self,nil) < points
  88              ? 'money-exchange-points' : nil;
  89      }
  90  ;