"""Crowd momentum meters: shots/checks pull M, ratings on ice scale by M/100 percent."""
ORIGIN = 0x2E0000
TILES = 0x2E0800
DIFF_TEXT = 0x209700
import struct


def tile(rows):
    """rows: 8 strings of 8 hex digits (palette indices)."""
    return bytes.fromhex(''.join(rows))


def tiles():
    t = []
    bg = ['00000000'] + ['44444444'] * 6 + ['00000000']
    t += [tile(bg)] * 4                                 # TILE+0..3 black background
    for c in '1A':                                      # +4..7 white (pal 0), +8..11 red (pal 1)
        t += [tile(['00000000'] * 2 + [c * 8] * 4 + ['00000000'] * 2)] * 4
    for c in '1A':                                      # +12..18 white, +19..25 red partial widths 1..7
        for w in range(1, 8):
            row = (c * w).ljust(8, '0')
            t.append(tile(['00000000'] * 2 + [row] * 4 + ['00000000'] * 2))
    t.append(tile(['10000000'] + ['40000000'] * 6 + ['10000000']))  # +26 neutral tick
    assert len(t) == 27
    return b''.join(t)


def install(data, assemble, patch):
    code = assemble('crowd', ORIGIN)
    assert ORIGIN + len(code) <= TILES, 'crowd code overlaps its tiles'
    patch(ORIGIN, b'\xFF' * len(code), code)
    art = tiles()
    patch(TILES, b'\xFF' * len(art), art)
    # Sprite list start: our meters go first (in front). Native a6/d6 set-up is done inside.
    patch(0x15ED4, bytes.fromhex('3c7cc0187c01'), bytes.fromhex('4eb9002e0000'))
    # Tail of the native per-player rating loader $15AA4.
    patch(0x15D7C, bytes.fromhex('4ef9001ff002'), bytes.fromhex('4ef9002e0004'))
    # jdc r15: main menu row 9 (hidden User Records since fix 11) becomes Difficulty Normal/Hard,
    # stored in $FFF07A (unreferenced RAM; User Records $D054 stays Off and unseen).
    patch(0x20915A + 16*9, b'\x00\x10User Records \x00', b'\x00\x10Difficulty   \x00')
    # jdc r27: a third value, Easy (2): your meter full, CPU empty, every forehand slapshot crits.
    values = b''.join(b'\x00\x16' + t.ljust(20) for t in (b'Normal', b'Hard', b'Easy'))
    patch(DIFF_TEXT, b'\xFF' * len(values), values)
    patch(0x2091FE + 2*9, bytes.fromhex('0300'), struct.pack('>H', DIFF_TEXT - 0x2091FE))
    patch(0x2095AE + 2*9, b'\x00\x02', b'\x00\x03')
    patch(0x2095C2 + 2*9, b'\x00\x02', b'\x00\x03')
    # fix 11 row map: row 9 (d7=$12) moveq #$C,d1 / bra.w -> move.w #$F07A-$D048,d1 / bra.s rts
    patch(0x2FE232, bytes.fromhex('720c60000010'), bytes.fromhex('323c2032600e'))
    patch(0xF777A, bytes.fromhex('0012'), bytes.fromhex('0014'))       # ten rows again
    patch(0xF7758, bytes.fromhex('0003'), bytes.fromhex('0004'))
    patch(0xF7762, bytes.fromhex('0003'), bytes.fromhex('0004'))
    patch(0xF7C08, bytes.fromhex('0003'), bytes.fromhex('0004'))
    # Team Roster value (crit hook $2FF404 continues here for every non-Crit mode).
    patch(0x8D70, bytes.fromhex('4eb9000fa9f8'), bytes.fromhex('4eb9002e000c'))
    # Game RAM reset after each game / at boot: meter, percents and bases start over.
    patch(0x172FA, bytes.fromhex('6100f6d446fc2700'), bytes.fromhex('4eb9002e00104e71'))
    # jdc r17: the meter also scales the crit chance (critical.s roll and its Roster column).
    if data[0x2FF462:0x2FF468] == bytes.fromhex('3200303c03e8'):
        patch(0x2FF462, bytes.fromhex('3200303c03e8'), bytes.fromhex('4eb9002e0014'))
        patch(0x2FF4B8, bytes.fromhex('4ef900008e4c'), bytes.fromhex('4ef9002e0018'))
        patch(0x2FF45A, bytes.fromhex('6100ffb04a40'), bytes.fromhex('4eb9002e0020'))   # r27 Easy crit
    # Power-on defaults: fix 10's routine, then Normal.
    patch(0x17C86, bytes.fromhex('4eb9002fe200'), bytes.fromhex('4eb9002e0008'))
