Make TTY and Raylib identical
This commit is contained in:
@@ -3,6 +3,6 @@
|
|||||||
# This software is released under the MIT License.
|
# This software is released under the MIT License.
|
||||||
# https://opensource.org/licenses/MIT
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
add_subdirectory(raylib)
|
# add_subdirectory(raylib)
|
||||||
add_subdirectory(term)
|
add_subdirectory(term)
|
||||||
#add_subdirectory(term)
|
add_subdirectory(tty)
|
||||||
@@ -6,19 +6,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
#include "platformraylib.h"
|
||||||
|
|
||||||
bool_t inputDown(const uint8_t action) {
|
bool_t inputDown(const uint8_t action) {
|
||||||
return false;
|
return (PLATFORM_RAYLIB.inputCurrent & action) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t inputUp(const uint8_t action) {
|
bool_t inputUp(const uint8_t action) {
|
||||||
return true;
|
return (PLATFORM_RAYLIB.inputCurrent & action) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t inputWasDown(const uint8_t action) {
|
bool_t inputWasDown(const uint8_t action) {
|
||||||
return false;
|
return (PLATFORM_RAYLIB.inputPrevious & action) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t inputWasUp(const uint8_t action) {
|
bool_t inputWasUp(const uint8_t action) {
|
||||||
return true;
|
return (PLATFORM_RAYLIB.inputPrevious & action) == 0;
|
||||||
}
|
}
|
||||||
@@ -6,18 +6,61 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
#include "platform/raylib/platformraylib.h"
|
||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "platform/term/term.h"
|
#include "platform/term/term.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "game.h"
|
||||||
|
#include "gametime.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
typedef struct rlkeyboardmap_t {
|
||||||
|
uint8_t action;
|
||||||
|
int32_t raylibKey;
|
||||||
|
} rlkeyboardmap_t;
|
||||||
|
|
||||||
|
static const rlkeyboardmap_t RL_KEYBOARD_MAP[] = {
|
||||||
|
{ INPUT_ACTION_UP, KEY_W },
|
||||||
|
{ INPUT_ACTION_UP, KEY_UP },
|
||||||
|
{ INPUT_ACTION_DOWN, KEY_S },
|
||||||
|
{ INPUT_ACTION_DOWN, KEY_DOWN },
|
||||||
|
{ INPUT_ACTION_LEFT, KEY_A },
|
||||||
|
{ INPUT_ACTION_LEFT, KEY_LEFT },
|
||||||
|
{ INPUT_ACTION_RIGHT, KEY_D },
|
||||||
|
{ INPUT_ACTION_RIGHT, KEY_RIGHT },
|
||||||
|
{ INPUT_ACTION_A, KEY_E },
|
||||||
|
{ INPUT_ACTION_B, KEY_Q },
|
||||||
|
{ INPUT_ACTION_START, KEY_ENTER },
|
||||||
|
{ INPUT_ACTION_START, KEY_SPACE },
|
||||||
|
{ INPUT_ACTION_SELECT, KEY_BACKSPACE },
|
||||||
|
{ 0x00, 0x00 }
|
||||||
|
};
|
||||||
|
|
||||||
|
platformraylib_t PLATFORM_RAYLIB;
|
||||||
|
|
||||||
uint8_t platformInit(void) {
|
uint8_t platformInit(void) {
|
||||||
|
memset(&PLATFORM_RAYLIB, 0, sizeof(platformraylib_t));
|
||||||
|
|
||||||
|
// Init raylib.
|
||||||
InitWindow(800, 600, "Micro JRPG");
|
InitWindow(800, 600, "Micro JRPG");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
|
|
||||||
|
// Load font
|
||||||
if(fontInit() != 0) return PLATFORM_ERROR;
|
if(fontInit() != 0) return PLATFORM_ERROR;
|
||||||
|
|
||||||
|
// Resize window
|
||||||
SetWindowSize(40 * FONT.charWidth, 30 * FONT.charHeight);
|
SetWindowSize(40 * FONT.charWidth, 30 * FONT.charHeight);
|
||||||
|
|
||||||
|
// Set in-game time to real world time.
|
||||||
|
time_t now = time(NULL);
|
||||||
|
struct tm *t = localtime(&now);
|
||||||
|
|
||||||
|
GAME.time.days = t->tm_wday;
|
||||||
|
GAME.time.hours = t->tm_hour;
|
||||||
|
GAME.time.minutes = t->tm_min;
|
||||||
|
GAME.time.seconds = t->tm_sec;
|
||||||
|
|
||||||
return PLATFORM_OK;
|
return PLATFORM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +68,18 @@ uint8_t platformUpdate() {
|
|||||||
if(WindowShouldClose()) {
|
if(WindowShouldClose()) {
|
||||||
return PLATFORM_EXIT;
|
return PLATFORM_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update input state.
|
||||||
|
PLATFORM_RAYLIB.inputPrevious = PLATFORM_RAYLIB.inputCurrent;
|
||||||
|
PLATFORM_RAYLIB.inputCurrent = 0;
|
||||||
|
rlkeyboardmap_t *map = RL_KEYBOARD_MAP;
|
||||||
|
do {
|
||||||
|
if(IsKeyDown(map->raylibKey)) {
|
||||||
|
PLATFORM_RAYLIB.inputCurrent |= map->action;
|
||||||
|
}
|
||||||
|
map++;
|
||||||
|
} while(map->action != 0x00);
|
||||||
|
|
||||||
return PLATFORM_OK;
|
return PLATFORM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
src/platform/raylib/platformraylib.h
Normal file
16
src/platform/raylib/platformraylib.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "microrpg.h"
|
||||||
|
|
||||||
|
typedef struct platformraylib_s {
|
||||||
|
uint8_t inputCurrent;
|
||||||
|
uint8_t inputPrevious;
|
||||||
|
} platformraylib_t;
|
||||||
|
|
||||||
|
extern platformraylib_t PLATFORM_RAYLIB;
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
# Sources
|
# Sources
|
||||||
target_sources(microrpg PRIVATE
|
target_sources(microrpg PRIVATE
|
||||||
term.c
|
term.c
|
||||||
|
termoverworld.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# Compiler flags
|
# Compiler flags
|
||||||
|
|||||||
@@ -6,49 +6,50 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "term.h"
|
#include "term.h"
|
||||||
#include "game.h"
|
#include "termoverworld.h"
|
||||||
|
|
||||||
void termDrawOverworld() {
|
|
||||||
// Draw map.
|
|
||||||
|
|
||||||
termDrawEntity(&GAME.player);
|
|
||||||
|
|
||||||
entity_t *start = GAME.overworld.map.entities;
|
|
||||||
entity_t *end = start + MAP_ENTITY_COUNT;
|
|
||||||
while(start < end) {
|
|
||||||
if(start->type != ENTITY_TYPE_NULL) termDrawEntity(start);
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void termDrawEntity(const entity_t *ent) {
|
|
||||||
// Placeholder: Draw entity at its position
|
|
||||||
char c;
|
|
||||||
switch(ent->direction) {
|
|
||||||
case DIRECTION_NORTH:
|
|
||||||
c = '^';
|
|
||||||
break;
|
|
||||||
case DIRECTION_EAST:
|
|
||||||
c = '>';
|
|
||||||
break;
|
|
||||||
case DIRECTION_SOUTH:
|
|
||||||
c = 'v';
|
|
||||||
break;
|
|
||||||
case DIRECTION_WEST:
|
|
||||||
c = '<';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
c = '@';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
termPushChar
|
|
||||||
}
|
|
||||||
|
|
||||||
void termDraw() {
|
void termDraw() {
|
||||||
termClear();
|
termClear();
|
||||||
|
|
||||||
|
int32_t width, height, x, y;
|
||||||
|
width = termGetColumnCount();
|
||||||
|
height = termGetRowCount();
|
||||||
|
|
||||||
|
// Create buffers
|
||||||
|
char_t *chars = malloc(width * height * sizeof(char_t));
|
||||||
|
if(chars == NULL) {
|
||||||
|
printf("termDrawOverworld: Out of memory!\n");
|
||||||
|
abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(chars, ' ', width * height * sizeof(char_t));
|
||||||
|
|
||||||
|
termcolor_t *colors = malloc(width * height * sizeof(termcolor_t));
|
||||||
|
if(colors == NULL) {
|
||||||
|
printf("termDrawOverworld: Out of memory!\n");
|
||||||
|
free(chars);
|
||||||
|
abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(colors, TERM_COLOR_WHITE, width * height * sizeof(termcolor_t));
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
termDrawOverworld(chars, colors, width, height);
|
||||||
|
|
||||||
|
// Print
|
||||||
|
size_t i;
|
||||||
|
termcolor_t curColor = TERM_COLOR_WHITE;
|
||||||
|
for(size_t i = 0; i < width * height; i++) {
|
||||||
|
if(colors[i] != curColor) {
|
||||||
|
termPushColor(colors[i]);
|
||||||
|
curColor = colors[i];
|
||||||
|
}
|
||||||
|
termPushChar(chars[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
free(chars);
|
||||||
|
free(colors);
|
||||||
|
|
||||||
termFlush();
|
termFlush();
|
||||||
}
|
}
|
||||||
46
src/platform/term/termoverworld.c
Normal file
46
src/platform/term/termoverworld.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "termoverworld.h"
|
||||||
|
|
||||||
|
void termDrawOverworld(
|
||||||
|
char_t *chars,
|
||||||
|
termcolor_t *colors,
|
||||||
|
const int32_t w,
|
||||||
|
const int32_t h
|
||||||
|
) {
|
||||||
|
// Draw the ground
|
||||||
|
for(int32_t x = 0; x < w; x++) {
|
||||||
|
for(int32_t y = 0; y < h; y++) {
|
||||||
|
size_t index = y * w + x;
|
||||||
|
chars[index] = '.';
|
||||||
|
colors[index] = TERM_COLOR_GREEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw entities
|
||||||
|
termDrawEntity(&GAME.player, chars, colors, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void termDrawEntity(
|
||||||
|
const entity_t *ent,
|
||||||
|
char_t *chars,
|
||||||
|
termcolor_t *colors,
|
||||||
|
const int32_t w,
|
||||||
|
const int32_t h
|
||||||
|
) {
|
||||||
|
if(ent->type == ENTITY_TYPE_NULL) return;
|
||||||
|
|
||||||
|
if(ent->position.x >= w || ent->position.y >= h) return;
|
||||||
|
|
||||||
|
int32_t index = ent->position.y * w + ent->position.x;
|
||||||
|
|
||||||
|
if(ent->type == ENTITY_TYPE_PLAYER) {
|
||||||
|
chars[index] = '@';
|
||||||
|
colors[index] = TERM_COLOR_YELLOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/platform/term/termoverworld.h
Normal file
42
src/platform/term/termoverworld.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "term.h"
|
||||||
|
#include "game.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the overworld SCENE to the terminal.
|
||||||
|
*
|
||||||
|
* @param chars Buffer of characters to write to.
|
||||||
|
* @param colors Buffer of colors to write to.
|
||||||
|
* @param w Width of the terminal in characters.
|
||||||
|
* @param h Height of the terminal in characters.
|
||||||
|
*/
|
||||||
|
void termDrawOverworld(
|
||||||
|
char_t *chars,
|
||||||
|
termcolor_t *colors,
|
||||||
|
const int32_t w,
|
||||||
|
const int32_t h
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw an entity to the terminal.
|
||||||
|
*
|
||||||
|
* @param ent The entity to draw.
|
||||||
|
* @param chars Buffer of characters to write to.
|
||||||
|
* @param colors Buffer of colors to write to.
|
||||||
|
* @param w Width of the terminal in characters.
|
||||||
|
* @param h Height of the terminal in characters.
|
||||||
|
*/
|
||||||
|
void termDrawEntity(
|
||||||
|
const entity_t *ent,
|
||||||
|
char_t *chars,
|
||||||
|
termcolor_t *colors,
|
||||||
|
const int32_t w,
|
||||||
|
const int32_t h
|
||||||
|
);
|
||||||
@@ -18,12 +18,12 @@ target_link_libraries(microrpg PRIVATE
|
|||||||
|
|
||||||
# Sources
|
# Sources
|
||||||
target_sources(microrpg PRIVATE
|
target_sources(microrpg PRIVATE
|
||||||
term.c
|
|
||||||
inputterm.c
|
inputterm.c
|
||||||
platform.c
|
platform.c
|
||||||
|
termtty.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# Compiler flags
|
# Compiler flags
|
||||||
target_compile_definitions(microrpg PRIVATE
|
target_compile_definitions(microrpg PRIVATE
|
||||||
RPG_TERM=1
|
RPG_TTY=1
|
||||||
)
|
)
|
||||||
@@ -5,20 +5,20 @@
|
|||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "term.h"
|
#include "platformtty.h"
|
||||||
|
|
||||||
bool_t inputDown(const uint8_t action) {
|
bool_t inputDown(const uint8_t action) {
|
||||||
return (TERM.inputCurrent & action) != 0;
|
return (PLATFORM_TTY.inputCurrent & action) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t inputUp(const uint8_t action) {
|
bool_t inputUp(const uint8_t action) {
|
||||||
return (TERM.inputCurrent & action) == 0;
|
return (PLATFORM_TTY.inputCurrent & action) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t inputWasDown(const uint8_t action) {
|
bool_t inputWasDown(const uint8_t action) {
|
||||||
return (TERM.inputPrevious & action) != 0;
|
return (PLATFORM_TTY.inputPrevious & action) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t inputWasUp(const uint8_t action) {
|
bool_t inputWasUp(const uint8_t action) {
|
||||||
return (TERM.inputPrevious & action) == 0;
|
return (PLATFORM_TTY.inputPrevious & action) == 0;
|
||||||
}
|
}
|
||||||
@@ -7,19 +7,109 @@
|
|||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "platform/term/term.h"
|
#include "platform/term/term.h"
|
||||||
|
#include "platform/tty/platformtty.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
void platformInit() {
|
typedef struct ttyinputmap_s {
|
||||||
termInit();
|
int key;
|
||||||
|
uint8_t action;
|
||||||
|
} ttyinputmap_t;
|
||||||
|
|
||||||
|
static const ttyinputmap_t TERM_INPUT_MAP[] = {
|
||||||
|
{ KEY_UP, INPUT_ACTION_UP },
|
||||||
|
{ 'w', INPUT_ACTION_UP },
|
||||||
|
{ KEY_DOWN, INPUT_ACTION_DOWN },
|
||||||
|
{ 's', INPUT_ACTION_DOWN },
|
||||||
|
{ KEY_LEFT, INPUT_ACTION_LEFT },
|
||||||
|
{ 'a', INPUT_ACTION_LEFT },
|
||||||
|
{ KEY_RIGHT, INPUT_ACTION_RIGHT },
|
||||||
|
{ 'd', INPUT_ACTION_RIGHT },
|
||||||
|
{ 'j', INPUT_ACTION_A },
|
||||||
|
{ 'e', INPUT_ACTION_A },
|
||||||
|
{ 'k', INPUT_ACTION_B },
|
||||||
|
{ 'q', INPUT_ACTION_B },
|
||||||
|
{ KEY_ENTER, INPUT_ACTION_START },
|
||||||
|
{ ' ', INPUT_ACTION_SELECT },
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
platformtty_t PLATFORM_TTY;
|
||||||
|
|
||||||
|
uint8_t platformInit() {
|
||||||
|
memset(&PLATFORM_TTY, 0, sizeof(platformtty_t));
|
||||||
|
|
||||||
|
initscr();
|
||||||
|
cbreak();
|
||||||
|
noecho();
|
||||||
|
keypad(stdscr, TRUE);
|
||||||
|
nodelay(stdscr, TRUE);
|
||||||
|
curs_set(0);
|
||||||
|
start_color();
|
||||||
|
use_default_colors();
|
||||||
|
|
||||||
|
// Color Pairs
|
||||||
|
init_pair(TERM_COLOR_BLACK, COLOR_BLACK, -1);
|
||||||
|
init_pair(TERM_COLOR_RED, COLOR_RED, -1);
|
||||||
|
init_pair(TERM_COLOR_GREEN, COLOR_GREEN, -1);
|
||||||
|
init_pair(TERM_COLOR_YELLOW, COLOR_YELLOW, -1);
|
||||||
|
init_pair(TERM_COLOR_BLUE, COLOR_BLUE, -1);
|
||||||
|
init_pair(TERM_COLOR_MAGENTA, COLOR_MAGENTA, -1);
|
||||||
|
init_pair(TERM_COLOR_CYAN, COLOR_CYAN, -1);
|
||||||
|
init_pair(TERM_COLOR_WHITE, COLOR_WHITE, -1);
|
||||||
|
|
||||||
|
|
||||||
|
// Set in-game time to real world time.
|
||||||
|
time_t now = time(NULL);
|
||||||
|
struct tm *t = localtime(&now);
|
||||||
|
|
||||||
|
GAME.time.days = t->tm_wday;
|
||||||
|
GAME.time.hours = t->tm_hour;
|
||||||
|
GAME.time.minutes = t->tm_min;
|
||||||
|
GAME.time.seconds = t->tm_sec;
|
||||||
|
|
||||||
|
return PLATFORM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void platformUpdate() {
|
uint8_t platformUpdate() {
|
||||||
termUpdate();
|
PLATFORM_TTY.inputPrevious = PLATFORM_TTY.inputCurrent;
|
||||||
|
PLATFORM_TTY.inputCurrent = 0;
|
||||||
|
|
||||||
|
int ch = getch();
|
||||||
|
if(ch == ERR) {
|
||||||
|
PLATFORM_TTY.lastch = ERR;
|
||||||
|
return PLATFORM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ch == PLATFORM_TTY.lastch) {
|
||||||
|
return PLATFORM_OK;
|
||||||
|
}
|
||||||
|
PLATFORM_TTY.lastch = ch;
|
||||||
|
|
||||||
|
const ttyinputmap_t *map = TERM_INPUT_MAP;
|
||||||
|
while(map->key != -1) {
|
||||||
|
if(map->key == ch) {
|
||||||
|
PLATFORM_TTY.inputCurrent |= map->action;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
map++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PLATFORM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void platformDraw() {
|
void platformDraw() {
|
||||||
|
clear();
|
||||||
|
|
||||||
termDraw();
|
termDraw();
|
||||||
|
|
||||||
|
attroff(COLOR_PAIR(1));
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
// 16ms delay (60FPS)
|
||||||
|
napms(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void platformDispose() {
|
void platformDispose() {
|
||||||
termDispose();
|
endwin();
|
||||||
}
|
}
|
||||||
19
src/platform/tty/platformtty.h
Executable file
19
src/platform/tty/platformtty.h
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "microrpg.h"
|
||||||
|
#include "game.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
typedef struct platformtty_s {
|
||||||
|
uint8_t inputCurrent;
|
||||||
|
uint8_t inputPrevious;
|
||||||
|
int lastch;
|
||||||
|
} platformtty_t;
|
||||||
|
|
||||||
|
extern platformtty_t PLATFORM_TTY;
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "term.h"
|
|
||||||
#include "input.h"
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
typedef struct terminputmap_s {
|
|
||||||
int key;
|
|
||||||
uint8_t action;
|
|
||||||
} terminputmap_t;
|
|
||||||
|
|
||||||
static const terminputmap_t TERM_INPUT_MAP[] = {
|
|
||||||
{ KEY_UP, INPUT_ACTION_UP },
|
|
||||||
{ 'w', INPUT_ACTION_UP },
|
|
||||||
{ KEY_DOWN, INPUT_ACTION_DOWN },
|
|
||||||
{ 's', INPUT_ACTION_DOWN },
|
|
||||||
{ KEY_LEFT, INPUT_ACTION_LEFT },
|
|
||||||
{ 'a', INPUT_ACTION_LEFT },
|
|
||||||
{ KEY_RIGHT, INPUT_ACTION_RIGHT },
|
|
||||||
{ 'd', INPUT_ACTION_RIGHT },
|
|
||||||
{ 'j', INPUT_ACTION_A },
|
|
||||||
{ 'e', INPUT_ACTION_A },
|
|
||||||
{ 'k', INPUT_ACTION_B },
|
|
||||||
{ 'q', INPUT_ACTION_B },
|
|
||||||
{ KEY_ENTER, INPUT_ACTION_START },
|
|
||||||
{ ' ', INPUT_ACTION_SELECT },
|
|
||||||
{ -1, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
term_t TERM;
|
|
||||||
|
|
||||||
void termInit() {
|
|
||||||
memset(&TERM, 0, sizeof(TERM));
|
|
||||||
|
|
||||||
initscr();
|
|
||||||
cbreak();
|
|
||||||
noecho();
|
|
||||||
keypad(stdscr, TRUE);
|
|
||||||
nodelay(stdscr, TRUE);
|
|
||||||
curs_set(0);
|
|
||||||
start_color();
|
|
||||||
use_default_colors();
|
|
||||||
|
|
||||||
init_pair(1, COLOR_GREEN, -1);
|
|
||||||
|
|
||||||
// Set in-game time to real world time.
|
|
||||||
time_t now = time(NULL);
|
|
||||||
struct tm *t = localtime(&now);
|
|
||||||
|
|
||||||
GAME.time.days = t->tm_wday;
|
|
||||||
GAME.time.hours = t->tm_hour;
|
|
||||||
GAME.time.minutes = t->tm_min;
|
|
||||||
GAME.time.seconds = t->tm_sec;
|
|
||||||
}
|
|
||||||
|
|
||||||
void termUpdate() {
|
|
||||||
TERM.inputPrevious = TERM.inputCurrent;
|
|
||||||
TERM.inputCurrent = 0;
|
|
||||||
|
|
||||||
int ch = getch();
|
|
||||||
if(ch == ERR) {
|
|
||||||
TERM.lastch = ERR;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ch == TERM.lastch) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TERM.lastch = ch;
|
|
||||||
|
|
||||||
const terminputmap_t *map = TERM_INPUT_MAP;
|
|
||||||
while(map->key != -1) {
|
|
||||||
if(map->key == ch) {
|
|
||||||
TERM.inputCurrent |= map->action;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
map++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void termDraw() {
|
|
||||||
clear();
|
|
||||||
|
|
||||||
switch(GAME.scene) {
|
|
||||||
case SCENE_OVERWORLD:
|
|
||||||
termDrawOverworld();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
attroff(COLOR_PAIR(1));
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
// 16ms delay (60FPS)
|
|
||||||
napms(16);
|
|
||||||
}
|
|
||||||
|
|
||||||
void termDrawOverworld() {
|
|
||||||
// Draw map.
|
|
||||||
|
|
||||||
// Draw entities.
|
|
||||||
attron(COLOR_PAIR(1));
|
|
||||||
termDrawEntity(&GAME.player);
|
|
||||||
|
|
||||||
entity_t *start = GAME.overworld.map.entities;
|
|
||||||
entity_t *end = start + MAP_ENTITY_COUNT;
|
|
||||||
while(start < end) {
|
|
||||||
if(start->type != ENTITY_TYPE_NULL) termDrawEntity(start);
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void termDrawEntity(const entity_t *ent) {
|
|
||||||
// Placeholder: Draw entity at its position
|
|
||||||
char c;
|
|
||||||
switch(ent->direction) {
|
|
||||||
case DIRECTION_NORTH:
|
|
||||||
c = '^';
|
|
||||||
break;
|
|
||||||
case DIRECTION_EAST:
|
|
||||||
c = '>';
|
|
||||||
break;
|
|
||||||
case DIRECTION_SOUTH:
|
|
||||||
c = 'v';
|
|
||||||
break;
|
|
||||||
case DIRECTION_WEST:
|
|
||||||
c = '<';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
c = '@';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mvaddch(ent->position.y, ent->position.x, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void termDispose() {
|
|
||||||
endwin();
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "microrpg.h"
|
|
||||||
#include "game.h"
|
|
||||||
#include <ncurses.h>
|
|
||||||
|
|
||||||
typedef struct term_s {
|
|
||||||
uint8_t inputCurrent;
|
|
||||||
uint8_t inputPrevious;
|
|
||||||
int lastch;
|
|
||||||
} term_t;
|
|
||||||
|
|
||||||
extern term_t TERM;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the terminal subsystem.
|
|
||||||
*/
|
|
||||||
void termInit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the terminal prior to game update.
|
|
||||||
*/
|
|
||||||
void termUpdate();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw the terminal game.
|
|
||||||
*/
|
|
||||||
void termDraw();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw the overworld scene.
|
|
||||||
*/
|
|
||||||
void termDrawOverworld();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw an entity to the terminal.
|
|
||||||
*
|
|
||||||
* @param ent The entity to draw.
|
|
||||||
*/
|
|
||||||
void termDrawEntity(const entity_t *ent);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispose of the terminal subsystem.
|
|
||||||
*/
|
|
||||||
void termDispose();
|
|
||||||
37
src/platform/tty/termtty.c
Normal file
37
src/platform/tty/termtty.c
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "platform/term/term.h"
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
void termClear() {
|
||||||
|
clear();
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void termFlush() {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t termGetColumnCount() {
|
||||||
|
int cols = getmaxx(stdscr);
|
||||||
|
return (uint8_t)cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t termGetRowCount() {
|
||||||
|
int rows = getmaxy(stdscr);
|
||||||
|
return (uint8_t)rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
void termPushColor(termcolor_t color) {
|
||||||
|
// Map the termcolor_t to the ncurses color pair
|
||||||
|
attron(COLOR_PAIR((int)color));
|
||||||
|
}
|
||||||
|
|
||||||
|
void termPushChar(char_t c) {
|
||||||
|
addch(c);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user