;===========================================================
; Sugarstar
; By Erik
;
; Uses extra bit: NO
;
; Uses extra bytes: YES
; - Extra byte 1: X radius. Valid values: 00-FF
; - Extra byte 2: Y radius. Valid values: 00-FF
; - Extra byte 3: speed. Valid values:
;   * 00-7F for clockwise movement.
;   * 80-FF for counter-clockwise movement.
;   Be careful with large values.
; - Extra byte 4: palette. Valid values: between 00 and 07
;   for the respective palette rows 08-0F.
;===========================================================

; Defines
!stun_time  = $FF   ;   time to stun the sugarstar

; GFX Defines
!ss_tile1   = $C0
!ss_tile2   = $E0
!stun_tile  = $BD

!ss_page_2  = 1     ;   set to 0 to use SP1/SP2, 1 to use SP3/SP4

;---

print "INIT ",pc
    ; save the center of rotation
    LDA !E4,x
    STA !1504,x
    LDA !14E0,x
    STA !151C,x
    LDA !D8,x
    STA !1528,x
    LDA !14D4,x
    STA !1534,x
    RTL

;-

print "MAIN ",pc
    PEA.w ($01)<<8|(sugarstar>>16)
    PLB
    JSR sugarstar
    PLB
    RTL

;---

;   - Misc. RAM Usage -
;   !C2   - Sugarstar state. 00 means normal, 01-FF means stunned
;   !1504 - X position of the center of rotation, low byte
;   !151C - X position of the center of rotation, high byte
;   !1528 - Y position of the center of rotation, low byte
;   !1534 - Y position of the center of rotation, high byte
;   !1540 - Stun timer
;   !157C - Current rotation angle, low byte
;   !1594 - Current rotation angle, high bit


sugarstar:
    LDA $9D
    BNE .no_move
    LDA !1540,x     ;\  sync the stun timer to the state
    STA !C2,x       ;/  so !C2,x = 0 means the sugarstar isn't stunned, !C2,x != 0 means stunned

    ; movement

    ; the rotation angle theta is now in $04-$05
    LDY #$00
    LDA !extra_byte_3,x
    BPL +
    DEY
+   CLC
    ADC !157C,x
    STA !157C,x
    STA $04
    TYA
    ADC !1594,x
    AND #$01
    STA !1594,x
    STA $05

    ; get (r_1*cos theta, r_2*cos theta) in $07-$0A
    LDA !extra_byte_1,x
    STA $06
    %CircleX()
    LDA !extra_byte_2,x
    STA $06
    %CircleY()

    ; (x,y) -> (x+r_1*cos theta, y+r_2*sin theta)
    LDA !1504,x
    CLC
    ADC $07
    STA !E4,x
    LDA !151C,x
    ADC $08
    STA !14E0,x
    LDA !1528,x
    CLC
    ADC $09
    STA !D8,x
    LDA !1534,x
    ADC $0A
    STA !14D4,x

    ; interaction
    LDA !C2,x               ;\  don't interact if stunned
    BNE .no_move            ;/
    JSR player_interact     ;   carry = player made the sugarstar stunned
    BCS .no_move
    JSR sprite_interact

.no_move
    JSR draw_sprite
    LDA #$03
    %SubOffScreen()
    RTS

;---

draw_sprite:
    %GetDrawInfo()

    if !ss_page_2
        SEC
    else
        CLC
    endif
    ; properties: palette bits from extra byte 4 + second page if needed
    LDA !extra_byte_4,x
    AND #$07            ;   -----ccc
    ROL                 ;   ----ccct (if !ss_page_2) ----ccc- (otherwise)
    ORA $64             ;   --ppccct (if !ss_page_2) --ppccc- (otherwise)
    STA $0303|!addr,y

    LDA !C2,x
    BNE .smol_tile

.big_tile
    ; x/y displacement
    ; setting carry according to second page settings for below
    REP #$20
    LDA $00
    STA $0300|!addr,y
    SEP #$20

    ; tile
    LDX #!ss_tile1
    LDA $14
    AND #$10
    BNE +
    LDX #!ss_tile2
+   TXA
    LDX $15E9|!addr
    STA $0302|!addr,y

    LDY #$02            ;\
    TDC                 ; | drew one 16x16 tile
    %FinishOAMWrite()   ;/
    RTS

.smol_tile
    REP #$20
    LDA $00
    CLC
    ADC #$0404
    STA $0300|!addr,y
    SEP #$20

    LDA #!stun_tile
    STA $0302|!addr,y

    LDY #$00            ;\
    TYA                 ; | drew one 8x8 tile
    %FinishOAMWrite()   ;/
    RTS
;---

player_interact:
    JSL $01A7DC|!bank   ;\  return if not even making contact
    BCC shatter_return  ;/
    LDA $1490|!addr
    BNE shatter
    LDA #$14
    STA $01
    LDA $05
    SBC $01
    ROL $00
    CMP $D3
    PHP
    LSR $00
    LDA $0B
    SBC #$00
    PLP
    SBC $D4
    BMI check_if_hurt
    LDA $140D|!addr
    ORA $187A|!addr
    BEQ check_if_hurt
    LDA #$02
    STA $1DF9|!addr
    JSL $01AA33|!bank
    JSL $01AB99|!bank
shatter:
    LDA #$07
    STA $1DFC|!addr
    LDA.b #!stun_time
    STA !1540,x
    SEC
.return
    RTS    

check_if_hurt:
    LDA $187A|!addr
    BEQ +
    %LoseYoshi()
+   LDA $1497|!addr
    BNE .return
    JSL $00F5B7|!bank
    CLC
.return
    RTS

;---

sprite_interact:
    LDA !15A0,x
    ORA !186C,x
    BNE .return

    LDY #!SprSize-1
.spr_loop
    CPY $15E9|!addr         ;\  don't interact with yourself
    BEQ .next               ;/
    TYA                     ;\
    EOR $13                 ; | don't interact every frame
    LSR                     ; |
    BCS .next               ;/

    ; courtesy of MarioFanGamer, the more adequate way to check if a sprite has been horizontally kicked.
    LDA !B6,y
    BEQ .next
    LDA !14C8,y
    CMP #$0A
    BEQ .valid_sprite
    LDA !9E,y
    CMP #$0D
    BCC .next
    LDA !14C8,y
    CMP #$09
    BEQ .valid_sprite
.next
    DEY
    BPL .spr_loop
.return
    RTS

.valid_sprite
    ; keep looping if no contact, otherwise shatter.
    JSL $03B69F|!bank
    TYX
    JSL $03B6E5|!bank
    JSL $03B72B|!bank
    LDX $15E9|!addr
    BCC .next
    LDA !B6,y
    EOR #$FF
    INC
    STA !B6,y
    LDA !9E,y
    CMP #$53
    BNE shatter
    LDA !E4,y
    STA $9A
    LDA !14E0,y
    STA $9B
    LDA !D8,y
    STA $98
    LDA !14D4,y
    STA $99
    LDA #$00
    STA !14C8,y
    PHB
    LDY #$02
    PHY
    PLB
    DEC
    JSL $028663|!bank
    PLB
    JMP shatter

