SprPoP: README для игрока и экран Controls в две колонки
README, который едет НА ДИСК рядом с программой, в двух версиях: README.TXT (английский) и README.RUS (русский). Краткое описание, запуск, полная раскладка управления, читы, файлы игры, чего не хватает против оригинала, благодарности. Русский обязан быть в CP866 — DSS и местные просмотрщики читают именно её, UTF-8 показался бы кракозябрами. Исходники лежат в dist/ как UTF-8 (чтобы читались в репозитории), перекодировка и CRLF делаются правилом Makefile. ПОРЯДОК В КОНВЕЙЕРЕ ВАЖЕН: sed ставит CRLF ДО iconv — BSD sed в UTF-8 локали отказывается работать с байтами CP866 («RE error: illegal byte sequence»), а с валидным UTF-8 работает. iconv БЕЗ -c намеренно: потеря символа должна ломать сборку, а не молча портить текст. ЭКРАН CONTROLS переписан в две колонки. В одну раскладка больше не помещалась: после фаз A-C клавиш стало вдвое больше, а по высоте есть только 200 точек вместе с заголовком. Слева игра (бег, лазание, бой), справа служебное и читы; высота блока считается по ДЛИННОЙ колонке. Строка «IN A FIGHT» — заголовок, а не клавиша: ниже неё те же стрелки и Shift означают другое, и без разделителя список читался бы противоречиво. Заодно экран перестал врать: там до сих пор висели P, I, U и F7/F8 — клавиши, переназначенные ещё в фазе A. Проверено в MAME: Backspace открывает меню, Settings -> Show key bindings показывает обе колонки целиком. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -90,13 +90,22 @@
|
||||
#define SET_HEAD2 (SET_HEAD1 + 4 * SET_STEP + SET_HEAD_GAP)
|
||||
#define SET_HEAD3 (SET_HEAD2 + 3 * SET_STEP + SET_HEAD_GAP)
|
||||
|
||||
/* CONTROLS: число строк зависит от того, включены ли читы, поэтому верх
|
||||
* блока считается в рантайме. */
|
||||
#define CTRL_TITLE_GAP 20
|
||||
#define CTRL_N_BASE 7 /* общие клавиши */
|
||||
#define CTRL_N_CHEAT 5 /* дополнительные строки читов */
|
||||
#define CTRL_COL_KEY 45
|
||||
#define CTRL_COL_DESC 145
|
||||
/* CONTROLS — ДВЕ КОЛОНКИ. В одну колонку раскладка уже не помещалась:
|
||||
* после приведения клавиш к keys.txt (docs/keys_plan.md) их стало вдвое
|
||||
* больше, а по высоте есть только 200 точек на всё вместе с заголовком.
|
||||
*
|
||||
* Слева — игра (бег, лазание, бой), справа — служебное и читы. Число строк
|
||||
* в колонках разное и зависит от того, включены ли читы, поэтому высота
|
||||
* блока считается в рантайме по ДЛИННОЙ колонке. */
|
||||
#define CTRL_TITLE_GAP 18
|
||||
#define CTRL_N_LEFT 10 /* игровые клавиши */
|
||||
#define CTRL_N_SYS 7 /* служебные */
|
||||
#define CTRL_N_CHEAT 5 /* читы: показываются, только если включены */
|
||||
#define CTRL_L_KEY 6
|
||||
#define CTRL_L_DESC 62
|
||||
#define CTRL_R_KEY 164
|
||||
#define CTRL_R_DESC 220
|
||||
#define CTRL_STEP 13
|
||||
|
||||
/* ABOUT = ровно тот же текст, что на стартовом Sprinter screen, минус
|
||||
* строка про клавиши. ABOUT_H — и высота блока, и смещение ПОСЛЕДНЕЙ
|
||||
@@ -317,39 +326,69 @@ static void settings_draw(uint8_t sel)
|
||||
|
||||
/* Две колонки «клавиша — что делает». Первые CTRL_N_BASE строк общие, за
|
||||
* ними идут читовые: их показываем, только когда читы включены. */
|
||||
static const char * const ctrl_key[CTRL_N_BASE + CTRL_N_CHEAT] = {
|
||||
"ARROWS", "SHIFT", "ESC", "F6 / F9", "CTRL+S", "CTRL+M", "P",
|
||||
"K", "I", "SHIFT+L", "U", "F7 / F8"
|
||||
/* ЛЕВАЯ КОЛОНКА — игра. Строка «IN A FIGHT» здесь заголовок, а не клавиша:
|
||||
* ниже неё те же стрелки и Shift означают уже другое, и без разделителя
|
||||
* список читался бы как противоречивый. */
|
||||
static const char * const ctrl_l_key[CTRL_N_LEFT] = {
|
||||
"ARROWS", "UP", "DOWN", "SHIFT", "SH+ARROWS", "HOME PGUP",
|
||||
"IN A FIGHT", "SHIFT", "UP", "DOWN"
|
||||
};
|
||||
static const char * const ctrl_l_desc[CTRL_N_LEFT] = {
|
||||
"RUN / TURN", "JUMP, CLIMB", "CROUCH", "PICK UP", "CAREFUL STEP",
|
||||
"JUMP L / R",
|
||||
"", "STRIKE", "BLOCK", "SHEATHE"
|
||||
};
|
||||
|
||||
static const char * const ctrl_desc[CTRL_N_BASE + CTRL_N_CHEAT] = {
|
||||
"MOVE / JUMP", "ACTION", "PAUSE MENU", "SAVE / LOAD", "SOUND", "MUSIC",
|
||||
"SPEED",
|
||||
"KILL GUARD", "IMMORTAL", "NEXT LEVEL", "FLIP SCREEN", "TIME - / +"
|
||||
/* ПРАВАЯ КОЛОНКА — служебное, ниже читы. */
|
||||
static const char * const ctrl_r_key[CTRL_N_SYS + 1 + CTRL_N_CHEAT] = {
|
||||
"BACKSPACE", "SPACE", "T", "F6 / F9", "CTRL+A", "CTRL+S M", "CTRL+Q F10",
|
||||
"CHEATS",
|
||||
"SHIFT+L", "K", "+ / -", "SHIFT+I", "SHIFT+S T"
|
||||
};
|
||||
static const char * const ctrl_r_desc[CTRL_N_SYS + 1 + CTRL_N_CHEAT] = {
|
||||
"MENU", "TIME LEFT", "SHOW TIMER", "SAVE / LOAD", "RESTART LVL",
|
||||
"SOUND / MUSIC", "QUIT",
|
||||
"",
|
||||
"NEXT LEVEL", "KILL GUARD", "TIME + / -", "FLIP SCREEN", "HEAL / MAX HP"
|
||||
};
|
||||
|
||||
/* Одна строка колонки: слева клавиша, справа что она делает. Пустое
|
||||
* описание — значит строка была заголовком секции, и клавишу мы печатаем
|
||||
* как есть, без второго столбца. */
|
||||
static void ctrl_row(int kx, int dx, int y, const char *key, const char *desc)
|
||||
{
|
||||
pop_text_draw_mapped(POP_TEXT_SMALL, kx, y, key);
|
||||
if (desc[0]) pop_text_draw_mapped(POP_TEXT_SMALL, dx, y, desc);
|
||||
}
|
||||
|
||||
static void controls_draw(void)
|
||||
{
|
||||
uint8_t back = ui_begin();
|
||||
/* С выключенными читами вместо пяти строк идёт одна пояснительная —
|
||||
* список короче, и блок обязан центрироваться по ФАКТИЧЕСКОЙ высоте. */
|
||||
/* С выключенными читами правая колонка короче: вместо пяти строк идёт
|
||||
* одна пояснительная. Блок центрируется по ДЛИННОЙ из двух колонок. */
|
||||
uint8_t cheats = pop_settings.cheats_enabled;
|
||||
uint8_t rows = (uint8_t)(cheats ? CTRL_N_BASE + CTRL_N_CHEAT
|
||||
: CTRL_N_BASE + 1);
|
||||
uint8_t rright = (uint8_t)(cheats ? CTRL_N_SYS + 1 + CTRL_N_CHEAT
|
||||
: CTRL_N_SYS + 1);
|
||||
uint8_t rows = (uint8_t)(rright > CTRL_N_LEFT ? rright : CTRL_N_LEFT);
|
||||
uint8_t i;
|
||||
int top = UI_CENTER_TOP(POP_FONT_BIG_ASCENT + CTRL_TITLE_GAP +
|
||||
(int)(rows - 1) * SET_STEP);
|
||||
int y = top + POP_FONT_BIG_ASCENT;
|
||||
(int)(rows - 1) * CTRL_STEP);
|
||||
int y0 = top + POP_FONT_BIG_ASCENT;
|
||||
int y;
|
||||
|
||||
pop_text_map();
|
||||
pop_text_center_mapped(POP_TEXT_BIG, GFX_WIDTH / 2, y, "CONTROLS");
|
||||
y += CTRL_TITLE_GAP;
|
||||
for (i = 0; i < rows; i++) {
|
||||
const char *key = ctrl_key[i], *desc = ctrl_desc[i];
|
||||
if (!cheats && i == CTRL_N_BASE) { key = "CHEATS"; desc = "DISABLED"; }
|
||||
pop_text_draw_mapped(POP_TEXT_SMALL, CTRL_COL_KEY, y, key);
|
||||
pop_text_draw_mapped(POP_TEXT_SMALL, CTRL_COL_DESC, y, desc);
|
||||
y += SET_STEP;
|
||||
pop_text_center_mapped(POP_TEXT_BIG, GFX_WIDTH / 2, y0, "CONTROLS");
|
||||
y = y0 + CTRL_TITLE_GAP;
|
||||
for (i = 0; i < CTRL_N_LEFT; i++, y += CTRL_STEP)
|
||||
ctrl_row(CTRL_L_KEY, CTRL_L_DESC, y, ctrl_l_key[i], ctrl_l_desc[i]);
|
||||
y = y0 + CTRL_TITLE_GAP;
|
||||
for (i = 0; i < rright; i++, y += CTRL_STEP) {
|
||||
const char *key = ctrl_r_key[i], *desc = ctrl_r_desc[i];
|
||||
|
||||
/* Заголовок секции читов: с выключенными читами он же и объясняет,
|
||||
* почему список ниже пуст. */
|
||||
if (i == CTRL_N_SYS && !cheats) desc = "DISABLED";
|
||||
ctrl_row(CTRL_R_KEY, CTRL_R_DESC, y, key, desc);
|
||||
}
|
||||
pop_text_unmap();
|
||||
ui_end(back);
|
||||
|
||||
Reference in New Issue
Block a user