; NAME: Visit Koopa (MP3) v2.3
; GAMES: MP3_USA
; EXECUTION: Direct
; PARAM: Space|KoopaSpace
; PARAM: Boolean|CountVisits
; PARAM: Boolean|KoopaKard
; PARAM: Number|KoopaKardCoins

; This code is designed to mimic the "Visit Koopa" event from MP1.
; Koopa gives 10 coins upon passing/landing, or 20 coins during the
; Last 5 Turns. Set the parameter "CountTurns" to "true" if you want
; Koopa to award extra coins to every 10th player to pass by before
; the last 5 turns. He gives 20 coins to the 10th player, 30 coins
; for the 20th player, and so on, capping at 50 coins.

; Use in conjunction with the "Model View Koopa" event to actively
; load the Koopa model on the board! The parameter "KoopaSpace" is
; the space the player will face during the event, which should also
; be where Koopa is standing.

; Set the parameter "KoopaKard" to "true" if you want Koopa to check
; for a Koopa Kard in the player's inventory and exchange any for
; coins. The number of coins is decided by the parameter
; "KoopaKardCoins".

ADDIU SP SP -64
SW RA 60(SP)
SW S0 56(SP)
SW S1 52(SP)
SW S2 48(SP)

; S0 = Current Player Struct
; S1 = Coins to Gain
; S2 = Koopa Count

;===Hide Dice Roll===
JAL GetPlayerStruct
LI A0 -1 ; Get current player struct at V0
MOVE S0 V0 ; Copy V0 to S0

JAL 0x800DBEC0 ; HideDiceRoll
LBU A0 0x1D(S0) ; Pass current player index on A0

;===Set Player Idle Animation===
LI A0 -1 ; Set current player
LI A1 -1 ; Set idle animation
JAL SetBoardPlayerAnimation
LI A2 2 ; Loop the animation

;===Rotate Toward KoopaSpace===
LI A0 -1 ; Set current player
LI A1 8 ; Rotate in 8 frames
JAL RotatePlayerModel
LI A2 KoopaSpace ; Face KoopaSpace

;===Add to Koopa Count===
LI T0 CountVisits
BEQZ T0 CheckTurns ; If CountVisits is OFF, check turns
NOP
; else, count Koopa visits

LUI T2 0x800C ; 0x800C0000
ORI T2 T2 0xD096 ; 0x800CD096, Koopa Count Address
LBU S2 0(T2) ; Load Koopa count into S2
ADDIU S2 S2 1 ; Add 1 to Koopa count
SB S2 0(T2) ; Store new Koopa count

;===Check Turn Count===
CheckTurns:
LUI T0 hi(total_turns)
ADDIU T0 T0 lo(total_turns)
LBU T1 0(T0) ; Load total turns into T1
LBU T0 1(T0) ; Load current turn into T0

SUBU T2 T1 T0 ; Subtract current turn from total turns
SLTI T3 T2 5 ; If T2 < 5, in the last 5 turns, T3 = 1
BNEZ T3 LastTurns ; If T3 = 1, go to LastTurns
NOP
; else, check if it's the 10th player

;===Check for 10th Visit===
LI T0 CountVisits
BEQZ T0 Get10Coins ; If CountVisits is OFF, get 10 coins
NOP
LI T2 10 ; Check for every 10th visit
DIVU S2 T2 ; Divide S2 by T2
MFHI T0 ; Move remainder into T0
BNEZ T0 Get10Coins ; If remainder isn't 0, get 10 coins
NOP
; else, visit is multiple of 10

;===Prepare 10th Visit Message===
LUI A0 hi(CountString)
ADDIU A0 A0 lo(CountString) ; Parse destination
LUI A1 hi(percent_d)
ADDIU A1 A1 lo(percent_d) ; String formatter
JAL sprintf
MOVE A2 S2 ; Convert Koopa count to text string

ADDIU S1 S2 10 ; Add 10 coin bonus for 10th visit
LI T1 50 ; Max 50 coins
SLT T2 T1 S1 ; If 50 < coin bonus, T2 = 1
BNEZL T2 PrepareCoinString ; If T2 = 1, prepare coin string
LI S1 50 ; Cap at 50 coins

PrepareCoinString:
LUI A0 hi(CoinString)
ADDIU A0 A0 lo(CoinString) ; Parse destination
LUI A1 hi(percent_d)
ADDIU A1 A1 lo(percent_d) ; String formatter
JAL sprintf
MOVE A2 S1 ; Convert coins to text string

;===10th Visit Message===
LUI A0 hi(CoinString)
ADDIU A0 A0 lo(CoinString) ; String #1 (Coins to Gain)
LUI A1 hi(10thMessage)
ADDIU A1 A1 lo(10thMessage) ; Display 10thMessage
LUI A2 hi(CountString)
JAL CallMessage
ADDIU A2 A2 lo(CountString) ; String #2 (Visit Count)

J GetCoins
NOP

;===Koopa Message===
Get10Coins:
LI A0 0 ; No string
LUI A1 hi(KoopaMessage)
ADDIU A1 A1 lo(KoopaMessage) ; Display KoopaMessage
JAL CallMessage
LI A2 0 ; No string

J GetCoins
LI S1 10 ; Get 10 coins

;===Last 5 Turns Message===
LastTurns:
LI A0 0 ; No string
LUI A1 hi(LastTurnsMessage)
ADDIU A1 A1 lo(LastTurnsMessage) ; Display LastTurnsMessage
JAL CallMessage
LI A2 0 ; No string

LI S1 20 ; Get 20 coins

;===Get Coins===
GetCoins:
LBU A0 0x1D(S0) ; Load player index from offset of player struct
JAL AdjustPlayerCoinsGradual
MOVE A1 S1 ; Gain coins

LBU A0 0x1D(S0) ; Load player index from offset of player struct
JAL ShowPlayerCoinChange
MOVE A1 S1 ; Gain coins

JAL SleepProcess
LI A0 30 ; Wait 30 frames for coin change

JAL HappyVoice
MOVE A0 S0 ; Pass current player struct on A0

;===Check for Koopa Kards===
LI T0 KoopaKard
BEQZ T0 exit ; If KoopaKard is OFF, exit
NOP
; else, check for Koopa Kards

LI S1 0 ; Reset bonus to 0
KoopaKardLoop:
LBU A0 0x1D(S0) ; Load player index from offset of player struct
JAL PlayerHasItem
LI A1 0x0F ; Check for Koopa Kard

BLTZ V0 CheckKards ; If no Koopa Kard, check Koopa Kards
NOP
ADDU T0 S0 V0 ; Add item slot offset to player struct
LI T1 0xFF ; No item index
SB T1 0x18(T0) ; Store no item into item slot offset of player struct
J KoopaKardLoop
ADDIU S1 S1 KoopaKardCoins ; Add coins bonus per Koopa Kard

CheckKards:
BEQZ S1 exit ; If no Koopa Kards found, exit
NOP
; else, player has 1 or more Koopa Kards

;===Prepare Koopa Kard Message===
LUI A0 hi(CoinString)
ADDIU A0 A0 lo(CoinString) ; Parse destination
LUI A1 hi(percent_d)
ADDIU A1 A1 lo(percent_d) ; String formatter
JAL sprintf
MOVE A2 S1 ; Convert coins to text string

;===Koopa Kard Message===
LUI A0 hi(CoinString)
ADDIU A0 A0 lo(CoinString) ; String #1 (Coins to Gain)
LUI A1 hi(KoopaKardMessage)
ADDIU A1 A1 lo(KoopaKardMessage) ; Display KoopaKardMessage
JAL CallMessage
LI A2 0 ; No string

;===Remove Koopa Kards from HUD===
JAL FixUpPlayerItemSlots
LBU A0 0x1D(S0) ; Load player index from offset of player struct
JAL FixUpPlayerItemSlots
LBU A0 0x1D(S0) ; Load player index from offset of player struct
JAL RefreshHUD
LBU A0 0x1D(S0) ; Load player index from offset of player struct

J GetCoins ; Get coins
NOP

exit:
JAL 0x800DB884 ; ShowDiceRoll
LBU A0 0x1D(S0) ; Pass current player index on A0

JAL SleepProcess
LI A0 10 ; Wait 10 frames for dice roll to show

LW RA 60(SP)
LW S0 56(SP)
LW S1 52(SP)
LW S2 48(SP)
JR RA
ADDIU SP SP 64

;===Prep for Displaying Coin String===
.align 16
percent_d:
.asciiz "%d" ; 0x25640000

.align 16
CoinString:
.fill 8

.align 16
CountString:
.fill 8

;===Mini Func to Call Message===
.align 4
CallMessage:
ADDIU SP SP -64
SW RA 60(SP)
SW S0 56(SP)
SW S1 52(SP)
SW S2 48(SP)

; A0 / S0 = String #1
; A1 / S1 = Message Address
; A2 / S2 = String #2

MOVE S0 A0 ; Copy A0 to S0
MOVE S1 A1 ; Copy A1 to S1
MOVE S2 A2 ; Copy A2 to S2

JAL PlaySound
LI A0 0x259 ; Koopa voice

SW R0 16(SP) ; A4
SW R0 20(SP) ; A5
SW R0 24(SP) ; A6
LI A0 0x2 ; Character image (-1 for none, 0x2 for Koopa)
; Visit the following link to get the full list of Character Images
; https://github.com/PartyPlanner64/PartyPlanner64/wiki/Displaying-Messages
; If you use a character image, check the bottom of the code
MOVE A1 S1 ; Pass message address on A1
MOVE A2 S0 ; Pass String #1 on A2
JAL ShowMessage
MOVE A3 S2 ; Pass String #2 on A3

; Obligatory message box closing/cleanup calls.
JAL 0x800EC9DC
NOP
JAL CloseMessage
NOP
JAL 0x800EC6EC
NOP

LW RA 60(SP)
LW S0 56(SP)
LW S1 52(SP)
LW S2 48(SP)
JR RA
ADDIU SP SP 64

;===Mini Func to Play Happy Voice and Animation===
.align 4
HappyVoice:
ADDIU SP SP -32
SW RA 28(SP)

; A0 = Current Player Struct

LBU A0 3(A0) ; Load character value from offset of player struct
JAL PlaySound
ADDIU A0 A0 0x2BE ; Add character value to Mario's happy voice
; Character voices are their "character value" distance away from
; Mario's, e.g. Luigi's character value = 1, so Luigi's happy voice
; is 1 away from Mario's.
; 0x2BE = Happy Voice, 0x287 = Sad Voice

LI A0 -1 ; Set current player
LI A1 5 ; Set joy animation
JAL SetBoardPlayerAnimation
LI A2 0 ; Do not loop animation

JAL SleepProcess
LI A0 40 ; Wait 40 frames for animation

LW RA 28(SP)
JR RA
ADDIU SP SP 32

;===Message Text===
.align 16
KoopaMessage:
.byte 0x1A,0x1A,0x1A,0x1A ; Padding for character image
.ascii "Nice work"
.byte 0xC2 ; Exclamation mark (!)
.byte 0x0A,0x1A,0x1A,0x1A,0x1A ; New line + character image padding
.ascii "Take this"
.byte 0x06 ; Blue font
.ascii " 10 Coin"
.byte 0x08 ; White font
.ascii " Bonus"
.byte 0xC2 ; Exclamation mark (!)
.byte 0x0A,0x1A,0x1A,0x1A,0x1A ; New line + character image padding
.ascii "Use it wisely"
.byte 0x85 ; Period (.)
.byte 0xFF,0 ; Wait, press A to confirm

.align 16
10thMessage:
.byte 0x1A,0x1A,0x1A,0x1A ; Padding for character image
.ascii "Congratulations"
.byte 0xC2 ; Exclamation mark (!)
.byte 0x0A,0x1A,0x1A,0x1A,0x1A ; New line + character image padding
.ascii "Since you"
.byte 0x5C ; Apostrophe (')
.ascii "re the "
.byte 0x12 ; String #2 stored on A3 (CountString)
.ascii "th person"
.byte 0x0A,0x1A,0x1A,0x1A,0x1A ; New line + character image padding
.ascii "to pass here"
.byte 0x82 ; Comma (,)
.ascii " I"
.byte 0x5C ; Apostrophe (')
.ascii "ll give you a"
.byte 0x0A,0x1A,0x1A,0x1A,0x1A ; New line + character image padding
.ascii "special present of "
.byte 0x06,0x11 ; Blue font, String #1 stored on A2 (CoinString)
.ascii " Coins"
.byte 0x08,0x85 ; White font, Period (.)
.byte 0xFF,0 ; Wait, press A to confirm

.align 16
LastTurnsMessage:
.byte 0x1A,0x1A,0x1A,0x1A ; Padding for character image
.ascii "Nice work"
.byte 0xC2 ; Exclamation mark (!)
.byte 0x0A,0x1A,0x1A,0x1A,0x1A ; New line + character image padding
.ascii "Take this"
.byte 0x06 ; Blue font
.ascii " 20 Coin"
.byte 0x08 ; White font
.ascii " Bonus"
.byte 0xC2 ; Exclamation mark (!)
.byte 0x0A,0x1A,0x1A,0x1A,0x1A ; New line + character image padding
.ascii "Just a little bit longer"
.byte 0x85,0x85,0x85 ; Three periods (...)
.byte 0xFF,0 ; Wait, press A to confirm

.align 16
KoopaKardMessage:
.byte 0x1A,0x1A,0x1A,0x1A ; Padding for character image
.ascii "Do I spy a shiny"
.byte 0x07 ; Yellow font
.ascii " Koopa Kard"
.byte 0x08,0xC3 ; White font, Question mark (?)
.byte 0x0A,0x1A,0x1A,0x1A,0x1A ; New line + character image padding
.ascii "Let me take that off your hands"
.byte 0xC2 ; Exclamation mark (!)
.byte 0x0A,0x1A,0x1A,0x1A,0x1A ; New line + character image padding
.ascii "Of course"
.byte 0x82 ; Comma (,)
.ascii " you"
.byte 0x5C ; Apostrophe (')
.ascii "ll be compensated"
.byte 0x85 ; Period (.)
.byte 0x0A,0x1A,0x1A,0x1A,0x1A ; New line + character image padding
.ascii "Take this "
.byte 0x06,0x11 ; Blue font, String #1 stored on A2 (CoinString)
.ascii " Coin"
.byte 0x08 ; White font
.ascii " Bonus"
.byte 0xC2 ; Exclamation mark (!)
.byte 0xFF,0 ; Wait, press A to confirm

; Here's a list of the most common bytes you'll need
; .byte 0x01 ; Black font
; .byte 0x03 ; Red font
; .byte 0x04 ; Purple font
; .byte 0x05 ; Green font
; .byte 0x06 ; Blue font
; .byte 0x07 ; Yellow font
; .byte 0x08 ; White font
; .byte 0x85 ; Period (.)
; .byte 0xC2 ; Exclamation mark (!)
; .byte 0xC3 ; Question mark (?)
; .byte 0x82 ; Comma (,)
; .byte 0x0A ; New line (writes below)
; .byte 0x5C ; Apostrophe (')
; .byte 0x29 ; Coin icon
; .byte 0x3D ; Minus (-)
; .byte 0x3E ; Multiply (x)
; .byte 0xFF,0 ; Wait, press A to confirm

; If your message has an image, use this at the start of each line
; .byte 0x1A,0x1A,0x1A,0x1A ; Padding for character image