"Are you a werewolf" test

See also the Jota Code Compiler version.

The questions

On the test object, we store several variables with a one-letter identifier. The 'q' variable holds the current question number, 'w' holds the wolfiness-score of the player, and 'o' holds 1 if the player's favourite insect is a carpenter ant.

The variables are stored on the form "ply%l%#" where %l is the one-letter identifier and %# is the player ID.

All variables are reset to 0 when the test starts, except for 'q' which starts at 1. (In retrospect, there's no reason why 'q' couldn't start at 0, but changing it now would mean changing the names of all the question fields.)

The test system is rather simple, actually. Each choice is stored in a separate field. First comes the choice-text, then a tilde (~), and then one or more variable letters. Each variable listed will be incremented by one. If the variable is listed twice, it'll be incremented twice. And so on.
Finally, for fancy effects, the variable-list can be followed by an at-sign and some JotaCode to execute.

Furthermore, question-texts are @called, which means we can put JotaCode in them.

This is also used for the final evaluation, where test-results are printed. This code is simply the text of question 11.
Note how the variable list of all choices start with a 'q'. This is to advance to the next question (as the question number is stored in 'q'.)

@create wolf test;test
(wolf test is created as object #14312.)
@set test = expert

@field test = q1: 1. My favorite type of bug is a...
@field test = q1_a: Carpenter ant~qo
@field test = q1_b: Wolf spider~qw

(If the player picks A, we increase the "o" variable, if B we increase the "w" variable. In both cases, we also increase the "q" variable.)
@field test = q2: @print("2. To keep ", @switch("%s", "he", "a clean-shaven face", "she", "clean-shaved legs", "clean-shaved"), ", I have to shave...")
(Print "To keep a clean-shaved face"/"To keep clean-shaved legs"/"To keep clean-shaved" depending on the player's sex.)

@field test = q2_a: Once a week~q
@field test = q2_b: Occasionally~q
@field test = q2_c: Once a day~qwm@print("Yeow. ")
@field test = q2_d: Continuously~qww@print("Yeow! ")

(Print "Yeow" if the player needs to shave once a day or even more often.)

(...)

@field test = q11:
 @print("You are... ");
 @switch(1,
  @gt(@g("plyw%#"), 12), "A WOLF!",
  "NOT a wolf."
 );
 @switch(@g("plyo%#"), "1", " Also, you hate wood.");
 @print("%cNot satisfied with your test results?
         Try again, or mud-mail Kwi!");
 @s("plyq%#", ""); // Clear question number.
 @tellroom(@location("%!"), "%#", @print(
  "%n has taken the \"Are you a wolf\"-test, and %s is... ",
  @switch(1,
   @gt(@g("plyw%#"), 12), "a WOLF! Quick, lynch %o before it's too late!",
   "NOT a wolf. (No warranties on the accuracy of this test, though.)"
  )
))

Showing the question

Here's the code we call to print the current question. First we @call the question text (e.g. "q2"), then we run through all choices (e.g. "q2_a") and print them.
Note that the choices appear in alphabetic order only through some kind of sheer luck. :)

@field test = showq : @let("q", @g("plyq%#"), @print(
 @call("%!", "q%q"), // E.g. "q2"
 @fieldloop("%!", "q%q_", @print(
  "%c",
  @uc(@substr("%f", @strlen("q%q_"), 1)), // Uppercase choice-letter
  ") ",
  @substr("%v", 0, @index("%v", "~")) // Print text up to the "~"
 ))
)

Here's the code/text we show when no test is in progress. Notice, also, that we show a fake "Obvious Actions:"-line. All the actions are in fact set dark.

@field test = desc_ : Are YOU a werewolf? Take this short (10 questions) test and find out! We've got to catch those filthy werewolves, after all.%cBased on the original "Are you a werewolf" book-object. Mud-mail comments and suggestions to Kwi.%cObvious Actions: take test

Finally, the actual test-description. Here, we see if a test is in progress (for the current player). If there is, we call showq, then show a fake "Obvious Actions:"-line listing all choices. If not, we show the "desc_".

@desc test = @let("q", @g("plyq%#"), @switch("%q",
 "", @call("%!", "desc_"),
 @print(
  @call("%!", "showq"),
  "%cObvious Actions: ",
  @fieldloop("%!", "q%q_",
   @print("answer ", @uc(@substr("%f", @strlen("q%q_"), 1)), ", ")
  ),
  "start over"
 )
))

Starting the test

@action take test;test me;start test;start over = test : nowhere
@set take test = dark
@success take test = @call(14312, "taketest")

@field test = intro : Welcome to the "Are you a werewolf"-test! Here comes the first question:%c

@field test = taketest : @call("%!", "intro");
 // Clear old variables for current player:
 @fieldloop("%!", "ply", @switch(@substr("%f", 4), "%#", @s("%f", "")) );
 @s("plyq%#", 1);
 // Show full description, including the fake Obvious Actions
 @call("%!", "description")

Answering questions

This is the nasty bit. Here we parse the player input, then parse the choice-field into choice-text, variable-list and (optional) JotaCode. Ready? Here we go:

@action answer * = test : nowhere
@set answer * = puzzle
@set answer * = dark
@success answer * = @let("q", @getfield(14312, "plyq%#"), @switch("%q",
 // No test in progress?
 "", "I think the command you're looking for is TAKE TEST.%c
      (The test is unreliable enough as it is,
      there's no need to answer questions before they're asked.)",
 @switch(@strlen("%0"),
 // Player typed exactly one char (E.g. ANSWER B, and not ANSWER SPIDER.)
  1, @switch(@getfield(14312, "q%q_%0"),
   "", @print(
    @uc("%0"), " was not one of the choices.
    (LOOK AT TEST if you've forgotten the question.)"
  ),
   @call(14312, "handleanswer")
  ),
  "Sorry, answer what? (Please specify a single letter, as in ANSWER A.)"
)
))

The effect of the code above is that we check if it was a valid choice, and if so, call "handleanswer".

// Now, %0 holds the answer-letter.
@field test = handleanswer : @let(
 "x", @g(@print("q", @g("plyq%#"), "_%0")),
 @let("i", @add(@index("%x", "~"), 1), "j", @index("%x", "@"),
  // Okay, now %x holds the entire choice-field,
  // %i the position of "~" in %x PLUS one,
  // and %j the position of "@" in the text (or -1 if no @.)

  @print(
   // Increment variables
   @strloop(
    @switch("%j",
     -1, @substr("%x", "%i"),
     @substr("%x", "%i", @sub("%j", "%i"))
    ),
    "c",
    @s("ply%c%#", @add(@g("ply%c%#"), 1))
   ),
   // Execute the JotaCode (if any)
   @switch("%j",
    -1, "",
    @execute(@substr("%x", "%j"))
   ),
   // Confirm the choice, show next question
   "\"",
   @substr("%x", 0, @sub("%i", 1)),
   "\" it is.%c",
   @call("%!", "showq")
  )
 )
)