Ivory Siege Tower

mobile construct built of thoughts and parentheses

FTL:Nomad Generators

nomad project scifi st_ftl_nomad_generators ttrpg

§ Character Generator

Random generation of SciFi ttRPG characters according to the FTL: Nomad ruleset.


§ Scripting the Generator Engine with Parenscript

It turns out that I'm way more skillful with Lisp than JavaScript, so that even using a translator feels more straightforward. And faster.

Aiming to make resulting statblocks compatible with Markdown.

Declaring Common Lisp package that uses Parenscript:

  (ql:quickload "parenscript")

  (defpackage :nomad (:use :cl :parenscript))

  (in-package :nomad)

§ Defining Setting Constants

Definitions of lists and tables for Species, Archetypes etc.

Playable Species and their feats:

  (in-package :nomad)

  (defpsmacro gen-var-species ()
    `(defvar *species*
       '(("human"
          "Humans are default species of the setting, skillful and talented.")
         ("insectoid"
          "Giant insectoid life form.<br>
  Males get +1D on Stealth rolls to sneak in dim light or darkness.<br>
  Females may fly up to Near range in any direction in one combat round,
  but their wings must rest for another combat round before flying again.<br>
  All insectoids gain +1D to resist poison and disease.")
         ("gekkonid"
          "An alien species that evolved from gecko-like ancestors.<br>
  They can climb walls and walk on ceilings as if walking on solid and horizontal ground.<br>
  They also have keen night vision and take no penalties to any actions performed in dim light.")
         ("gray"
          "These are the archetypal UFO pilots engaged in scientific research, including the abduction of humans as test subjects.<br>
  Grays gain two free Psionic powers of the player’s choice, cumulative with the two Psionic powers granted by the Mystic Archetype, if applicable.<br>
  Grays suffer -1D to all Combat rolls in melee combat.")
         ("reptilian"
          "Reptilians are proud and brutal warrior species that evolved from carnivorous lizards.<br>
  Their unarmed attacks cause 2d6 damage. A reptilian with Martial Artist Archetype cause 3d6 damage while unarmed."))))

Ranks that are conceptually levels of experience:

  (defpsmacro gen-var-ranks ()
    `(defvar *ranks*
       '(("experienced" 0)
         ("expert" 1)
         ("veteran" 2)
         ("elite" 3)
         ("legendary" 4))))

Raise types for each new rank gain:

  (defpsmacro gen-var-raises ()
    `(defvar *raises*
       '("talent"
         "skill"
         "psionic"
         "archetype")))

Describe the order of skills in e.g. statblock:

  (defpsmacro gen-var-skills-order ()
    `(defvar *skills-order*
       '("combat" "knowledge" "physical" "social" "stealth" "vehicles" "technology")))

§ Talents

Talents represent special abilities that a given character has that would differentiate them from their colleagues.

Talent descriptions are hidden to save some space. One can find them in the rulebook on page 19.

§ Professional and Character Talents

  (defpsmacro gen-var-talents ()
    `(defvar *talents*
       '("Ambidextrous"
         "Awareness"
         "Beast Friendsip"
         "Big Mouth"
         "Charming"
         "Deduction"
         "Determined"
         "Eidetic Memory"
         "Empath"
         "Endurance"
         "Pet"
         "Immunity"
         "Infuriating"
         "Ingenious"
         "Insightful"
         "Inspiring"
         "Intimidating"
         "Mighty"
         "Runner"
         "Status"
       
         "Ace Pilot"
         "Acrobat"
         "Animal Handling"
         "Broker"
         "Commando"
         "Con Artist"
         "Contortionism"
         "Demolitions Expert"
         "Detective"
         "Drone Operator"
         "Gambler"
         "Ghost"
         "Hacker"
         "Intelligence Analyst"
         "Logistics Expert"
         "Medic"
         "Professional"
         "Rigger"
         "Scholar"
         "Spacer"
         "Streetwise"
         "Street Thief"
         "Survivalist"
         "Tech Specialist"
         "Tinker"
         "Untraceable")))

§ Combat Talents

  (defpsmacro gen-var-combat-talents ()
    `(defvar *combat-talents*
       '("Armor Training"
         "Artillery"
         "Assault"
         "Berserker"
         "Blind Fighter"
         "Bodyguard"
         "Evasive Action"
         "Hardy"
         "Heavy Hitter"
         "Hunter"
         "Leader"
         "Marksman"
         "Martial Artist"
         "Maverick"
         "Quick Draw"
         "Relentless"
         "Sneak Attack"
         "Tactics"
         "Two-Fisted"
         "Weak Point"
         "Whirlwind")))

§ Psionic Talents

  (defpsmacro gen-var-psionic-talents ()
    `(defvar *psionic-talents*
       '("Augmented Speed"
         "Augmented Strength"
         "Blink"
         "Choke"
         "Clairvoyance"
         "Cryokinesis"
         "Electrokinesis"
         "Emotion"
         "Empathy"
         "False Perception"
         "Hibernation"
         "Inspiration"
         "Invisibility"
         "Kinetic Blast"
         "Kinetic Shield"
         "Levitation"
         "Life Detection"
         "Memory Block"
         "Microkinesis"
         "Mind Blast"
         "Mind Control"
         "Mind Lock"
         "Mind Shield"
         "Precognition"
         "Psychic Healing"
         "Pyrokinesis"
         "Regeneration"
         "Second Wind"
         "Suggestion"
         "Telekinesis"
         "Telepathy"
         "Thousand Faces"
         "Truth"
         "Vampire"
         "Zombie")))

§ Archetype Definitions

Archetypes are base character concepts and sources of many special abilities.

  (defpsmacro gen-var-archetypes ()
    `(defvar *archetypes*
       '(("agent"
          "**Agent**: Spy, Detective, Bounty Hunter, Corporate Troubleshooter.
    This character is well-versed in espionage, subterfuge,
    skullduggery, and conspiracies.")
         ("diplomat"
          "**Diplomat**: Ambassador, Administrator, Liaison Officer, Face.
    Whatever the title,this archetype is invaluable in all sorts of
    situations where a lighter touch and smiling face are essential.")
         ("engineer"
          "**Engineer**: Gearhead, Techie, Greasemonkey, Miracle Worker. Whenever
    something needs fixing, building, or optimizing, the Engineer is the
    one to call. They are especially useful in situations where
    technology is central to the task at hand.")
         ("merchant"
          "**Merchant**: Entrepreneur, Smuggler, Mover and Shaker, Free Trader.
    Merchants know how to spot a moneymaking opportunity anywhere. Some
    might even be honest.")
         ("mystic"
          "**Mystic**: Spiritual Guru, Religious Leader, Itinerant Preacher,
    Washed-Up Hippie. This character embraces everything
    parapsychological and lives life according to an esoteric mystical
    creed.")
         ("outlaw"
          "**Outlaw**: Con Artist, Pirate, Bandit, Rogue, Thief. This character
    is a criminal, or has an extensive criminal past. They have shady
    connections, and even shadier skills. They might only be one step
    ahead of their questionable past catching up with them.")
         ("outsider"
          "**Outsider**: Barbarian, Drifter, Outcast, Exile. This character hails from a
  technological backwater, or they have spent long years as an outcast on the fringes
  of society.")
         ("pilot"
          "**Pilot**: Flyboy, Rocket-Jock, Tanker, Wheel-girl. This character is
    a natural with vehicles, and knows how to maximize the performance
    parameters of any vehicle they are operating.")
         ("roughneck"
          "**Roughneck**: Belter, Ship’s Crew, Prospector, Colonist. Roughnecks
    are the working stiffs in space, and they are used to doing all the
    dirty, unpleasant tasks that no one else wants to do.")
         ("scholar"
          "**Scholar**: Doctor, Researcher, Scientist. These characters are
    well-educated and have extensive knowledge in a broad range of
    esoteric and technical fields.")
         ("scout"
          "**Scout**: Courier, Surveyor, Explorer, Spacer. Scouts are well-versed
    in surveying, navigation, and starship piloting. They might know a
    bit about xeno-biology or long-lost human cultures than their
    colleagues might expect.")
         ("soldier"
          "**Soldier**: Marine, Grunt, Mercenary, Officer. This character is a
    professional, long- service soldier. They are familiar with weapons,
    tactics, combat in a variety of environments, and military
    procedures."))))

§ Skill Sets

The skill sets determine the most useful skills for each archetype.

The closer a given skill is to beginning of the list, the most likely it is to be trained following a bell-like distribution.

  (defpsmacro gen-var-archetype-skills ()
    `(defvar *archetype-skills*
       '(("agent"
          ("stealth" "vehicles" "social" "technology" "combat" "knowledge" "physical"))
         ("diplomat"
          ("social" "knowledge" "technology" "stealth" "vehicles" "combat" "physical"))
         ("engineer"
          ("technology" "knowledge" "vehicles" "physical" "combat" "social" "stealth"))
         ("merchant"
          ("social" "knowledge" "stealth" "technology" "combat" "vehicles" "physical"))
         ("mystic"
          ("knowledge" "social" "technology" "stealth" "combat" "physical" "vehicles"))
         ("outlaw"
          ("stealth" "combat" "social" "technology" "vehicles" "physical" "knowledge"))
         ("outsider"
          ("physical" "combat" "stealth" "knowledge" "vehicles" "social" "technology"))
         ("pilot"
          ("vehicles" "physical" "knowledge" "technology" "combat" "social" "stealth"))
         ("roughneck"
          ("physical" "vehicles" "combat" "technology" "knowledge" "stealth" "social"))
         ("scholar"
          ("knowledge" "social" "technology" "physical" "vehicles" "stealth" "combat"))
         ("scout"
          ("knowledge" "vehicles" "stealth" "technology" "social" "combat" "physical"))
         ("soldier"
          ("combat" "physical" "vehicles" "stealth" "knowledge" "social" "technology")))))

§ Gear List

The gear list provides inventory templates for archetype characters.

  (defpsmacro gen-var-gear-list ()
    `(defvar *gear-list*
       '(("agent"
          ("Bulletproof Vest (4 Prot.)" "Stealth Pistol (2d6, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Omnicomp" "Breather Mask" "Disguise Kit" "Multiscanner" "**Cr**2795"))
         ("diplomat"
          ("Bulletproof Vest (4 Prot.)" "Stealth Pistol (2d6, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Omnicomp" "Breather Mask" "Disguise Kit" "Multiscanner" "**Cr**2795"))
         ("engineer"
          ("Envirosuit (4 Prot.)" "Gyrojet Pistol (2d6+2, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Omnicomp" "OmniTool" "AntiRad (1 dose)" "Breather Mask" "**Cr**3845"))
         ("merchant"
          ("Bulletproof Vest (4 Prot.)" "Stealth Pistol (2d6, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Omnicomp" "Breather Mask" "Disguise Kit" "Multiscanner" "**Cr**2795"))
         ("mystic"
          ("Envirosuit (4 Prot.)" "Semi-Auto Pistol (2d6, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Multiscanner" "Omnicomp" "Breather Mask" "**Cr**3825"))
         ("outlaw"
          ("Ceramic Plates (8 Prot.)" "Shotgun (4d6, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Chameleon Suit" "Disguise Kit" "Breather Mask" "**Cr**3215"))
         ("outsider"
          ("Bulletproof Vest (4 Prot.)" "Revolver (2d6+1, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Lockpicks" "Breather Mask" "Dagger (2d6)" "Cutlass (3d6)" "**Cr**6275"))
         ("pilot"
          ("Envirosuit (4 Prot.)" "Gyrojet Pistol (2d6+2, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Breather Mask" "Omnicomp" "Technical Tool Kit" "AntiRad (1 dose)" "**Cr**4025"))
         ("roughneck"
          ("Envirosuit (4 Prot.)" "Gyrojet Pistol (2d6+2, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Omnicomp" "OmniTool" "AntiRad (1 dose)" "Breather Mask" "**Cr**3845"))
         ("scholar"
          ("Envirosuit (4 Prot.)" "Semi-Auto Pistol (2d6, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Multiscanner" "Omnicomp" "Breather Mask" "**Cr**3825"))
         ("scout"
          ("Envirosuit (4 Prot.)" "Gyrojet Rifle (3d6+2, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Multiscanner" "Breather Mask" "**Cr**2602"))
         ("soldier"
          ("Ceramic Plates (8 Prot.)" "Pulse Rifle (3d6+3, 4 reloads)" "Semi-Auto Pistol (2d6, 2 reloads)" "Backpack" "LED Flashlight" "OmniComm" "Medkit" "Chameleon Suit" "Breather Mask" "**Cr**2651")))))

§ Engine Code

§ Utility Functions

Some utilities that simplify my life with Parenscript here.

  (in-package :nomad)

  (defpsmacro gen-utils ()
    `(progn
       (defun -random-choice (list)
         "Select randomly (uniformly) an item from a list."
         (let* ((size (length list))
                (pos (random size)))
           (getprop list pos)))

       (defun -range (max &key (min 0) (step 1))
         "Generate a range-list of numbers."
         (loop for n from min below max by step
               collect n))

       (defun -normal-random (mean stdev)
         "Generate stochastic value that obeys normal distribution."
         (let* ((u (- 1.0 (random)))
                (v (random))
                (z (* (sqrt (* -2.0 (log u)))
                      (cos (* 2.0 pi v)))))
           (+ (* z stdev) mean)))

       (defun -normal-random-choice (list)
         "Select from list with bell-like probability. The beginning (left-side) items are most probable."
         (let* ((step (/ 3.0 (length list)))
                (range-list (-range (+ 3.0 step) :min step :step step))
                (rn (abs (-normal-random 0.0 1.0)))
                (prox-list (chain range-list (map (lambda (x) (abs (- x rn))))))
                (min-value (apply (chain -math min) prox-list))
                (pos (chain prox-list (index-of min-value))))
           (getprop list pos))) 

       (defun -choose-to-list (to from &key (normal nil))
         "Select an item from FROM and add it to TO. Items should be unique."
         (let ((choice (if normal
                           (-normal-random-choice from)
                           (-random-choice from))))
           (if (chain to (includes choice))
               (-choose-to-list to from)
               (chain to (push choice)))
           to))    

       (defun -capitalize (str)
         "Capitalize first letter of a string."
         (+ (chain (getprop str 0) (to-upper-case))
            (chain str (slice 1))))

       (defun -assoc (key list)
         "Access a value in an associated array."
         (loop :for item :in list :when (= (getprop item 0) key)
               :return (getprop item 1)))

       (defun -remove (list item)
         "Remove ITEM from LIST array."
         (let ((index (chain list (index-of item))))
           (when (> index -1)
             (chain list (splice index 1)))
           list))

       (defun -by-id (elem)
         "Shortcut to get element by Id."
         (chain document (get-element-by-id elem)))

       (defun -value-at (elem)
         "Shortcut to get element value."
         (@ (chain document (get-element-by-id elem)) value))

       (defun -bold (str)
         "Wrap string in a markdown 'strong' markup."
         (+ "**" str "**"))))

§ Generate Initial Selector Lists Macro

Initialize selector options from lists of string labels. When options are lists their first elements are taken as labels.

  (defpsmacro gen-init-selectors (options element-id)
    `(let ((select-element (-by-id ,element-id)))
       (loop for option in ,options
             do (let ((option (if (listp option)
                                  (getprop option 0) option))
                      (opt (chain document (create-element "option"))))
                  (setf (@ opt text-content) (-capitalize option))
                  (chain select-element (append-child opt))))))

§ Skill Scores distribution generator

Randomly generates a distribution of skill score points. This distribution is to be mapped on a selection of skills for a given archetype.

  (defpsmacro gen-skill-scores ()
    `(defun skill-scores (total scores)
       (if (= 0 total) (chain scores (sort) (reverse))
           (let* ((score (chain -math (ceil (/ (random) 0.3334))))
                  (score (if (< total score) total score)))
             (chain scores (push score))
             (skill-scores (- total score) scores)))))

Initialize skills at Experienced level.

  (defpsmacro gen-init-skills ()
    `(defun init-skills (archetype total)
       (let ((scores (skill-scores total '()))
             (skill-package (chain (-assoc archetype *archetype-skills*) (slice)))
             (result '()))
         (loop for _ from (length scores) to 6
               do (chain scores (push 0)))
         (loop for i from 0 to 7
               do (let ((skill (-normal-random-choice skill-package)))
                    (chain result (push (list skill (getprop scores i))))
                    (-remove skill-package skill)))
         result)))

Raise a random skill with Rank increase.

  (defpsmacro gen-level-up-skill-increase ()
    `(defun level-up-skill-increase (skills)
       (let ((skill (-random-choice *skills-order*)))
         (loop :for item :in skills
               :do (if (= (getprop item 0) skill)
                       (if (< (getprop item 1) 5)
                           (setf (getprop item 1) (+ 1 (getprop item 1)))
                           (level-up-skill-increase skills)))))))

§ Init Character State

A subroutine for rank raise.

  (defpsmacro gen-rank-raise ()
    `(defun rank-raise (skills combat talents psionics archetype second-archetype use-psionics)
       (let ((raise (-random-choice *raises*)))
         (case raise
           ("talent"
            (let ((choice (-random-choice '("combat" "talent"))))
              (if (= choice "combat")
                  (-choose-to-list combat *combat-talents*)
                  (-choose-to-list talents *talents*))))
           ("psionic" (if (= use-psionics "yes")
                          (-choose-to-list psionics *psionic-talents*)
                          (rank-raise skills combat talents psionics archetype second-archetype use-psionics)))
           ("skill" (level-up-skill-increase skills))
           ("archetype"
            (if (= (length second-archetype) 0)
                (let ((archetypes
                        (loop for a in *archetypes*
                              when (not (= (getprop a 0) archetype))
                                collect (getprop a 0))))
                  (-choose-to-list second-archetype archetypes))
                (rank-raise skills combat talents psionics archetype second-archetype use-psionics)))))))

Here we are generating the character state.

  (defpsmacro gen-character-state ()
    `(defun character-state (specie rank archetype use-psionics)
       (let ((skills '())
             (talents '())
             (combat '())
             (psionics '())
             (stamina 14)
             (second-archetype '())
             (gear '()))
         (if (= specie "human")
             (setf skills (init-skills archetype 5))
             (setf skills (init-skills archetype 4)))
         (when (= specie "human")
           (let ((choice (-random-choice '("combat" "talent"))))
             (if (= choice "combat")
                 (-choose-to-list combat *combat-talents*)
                 (-choose-to-list talents *talents*))))
         (when (= archetype "soldier")
           (-choose-to-list combat *combat-talents*))
         (when (and (= archetype "mystic") (= use-psionics "yes"))
           (-choose-to-list psionics *psionic-talents*)
           (-choose-to-list psionics *psionic-talents*))
         (when (and (= specie "gray") (= use-psionics "yes"))
           (-choose-to-list psionics *psionic-talents*)
           (-choose-to-list psionics *psionic-talents*))
         (loop for num from 1 to (-assoc rank *ranks*)
               do (rank-raise skills combat talents psionics archetype second-archetype use-psionics))
         (setf stamina (+ 14 (* 3 (-assoc "physical" skills))))
         (list (list "skills" skills)
               (list "talents" talents)
               (list "combat" combat)
               (list "psionics" psionics)
               (list "stamina" stamina)
               (list "second-archetype" second-archetype)))))

§ Build Character Statblock

Assemble character from generated elements.

  (defpsmacro gen-build-character ()
    `(defun build-character ()
       (let* ((output-element (-by-id "characterList"))
              (statblock "")
              (name (-value-at "nameInput"))
              (specie (chain (-value-at "speciesSelect") (to-lower-case)))
              (rank (chain (-value-at "rankSelect") (to-lower-case)))
              (archetype
                (let ((archetype (chain (-value-at "archetypeSelect") (to-lower-case))))
                  (if (= "<<random>>" archetype)
                      (getprop (-random-choice *archetypes*) 0)
                      archetype)))
              (use-psionics (chain (-value-at "usePsionicsSelect") (to-lower-case)))
              (state (character-state specie rank archetype use-psionics)))
         ;; Name, Rank Specie and Archetype 
         (setf statblock (+ "<p>"
                            "# " name "<br>"
                            (-capitalize rank) " "
                            (-capitalize specie) " "
                            (-bold (-capitalize archetype))))
         ;; Second Archetype
         (if (> (length (-assoc "second-archetype" state)) 0)
           (setf statblock (+ statblock
                              " and "
                              (-bold (-capitalize
                                      (getprop (-assoc "second-archetype" state) 0)))
                              "</p>"))
           (setf statblock (+ statblock "</p>")))
         ;; Stamina
         (setf statblock (+ statblock
                            "<p> Stamina: "
                            (-assoc "stamina" state) "/"
                            (-assoc "stamina" state) "</p>"))
         ;; Skills
         (setf statblock (+ statblock "<p>## Skills <br>"))
         (loop for label in *skills-order*
               do (setf statblock (+ statblock
                                     "  - "
                                     (-capitalize label)
                                     ": "
                                     (-assoc label (-assoc "skills" state))
                                     "<br>")))
         (setf statblock (+ statblock "</p>"))
         ;; Combat
         (when (> (length (-assoc "combat" state)) 0)
           (setf statblock (+ statblock "<p>## Combat Talents <br>"))
           (loop for talent in (-assoc "combat" state)
                 do (setf statblock (+ statblock
                                       "  + " (-bold talent) ": "
                                       (-assoc talent *talent-descriptions*)
                                       "<br>")))
           (setf statblock (+ statblock "</p>")))
         ;; Professional and Character Talents
         (when (> (length (-assoc "talents" state)) 0)
           (setf statblock (+ statblock "<p>## Professional and Character Talents <br>"))
           (loop for talent in (-assoc "talents" state)
                 do (setf statblock (+ statblock
                                       "  + " (-bold talent) ": "
                                       (-assoc talent *talent-descriptions*)
                                       "<br>")))
           (setf statblock (+ statblock "</p>")))
         ;; Psionics
         (when (> (length (-assoc "psionics" state)) 0)
           (setf statblock (+ statblock "<p>## Psionic Talents<br>"))
           (loop for talent in (-assoc "psionics" state)
                 do (setf statblock (+ statblock
                                       "  + " (-bold talent) ": "
                                       (-assoc talent *talent-descriptions*)
                                       "<br>")))
           (setf statblock (+ statblock "</p>")))
         ;; Gear
         (setf statblock (+ statblock "<p>## Gear<br>"))
         (loop for item in (-assoc archetype *gear-list*)
               do (setf statblock (+ statblock "  * " item "<br>")))
         (setf statblock (+ statblock "</p>"))
         ;; Descriptions
         (setf statblock (+ statblock "<p>-----</p>"))
         (setf statblock (+ statblock "<p>" (-assoc specie *species*) "</p>"))
         (setf statblock (+ statblock "<p>" (-assoc archetype *archetypes*) "</p>"))
         (when (> (length (-assoc "second-archetype" state)) 0)
           (setf statblock
                 (+ statblock "<p>" (-assoc (getprop (-assoc "second-archetype" state) 0)
                                            ,*archetypes*) "</p>")))
         (setf (@ output-element inner-h-t-m-l) statblock))))

§ Generate JavaScript from Parenscript

Assemble macro-definitions given above inside a routine that generates resulting JavaScript code.

  (defun generate-js ()
    (ps
      (gen-var-species)
      (gen-var-ranks)
      (gen-var-raises)
      (gen-var-skills-order)
      (gen-var-talents)
      (gen-var-combat-talents)
      (gen-var-psionic-talents)
      (gen-var-talent-descriptions)
      (gen-var-archetypes)
      (gen-var-archetype-skills)
      (gen-var-gear-list)
      (gen-utils)
      (gen-init-selectors *species* "speciesSelect")
      (gen-init-selectors *ranks* "rankSelect")
      (gen-init-selectors (chain '("<<random>>") (concat *archetypes*)) "archetypeSelect")
      (gen-init-selectors (list "yes" "no") "usePsionicsSelect")
      (gen-skill-scores)
      (gen-init-skills)
      (gen-level-up-skill-increase)
      (gen-rank-raise)
      (gen-character-state)
      (gen-build-character)
      (setf (@ window onload)
            (lambda ()
              (setf (@ (chain document (get-element-by-id "nameInput")) value)
                    "John Doe")
              (chain console (log "Page loaded!"))))))