-----------------------------------
-- Chocobo Racing
-- https://www.bg-wiki.com/ffxi/Category:Chocobo_Racing
-- https://ffxiclopedia.fandom.com/wiki/Chocobo_Racing_Guide
-----------------------------------
require('scripts/globals/packet')
-----------------------------------
xi = xi or {}
xi.chocoboRacing = xi.chocoboRacing or {}

-- FOR HEAVILY-IN-DEVELOPMET TESTING, you can force these setting:
-- TODO: When ready for release, publish these to main settings files.
xi.settings.main.ENABLE_CHOCOBO_RACING = false
xi.settings.main.DEBUG_CHOCOBO_RACING = false

-- Notes:
-- Since there is a timed element, packet elements, and a lot of data to fill in,
-- it makes sense to move pretty much everything apart from the CS handling down
-- into core. While developing, things can stay up here, but as this approaches
-- a stable state everything should be pushed down.

-- To Run:
-- !exec xi.chocoboRacing.startRace()

-- https://github.com/atom0s/XiPackets/blob/main/world/server/0x0069/README.md
-- From your capture, paste in the contents of: packetviewer/incoming/0x069.log
local combinedPacketData = [[
[2024-06-08 16:51:00]
        |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      | 0123456789ABCDEF
    -----------------------------------------------------  ----------------------
      0 | 69 64 6C 1B 01 00 08 01 C8 00 00 00 00 00 00 80    0 | idl.............
      1 | CF F7 8F C0 85 6B C2 C2 00 00 00 00 32 32 64 00    1 | .....k......22d.
      2 | 06 1B 00 00 00 00 00 20 00 00 00 00 00 00 00 00    2 | ....... ........
      3 | 01 00 05 02 17 10 17 20 17 30 17 40 17 50 00 60    3 | ....... .0.@.P.`
      4 | 00 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00    4 | .p..............
      5 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    5 | ................
      6 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    6 | ................
      7 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    7 | ................
      8 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    8 | ................
      9 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    9 | ................
      A | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    A | ................
      B | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    B | ................
      C | 00 00 00 00 00 00 00 00 -- -- -- -- -- -- -- --    C | ........--------

[2024-06-08 16:51:01]
        |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      | 0123456789ABCDEF
    -----------------------------------------------------  ----------------------
      0 | 69 64 6D 1B 02 00 60 00 41 00 00 00 00 00 00 00    0 | idm...`.A.....`.
      1 | 00 00 08 15 41 00 00 00 00 00 00 00 00 00 00 00    1 | ....A.....`....!
      2 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    2 | b.........V.!...
      3 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    3 | ......$.b.......
      4 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    4 | ..""A.....`...".
      5 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    5 | b.....@@.. .0...
      6 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    6 | ......"#........
      7 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    7 | ................
      8 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    8 | ................
      9 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    9 | ................
      A | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    A | ................
      B | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    B | ................
      C | 00 00 00 00 00 00 00 00 -- -- -- -- -- -- -- --    C | ........--------

[2024-06-08 16:51:01]
        |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      | 0123456789ABCDEF
    -----------------------------------------------------  ----------------------
      0 | 69 64 6D 1B 03 00 C0 00 88 88 88 88 89 66 98 85    0 | idm..........f..
      1 | 00 B3 00 20 89 66 98 85 89 77 99 86 00 00 00 00    1 | ... .f...w......
      2 | 89 77 99 86 89 77 99 86 00 00 00 00 89 77 99 86    2 | .w...w.......w..
      3 | 88 77 99 86 80 80 00 03 88 77 99 86 88 77 99 86    3 | .w.......w...w..
      4 | 00 00 00 00 88 77 99 86 78 67 88 88 02 40 00 04    4 | .....w..xg...@..
      5 | 78 67 88 88 77 67 88 78 00 00 00 00 77 67 88 78    5 | xg..wg.x....wg.x
      6 | 77 67 88 87 08 08 00 02 77 67 88 87 77 67 78 87    6 | wg......wg..wgx.
      7 | 01 00 08 04 77 67 78 87 77 67 78 87 00 00 00 00    7 | ....wgx.wgx.....
      8 | 77 67 78 87 77 67 78 87 00 00 00 00 77 67 78 87    8 | wgx.wgx.....wgx.
      9 | 77 68 78 87 00 00 00 00 77 68 78 87 77 68 79 87    9 | whx.....whx.why.
      A | 00 00 00 00 77 68 79 87 66 57 79 76 04 30 CB 06    A | ....why.fWyv.0..
      B | 66 57 79 76 66 57 79 86 20 00 08 04 66 57 79 86    B | fWyvfWy. ...fWy.
      C | 66 67 79 85 00 00 00 00 -- -- -- -- -- -- -- --    C | fgy.....--------

[2024-06-08 16:51:01]
        |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      | 0123456789ABCDEF
    -----------------------------------------------------  ----------------------
      0 | 69 64 6D 1B 03 10 C0 00 66 67 79 85 67 57 79 86    0 | idm.....fgy.gWy.
      1 | 00 00 00 00 67 57 79 86 67 57 79 86 00 00 00 00    1 | ....gWy.gWy.....
      2 | 67 57 79 86 67 57 79 86 00 00 00 00 67 57 79 86    2 | gWy.gWy.....gWy.
      3 | 67 67 79 95 00 00 00 00 67 67 79 95 67 68 79 95    3 | ggy.....ggy.ghy.
      4 | 00 00 00 00 67 68 79 95 67 58 79 96 00 00 00 00    4 | ....ghy.gXy.....
      5 | 67 58 79 96 67 68 79 95 10 0C E3 06 67 68 79 95    5 | gXy.ghy.....ghy.
      6 | 68 79 7A A5 40 99 26 06 68 79 7A A5 89 6A 69 A4    6 | hyz.@.&.hyz..ji.
      7 | 00 07 F8 21 89 6A 69 A4 89 6A 69 A4 95 00 00 00    7 | ...!.ji..ji.....
      8 | 89 6A 69 A4 89 6A 69 A4 95 00 00 00 89 6A 69 A4    8 | .ji..ji......ji.
      9 | 89 6A 69 A4 D7 00 00 00 89 6A 69 A4 89 6A 69 B4    9 | .ji......ji..ji.
      A | F7 00 00 00 89 6A 69 B4 89 69 69 B4 F7 00 00 00    A | .....ji..ii.....
      B | 89 69 69 B4 79 69 69 B4 00 00 00 00 79 69 69 B4    B | .ii.yii.....yii.
      C | 79 59 69 B4 00 00 00 00 -- -- -- -- -- -- -- --    C | yYi.....--------

[2024-06-08 16:51:01]
        |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      | 0123456789ABCDEF
    -----------------------------------------------------  ----------------------
      0 | 69 64 6D 1B 04 00 04 00 34 16 25 70 0A 00 00 00    0 | idm.....4.%p....
      1 | 30 EE 00 00 20 73 64 15 00 00 00 00 00 00 00 00    1 | 0... sd.........
      2 | FB FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00    2 | ................
      3 | 00 00 34 00 63 61 6D 65 72 61 42 00 00 00 00 00    3 | ..4.cameraB.....
      4 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    4 | ................
      5 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    5 | ................
      6 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    6 | ................
      7 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    7 | ................
      8 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    8 | ................
      9 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    9 | ................
      A | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    A | ................
      B | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    B | ................
      C | 00 00 00 00 00 00 00 00 -- -- -- -- -- -- -- --    C | ........--------

[2024-06-08 16:51:01]
        |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      | 0123456789ABCDEF
    -----------------------------------------------------  ----------------------
      0 | 69 64 6E 1B 05 00 00 00 27 00 57 00 00 00 00 00    0 | idn.....'.W.....
      1 | 00 00 00 00 00 00 00 00 00 00 00 00 32 32 64 00    1 | ............22d.
      2 | 02 19 00 00 00 00 00 20 00 00 00 00 00 00 00 00    2 | ....... ........
      3 | 07 00 20 00 00 00 01 00 00 00 00 00 00 00 00 00    3 | .. .............
      4 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    4 | ................
      5 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    5 | ................
      6 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    6 | ................
      7 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    7 | ................
      8 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    8 | ................
      9 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    9 | ................
      A | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    A | ................
      B | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    B | ................
      C | 00 00 00 00 00 00 00 00 -- -- -- -- -- -- -- --    C | ........--------
]]

local debug = function(player, ...)
    if xi.settings.main.DEBUG_CHOCOBO_RACING then
        local t = { ... }
        print(unpack(t))
        player:printToPlayer(table.concat(t, ' '), xi.msg.channel.SYSTEM_3, '')
    end
end

local setTimer = function(player, npcId)
end

setTimer = function(player, npcId)
    player:timer(400, function(playerArg)
        playerArg:sendEmptyEntityUpdateToPlayer(GetNPCByID(npcId))
        setTimer(playerArg, npcId)
    end)
end

local startRaceImpl = function(player)
    debug(player, 'Starting race')

    for _, packet in ipairs(xi.packet.parseMultiplePackets(combinedPacketData)) do
        if packet[0x04 + 1] == 0x02 then
            -- Races:
            -- 0x0: Galka
            -- 0x1: Hume M
            -- 0x2: Hume F
            -- 0x3: Elvaan M
            -- 0x4: Elvaan F
            -- 0x5: Tarutaru M
            -- 0x6: Tarutaru F
            -- 0x7: Mithra
            local races = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }

            -- Colors:
            -- 0x0: Yellow
            -- 0x1: Yellow
            -- 0x2: Black
            -- 0x3: Black
            -- 0x4: Blue
            -- 0x5: Blue
            -- 0x6: Red
            -- 0x7: Red
            -- 0x8: Green
            local colors = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 }

            for _, offset in ipairs({ 0x0C, 0x18, 0x24, 0x30, 0x3C, 0x48, 0x54, 0x60 }) do
                local race   = utils.randomEntry(races)
                local color = utils.randomEntry(colors)

                -- Remember Lua is 1-offset!
                packet[offset + 0 + 1] = 0x0E
                packet[offset + 1 + 1] = 0x0C
                packet[offset + 2 + 1] = 0x60
                packet[offset + 3 + 1] = 0x80
                packet[offset + 4 + 1] = 0x00
                packet[offset + 5 + 1] = 0x00
                packet[offset + 6 + 1] = 0x08
                packet[offset + 7 + 1] = bit.lshift(race, 4) + color
                packet[offset + 8 + 1] = 0x41
                packet[offset + 9 + 1] = 0x00
                packet[offset + 10 + 1] = 0x00
                packet[offset + 11 + 1] = 0x00
            end
        end

        player:sendDebugPacket(packet)
    end

    player:startEvent(210, 3885177, 3885177, -132554, -14500, 1344, -1, 610862737, 1)

     -- 'Rungaga' seems to an anchor NPC that everything is orchestrated through?
    setTimer(player, zones[xi.zone.CHOCOBO_CIRCUIT].npc.RUNGAGA)
end

xi.chocoboRacing.startRace = function()
    local players = GetZone(xi.zone.CHOCOBO_CIRCUIT):getPlayers()
    for _, player in ipairs(players) do
        startRaceImpl(player)
    end
end

-- 0x05C
xi.chocoboRacing.onEventUpdate = function(player, csid, option, npc)
    debug(player, 'update', csid, option)

    local chocobos =
    {
        'One',
        'Two',
        'Three',
        'Four',
        'Five',
        'Six',
        'Seven',
        'Eight',
    }

    local winningsPerQuill = 1076

    local unknown0 = 389304928
    local unknown1 = -1
    local unknown2 = 610862737
    local unknown3 = -5

    -- NOTE: The race win order seems to be encoded in here

    if csid == 210 then
        if option == 5 then
            debug(player, 'Intro banner')
            player:updateEvent(1, 0, -132554, -14500, unknown0, unknown1, unknown2, unknown3)
        elseif option == 274 then
            debug(player, 'Names 1-4')
            player:updateEventString(chocobos[1], chocobos[2], chocobos[3], chocobos[4])
            player:updateEvent(70, 0, 7, 4, unknown0, unknown1, unknown2, unknown3)
        elseif option == 510 or option == 530 then
            debug(player, 'Names 5-8 and Start')
            player:updateEventString(chocobos[5], chocobos[6], chocobos[7], chocobos[8])
            player:updateEvent(70, 0, 7, 4, unknown0, unknown1, unknown2, unknown3)
        elseif option == 17 then
            debug(player, 'End and announce winnings')
            player:updateEvent(70, 0, winningsPerQuill, 1, 0, 3, 3, unknown3)
        end
    end
end

xi.chocoboRacing.onEventFinish = function(player, csid, option, npc)
    debug(player, 'finish', csid, option)
    if csid == 210 and option == 17 then
        debug(player, 'Hand out winnings')
    end
end
