-
Notifications
You must be signed in to change notification settings - Fork 0
/
clock.z80
237 lines (213 loc) · 8.11 KB
/
clock.z80
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
clock_tick_frame: defb 0
is_panic: defb 0
panic_flash_counter: defb 0
clock_color: defb 0
NO_PANIC: equ 0
MILD_PANIC: equ 1
FULL_PANIC: equ 2
init_clock:
; clock_tick_frame counts from 49 (or 59...) to 0 (inclusive).
; When counter==0, update() will reset it to FPS-1 .
; so when counter == FPS-1, draw() will redraw the clock.
; Of course, update() will also subtract 1 second from the remaining time when this happens -
; but we want to force a redraw of clock on the first frame, without subtracting 1 second.
;
; So initialize tick frame to FPS , so that update() will decrement it by 1, and draw() will see
; that the counter == FPS-1
ld a, FRAMES_PER_CLOCK_SECOND
ld (clock_tick_frame), a
xor a
ld (panic_flash_counter), a
ld (is_panic), a
ld (clock_color), a
ret
draw_clock:
; if we're in full panic mode, we'll actually redraw the time every 4 frames
; (as well as if clock_frame == 0)
ld a, (is_panic)
cp FULL_PANIC
jp z, @check_panic_clock
; not a panic mode, so just redraw clock when frame counter resets
ld a, (clock_tick_frame)
cp FRAMES_PER_CLOCK_SECOND-1
ret nz
ld a, (clock_color)
ld c, a
@_draw_clock_main:
; minutes
ld a, (clock_min_bcd)
; top minute decimal is ignored
and 15
push bc ; color
ld de, CLOCK_Y_OFFSET*128
pop bc ; color
push bc ; color
call fatnum_digit_a_variant_c_xy_de
; seconds
ld a, (clock_sec_bcd)
; top second decimal
and 240
rrca
rrca
rrca
rrca
ld de, CLOCK_Y_OFFSET*128 + 12 ; y*128+(x/2)
pop bc ; color
push bc ; color
call fatnum_digit_a_variant_c_xy_de
; bottom second decimal
ld a, (clock_sec_bcd)
and 15
ld de, CLOCK_Y_OFFSET*128 + 20 ; y*128+(x/2)
pop bc ; color
call fatnum_digit_a_variant_c_xy_de ; TODO optimize maybe JP rather than call+ret?
ret
update_clock:
ld a, (clock_tick_frame)
dec a
ld (clock_tick_frame), a
; If we are now < 0 then a full second has elapsed
; (if we are not < 0, then we're between second ticks
; and we've done all the updates we need to do)
ret p ; not negative i.e. not < 0
ld a, FRAMES_PER_CLOCK_SECOND-1
ld (clock_tick_frame), a
@next_sec:
; decrement number of remaining seconds
ld a, (clock_sec_bcd)
sub 1
daa
; did we underflow (0 -> 99) ?
jr c, @+next_min
; no? ok, just save back the number of seconds
ld (clock_sec_bcd), a
; quick check - are we in panic mode? or indeed, run out of time
; time > 0:30 : normal
; time <= 0:30 and time > 0:10 : mild panic
; time <= 0:10 : full panic
; time = 0:00 : time over
ld a, (clock_min_bcd)
and a
ret nz ; time >= 1:00 remaining, all normal
ld a, (clock_sec_bcd)
and a
jr z, @time_over
cp 0x31 ; bcd
ret nc ; time >= 0:30 remaining
; either mild panic or full panic!
; assume mild panic
cp 0x11 ; bcd
jr nc, @mild_panic ; 0:11 <= time <= 0:30 remaining, mild panic only
ld (is_panic), a
cp FULL_PANIC
call nz, @initiate_full_panic
ld a, FULL_PANIC
ld (is_panic), a ; time <= 0:10 remaining!! panic!!
xor a
ld (clock_color), a
ret
@mild_panic:
; <= 30 seconds remaining. red clock!
ld (is_panic), a
cp MILD_PANIC
call nz, @initiate_mild_panic
ld a, MILD_PANIC
ld (is_panic), a
ld a, 1
ld (clock_color), a
ret
@next_min:
ld a, (clock_min_bcd)
sub 1
daa
ld (clock_min_bcd), a
ld a, 0x59 ; bcd
ld (clock_sec_bcd), a
ret
@time_over:
ld a, 3 ; 3 = failed (time over) (if there are retries, this will be prompted, otherwise game over)
ld (level_clear_process), a
ret
@check_panic_clock:
; called each frame to render a flashing clock (<10 seconds remaining)
ld a, (clock_tick_frame)
cp FRAMES_PER_CLOCK_SECOND-1
jr nz, @+flashing
; not flashing, but need to redraw anyway
ld a, (panic_flash_counter)
inc a
ld (panic_flash_counter), a
jp @draw_panic_clock
@flashing:
; only redraw every 4 frames (color change)
ld a, (panic_flash_counter)
inc a
ld (panic_flash_counter), a
and 3
ret nz ; this is not frame 0 (it's frame 1/2/3) so do NOT redraw clock
; get the color (0 or 1) from the 2th bit of the counter
@draw_panic_clock:
ld a, (panic_flash_counter)
rrca
rrca
and 1
ld c, a
jp @_draw_clock_main
@initiate_mild_panic:
; called (once) when clock hits 30s remaining
; - trigger sfx / music change
ret
@initiate_full_panic:
; called (once) when clock hits 10s remaining
; - trigger sfx / music change
ld a, 24 ; just some number
ld (glint_period), a
ret
time_over:
; called (from game loop) when time is up
ld hl, message.TIME_OVER
ld de, 128*TIMEOVER_Y_OFFSET + TIMEOVER_X_OFFSET
ld c, 0x99 ; YELLOW
call print_text_hl_de
ld hl, message.CONTINUE
ld de, 128*TIMEOVER_CONTINUE_Y_OFFSET + TIMEOVER_CONTINUE_X_OFFSET
ld c, 0x11 ; WHITE
call print_text_hl_de
; you can insert another coin to continue
; 10 second "continue" timer
; ...
ld b, 10
ld c, 0x11 ; WHITE
@countdown:
push bc
ld a, b
cp 10
jr c, @only_one_digit
ld a, 1
ld de, 128*TIMEOVER_CONTINUE_SECONDS_Y_OFFSET + TIMEOVER_CONTINUE_SECONDS_X_OFFSET
call digit_a_xy_de
@second_digit:
pop bc
push bc
ld a, b
add a, 0
daa
and 15
ld de, 128*TIMEOVER_CONTINUE_SECONDS_Y_OFFSET + TIMEOVER_CONTINUE_SECONDS_X_OFFSET + 4
call digit_a_xy_de
ld b, FPS
call wait_b
pop bc
djnz @-countdown
ret
@only_one_digit:
ld de, 128*TIMEOVER_CONTINUE_SECONDS_Y_OFFSET + TIMEOVER_CONTINUE_SECONDS_X_OFFSET
ld a, 0x00 ; BLACK
call fillrect_8x8_de_colorbyte_a
jp @second_digit
message.TIME_OVER: defm "TIME OVER"
defb 0
message.CONTINUE: defm "CONTINUE?"
defb 0
message.SPACE: defm " "
defb 0