summaryrefslogtreecommitdiff
path: root/src/engine/link/card_pop.asm
blob: 5f809ef42632e594caf16d94f7fecc73ae522564 (plain)
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
_DoCardPop:
; loads scene for Card Pop! screen
; then checks if console is SGB
; and issues an error message in case it is
	call SetSpriteAnimationsAsVBlankFunction
	ld a,SCENE_CARD_POP
	lb bc, 0, 0
	call LoadScene
	ldtx hl, AreYouBothReadyToCardPopText
	call PrintScrollableText_NoTextBoxLabel
	call RestoreVBlankFunction
	ldtx hl, CardPopCannotBePlayedWithTheGameBoyText
	ld a, [wConsole]
	cp CONSOLE_SGB
	jr z, .error

; initiate the communications
	call PauseSong
	call SetSpriteAnimationsAsVBlankFunction
	ld a, SCENE_GAMEBOY_LINK_CONNECTING
	lb bc, 0, 0
	call LoadScene
	ldtx hl, PositionGameBoyColorsAndPressAButtonText
	call DrawWideTextBox_PrintText
	call EnableLCD
	call HandleCardPopCommunications
	push af
	push hl
	call ClearRP
	call RestoreVBlankFunction
	pop hl
	pop af
	jr c, .error

; show the received card detail page
; and play the corresponding song
	ld a, [wLoadedCard1ID]
	call AddCardToCollectionAndUpdateAlbumProgress
	ld hl, wLoadedCard1Name
	ld a, [hli]
	ld h, [hl]
	ld l, a
	call LoadTxRam2
	ld a, PLAYER_TURN
	ldh [hWhoseTurn], a
	ld a, SFX_5D
	call PlaySFX
.wait_sfx
	call AssertSFXFinished
	or a
	jr nz, .wait_sfx
	ld a, [wCardPopCardObtainSong]
	call PlaySong
	ldtx hl, ReceivedThroughCardPopText
	bank1call _DisplayCardDetailScreen
	call ResumeSong
	lb de, $38, $9f
	call SetupText
	bank1call OpenCardPage_FromHand
	ret

.error
; show Card Pop! error scene
; and print text in hl
	push hl
	call ResumeSong
	call SetSpriteAnimationsAsVBlankFunction
	ld a, SCENE_CARD_POP_ERROR
	lb bc, 0, 0
	call LoadScene
	pop hl
	call PrintScrollableText_NoTextBoxLabel
	call RestoreVBlankFunction
	ret

; handles all communications to the other device to do Card Pop!
; returns carry if Card Pop! is unsuccessful
; and returns in hl the corresponding error text ID
HandleCardPopCommunications:
; copy CardPopNameList from SRAM to WRAM
	call EnableSRAM
	ld hl, sCardPopNameList
	ld de, wCardPopNameList
	ld bc, CARDPOP_NAME_LIST_SIZE
	call CopyDataHLtoDE
	call DisableSRAM

	ld a, IRPARAM_CARD_POP
	call InitIRCommunications
.asm_19cc9
	call TryReceiveIRRequest ; receive request
	jr nc, .asm_19d05
	bit 1, a
	jr nz, .fail
	call TrySendIRRequest ; send request
	jr c, .asm_19cc9

; do the player name search, then transmit the result
	call ExchangeIRCommunicationParameters
	jr c, .fail
	ld hl, wCardPopNameList
	ld de, wOtherPlayerCardPopNameList
	ld c, 0 ; $100 bytes = CARDPOP_NAME_LIST_SIZE
	call RequestDataTransmissionThroughIR
	jr c, .fail
	call LookUpNameInCardPopNameList
	ld hl, wCardPopNameSearchResult
	ld de, wCardPopNameSearchResult
	ld c, 1
	call RequestDataReceivalThroughIR
	jr c, .fail
	call SetIRCommunicationErrorCode_NoError
	jr c, .fail
	call ExecuteReceivedIRCommands
	jr c, .fail
	jr .check_search_result

.asm_19d05
	call ExecuteReceivedIRCommands
	ld a, [wIRCommunicationErrorCode]
	or a
	jr nz, .fail
	call RequestCloseIRCommunication
	jr c, .fail

.check_search_result
	ld a, [wCardPopNameSearchResult]
	or a
	jr z, .success
	; not $00, means the name was found in the list
	ldtx hl, CannotCardPopWithFriendPreviouslyPoppedWithText
	scf
	ret

.success
	call DecideCardToReceiveFromCardPop

; increment number of times Card Pop! was done
; and write the other player's name to sCardPopNameList
; the spot where this is written in the list is derived
; from the lower nybble of sTotalCardPopsDone
; that means that after 16 Card Pop!, the older
; names start to get overwritten
	call EnableSRAM
	ld hl, sTotalCardPopsDone
	ld a, [hl]
	inc [hl]
	and $0f
	swap a ; *NAME_BUFFER_LENGTH
	ld l, a
	ld h, $0
	ld de, sCardPopNameList
	add hl, de
	ld de, wNameBuffer
	ld c, NAME_BUFFER_LENGTH
.loop_write_name
	ld a, [de]
	inc de
	ld [hli], a
	dec c
	jr nz, .loop_write_name
	call DisableSRAM
	or a
	ret

.fail
	ldtx hl, ThePopWasntSuccessfulText
	scf
	ret

; looks up the name in wNameBuffer in wCardPopNameList
; used to know whether this save file has done Card Pop!
; with the other player already
; returns carry and wCardPopNameSearchResult = $ff if the name was found;
; returns no carry and wCardPopNameSearchResult = $00 otherwise
LookUpNameInCardPopNameList:
; searches for other player's name in this game's name list
	ld hl, wCardPopNameList
	ld c, CARDPOP_NAME_LIST_MAX_ELEMS
.loop_own_card_pop_name_list
	push hl
	ld de, wNameBuffer
	call .CompareNames
	pop hl
	jr nc, .found_name
	ld de, NAME_BUFFER_LENGTH
	add hl, de
	dec c
	jr nz, .loop_own_card_pop_name_list

; name was not found in wCardPopNameList

; searches for this player's name in the other game's name list
; this is useless since it discards the result from the name comparisons
; as a result this loop will always return no carry
	call EnableSRAM
	ld hl, wOtherPlayerCardPopNameList
	ld c, CARDPOP_NAME_LIST_MAX_ELEMS
.loop_other_card_pop_name_list
	push hl
	ld de, sPlayerName
	call .CompareNames ; discards result from comparison
	pop hl
	ld de, NAME_BUFFER_LENGTH
	add hl, de
	dec c
	jr nz, .loop_other_card_pop_name_list
	xor a
	jr .no_carry

.found_name
	ld a, $ff
	scf
.no_carry
	call DisableSRAM
	ld [wCardPopNameSearchResult], a ; $00 if name was not found, $ff otherwise
	ret

; compares names in hl and de
; if they are different, return carry
.CompareNames
	ld b, NAME_BUFFER_LENGTH
.loop_chars
	ld a, [de]
	inc de
	cp [hl]
	jr nz, .not_same
	inc hl
	dec b
	jr nz, .loop_chars
	or a
	ret
.not_same
	scf
	ret

; loads in wLoadedCard1 a random card to be received
; this selection is done based on the rarity that is
; decided from the names of both participants
; the card will always be a Pokemon card that is not
; from a Promotional set, with the exception
; of Venusaur1 and Mew2
; output:
; - e = card ID chosen
DecideCardToReceiveFromCardPop:
	ld a, PLAYER_TURN
	ldh [hWhoseTurn], a
	call EnableSRAM
	ld hl, sPlayerName
	call CalculateNameHash
	call DisableSRAM
	push de
	ld hl, wNameBuffer
	call CalculateNameHash
	pop bc

; de = other player's name  hash
; bc = this player's name hash

; updates RNG values to subtraction of these two hashes
	ld hl, wRNG1
	ld a, b
	sub d
	ld d, a ; b - d
	ld [hli], a ; wRNG1
	ld a, c
	sub e
	ld e, a ; c - e
	ld [hli], a ; wRNG2
	ld [hl], $0 ; wRNGCounter

; depending on the values obtained from the hashes,
; determine which rarity card to give to the player
; along with the song to play with each rarity
; the probabilities of each possibility can be calculated
; as follows (given 2 random player names):
; 101/256 ~ 39% for Circle
;  90/256 ~ 35% for Diamond
;  63/256 ~ 25% for Star
;   1/256 ~ .4% for Venusaur1 or Mew2
	ld a, e
	cp 5
	jr z, .venusaur1_or_mew2
	cp 64
	jr c, .star_rarity ; < 64
	cp 154
	jr c, .diamond_rarity ; < 154
	; >= 154

	ld a, MUSIC_BOOSTER_PACK
	ld b, CIRCLE
	jr .got_rarity
.diamond_rarity
	ld a, MUSIC_BOOSTER_PACK
	ld b, DIAMOND
	jr .got_rarity
.star_rarity
	ld a, MUSIC_MATCH_VICTORY
	ld b, STAR
.got_rarity
	ld [wCardPopCardObtainSong], a
	ld a, b
	call CreateCardPopCandidateList
	; shuffle candidates and pick first from list
	call ShuffleCards
	ld a, [hl]
	ld e, a
.got_card_id
	ld d, $0
	call LoadCardDataToBuffer1_FromCardID
	ld a, e
	ret

.venusaur1_or_mew2
; choose either Venusaur1 or Mew2
; depending on whether the lower
; bit of d is unset or set, respectively
	ld a, MUSIC_MEDAL
	ld [wCardPopCardObtainSong], a
	ld e, VENUSAUR1
	ld a, d
	and $1 ; get lower bit
	jr z, .got_card_id
	ld e, MEW2
	jr .got_card_id

; lists in wCardPopCardCandidates all cards that:
; - are Pokemon cards;
; - have the same rarity as input register a;
; - are not from Promotional set.
; input:
; - a = card rarity
; output:
; - a = number of candidates
CreateCardPopCandidateList:
	ld hl, wPlayerDeck
	push hl
	push de
	push bc
	ld b, a

	lb de, 0, GRASS_ENERGY
.loop_card_ids
	call LoadCardDataToBuffer1_FromCardID
	jr c, .count ; no more card IDs
	ld a, [wLoadedCard1Type]
	and TYPE_ENERGY
	jr nz, .next_card_id ; not Pokemon card
	ld a, [wLoadedCard1Rarity]
	cp b
	jr nz, .next_card_id ; not equal rarity
	ld a, [wLoadedCard1Set]
	and $f0
	cp PROMOTIONAL
	jr z, .next_card_id ; no promos
	ld [hl], e
	inc hl
.next_card_id
	inc de
	jr .loop_card_ids

; count all the cards that were listed
; and return it in a
.count
	ld [hl], $00 ; invalid card ID as end of list
	ld hl, wPlayerDeck
	ld c, -1
.loop_count
	inc c
	ld a, [hli]
	or a
	jr nz, .loop_count
	ld a, c
	pop bc
	pop de
	pop hl
	ret

; creates a unique two-byte hash from the name given in hl
; the low byte is calculated by simply adding up all characters
; the high byte is calculated by xoring all characters together
; input:
; - hl = points to the start of the name buffer
; output:
; - de = hash
CalculateNameHash:
	ld c, NAME_BUFFER_LENGTH
	ld de, $0
.loop
	ld a, e
	add [hl]
	ld e, a
	ld a, d
	xor [hl]
	ld d, a
	inc hl
	dec c
	jr nz, .loop
	ret