shithub: pokered

Download patch

ref: 2e67759f9daf0d833d21bac3aea38444d0578974
parent: c82b5f5e3d62c585bb4e842e039107947ab19ac6
author: YamaArashi <[email protected]>
date: Tue Jan 31 18:43:28 EST 2012

disasm of some battle animation code

hg-commit-id: 5c2a07265f14


--- a/constants.asm
+++ b/constants.asm
@@ -156,6 +156,8 @@
 
 W_WHICHTRADE EQU $CD3D ; which entry from TradeMons to select
 
+W_ANIMSOUNDID EQU $CF07 ; sound ID during battle animations
+
 W_WHICHPOKEMON EQU $CF92 ; which pokemon you selected
 
 W_WALKCOUNTER EQU $CFC5 ; walk animation counter
@@ -269,6 +271,39 @@
 
 W_NUMHITS EQU $D074 ; number of hits in attacks like Doubleslap, etc.
 
+W_ANIMATIONID EQU $D07C ; ID number of the current battle animation
+
+; base coordinates of frame block
+W_BASECOORDX EQU $D081
+W_BASECOORDY EQU $D082
+
+W_FBTILECOUNTER EQU $D084 ; counts how many tiles of the current frame block have been drawn
+
+W_SUBANIMFRAMEDELAY EQU $D086 ; duration of each frame of the current subanimation in terms of screen refreshes
+
+W_SUBANIMSIZE EQU $D087 ; number of frame blocks in the current subanimation
+
+W_NUMFBTILES EQU $D089 ; number of tiles in current battle animation frame block
+
+W_SUBANIMTRANSFORM EQU $D08B ; controls what transformations are applied to the subanimation
+; 01: flip horizontally and vertically
+; 02: flip horizontally and translate downwards 40 pixels
+; 03: translate base coordinates of frame blocks, but don't change their internal coordinates or flip their tiles
+; 04: reverse the subanimation
+
+W_SUBANIMADDRPTR EQU $D094 ; the address _of the address_ of the current subanimation entry (2 bytes)
+
+W_SUBANIMSUBENTRYADDR EQU $D096 ; the address of the current subentry of the current subanimation (2 bytes)
+
+W_FBDESTADDR EQU $D09C ; current destination address in OAM for frame blocks (2 bytes, big endian)
+
+W_FBMODE EQU $D09E ; controls how the frame blocks are put together to form frames
+; specifically, after finishing drawing the frame block, the frame block's mode determines what happens
+; 00: clean OAM buffer and delay
+; 02: move onto the next frame block with no delay and no cleaning OAM buffer
+; 03: delay, but don't clean OAM buffer
+; 04: delay, without cleaning OAM buffer, and do not advance [W_FBDESTADDR], so that the next frame block will overwrite this one
+
 W_DAMAGE EQU $D0D7
 
 ; List type
@@ -833,6 +868,9 @@
 rWX EQU $FF4B
 rIE EQU $FFFF
 
+; OAM attribute flags
+OAM_HFLIP EQU %00100000 ; horizontal flip
+OAM_VFLIP EQU %01000000 ; vertical flip
 
 ; pokemon name constants
 RHYDON     EQU $01
--- a/main.asm
+++ b/main.asm
@@ -63774,43 +63774,205 @@
 
 SECTION "bank1E",DATA,BANK[$1E]
 
-INCBIN "baserom.gbc",$78000,$F1
+; Draws a "frame block". Frame blocks are blocks of tiles that are put
+; together to form frames in battle animations.
+DrawFrameBlock: ; 4000
+	ld l,c
+	ld h,b
+	ld a,[hli]
+	ld [W_NUMFBTILES],a
+	ld a,[W_FBDESTADDR + 1]
+	ld e,a
+	ld a,[W_FBDESTADDR]
+	ld d,a
+	xor a
+	ld [W_FBTILECOUNTER],a ; loop counter
+.loop\@
+	ld a,[W_FBTILECOUNTER]
+	inc a
+	ld [W_FBTILECOUNTER],a
+	ld a,[W_SUBANIMTRANSFORM]
+	dec a
+	jr z,.flipHorizontalAndVertical\@   ; 1
+	dec a
+	jp z,.flipHorizontalTranslateDown\@ ; 2
+	dec a
+	jr z,.flipBaseCoords\@              ; 3
+.noTransformation\@
+	ld a,[W_BASECOORDY]
+	add [hl]
+	ld [de],a ; store Y
+	inc hl
+	inc de
+	ld a,[W_BASECOORDX]
+	jr .finishCopying\@
+.flipBaseCoords\@
+	ld a,[W_BASECOORDY]
+	ld b,a
+	ld a,136
+	sub b ; flip Y base coordinate
+	add [hl] ; Y offset
+	ld [de],a ; store Y
+	inc hl
+	inc de
+	ld a,[W_BASECOORDX]
+	ld b,a
+	ld a,168
+	sub b ; flip X base coordinate
+.finishCopying\@ ; finish copying values to OAM (when [W_SUBANIMTRANSFORM] not 1 or 2)
+	add [hl] ; X offset
+	ld [de],a ; store X
+	inc hl
+	inc de
+	ld a,[hli]
+	add a,$31 ; base tile ID for battle animations
+	ld [de],a ; store tile ID
+	inc de
+	ld a,[hli]
+	ld [de],a ; store flags
+	inc de
+	jp .nextTile\@
+.flipHorizontalAndVertical\@
+	ld a,[W_BASECOORDY]
+	add [hl] ; Y offset
+	ld b,a
+	ld a,136
+	sub b ; flip Y coordinate
+	ld [de],a ; store Y
+	inc hl
+	inc de
+	ld a,[W_BASECOORDX]
+	add [hl] ; X offset
+	ld b,a
+	ld a,168
+	sub b ; flip X coordinate
+	ld [de],a ; store X
+	inc hl
+	inc de
+	ld a,[hli]
+	add a,$31 ; base tile ID for battle animations
+	ld [de],a ; store tile ID
+	inc de
+; toggle horizontal and vertical flip
+	ld a,[hli] ; flags
+	and a
+	ld b,OAM_VFLIP | OAM_HFLIP
+	jr z,.storeFlags1\@
+	cp a,OAM_HFLIP
+	ld b,OAM_VFLIP
+	jr z,.storeFlags1\@
+	cp a,OAM_VFLIP
+	ld b,OAM_HFLIP
+	jr z,.storeFlags1\@
+	ld b,0
+.storeFlags1\@
+	ld a,b
+	ld [de],a
+	inc de
+	jp .nextTile\@
+.flipHorizontalTranslateDown\@
+	ld a,[W_BASECOORDY]
+	add [hl]
+	add a,40 ; translate Y coordinate downwards
+	ld [de],a ; store Y
+	inc hl
+	inc de
+	ld a,[W_BASECOORDX]
+	add [hl]
+	ld b,a
+	ld a,168
+	sub b ; flip X coordinate
+	ld [de],a ; store X
+	inc hl
+	inc de
+	ld a,[hli]
+	add a,$31 ; base tile ID for battle animations
+	ld [de],a ; store tile ID
+	inc de
+	ld a,[hli]
+	bit 5,a ; is horizontal flip enabled?
+	jr nz,.disableHorizontalFlip\@
+.enableHorizontalFlip\@
+	set 5,a
+	jr .storeFlags2\@
+.disableHorizontalFlip\@
+	res 5,a
+.storeFlags2\@
+	ld [de],a
+	inc de
+.nextTile\@
+	ld a,[W_FBTILECOUNTER]
+	ld c,a
+	ld a,[W_NUMFBTILES]
+	cp c
+	jp nz,.loop\@ ; go back up if there are more tiles to draw
+.afterDrawingTiles\@
+	ld a,[W_FBMODE]
+	cp a,2
+	jr z,.advanceFrameBlockDestAddr\@; skip delay and don't clean OAM buffer
+	ld a,[W_SUBANIMFRAMEDELAY]
+	ld c,a
+	call DelayFrames
+	ld a,[W_FBMODE]
+	cp a,3
+	jr z,.advanceFrameBlockDestAddr\@ ; skip cleaning OAM buffer
+	cp a,4
+	jr z,.done\@ ; skip cleaning OAM buffer and don't advance the frame block destination address
+	ld a,[W_ANIMATIONID]
+	cp a,GROWL
+	jr z,.resetFrameBlockDestAddr\@
+	call AnimationCleanOAM
+.resetFrameBlockDestAddr\@
+	ld hl,$C300 ; OAM buffer
+	ld a,l
+	ld [W_FBDESTADDR + 1],a
+	ld a,h
+	ld [W_FBDESTADDR],a ; set destination address to beginning of OAM buffer
+	ret
+.advanceFrameBlockDestAddr\@
+	ld a,e
+	ld [W_FBDESTADDR + 1],a
+	ld a,d
+	ld [W_FBDESTADDR],a
+.done\@
+	ret
 
 PlayAnimation: ; 40F1
 	xor a
 	ld [$FF8B],a
-	ld [$D08B],a
-	ld a,[$D07C] ; get animation number
+	ld [W_SUBANIMTRANSFORM],a
+	ld a,[W_ANIMATIONID] ; get animation number
 	dec a
 	ld l,a
 	ld h,0
 	add hl,hl
-	ld de,$607D
+	ld de,$607D ; animation command stream pointers
 	add hl,de
 	ld a,[hli]
 	ld h,[hl]
 	ld l,a
-.next7\@
+.animationLoop\@
 	ld a,[hli]
 	cp a,$FF
 	jr z,.AnimationOver\@
-	cp a,$C0 ; is this animation for a monster onscreen?
-	jr c,.next2\@
+	cp a,$C0 ; is this subanimation or a special effect?
+	jr c,.playSubanimation\@
+.doSpecialEffect\@
 	ld c,a
-	ld de,$50DA
-.next4\@
+	ld de,SpecialEffectPointers
+.searchSpecialEffectTableLoop\@
 	ld a,[de]
 	cp c
-	jr z,.next3\@
+	jr z,.foundMatch\@
 	inc de
 	inc de
 	inc de
-	jr .next4\@
-.next3\@
+	jr .searchSpecialEffectTableLoop\@
+.foundMatch\@
 	ld a,[hli]
-	cp a,$FF
-	jr z,.next5\@
-	ld [$CF07],a
+	cp a,$FF ; is there a sound to play?
+	jr z,.skipPlayingSound\@
+	ld [$CF07],a ; store sound
 	push hl
 	push de
 	call $586F
@@ -63817,7 +63979,7 @@
 	call $23B1
 	pop de
 	pop hl
-.next5\@
+.skipPlayingSound\@
 	push hl
 	inc de
 	ld a,[de]
@@ -63825,33 +63987,33 @@
 	inc de
 	ld a,[de]
 	ld h,a
-	ld de,.next6\@
+	ld de,.nextAnimationCommand\@
 	push de
-	jp [hl]
-.next2\@
+	jp [hl] ; jump to special effect function
+.playSubanimation\@
 	ld c,a
-	and a,$3F
-	ld [$D086],a
+	and a,63
+	ld [W_SUBANIMFRAMEDELAY],a
 	xor a
 	sla c
 	rla
 	sla c
 	rla
-	ld [$D09F],a
-	ld a,[hli]
-	ld [$CF07],a
-	ld a,[hli]
+	ld [$D09F],a ; tile select
+	ld a,[hli] ; sound
+	ld [$CF07],a ; store sound
+	ld a,[hli] ; subanimation ID
 	ld c,l
 	ld b,h
 	ld l,a
 	ld h,0
 	add hl,hl
-	ld de,$676D
+	ld de,$676D ; subanimation pointer table
 	add hl,de
 	ld a,l
-	ld [$D094],a
+	ld [W_SUBANIMADDRPTR],a
 	ld a,h
-	ld [$D095],a
+	ld [W_SUBANIMADDRPTR + 1],a
 	ld l,c
 	ld h,b
 	push hl
@@ -63859,19 +64021,127 @@
 	push af
 	ld a,[$CC79]
 	ld [rOBP0],a
-	call $41D2
-	call $417C
-	call RealPlayAnimation
+	call LoadAnimationTileset
+	call LoadSubanimation
+	call PlaySubanimation
 	pop af
 	ld [rOBP0],a
-.next6\@
+.nextAnimationCommand\@
 	pop hl
-	jr .next7\@
+	jr .animationLoop\@
 .AnimationOver\@ ; 417B
 	ret
 
-INCBIN "baserom.gbc",$7817C,$78BDE - $7817C
+LoadSubanimation: ; 417C
+	ld a,[W_SUBANIMADDRPTR + 1]
+	ld h,a
+	ld a,[W_SUBANIMADDRPTR]
+	ld l,a
+	ld a,[hli]
+	ld e,a
+	ld a,[hl]
+	ld d,a ; de = address of subanimation
+	ld a,[de]
+	ld b,a
+	and a,31
+	ld [W_SUBANIMSIZE],a ; number of frame blocks
+	ld a,b
+	and a,%11100000
+	cp a,5 << 5 ; is subanimation type 5?
+	jr nz,.isNotType5\@
+.isType5\@
+	call GetSubanimationTransform2
+	jr .saveTransformation\@
+.isNotType5\@
+	call GetSubanimationTransform1
+.saveTransformation\@
+; place the upper 3 bits of a into bits 0-2 of a before storing
+	srl a
+	swap a
+	ld [W_SUBANIMTRANSFORM],a
+	cp a,4 ; is the animation reversed?
+	ld hl,0
+	jr nz,.storeSubentryAddr\@
+; if the animation is reversed, then place the initial subentry address at the end of the list of subentries
+	ld a,[W_SUBANIMSIZE]
+	dec a
+	ld bc,3
+.loop\@
+	add hl,bc
+	dec a
+	jr nz,.loop\@
+.storeSubentryAddr\@
+	inc de
+	add hl,de
+	ld a,l
+	ld [W_SUBANIMSUBENTRYADDR],a
+	ld a,h
+	ld [W_SUBANIMSUBENTRYADDR + 1],a
+	ret
 
+; called if the subanimation type is not 5
+; sets the transform to 0 (i.e. no transform) if it's the player's turn
+; sets the transform to the subanimation type if it's the enemy's turn
+GetSubanimationTransform1: ; 41C2
+	ld b,a
+	ld a,[H_WHOSETURN]
+	and a
+	ld a,b
+	ret nz
+	xor a
+	ret
+
+; called if the subanimation type is 5
+; sets the transform to 2 (i.e. horizontal and vertical flip) if it's the player's turn
+; sets the transform to 0 (i.e. no transform) if it's the enemy's turn
+GetSubanimationTransform2: ; 41CA
+	ld a,[H_WHOSETURN]
+	and a
+	ld a,2 << 5
+	ret z
+	xor a
+	ret
+
+; loads tile patterns for battle animations
+LoadAnimationTileset: ; 41D2
+	ld a,[$D09F] ; tileset select
+	add a
+	add a
+	ld hl,AnimationTilesetPointers
+	ld e,a
+	ld d,0
+	add hl,de
+	ld a,[hli]
+	ld [$D07D],a ; number of tiles
+	ld a,[hli]
+	ld e,a
+	ld a,[hl]
+	ld d,a ; de = address of tileset
+	ld hl,$8310 ; destination address in VRAM
+	ld b,$1E ; ROM bank
+	ld a,[$D07D]
+	ld c,a ; number of tiles
+	jp $1848 ; load tileset
+
+AnimationTilesetPointers: ; 41F2
+db 79 ; number of tiles
+dw AnimationTileset1
+db $FF
+
+db 79 ; number of tiles
+dw AnimationTileset2
+db $FF
+
+db 64 ; number of tiles
+dw AnimationTileset1
+db $FF
+
+AnimationTileset1: ; 41FE
+INCBIN "baserom.gbc",$781FE,79 * 16
+
+AnimationTileset2: ; 46EE
+INCBIN "baserom.gbc",$786EE,79 * 16
+
 IF _RED
 	INCBIN "gfx/red/slotmachine2.2bpp"
 ENDC
@@ -63886,7 +64156,7 @@
 	push af
 	call $3748
 	call $4E23
-	ld a,[$D07C]
+	ld a,[W_ANIMATIONID]
 	and a
 	jr z,.AnimationFinished\@
 
@@ -63932,7 +64202,7 @@
 
 	; opponent’s turn
 
-	ld a,[$D07C]
+	ld a,[W_ANIMATIONID]
 
 	cp a,AMNESIA
 	ld b,CONF_ANIM
@@ -63944,7 +64214,7 @@
 
 .Replace\@
 	ld a,b
-	ld [$D07C],a
+	ld [W_ANIMATIONID],a
 	ret
 
 Function4DBD: ; 4DBD
@@ -63967,24 +64237,25 @@
 
 INCBIN "baserom.gbc",$78DDB,$78E53-$78DDB
 
-RealPlayAnimation: ; 4E53
-	ld a,[$CF07] ; get animation # − 1
+PlaySubanimation: ; 4E53
+	ld a,[W_ANIMSOUNDID]
 	cp a,$FF
-	jr z,.Next4E60
+	jr z,.skipPlayingSound\@
 	call $586F
 	call $23B1 ; play sound effect
-.Next4E60
-	ld hl,$C300
+.skipPlayingSound\@
+	ld hl,$C300 ; base address of OAM buffer
 	ld a,l
-	ld [$D09D],a
+	ld [W_FBDESTADDR + 1],a
 	ld a,h
-	ld [$D09C],a
-	ld a,[$D097]
+	ld [W_FBDESTADDR],a
+	ld a,[W_SUBANIMSUBENTRYADDR + 1]
 	ld h,a
-	ld a,[$D096]
+	ld a,[W_SUBANIMSUBENTRYADDR]
 	ld l,a
+.loop\@
 	push hl
-	ld c,[hl]
+	ld c,[hl] ; frame block ID
 	ld b,0
 	ld hl,PointerTable6F74
 	add hl,bc
@@ -63996,44 +64267,241 @@
 	pop hl
 	inc hl
 	push hl
-	ld e,[hl]
+	ld e,[hl] ; base coordinate ID
 	ld d,0
-	ld hl,$7C85
+	ld hl,$7C85 ; base coordinate table
 	add hl,de
 	add hl,de
 	ld a,[hli]
-	ld [$D082],a
+	ld [W_BASECOORDY],a
 	ld a,[hl]
-	ld [$D081],a
+	ld [W_BASECOORDX],a
 	pop hl
 	inc hl
-	ld a,[hl]
-	ld [$D09E],a
-	call $4000
-	call $4ED7
-	ld a,[$D087]
+	ld a,[hl] ; frame block mode
+	ld [W_FBMODE],a
+	call DrawFrameBlock
+	call $4ED7 ; run animation-specific function (if there is one)
+	ld a,[W_SUBANIMSIZE]
 	dec a
-	ld [$D087],a
+	ld [W_SUBANIMSIZE],a
 	ret z
-	ld a,[$D097]
+	ld a,[W_SUBANIMSUBENTRYADDR + 1]
 	ld h,a
-	ld a,[$D096]
+	ld a,[W_SUBANIMSUBENTRYADDR]
 	ld l,a
-	ld a,[$D08B]
-	cp a,4
+	ld a,[W_SUBANIMTRANSFORM]
+	cp a,4 ; is the animation reversed?
 	ld bc,3
-	jr nz,.Next4EBC
-	ld bc,$FFFD
-.Next4EBC
+	jr nz,.nextSubanimationSubentry\@
+	ld bc,-3
+.nextSubanimationSubentry\@
 	add hl,bc
 	ld a,h
-	ld [$D097],a
+	ld [W_SUBANIMSUBENTRYADDR + 1],a
 	ld a,l
-	ld [$D096],a
-	jp $4E73
+	ld [W_SUBANIMSUBENTRYADDR],a
+	jp .loop\@
 
-INCBIN "baserom.gbc",$78EC8,$7986F - $78EC8
+AnimationCleanOAM: ; 4EC8
+	push hl
+	push de
+	push bc
+	push af
+	call DelayFrame
+	call CleanLCD_OAM
+	pop af
+	pop bc
+	pop de
+	pop hl
+	ret
 
+; this runs after each frame block is drawn in a subanimation
+; it runs a particular special effect based on the animation ID
+DoSpecialEffectByAnimationId: ; 4ED7
+	push hl
+	push de
+	push bc
+	ld a,[W_ANIMATIONID]
+	ld hl,AnimationIdSpecialEffects
+	ld de,3
+	call IsInArray
+	jr nc,.done\@
+	inc hl
+	ld a,[hli]
+	ld h,[hl]
+	ld l,a
+	ld de,.done\@
+	push de
+	jp [hl]
+.done\@
+	pop bc
+	pop de
+	pop hl
+	ret
+
+; Format: Animation ID (1 byte), Address (2 bytes)
+AnimationIdSpecialEffects: ; 4EF5
+	db MEGA_PUNCH
+	dw $51BE
+
+	db GUILLOTINE
+	dw $51BE
+
+	db MEGA_KICK
+	dw $51BE
+
+	db HEADBUTT
+	dw $51BE
+
+	db TAIL_WHIP
+	dw $50D0
+
+	db GROWL
+	dw $50BC
+
+	db DISABLE
+	dw $51BE
+
+	db BLIZZARD
+	dw $5016
+
+	db BUBBLEBEAM
+	dw $51BE
+
+	db HYPER_BEAM
+	dw $5000
+
+	db THUNDERBOLT
+	dw $4FF7
+
+	db REFLECT
+	dw $51BE
+
+	db SELFDESTRUCT
+	dw $5009
+
+	db SPORE
+	dw $51BE
+
+	db EXPLOSION
+	dw $5009
+
+	db ROCK_SLIDE
+	dw $4FD9
+
+	db $AA
+	dw $5041
+
+	db $AB
+	dw $504C
+
+	db $AC
+	dw $507C
+
+	db TOSS_ANIM
+	dw $4F3E
+
+	db $C2
+	dw $4F96
+
+	db POOF_ANIM
+	dw $4FCE
+
+	db GREATTOSS_ANIM
+	dw $4F3E
+
+	db ULTRATOSS_ANIM
+	dw $4F3E
+
+	db $FF ; terminator
+
+INCBIN "baserom.gbc",$78F3E,$790DA - $78F3E
+
+; Format: Special Effect ID (1 byte), Address (2 bytes)
+SpecialEffectPointers: ; 50DA
+	db $FE
+	dw $51BE
+	db $FD
+	dw $51D6
+	db $FC
+	dw $51EA
+	db $FB
+	dw $520E
+	db $FA
+	dw $5215
+	db $F9
+	dw $51DB
+	db $F8
+	dw $5165
+	db $F7
+	dw $527A
+	db $F6
+	dw $5297
+	db $F5
+	dw $5389
+	db $F4
+	dw $52AF
+	db $F3
+	dw $536F
+	db $F2
+	dw $53F9
+	db $F1
+	dw $5415
+	db $F0
+	dw $51F4
+	db $EF
+	dw $5801
+	db $EE
+	dw $54A1
+	db $ED
+	dw $54F9
+	db $EC
+	dw $5566
+	db $EB
+	dw $577A
+	db $EA
+	dw $559F
+	db $E9
+	dw $55C9
+	db $E8
+	dw $5787
+	db $E7
+	dw $5C74
+	db $E6
+	dw $5C8A
+	db $E5
+	dw $5645
+	db $E4
+	dw $5D77
+	db $E3
+	dw $5D77
+	db $E2
+	dw $5424
+	db $E1
+	dw $5150
+	db $E0
+	dw $5398
+	db $DF
+	dw $57D8
+	db $DE
+	dw $5369
+	db $DD
+	dw $539E
+	db $DC
+	dw $53AB
+	db $DB
+	dw $52B9
+	db $DA
+	dw $53B1
+	db $D9
+	dw $56E0
+	db $D8
+	dw $5666
+	db $FF
+
+INCBIN "baserom.gbc",$79150,$7986F - $79150
+
 Func586F: ; 0x7986F 586F
 	ld hl,MoveSoundTable
 	ld e,a
@@ -64075,7 +64543,7 @@
 	ret
 IsCryMove: ; 0x798ad
 ; set carry if the move animation involves playing a monster cry
-	ld a,[$D07C]
+	ld a,[W_ANIMATIONID]
 	cp a,GROWL
 	jr z,.CryMove
 	cp a,ROAR
@@ -64288,7 +64756,7 @@
 .done\@
 	ld a,b
 .PlayNextAnimation\@
-	ld [$D07C],a
+	ld [W_ANIMATIONID],a
 	push bc
 	push hl
 	call PlayAnimation
@@ -64305,12 +64773,12 @@
 
 .BlockBall\@ ; 5E55
 	ld a,$C1
-	ld [$D07C],a
+	ld [W_ANIMATIONID],a
 	call PlayAnimation
 	ld a,$95
 	call $23B1 ; play sound effect
 	ld a,BLOCKBALL_ANIM
-	ld [$D07C],a
+	ld [W_ANIMATIONID],a
 	jp PlayAnimation
 
 INCBIN "baserom.gbc",$79E6A,$7AF74 - $79E6A