Prev: 74A6 Up: Map Next: 7574
74BA: Expand a packed word into letters
Used by the routine at NARRATE_ACTION.
Takes a 2-byte word reference and writes the letters to a buffer at WORD_BUFFER -- which the disassembly shows as a data block and a message, because it holds whatever was last expanded into it rather than anything the game was built with.
The reference: the low 12 bits are an offset from WORD_INDEX to the entry, and the top 4 bits are flags the tail of the routine acts on. Zero means print nothing. The letters come back out as lowercase ASCII by adding $60 to each 5-bit code.
The loop is where the game states the format's awkward rule itself. It stops on a byte with bit 7 set, except that if only two letters have been emitted it carries on regardless -- because the top bits of the first two bytes are the word's part of speech, so bit 7 there is not a terminator. At exactly three letters it goes back and re-tests the second byte's bit 7 before deciding. A decoder that simply stops at the first bit 7 splits ATTACK into AT and TACK.
Input
HL The word reference to read, or use the entry at PRINT_WORD_DE with it already in DE
PRINT_WORD 74BA LD E,(HL) DE = the reference at HL
74BB INC HL
74BC LD A,(HL)
74BD INC HL
74BE AND $0F
74C0 LD D,A
PRINT_WORD_DE 74C1 LD A,D Zero prints nothing
74C2 AND $0F
74C4 OR E
74C5 RET Z
74C6 PUSH HL
74C7 PUSH BC
74C8 PUSH DE
74C9 LD C,D C = the flag nibble, for later
74CA LD A,D HL = the dictionary entry
74CB AND $0F
74CD LD D,A
74CE LD HL,WORD_INDEX
74D1 ADD HL,DE
74D2 LD DE,WORD_BUFFER The letters go into the buffer at WORD_BUFFER
74D5 PUSH HL
74D6 LD B,$00
PRINT_WORD_0 74D8 LD A,(HL) Each letter as lower-case ASCII, counted in B
74D9 AND $1F
74DB JR Z,PRINT_WORD_1
74DD INC B
74DE ADD A,$60
74E0 LD (DE),A
74E1 INC DE
74E2 BIT 7,(HL) Bit 7 clear: more letters to come
74E4 INC HL
74E5 JR Z,PRINT_WORD_0
74E7 LD A,B Bit 7 set after only two letters is part of the class, not the end
74E8 CP $02
74EA JR Z,PRINT_WORD_0
74EC CP $03 After three, look again at the second byte's bit 7 before deciding
74EE JR NZ,PRINT_WORD_1
74F0 DEC HL
74F1 DEC HL
74F2 LD A,(HL)
74F3 INC HL
74F4 INC HL
74F5 BIT 7,A
74F7 JR NZ,PRINT_WORD_0
PRINT_WORD_1 74F9 POP HL
74FA LD A,C Flag nibble $50: never inflect
74FB AND $F0
74FD CP $50
74FF JR Z,PRINT_WORD_5
7501 CP $40 $40: always inflect
7503 JR Z,PRINT_WORD_3
7505 CP $10 $10 agrees with TARGET, anything else with ACTING: zero, no ending
7507 LD A,(TARGET)
750A JR Z,PRINT_WORD_2
750C LD A,(ACTING)
PRINT_WORD_2 750F AND A
7510 JR Z,PRINT_WORD_5
PRINT_WORD_3 7512 INC HL The word itself has to allow an ending: bit 7 of its second byte
7513 BIT 7,(HL)
7515 JR Z,PRINT_WORD_5
7517 INC HL HL = the ending chosen by bits 5-7 of its third byte, in ENDINGS
7518 LD A,(HL)
7519 AND $E0
751B RRCA
751C RRCA
751D RRCA
751E LD L,A
751F LD H,$00
7521 LD BC,ENDINGS
7524 ADD HL,BC
7525 LD B,$04 Add up to four characters of it to the buffer
PRINT_WORD_4 7527 LD A,(HL)
7528 AND A
7529 JR Z,PRINT_WORD_5
752B INC HL
752C LD (DE),A
752D INC DE
752E DJNZ PRINT_WORD_4
PRINT_WORD_5 7530 LD HL,WORD_BUFFER B = how many characters there are to print
7533 EX DE,HL
7534 AND A
7535 SBC HL,DE
7537 LD B,L
7538 LD A,(INPUT_STYLE) A space before the word, when one is wanted
753B AND A
753C PUSH AF
753D JR NZ,PRINT_WORD_6
753F LD A,(MID_LINE)
7542 AND A
PRINT_WORD_6 7543 LD A,$20
7545 CALL NZ,PRINT_CHAR
7548 POP AF Start a new line first if the word would not fit on this one
7549 LD A,(INPUT_COLUMNS)
754C JR NZ,PRINT_WORD_7
754E LD A,(STORY_COLUMNS)
PRINT_WORD_7 7551 LD HL,CAPITAL_NEXT
7554 CP B
7555 JR NC,PRINT_WORD_8
7557 LD A,(HL)
7558 CALL NEW_LINE
755B LD (HL),A
PRINT_WORD_8 755C POP DE
755D LD A,D Flag nibble $70 sets CAPITAL_NEXT to 1
755E AND $F0
7560 CP $70
7562 LD A,$01
7564 JR NZ,PRINT_WORD_9
7566 LD (HL),A
PRINT_WORD_9 7567 LD HL,WORD_BUFFER Print the buffer
PRINT_WORD_10 756A LD A,(HL)
756B CALL PRINT_CHAR
756E INC HL
756F DJNZ PRINT_WORD_10
7571 POP BC
7572 POP HL
7573 RET
The flags in the top nibble choose whether the word is inflected, and the whole of it is: $40 always adds the suffix, $50 never does, $10 adds it when TARGET is non-zero, and every other value adds it when ACTING is non-zero. Either way the word itself has the final say -- the suffix is only added if bit 7 of its second byte is set, which is what marks an entry as one that can take it.
Measured rather than read off: PRINT_WORD was called directly with each of the sixteen flag values and the buffer read back, then TARGET and ACTING were toggled by hand to test the dispatch. The word at WORD_SHATTER comes out as "shatter" or "shatters" exactly as the rule above predicts in all six cases, the ones at WORD_RECOVER and WORD_ARRIVES inflect the same way, and no word in the indexed list inflects at all -- none of them has that bit set, which fits, since the indexed list is what the parser matches against and nothing is ever printed from it.
ACTING holds who the sentence is about, and zero means the player -- so the test really is subject agreement. Watched across real sentences: while the game narrates you it is zero and no verb inflects, and while it narrates anybody else it holds that character's identifier and the inflectable verbs take their -s. TARGET is a second participant, and flag $10 is how a word is made to agree with that one instead.
The identifiers are not a flag but a character number: TARGET is set to $FF at PARSE_ACTION, loaded from tables at FIRST_TARGET_FAILED and TARGET_NAME elsewhere, and compared against list entries with CP (HL) at EXCEPTED. One turn of narration walked ACTING through a run of consecutive values while repeating the same verb, which is a group of characters being described one after another rather than anything to do with grammar.
Prev: 74A6 Up: Map Next: 7574