// SPDX-License-Identifier: CC0-1.0
//
// SPDX-FileContributor: Antonio Niño Díaz, 2024-2026

#include <stdio.h>

#include <nds.h>

// Headers autogenerated for each PNG file inside GFXDIRS in the Makefile
#include "statue.h"
#include "forest_town.h"

int main(int argc, char **argv)
{
    videoSetMode(MODE_0_2D);

    vramSetPrimaryBanks(VRAM_A_MAIN_BG, VRAM_B_MAIN_SPRITE,
                        VRAM_C_LCD, VRAM_D_LCD);

    // Setup console in the sub screen
    vramSetBankH(VRAM_H_SUB_BG);
    consoleDemoInit();

    // Setup 2D background
    // ===================

    int bg = bgInitHidden(2, BgType_Text8bpp, BgSize_T_256x256, 0, 4);
    bgSetPriority(bg, 2);
    bgMosaicEnable(bg);

    memcpy(bgGetGfxPtr(bg), forest_townTiles, forest_townTilesLen);
    memcpy(bgGetMapPtr(bg), forest_townMap, forest_townMapLen);
    memcpy(BG_PALETTE, forest_townPal, forest_townPalLen);

    bgShow(bg);

    // Setup 2D sprites
    // ================

    oamInit(&oamMain, SpriteMapping_1D_32, false);

    oamEnable(&oamMain);

    // Allocate space for the tiles and copy them there
    u16 *gfxMain = oamAllocateGfx(&oamMain, SpriteSize_64x64, SpriteColorFormat_256Color);
    memcpy(gfxMain, statueTiles, statueTilesLen);

    // Copy palette
    memcpy(SPRITE_PALETTE, statuePal, statuePalLen);

    oamSet(&oamMain, 0,
           100, 50, // X, Y
           0, // Priority
           0, // Palette index
           SpriteSize_64x64, SpriteColorFormat_256Color, // Size, format
           gfxMain, // Graphics offset
           -1, // Affine index
           false, // Double size
           false, // Hide
           false, false, // H flip, V flip
           false); // Mosaic

    oamSet(&oamMain, 1,
           150, 70, // X, Y
           0, // Priority
           0, // Palette index
           SpriteSize_64x64, SpriteColorFormat_256Color, // Size, format
           gfxMain, // Graphics offset
           -1, // Affine index
           false, // Double size
           false, // Hide
           false, false, // H flip, V flip
           true); // Mosaic

    // Setup done
    // ==========

    int bg_x = 150, bg_y = 70;
    int spr_x = 150, spr_y = 70;

    int mos_bg_x = 5;
    int mos_bg_y = 8;
    int mos_obj_x = 10;
    int mos_obj_y = 3;

    while (1)
    {
        // Synchronize game loop to the screen refresh
        swiWaitForVBlank();

        bgSetScroll(bg, bg_x, bg_y);

        bgSetMosaic(mos_bg_x, mos_bg_y);
        oamSetMosaic(mos_obj_x, mos_obj_y);

        bgUpdate();

        oamSetXY(&oamMain, 1, spr_x, spr_y);

        oamUpdate(&oamMain);

        // Print some text in the demo console
        // -----------------------------------

        consoleClear();

        // Print some controls
        printf("L + PAD: Scroll background\n");
        printf("R + PAD: Move sprite\n");
        printf("X + PAD: Change BG mosaic\n");
        printf("Y + PAD: Change OBJ mosaic\n");
        printf("\n");
        printf("BG: %d %d\n", mos_bg_x, mos_bg_y);
        printf("OBJ: %d %d\n", mos_obj_x, mos_obj_y);
        printf("\n");
        printf("START:   Exit to loader\n");
        printf("\n");

        // Handle user input
        // -----------------

        scanKeys();

        uint16_t keys_held = keysHeld();
        uint16_t keys_down = keysDown();

        if (keys_held & KEY_L)
        {
            if (keys_held & KEY_UP)
                bg_y--;
            else if (keys_held & KEY_DOWN)
                bg_y++;

            if (keys_held & KEY_LEFT)
                bg_x--;
            else if (keys_held & KEY_RIGHT)
                bg_x++;
        }

        if (keys_held & KEY_R)
        {
            if (keys_held & KEY_UP)
                spr_y--;
            else if (keys_held & KEY_DOWN)
                spr_y++;

            if (keys_held & KEY_LEFT)
                spr_x--;
            else if (keys_held & KEY_RIGHT)
                spr_x++;
        }

        if (keys_held & KEY_X)
        {
            if (keys_down & KEY_UP)
                mos_bg_y--;
            else if (keys_down & KEY_DOWN)
                mos_bg_y++;

            if (keys_down & KEY_LEFT)
                mos_bg_x--;
            else if (keys_down & KEY_RIGHT)
                mos_bg_x++;
        }

        if (keys_held & KEY_Y)
        {
            if (keys_down & KEY_UP)
                mos_obj_y--;
            else if (keys_down & KEY_DOWN)
                mos_obj_y++;

            if (keys_down & KEY_LEFT)
                mos_obj_x--;
            else if (keys_down & KEY_RIGHT)
                mos_obj_x++;
        }

        mos_bg_x &= 15;
        mos_bg_y &= 15;
        mos_obj_x &= 15;
        mos_obj_y &= 15;

        if (keys_held & KEY_START)
            break;
    }

    oamFreeGfx(&oamMain, gfxMain);

    return 0;
}

