New basic console
This commit is contained in:
@ -3,6 +3,5 @@
|
|||||||
# 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(dusk)
|
add_subdirectory(dusktest)
|
||||||
add_subdirectory(duskgl)
|
add_subdirectory(dusk)
|
||||||
add_subdirectory(duskglfw)
|
|
@ -17,12 +17,10 @@ target_include_directories(${DUSK_TARGET_NAME}
|
|||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
game.c
|
|
||||||
input.c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
add_subdirectory(assert)
|
add_subdirectory(assert)
|
||||||
add_subdirectory(display)
|
add_subdirectory(console)
|
||||||
add_subdirectory(overworld)
|
add_subdirectory(error)
|
||||||
add_subdirectory(util)
|
add_subdirectory(util)
|
@ -122,7 +122,7 @@ void assertMemoryRangeMatchesImpl(
|
|||||||
#define assertDeprecated(message) \
|
#define assertDeprecated(message) \
|
||||||
assertDeprecatedImpl(__FILE__, __LINE__, message)
|
assertDeprecatedImpl(__FILE__, __LINE__, message)
|
||||||
|
|
||||||
#define assertStrLen(str, len, message) \
|
#define assertStrLenMax(str, len, message) \
|
||||||
assertTrue(strlen(str) <= len, message)
|
assertTrue(strlen(str) <= len, message)
|
||||||
|
|
||||||
#define assertStrLenMin(str, len, message) \
|
#define assertStrLenMin(str, len, message) \
|
||||||
|
@ -6,8 +6,7 @@
|
|||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
scene.c
|
console.c
|
||||||
tileset.c
|
consolecmd.c
|
||||||
)
|
consolevar.c
|
||||||
|
)
|
||||||
# Subdirs
|
|
224
src/dusk/console/console.c
Normal file
224
src/dusk/console/console.c
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "console.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
|
console_t CONSOLE;
|
||||||
|
|
||||||
|
void consoleInit() {
|
||||||
|
memoryZero(&CONSOLE, sizeof(console_t));
|
||||||
|
|
||||||
|
// Register the get and set command.
|
||||||
|
CONSOLE.cmdGet = consoleRegCmd("get", consoleCmdGet);
|
||||||
|
CONSOLE.cmdSet = consoleRegCmd("set", consoleCmdSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
consolecmd_t * consoleRegCmd(const char_t *name, consolecmdfunc_t function) {
|
||||||
|
consolecmd_t *cmd = &CONSOLE.commands[CONSOLE.commandCount++];
|
||||||
|
consoleCmdInit(cmd, name, function);
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
consolevar_t * consoleRegVar(
|
||||||
|
const char_t *name,
|
||||||
|
const char_t *value,
|
||||||
|
consolevarchanged_t event
|
||||||
|
) {
|
||||||
|
consolevar_t *var = &CONSOLE.variables[CONSOLE.variableCount++];
|
||||||
|
consoleVarInitListener(var, name, value, event);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
void consolePrint(const char_t *message, ...) {
|
||||||
|
char_t buffer[CONSOLE_LINE_MAX];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, message);
|
||||||
|
size_t len = vsnprintf(buffer, CONSOLE_LINE_MAX, message, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
assertTrue(len < CONSOLE_LINE_MAX, "Message is too long.");
|
||||||
|
|
||||||
|
// Move all lines back
|
||||||
|
memoryMove(
|
||||||
|
CONSOLE.line[0],
|
||||||
|
CONSOLE.line[1],
|
||||||
|
(CONSOLE_HISTORY_MAX - 1) * CONSOLE_LINE_MAX
|
||||||
|
);
|
||||||
|
|
||||||
|
// Copy the new line
|
||||||
|
memoryCopy(
|
||||||
|
CONSOLE.line[CONSOLE_HISTORY_MAX - 1],
|
||||||
|
buffer,
|
||||||
|
len + 1
|
||||||
|
);
|
||||||
|
printf("%s\n", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void consoleExec(const char_t *line) {
|
||||||
|
assertNotNull(line, "line must not be NULL");
|
||||||
|
assertTrue(
|
||||||
|
CONSOLE.execBufferCount < CONSOLE_EXEC_BUFFER_MAX,
|
||||||
|
"Too many commands in the buffer."
|
||||||
|
);
|
||||||
|
|
||||||
|
if(line[0] == '\0') return;
|
||||||
|
|
||||||
|
char_t buffer[CONSOLE_LINE_MAX + 1];
|
||||||
|
size_t i = 0, j = 0;
|
||||||
|
char_t c;
|
||||||
|
|
||||||
|
do {
|
||||||
|
c = line[i++];
|
||||||
|
|
||||||
|
// Handle command separation by semicolon or end of line
|
||||||
|
if(c == ';' || c == '\0') {
|
||||||
|
// Null-terminate the current command and trim whitespace
|
||||||
|
buffer[j] = '\0';
|
||||||
|
stringTrim(buffer);
|
||||||
|
|
||||||
|
// Skip empty commands
|
||||||
|
if(buffer[0] == '\0') {
|
||||||
|
j = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the exec buffer is not full
|
||||||
|
assertTrue(
|
||||||
|
CONSOLE.execBufferCount < CONSOLE_EXEC_BUFFER_MAX,
|
||||||
|
"Too many commands in the buffer."
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create a new command execution
|
||||||
|
consolecmdexec_t *exec = &CONSOLE.execBuffer[CONSOLE.execBufferCount++];
|
||||||
|
memoryZero(exec, sizeof(consolecmdexec_t));
|
||||||
|
|
||||||
|
// Parse command and arguments
|
||||||
|
char_t *token = strtok(buffer, " ");
|
||||||
|
while(token != NULL) {
|
||||||
|
assertTrue(
|
||||||
|
exec->argc < CONSOLE_CMD_ARGC_MAX,
|
||||||
|
"Too many arguments in the command."
|
||||||
|
);
|
||||||
|
stringCopy(exec->argv[exec->argc++], token, CONSOLE_LINE_MAX);
|
||||||
|
token = strtok(NULL, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, see if there's a matching command.
|
||||||
|
for(uint32_t k = 0; k < CONSOLE.commandCount; k++) {
|
||||||
|
if(stringCompare(CONSOLE.commands[k].name, exec->argv[0]) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
exec->cmd = &CONSOLE.commands[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If match found continue
|
||||||
|
if(exec->cmd != NULL) {
|
||||||
|
j = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no match found, see if there's a matching variable.
|
||||||
|
consolevar_t *var = NULL;
|
||||||
|
|
||||||
|
for(uint32_t k = 0; k < CONSOLE.variableCount; k++) {
|
||||||
|
if(stringCompare(CONSOLE.variables[k].name, exec->argv[0]) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var = &CONSOLE.variables[k];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no variable found, error out.
|
||||||
|
if(!var) {
|
||||||
|
consolePrint("Error: Command/Variable '%s' not found.", exec->argv[0]);
|
||||||
|
CONSOLE.execBufferCount--;
|
||||||
|
j = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Found a matching variable, we basically change this entire command
|
||||||
|
// to a get or a set. Arguments are reversed so they aren't stepped over
|
||||||
|
if(exec->argc == 1) {
|
||||||
|
exec->cmd = CONSOLE.cmdGet;
|
||||||
|
exec->argc = 2;
|
||||||
|
stringCopy(exec->argv[1], var->name, CONSOLE_LINE_MAX);
|
||||||
|
stringCopy(exec->argv[0], CONSOLE.cmdGet->name, CONSOLE_LINE_MAX);
|
||||||
|
} else {
|
||||||
|
exec->cmd = CONSOLE.cmdSet;
|
||||||
|
exec->argc = 3;
|
||||||
|
stringCopy(exec->argv[2], exec->argv[1], CONSOLE_LINE_MAX);
|
||||||
|
stringCopy(exec->argv[1], var->name, CONSOLE_LINE_MAX);
|
||||||
|
stringCopy(exec->argv[0], CONSOLE.cmdSet->name, CONSOLE_LINE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(j >= CONSOLE_LINE_MAX) {
|
||||||
|
assertTrue(false, "Command exceeds maximum length.");
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[j++] = c; // Accumulate characters into the buffer
|
||||||
|
} while(c != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
void consoleProcess() {
|
||||||
|
for(uint32_t i = 0; i < CONSOLE.execBufferCount; i++) {
|
||||||
|
consolecmdexec_t *exec = &CONSOLE.execBuffer[i];
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
exec->argc > 0,
|
||||||
|
"Command execution has no arguments."
|
||||||
|
);
|
||||||
|
assertNotNull(
|
||||||
|
exec->cmd,
|
||||||
|
"Command execution has no command."
|
||||||
|
);
|
||||||
|
|
||||||
|
exec->cmd->function(exec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the exec buffer
|
||||||
|
CONSOLE.execBufferCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void consoleCmdGet(const consolecmdexec_t *exec) {
|
||||||
|
assertTrue(
|
||||||
|
exec->argc >= 2,
|
||||||
|
"get command requires 1 argument."
|
||||||
|
);
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < CONSOLE.variableCount; i++) {
|
||||||
|
consolevar_t *var = &CONSOLE.variables[i];
|
||||||
|
if(stringCompare(var->name, exec->argv[1]) != 0) continue;
|
||||||
|
consolePrint("%s", var->value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
consolePrint("Error: Variable '%s' not found.", exec->argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void consoleCmdSet(const consolecmdexec_t *exec) {
|
||||||
|
assertTrue(
|
||||||
|
exec->argc >= 3,
|
||||||
|
"set command requires 2 arguments."
|
||||||
|
);
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < CONSOLE.variableCount; i++) {
|
||||||
|
consolevar_t *var = &CONSOLE.variables[i];
|
||||||
|
if(stringCompare(var->name, exec->argv[1]) != 0) continue;
|
||||||
|
consoleVarSetValue(var, exec->argv[2]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
consolePrint("Error: Variable '%s' not found.", exec->argv[1]);
|
||||||
|
}
|
95
src/dusk/console/console.h
Normal file
95
src/dusk/console/console.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "consolevar.h"
|
||||||
|
#include "consolecmd.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
consolecmd_t commands[CONSOLE_COMMANDS_MAX];
|
||||||
|
uint32_t commandCount;
|
||||||
|
|
||||||
|
consolevar_t variables[CONSOLE_VARIABLES_MAX];
|
||||||
|
uint32_t variableCount;
|
||||||
|
|
||||||
|
char_t line[CONSOLE_HISTORY_MAX][CONSOLE_LINE_MAX];
|
||||||
|
|
||||||
|
consolecmdexec_t execBuffer[CONSOLE_EXEC_BUFFER_MAX];
|
||||||
|
uint32_t execBufferCount;
|
||||||
|
|
||||||
|
consolecmd_t *cmdGet;
|
||||||
|
consolecmd_t *cmdSet;
|
||||||
|
} console_t;
|
||||||
|
|
||||||
|
extern console_t CONSOLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the console.
|
||||||
|
*/
|
||||||
|
void consoleInit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a console command.
|
||||||
|
*
|
||||||
|
* @param name The name of the command.
|
||||||
|
* @param function The function to execute when the command is called.
|
||||||
|
* @return The registered command.
|
||||||
|
*/
|
||||||
|
consolecmd_t * consoleRegCmd(const char_t *name, consolecmdfunc_t function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a console variable.
|
||||||
|
*
|
||||||
|
* @param name The name of the variable.
|
||||||
|
* @param value The initial value of the variable.
|
||||||
|
* @param event The event to register.
|
||||||
|
* @return The registered variable.
|
||||||
|
*/
|
||||||
|
consolevar_t * consoleRegVar(
|
||||||
|
const char_t *name,
|
||||||
|
const char_t *value,
|
||||||
|
consolevarchanged_t event
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of a console variable.
|
||||||
|
*
|
||||||
|
* @param name The name of the variable.
|
||||||
|
* @param value The new value of the variable.
|
||||||
|
*/
|
||||||
|
void consolePrint(
|
||||||
|
const char_t *message,
|
||||||
|
...
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a console command.
|
||||||
|
*
|
||||||
|
* @param line The line to execute.
|
||||||
|
*/
|
||||||
|
void consoleExec(const char_t *line);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the console's pending commands.
|
||||||
|
*/
|
||||||
|
void consoleProcess();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of a console variable.
|
||||||
|
*
|
||||||
|
* @param name The name of the variable.
|
||||||
|
* @return The value of the variable.
|
||||||
|
*/
|
||||||
|
void consoleCmdGet(const consolecmdexec_t *exec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of a console variable.
|
||||||
|
*
|
||||||
|
* @param name The name of the variable.
|
||||||
|
* @param value The new value of the variable.
|
||||||
|
*/
|
||||||
|
void consoleCmdSet(const consolecmdexec_t *exec);
|
27
src/dusk/console/consolecmd.c
Normal file
27
src/dusk/console/consolecmd.c
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "consolecmd.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
|
void consoleCmdInit(
|
||||||
|
consolecmd_t *cmd,
|
||||||
|
const char_t *name,
|
||||||
|
consolecmdfunc_t function
|
||||||
|
) {
|
||||||
|
assertNotNull(cmd, "Command is NULL.");
|
||||||
|
assertNotNull(name, "Name is NULL.");
|
||||||
|
assertNotNull(function, "Function is NULL.");
|
||||||
|
assertStrLenMin(name, 1, "Name is empty.");
|
||||||
|
assertStrLenMax(name, CONSOLE_CMD_NAME_MAX, "Name is too long.");
|
||||||
|
|
||||||
|
memoryZero(cmd, sizeof(consolecmd_t));
|
||||||
|
stringCopy(cmd->name, name, CONSOLE_CMD_NAME_MAX);
|
||||||
|
cmd->function = function;
|
||||||
|
}
|
38
src/dusk/console/consolecmd.h
Normal file
38
src/dusk/console/consolecmd.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
#include "consoledefs.h"
|
||||||
|
|
||||||
|
typedef struct consolecmd_s consolecmd_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const consolecmd_t *cmd;
|
||||||
|
uint32_t argc;
|
||||||
|
char_t argv[CONSOLE_CMD_ARGC_MAX][CONSOLE_LINE_MAX];
|
||||||
|
} consolecmdexec_t;
|
||||||
|
|
||||||
|
typedef void (*consolecmdfunc_t)(const consolecmdexec_t *exec);
|
||||||
|
|
||||||
|
typedef struct consolecmd_s {
|
||||||
|
char_t name[CONSOLE_CMD_NAME_MAX + 1];
|
||||||
|
consolecmdfunc_t function;
|
||||||
|
} consolecmd_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a console command.
|
||||||
|
*
|
||||||
|
* @param cmd Pointer to the console command.
|
||||||
|
* @param name The name of the command.
|
||||||
|
* @param function The function to execute when the command is called.
|
||||||
|
*/
|
||||||
|
void consoleCmdInit(
|
||||||
|
consolecmd_t *cmd,
|
||||||
|
const char_t *name,
|
||||||
|
consolecmdfunc_t function
|
||||||
|
);
|
21
src/dusk/console/consoledefs.h
Normal file
21
src/dusk/console/consoledefs.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CONSOLE_CMD_NAME_MAX 32
|
||||||
|
#define CONSOLE_CMD_ARGC_MAX 16
|
||||||
|
|
||||||
|
#define CONSOLE_COMMANDS_MAX 128
|
||||||
|
#define CONSOLE_VARIABLES_MAX 128
|
||||||
|
#define CONSOLE_LINE_MAX 256
|
||||||
|
#define CONSOLE_HISTORY_MAX 32
|
||||||
|
#define CONSOLE_EXEC_BUFFER_MAX 16
|
||||||
|
|
||||||
|
#define CONSOLE_VAR_NAME_MAX 32
|
||||||
|
#define CONSOLE_VAR_VALUE_MAX 128
|
||||||
|
#define CONSOLE_VAR_EVENTS_MAX 8
|
64
src/dusk/console/consolevar.c
Normal file
64
src/dusk/console/consolevar.c
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "consolevar.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
|
void consoleVarInit(
|
||||||
|
consolevar_t *var,
|
||||||
|
const char_t *name,
|
||||||
|
const char_t *value
|
||||||
|
) {
|
||||||
|
assertNotNull(var, "var must not be NULL");
|
||||||
|
assertNotNull(name, "name must not be NULL");
|
||||||
|
assertNotNull(value, "value must not be NULL");
|
||||||
|
|
||||||
|
assertStrLenMin(name, 1, "name must not be empty");
|
||||||
|
assertStrLenMax(name, CONSOLE_VAR_NAME_MAX, "name is too long");
|
||||||
|
assertStrLenMax(value, CONSOLE_VAR_VALUE_MAX, "value is too long");
|
||||||
|
|
||||||
|
memoryZero(var, sizeof(consolevar_t));
|
||||||
|
stringCopy(var->name, name, CONSOLE_VAR_NAME_MAX);
|
||||||
|
stringCopy(var->value, value, CONSOLE_VAR_VALUE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void consoleVarInitListener(
|
||||||
|
consolevar_t *var,
|
||||||
|
const char_t *name,
|
||||||
|
const char_t *value,
|
||||||
|
consolevarchanged_t event
|
||||||
|
) {
|
||||||
|
consoleVarInit(var, name, value);
|
||||||
|
if(event) consoleVarListen(var, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void consoleVarSetValue(consolevar_t *var, const char_t *value) {
|
||||||
|
assertNotNull(var, "var must not be NULL");
|
||||||
|
assertNotNull(value, "value must not be NULL");
|
||||||
|
assertStrLenMax(value, CONSOLE_VAR_VALUE_MAX, "value is too long");
|
||||||
|
|
||||||
|
stringCopy(var->value, value, CONSOLE_VAR_VALUE_MAX);
|
||||||
|
|
||||||
|
uint8_t i = 0;
|
||||||
|
while (i < var->eventCount) {
|
||||||
|
var->events[i](var);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void consoleVarListen(consolevar_t *var, consolevarchanged_t event) {
|
||||||
|
assertNotNull(var, "var must not be NULL");
|
||||||
|
assertNotNull(event, "event must not be NULL");
|
||||||
|
assertTrue(
|
||||||
|
var->eventCount < CONSOLE_VAR_EVENTS_MAX,
|
||||||
|
"Event count is too high"
|
||||||
|
);
|
||||||
|
var->events[var->eventCount++] = event;
|
||||||
|
}
|
||||||
|
|
65
src/dusk/console/consolevar.h
Normal file
65
src/dusk/console/consolevar.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
#include "consoledefs.h"
|
||||||
|
|
||||||
|
typedef struct consolevar_s consolevar_t;
|
||||||
|
|
||||||
|
typedef void (*consolevarchanged_t)(const consolevar_t *var);
|
||||||
|
|
||||||
|
typedef struct consolevar_s {
|
||||||
|
char_t name[CONSOLE_VAR_NAME_MAX + 1];
|
||||||
|
char_t value[CONSOLE_VAR_VALUE_MAX + 1];
|
||||||
|
consolevarchanged_t events[CONSOLE_VAR_EVENTS_MAX];
|
||||||
|
uint8_t eventCount;
|
||||||
|
} consolevar_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a console variable.
|
||||||
|
*
|
||||||
|
* @param var Pointer to the console variable.
|
||||||
|
* @param name The name of the variable.
|
||||||
|
* @param value The initial value of the variable.
|
||||||
|
*/
|
||||||
|
void consoleVarInit(
|
||||||
|
consolevar_t *var,
|
||||||
|
const char_t *name,
|
||||||
|
const char_t *value
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a console variable with a listener.
|
||||||
|
*
|
||||||
|
* @param var Pointer to the console variable.
|
||||||
|
* @param name The name of the variable.
|
||||||
|
* @param value The initial value of the variable.
|
||||||
|
* @param event The event to register.
|
||||||
|
*/
|
||||||
|
void consoleVarInitListener(
|
||||||
|
consolevar_t *var,
|
||||||
|
const char_t *name,
|
||||||
|
const char_t *value,
|
||||||
|
consolevarchanged_t event
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of a console variable.
|
||||||
|
*
|
||||||
|
* @param var Pointer to the console variable.
|
||||||
|
* @param value The new value of the variable.
|
||||||
|
*/
|
||||||
|
void consoleVarSetValue(consolevar_t *var, const char_t *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an event to be called when the value of a console variable changes.
|
||||||
|
*
|
||||||
|
* @param var Pointer to the console variable.
|
||||||
|
* @param event The event to register.
|
||||||
|
*/
|
||||||
|
void consoleVarListen(consolevar_t *var, consolevarchanged_t event);
|
@ -1,9 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define SCREEN_WIDTH 320
|
|
||||||
#define SCREEN_HEIGHT 240
|
|
@ -1,65 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "scene.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
#include "overworld/overworld.h"
|
|
||||||
|
|
||||||
scenetypecallback_t SCENE_CALLBACKS[] = {
|
|
||||||
// SCENE_TYPE_INITIAL
|
|
||||||
{ NULL, NULL, NULL, NULL, NULL },
|
|
||||||
|
|
||||||
// SCENE_TYPE_OVERWORLD
|
|
||||||
{
|
|
||||||
overworldInit,
|
|
||||||
overworldSceneInit,
|
|
||||||
overworldSceneDeinit,
|
|
||||||
overworldUpdate,
|
|
||||||
overworldRender
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
scene_t SCENE;
|
|
||||||
|
|
||||||
void sceneInit() {
|
|
||||||
memoryZero(&SCENE, sizeof(scene_t));
|
|
||||||
|
|
||||||
for(uint8_t i = 0; i < SCENE_TYPE_COUNT; i++) {
|
|
||||||
if(SCENE_CALLBACKS[i].onInit) SCENE_CALLBACKS[i].onInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
sceneSet(SCENE_TYPE_OVERWORLD);// Testing
|
|
||||||
}
|
|
||||||
|
|
||||||
void sceneUpdate() {
|
|
||||||
assertTrue(SCENE.current < SCENE_TYPE_COUNT, "Invalid Scene Type");
|
|
||||||
|
|
||||||
if(SCENE.next != SCENE.current) {
|
|
||||||
SCENE.current = SCENE.next;
|
|
||||||
if(SCENE_CALLBACKS[SCENE.current].onActive) {
|
|
||||||
SCENE_CALLBACKS[SCENE.current].onActive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(SCENE_CALLBACKS[SCENE.current].onUpdate) {
|
|
||||||
SCENE_CALLBACKS[SCENE.current].onUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sceneRender() {
|
|
||||||
assertTrue(SCENE.current < SCENE_TYPE_COUNT, "Invalid Scene Type");
|
|
||||||
|
|
||||||
if(SCENE_CALLBACKS[SCENE.current].onRender) {
|
|
||||||
SCENE_CALLBACKS[SCENE.current].onRender();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sceneSet(const scenetype_t scene) {
|
|
||||||
assertTrue(SCENE.next < SCENE_TYPE_COUNT, "Invalid Scene Type");
|
|
||||||
SCENE.next = scene;
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SCENE_TYPE_INITIAL,
|
|
||||||
SCENE_TYPE_OVERWORLD,
|
|
||||||
} scenetype_t;
|
|
||||||
|
|
||||||
#define SCENE_TYPE_COUNT 2
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
scenetype_t current;
|
|
||||||
scenetype_t next;
|
|
||||||
} scene_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void (*onInit)();
|
|
||||||
void (*onActive)();
|
|
||||||
void (*onInactive)();
|
|
||||||
void (*onUpdate)();
|
|
||||||
void (*onRender)();
|
|
||||||
} scenetypecallback_t;
|
|
||||||
|
|
||||||
extern scene_t SCENE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the scene system.
|
|
||||||
*/
|
|
||||||
void sceneInit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the scene system.
|
|
||||||
*/
|
|
||||||
void sceneUpdate();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the scene system.
|
|
||||||
*
|
|
||||||
* Scene rendering is really just an abstraction meant to simplify things for
|
|
||||||
* the render host. It is not REQUIRED to be called at all and is not actually
|
|
||||||
* implemented in the dusk dir itself, it is overriden somewhere within the
|
|
||||||
* render host.
|
|
||||||
*/
|
|
||||||
void sceneRender();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the current scene. This will happen at the start of the next tick.
|
|
||||||
*
|
|
||||||
* @param scene The scene to set.
|
|
||||||
*/
|
|
||||||
void sceneSet(const scenetype_t scene);
|
|
@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "tileset.h"
|
|
||||||
|
|
||||||
tileset_t TILESETS[TILESET_COUNT] = {
|
|
||||||
// TILESET_NULL
|
|
||||||
{ 0, 0 },
|
|
||||||
// TILESET_FONT
|
|
||||||
{ 16, 14 }
|
|
||||||
};
|
|
||||||
|
|
||||||
tilesetid_t TILESET_SLOTS[TILESET_SLOT_COUNT] = {
|
|
||||||
TILESET_NULL,
|
|
||||||
TILESET_NULL,
|
|
||||||
TILESET_NULL,
|
|
||||||
TILESET_NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t tilesetGetSlot(const tilesetid_t id) {
|
|
||||||
uint8_t i = 0;
|
|
||||||
do {
|
|
||||||
if(TILESET_SLOTS[i] == id) return i;
|
|
||||||
} while(++i < TILESET_SLOT_COUNT);
|
|
||||||
return 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool_t tilesetIsBound(const tilesetid_t id) {
|
|
||||||
return tilesetGetSlot(id) != 0xFF;
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
#include "tilesetdefs.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
TILESET_NULL,
|
|
||||||
TILESET_FONT
|
|
||||||
} tilesetid_t;
|
|
||||||
|
|
||||||
#define TILESET_COUNT 2
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t columns;
|
|
||||||
uint8_t rows;
|
|
||||||
} tileset_t;
|
|
||||||
|
|
||||||
extern tileset_t TILESETS[];
|
|
||||||
extern tilesetid_t TILESET_SLOTS[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds a tileset to a slot. The host can also use this to say load a texture,
|
|
||||||
* or upload to VRAM.
|
|
||||||
*
|
|
||||||
* This does not guarantee anything on the game side, rendering is responsible
|
|
||||||
* for handling anything visual.
|
|
||||||
*
|
|
||||||
* @param id The tileset to bind.
|
|
||||||
* @param slot The slot to bind the tileset to.
|
|
||||||
*/
|
|
||||||
void tilesetBind(const tilesetid_t id, const uint8_t slot);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the slot that a tileset is bound to, or 0xFF if not bound.
|
|
||||||
*
|
|
||||||
* @param id The tileset to check.
|
|
||||||
* @return The slot the tileset is bound to, or 0xFF if not bound.
|
|
||||||
*/
|
|
||||||
uint8_t tilesetGetSlot(const tilesetid_t id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a tileset is bound to a slot.
|
|
||||||
*
|
|
||||||
* @param id The tileset to check.
|
|
||||||
* @return TRUE if the tileset is bound, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
bool_t tilesetIsBound(const tilesetid_t id);
|
|
@ -1,17 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define TILESET_SLOT_0 0
|
|
||||||
#define TILESET_SLOT_1 1
|
|
||||||
#define TILESET_SLOT_2 2
|
|
||||||
#define TILESET_SLOT_3 3
|
|
||||||
|
|
||||||
#define TILESET_SLOT_UI TILESET_SLOT_0
|
|
||||||
#define TILESET_SLOT_ENTITIES TILESET_SLOT_1
|
|
||||||
#define TILESET_SLOT_MAP TILESET_SLOT_2
|
|
||||||
|
|
||||||
#define TILESET_SLOT_COUNT 4
|
|
@ -14,6 +14,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
typedef bool bool_t;
|
typedef bool bool_t;
|
||||||
typedef char char_t;
|
typedef char char_t;
|
||||||
|
|
||||||
|
@ -6,8 +6,5 @@
|
|||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
tile.c
|
error.c
|
||||||
map.c
|
)
|
||||||
)
|
|
||||||
|
|
||||||
# Subdirs
|
|
45
src/dusk/error/error.c
Normal file
45
src/dusk/error/error.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
errorstack_t ERROR_STACK;
|
||||||
|
|
||||||
|
errorret_t error(const char_t *message, ...) {
|
||||||
|
return errorCode(1, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t errorCode(const errorret_t code, const char_t *message, ...) {
|
||||||
|
if(ERROR_STACK.code != ERROR_OK) {
|
||||||
|
snprintf(
|
||||||
|
ERROR_STACK.message,
|
||||||
|
ERROR_STACK_SIZE,
|
||||||
|
"Multiple errors encountered."
|
||||||
|
);
|
||||||
|
errorPrint();
|
||||||
|
}
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, message);
|
||||||
|
vsnprintf(ERROR_STACK.message, ERROR_STACK_SIZE, message, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return ERROR_STACK.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_t errorCheck() {
|
||||||
|
return ERROR_STACK.code != ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t errorPrint() {
|
||||||
|
if(ERROR_STACK.code == ERROR_OK) return ERROR_OK;
|
||||||
|
|
||||||
|
printf("Error: %s\n", ERROR_STACK.message);
|
||||||
|
errorret_t code = ERROR_STACK.code;
|
||||||
|
ERROR_STACK.code = ERROR_OK;
|
||||||
|
return code;
|
||||||
|
}
|
50
src/dusk/error/error.h
Normal file
50
src/dusk/error/error.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
typedef int32_t errorret_t;
|
||||||
|
#define ERROR_OK 0
|
||||||
|
|
||||||
|
#define ERROR_STACK_SIZE 256
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char_t message[ERROR_STACK_SIZE + 1];
|
||||||
|
errorret_t code;
|
||||||
|
} errorstack_t;
|
||||||
|
|
||||||
|
extern errorstack_t ERROR_STACK;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes an error message to the error stack.
|
||||||
|
*
|
||||||
|
* @param message Message to push to the error stack.
|
||||||
|
* @param ... Arguments to format the message with.
|
||||||
|
*/
|
||||||
|
errorret_t error(const char_t *message, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes an error message to the error stack with a given error code.
|
||||||
|
*
|
||||||
|
* @param code Error code to push to the error stack.
|
||||||
|
* @param message Message to push to the error stack.
|
||||||
|
* @param ... Arguments to format the message with.
|
||||||
|
*/
|
||||||
|
errorret_t errorCode(const errorret_t code, const char_t *message, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an error has been pushed to the error stack.
|
||||||
|
*
|
||||||
|
* @return True if an error has been pushed to the error stack.
|
||||||
|
*/
|
||||||
|
bool_t errorCheck();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the error stack to the console. This also clears the error stack.
|
||||||
|
*/
|
||||||
|
errorret_t errorPrint();
|
@ -1,31 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "game.h"
|
|
||||||
#include "input.h"
|
|
||||||
#include "display/scene.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
|
|
||||||
game_t GAME;
|
|
||||||
|
|
||||||
void gameInit() {
|
|
||||||
memoryZero(&GAME, sizeof(game_t));
|
|
||||||
|
|
||||||
inputInit();
|
|
||||||
sceneInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void gameUpdate() {
|
|
||||||
GAME.tick++;
|
|
||||||
|
|
||||||
inputUpdate();
|
|
||||||
sceneUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void gameDispose() {
|
|
||||||
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
#define GAME_TICK_RATE 60
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t tick;
|
|
||||||
} game_t;
|
|
||||||
|
|
||||||
extern game_t GAME;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the game.
|
|
||||||
*/
|
|
||||||
void gameInit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the game. The game is setup to handle "frames", aka 1/60th of a
|
|
||||||
* second. Typically more modern engines would use floats to tick game engine
|
|
||||||
* by a semi random delta time, but this engine is intended to work on really
|
|
||||||
* weak machines so we take the simple approach.
|
|
||||||
*/
|
|
||||||
void gameUpdate();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes the game.
|
|
||||||
*/
|
|
||||||
void gameDispose();
|
|
@ -1,37 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "input.h"
|
|
||||||
|
|
||||||
inputstate_t INPUT_CURRENT;
|
|
||||||
inputstate_t INPUT_LAST_FRAME;
|
|
||||||
|
|
||||||
void inputInit() {
|
|
||||||
INPUT_CURRENT = 0;
|
|
||||||
INPUT_LAST_FRAME = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void inputUpdate() {
|
|
||||||
INPUT_LAST_FRAME = INPUT_CURRENT;
|
|
||||||
INPUT_CURRENT = inputPlatformState();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool_t inputWasPressed(const inputstate_t state) {
|
|
||||||
return (INPUT_LAST_FRAME & state) == 0 && (INPUT_CURRENT & state) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool_t inputWasReleased(const inputstate_t state) {
|
|
||||||
return (INPUT_LAST_FRAME & state) != 0 && (INPUT_CURRENT & state) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool_t inputIsDown(const inputstate_t state) {
|
|
||||||
return (INPUT_CURRENT & state) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool_t inputIsUp(const inputstate_t state) {
|
|
||||||
return (INPUT_CURRENT & state) == 0;
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
typedef uint16_t inputstate_t;
|
|
||||||
|
|
||||||
#define INPUT_MENU (1 << 0)
|
|
||||||
#define INPUT_UP (1 << 1)
|
|
||||||
#define INPUT_DOWN (1 << 2)
|
|
||||||
#define INPUT_LEFT (1 << 3)
|
|
||||||
#define INPUT_RIGHT (1 << 4)
|
|
||||||
#define INPUT_ACCEPT (1 << 5)
|
|
||||||
#define INPUT_BACK (1 << 6)
|
|
||||||
|
|
||||||
extern inputstate_t INPUT_CURRENT;
|
|
||||||
extern inputstate_t INPUT_LAST_FRAME;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the input system
|
|
||||||
*/
|
|
||||||
void inputInit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the input system for this tick.
|
|
||||||
*/
|
|
||||||
void inputUpdate();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requests the platform let us know the current state of each input.
|
|
||||||
*
|
|
||||||
* @return Current input state.
|
|
||||||
*/
|
|
||||||
inputstate_t inputPlatformState();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the input was pressed this frame, but not last frame.
|
|
||||||
*
|
|
||||||
* @param state Inputs to check, typically a single input.
|
|
||||||
* @return True if input was pressed this frame but not last frame.
|
|
||||||
*/
|
|
||||||
bool_t inputWasPressed(const inputstate_t state);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the input was released this frame, but pressed last frame.
|
|
||||||
*
|
|
||||||
* @param state Inputs to check, typically a single input.
|
|
||||||
* @return True if input was released this frame but was pressed last frame.
|
|
||||||
*/
|
|
||||||
bool_t inputWasReleased(const inputstate_t state);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the input is currently pressed.
|
|
||||||
*
|
|
||||||
* @param state Inputs to check, typically a single input.
|
|
||||||
* @return True if input is currently pressed.
|
|
||||||
*/
|
|
||||||
bool_t inputIsDown(const inputstate_t state);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the input is currently released.
|
|
||||||
*
|
|
||||||
* @param state Inputs to check, typically a single input.
|
|
||||||
* @return True if input is currently released.
|
|
||||||
*/
|
|
||||||
bool_t inputIsUp(const inputstate_t state);
|
|
@ -1,14 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
# Sources
|
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
|
||||||
PRIVATE
|
|
||||||
overworld.c
|
|
||||||
)
|
|
||||||
|
|
||||||
# Subdirs
|
|
||||||
add_subdirectory(entity)
|
|
||||||
add_subdirectory(map)
|
|
@ -1,150 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "entity.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
#include "overworld/overworld.h"
|
|
||||||
|
|
||||||
entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT] = {
|
|
||||||
{ NULL, NULL, NULL },
|
|
||||||
{ playerInit, playerUpdate, NULL },
|
|
||||||
{ npcInit, npcUpdate, npcInteract }
|
|
||||||
};
|
|
||||||
|
|
||||||
entity_t ENTITY_TEST;
|
|
||||||
|
|
||||||
void entityInit(
|
|
||||||
entity_t *ent,
|
|
||||||
const entitytype_t type
|
|
||||||
) {
|
|
||||||
assertNotNull(ent, "Entity cannot be NULL");
|
|
||||||
assertTrue(type < ENTITY_TYPE_COUNT, "Invalid entity type");
|
|
||||||
|
|
||||||
// Init values
|
|
||||||
memoryZero(ent, sizeof(entity_t));
|
|
||||||
ent->type = type;
|
|
||||||
|
|
||||||
// Call init
|
|
||||||
assertNotNull(ENTITY_CALLBACKS[type].init, "Entity type init callback err.");
|
|
||||||
ENTITY_CALLBACKS[type].init(ent);
|
|
||||||
|
|
||||||
entityTurn(ent, FACING_DIRECTION_SOUTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
void entityUpdate(entity_t *ent) {
|
|
||||||
assertNotNull(ent, "Entity cannot be NULL");
|
|
||||||
assertTrue(ent->type < ENTITY_TYPE_COUNT, "Invalid entity type");
|
|
||||||
assertNotNull(ENTITY_CALLBACKS[ent->type].update, "Entity type update err.");
|
|
||||||
ENTITY_CALLBACKS[ent->type].update(ent);
|
|
||||||
|
|
||||||
// Handle moving
|
|
||||||
if(ent->subX > 0) {
|
|
||||||
ent->subX -= ENTITY_MOVE_SPEED;
|
|
||||||
if(ent->subX < 0) ent->subX = 0;
|
|
||||||
} else if(ent->subX < 0) {
|
|
||||||
ent->subX += ENTITY_MOVE_SPEED;
|
|
||||||
if(ent->subX > 0) ent->subX = 0;
|
|
||||||
} else if(ent->subY > 0) {
|
|
||||||
ent->subY -= ENTITY_MOVE_SPEED;
|
|
||||||
if(ent->subY < 0) ent->subY = 0;
|
|
||||||
} else if(ent->subY < 0) {
|
|
||||||
ent->subY += ENTITY_MOVE_SPEED;
|
|
||||||
if(ent->subY > 0) ent->subY = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void entityTurn(entity_t *ent, const facingdir_t dir) {
|
|
||||||
assertNotNull(ent, "Entity cannot be NULL");
|
|
||||||
assertTrue(dir < FACING_DIRECTION_COUNT, "Invalid facing direction");
|
|
||||||
|
|
||||||
ent->direction = dir;
|
|
||||||
switch(dir) {
|
|
||||||
case FACING_DIRECTION_SOUTH:
|
|
||||||
ent->frame = 25;
|
|
||||||
break;
|
|
||||||
case FACING_DIRECTION_NORTH:
|
|
||||||
ent->frame = 24;
|
|
||||||
break;
|
|
||||||
case FACING_DIRECTION_EAST:
|
|
||||||
ent->frame = 26;
|
|
||||||
break;
|
|
||||||
case FACING_DIRECTION_WEST:
|
|
||||||
ent->frame = 27;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void entityMove(entity_t *ent, const facingdir_t dir) {
|
|
||||||
assertNotNull(ent, "Entity cannot be NULL");
|
|
||||||
if(entityIsMoving(ent)) return;
|
|
||||||
|
|
||||||
entityTurn(ent, dir);
|
|
||||||
|
|
||||||
uint8_t targetX = ent->x, targetY = ent->y;
|
|
||||||
facingDirAdd(ent->direction, &targetX, &targetY);
|
|
||||||
|
|
||||||
// Check oob
|
|
||||||
if(targetX < 0 || targetX >= OVERWORLD.map.width) return;
|
|
||||||
if(targetY < 0 || targetY >= OVERWORLD.map.height) return;
|
|
||||||
|
|
||||||
// Check tile at target
|
|
||||||
uint8_t i = 0;
|
|
||||||
tileid_t tileId;
|
|
||||||
for(i = 0; i < OVERWORLD.map.layerCount; i++) {
|
|
||||||
tileId = mapGetTileIdAtPosition(&OVERWORLD.map, i, targetX, targetY);
|
|
||||||
if(tileIsSolid(tileId)) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for entity at target
|
|
||||||
entity_t *atPos = overworldEntityGetAtPosition(targetX, targetY);
|
|
||||||
if(atPos != NULL) return;
|
|
||||||
|
|
||||||
// Commit to move
|
|
||||||
ent->x = targetX;
|
|
||||||
ent->y = targetY;
|
|
||||||
|
|
||||||
switch(dir) {
|
|
||||||
case FACING_DIRECTION_EAST:
|
|
||||||
ent->subX = -OVERWORLD_ENTITY_WIDTH;
|
|
||||||
break;
|
|
||||||
case FACING_DIRECTION_WEST:
|
|
||||||
ent->subX = OVERWORLD_ENTITY_WIDTH;
|
|
||||||
break;
|
|
||||||
case FACING_DIRECTION_NORTH:
|
|
||||||
ent->subY = -OVERWORLD_ENTITY_HEIGHT;
|
|
||||||
break;
|
|
||||||
case FACING_DIRECTION_SOUTH:
|
|
||||||
ent->subY = OVERWORLD_ENTITY_HEIGHT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool_t entityIsMoving(const entity_t *ent) {
|
|
||||||
assertNotNull(ent, "Entity cannot be NULL");
|
|
||||||
return ent->subX != 0 || ent->subY != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool_t entityInteract(entity_t *ent) {
|
|
||||||
assertNotNull(ent, "Entity cannot be NULL.");
|
|
||||||
assertTrue(ent->type == ENTITY_TYPE_PLAYER, "Entity should be player.");
|
|
||||||
if(entityIsMoving(ent)) return false;
|
|
||||||
|
|
||||||
uint8_t targetX = ent->x, targetY = ent->y;
|
|
||||||
facingDirAdd(ent->direction, &targetX, &targetY);
|
|
||||||
|
|
||||||
entity_t *target = overworldEntityGetAtPosition(targetX, targetY);
|
|
||||||
assertFalse(target == ent, "Cannot interact with self.");
|
|
||||||
|
|
||||||
if(target == NULL) return false;
|
|
||||||
assertTrue(target->type < ENTITY_TYPE_COUNT, "Invalid entity type.");
|
|
||||||
|
|
||||||
if(ENTITY_CALLBACKS[target->type].interact == NULL) return false;
|
|
||||||
ENTITY_CALLBACKS[target->type].interact(ent, target);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "facing.h"
|
|
||||||
#include "player.h"
|
|
||||||
#include "npc.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ENTITY_TYPE_NULL,
|
|
||||||
ENTITY_TYPE_PLAYER,
|
|
||||||
ENTITY_TYPE_NPC
|
|
||||||
} entitytype_t;
|
|
||||||
|
|
||||||
#define ENTITY_TYPE_COUNT 3
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void (*init)(entity_t *);
|
|
||||||
void (*update)(entity_t *);
|
|
||||||
void (*interact)(entity_t *, entity_t *);
|
|
||||||
} entitycallback_t;
|
|
||||||
|
|
||||||
typedef struct _entity_t {
|
|
||||||
uint8_t x, y;
|
|
||||||
int8_t subX, subY;
|
|
||||||
uint8_t frame;
|
|
||||||
facingdir_t direction;
|
|
||||||
entitytype_t type;
|
|
||||||
|
|
||||||
union {
|
|
||||||
player_t player;
|
|
||||||
};
|
|
||||||
} entity_t;
|
|
||||||
|
|
||||||
#define ENTITY_MOVE_SPEED 3
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes an entity.
|
|
||||||
*
|
|
||||||
* @param entity The entity to initialize.
|
|
||||||
* @param type The type of entity to initialize.
|
|
||||||
*/
|
|
||||||
void entityInit(
|
|
||||||
entity_t *entity,
|
|
||||||
const entitytype_t type
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates an entity.
|
|
||||||
*
|
|
||||||
* @param entity The entity to update.
|
|
||||||
*/
|
|
||||||
void entityUpdate(entity_t *entity);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns an entity in a given direction.
|
|
||||||
*
|
|
||||||
* @param entity The entity to turn.
|
|
||||||
* @param dir The direction to turn the entity.
|
|
||||||
*/
|
|
||||||
void entityTurn(entity_t *entity, const facingdir_t dir);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves an entity in a given direction.
|
|
||||||
*
|
|
||||||
* @param entity The entity to move.
|
|
||||||
* @param dir The direction to move the entity.
|
|
||||||
*/
|
|
||||||
void entityMove(entity_t *entity, const facingdir_t dir);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if an entity is moving.
|
|
||||||
*
|
|
||||||
* @param entity The entity to check.
|
|
||||||
* @return TRUE if the entity is moving, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
bool_t entityIsMoving(const entity_t *entity);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make this entity attempt to interact with the world.
|
|
||||||
*
|
|
||||||
* @param entity The entity that is doing the interaction.
|
|
||||||
* @return TRUE if an entity was interacted with, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
bool_t entityInteract(entity_t *entity);
|
|
@ -1,65 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "facing.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
|
|
||||||
void facingDirGetRelative(const facingdir_t dir, int8_t *x, int8_t *y) {
|
|
||||||
assertNotNull(x, "X cannot be NULL");
|
|
||||||
assertNotNull(y, "Y cannot be NULL");
|
|
||||||
|
|
||||||
switch(dir) {
|
|
||||||
case FACING_DIRECTION_SOUTH:
|
|
||||||
*x = 0;
|
|
||||||
*y = -1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FACING_DIRECTION_EAST:
|
|
||||||
*x = 1;
|
|
||||||
*y = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FACING_DIRECTION_NORTH:
|
|
||||||
*x = 0;
|
|
||||||
*y = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FACING_DIRECTION_WEST:
|
|
||||||
*x = -1;
|
|
||||||
*y = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assertUnreachable("Invalid facing direction.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void facingDirAdd(const facingdir_t dir, uint8_t *x, uint8_t *y) {
|
|
||||||
assertNotNull(x, "X cannot be NULL");
|
|
||||||
assertNotNull(y, "Y cannot be NULL");
|
|
||||||
|
|
||||||
int8_t dx, dy;
|
|
||||||
facingDirGetRelative(dir, &dx, &dy);
|
|
||||||
|
|
||||||
*x += dx;
|
|
||||||
*y += dy;
|
|
||||||
}
|
|
||||||
|
|
||||||
facingdir_t facingDirFace(
|
|
||||||
const uint8_t x1, const uint8_t y1,
|
|
||||||
const uint8_t x2, const uint8_t y2
|
|
||||||
) {
|
|
||||||
if(x1 == x2) {
|
|
||||||
if(y1 < y2) return FACING_DIRECTION_SOUTH;
|
|
||||||
if(y1 > y2) return FACING_DIRECTION_NORTH;
|
|
||||||
} else if(y1 == y2) {
|
|
||||||
if(x1 < x2) return FACING_DIRECTION_WEST;
|
|
||||||
if(x1 > x2) return FACING_DIRECTION_EAST;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FACING_DIRECTION_SOUTH;
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FACING_DIRECTION_SOUTH,
|
|
||||||
FACING_DIRECTION_EAST,
|
|
||||||
FACING_DIRECTION_NORTH,
|
|
||||||
FACING_DIRECTION_WEST
|
|
||||||
} facingdir_t;
|
|
||||||
|
|
||||||
#define FACING_DIRECTION_COUNT 4
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a facing direction to a directional vector.
|
|
||||||
*
|
|
||||||
* @param dir The direction to convert.
|
|
||||||
* @param x The x component of the vector.
|
|
||||||
* @param y The y component of the vector.
|
|
||||||
*/
|
|
||||||
void facingDirGetRelative(const facingdir_t dir, int8_t *x, int8_t *y);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a facing direction to a position.
|
|
||||||
*
|
|
||||||
* @param dir The direction to add.
|
|
||||||
* @param x The x position to add to.
|
|
||||||
* @param y The y position to add to.
|
|
||||||
*/
|
|
||||||
void facingDirAdd(const facingdir_t dir, uint8_t *x, uint8_t *y);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the facing direction to face from one position to another.
|
|
||||||
*
|
|
||||||
* @param x1 The x position to face from.
|
|
||||||
* @param y1 The y position to face from.
|
|
||||||
* @param x2 The x position to face to.
|
|
||||||
* @param y2 The y position to face to.
|
|
||||||
* @return The facing direction to face from one position to another.
|
|
||||||
*/
|
|
||||||
facingdir_t facingDirFace(
|
|
||||||
const uint8_t x1, const uint8_t y1,
|
|
||||||
const uint8_t x2, const uint8_t y2
|
|
||||||
);
|
|
@ -1,19 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "entity.h"
|
|
||||||
|
|
||||||
void npcInit(entity_t *ent) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void npcUpdate(entity_t *ent) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void npcInteract(entity_t *player, entity_t *ent) {
|
|
||||||
printf("Interact\n");
|
|
||||||
entityTurn(ent, facingDirFace(player->x, player->y, ent->x, ent->y));
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
typedef struct _entity_t entity_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int32_t nothing;
|
|
||||||
} npc_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles initialization of an NPC.
|
|
||||||
*
|
|
||||||
* @param ent The entity to initialize as an NPC.
|
|
||||||
*/
|
|
||||||
void npcInit(entity_t *ent);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles updating an NPC.
|
|
||||||
*
|
|
||||||
* @param ent The entity to update as an NPC.
|
|
||||||
*/
|
|
||||||
void npcUpdate(entity_t *ent);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles interaction with an NPC.
|
|
||||||
*
|
|
||||||
* @param player The player entity interacting.
|
|
||||||
* @param ent The entity to interact with.
|
|
||||||
*/
|
|
||||||
void npcInteract(entity_t *player, entity_t *ent);
|
|
@ -1,33 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "overworld/overworld.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "input.h"
|
|
||||||
|
|
||||||
void playerInit(entity_t *ent) {
|
|
||||||
assertNotNull(ent, "Entity cannot be NULL");
|
|
||||||
|
|
||||||
printf("Initializing player entity\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void playerUpdate(entity_t *ent) {
|
|
||||||
assertNotNull(ent, "Entity cannot be NULL");
|
|
||||||
|
|
||||||
if(inputIsDown(INPUT_RIGHT)) {
|
|
||||||
entityMove(ent, FACING_DIRECTION_EAST);
|
|
||||||
} else if(inputIsDown(INPUT_LEFT)) {
|
|
||||||
entityMove(ent, FACING_DIRECTION_WEST);
|
|
||||||
} else if(inputIsDown(INPUT_UP)) {
|
|
||||||
entityMove(ent, FACING_DIRECTION_NORTH);
|
|
||||||
} else if(inputIsDown(INPUT_DOWN)) {
|
|
||||||
entityMove(ent, FACING_DIRECTION_SOUTH);
|
|
||||||
} else if(inputWasPressed(INPUT_ACCEPT)) {
|
|
||||||
entityInteract(ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
typedef struct _entity_t entity_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int32_t nothing;
|
|
||||||
} player_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles initialization of the player.
|
|
||||||
*
|
|
||||||
* @param ent The entity to initialize as a player.
|
|
||||||
*/
|
|
||||||
void playerInit(entity_t *ent);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles updating the player.
|
|
||||||
*
|
|
||||||
* @param ent The entity to update as a player.
|
|
||||||
*/
|
|
||||||
void playerUpdate(entity_t *ent);
|
|
@ -1,69 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "map.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
|
|
||||||
void mapInit(map_t *map) {
|
|
||||||
memoryZero(map, sizeof(map_t));
|
|
||||||
|
|
||||||
// Test
|
|
||||||
map->width = 16;
|
|
||||||
map->height = 16;
|
|
||||||
map->layerCount = 1;
|
|
||||||
memorySet(&map->tileIds, 0x01, sizeof(map->tileIds));
|
|
||||||
|
|
||||||
// Test size
|
|
||||||
assertTrue(
|
|
||||||
(map->width * map->height * map->layerCount) <= OVERWORLD_TILE_COUNT_MAX,
|
|
||||||
"Map size exceeds tile count."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t mapGetTileIndex(
|
|
||||||
const map_t *map,
|
|
||||||
const uint8_t layer,
|
|
||||||
const uint8_t x,
|
|
||||||
const uint8_t y
|
|
||||||
) {
|
|
||||||
assertNotNull(map, "Map cannot be NULL");
|
|
||||||
assertTrue(layer < map->layerCount, "Invalid layer");
|
|
||||||
assertTrue(x < map->width, "Invalid x");
|
|
||||||
assertTrue(y < map->height, "Invalid y");
|
|
||||||
|
|
||||||
return (layer * map->width * map->height) + (y * map->width) + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
tileid_t mapGetTileId(
|
|
||||||
const map_t *map,
|
|
||||||
const uint32_t tileIndex
|
|
||||||
) {
|
|
||||||
assertNotNull(map, "Map cannot be NULL");
|
|
||||||
assertMapIndexValid(map, tileIndex);
|
|
||||||
|
|
||||||
return map->tileIds[tileIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
tileid_t mapGetTileIdAtPosition(
|
|
||||||
const map_t *map,
|
|
||||||
const uint8_t layer,
|
|
||||||
const uint8_t x,
|
|
||||||
const uint8_t y
|
|
||||||
) {
|
|
||||||
return mapGetTileId(map, mapGetTileIndex(map, layer, x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
tiledata_t mapGetTileData(
|
|
||||||
const map_t *map,
|
|
||||||
const uint32_t tileIndex
|
|
||||||
) {
|
|
||||||
assertNotNull(map, "Map cannot be NULL");
|
|
||||||
assertMapIndexValid(map, tileIndex);
|
|
||||||
|
|
||||||
return map->tileData[tileIndex];
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "tile.h"
|
|
||||||
#include "overworld/overworlddefs.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
|
|
||||||
#define assertMapIndexValid(map, index) \
|
|
||||||
assertTrue( \
|
|
||||||
index < (map->layerCount * map->width * map->height), \
|
|
||||||
"Invalid tile index" \
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
tileid_t tileIds[OVERWORLD_TILE_COUNT_MAX];
|
|
||||||
tiledata_t tileData[OVERWORLD_TILE_COUNT_MAX];
|
|
||||||
uint8_t width, height, layerCount;
|
|
||||||
} map_t;
|
|
||||||
|
|
||||||
void mapInit(map_t *map);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the index of the tile at the given position.
|
|
||||||
*
|
|
||||||
* @param map The map to get the tile index from.
|
|
||||||
* @param layer The layer to get the tile from.
|
|
||||||
* @param x The x position of the tile.
|
|
||||||
* @param y The y position of the tile.
|
|
||||||
* @return The index of the tile at the given position.
|
|
||||||
*/
|
|
||||||
uint32_t mapGetTileIndex(
|
|
||||||
const map_t *map,
|
|
||||||
const uint8_t layer,
|
|
||||||
const uint8_t x,
|
|
||||||
const uint8_t y
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the tile ID at the given index.
|
|
||||||
*
|
|
||||||
* @param map The map to get the tile ID from.
|
|
||||||
* @param tileIndex The index of the tile to get.
|
|
||||||
* @return The tile ID at the given index.
|
|
||||||
*/
|
|
||||||
tileid_t mapGetTileId(
|
|
||||||
const map_t *map,
|
|
||||||
const uint32_t tileIndex
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the tile ID at the given position. Shorthand for both getting the
|
|
||||||
* map index and the tile ID.
|
|
||||||
*
|
|
||||||
* @param map The map to get the tile ID from.
|
|
||||||
* @param layer The layer to get the tile from.
|
|
||||||
* @param x The x position of the tile.
|
|
||||||
* @param y The y position of the tile.
|
|
||||||
* @return The tile ID at the given position.
|
|
||||||
*/
|
|
||||||
tileid_t mapGetTileIdAtPosition(
|
|
||||||
const map_t *map,
|
|
||||||
const uint8_t layer,
|
|
||||||
const uint8_t x,
|
|
||||||
const uint8_t y
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the tile data at the given index.
|
|
||||||
*
|
|
||||||
* @param map The map to get the tile data from.
|
|
||||||
* @param tileIndex The index of the tile to get.
|
|
||||||
* @return The tile data at the given index.
|
|
||||||
*/
|
|
||||||
tiledata_t mapGetTileData(
|
|
||||||
const map_t *map,
|
|
||||||
const uint32_t tileIndex
|
|
||||||
);
|
|
@ -1,19 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "tile.h"
|
|
||||||
|
|
||||||
bool_t tileIsSolid(const tileid_t id) {
|
|
||||||
switch(id) {
|
|
||||||
case TILE_ID_NULL:
|
|
||||||
case TILE_ID_GRASS:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
typedef uint8_t tileid_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t nothing;
|
|
||||||
} tiledata_t;
|
|
||||||
|
|
||||||
#define TILE_ID_NULL 0
|
|
||||||
#define TILE_ID_GRASS 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether or not the tile is solid.
|
|
||||||
*
|
|
||||||
* @param id The tile id to check.
|
|
||||||
* @return Whether or not the tile is solid.
|
|
||||||
*/
|
|
||||||
bool_t tileIsSolid(const tileid_t id);
|
|
@ -1,49 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "overworld.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "display/tileset.h"
|
|
||||||
|
|
||||||
overworld_t OVERWORLD;
|
|
||||||
|
|
||||||
void overworldInit() {
|
|
||||||
memoryZero(&OVERWORLD, sizeof(overworld_t));
|
|
||||||
|
|
||||||
mapInit(&OVERWORLD.map);
|
|
||||||
|
|
||||||
entityInit(OVERWORLD.entities + OVERWORLD.entityCount++, ENTITY_TYPE_PLAYER);
|
|
||||||
|
|
||||||
entityInit(OVERWORLD.entities + OVERWORLD.entityCount++, ENTITY_TYPE_NPC);
|
|
||||||
OVERWORLD.entities[1].x = 2;
|
|
||||||
OVERWORLD.entities[1].y = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void overworldSceneInit() {
|
|
||||||
tilesetBind(TILESET_FONT, TILESET_SLOT_ENTITIES);
|
|
||||||
}
|
|
||||||
|
|
||||||
void overworldSceneDeinit() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void overworldUpdate() {
|
|
||||||
uint8_t i = 0;
|
|
||||||
while(i < OVERWORLD.entityCount) {
|
|
||||||
entityUpdate(OVERWORLD.entities + i++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entity_t * overworldEntityGetAtPosition(const uint8_t x, const uint8_t y) {
|
|
||||||
uint8_t i = 0;
|
|
||||||
while(i < OVERWORLD.entityCount) {
|
|
||||||
entity_t * entity = OVERWORLD.entities + i++;
|
|
||||||
if(entity->x == x && entity->y == y) return entity;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "overworlddefs.h"
|
|
||||||
#include "overworld/entity/entity.h"
|
|
||||||
#include "overworld/map/map.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
entity_t entities[OVERWORLD_ENTITY_COUNT_MAX];
|
|
||||||
uint8_t entityCount;
|
|
||||||
map_t map;
|
|
||||||
} overworld_t;
|
|
||||||
|
|
||||||
extern overworld_t OVERWORLD;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the overworld.
|
|
||||||
*/
|
|
||||||
void overworldInit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the scene system when the overworld scene is made to be the
|
|
||||||
* active scene.
|
|
||||||
*/
|
|
||||||
void overworldSceneInit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the scene system when the overworld scene is made to be inactive.
|
|
||||||
*/
|
|
||||||
void overworldSceneDeinit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the scene system when the overworld scene is to perform a tick.
|
|
||||||
*/
|
|
||||||
void overworldUpdate();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Platform level render method. Refer to sceneRender for information.
|
|
||||||
*/
|
|
||||||
void overworldRender();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the entity at the given position.
|
|
||||||
*
|
|
||||||
* @param x The x position of the entity.
|
|
||||||
* @param y The y position of the entity.
|
|
||||||
* @return The entity at the given position.
|
|
||||||
*/
|
|
||||||
entity_t * overworldEntityGetAtPosition(
|
|
||||||
const uint8_t x,
|
|
||||||
const uint8_t y
|
|
||||||
);
|
|
@ -1,16 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define OVERWORLD_ENTITY_COUNT_MAX 8
|
|
||||||
#define OVERWORLD_ENTITY_WIDTH 32
|
|
||||||
#define OVERWORLD_ENTITY_HEIGHT 32
|
|
||||||
|
|
||||||
#define OVERWORLD_TILE_LAYER_COUNT_MAX 2
|
|
||||||
#define OVERWORLD_TILE_COUNT_PER_LAYER 256
|
|
||||||
#define OVERWORLD_TILE_COUNT_MAX (OVERWORLD_TILE_COUNT_PER_LAYER * OVERWORLD_TILE_LAYER_COUNT_MAX)
|
|
||||||
#define OVERWORLD_TILE_WIDTH OVERWORLD_ENTITY_WIDTH
|
|
||||||
#define OVERWORLD_TILE_HEIGHT OVERWORLD_ENTITY_HEIGHT
|
|
19
src/dusk/server/server.h
Normal file
19
src/dusk/server/server.h
Normal 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 "dusk.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
} server_t;
|
||||||
|
|
||||||
|
extern server_t SERVER;
|
||||||
|
|
||||||
|
void serverInit();
|
||||||
|
void serverStart();
|
||||||
|
void serverDispose();
|
@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "uimenu.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "input.h"
|
|
||||||
|
|
||||||
void uiMenuInit(
|
|
||||||
uimenu_t *menu,
|
|
||||||
const uint8_t columns,
|
|
||||||
const uint8_t rows
|
|
||||||
) {
|
|
||||||
assertNotNull(menu, "Menu cannot be NULL.");
|
|
||||||
|
|
||||||
memoryZero(menu, sizeof(uimenu_t));
|
|
||||||
|
|
||||||
menu->columns = columns;
|
|
||||||
menu->rows = rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uiMenuSetCursor(
|
|
||||||
uimenu_t *menu,
|
|
||||||
const uint8_t x,
|
|
||||||
const uint8_t y
|
|
||||||
) {
|
|
||||||
assertNotNull(menu, "Menu cannot be NULL.");
|
|
||||||
assert(x < menu->columns, "X position out of bounds.");
|
|
||||||
assert(y < menu->rows, "Y position out of bounds.");
|
|
||||||
|
|
||||||
menu->x = x;
|
|
||||||
menu->y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uiMenuMoveCursor(
|
|
||||||
uimenu_t *menu,
|
|
||||||
const int8_t x,
|
|
||||||
const int8_t y
|
|
||||||
) {
|
|
||||||
assertNotNull(menu, "Menu cannot be NULL.");
|
|
||||||
uiMenuSetCursor(
|
|
||||||
menu,
|
|
||||||
(menu->x + x) % menu->columns,
|
|
||||||
(menu->y + y) % menu->rows
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
uimenuaction_t uiMenuUpdate(uimenu_t *menu) {
|
|
||||||
assertNotNull(menu, "Menu cannot be NULL.");
|
|
||||||
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
UI_MENU_ACTION_NOTHING,
|
|
||||||
UI_MENU_ACTION_CURSOR_MOVE,
|
|
||||||
UI_MENU_ACTION_CURSOR_ACCEPT,
|
|
||||||
UI_MENU_ACTION_CURSOR_CANCEL
|
|
||||||
} uimenuaction_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t columns;
|
|
||||||
uint8_t rows;
|
|
||||||
uint8_t x;
|
|
||||||
uint8_t y;
|
|
||||||
} uimenu_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a menu.
|
|
||||||
*
|
|
||||||
* @param menu The menu to initialize.
|
|
||||||
* @param columns The amount of columns in the menu.
|
|
||||||
* @param rows The amount of rows in the menu.
|
|
||||||
*/
|
|
||||||
void uiMenuInit(
|
|
||||||
uimenu_t *menu,
|
|
||||||
const uint8_t columns,
|
|
||||||
const uint8_t rows
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the cursor of a menu.
|
|
||||||
*
|
|
||||||
* @param menu The menu to set the cursor of.
|
|
||||||
* @param x The x position of the cursor.
|
|
||||||
* @param y The y position of the cursor.
|
|
||||||
*/
|
|
||||||
void uiMenuSetCursor(
|
|
||||||
uimenu_t *menu,
|
|
||||||
const uint8_t x,
|
|
||||||
const uint8_t y
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the cursor of a menu.
|
|
||||||
*
|
|
||||||
* @param menu The menu to move the cursor of.
|
|
||||||
* @param x The amount to move the cursor on the x axis.
|
|
||||||
* @param y The amount to move the cursor on the y axis.
|
|
||||||
*/
|
|
||||||
void uiMenuMoveCursor(
|
|
||||||
uimenu_t *menu,
|
|
||||||
const int8_t x,
|
|
||||||
const int8_t y
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles updating of a menu, this will accept input basically.
|
|
||||||
*
|
|
||||||
* @param menu The menu to update.
|
|
||||||
*/
|
|
||||||
uimenuaction_t uiMenuUpdate(uimenu_t *menu);
|
|
@ -1,12 +1,11 @@
|
|||||||
# Copyright (c) 2023 Dominic Masters
|
# Copyright (c) 2025 Dominic Masters
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
|
||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
math.c
|
|
||||||
random.c
|
|
||||||
memory.c
|
memory.c
|
||||||
|
string.c
|
||||||
)
|
)
|
@ -1,24 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2023 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "math.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
|
|
||||||
int32_t mathClampi32(
|
|
||||||
const int32_t value,
|
|
||||||
const int32_t min,
|
|
||||||
const int32_t max
|
|
||||||
) {
|
|
||||||
assertTrue(max >= min, "mathClampi32: Max must be >= Min");
|
|
||||||
if(value < min) return min;
|
|
||||||
if(value > max) return max;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t mathModi32(int32_t value, int32_t modulo) {
|
|
||||||
return ((value % modulo) + modulo) % modulo;
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2023 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the minimum of two values.
|
|
||||||
* @param a First value.
|
|
||||||
* @param b Second value.
|
|
||||||
* @return The minimum of the two values.
|
|
||||||
*/
|
|
||||||
#define mathMin(a, b) ((a) < (b) ? (a) : (b))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the maximum of two values.
|
|
||||||
* @param a First value.
|
|
||||||
* @param b Second value.
|
|
||||||
* @return The maximum of the two values.
|
|
||||||
*/
|
|
||||||
#define mathMax(a, b) ((a) > (b) ? (a) : (b))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clamps a value between a min and max.
|
|
||||||
*
|
|
||||||
* @param value Value to clamp.
|
|
||||||
* @param min Minimum value to clamp value to.
|
|
||||||
* @param max Maximum value to clamp value to.
|
|
||||||
* @return The clamped value.
|
|
||||||
*/
|
|
||||||
int32_t mathClampi32(
|
|
||||||
const int32_t value,
|
|
||||||
const int32_t min,
|
|
||||||
const int32_t max
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the modulo of a value. For 32 bit integers.
|
|
||||||
*
|
|
||||||
* @param value Value to modulo.
|
|
||||||
* @param modulo Modulo value.
|
|
||||||
* @return The modulo of the value.
|
|
||||||
*/
|
|
||||||
int32_t mathModi32(int32_t value, int32_t modulo);
|
|
@ -49,4 +49,12 @@ void memoryCopyRangeSafe(
|
|||||||
size_t copy = (size_t)end - (size_t)start;
|
size_t copy = (size_t)end - (size_t)start;
|
||||||
assertTrue(copy <= sizeMax, "Size of memory to copy is too large.");
|
assertTrue(copy <= sizeMax, "Size of memory to copy is too large.");
|
||||||
memoryCopy(dest, start, copy);
|
memoryCopy(dest, start, copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void memoryMove(void *dest, const void *src, const size_t size) {
|
||||||
|
assertNotNull(dest, "Cannot move to NULL memory.");
|
||||||
|
assertNotNull(src, "Cannot move from NULL memory.");
|
||||||
|
assertTrue(size > 0, "Cannot move 0 bytes of memory.");
|
||||||
|
assertTrue(dest != src, "Cannot move memory to itself.");
|
||||||
|
memmove(dest, src, size);
|
||||||
}
|
}
|
@ -64,4 +64,13 @@ void memoryCopyRangeSafe(
|
|||||||
const void *start,
|
const void *start,
|
||||||
const void *end,
|
const void *end,
|
||||||
const size_t sizeMax
|
const size_t sizeMax
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves memory.
|
||||||
|
*
|
||||||
|
* @param dest The destination to move to.
|
||||||
|
* @param src The source to move from.
|
||||||
|
* @param size The size of the memory to move.
|
||||||
|
*/
|
||||||
|
void memoryMove(void *dest, const void *src, const size_t size);
|
@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2024 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "random.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
|
|
||||||
bool_t RANDOM_IS_INITIALIZED = false;
|
|
||||||
|
|
||||||
void randomInit() {
|
|
||||||
assertFalse(RANDOM_IS_INITIALIZED, "Random already initialized.");
|
|
||||||
srand(1234567890);
|
|
||||||
RANDOM_IS_INITIALIZED = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t randomInt32() {
|
|
||||||
assertTrue(RANDOM_IS_INITIALIZED, "Random not initialized.");
|
|
||||||
return rand();
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t randomInt32Range(int32_t min, int32_t max) {
|
|
||||||
return min + (rand() % (max - min));
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2024 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
extern bool_t RANDOM_IS_INITIALIZED;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the random number generator, and seeds it.
|
|
||||||
*/
|
|
||||||
void randomInit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a random 32-bit integer.
|
|
||||||
*
|
|
||||||
* @return Random 32-bit integer.
|
|
||||||
*/
|
|
||||||
int32_t randomInt32();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a random 32-bit integer within a given range.
|
|
||||||
*
|
|
||||||
* @param min Minimum value.
|
|
||||||
* @param max Maximum value (exclusive).
|
|
||||||
* @return Random 32-bit integer within the given range.
|
|
||||||
*/
|
|
||||||
int32_t randomInt32Range(int32_t min, int32_t max);
|
|
50
src/dusk/util/string.c
Normal file
50
src/dusk/util/string.c
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
bool_t stringIsWhitespace(const char_t c) {
|
||||||
|
return isspace(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stringCopy(char_t *dest, const char_t *src, const size_t destSize) {
|
||||||
|
assertNotNull(dest, "dest must not be NULL");
|
||||||
|
assertNotNull(src, "src must not be NULL");
|
||||||
|
assertStrLenMax(src, destSize, "src is too long");
|
||||||
|
strncpy(dest, src, destSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int stringCompare(const char_t *str1, const char_t *str2) {
|
||||||
|
assertNotNull(str1, "str1 must not be NULL");
|
||||||
|
assertNotNull(str2, "str2 must not be NULL");
|
||||||
|
return strcmp(str1, str2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stringTrim(char_t *str) {
|
||||||
|
assertNotNull(str, "str must not be NULL");
|
||||||
|
|
||||||
|
// Trim leading whitespace
|
||||||
|
char_t *start = str;
|
||||||
|
while(stringIsWhitespace(*start)) start++;
|
||||||
|
|
||||||
|
// Trim trailing whitespace
|
||||||
|
char_t *end = start + strlen(start) - 1;
|
||||||
|
while (end >= start && stringIsWhitespace(*end)) end--;
|
||||||
|
|
||||||
|
// Null-terminate the string
|
||||||
|
*(end + 1) = '\0';
|
||||||
|
|
||||||
|
// Move trimmed string to the original buffer
|
||||||
|
if (start != str) memmove(str, start, end - start + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
char_t * stringToken(char_t *str, const char_t *delim) {
|
||||||
|
assertNotNull(str, "str must not be NULL");
|
||||||
|
assertNotNull(delim, "delim must not be NULL");
|
||||||
|
return strtok(str, delim);
|
||||||
|
}
|
55
src/dusk/util/string.h
Normal file
55
src/dusk/util/string.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a character is whitespace.
|
||||||
|
*
|
||||||
|
* @param c The character to check.
|
||||||
|
* @return TRUE if the character is whitespace, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
bool_t stringIsWhitespace(const char_t c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies a string from src to dest, ensuring the dest string is null-terminated
|
||||||
|
* and does not exceed the specified size.
|
||||||
|
*
|
||||||
|
* @param dest The destination string.
|
||||||
|
* @param src The source string.
|
||||||
|
* @param destSize The size of the destination string exc. null terminator.
|
||||||
|
*/
|
||||||
|
void stringCopy(char_t *dest, const char_t *src, const size_t destSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two strings.
|
||||||
|
*
|
||||||
|
* @param str1 The first string.
|
||||||
|
* @param str2 The second string.
|
||||||
|
* @return 0 if the strings are equal, -1 if str1 is less than str2, 1 if str1
|
||||||
|
* is greater than str2.
|
||||||
|
*/
|
||||||
|
int stringCompare(const char_t *str1, const char_t *str2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trims whitespace from the beginning and end of a string.
|
||||||
|
*
|
||||||
|
* @param str The string to trim.
|
||||||
|
*/
|
||||||
|
void stringTrim(char_t *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next token in a string using a delimiter.
|
||||||
|
* e.g. input: "Hello, World, Happy Monday!" with stringToken(input, ",") will
|
||||||
|
* return "Hello" then " World" then " Happy Monday!" on each subsequent call.
|
||||||
|
*
|
||||||
|
* @param str The string to split.
|
||||||
|
* @param delim The delimiter to split by.
|
||||||
|
* @return A pointer to the next token in the string.
|
||||||
|
*/
|
||||||
|
char_t * stringToken(char_t *str, const char_t *delim);
|
@ -1,15 +1,23 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
# Copyright (c) 2025 Dominic Masters
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
|
||||||
|
# Libs
|
||||||
|
target_link_libraries(${DUSK_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
)
|
||||||
|
|
||||||
|
# Includes
|
||||||
|
target_include_directories(${DUSK_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
entity.c
|
main.c
|
||||||
facing.c
|
|
||||||
player.c
|
|
||||||
npc.c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
39
src/dusktest/main.c
Normal file
39
src/dusktest/main.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dusk.h"
|
||||||
|
#include "error/error.h"
|
||||||
|
#include "console/console.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
|
bool_t exitRequested = false;
|
||||||
|
|
||||||
|
void cmdExit(const consolecmdexec_t *exec) {
|
||||||
|
exitRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testChange(const consolevar_t *var) {
|
||||||
|
consolePrint("Variable '%s' changed to '%s'.", var->name, var->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
consoleInit();
|
||||||
|
|
||||||
|
consoleRegCmd("exit", cmdExit);
|
||||||
|
consoleRegVar("test", "Hello", testChange);
|
||||||
|
consolePrint(" = Dusk Console = ");
|
||||||
|
|
||||||
|
char_t buffer[CONSOLE_LINE_MAX];
|
||||||
|
while(fgets(buffer, sizeof(buffer), stdin)) {
|
||||||
|
consoleExec(buffer);
|
||||||
|
consoleProcess();
|
||||||
|
if(exitRequested) break;
|
||||||
|
}
|
||||||
|
printf("Goodbye!\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Reference in New Issue
Block a user