! ---------------------------------------------------------------------------- ! FORM_EX : Example forms using Form_Class. ! ! This program implements a reasonable facsimile of the Bureaucracy ! introduction form, and some much simpler example forms to test various ! features of Form_Class. ! _ ! Torbjorn Andersson, November 1995, No Rights Reserved ! ---------------------------------------------------------------------------- Switches xdv5s; Release 5; Constant Story "FORMS"; Constant Headline "^Bureaucracy-style Forms in Inform^"; Include "Parser"; Include "VerbLib"; ! NOTE: It is important that Grammar.h is included before form.h, and that ! form.h is included before the example forms. The reason for this is ! that form.h contains global variables used by the example, and wants ! to extend on the standard grammar for "fill". Include "Grammar"; Include "form"; ! ---------------------------------------------------------------------------- ! EXAMPLE FORMS ! ---------------------------------------------------------------------------- Global player_name -> 80; ! The introduction form and the remarks are all stolen from Bureaucracy, but ! I don't know whether or not I managed to map the remarks to the right ! questions. Array remark_offset -> [; 0; 2; ! Last name 2; 1; ! First name 0; 0; ! Middle initial 0; 0; ! Male/Female 3; 1; ! House number 4; 2; ! Street name 6; 3; ! City 0; 0; ! State 0; 0; ! Zip 0; 0; ! Phone 9; 5; ! Last employer but one 0; 0; ! Least favourite colour 14; 4; ! Name of girl/boy friend 18; 3; ! Previous girl/boy friend ]; Array remark_array --> [; "NOTE: How embarrassing for you."; ! Last name "NOTE: A well-known criminal family."; "NOTE: Your parents had the last laugh."; ! First name "NOTE: Due to be condemned."; ! House number "NOTE: The bad part of town."; ! Street name "NOTE: Next to the dump."; "NOTE: What a dump." ! City "NOTE: What a pit." "NOTE: You'd better move again."; "NOTE: Now in Chapter 11."; ! Last employer but one "NOTE: Now in liquidation."; "NOTE: A sweatshop."; "NOTE: Run by Bozo the Clown."; "NOTE: Much happier without you."; "NOTE: What a dog."; ! Curr. girl/boy friend "NOTE: Still? You should have learned."; "NOTE: Surely you can do better."; "NOTE: One of a long time of losers."; "NOTE: You were better off then."; ! Prev. girl/boy friend "NOTE: Now a millionaire."; "NOTE: Now a famous porno star."; ]; Array init_form_array --> [; 1; ! One line for header "SOFTWARE LICENCE APPLICATION"; "Type @@94 to back up a field. Thank you."; ! Helpful message 14; ! 14 questions 0 0 21 NULL "Last Name:"; 1 0 25 NULL "First Name:"; 2 0 1 NULL "Middle Initial:"; 2 20 1 #r$MFFilter "Your sex (M/F):"; 3 0 4 #r$NumFilter "House number:"; 4 0 24 NULL "Street name:"; 5 0 18 NULL "City:"; 5 25 5 NULL "State:"; 6 0 6 NULL "Zip:"; 6 14 16 #r$PhoneFilter "Phone:"; 7 0 14 NULL "Last employer but one:"; 8 0 13 NULL "Least favourite colour:"; 9 0 12 NULL "Name of girl/boy frield:"; 10 0 11 NULL "Previous girl/boy frield:"; ]; Object init_form "if" class Form_Class, with form_text init_form_array, form_select #r$InitFormSelect, form_parser #r$InitFormParser, after [ i; give self ~general; style bold; print "[Your blood pressure just went up.]"; style roman; print "^^Thank you for your cooperation, M"; ! Anyone who has played Bureaucracy knows this isn't a bug; it's ! supposed to be "wrong". if (selfobj has female) print_char 'r'; else print_char 's'; print_char ' '; for (i = 0 : i < player_name-->0 : i++) print_char player_name->(i + 2); print ".^"; rtrue; ! Override default rule. ]; [ InitFormParser o n i j k; if (o == init_form) { switch (n) { 0: ! Last name; Copy the contents of form_buffer into player_name, ! turning upper-case into lower-case whenever appropriate. Note ! that form_buffer-->0 holds the length of the input. player_name-->0 = form_buffer-->0; player_name->2 = form_buffer->2; for (i = 3 : i < 2 + form_buffer-->0: i++) { if (form_buffer->i >= 'A' && form_buffer->i <= 'Z') player_name->i = form_buffer->i + ('a' - 'A'); else player_name->i = form_buffer->i; } 3: ! Gender. I hope nothing bad comes from giving the player ! object the 'female' attribute, even though it is aliased by ! the library. ! ! Note that since an entry may be entered several times (by ! using "^"), the attribute has to be set/cleared for both ! cases. if (form_buffer->2 == 'F') give selfobj female; else give selfobj ~female; 4: ! House number if (form_buffer-->0 < 2) return "ERROR: We know it's actually 15."; } ! Get the offset to the first remark and the number of remarks. j = remark_offset->(n * 2); k = remark_offset->(n * 2 + 1); ! If there are any remarks available, pick one of them. I don't know ! how well this works on interpreters with deficient random-number ! generators, but it's not as if it's any vital information ... if (k > 0 && random(100) < 25) { if (k == 1) return remark_array-->j; return remark_array-->(j + random(k) - 1); } } return NULL; ]; Global scratch_area -> 14; Global init_form_select -> 14; [ InitFormSelect o asked max i n; if (o ~= init_form || asked == max) return -1; ! The following algorithm for permuting an array was used by Bengt Sagnell ! in the Swedish computer magazine "ABC-bladet" back in 1981, and was said ! to have been used during the European Twirling Championship. It seems to ! work, so I haven't bothered figuring out exactly HOW it works. :-) ! ! I could have done this in the 'before' rule of the init_form, but here I ! have the number of questions conveniently available. if (self hasnt general) { for (i = 0 : i < max : i++) scratch_area->i = i; for (i = max - 1 : i >= 0 : i--) { n = random(i + 1) - 1; init_form_select->i = scratch_area->n; scratch_area->n = scratch_area->i; } give self general; } return init_form_select->asked; ]; ! The filters. The "n = 0;" lines are really rather unnecessary, but keeps ! Inform from complaining about unused local variables. [ MFFilter c n; n = 0; if (c == 'M' or 'F') return NULL; return "ERROR: Entry not M or F."; ]; [ NumFilter c n; if (c == '-' && n == 0) return "ERROR: Don't be so negative."; if (c >= '0' && c <= '9') return NULL; return "ERROR: Not a number."; ]; [ PhoneFilter c n; n = 0; if (c == '-' || (c >= '0' && c <= '9')) return NULL; return InvalidChar; ]; ! The world. (It's a small world after all.) Object Empty_Room "Empty Room" with description "An empty room.", has light; ! The blank form tests that the class can handle the default properties. The ! result might not be very interesting, but at least it doesn't crash the ! interpreter; knock on wood. Nearby blank_form "blank form" class Form_Class, with name "blank" "form"; ! The green form tests headerless forms and the select/reject feature. Nearby green_form "green form" class Form_Class, with name "green" "form", form_text 0 ! Nothing in the header NULL ! Nothing in the message field 2 ! Only two questions 0 0 9 NULL "Are you enjoying this game?" 1 0 10 NULL "If not, why?", form_select #r$GreenFormSelect, form_parser #r$GreenFormParser; [ GreenFormParser o n; if (o == green_form) { switch (n) { 0: if (form_buffer->2 == 'N') { give self ~general; return "NOTE: Why so negative?"; } if (form_buffer->2 == 'Y') { give self general; return NULL; } form_parse_reject = 1; return "ERROR: Yes or No?"; } } return NULL; ]; [ GreenFormSelect o asked max; if (o ~= green_form) return -1; if (asked == max || (asked == 1 && self has general)) return -1; return asked; ]; ! The blue form tests multiple-line headers, automatic calculation of the ! form's width, the select feature and the addition of new 'before' rules. Nearby blue_form "blue form" class Form_Class, with name "blue" "form", form_width -1, ! Calculate the form's width automatically form_text 2 ! Two lines in the header "FILLMORE BETTER BEEZER CARD" "Application" "Have a nice day." ! "Nice" message for the message field 3 ! Three questions 0 0 10 NULL "Last Name:" 1 0 10 NULL "First Name:" 2 0 10 NULL "Date of birth:", form_select #r$MyFormSelect2, before [ key; Complete: print "You are about to fill out a form. Don't Panic!^^\ [Press any key] "; @read_char 1 key; rfalse; ! Don't override the default rule ]; [ MyFormSelect2 o asked max; if (o ~= blue_form || asked == max) return -1; switch (asked) { 0: return 1; 1: return 2; 2: return 0; default: return -1; } ]; ! ---------------------------------------------------------------------------- ! INITIALISATION ! ---------------------------------------------------------------------------- ! When YesOrNo() is called, the status line will be displayed. I don't want ! that to show the empty room, so I'm adding this minimalistic object. Object Limbo "Limbo"; [ Initialise key; location = Limbo; print "^^^^"; print "[NOTE: This isn't really Bureaucracy, but I simply couldn't \ resist stealing the opening text - and form - from it.]^^^"; style bold; print "Important!"; style roman; print "^^Our records show that you do not have a license to operate this \ software.^^"; print "Normally, you would be required to complete a License Application \ Form and mail it (with proof of purchase) to our Licensing \ Department, and then wait the customary four to six weeks for \ processing.^^"; print "Luckily, for your convenience, we have, at the last minute and at \ great expense, installed a remarkable new on-line electronic \ application form on this very disk, which will be processed by our \ modern 24-hour computer service moments after you fill it in.^^"; print "[Press any key to begin.] "; @read_char 1 key; print "^^Would you like to skip this long and boring form? "; if (YesOrNo() == 0) ; print "^"; location = Empty_Room; ]; end;