-
Notifications
You must be signed in to change notification settings - Fork 0
/
bonus.z80
268 lines (256 loc) · 12.8 KB
/
bonus.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
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
; The bonus logic seems to be the following:
; S (default score): 100 for a 2-match or 200 for a 3-match
; I (initial bonus): 400 or 1000 but this is INSTEAD OF the default score
; (i.e. if you get two 2-matches, you get 400, not 400 + 100 + 100 )
; T (trigger bonus): 600 -> 1000 -> 2000 -> 2000 -> 2000 -> ....
;
; Initial bonus:
; The initial bonus is what you get as the direct result of moving
; a tile into a matching position (including waiting for tiles to fall
; as a direct result of the tile move you just did).
;
; A regular 2-match or 3-match has no bonus
; Two simultaneous 2-matches (i.e. 4 tiles) has 400 bonus
; A 2-match and a 3-match (i.e. 5 tiles) simultanously has 1000 bonus.
; Q: Two simultanous 3-matches (i.e. 6 tiles), or more, has what kind of bonus?
; A: ?
;
; Trigger bonus:
; After a match has been created, and tiles disappear causing tiles to fall
; into a new place creating a new match, the trigger bonus is generated.
; If the new match is a 2-match, you get the current value of T (and T moves up by one)
; i.e. you get 600 bonus (and if another is subsequently triggered from that, you get 1000
; bonus etc))
; If the new match is 3-match, or simultaneously 2 different matches, the
; value of T moves up by one and you get that value of T (and T moves up by one)
;
; If a match triggers a second subsequent match, or a third, etc,
; the subsequent matches trigger 600, 100, 2000 . (regardless of whether
; the first match is 2 simulatenous matches or just a single match)
;
; Q: what happens if a single 2-match triggers a 3-match which in turn triggers a 2-match?
; will that generate a 1000 bonus for the 3-match, and a 2000-bonus for the triggered 2-match
; (i.e. the tier is sticky?) or a 1000 bonus for the 3-match and a 1000-bonus for the triggered
; 2-match (i.e. the extra bonus for the 3-match being 3 (instead of 2) isn't a tier but a one-off)
; A: ?
;
; Q: What happens if you create a simultaneous 2-match AND 3-match?
; Which in turn triggers another 2-match?
; A: Watch https://www.youtube.com/watch?v=Wpy5U2_O55E at 11:15
; The the double match (the 2- and the 3-) generates a 1000 bonus,
; and the final triggered 2-match generates a 600 bonus!
;
; matches generated by a slider, or by a tile falling off a slider
; at protruding wall edges, etc etc all appear to score the same as
; matches created by controller pushing a tile in the regular way
;
; Examples:
; 1. a single 2-match triggers a second 2-match: 600 bonus on the second match
; 2. a single 2-match triggers a second 3-match: 1000 bonus on the second match
; 3. a single 3-match triggers a second 3-match: 1000 bonus on the second match (same as case 2)
; 4. you push a tile (and another tile falls) and two 2-matches are achieved simultanously
; (i.e. a double 2-match): 400 bonus
; 5. a single 2-match triggers a subequent 3-match which in turn triggers a double 2-match
; which in turn triggers yet more single and double 2-matches:
; 1000 bonus (for the triggered 3-match) followed by 2000 bonus for all the subsequent triggered matches
; https://www.youtube.com/watch?v=Wpy5U2_O55E at 8:48
init_bonus:
xor a
ld (bonus_tier), a
ret
ds ALIGN 256
bonus_scores: defw &0000, &0000, &0060, &0100, &0200
calculate_bonus_de:
; on entry:
; d = number of simultaneous matches
; e = number of tiles matches simultaneously
; if tier = 0, then bonus = 400 or 1000 according to e
; and tier goes to 1
; if tier >= 1, we add d to tier,
; and we also add 1 if e > 2
; and bonus = value at that tier
; (tier is capped at 4)
; As a piece of sanity, set the "bonus is displayed"
; flag to FALSE on entry (it gets enabled LATER, several
; frames after we did the calculation))
xor a
ld (bonus_icon_frame), a
ld (bonus_score), a
ld (bonus_score+1), a
; where should the bonus actually showup on-screen..?? which tile, specifically?
; I'm just going to take it from the first match tile in my list. not arcade-accurate
; but it will do for not and we can always change it later
ld hl, match_list
@find_match:
ld a, (hl)
cp 254 ; skip 254 (and we shouldn't find any 255 here because WE KNOW there is a valid match in here)
jr c, @match_found
inc hl
jp @find_match
; a = the tile type, which we can ignore. find the first xy
@match_found:
inc hl
ld a, (hl)
ld (bonus_icon_xy), a
; now start working out the bonus amount according to the rules
ld a, (bonus_tier)
and a
jr z, @initial_bonus
@triggered_bonus:
add d ; a = tier + number of simultaneous matches (at least 1)
ld b, a ; backup
ld a, e
cp 3
ld a, b ; doesn't affect flags
jr c, @+_2_tiles_matched
@_3_or_more_tiles_matched:
inc a
@_2_tiles_matched:
cp 5
jr c, @+tier_less_than_5
ld a, 4
@tier_less_than_5:
ld (bonus_tier), a
ld (bonus_icon), a
ld h, bonus_scores/256
add a, a ; multiply by 2 since bonus_scores table contains dwords
ld l, a
ld c, (hl)
inc hl
ld b, (hl)
ld (bonus_score), bc
; WE ACTUALLY ADD THE SCORE ONLY LATER
ld a, 128 ; record the fact we want to pop up the bonus overlay (later)
ld (bonus_icon_frame), a
ret
@initial_bonus:
; 2 tiles match: score 100 (not regarded as a bonus)
; 3 tiles match: score 200 (not regarded as a bonus)
; 4 tiles match: score 400 (which shows up as BONUS!)
; 5 tiles match: score 1000 (which shows as BONUS!)
; next tier is 1, it seems (from gameplay), regardless
; of how many matches in initial bonus
ld a, 1
ld (bonus_tier), a
ld a, e
cp 3
jr c, @+_2_tiles_matched
cp 4
jr c, @+_3_tiles_matched
cp 5
jr c, @+_4_tiles_matched
@_5_or_more_tiles_matched:
ld bc, &0100
ld (bonus_score), bc
; WE ACTUALLY ADD THE SCORE ONLY LATER
ld a, 3
ld (bonus_icon), a ; bonus icon[3] is 1000
ld a, 128 ; record the fact we want to pop up the bonus overlay (later)
ld (bonus_icon_frame), a
ret
@_4_tiles_matched:
ld bc, &0040
ld (bonus_score), bc
; WE ACTUALLY ADD THE SCORE ONLY LATER
ld a, 1
ld (bonus_icon), a ; bonus icon[1] is 400
ld a, 128 ; record the fact we want to pop up the bonus overlay (later)
ld (bonus_icon_frame), a
ret
@_2_tiles_matched:
; no bonus ;-) but still score
ld bc, &0010
ld (bonus_score), bc
xor a ; no bonus overlay
ld (bonus_icon_frame), a
; WE ACTUALLY ADD THE SCORE ONLY LATER
ret
@_3_tiles_matched:
; no bonus ;-) but still score
ld bc, &0020
ld (bonus_score), bc
xor a ; no bonus overlay
ld (bonus_icon_frame), a
; WE ACTUALLY ADD THE SCORE ONLY LATER
ret
render_bonus:
; show the 'bonus' overlay, if we're supposed to
; bonus_icon_frame will be >= 1 (if we're supposed to)
; top bit is magic, means "there is a bonus, it's ready to show"
; so ignore that top bit
ld a, (bonus_icon_frame)
and 127
ret z ; no bonus so do nothing
;
inc a
cp 34
jr nz, @+still_going ; A != 34 (frame != 33 i.e. frame 1-32)
xor a
ld (bonus_icon_frame), a
ret
@still_going:
ld (bonus_icon_frame), a
ld a, (bonus_icon_xy)
ld c, a
call grid_xy_in_C_to_screen_de
; the bonus icon placement goes up by one pixel row every two frames
; so divide the frame by 2, and if the low bit is 1 then subtract 128 from DE;
; and then divide by 2 again (with the value in A being subtracted from D)
; maybe better ways to do this but I divide by 4, and test carry instead
ld a, (bonus_icon_frame)
sub 2 ; because if everything else is working, then bonus_icon_frame already == 2 on the first frame.
srl a
srl a
jr nc, @+_skip_adjust_for_odd
; maybe better ways to do this ..!
set 7, e
dec d
@_skip_adjust_for_odd:
neg ; we're subtracting A from D, so we're adding -A to D
add d ; subtract the "rising y" offset
ld d, a
; now point HL to the correct bitmap (a combination of
; the bonus_icon AND the frame count, due to the colour change!)
; each bonus tile is 32x16 pixels * 2 (due to mask) = 16x16*2 bytes = 512 * bonus_icon
; but then add another (32x16x2)*4 = 2048 bytes for each colour change (which happens every 8 frames)
; so 512 * bonus_icon + 2048 * (frame_count // 8)
; H will be equal to the above divided by 256 (L will be 0)
; so H needs to be 2 * bonus_icon + 8 * (frame_count // 8)
; = 2 * bonus_icon + (frame_count AND 0xf8))
ld a, (bonus_icon_frame)
sub 2 ; same reason as before above
and 0xf8
ld h, a
ld a, (bonus_icon)
dec a ; bonus_icon (0) means nothing
add a, a
add h
add bonus_icon_bitmaps/256
ld h,a
ld l,0
call draw_masked_bitmap_32x16_hl_at_de
; also: these locations are going to be dirty next frame
; TODO optimise. we definitely should not need to redraw the whole tile
; and we're also drawing (bits of) these already anyway due to the destruction
; animation. so, probably want to avoid marking matched tiles as dirty?
ld a, (bonus_icon_xy)
call push_dirty_tile
inc a ; since bonus icon is 2 tiles wide
call push_dirty_tile
sub 16 ; since bonus icon moves upwards overwriting the tiles vertically above this one
call push_dirty_tile
dec a ; since bonus icon is 2 tiles wide
call push_dirty_tile
ret
trigger_bonus_overlay:
; External code in the game loop will call this when
; it's ready to show the bonus overlay
; This doesn't actually mean there IS a bonus.
; if there isn't a bonus, we should do nothing still.
ld a, (bonus_icon_frame)
and 128
ret z ; there is "no bonus" ergo nothing to do here
ld a, 1 ; set flag to say 'yep starting drawing the bonus overlay now please'
; (this flag is simply the frame counter for the animation)
ld (bonus_icon_frame), a
ret