IsAnyMonHoldingExpShare:
	ld a, [wPartyCount]
	ld b, a
	ld hl, wPartyMon1
	ld c, 1
	ld d, 0
.loop
	push hl
	push bc
	ld bc, MON_HP
	add hl, bc
	ld a, [hli]
	or [hl]
	pop bc
	pop hl
	jr z, .next

	push hl
	push bc
	ld bc, MON_ITEM
	add hl, bc
	pop bc
	ld a, [hl]
	pop hl

	cp EXP_SHARE
	jr nz, .next
	ld a, d
	or c
	ld d, a

.next
	sla c
	push de
	ld de, PARTYMON_STRUCT_LENGTH
	add hl, de
	pop de
	dec b
	jr nz, .loop

	ld a, d
	ld e, 0
	ld b, PARTY_LENGTH
.loop2
	srl a
	jr nc, .okay
	inc e

.okay
	dec b
	jr nz, .loop2
	ld a, e
	and a
	ret

GiveExperiencePoints:
; Give experience.
	xor a
	ld [wCurPartyMon], a
	ld bc, wPartyMon1Species

.loop
	ld hl, MON_HP
	add hl, bc
	ld a, [hli]
	or [hl]
	jp z, .next_mon ; fainted

	CheckEngine ENGINE_HYPER_SHARE_ENABLED
	jr nz, .hyper_share_enabled
	push bc
	ld hl, wBattleParticipantsNotFainted
	ld a, [wCurPartyMon]
	ld c, a
	ld b, CHECK_FLAG
	predef FlagAction
	pop bc
	jp z, .next_mon
.hyper_share_enabled
	call .GiveStatExperience
	; Now give experience. Except if the pokémon is level 100
	ld a, MON_LEVEL
	call GetPartyParam
	cp 100
	jp nc, .next_mon
	xor a
	ld [hMultiplicand], a
	ld [hMultiplicand + 1], a
	ld a, [wEnemyMonBaseExp]
	ld [hMultiplicand + 2], a
	ld a, [wEnemyMonLevel]
	ld [hMultiplier], a
	push bc
	predef Multiply
	CheckEngine ENGINE_HYPER_SHARE_ENABLED
	ld a, 7
	jr z, .no_division_by_three
	ld a, 21
.no_division_by_three
	ld [hDivisor], a
	ld b, 4
	predef Divide
; Boost Experience for traded Pokemon
	pop bc
	ld hl, MON_ID
	add hl, bc
	ld a, [wPlayerID]
	cp [hl]
	jr nz, .boosted
	inc hl
	ld a, [wPlayerID + 1]
	cp [hl]
	ld a, 0
	jr z, .no_boost
.boosted
	call BoostExp
	ld a, 1
.no_boost
; Boost experience for a Trainer Battle
	ld [wStringBuffer2 + 2], a
	ld a, [wBattleMode]
	dec a
	call nz, BoostExp
; Boost experience for Lucky Egg
	push bc
	ld a, MON_ITEM
	call GetPartyParam
	cp LUCKY_EGG
	jr nz, .no_lucky_egg
	CheckEngine ENGINE_HYPER_SHARE_ENABLED
	call z, BoostExp
.no_lucky_egg
	ld a, [hQuotient + 2]
	ld [wStringBuffer2 + 1], a
	ld a, [hQuotient + 1]
	ld [wStringBuffer2], a
	ld a, [wCurPartyMon]
	ld hl, wPartyMonNicknames
	call GetNick
	ld hl, Text_PkmnGainedExpPoint
	call BattleTextBox
	ld a, [wStringBuffer2 + 1]
	ld [hQuotient + 2], a
	ld a, [wStringBuffer2]
	ld [hQuotient + 1], a
	pop bc
	call AnimateExpBar
	push bc
	call LoadTileMapToTempTileMap
	pop bc
	ld hl, MON_STAT_EXP - 1
	add hl, bc
	ld d, [hl]
	ld a, [hQuotient + 2]
	add d
	ld [hld], a
	ld d, [hl]
	ld a, [hQuotient + 1]
	adc d
	ld [hl], a
	jr nc, .no_exp_overflow
	dec hl
	inc [hl]
	jr nz, .no_exp_overflow ;in a sane world this jump will always happen
	dec a
	ld [hli], a
	ld [hli], a
	ld [hl], a
.no_exp_overflow
	ld a, [wCurPartyMon]
	ld e, a
	ld d, 0
	ld hl, wPartySpecies
	add hl, de
	ld a, [hl]
	ld [wCurSpecies], a
	call GetBaseData
	push bc
	ld d, MAX_LEVEL
	callba CalcExpAtLevel
	pop bc
	ld hl, MON_EXP + 2
	add hl, bc
	push bc
	ld a, [hQuotient]
	ld b, a
	ld a, [hQuotient + 1]
	ld c, a
	ld a, [hQuotient + 2]
	ld d, a
	ld a, [hld]
	sub d
	ld a, [hld]
	sbc c
	ld a, [hl]
	sbc b
	jr c, .not_max_exp
	ld a, b
	ld [hli], a
	ld a, c
	ld [hli], a
	ld a, d
	ld [hld], a
.not_max_exp
	xor a ; PARTYMON
	ld [wMonType], a
	predef CopyPkmnToTempMon
	callba CalcLevel
	pop bc
	ld hl, MON_LEVEL
	add hl, bc
	ld a, [hl]
	cp MAX_LEVEL
	jp nc, .next_mon
	cp d
	jp z, .next_mon
; <NICKNAME> grew to level ##!
	ld [wTempLevel], a
	ld a, [wCurPartyLevel]
	push af
	push bc
	ld a, MON_LEVEL
	call GetPartyParamLocation
	ld [hl], d
	callba UpdatePkmnStats
	ld a, MON_HP
	call GetPartyParamLocation
	pop bc
	ld a, [wCurBattleMon]
	ld d, a
	ld a, [wCurPartyMon]
	cp d
	jr nz, .skip_animation
	ld de, wBattleMonHP
	ld a, [hli]
	ld [de], a
	inc de
	ld a, [hli]
	ld [de], a
	ld de, wBattleMonMaxHP
	push bc
	ld bc, PARTYMON_STRUCT_LENGTH - MON_MAXHP
	rst CopyBytes
	pop bc
	ld hl, MON_LEVEL
	add hl, bc
	ld a, [hl]
	ld [wBattleMonLevel], a
	ld a, [wPlayerSubStatus5]
	bit SUBSTATUS_TRANSFORMED, a
	jr nz, .transformed
	ld hl, MON_ATK
	add hl, bc
	ld de, wPlayerStats
	ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK
	rst CopyBytes
.transformed
	xor a
	ld [wd265], a
	call ApplyStatLevelMultiplierOnAllStats
	call ApplyStatusEffectOnPlayerStats
	callba BadgeStatBoosts
	call UpdatePlayerHUD
	call EmptyBattleTextBox
	call LoadTileMapToTempTileMap
	ld a, 1
	ld [hBGMapMode], a

.skip_animation
	callba LevelUpHappinessMod
	ld a, [wCurBattleMon]
	ld b, a
	ld a, [wCurPartyMon]
	cp b
	jr z, .skip_animation2
	ld de, SFX_HIT_END_OF_EXP_BAR
	call PlayWaitSFX
	ld hl, BattleText_StringBuffer1GrewToLevel
	call StdBattleTextBox
	ld de, SFX_DEX_FANFARE_50_79
	call PlayWaitSFX
	call LoadTileMapToTempTileMap

.skip_animation2
	xor a ; PARTYMON
	ld [wMonType], a
	predef CopyPkmnToTempMon
	hlcoord 9, 0
	lb bc, $a, $9
	call TextBox
	hlcoord 11, 1
	ld bc, 4
	predef PrintTempMonStats
	ld c, 30
	call DelayFrames
	call WaitPressAorB_BlinkCursor
	call Call_LoadTempTileMapToTileMap
	xor a ; PARTYMON
	ld [wMonType], a
	ld a, [wCurSpecies]
	ld [wd265], a
	ld a, [wCurPartyLevel]
	push af
	ld c, a
	ld a, [wTempLevel]
	ld b, a

.level_loop
	inc b
	ld a, b
	ld [wCurPartyLevel], a
	push bc
	predef LearnLevelMoves
	pop bc
	ld a, b
	cp c
	jr nz, .level_loop
	pop af
	ld [wCurPartyLevel], a
	ld hl, wEvolvableFlags
	ld a, [wCurPartyMon]
	ld c, a
	ld b, SET_FLAG
	predef FlagAction
	pop af
	ld [wCurPartyLevel], a

.next_mon
	ld a, [wPartyCount]
	ld b, a
	ld a, [wCurPartyMon]
	inc a
	cp b
	jp z, ResetBattleParticipants
	ld [wCurPartyMon], a
	ld a, MON_SPECIES
	call GetPartyParamLocation
	ld b, h
	ld c, l
	jp .loop

.GiveStatExperience
	ld e, 1
	ld hl, MON_PKRUS
	add hl, bc
	ld a, [hl]
	and $f
	jr z, .no_pokerus
	sla e
.no_pokerus
	ld hl, MON_ITEM
	add hl, bc
	ld a, [hl]
	cp MACHO_BRACE
	jr nz, .no_macho_brace
	sla e
.no_macho_brace
	CheckEngine ENGINE_HYPER_SHARE_ENABLED
	ld a, e
	jr nz, .divide_stat_exp_by_three
	add a, a
	add a, e
.divide_stat_exp_by_three
	ld [wStatEXPMultiplier], a
	ld hl, MON_STAT_EXP + 9
	add hl, bc
	push bc
	ld de, wEnemyMonBaseStats + 4
	ld a, 5
.stat_exp_loop
	push af
	ld a, [de]
	dec de
	ld c, a
	ld a, [wStatEXPMultiplier]
	ld b, 3
	call SimpleMultiplyDivide
	ld a, [hl]
	add a, c
	ld [hld], a
	ld a, [hl]
	adc b
	jr nc, .no_stat_exp_carry
	inc hl
	ld a, $ff
	ld [hld], a
.no_stat_exp_carry
	ld [hld], a
	pop af
	dec a
	jr nz, .stat_exp_loop
	pop bc
	ret

BoostExp:
; Multiply experience by 1.5x
	push bc
; load experience value
	ld a, [hProduct + 2]
	ld b, a
	ld a, [hProduct + 3]
	ld c, a
; halve it
	srl b
	rr c
; add it back to the whole exp value
	add c
	ld [hProduct + 3], a
	ld a, [hProduct + 2]
	adc b
	ld [hProduct + 2], a
	pop bc
	ret

HalveExp:
	push bc
	ld a, [hProduct + 2]
	ld b, a
	ld a, [hProduct + 3]
	ld c, a
; halve it
	srl b
	rr c
; load it back as the whole exp value
	ld a, c
	ld [hProduct + 3], a
	ld a, b
	ld [hProduct + 2], a
	pop bc
	ret

Text_PkmnGainedExpPoint:
	text_far Text_Gained
	start_asm
	ld hl, TextJump_StringBuffer2ExpPoints
	ld a, [wStringBuffer2 + 2] ; IsTradedMon
	and a
	ret z

	ld hl, TextJump_ABoostedStringBuffer2ExpPoints
	ret

TextJump_ABoostedStringBuffer2ExpPoints:
	text_jump Text_ABoostedStringBuffer2ExpPoints

TextJump_StringBuffer2ExpPoints:
	text_jump Text_StringBuffer2ExpPoints

AnimateExpBar:
	push bc

	ld hl, wCurPartyMon
	ld a, [wCurBattleMon]
	cp [hl]
	jp nz, .finish

	ld a, [wBattleMonLevel]
	cp MAX_LEVEL
	jp nc, .finish

	ld a, [hProduct + 3]
	ld [wBattleTempExpPoints + 2], a
	push af
	ld a, [hProduct + 2]
	ld [wBattleTempExpPoints + 1], a
	push af
	xor a
	ld [wBattleTempExpPoints], a
	xor a ; PARTYMON
	ld [wMonType], a
	predef CopyPkmnToTempMon
	ld a, [wTempMonLevel]
	ld b, a
	ld e, a
	push de
	ld de, wTempMonExp + 2
	call CalcExpBar
	push bc
	ld hl, wTempMonExp + 2
	ld a, [wBattleTempExpPoints + 2]
	add [hl]
	ld [hld], a
	ld a, [wBattleTempExpPoints + 1]
	adc [hl]
	ld [hld], a
	jr nc, .NoOverflow
	inc [hl]
	jr nz, .NoOverflow
	ld a, $ff
	ld [hli], a
	ld [hli], a
	ld [hl], a

.NoOverflow
	ld d, MAX_LEVEL
	callba CalcExpAtLevel
	ld a, [hProduct + 1]
	ld b, a
	ld a, [hProduct + 2]
	ld c, a
	ld a, [hProduct + 3]
	ld d, a
	ld hl, wTempMonExp + 2
	ld a, [hld]
	sub d
	ld a, [hld]
	sbc c
	ld a, [hl]
	sbc b
	jr c, .AlreadyAtMaxExp
	ld a, b
	ld [hli], a
	ld a, c
	ld [hli], a
	ld a, d
	ld [hld], a

.AlreadyAtMaxExp
	callba CalcLevel
	ld a, d
	pop bc
	pop de
	ld d, a
	cp e
	jr nc, .LoopLevels
	ld a, e
	ld d, a

.LoopLevels
	ld a, e
	cp MAX_LEVEL
	jr nc, .FinishExpBar
	cp d
	jr z, .FinishExpBar
	inc a
	ld [wTempMonLevel], a
	ld [wCurPartyLevel], a
	ld [wBattleMonLevel], a
	push de
	call .PlayExpBarSound
	ld c, $48
	call .LoopBarAnimation
	call PrintPlayerHUD
	ld hl, wBattleMonNick
	ld de, wStringBuffer1
	ld bc, PKMN_NAME_LENGTH
	rst CopyBytes
	call TerminateExpBarSound
	ld de, SFX_HIT_END_OF_EXP_BAR
	call PlaySFX
	callba AnimateEndOfExpBar
	call WaitSFX
	ld hl, BattleText_StringBuffer1GrewToLevel
	call StdBattleTextBox
	ld de, SFX_DEX_FANFARE_50_79
	call PlayWaitSFX
	pop de
	inc e
	ld b, $0
	jr .LoopLevels

.FinishExpBar
	push bc
	ld b, d
	ld de, wTempMonExp + 2
	call CalcExpBar
	ld a, b
	pop bc
	ld c, a
	call .PlayExpBarSound
	call .LoopBarAnimation
	call TerminateExpBarSound
	pop af
	ld [hProduct + 2], a
	pop af
	ld [hProduct + 3], a

.finish
	pop bc
	ret

.PlayExpBarSound
	push bc
	call WaitSFX
	ld de, SFX_EXP_BAR
	call PlaySFX
	ld c, 10
	call DelayFrames
	pop bc
	ret

.LoopBarAnimation
	ld d, 3
	dec b
.anim_loop
	inc b
	push bc
	push de
	hlcoord 18, 11
	call PlaceExpBar
	pop de
	call .delay
	pop bc
	ld a, c
	cp b
	jr z, .end_animation
	inc b
	push bc
	push de
	hlcoord 18, 11
	call PlaceExpBar
	pop de
	call .delay
	dec d
	jr nz, .min_number_of_frames
	ld d, 1
.min_number_of_frames
	pop bc
	ld a, c
	cp b
	jr nz, .anim_loop
.end_animation
	ld a, $1
	ld [hBGMapMode], a
	ret
.delay
	xor a
	ld [hCGBPalUpdate], a
	ld a, $1
	ld [hBGMapMode], a
	ld [hBGMapHalf], a
	ld c, d
	call DelayFrames
	xor a
	ld [hBGMapMode], a
	ld a, $1
	ld [hCGBPalUpdate], a
	ret

CalcExpBar:
; Calculate the percent exp between this level and the next
; Level in b, experience in [de]
	push de
	ld d, b
	push de
	callba CalcExpAtLevel
	pop de
	ld hl, hProduct + 1
	ld a, [hli]
	ld e, a
	ld a, [hli]
	ld b, a
	ld c, [hl] ; ebc = lowest exp of current level
	inc d
	push de
	push bc
	callba CalcExpAtLevel ; [hProduct + 1] = lowest exp of next level
	pop bc
	pop de
	pop hl
	ld a, [hld]
	sub c
	ld d, a
	ld a, [hld]
	ld h, [hl]
	sbc b
	ld l, a
	ld a, h
	sbc e
	ld h, a ; hld = current exp - lowest exp of current level
	ld a, [hProduct + 3]
	sub c
	ld c, a
	ld a, [hProduct + 2]
	sbc b
	ld b, a
	ld a, [hProduct + 1]
	sbc e
	ld e, a ; ebc = lowest exp of next level - lowest exp of current level
.halveloop
; shift hld and ebc until ebc is a 16-bit number
	ld a, e
	and a
	jr z, .done
	srl h
	rr l
	rr d
	srl e
	rr b
	rr c
	jr .halveloop
.done
	ld a, h
	ld [hMultiplicand], a
	ld a, l
	ld [hMultiplicand + 1], a
	ld a, d
	ld [hMultiplicand + 2], a
	ld a, 9 * 8
	ld [hMultiplier], a
	predef Multiply
	ld a, b
	ld [hDivisor], a
	ld a, c
	ld [hDivisor + 1], a
	predef DivideLong
	ld a, [hLongQuotient + 3]
	ld b, a
	ret

FillInExpBar:
	push hl
	call CalcExpBar
	pop hl
	ld de, 8
	add hl, de
PlaceExpBar:
	ld c, $9 ; number of tiles
.loop1
	ld a, b
	sub $8
	jr c, .next
	ld b, a
	ld a, $5d ; full bar
	ld [hld], a
	dec c
	jr nz, .loop1
	ret

.next
	add $5d ; full bar (a is a negative number right now)
.loop2
	ld [hld], a
	ld a, $55 ; empty bar
	dec c
	jr nz, .loop2
	ret
