/* * pop_geom.h — общая геометрия PoP и PRNG оригинала. * * Сюда сведено то, что раньше дублировалось по модулям (x_bump/y_land в * pop_kid и pop_map, y_to_row в pop_bg и pop_map, 32-битный LCG в pop_bg и * pop_trob). Кроме экономии это ФУНДАМЕНТ bank-safe API: модуль живёт в * W1/W2 и не трогает графику, поэтому его может звать и главный цикл, и * резидент W3, и будущий __banked-код стражей (docs/layout_plan_v2.md §4). */ #ifndef POP_GEOM_H #define POP_GEOM_H #include #define FIRST_ONSCREEN_COLUMN 5 /* индекс col 0 комнаты в x_bump */ #define TILE_SIZEX 14 /* ширина тайла в координатах персонажа */ #define TILE_SIZEY 63 /* высота ряда */ /* x_bump (data.h): левая граница колонки в координатах персонажа; колонка * комнаты col = x_bump[col + FIRST_ONSCREEN_COLUMN]. y_land: пол ряда * (индекс row+1; [0] — ряд «над комнатой»). */ extern const int16_t pop_x_bump[20]; extern const int16_t pop_y_land[5]; /* y_to_row_mod4 (seg006): ряд по координате y с оборотом mod 4 (−1 = полоса * над комнатой, 3 = под комнатой). */ int8_t pop_y_to_row(int16_t y); /* prandom (порт seg009:321). Сид ВНЕШНИЙ: у стен (раскладка кладки) и у * анимаций тайлов (фаза факелов) свои последовательности, смешивать их * нельзя. * * ДВА генератора, выбор через POP_PRANDOM_EXACT (см. pop_geom.c): * 1 (по умолчанию) — LCG оригинала (s*214013+2531011) БИТ-В-БИТ: та же * раскладка кладки и те же броски, что в SDLPoP, поэтому по картинке * можно сверяться с эталоном; * 0 — xorshift16 + шаг Вейля, без единого умножения. Дешевле ровно на * 5 646 тактов за кадр, 1.3 % бюджета (замер A/B в MAME, комната 3, * 175 кадров: 403 632 против 397 986). Последовательность другая — * статистически эквивалентная, но не та же. * * Обе версии считают 16-битными половинами, а не unsigned long: на 32-бит * умножении SDCC зовёт __mullong, и это 8 430 тактов на вызов (замер в * MAME, breakpoint на __mullong). * * ЗАДЕЛ: разрыв между версиями определяется не алгоритмом, а кодогенерацией * SDCC — те же генераторы на Z80-ассемблере укладываются в 86..148 тактов. * Если процент понадобится, сначала переписать в asm ОРИГИНАЛЬНЫЙ LCG (там * умножение на константу), а менять генератор — только если и этого мало. */ typedef struct { uint16_t lo, hi; } pop_rnd_t; #ifndef POP_PRANDOM_EXACT #define POP_PRANDOM_EXACT 1 #endif uint16_t pop_prandom(pop_rnd_t *seed, uint16_t maxv); /* Сид из 16-битного числа (старшая половина = 0). */ #define pop_prandom_set(s, v) do { (s).lo = (uint16_t)(v); (s).hi = 0; } while (0) #endif