![]() |
Routines |
| Prev: C041 | Up: Map | Next: C17D |
|
Used by the routine at Handler_UserInput.
Parses and tokenises the user's command input when they press ENTER. The input is broken down into individual words, each word is looked up in the vocabulary table, and unrecognised words are reported to the player.
|
||||||||||
| UserInput_Enter | C058 | LD (HL),A | Write 0D to the command buffer at the current position for use as a termination character. | |||||||
|
Force a newline to be "printed" to the screen.
|
||||||||||
| C059 | CALL SwitchNormalScreenOutput | Call SwitchNormalScreenOutput. | ||||||||
| C05C | CALL PrintCharacter | Call PrintCharacter. | ||||||||
|
Initialise the word token buffer. This buffer will store up to 0A vocabulary tokens (one per word in the command). Each token is the index of the word in the vocabulary table.
|
||||||||||
| C05F | LD HL,$BD66 | HL=UserInput_FirstToken. | ||||||||
| C062 | LD A,$FF | A=FF. | ||||||||
| C064 | LD B,$0A | Set a counter in B for the size of the word token buffer (0A bytes). | ||||||||
|
Fill the word token buffer with FF (the terminator value) to mark all slots as empty.
|
||||||||||
| EmptyWordTokenBuffer_Loop | C066 | LD (HL),A | Write A to *HL. | |||||||
| C067 | INC HL | Increment HL by one. | ||||||||
| C068 | DJNZ EmptyWordTokenBuffer_Loop | Decrease the word token buffer counter by one and loop back to EmptyWordTokenBuffer_Loop until the whole buffer is cleared. | ||||||||
| C06A | LD HL,$BD34 | HL=CommandBuffer. | ||||||||
| C06D | LD C,$0A | C=0A. | ||||||||
|
Begin parsing the command. Extract each word from the input, look it up in the vocabulary, and store its token. Words are separated by spaces or commas, and the word "The" is automatically ignored.
|
||||||||||
| UserInputParser_Loop | C06F | LD DE,$BD71 | DE=FourLetterBuffer. | |||||||
| C072 | LD B,$04 | Set a counter in B for the 04 letters. | ||||||||
|
Clear the four-letter buffer to spaces so a short word cannot match the previous one's tail.
|
||||||||||
| C074 | LD A,$20 | A=20. | ||||||||
| ClearWordBuffer_Loop | C076 | LD (DE),A | Write a space character (20) to the buffer. | |||||||
| C077 | INC DE | Move to the next letter. | ||||||||
| C078 | DJNZ ClearWordBuffer_Loop | Decrease the counter by one and loop back to ClearWordBuffer_Loop until the counter is zero. | ||||||||
| C07A | XOR A | A=00. | ||||||||
| C07B | OR C | A|=C. | ||||||||
| C07C | JP Z,CheckIfEmptyInput | Jump to CheckIfEmptyInput if DE is equal to C. | ||||||||
| C07F | LD A,(HL) | Jump to CheckIfEmptyInput if *HL is equal to 0D. | ||||||||
| C080 | CP $0D | |||||||||
| C082 | JP Z,CheckIfEmptyInput | |||||||||
| C085 | LD B,$04 | B=04. | ||||||||
| C087 | LD DE,$BD71 | DE=FourLetterBuffer. | ||||||||
|
Extract the next word from the command buffer. Copy up to 04 characters (the maximum word length) into the word buffer, stopping at a space, comma, or end of input.
|
||||||||||
| CopyWord_Loop | C08A | LD A,(HL) | Read the character from *HL and store it in A. | |||||||
| C08B | CP $0D | Jump to CheckIfThe if this character is a newline (0D, end of input). | ||||||||
| C08D | JR Z,CheckIfThe | |||||||||
| C08F | CP $20 | Jump to SkipDelimiters_Loop if the character is either an ASCII "SPACE" (20) or an ASCII comma (2C). | ||||||||
| C091 | JR Z,SkipDelimiters_Loop | |||||||||
| C093 | CP $2C | |||||||||
| C095 | JR Z,SkipDelimiters_Loop | |||||||||
| C097 | LD (DE),A | Write this character to the word buffer at *DE. | ||||||||
| C098 | INC HL | Move to the next character in the command buffer. | ||||||||
| C099 | INC DE | Move to the next position in the word buffer. | ||||||||
| C09A | DJNZ CopyWord_Loop | Decrease counter by one and loop back to CopyWord_Loop until counter is zero. | ||||||||
|
If the word was longer than 04 characters, skip over the remaining characters until a delimiter (space, comma, or end of input) is found.
|
||||||||||
| SkipRemainingWord_Loop | C09C | LD A,(HL) | Read the character from *HL and store it in A. | |||||||
| C09D | CP $0D | Jump to CheckIfThe if this character is a newline (0D). | ||||||||
| C09F | JR Z,CheckIfThe | |||||||||
| C0A1 | CP $20 | Jump to SkipDelimiters_Loop if the character is an ASCII "SPACE" (20). | ||||||||
| C0A3 | JR Z,SkipDelimiters_Loop | |||||||||
| C0A5 | CP $2C | Jump to SkipDelimiters_Loop if the character is an ASCII comma (2C). | ||||||||
| C0A7 | JR Z,SkipDelimiters_Loop | |||||||||
| C0A9 | INC HL | Move to the next character in the command buffer. | ||||||||
| C0AA | JR SkipRemainingWord_Loop | Jump to SkipRemainingWord_Loop. | ||||||||
|
Skip over any consecutive spaces or commas to find the start of the next word.
|
||||||||||
| SkipDelimiters_Loop | C0AC | INC HL | Move to the next character in the command buffer. | |||||||
| C0AD | LD A,(HL) | Read the character from *HL and store it in A. | ||||||||
| C0AE | CP $20 | Jump to SkipDelimiters_Loop if the character is an ASCII "SPACE" (20). | ||||||||
| C0B0 | JR Z,SkipDelimiters_Loop | |||||||||
| C0B2 | CP $2C | Jump to SkipDelimiters_Loop if the character is an ASCII comma (2C). | ||||||||
| C0B4 | JR Z,SkipDelimiters_Loop | |||||||||
|
Check if the extracted word is "The". If it is, ignore it and continue with the next word (adventure games typically ignore articles like "the", "a", "an").
Preserve the command pointer, word buffer and token counter while comparing.
|
||||||||||
| CheckIfThe | C0B6 | PUSH HL | Stash HL, DE and BC on the stack. | |||||||
| C0B7 | PUSH DE | |||||||||
| C0B8 | PUSH BC | |||||||||
| C0B9 | LD HL,$BD8C | HL=Messaging_The. | ||||||||
| C0BC | LD DE,$BD71 | DE=FourLetterBuffer. | ||||||||
| C0BF | LD B,$04 | B=04. | ||||||||
| CompareWord_Loop | C0C1 | LD A,(DE) | Jump to AfterCompareWord if the characters don't match (the word is not "The"). | |||||||
| C0C2 | CP (HL) | |||||||||
| C0C3 | JR NZ,AfterCompareWord | |||||||||
| C0C5 | INC DE | Move to the next character in the extracted word. | ||||||||
| C0C6 | INC HL | Move to the next character in "The". | ||||||||
| C0C7 | DJNZ CompareWord_Loop | Decrease counter by one and loop back to CompareWord_Loop until all 04 characters have been compared. | ||||||||
|
Restore the registers saved before the "THE" comparison.
|
||||||||||
| AfterCompareWord | C0C9 | POP BC | Restore BC, DE and HL from the stack. | |||||||
| C0CA | POP DE | |||||||||
| C0CB | POP HL | |||||||||
| C0CC | JR Z,UserInputParser_Loop | Jump to UserInputParser_Loop if the words matched (this was "The", so skip it and process the next word). | ||||||||
| C0CE | DEC C | Decrease C by one. | ||||||||
| C0CF | LD ($BD7D),HL | Write HL to *TempStore_TablePointer. | ||||||||
| C0D2 | LD ($BD7F),DE | Write DE to *TempStore_TableIndex. | ||||||||
| C0D6 | LD ($BD81),BC | Write BC to *TempStore_WordCount. | ||||||||
|
Look up the word in the vocabulary table. The vocabulary contains all recognised verbs, nouns, and other words the game understands. Each entry can have synonyms separated by commas.
|
||||||||||
| C0DA | LD HL,($BD0C) | HL=*Pointer_Vocabulary. | ||||||||
| C0DD | LD C,$00 | Set the token number in C to 00. | ||||||||
| VocabularyLookup_Loop | C0DF | LD A,(HL) | Jump to ProcessUnrecognisedWords if the word is the FF terminator. | |||||||
| C0E0 | CP $FF | |||||||||
| C0E2 | JR Z,ProcessUnrecognisedWords | |||||||||
| CompareVocabularyWord | C0E4 | LD DE,$BD71 | DE=FourLetterBuffer. | |||||||
| C0E7 | LD B,$04 | Set a counter in B for the 04 letters. | ||||||||
| CompareVocabularyWord_Loop | C0E9 | LD A,(DE) | Jump to VocabularyWordNoMatch if this letter does not match. | |||||||
| C0EA | CP (HL) | |||||||||
| C0EB | JR NZ,VocabularyWordNoMatch | |||||||||
| C0ED | INC DE | Move to the next letter of the four-letter buffer. | ||||||||
| C0EE | INC HL | Move to the next vocabulary letter. | ||||||||
| C0EF | DJNZ CompareVocabularyWord_Loop | Decrease the letter counter by one and loop back to CompareVocabularyWord_Loop until the counter is zero. | ||||||||
|
The word matched. Calculate which token-buffer slot to use and store the vocabulary index as the token.
|
||||||||||
| C0F1 | LD HL,$BD81 | HL=TempStore_WordCount. | ||||||||
| C0F4 | LD A,$09 | A=09. | ||||||||
| C0F6 | SUB (HL) | Calculate the token buffer slot index: A-=*HL. | ||||||||
| C0F7 | LD D,$00 | Turn the slot index into a 16-bit offset in DE. | ||||||||
| C0F9 | LD E,A | |||||||||
| C0FA | LD HL,$BD66 | Calculate the address of the token buffer slot: HL=UserInput_FirstToken+DE. | ||||||||
| C0FD | ADD HL,DE | |||||||||
| C0FE | LD (HL),C | Store the vocabulary index (C) in the token buffer slot. | ||||||||
| C0FF | LD HL,($BD7D) | Restore the command buffer position from *TempStore_TablePointer. | ||||||||
| C102 | LD DE,($BD7F) | Restore the word buffer position from *TempStore_TableIndex. | ||||||||
| C106 | LD BC,($BD81) | Restore the word counter from *TempStore_WordCount. | ||||||||
| C10A | JP UserInputParser_Loop | Jump to UserInputParser_Loop. | ||||||||
|
This vocabulary word did not match. Step past the remaining letters. A comma keeps the same token for a synonym; anything else advances the token number for the next entry.
|
||||||||||
| VocabularyWordNoMatch | C10D | LD E,B | Turn the remaining letter count into a 16-bit offset in DE. | |||||||
| C10E | LD D,$00 | |||||||||
| C110 | ADD HL,DE | Move HL past the unmatched letters. | ||||||||
| C111 | LD A,(HL) | Fetch the next vocabulary byte into A. | ||||||||
| C112 | CP $2C | Jump to VocabularyNextEntry if this byte is not a comma (2C). | ||||||||
| C114 | JR NZ,VocabularyNextEntry | |||||||||
| C116 | INC HL | Move past the comma. | ||||||||
| C117 | JR CompareVocabularyWord | Jump to CompareVocabularyWord to try matching the synonym. | ||||||||
| VocabularyNextEntry | C119 | INC C | Advance the token number for the next vocabulary entry. | |||||||
| C11A | JR VocabularyLookup_Loop | Jump to VocabularyLookup_Loop. | ||||||||
|
All recognised words have been tokenised. Now check if there are any unrecognised words remaining in the input. If so, display an error message to the player showing which word(s) weren't understood.
|
||||||||||
| ProcessUnrecognisedWords | C11C | LD HL,($BD7D) | HL=*TempStore_TablePointer. | |||||||
| C11F | LD DE,($BD7F) | DE=*TempStore_TableIndex. | ||||||||
| C123 | LD BC,($BD81) | BC=*TempStore_WordCount. | ||||||||
| C127 | LD A,$0A | C=0A-C. | ||||||||
| C129 | SUB C | |||||||||
| C12A | LD C,A | |||||||||
| C12B | LD HL,$BD34 | HL=CommandBuffer. | ||||||||
| ProcessUnrecognisedWords_Loop | C12E | DEC C | Decrease C by one. | |||||||
| C12F | JR Z,PrintUnrecognisedWord | Jump to PrintUnrecognisedWord if C is equal to 0A (no unrecognised words found). | ||||||||
| FindUnrecognisedWord_Loop | C131 | LD A,(HL) | Read the character from *HL and store it in A. | |||||||
| C132 | CP $20 | Jump to SkipDelimiters_Loop2 if the character is an ASCII "SPACE" (20). | ||||||||
| C134 | JR Z,SkipDelimiters_Loop2 | |||||||||
| C136 | CP $2C | Jump to SkipDelimiters_Loop2 if the character is an ASCII comma (2C). | ||||||||
| C138 | JR Z,SkipDelimiters_Loop2 | |||||||||
| C13A | INC HL | Move to the next character in the command buffer. | ||||||||
| C13B | JR FindUnrecognisedWord_Loop | Jump to FindUnrecognisedWord_Loop. | ||||||||
| SkipDelimiters_Loop2 | C13D | INC HL | Move to the next character in the command buffer. | |||||||
| C13E | LD A,(HL) | Read the character from *HL and store it in A. | ||||||||
| C13F | CP $20 | Jump to SkipDelimiters_Loop2 if the character is an ASCII "SPACE" (20). | ||||||||
| C141 | JR Z,SkipDelimiters_Loop2 | |||||||||
| C143 | CP $2C | Jump to SkipDelimiters_Loop2 if the character is an ASCII comma (2C). | ||||||||
| C145 | JR Z,SkipDelimiters_Loop2 | |||||||||
| C147 | JR ProcessUnrecognisedWords_Loop | Jump to ProcessUnrecognisedWords_Loop. | ||||||||
|
Print the unrecognised word(s) in quotes.
|
||||||||||
| PrintUnrecognisedWord | C149 | PUSH HL | Stash HL on the stack. | |||||||
|
Print "I don't know the word:-".
|
||||||||||
| C14A | LD HL,$BDA5 | HL=Messaging_IDontKnowTheWord. | ||||||||
| C14D | CALL PrintStringAndNewline | Call PrintStringAndNewline. | ||||||||
| C150 | POP HL | Restore HL from the stack. | ||||||||
| C151 | LD A,$22 | Print a double quote character: """. |
||||||||
| C153 | CALL PrintCharacter | |||||||||
| PrintUnrecognisedWord_Loop | C156 | LD A,(HL) | Read the character from *HL and store it in A. | |||||||
| C157 | CP $21 | Jump to PrintUnrecognisedWord_End if this character is less than 21 (a control character, indicating end of word). | ||||||||
| C159 | JR C,PrintUnrecognisedWord_End | |||||||||
| C15B | INC HL | Move to the next character in the command buffer. | ||||||||
| C15C | CALL PrintCharacter | Call PrintCharacter. | ||||||||
| C15F | JR PrintUnrecognisedWord_Loop | Jump to PrintUnrecognisedWord_Loop. | ||||||||
| PrintUnrecognisedWord_End | C161 | LD A,$22 | Print a double quote character: """. |
|||||||
| C163 | CALL PrintCharacter | |||||||||
|
Print ".".
|
||||||||||
| C166 | LD HL,$BF29 | HL=Messaging_FullStop. | ||||||||
| C169 | CALL PrintStringAndNewline | Call PrintStringAndNewline. | ||||||||
| C16C | JR ReturnToInputHandler | Jump to ReturnToInputHandler. | ||||||||
|
Check if the input was empty (no words were tokenised). If tokens were found, return to allow the command to be processed. Otherwise, display "I Don't Understand".
|
||||||||||
| CheckIfEmptyInput | C16E | LD A,($BD66) | Return if *UserInput_FirstToken is not equal to FF (input was not empty). | |||||||
| C171 | CP $FF | |||||||||
| C173 | RET NZ | |||||||||
|
Print "I don't understand.".
|
||||||||||
| C174 | LD HL,$BD91 | HL=Messaging_IDontUnderstand. | ||||||||
| C177 | CALL PrintStringAndNewline | Call PrintStringAndNewline. | ||||||||
| ReturnToInputHandler | C17A | JP Handler_UserInput | Jump to Handler_UserInput to wait for the next command input. | |||||||
|
View the equivalent code in;
|
||||||||||
| Prev: C041 | Up: Map | Next: C17D |