tch.awk (2356B)
1 #!/sbin/env awk -f 2 # TCh: the simplest TinyChoice game engine port to POSIX AWK 3 # Usage: awk -f tch.awk your-story.txt 4 # Controls: respond with a number to go to a particular choice, q to quit 5 # Created by Luxferre in 2023, released into public domain 6 7 BEGIN { 8 curscreen = "" # store the current screen key 9 firstscreen = "" 10 split("", screens) # init the screens map 11 if(ARGC < 2) {print "No input story file!"; exit(1)} 12 while((getline < ARGV[1]) > 0) { 13 if($0 ~ /^=.*=$/) { # header line processing 14 if(curscreen) { # finalize the previous entry 15 gsub(/^\n+/, "", screens[curscreen]) 16 gsub(/\n+$/, "", screens[curscreen]) 17 } else firstscreen = -999 18 curscreen = tolower(substr($0, 2, length($0)-2)) 19 if(firstscreen == -999) firstscreen = curscreen # save the key value 20 } else if(curscreen) screens[curscreen] = screens[curscreen] $0 "\n" 21 } 22 close(ARGV[1]) 23 delete ARGV[1] 24 # actual runtime logic 25 curscreen = ("start" in screens) ? "start" : firstscreen 26 while(length(curscreen) > 0) { # get the lines of the current screen 27 l = split(screens[curscreen], lines, "\n") 28 split("", choices) # init the choices array 29 ch = 1 # init the choice number 30 for(i=1;i<=l;i++) { # we must iterate in order 31 line = lines[i] 32 if(index(line, "->") > 0) { # we have a choice spec 33 split(line, rch, /[ \t]*\->[ \t]*/) 34 tlabel = rch[1] # label is before -> 35 tscreen = rch[2] # target screen is after -> 36 gsub(/^[ \t]+/, "", tlabel) # trim leading spaces in the label 37 gsub(/[ \t]+$/, "", tlabel) # trim trailing spaces in the label 38 gsub(/^[ \t]+/, "", tscreen) # trim leading spaces in the ref 39 gsub(/[ \t]+$/, "", tscreen) # trim trailing spaces in the ref 40 if(!(tscreen in screens)) { 41 printf("Invalid reference %s!\n", tscreen) 42 exit(1) 43 } 44 choices[ch] = tscreen 45 printf("%u) %s\n", ch++, tlabel) 46 } else print line # just print the line "as is" 47 } 48 do { 49 printf "\n> "; if((getline) <= 0) break # prompt for the user choice 50 if($1 == "q" || $1 == "Q" || $1 == "quit" || $1 == "QUIT") { 51 print "Bye!"; exit(0) 52 } 53 ch = int($1) 54 } while(!(ch && (ch in choices) && (choices[ch] in screens))) 55 curscreen = choices[ch] # jump to the selected screen 56 } 57 }