// -----------------------------------------------------------
// slide4.c - CONTACT
//   pulsing big title, contact lines, three-layer starfield
//   drifting left, six star sprites floating on sine paths
//   behind the text
// -----------------------------------------------------------
#include "defs.h"
#include "common.h"
#include "slides.h"

// ---- data ----

// starfield: rows avoid the title (2-6) and text (10, 13, 16) rows
static const char star_row[12] = {
	 0,  8, 11, 14, 17, 19,  1,  9, 12, 15, 21, 23
};
static const char star_mask[12] = {  // move on framectr & mask == 0
	 1,  3,  7,  1,  3,  7,  1,  3,  7,  1,  3,  7
};
static const char star_col[12] = {   // fast = white, mid = lgrey, slow = dgrey
	VCOL_WHITE, VCOL_LT_GREY, VCOL_DARK_GREY, VCOL_WHITE, VCOL_LT_GREY, VCOL_DARK_GREY,
	VCOL_WHITE, VCOL_LT_GREY, VCOL_DARK_GREY, VCOL_WHITE, VCOL_LT_GREY, VCOL_DARK_GREY
};

static const char sprcols[6] = {
	VCOL_YELLOW, VCOL_LT_BLUE, VCOL_LT_GREEN, VCOL_WHITE, VCOL_ORANGE, VCOL_CYAN
};
static const char spr_xbase[6] = {   // spread across the screen; sprite 5 gets
	40, 85, 130, 175, 220, 20        //   +256 via the x MSB register
};
static const char spr_yph[6] = {     // sine phase offsets per sprite
	 0, 11, 21, 32, 43, 53
};
static const char spr_xph[6] = {
	 0, 26, 52, 13, 39,  7
};

static const char ysin[64] = {       // 64-entry sine, 134 +/- 60 (sprite y)
	0x86, 0x8c, 0x92, 0x97, 0x9d, 0xa2, 0xa7, 0xac,
	0xb0, 0xb4, 0xb8, 0xbb, 0xbd, 0xbf, 0xc1, 0xc2,
	0xc2, 0xc2, 0xc1, 0xbf, 0xbd, 0xbb, 0xb8, 0xb4,
	0xb0, 0xac, 0xa7, 0xa2, 0x9d, 0x97, 0x92, 0x8c,
	0x86, 0x80, 0x7a, 0x75, 0x6f, 0x6a, 0x65, 0x60,
	0x5c, 0x58, 0x54, 0x51, 0x4f, 0x4d, 0x4b, 0x4a,
	0x4a, 0x4a, 0x4b, 0x4d, 0x4f, 0x51, 0x54, 0x58,
	0x5c, 0x60, 0x65, 0x6a, 0x6f, 0x75, 0x7a, 0x80
};

static const char xwob[64] = {       // 64-entry sine, 12 +/- 12 (x wobble)
	0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x12, 0x13, 0x14,
	0x14, 0x15, 0x16, 0x17, 0x17, 0x17, 0x18, 0x18,
	0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x16, 0x15,
	0x14, 0x14, 0x13, 0x12, 0x11, 0x0f, 0x0e, 0x0d,
	0x0c, 0x0b, 0x0a, 0x09, 0x07, 0x06, 0x05, 0x04,
	0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x03,
	0x04, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b
};

// 24x21 four-pointed star sprite; copied to SPRBUF at init, so
// it needs no alignment and may sit anywhere
static const char sprdata[63] = {
	0x00, 0x00, 0x00,
	0x00, 0x00, 0x00,
	0x00, 0x18, 0x00,
	0x00, 0x18, 0x00,
	0x00, 0x18, 0x00,
	0x00, 0x3c, 0x00,
	0x00, 0x3c, 0x00,
	0x00, 0x7e, 0x00,
	0x07, 0xff, 0xe0,
	0x00, 0x7e, 0x00,
	0x00, 0x3c, 0x00,
	0x00, 0x3c, 0x00,
	0x00, 0x18, 0x00,
	0x00, 0x18, 0x00,
	0x00, 0x18, 0x00,
	0x00, 0x00, 0x00,
	0x00, 0x00, 0x00,
	0x00, 0x00, 0x00,
	0x00, 0x00, 0x00,
	0x00, 0x00, 0x00,
	0x00, 0x00, 0x00
};

// ---- variables ----
static char star_x[12] = {           // star columns (start scattered);
	 3, 17, 29,  8, 35, 22, 13, 31,  5, 26, 19, 37   //   persist across visits
};

void s4_init(void)
{
	clear_screen();
	draw_big(    2,  6, VCOL_WHITE,    "contact");
	print_text(10,  7, VCOL_LT_GREEN, "web: www.teletypegames.org");
	print_text(13,  6, VCOL_YELLOW,   "bbs: teletypegames.org 2323");
	print_text(16,  4, VCOL_CYAN,     "irc: libera.chat #teletypegames");

	// starfield: draw the stars at their current positions so
	// the in-transition reveals them together with the text
	for (char i = 0; i < 12; i++)
	{
		unsigned o = rowoff[star_row[i]] + star_x[i];
		SCREEN[o] = '.';
		COLRAM[o] = star_col[i];
	}

	// sprites: same star shape on all six, floating behind the
	// characters; enabled by the update, so they pop in only
	// after the slide's in-transition is done
	//
	// the shape is copied to the cassette buffer: the VIC sees
	// the chargen ROM at $1000-$1fff instead of RAM, so sprite
	// data placed there would show as glyph garbage
	for (char i = 0; i < 63; i++)
		SPRBUF[i] = sprdata[i];
	for (char i = 0; i < 6; i++)
	{
		SCREEN[0x3f8 + i] = (unsigned)SPRBUF >> 6;
		vic.spr_color[i] = sprcols[i];
	}
	vic.spr_multi    = 0;
	vic.spr_expand_x = 0;
	vic.spr_expand_y = 0;
	vic.spr_priority = 0x3f;         // behind the text
	vic.spr_msbx     = 0x20;         // sprite 5 lives right of x=255
}

void s4_update(void)
{
	while (vic.raster != RAS_BOTTOM)
		;

	framectr++;

	// grey-white pulse on the big title rows (2-6)
	char p = pulsetbl[(framectr >> 3) & 7];
	for (char x = 0; x < 40; x++)
	{
		COLRAM[2 * 40 + x] = p;
		COLRAM[3 * 40 + x] = p;
		COLRAM[4 * 40 + x] = p;
		COLRAM[5 * 40 + x] = p;
		COLRAM[6 * 40 + x] = p;
	}

	// starfield: three layers, each layer steps left on its own
	// frame mask (fast/mid/slow parallax)
	for (char i = 0; i < 12; i++)
	{
		if (framectr & star_mask[i])
			continue;
		unsigned o = rowoff[star_row[i]];
		SCREEN[o + star_x[i]] = ' ';         // erase at the old position
		char nx = star_x[i];                 // step left, wrap at the edge
		if (nx == 0)
			nx = 40;
		nx--;
		star_x[i] = nx;
		SCREEN[o + nx] = '.';
		COLRAM[o + nx] = star_col[i];
	}

	// sprites: y from a sine table, x = base + slower sine wobble
	vic.spr_enable = 0x3f;
	for (char s = 0; s < 6; s++)
	{
		vic.spr_pos[s].y = ysin[((framectr >> 1) + spr_yph[s]) & 63];
		vic.spr_pos[s].x = spr_xbase[s] + xwob[((framectr >> 2) + spr_xph[s]) & 63];
	}
}
