forked from johanberntsson/ozmoo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtext.asm
1495 lines (1456 loc) · 33.2 KB
/
text.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; text opcodes
;TRACE_READTEXT = 1
;TRACE_TOKENISE = 1
;TRACE_SHOW_DICT_ENTRIES = 1
;TRACE_PRINT_ARRAYS = 1
.text_tmp !byte 0
.current_character !byte 0
.character_translation_table
; Pairs of values (zscii code, petscii code). End with 0,0.
!byte $5f, $a4 ; Underscore = underscore-like graphic character
!byte $7c, $7d ; Pipe = pipe-like graphic character
!ifdef SWEDISH_CHARS {
!byte $e5, $5d ; å = ]
!byte $e4, $5b ; ä = [
!byte $f6, $5c ; ä = [
}
!byte 0,0
!ifdef BENCHMARK {
benchmark_commands
; !pet "turn statue w:turn it e:turn it n:n:open door:",255,0
!pet 255,"turn statue w:turn it e:turn it n:n:open door:n:turn flashlight on:n:examine model:press green:g:g:press black:g:press white:g:press green:g:g:press black:press blue:press green:g:g:g:press red:g:g:take ring:e:e:take yellow card:s:take slide:put it in slide projector:turn slide projector on:focus slide projector:take film:examine film projector:remove cap:drop it:put film in film projector:turn film projector on:examine screen:n:w:w:s:e:e:examine piano:open lid:take violet card:play tomorrow:push piano n:d:s:take dirty pillar:n:u:push piano s:g:d:n:take meter:s:u:drop pillar:w:w:w:drop ring:drop meter:e:drop yellow and violet:n:drop letter and photo:s:w:enter fireplace:take brick and drop it:u:u:u:e:d:take penguin:u:w:d:d:d:take indigo card:e:drop penguin:e:drop indigo:w:examine red statue:examine white statue:examine blue statue:e:e:move painting:take green card:examine safe:turn dial right 3:turn dial left 7:turn dial right 5:open safe:take grater:w:drop green:w:drop grater:e:open closet:enter closet:pull third peg:open door:n:examine newel:turn newel:e:take sack:open window:open sack:take finch:drop sack:w:w:s:move mat:take red card:n:e:s:pull second peg:open door:n:drop red:w:drop finch:e:enter closet:take bucket:n:n:unlock patio door:open door:n:take orange card:e:n:n:examine cannon:fill bucket with water:e:s:w:s:s:enter closet:hang bucket on third peg:n:u:open closet:s:wait:wait:open door:n:open panel:open trunk:take hydrant:d:d:w:drop hydrant:e:take all:n:w:w:d:open door:s:take blue card:n:turn computer on:examine it:put red in slot:put yellow in slot:put orange in slot:put green in slot:put blue in slot:put indigo in slot:put violet in slot:examine display:u:take matchbox:open it:take match:drop matchbox:e:e:n:e:n:n:take cannon ball:put it in cannon:light match:light fuse:open compartment:take mask:e:s:w:s:s:w:drop mask:e:s:open mailbox:take yellowed piece of paper:take card:examine card:drop card:n:n:w:take thin:e:n:n:nw:take shovel:ne:n:put thin on yellowed:n:w:n:w:n:w:s:w:w:n:w:s:e:s:e:n:e:s:w:n:w:s:w:n:w:s:w:n:e:n:e:n:e:e:n:e:s:e:e:s:e:n:e:n:e:s:w:s:w:s:e:n:w:s:dig ground with shovel:take stamp:n:e:s:w:n:e:n:e:n:w:s:w:s:w:n:w:w:n:w:s:w:w:s:w:s:w:s:e:n:e:s:e:n:e:s:e:n:w:s:w:n:w:n:e:s:e:e:n:e:s:e:s:e:s:w:s:e:s:s:w:drop stamp:e:drop all except flashlight:w:take red statuette:e:u:open door:enter closet:take skis:n:d:n:n:e:n:n:n:drop flashlight:s:e:e:wear skis:n:take match:light red statue:put wax on match:take skis off:swim:s:d:d:w:u:u:n:n:u:light match:light red statue:lift left end of plank:pull chain:burn rope:stand on right end of plank:wait:blow statue out:drop skis:drop statue:take ladder and flashlight:d:hang ladder on hooks:examine safe:turn dial left 4:turn dial right 5:turn dial left 7:open safe:take film:u:s:e:s:w:s:s:w:drop film:call 576-3190:n:w:d:take toupee:take peg and note:read note:u:e:e:s:u:s:put peg in hole:get gun:shoot herman:get sword:kill herman with sword:get shears:kill herman with shears:untie Hildegarde:",255,0
benchmark_read_char
lda benchmark_commands
beq +++
inc benchmark_read_char + 1
bne +
inc benchmark_read_char + 2
+ cmp #255
beq ++
+++ rts
++ jsr dollar
lda $a0
jsr print_byte_as_hex
lda $a1
jsr print_byte_as_hex
lda $a2
jsr print_byte_as_hex
jsr space
lda #13
rts
}
z_ins_print_char
; lda #0
; sta .alphabet_offset
; sta .escape_char_counter
; sta .abbreviation_command
lda z_operand_value_low_arr
jsr invert_case
jsr translate_zscii_to_petscii
jmp streams_print_output
z_ins_new_line
lda #13
jmp streams_print_output
z_ins_read_char
; read_char 1 [time routine] -> (result)
; ignore argument 0 (always 1)
; ldy z_operand_value_low_arr
; optional time routine arguments
ldy #0
sty .read_text_time
ldy z_operand_count
cpy #3
bne .read_char_loop
ldy z_operand_value_low_arr + 1
sty .read_text_time
ldy z_operand_value_high_arr + 2
sty .read_text_routine
ldy z_operand_value_low_arr + 2
sty .read_text_routine + 1
jsr init_read_text_timer
.read_char_loop
jsr read_char
cmp #0
beq .read_char_loop ; timer routine returned false
cmp #1
bne +
lda #0 ; time routine returned true, and read_char should return 0
+ tax
lda #0
jmp z_store_result
z_ins_tokenise_text
; tokenise text parse dictionary flag
; default dictionary
lda dict_entries
sta .dict_entries
lda dict_entries + 1
sta .dict_entries + 1
; setup string_array
ldx z_operand_value_low_arr
lda z_operand_value_high_arr
stx string_array
clc
adc #>story_start
sta string_array + 1
; setup user dictionary, if supplied
lda z_operand_value_low_arr + 2
ora z_operand_value_high_arr + 2
beq .no_user_dictionary
; user dictionary
lda z_operand_value_low_arr + 2
sta .dict_entries
lda z_operand_value_high_arr + 2
sta .dict_entries + 1
.no_user_dictionary
; setup parse_array and flag
ldx z_operand_value_low_arr + 1
lda z_operand_value_high_arr + 1
ldy z_operand_value_low_arr + 3
jmp tokenise_text
z_ins_encode_text
; encode_text zscii-text length from coded-text
; setup string_array
ldx z_operand_value_low_arr
lda z_operand_value_high_arr
stx string_array
clc
adc #>story_start
sta string_array + 1
; setup length (seems okay to ignore)
; ldx z_operand_value_low_arr + 1
; setup from
ldx z_operand_value_low_arr + 2
stx .wordstart
; do the deed
jsr encode_text
; save result
ldx z_operand_value_low_arr + 3
lda z_operand_value_high_arr + 3
stx string_array
clc
adc #>story_start
sta string_array + 1
ldy #0
- lda .zword,y
sta (string_array),y
iny
cpy #6
bne -
rts
z_ins_print_addr
ldx z_operand_value_low_arr
lda z_operand_value_high_arr
jsr set_z_address
jmp print_addr
z_ins_print_paddr
; Packed address is now in (z_operand_value_high_arr, z_operand_value_low_arr)
lda z_operand_value_high_arr
ldx z_operand_value_low_arr
jsr set_z_paddress
jmp print_addr
z_ins_print
ldy z_pc
lda z_pc + 1
ldx z_pc + 2
jsr set_z_himem_address
jsr print_addr
jsr get_z_himem_address
sty z_pc
sta z_pc + 1
stx z_pc + 2
inc z_pc_mempointer_is_unsafe
rts
z_ins_print_ret
jsr z_ins_print
lda #$0d
jsr streams_print_output
lda #0
ldx #1
jmp stack_return_from_routine
!ifndef Z5PLUS {
z_ins_sread
; sread text parse (Z1-Z3)
; sread text parse time routine (Z4)
jsr printchar_flush
!ifdef TRACE_VM {
;jsr print_vm_map
}
; read input
ldy #0
sty .read_text_time
!ifndef Z4 {
jsr draw_status_line
}
lda z_operand_value_high_arr
ldx z_operand_value_low_arr
!ifdef Z4 {
; time routine arguments
ldy z_operand_count
cpy #4
bne +
ldy z_operand_value_low_arr + 2
sty .read_text_time
ldy z_operand_value_high_arr + 3
sty .read_text_routine
ldy z_operand_value_low_arr + 3
sty .read_text_routine + 1
+
}
jsr read_text
!ifdef TRACE_READTEXT {
jsr print_following_string
!pet "read_text ",0
ldx z_operand_value_low_arr
lda z_operand_value_high_arr
jsr printx
jsr space
jsr printa
jsr newline
ldy #0
- lda (string_array),y
jsr printa
jsr space
iny
cpy #14
bne -
jsr newline
}
; parse it as well?
ldx z_operand_count
cpx #2
bcc .sread_done
lda dict_entries
sta .dict_entries
lda dict_entries + 1
sta .dict_entries + 1
lda z_operand_value_high_arr + 1
ldx z_operand_value_low_arr + 1
!ifdef TRACE_TOKENISE {
jsr print_following_string
!pet "tokenise_text ",0
ldx z_operand_value_low_arr + 1
lda z_operand_value_high_arr + 1
jsr printx
jsr space
jsr printa
jsr newline
}
ldy #0
jsr tokenise_text
!ifdef TRACE_TOKENISE {
ldy #0
- lda (parse_array),y
jsr printa
jsr space
iny
cpy #10
bne -
jsr newline
}
.sread_done
rts
} else {
z_ins_aread
; aread text parse time routine -> (result)
jsr printchar_flush
; read input
ldy #0
sty .read_text_time
; time routine arguments
ldy z_operand_count
cpy #4
bne +
ldy z_operand_value_low_arr + 2
sty .read_text_time
ldy z_operand_value_high_arr + 3
sty .read_text_routine
ldy z_operand_value_low_arr + 3
sty .read_text_routine + 1
+ lda z_operand_value_high_arr
ldx z_operand_value_low_arr
jsr read_text
!ifdef TRACE_READTEXT {
jsr print_following_string
!pet "read_text ",0
ldx z_operand_value_low_arr
lda z_operand_value_high_arr
jsr printx
jsr space
jsr printa
jsr newline
ldy #0
- lda (string_array),y
jsr printa
jsr space
iny
cpy #10
bne -
jsr newline
}
; parse it as well?
ldx z_operand_count
cpx #2
bcc .aread_done
lda dict_entries
sta .dict_entries
lda dict_entries + 1
sta .dict_entries + 1
lda z_operand_value_high_arr + 1
ldx z_operand_value_low_arr + 1
!ifdef TRACE_TOKENISE {
jsr print_following_string
!pet "tokenise_text ",0
ldx z_operand_value_low_arr + 1
lda z_operand_value_high_arr + 1
jsr printx
jsr space
jsr printa
jsr newline
}
ldy #0
jsr tokenise_text
!ifdef TRACE_TOKENISE {
ldy #0
- lda (parse_array),y
jsr printa
jsr space
iny
cpy #10
bne -
jsr newline
}
.aread_done
; debug - print parsearray
!ifdef TRACE_PRINT_ARRAYS {
ldy #0
- lda (string_array),y
tax
jsr printx
lda #$20
jsr streams_print_output
iny
cpy #12
bne -
lda #$0d
jsr streams_print_output
ldy #0
- lda (parse_array),y
tax
jsr printx
lda #$20
jsr streams_print_output
iny
cpy #16
bne -
lda #$0d
jsr streams_print_output
}
lda #0
ldx #13
jmp z_store_result
}
invert_case
cmp #$41
bcc + ; Lower than ascii A
cmp #$7b
bcs + ; Higher than ascii z
sta .text_tmp
and #%00011111
beq ++
cmp #$1b ; "z" + 1
bcs ++
lda .text_tmp
eor #$20
+ rts
++ lda .text_tmp
rts
convert_zchar_to_char
; input: a=zchar
; output: a=char
; side effects:
; used registers: a,y
cmp #$20
beq +++
cmp #6
bcc +++
sec
sbc #6
clc
adc .alphabet_offset
tay
lda .alphabet,y
translate_zscii_to_petscii
+ sta .current_character
ldy #0
- lda .character_translation_table,y
beq ++
iny
cmp .current_character
beq +
iny
bne - ; Always branch
++ lda .current_character
rts
+ lda .character_translation_table,y
+++ rts
convert_char_to_zchar
; input: a=char
; output: a=zchar
; side effects:
; used registers: a,x
sta .current_character
ldx #1
- lda .character_translation_table,x
beq +
cmp .current_character
beq ++
inx
inx
bne - ; Always branch
++ dex
lda .character_translation_table,x
bne +++ ; Always branch
+ lda .current_character
+++ ldx #0
- cmp .alphabet,x
beq +
inx
cpx #26*3
bne -
tax
!ifdef DEBUG {
jsr printx
}
lda #ERROR_INVALID_CHAR
jsr fatalerror
+ txa
clc
adc #6
rts
encode_text
; input .wordstart
; registers: a,x,y
; side effects: .last_char_index, .triplet_counter, .zword
lda .wordstart
clc
; truncate the word length to dictionary size
!ifdef Z4PLUS {
adc #9
} else {
adc #6
}
sta .last_char_index
; get started!
lda #1
sta .triplet_counter ; keep track of triplets to insert extra bit
ldy .wordstart
.encode_chars
ldx #5 ; shift 5 times to make place for the next zchar
dec .triplet_counter
bne .shift_zchar
lda #3
sta .triplet_counter
ldx #6 ; no, make that 6 times (to fill up 3 zchars in 2 bytes)
.shift_zchar
asl .zword + 5
rol .zword + 4
rol .zword + 3
rol .zword + 2
rol .zword + 1
rol .zword
dex
bne .shift_zchar
lda #5 ; pad character
cpy .wordend
bcs +
lda (string_array),y
jsr convert_char_to_zchar
+ tax
!ifdef TRACE_TOKENISE {
jsr printx ; next zchar to insert into zword
jsr space
}
ora .zword + 5
sta .zword + 5
iny
cpy .last_char_index
bne .encode_chars
; done. Add stop bit to mark end of string
lda .zword + 4
ora #$80
sta .zword + 4
rts
find_word_in_dictionary
; convert word to zchars and find it in the dictionary
; see: http://inform-fiction.org/zmachine/standards/z1point1/sect13.html
; http://inform-fiction.org/manual/html/s2.html#s2_5
; input:
; y = index in parse_array to store result in
; parse_array = indirect address to parse_array
; string_array = indirect address to string being parsed
; .wordstart = index in string_array to first char of current word
; .wordend = index in string_array to last char of current word
; output: puts address in parse_array[y] and parse_array[y+1]
; side effects:
; used registers: a,x
sty .parse_array_index ; store away the index for later
lda #0
sta .zword ; clear zword buffer
sta .zword + 1
sta .zword + 2
sta .zword + 3
sta .zword + 4
sta .zword + 5
lda #1
sta .is_word_found ; assume success until proven otherwise
jsr encode_text
!ifdef TRACE_TOKENISE {
; print zword (6 or 9 bytes)
jsr newline
ldx .zword
jsr printx
lda #44
jsr $ffd2
ldx .zword + 1
jsr printx
lda #44
jsr $ffd2
ldx .zword + 2
jsr printx
lda #44
jsr $ffd2
ldx .zword + 3
jsr printx
lda #44
jsr $ffd2
ldx .zword + 4
jsr printx
lda #44
jsr $ffd2
ldx .zword + 5
jsr printx
jsr newline
}
; find entry in dictionary
lda #0
sta .dict_cnt ; loop counter is 2 bytes
sta .dict_cnt + 1
ldx .dict_entries ; start address of dictionary
lda .dict_entries + 1
jsr set_z_address
!ifdef Z4PLUS {
lda #6
} else {
lda #4
}
sta .zchars_per_entry
.dictionary_loop
; show the dictonary word
!ifdef TRACE_SHOW_DICT_ENTRIES {
;lda .addr
;pha
lda .addr + 1
pha
lda .addr + 2
pha
lda .addr+1
jsr printa
jsr comma
lda .addr+2
jsr printa
;jsr space
jsr print_addr
;jsr space
pla
sta .addr + 2
pla
sta .addr + 1
;pla
;sta .addr
}
; store address to current entry
jsr get_z_address
sta .dictionary_address
stx .dictionary_address + 1
; check if correct entry
ldy #0
sty .num_matching_zchars
.loop_check_entry
jsr read_next_byte
!ifdef TRACE_SHOW_DICT_ENTRIES {
jsr printa
jsr space
}
!ifdef Z4PLUS {
cmp .zword,y
} else {
cmp .zword + 2,y
}
bne .zchars_differ
inc .num_matching_zchars
.zchars_differ
iny
cpy .zchars_per_entry
bne .loop_check_entry
!ifdef TRACE_SHOW_DICT_ENTRIES {
jsr printy
jsr space
lda .num_matching_zchars
jsr printa
jsr newline
}
cpy .num_matching_zchars
beq .found_dict_entry ; we found the correct entry!
; skip the extra data bytes
lda dict_len_entries
sec
!ifdef Z4PLUS {
sbc #6
} else {
sbc #4
}
tay
.dictionary_extra_bytes
jsr read_next_byte
dey
bne .dictionary_extra_bytes
; increase the loop counter
inc .dict_cnt + 1
bne .check_high
inc .dict_cnt
; counter < dict_num_entries?
.check_high
lda dict_num_entries + 1
cmp .dict_cnt + 1
bne .dictionary_loop
lda dict_num_entries
cmp .dict_cnt
bne .dictionary_loop
; no entry found
lda #0
sta .dictionary_address
sta .dictionary_address + 1
sta .is_word_found
.found_dict_entry
; store result into parse_array and exit
ldy .parse_array_index
lda .dictionary_address
sta (parse_array),y
iny
lda .dictionary_address + 1
sta (parse_array),y
iny
rts
.is_word_found !byte 0
.dict_cnt !byte 0,0
.dict_entries !byte 0,0
.triplet_counter !byte 0
.last_char_index !byte 0
.parse_array_index !byte 0
.dictionary_address !byte 0,0
.zword !byte 0,0,0,0,0,0
.zchars_per_entry !byte 0
.num_matching_zchars !byte 0
init_read_text_timer
lda .read_text_time
sta .read_text_time_jiffy
bne +
rts ; no timer
+ ; calculate timer interval in jiffys (1/60 second NTSC, 1/50 second PAL)
lda #0
sta multiplier + 1
sta multiplicand + 1
lda .read_text_time
sta multiplier
lda #5
sta multiplicand ; t*5 for NTSC
lda c64_model
cmp #3
bne .is_ntsc
inc multiplicand ; t*6 for PAL
.is_ntsc
jsr mult16
lda product
sta .read_text_time_jiffy
;jmp update_read_text_timer
; update_read_text_timer must follow below to save a few bytes
update_read_text_timer
; prepare time for next routine call (current time + time_jiffy)
jsr kernel_readtime ; read current time (in jiffys)
clc
adc .read_text_time_jiffy
sta .read_text_jiffy
txa
adc #0
sta .read_text_jiffy + 1
tya
adc #0
sta .read_text_jiffy + 2
rts
read_char
; return: 0,1: return value of routine (false, true)
; any other number: char value
!ifdef BENCHMARK {
jsr benchmark_read_char
cmp #0
beq +
cmp #58 ; colon
bne ++
lda #13
++ rts
+
}
!ifdef Z4PLUS {
; check if time for routine call
; http://www.6502.org/tutorials/compare_beyond.html#2.2
lda .read_text_time
beq .no_timer
jsr kernel_readtime ; read start time (in jiffys) in a,x,y (low to high)
cpy .read_text_jiffy + 2 ; compare high bytes
bcc .no_timer
bne .call_routine
cpx .read_text_jiffy + 1
bcc .no_timer
bne .call_routine
cmp .read_text_jiffy
bcc .no_timer
.call_routine
; current time >= .read_text_jiffy. Time to call routine
jsr turn_off_cursor
; Turn off buffering
lda is_buffered_window
sta .text_tmp
lda #0
sta is_buffered_window
; stx z_operand_value_low_arr
; jsr z_ins_buffer_mode
lda .read_text_routine
sta z_operand_value_high_arr
ldx .read_text_routine + 1
stx z_operand_value_low_arr
lda #z_exe_mode_return_from_read_interrupt
ldx #0
ldy #0
jsr stack_call_routine
; let the interrupt routine start, so we need to rts.
jsr z_execute
; Restore buffering setting
lda .text_tmp
sta is_buffered_window
; Interrupt routine has been executed, with value in word
; z_interrupt_return_value
; set up next time out
jsr update_read_text_timer
; just return the value: 0 or 1 (true or false)
lda z_interrupt_return_value
ora z_interrupt_return_value + 1
beq +
lda #1
+ rts
}
.no_timer
jsr kernel_getchar
cmp #$00
beq read_char
rts
turn_on_cursor
lda #0
sta zp_cursorswitch
rts
turn_off_cursor
lda #$ff
sta zp_cursorswitch
; hide cursor if still visible
ldy zp_screencolumn
lda (zp_screenline),y
and #$7f
sta (zp_screenline),y
rts
read_text
; read line from keyboard into an array (address: a/x)
; See also: http://inform-fiction.org/manual/html/s2.html#p54
; input: a,x, .read_text_time, .read_text_routine
; output: string_array
; side effects: zp_screencolumn, zp_screenline, .read_text_jiffy
; used registers: a,x,y
stx string_array
clc
adc #>story_start
sta string_array + 1
; clear [More] counter
jsr clear_num_rows
; check timer usage
jsr init_read_text_timer
.init_read_text
; turn on blinking cursor
jsr turn_on_cursor
; store start column
lda zp_screencolumn
sta .read_text_startcolumn
ldy #1
!ifdef Z5PLUS {
lda (string_array),y
} else {
lda #0
sta (string_array),y ; default is empty string (0 in pos 1)
}
sta .read_text_offset
.readkey
jsr get_cursor ; x=row, y=column
stx .read_text_cursor
sty .read_text_cursor + 1
jsr read_char
cmp #0
bne +
; timer routine returned false
; did the routine draw something on the screen?
jsr get_cursor ; x=row, y=column
cpy .read_text_cursor + 1
beq .readkey
; text changed, redraw input line
!ifdef Z5PLUS {
ldy #1
lda (string_array),y
tax
.p0 cpx #0
beq .p1
iny
lda (string_array),y
jsr $ffd2
dex
jmp .p0
.p1
} else {
ldy #1
.p0 lda (string_array),y ; default is empty string (0 in pos 1)
beq .p1
jsr $ffd2
iny
jmp .p0
.p1
}
jsr turn_on_cursor
jmp .readkey
+ cmp #1
bne +
; timer routine returned true
; clear input and return
ldy #1
lda #0
sta (string_array),y
lda #0 ; return 0
jmp .read_text_done
+ cmp #$0d
bne +
lda #13 ; return 13
jmp .read_text_done
+ cmp #20
bne +
; allow delete if anything in the buffer
ldy zp_screencolumn
cpy .read_text_startcolumn
beq .readkey
jsr $ffd2 ; kernel_printchar ; print the delete char
jmp .readkey ; don't store in the array
+ ; disallow cursor keys etc
cmp #14
beq .readkey ; big/small
cmp #19
beq .readkey ; home
cmp #145
beq .readkey ; cursor up
cmp #17
beq .readkey ; cursor down
cmp #157
beq .readkey ; cursor left
cmp #29
beq .readkey ; cursor right
; print the allowed char and store in the array
jsr $ffd2; kernel_printchar
pha
lda zp_screencolumn ; compare with size of keybuffer
sec
sbc .read_text_startcolumn
!ifdef Z5PLUS {
clc
adc .read_text_offset
}
ldy #0
cmp (string_array),y ; max characters in array
bcs +
; keybuffer < maxchars
!ifdef Z5PLUS {
iny
sta (string_array),y ; number of characters in the array
}
tay
!ifdef Z5PLUS {
iny
}
pla
; convert to lower case
and #$7f
sta (string_array),y ; store new character in the array
!ifndef Z5PLUS {
iny
lda #0
sta (string_array),y ; store 0 after last char
}
jmp .readkey
+ ; keybuffer >= maxchars
!ifdef Z5PLUS {
lda (string_array),y ; max characters in array
sec
sbc #1
iny
sta (string_array),y ; number of characters in the array (max - 1)
}
pla ; don't save this character (out of bounds)
jmp .readkey
.read_text_done
pha ; return value
; turn off blinking cursor
jsr turn_off_cursor
pla
beq +
jsr $ffd2 ; print final char unless it is 0
+ rts
.read_text_cursor !byte 0,0
.read_text_offset !byte 0
.read_text_startcolumn !byte 0
.read_text_time !byte 0 ; update interval in 1/10 seconds
.read_text_time_jiffy !byte 0 ; update interval in jiffys
.read_text_routine !byte 0, 0 ; called with .read_text_time intervals
.read_text_jiffy !byte 0, 0, 0 ; current time
tokenise_text
; divide read_line input into words and look up them in the dictionary
; input: string_array should be pointing to the text array
; (this will be okay if called immediately after read_text)
; a/x should be the address of the parse array
; input: - string_array
; - .dict_entries: set to default (dict_entries or user dictionary)
; - x,a: address of parse_array
; - y: flag (1 = don't add unknown words to parse_array)
; output: parse_array
; side effects:
; used registers: a,x,y
sty .ignore_unknown_words
stx parse_array
clc
adc #>story_start
sta parse_array + 1
lda #0
sta .numwords ; no words found yet
lda #2
sta .wordoffset ; where to store the next word in parse_array
ldy #0
lda (parse_array),y
sta .maxwords
!ifdef Z5PLUS {
iny
lda (string_array),y ; number of chars in text string
clc
adc #1
sta .textend
ldy #2 ; start position in text
} else {
- iny
lda (string_array),y
bne -
dey
sty .textend
ldy #1 ; start position in text
}
; look over text and find each word
.find_word_loop
; skip initial space
cpy .textend
beq .start_of_word
bcs .parsing_done