;; NOTE: automatically generated by the build system.
.include "../config/generated.s"

.segment "HEADER"
    ;; Bytes 0-3: NES\0 magic header.
    .byte 'N', 'E', 'S', $1A

    ;; Standard 32KB + 8KB NROM cartridge.
    .byte $02, $01

    ;; Horizontal mirroring, no battery.
    .byte $00

    ;; We use the NES 2.0 header mainly to differentiate between NTSC vs PAL in
    ;; a way that emulators won't ignore it.
    .byte $08

    ;; Blanked out stuff.
    .res $04, $00

    ;; NTSC vs PAL
    .ifdef PAL
        .byte $01
    .else
        .byte $00
    .endif

    ;; Blanked out stuff.
    .res $03, $00

.segment "CODE"

.include "../include/apu.s"
.include "../include/oam.s"
.include "../include/ppu.s"
.include "../include/asm.s"
.include "../include/joypad.s"
.include "../include/globals.s"

.include "assets.s"
.include "background.s"
.include "prng.s"
.include "player.s"
.include "bullets.s"
.include "enemies.s"
.include "title.s"
.include "driver.s"
.include "vectors.s"

.proc main
    ;; Disable the PPU and zero out variables which shadow PPU registers.
    lda #0
    sta PPU::m_mask
    sta PPU::zp_mask
    sta PPU::zp_control

    ;; Initialize other global variables which the rest of the game assume to
    ;; have zero as their initial values.
    sta Globals::zp_flags
    sta Joypad::zp_buttons1
    sta Joypad::zp_buttons2

    ;; Initialize the level. We allow the build system to pass its own value for
    ;; this in `LEVEL`, just in case we want to debug the enemy of a specific
    ;; level.
    .ifdef LEVEL
        lda #LEVEL
        sta Globals::zp_level
        and #%00000111
        sta Globals::zp_level_kind
    .else
        sta Globals::zp_level
        sta Globals::zp_level_kind
    .endif

    ;; Initialize the assets for the game.
    jsr Assets::init

    ;; Initialize some PAL-specific constants.
    .ifdef PAL
        lda #0
        sta Driver::zp_pal_counter
    .endif

    ;; We shadow the PPU control register in memory. Depending on the `make`
    ;; target we might need to switch directly to the main game. Otherwise we go
    ;; into the title as expected.
    .ifdef PARTIAL
        jsr Driver::switch

        lda PPU::zp_control
        sta PPU::m_control
    .else
        jsr Title::init

        lda #%10001000
        sta PPU::zp_control
        sta PPU::m_control
    .endif

    cli

    ;; Enable back the PPU
    lda #%00011110
    sta PPU::zp_mask
    sta PPU::m_mask

@main_game_loop:
    READ_JOYPAD1

    lda Globals::zp_flags
    and #%00000011
    beq @title_screen
    cmp #1
    beq @game_screen
    jmp @over

@title_screen:
    ;; If we are in a transitioning state, avoid the update from the title.
    lda Globals::zp_flags
    and #%00000100
    bne @do_switch

    jsr Title::update
    beq @set_flags

@do_switch:
    ;; Start was pressed by the player, switch to the main game.
    jsr Driver::switch
    jmp @set_flags

@game_screen:
    jsr Driver::update
    ;; NOTE: fallthrough

@set_flags:
    lda #%10000000
    ora Globals::zp_flags
    sta Globals::zp_flags
@wait_for_render:
    bit Globals::zp_flags
    bmi @wait_for_render

    ;; Rendering is done, we can perform another iteration of the loop!
    jmp @main_game_loop

@over:
    ;; TODO: allow to start over, reset flags, control register, etc.
    jmp @over
.endproc
