Moved the platform stuff around
This commit is contained in:
@@ -11,11 +11,11 @@ target_sources(microrpg PRIVATE
|
||||
main.c
|
||||
game.c
|
||||
input.c
|
||||
gametime.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(entity)
|
||||
add_subdirectory(scene)
|
||||
add_subdirectory(platform)
|
||||
add_subdirectory(world)
|
||||
|
||||
add_subdirectory(term)
|
||||
27
src/cutscene/cutscene.h
Executable file
27
src/cutscene/cutscene.h
Executable file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "microrpg.h"
|
||||
|
||||
#define CUTSCENE_ITEM_NULL 0
|
||||
#define CUTSCENE_ITEM_TEXTBOX 1
|
||||
#define CUTSCENE_ITEM_CALLBACK 2
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
|
||||
union {
|
||||
const char *textbox;
|
||||
void (*callback)(void);// TODO: Bring entity data across.
|
||||
};
|
||||
} cutsceneitem_t;
|
||||
|
||||
typedef struct {
|
||||
cutsceneitem_t *items;
|
||||
uint8_t itemCount;
|
||||
} cutscene_t;
|
||||
13
src/cutscene/testcutscene.h
Executable file
13
src/cutscene/testcutscene.h
Executable file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "cutscene.h"
|
||||
|
||||
cutsceneitem_t TEST_CUTSCENE_ITEMS[] = {
|
||||
{ .type = CUTSCENE_ITEM_TEXTBOX, .textbox = "Hello World" }
|
||||
};
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
# Sources
|
||||
target_sources(microrpg PRIVATE
|
||||
direction.c
|
||||
entity.c
|
||||
player.c
|
||||
sign.c
|
||||
)
|
||||
32
src/entity/direction.c
Executable file
32
src/entity/direction.c
Executable file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "direction.h"
|
||||
|
||||
void directionGetRelative(const direction_t from, int8_t *outX, int8_t *outY) {
|
||||
switch(from) {
|
||||
case DIRECTION_NORTH:
|
||||
*outX = 0;
|
||||
*outY = -1;
|
||||
break;
|
||||
|
||||
case DIRECTION_EAST:
|
||||
*outX = 1;
|
||||
*outY = 0;
|
||||
break;
|
||||
|
||||
case DIRECTION_SOUTH:
|
||||
*outX = 0;
|
||||
*outY = 1;
|
||||
break;
|
||||
|
||||
case DIRECTION_WEST:
|
||||
*outX = -1;
|
||||
*outY = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -19,3 +19,12 @@
|
||||
#define DIRECTION_WEST DIRECTION_LEFT
|
||||
|
||||
typedef uint8_t direction_t;
|
||||
|
||||
/**
|
||||
* Get the relative x and y offsets for a given direction.
|
||||
*
|
||||
* @param from The direction to get offsets for.
|
||||
* @param outX Pointer to store the x offset.
|
||||
* @param outY Pointer to store the y offset.
|
||||
*/
|
||||
void directionGetRelative(const direction_t from, int8_t *outX, int8_t *outY);
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "entity.h"
|
||||
#include "game.h"
|
||||
|
||||
void entityInit(entity_t *entity, const entitytype_t type) {
|
||||
memset(entity, 0, sizeof(entity_t));
|
||||
@@ -28,21 +29,62 @@ void entityTurn(entity_t *entity, const direction_t direction) {
|
||||
}
|
||||
|
||||
void entityWalk(entity_t *entity, const direction_t direction) {
|
||||
// TODO: Animation, delay, colission, result, etc.
|
||||
// TODO: Animation, delay, etc.
|
||||
entity->direction = direction;
|
||||
|
||||
switch(direction) {
|
||||
case DIRECTION_NORTH:
|
||||
entity->position.y--;
|
||||
// Where are we moving?
|
||||
uint8_t newX, newY;
|
||||
newX = entity->position.x;
|
||||
newY = entity->position.y;
|
||||
{
|
||||
int8_t relX, relY;
|
||||
directionGetRelative(direction, &relX, &relY);
|
||||
newX += relX;
|
||||
newY += relY;
|
||||
}
|
||||
|
||||
// TODO: Tile in way?
|
||||
// TODO: Map bounds in way?
|
||||
|
||||
// Entity in way?
|
||||
entity_t *start = GAME.overworld.map.entities;
|
||||
entity_t *end = start + MAP_ENTITY_COUNT;
|
||||
while(start < end) {
|
||||
if(
|
||||
start == entity ||
|
||||
entity->type == ENTITY_TYPE_NULL ||
|
||||
start->position.x != newX ||
|
||||
start->position.y != newY
|
||||
) {
|
||||
start++;
|
||||
continue;
|
||||
}
|
||||
|
||||
return;// Blocked
|
||||
}
|
||||
|
||||
// Player in way?
|
||||
entity_t *player = &GAME.player;
|
||||
if(
|
||||
entity != player &&
|
||||
player->position.x == newX &&
|
||||
player->position.y == newY
|
||||
) {
|
||||
return;// Blocked
|
||||
}
|
||||
|
||||
// Move.
|
||||
entity->position.x = newX;
|
||||
entity->position.y = newY;
|
||||
}
|
||||
|
||||
void entityInteract(entity_t *entity) {
|
||||
switch(entity->type) {
|
||||
case ENTITY_TYPE_SIGN:
|
||||
signInteract(entity);
|
||||
break;
|
||||
case DIRECTION_EAST:
|
||||
entity->position.x++;
|
||||
break;
|
||||
case DIRECTION_SOUTH:
|
||||
entity->position.y++;
|
||||
break;
|
||||
case DIRECTION_WEST:
|
||||
entity->position.x--;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -9,15 +9,20 @@
|
||||
#include "entity/direction.h"
|
||||
#include "entity/entitytype.h"
|
||||
#include "player.h"
|
||||
#include "sign.h"
|
||||
|
||||
typedef struct entity_s {
|
||||
struct {
|
||||
// Relative to top-left of the map
|
||||
// Relative to top-left position of the top-left chunk of the map.
|
||||
uint8_t x, y;
|
||||
} position;
|
||||
|
||||
direction_t direction;
|
||||
entitytype_t type;
|
||||
|
||||
union {
|
||||
sign_t sign;
|
||||
};
|
||||
} entity_t;
|
||||
|
||||
/**
|
||||
@@ -50,3 +55,10 @@ void entityTurn(entity_t *entity, const direction_t direction);
|
||||
* @param direction The direction to walk in.
|
||||
*/
|
||||
void entityWalk(entity_t *entity, const direction_t direction);
|
||||
|
||||
/**
|
||||
* Receive interaction from player.
|
||||
*
|
||||
* @param entity Pointer to the entity being interacted with.
|
||||
*/
|
||||
void entityInteract(entity_t *entity);
|
||||
@@ -10,5 +10,6 @@
|
||||
|
||||
#define ENTITY_TYPE_NULL 0
|
||||
#define ENTITY_TYPE_PLAYER 1
|
||||
#define ENTITY_TYPE_SIGN 2
|
||||
|
||||
typedef uint8_t entitytype_t;
|
||||
@@ -7,15 +7,65 @@
|
||||
|
||||
#include "entity.h"
|
||||
#include "input.h"
|
||||
#include "game.h"
|
||||
|
||||
void playerTickInput(entity_t *entity) {
|
||||
if(inputPressed(INPUT_ACTION_UP)) {
|
||||
entityWalk(entity, DIRECTION_NORTH);
|
||||
} else if(inputPressed(INPUT_ACTION_DOWN)) {
|
||||
entityWalk(entity, DIRECTION_SOUTH);
|
||||
} else if(inputPressed(INPUT_ACTION_LEFT)) {
|
||||
entityWalk(entity, DIRECTION_WEST);
|
||||
} else if(inputPressed(INPUT_ACTION_RIGHT)) {
|
||||
entityWalk(entity, DIRECTION_EAST);
|
||||
// Turn
|
||||
if(inputPressed(INPUT_ACTION_UP) && entity->direction != DIRECTION_NORTH) {
|
||||
return entityTurn(entity, DIRECTION_NORTH);
|
||||
}
|
||||
if(inputPressed(INPUT_ACTION_DOWN) && entity->direction != DIRECTION_SOUTH) {
|
||||
return entityTurn(entity, DIRECTION_SOUTH);
|
||||
}
|
||||
if(inputPressed(INPUT_ACTION_LEFT) && entity->direction != DIRECTION_WEST) {
|
||||
return entityTurn(entity, DIRECTION_WEST);
|
||||
}
|
||||
if(inputPressed(INPUT_ACTION_RIGHT) && entity->direction != DIRECTION_EAST) {
|
||||
return entityTurn(entity, DIRECTION_EAST);
|
||||
}
|
||||
|
||||
// Walk
|
||||
if(inputDown(INPUT_ACTION_UP)) {
|
||||
return entityWalk(entity, DIRECTION_NORTH);
|
||||
}
|
||||
if(inputDown(INPUT_ACTION_DOWN)) {
|
||||
return entityWalk(entity, DIRECTION_SOUTH);
|
||||
}
|
||||
if(inputDown(INPUT_ACTION_LEFT)) {
|
||||
return entityWalk(entity, DIRECTION_WEST);
|
||||
}
|
||||
if(inputDown(INPUT_ACTION_RIGHT)) {
|
||||
return entityWalk(entity, DIRECTION_EAST);
|
||||
}
|
||||
|
||||
// Interaction
|
||||
if(inputPressed(INPUT_ACTION_A)) {
|
||||
// Facing direction relative
|
||||
uint8_t targetX, targetY;
|
||||
{
|
||||
int8_t faceX, faceY;
|
||||
directionGetRelative(entity->direction, &faceX, &faceY);
|
||||
targetX = entity->position.x + faceX;
|
||||
targetY = entity->position.y + faceY;
|
||||
}
|
||||
|
||||
// For each entity
|
||||
entity_t *start = GAME.overworld.map.entities;
|
||||
entity_t *end = start + MAP_ENTITY_COUNT;
|
||||
while(start < end) {
|
||||
if(
|
||||
start == entity ||
|
||||
start->type == ENTITY_TYPE_NULL ||
|
||||
start->position.x != targetX ||
|
||||
start->position.y != targetY
|
||||
) {
|
||||
start++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Interact
|
||||
entityInteract(start);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/entity/sign.c
Executable file
13
src/entity/sign.c
Executable file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "sign.h"
|
||||
#include "entity.h"
|
||||
|
||||
void signInteract(entity_t *entity) {
|
||||
abort();
|
||||
}
|
||||
22
src/entity/sign.h
Executable file
22
src/entity/sign.h
Executable file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 entity_s entity_t;
|
||||
|
||||
typedef struct sign_s {
|
||||
void *nothing;
|
||||
} sign_t;
|
||||
|
||||
/**
|
||||
* Receive interaction from player.
|
||||
*
|
||||
* @param entity Pointer to the entity being interacted with.
|
||||
*/
|
||||
void signInteract(entity_t *entity);
|
||||
@@ -14,9 +14,14 @@ void gameInit() {
|
||||
|
||||
entityInit(&GAME.player, ENTITY_TYPE_PLAYER);
|
||||
|
||||
entityInit(&GAME.overworld.map.entities[0], ENTITY_TYPE_SIGN);
|
||||
GAME.overworld.map.entities[0].position.x = 5;
|
||||
GAME.overworld.map.entities[0].position.y = 5;
|
||||
|
||||
GAME.scene = SCENE_OVERWORLD;
|
||||
}
|
||||
|
||||
void gameTick() {
|
||||
gameTimeTick(&GAME.time);
|
||||
sceneTick();
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "entity/entity.h"
|
||||
#include "world/map.h"
|
||||
#include "scene/scene.h"
|
||||
#include "gametime.h"
|
||||
|
||||
#define GAME_SCENE_INITIAL 0
|
||||
#define GAME_SCENE_OVERWORLD 1
|
||||
@@ -16,6 +17,7 @@
|
||||
typedef struct game_s {
|
||||
scene_t scene;
|
||||
entity_t player;
|
||||
gametime_t time;
|
||||
|
||||
union {
|
||||
struct {
|
||||
|
||||
38
src/gametime.c
Executable file
38
src/gametime.c
Executable file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "time.h"
|
||||
#include "game.h"
|
||||
|
||||
void gameTimeTick() {
|
||||
GAME.time.ticks++;
|
||||
|
||||
if(GAME.time.ticks >= GAME_TIME_TICKS_PER_SECOND) {
|
||||
GAME.time.ticks = 0;
|
||||
GAME.time.seconds++;
|
||||
|
||||
if(GAME.time.seconds >= GAME_TIME_SECONDS_PER_MINUTE) {
|
||||
GAME.time.seconds = 0;
|
||||
GAME.time.minutes++;
|
||||
|
||||
if(GAME.time.minutes >= GAME_TIME_MINUTES_PER_HOUR) {
|
||||
GAME.time.minutes = 0;
|
||||
GAME.time.hours++;
|
||||
|
||||
if(GAME.time.hours >= GAME_TIME_HOURS_PER_DAY) {
|
||||
GAME.time.hours = 0;
|
||||
GAME.time.days++;
|
||||
|
||||
if(GAME.time.days >= GAME_TIME_DAYS_MAX) {
|
||||
GAME.time.days = 0;
|
||||
// Roll over occured.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/gametime.h
Executable file
36
src/gametime.h
Executable file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "microrpg.h"
|
||||
|
||||
#define GAME_TIME_TICKS_PER_SECOND 60
|
||||
#define GAME_TIME_SECONDS_PER_MINUTE 60
|
||||
#define GAME_TIME_MINUTES_PER_HOUR 60
|
||||
#define GAME_TIME_HOURS_PER_DAY 24
|
||||
#define GAME_TIME_DAYS_MAX 7
|
||||
|
||||
#define GAME_TIME_SUNDAY 0
|
||||
#define GAME_TIME_MONDAY 1
|
||||
#define GAME_TIME_TUESDAY 2
|
||||
#define GAME_TIME_WEDNESDAY 3
|
||||
#define GAME_TIME_THURSDAY 4
|
||||
#define GAME_TIME_FRIDAY 5
|
||||
#define GAME_TIME_SATURDAY 6
|
||||
|
||||
typedef struct gametime_s {
|
||||
uint8_t ticks;
|
||||
uint8_t seconds;
|
||||
uint8_t minutes;
|
||||
uint8_t hours;
|
||||
uint8_t days;
|
||||
} gametime_t;
|
||||
|
||||
/**
|
||||
* Advance the game time by one tick.
|
||||
*/
|
||||
void gameTimeTick();
|
||||
22
src/main.c
22
src/main.c
@@ -6,32 +6,20 @@
|
||||
*/
|
||||
|
||||
#include "game.h"
|
||||
#if RPG_TERM == 1
|
||||
#include "term/term.h"
|
||||
#endif
|
||||
#include "platform/platform.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
gameInit();
|
||||
|
||||
#if RPG_TERM == 1
|
||||
termInit();
|
||||
#endif
|
||||
platformInit();
|
||||
|
||||
while(1) {
|
||||
#if RPG_TERM == 1
|
||||
termUpdate();
|
||||
#endif
|
||||
platformUpdate();
|
||||
|
||||
gameTick();
|
||||
|
||||
#if RPG_TERM == 1
|
||||
termDraw();
|
||||
#endif
|
||||
platformDraw();
|
||||
}
|
||||
|
||||
#if RPG_TERM == 1
|
||||
termDispose();
|
||||
#endif
|
||||
|
||||
platformDispose();
|
||||
return 0;
|
||||
}
|
||||
7
src/platform/CMakeLists.txt
Executable file
7
src/platform/CMakeLists.txt
Executable file
@@ -0,0 +1,7 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Change inclusion to platform-specific
|
||||
add_subdirectory(term)
|
||||
29
src/platform/platform.h
Normal file
29
src/platform/platform.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "microrpg.h"
|
||||
|
||||
/**
|
||||
* Initialize the platform-specific subsystem.
|
||||
*/
|
||||
void platformInit(void);
|
||||
|
||||
/**
|
||||
* Update the platform-specific subsystem.
|
||||
*/
|
||||
void platformUpdate(void);
|
||||
|
||||
/**
|
||||
* Render the platform-specific subsystem.
|
||||
*/
|
||||
void platformDraw(void);
|
||||
|
||||
/**
|
||||
* Dispose of the platform-specific subsystem.
|
||||
*/
|
||||
void platformDispose(void);
|
||||
@@ -20,6 +20,7 @@ target_link_libraries(microrpg PRIVATE
|
||||
target_sources(microrpg PRIVATE
|
||||
term.c
|
||||
inputterm.c
|
||||
platform.c
|
||||
)
|
||||
|
||||
# Compiler flags
|
||||
25
src/platform/term/platform.c
Normal file
25
src/platform/term/platform.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "platform/term/term.h"
|
||||
|
||||
void platformInit() {
|
||||
termInit();
|
||||
}
|
||||
|
||||
void platformUpdate() {
|
||||
termUpdate();
|
||||
}
|
||||
|
||||
void platformDraw() {
|
||||
termDraw();
|
||||
}
|
||||
|
||||
void platformDispose() {
|
||||
termDispose();
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "term.h"
|
||||
#include "input.h"
|
||||
#include <time.h>
|
||||
|
||||
typedef struct terminputmap_s {
|
||||
int key;
|
||||
@@ -44,7 +45,17 @@ void termInit() {
|
||||
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() {
|
||||
@@ -74,9 +85,15 @@ void termUpdate() {
|
||||
|
||||
void termDraw() {
|
||||
clear();
|
||||
attron(COLOR_PAIR(1));
|
||||
|
||||
termDrawEntity(&GAME.player);
|
||||
switch(GAME.scene) {
|
||||
case SCENE_OVERWORLD:
|
||||
termDrawOverworld();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
attroff(COLOR_PAIR(1));
|
||||
refresh();
|
||||
@@ -85,9 +102,43 @@ void termDraw() {
|
||||
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
|
||||
mvaddch(ent->position.y, ent->position.x, '@');
|
||||
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() {
|
||||
@@ -33,6 +33,11 @@ void termUpdate();
|
||||
*/
|
||||
void termDraw();
|
||||
|
||||
/**
|
||||
* Draw the overworld scene.
|
||||
*/
|
||||
void termDrawOverworld();
|
||||
|
||||
/**
|
||||
* Draw an entity to the terminal.
|
||||
*
|
||||
@@ -18,7 +18,7 @@ typedef struct map_s {
|
||||
// Loaded chunks.
|
||||
chunk_t chunks[MAP_CHUNK_COUNT];
|
||||
chunk_t *order[MAP_CHUNK_COUNT];
|
||||
int8_t firstChunk;
|
||||
int8_t topLeftX, topLeftY;
|
||||
|
||||
// Map entities
|
||||
entity_t entities[MAP_ENTITY_COUNT];
|
||||
|
||||
Reference in New Issue
Block a user