BG implemented
This commit is contained in:
@ -8,11 +8,13 @@ cmake_minimum_required(VERSION 3.13)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
if(NOT DEFINED DUSK_TARGET_SYSTEM)
|
||||
set(DUSK_TARGET_SYSTEM "raylib")
|
||||
endif()
|
||||
|
||||
# Prep cache
|
||||
set(DUSK_CACHE_TARGET "dusk-target")
|
||||
|
||||
# Platform configs
|
||||
|
||||
# Build variables
|
||||
set(DUSK_ROOT_DIR "${CMAKE_SOURCE_DIR}")
|
||||
set(DUSK_BUILD_DIR "${CMAKE_BINARY_DIR}")
|
||||
@ -26,6 +28,11 @@ set(DUSK_TARGET_NAME "Dusk" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
set(DUSK_BUILD_BINARY ${DUSK_BUILD_DIR}/Dusk CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
set(DUSK_ASSETS "" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
|
||||
# Toolchain
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "gb")
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/toolchains/gbdk.cmake)
|
||||
endif()
|
||||
|
||||
# Create directories
|
||||
file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR})
|
||||
file(MAKE_DIRECTORY ${DUSK_ASSETS_BUILD_DIR})
|
||||
@ -36,7 +43,7 @@ project(${DUSK_TARGET_NAME}
|
||||
LANGUAGES C
|
||||
)
|
||||
|
||||
# Executable
|
||||
# Executable
|
||||
add_executable(${DUSK_TARGET_NAME})
|
||||
|
||||
# Add tools
|
||||
|
49
cmake/toolchains/gbdk.cmake
Normal file
49
cmake/toolchains/gbdk.cmake
Normal file
@ -0,0 +1,49 @@
|
||||
set(GBDK_HOME "$ENV{GBDK_HOME}")
|
||||
if(NOT GBDK_HOME)
|
||||
set(GBDK_HOME "/opt/gbdk")
|
||||
message(STATUS "GBDK_HOME not set, using default: ${GBDK_HOME}")
|
||||
endif()
|
||||
|
||||
# Use Linux to omit any unwanted file extension in the created ROM file
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
|
||||
set(CMAKE_C_COMPILER lcc)
|
||||
set(CMAKE_C_COMPILER_FORCED TRUE)
|
||||
|
||||
set(GBDK_INCLUDE_DIR ${GBDK_HOME}/include)
|
||||
set(GBDK_LIB_DIR ${GBDK_HOME}/lib)
|
||||
|
||||
set(CMAKE_PROGRAM_PATH ${GBDK_HOME}/bin)
|
||||
set(CMAKE_INCLUDE_PATH ${GBDK_INCLUDE_DIR})
|
||||
set(CMAKE_LIBRARY_PATH ${GBDK_LIB_DIR})
|
||||
|
||||
|
||||
set(CMAKE_SYSTEM_INCLUDE_PATH ${GBDK_INCLUDE_DIR})
|
||||
set(CMAKE_SYSTEM_LIBRARY_PATH ${GBDK_LIB_DIR})
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
|
||||
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
|
||||
|
||||
function(add_gb_rom target)
|
||||
set(GB_MBC_TYPE 0)
|
||||
if(ARGC GREATER_EQUAL 2)
|
||||
set(GB_MBC_TYPE ${ARGV1})
|
||||
endif()
|
||||
set(GB_ROM_BANKS 2)
|
||||
if(ARGC GREATER_EQUAL 3)
|
||||
set(GB_ROM_BANKS ${ARGV2})
|
||||
endif()
|
||||
set(GB_RAM_BANKS 0)
|
||||
if(ARGC GREATER_EQUAL 4)
|
||||
set(GB_RAM_BANKS ${ARGV3})
|
||||
endif()
|
||||
|
||||
|
||||
set_target_properties(${target} PROPERTIES OUTPUT_NAME ${target} SUFFIX ".gb")
|
||||
target_compile_options(${target} PRIVATE -Wa-l -Wl-m -Wl-j -DUSE_SFR_FOR_REG)
|
||||
target_link_options(${target} PRIVATE "-Wl-yt${GB_MBC_TYPE}" "-Wl-yo${GB_ROM_BANKS}" "-Wl-ya${GB_RAM_BANKS}")
|
||||
endfunction()
|
@ -4,4 +4,9 @@
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_subdirectory(dusk)
|
||||
add_subdirectory(duskraylib)
|
||||
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "gb")
|
||||
add_subdirectory(duskgb)
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "raylib")
|
||||
add_subdirectory(duskraylib)
|
||||
endif()
|
@ -6,7 +6,6 @@
|
||||
# Libs
|
||||
target_link_libraries(${DUSK_TARGET_NAME}
|
||||
PUBLIC
|
||||
m
|
||||
)
|
||||
|
||||
# Includes
|
||||
@ -19,12 +18,9 @@ target_include_directories(${DUSK_TARGET_NAME}
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
main.c
|
||||
input.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(assert)
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(rpg)
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(ui)
|
||||
add_subdirectory(util)
|
@ -7,118 +7,79 @@
|
||||
|
||||
#include "assert.h"
|
||||
|
||||
void assertTrueImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const bool x,
|
||||
const char *message
|
||||
) {
|
||||
if(x != true) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Assertion Failed in %s:%i\n\n%s\n",
|
||||
#ifndef ASSERTIONS_FAKED
|
||||
void assertTrueImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const bool x,
|
||||
const char *message
|
||||
) {
|
||||
if(x != true) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Assertion Failed in %s:%i\n\n%s\n",
|
||||
file,
|
||||
line,
|
||||
message
|
||||
);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void assertFalseImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
bool x,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(file, line, !x, message);
|
||||
}
|
||||
|
||||
void assertUnreachableImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(file, line, false, message);
|
||||
}
|
||||
|
||||
void assertNotNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(
|
||||
file,
|
||||
line,
|
||||
pointer != NULL,
|
||||
message
|
||||
);
|
||||
abort();
|
||||
|
||||
// Ensure we can touch it
|
||||
volatile char temp;
|
||||
temp = *((char*)pointer);
|
||||
}
|
||||
}
|
||||
|
||||
void assertFalseImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
bool x,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(file, line, !x, message);
|
||||
}
|
||||
void assertNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(
|
||||
file,
|
||||
line,
|
||||
pointer == NULL,
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
void assertUnreachableImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(file, line, false, message);
|
||||
}
|
||||
|
||||
void assertNotNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(
|
||||
file,
|
||||
line,
|
||||
pointer != NULL,
|
||||
message
|
||||
);
|
||||
|
||||
// Ensure we can touch it
|
||||
volatile char temp;
|
||||
temp = *((char*)pointer);
|
||||
}
|
||||
|
||||
void assertNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
) {
|
||||
assertTrueImpl(
|
||||
file,
|
||||
line,
|
||||
pointer == NULL,
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
void assertDeprecatedImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
) {
|
||||
assertUnreachableImpl(file, line, message);
|
||||
}
|
||||
|
||||
// void assertMemoryRangeMatchesImpl(
|
||||
// const char *file,
|
||||
// const int32_t line,
|
||||
// const void *start,
|
||||
// const void *end,
|
||||
// const size_t size,
|
||||
// const char *message
|
||||
// ) {
|
||||
// assertTrueImpl(
|
||||
// file,
|
||||
// line,
|
||||
// start != NULL,
|
||||
// "Start pointer is NULL"
|
||||
// );
|
||||
// assertTrueImpl(
|
||||
// file,
|
||||
// line,
|
||||
// end != NULL,
|
||||
// "End pointer is NULL"
|
||||
// );
|
||||
// assertTrueImpl(
|
||||
// file,
|
||||
// line,
|
||||
// size > 0,
|
||||
// "Size is 0"
|
||||
// );
|
||||
// assertTrueImpl(
|
||||
// file,
|
||||
// line,
|
||||
// start < end,
|
||||
// "Start pointer is not before end pointer"
|
||||
// );
|
||||
|
||||
// assertTrueImpl(
|
||||
// file,
|
||||
// line,
|
||||
// ((uintptr_t)end - (uintptr_t)start) == size,
|
||||
// message
|
||||
// );
|
||||
// }
|
||||
void assertDeprecatedImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
) {
|
||||
assertUnreachableImpl(file, line, message);
|
||||
}
|
||||
#endif
|
@ -8,124 +8,136 @@
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
/**
|
||||
* Assert a given value to be true.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param x Value to assert as true.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertTrueImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const bool x,
|
||||
const char *message
|
||||
);
|
||||
#ifndef ASSERTIONS_FAKED
|
||||
/**
|
||||
* Assert a given value to be true.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param x Value to assert as true.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertTrueImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const bool_t x,
|
||||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Asserts a given statement to be false.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param x Value to assert as false.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertFalseImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const bool x,
|
||||
const char *message
|
||||
);
|
||||
/**
|
||||
* Asserts a given statement to be false.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param x Value to assert as false.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertFalseImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const bool_t x,
|
||||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Asserts that a given line of code is unreachable. Essentially a forced
|
||||
* assertion failure, good for "edge cases"
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertUnreachableImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
);
|
||||
/**
|
||||
* Asserts that a given line of code is unreachable. Essentially a forced
|
||||
* assertion failure, good for "edge cases"
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertUnreachableImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Assert a given pointer to not point to a null pointer.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param pointer Pointer to assert is not a null pointer.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertNotNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
);
|
||||
/**
|
||||
* Assert a given pointer to not point to a null pointer.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param pointer Pointer to assert is not a null pointer.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertNotNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Asserts a given pointer to be a nullptr.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param pointer Pointer to assert is nullptr.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
);
|
||||
/**
|
||||
* Asserts a given pointer to be a nullptr.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param pointer Pointer to assert is nullptr.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertNullImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *pointer,
|
||||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* Asserts a function as being deprecated.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertDeprecatedImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
);
|
||||
/**
|
||||
* Asserts a function as being deprecated.
|
||||
*
|
||||
* @param file File that the assertion is being made from.
|
||||
* @param line Line that the assertion is being made from.
|
||||
* @param message Message to throw against assertion failure.
|
||||
*/
|
||||
void assertDeprecatedImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const char *message
|
||||
);
|
||||
|
||||
void assertMemoryRangeMatchesImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *start,
|
||||
const void *end,
|
||||
const size_t size,
|
||||
const char *message
|
||||
);
|
||||
void assertMemoryRangeMatchesImpl(
|
||||
const char *file,
|
||||
const int32_t line,
|
||||
const void *start,
|
||||
const void *end,
|
||||
const size_t size,
|
||||
const char *message
|
||||
);
|
||||
|
||||
#define assertTrue(x, message) \
|
||||
assertTrueImpl(__FILE__, __LINE__, x, message)
|
||||
#define assertTrue(x, message) \
|
||||
assertTrueImpl(__FILE__, __LINE__, x, message)
|
||||
|
||||
#define assertFalse(x, message) \
|
||||
assertFalseImpl(__FILE__, __LINE__, x, message)
|
||||
#define assertFalse(x, message) \
|
||||
assertFalseImpl(__FILE__, __LINE__, x, message)
|
||||
|
||||
#define assertUnreachable(message) \
|
||||
assertUnreachableImpl(__FILE__, __LINE__, message)
|
||||
#define assertUnreachable(message) \
|
||||
assertUnreachableImpl(__FILE__, __LINE__, message)
|
||||
|
||||
#define assertNotNull(pointer, message) \
|
||||
assertNotNullImpl(__FILE__, __LINE__, pointer, message)
|
||||
#define assertNotNull(pointer, message) \
|
||||
assertNotNullImpl(__FILE__, __LINE__, pointer, message)
|
||||
|
||||
#define assertNull(pointer, message) \
|
||||
assertNullImpl(__FILE__, __LINE__, pointer, message)
|
||||
#define assertNull(pointer, message) \
|
||||
assertNullImpl(__FILE__, __LINE__, pointer, message)
|
||||
|
||||
#define assertDeprecated(message) \
|
||||
assertDeprecatedImpl(__FILE__, __LINE__, message)
|
||||
#define assertDeprecated(message) \
|
||||
assertDeprecatedImpl(__FILE__, __LINE__, message)
|
||||
|
||||
#define assertStrLenMax(str, len, message) \
|
||||
assertTrue(strlen(str) < len, message)
|
||||
#define assertStrLenMax(str, len, message) \
|
||||
assertTrue(strlen(str) < len, message)
|
||||
|
||||
#define assertStrLenMin(str, len, message) \
|
||||
assertTrue(strlen(str) >= len, message)
|
||||
#define assertStrLenMin(str, len, message) \
|
||||
assertTrue(strlen(str) >= len, message)
|
||||
|
||||
// EOF
|
||||
#else
|
||||
// If assertions are faked, we define the macros to do nothing.
|
||||
#define assertTrue(x, message) ((void)0)
|
||||
#define assertFalse(x, message) ((void)0)
|
||||
#define assertUnreachable(message) ((void)0)
|
||||
#define assertNotNull(pointer, message) ((void)0)
|
||||
#define assertNull(pointer, message) ((void)0)
|
||||
#define assertDeprecated(message) ((void)0)
|
||||
#define assertStrLenMax(str, len, message) ((void)0)
|
||||
#define assertStrLenMin(str, len, message) ((void)0)
|
||||
|
||||
#endif
|
@ -1,9 +1,10 @@
|
||||
# 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
|
||||
render.c
|
||||
)
|
@ -5,4 +5,4 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "quest.h"
|
||||
#include "render.h"
|
@ -6,22 +6,37 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "display/renderimpl.h"
|
||||
|
||||
extern const uint16_t RENDER_WIDTH;
|
||||
extern const uint16_t RENDER_HEIGHT;
|
||||
#define RENDER_WIDTH_PIXELS 160
|
||||
#define RENDER_HEIGHT_PIXELS 144
|
||||
#define RENDER_WIDTH_TILES 20
|
||||
#define RENDER_HEIGHT_TILES 18
|
||||
|
||||
extern uint8_t RENDER_STATUS;
|
||||
#define RENDER_SHOULD_EXIT (1 << 0)
|
||||
|
||||
/**
|
||||
* Init the render system.
|
||||
* Initializes the rendering system.
|
||||
*/
|
||||
void renderInit();
|
||||
void renderInit(void);
|
||||
|
||||
/**
|
||||
* Update the render system.
|
||||
* Vsyncs the frame.
|
||||
*/
|
||||
bool_t renderUpdate();
|
||||
void renderVsync(void);
|
||||
|
||||
/**
|
||||
* Dispose of the render system.
|
||||
* Disposes of the rendering system.
|
||||
*/
|
||||
void renderDispose();
|
||||
void renderDispose(void);
|
||||
|
||||
/**
|
||||
* Turns off the display.
|
||||
*/
|
||||
void renderDisplayOff(void);
|
||||
|
||||
/**
|
||||
* Turns on the display.
|
||||
*/
|
||||
void renderDisplayOn(void);
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Dominic Masters
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
@ -7,20 +7,10 @@
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef bool bool_t;
|
||||
typedef char char_t;
|
||||
|
||||
#define DUSK_NAME "Dusk"
|
||||
#define DUSK_VERSION "1.0.0"
|
||||
typedef int int_t;
|
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "input.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
input_t INPUT;
|
||||
|
||||
bool_t inputIsDown(const uint8_t key) {
|
||||
assertTrue(key < INPUT_COUNT, "Invalid input key");
|
||||
return (INPUT.current & key) != 0;
|
||||
}
|
||||
|
||||
bool_t inputWasDown(const uint8_t key) {
|
||||
assertTrue(key < INPUT_COUNT, "Invalid input key");
|
||||
return (INPUT.previous & key) != 0;
|
||||
}
|
||||
|
||||
bool_t inputWasPressed(const uint8_t key) {
|
||||
return inputIsDown(key) && !inputWasDown(key);
|
||||
}
|
||||
|
||||
bool_t inputWasReleased(const uint8_t key) {
|
||||
return !inputIsDown(key) && inputWasDown(key);
|
||||
}
|
@ -1,74 +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 <termios.h>
|
||||
|
||||
#define INPUT_UP (1 << 0)
|
||||
#define INPUT_DOWN (1 << 1)
|
||||
#define INPUT_LEFT (1 << 2)
|
||||
#define INPUT_RIGHT (1 << 3)
|
||||
#define INPUT_ACTION (1 << 4)
|
||||
#define INPUT_CANCEL (1 << 5)
|
||||
#define INPUT_COUNT (INPUT_CANCEL + 1)
|
||||
|
||||
#define INPUT_BUFFER_SIZE 128
|
||||
|
||||
typedef struct {
|
||||
uint8_t current;
|
||||
uint8_t previous;
|
||||
} input_t;
|
||||
|
||||
extern input_t INPUT;
|
||||
|
||||
/**
|
||||
* Initializes the input system.
|
||||
*/
|
||||
void inputInit();
|
||||
|
||||
/**
|
||||
* Updates the input system.
|
||||
*/
|
||||
void inputUpdate();
|
||||
|
||||
/**
|
||||
* Disposes of the input system, restoring terminal settings.
|
||||
*/
|
||||
void inputDispose();
|
||||
|
||||
/**
|
||||
* Returns true if the specified key is currently pressed down.
|
||||
*
|
||||
* @param key The key to check.
|
||||
* @return True if the key is down, false otherwise.
|
||||
*/
|
||||
bool_t inputIsDown(const uint8_t key);
|
||||
|
||||
/**
|
||||
* Returns true if the specified key was pressed down in the previous frame.
|
||||
*
|
||||
* @param key The key to check.
|
||||
* @return True if the key was down in the previous frame, false otherwise.
|
||||
*/
|
||||
bool_t inputWasDown(const uint8_t key);
|
||||
|
||||
/**
|
||||
* Returns true if the specified key was pressed in the current frame.
|
||||
*
|
||||
* @param key The key to check.
|
||||
* @return True if the key was pressed, false otherwise.
|
||||
*/
|
||||
bool_t inputWasPressed(const uint8_t key);
|
||||
|
||||
/**
|
||||
* Returns true if the specified key was released in the current frame.
|
||||
*
|
||||
* @param key The key to check.
|
||||
* @return True if the key was released, false otherwise.
|
||||
*/
|
||||
bool_t inputWasReleased(const uint8_t key);
|
138
src/dusk/main.c
138
src/dusk/main.c
@ -1,32 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "input.h"
|
||||
#include "util/random.h"
|
||||
#include "display/render.h"
|
||||
|
||||
#include "ui/ui.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "rpg/world/maps/testmap.h"
|
||||
uint8_t backgroundtiles[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFE, 0xFE, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0xFE, 0xFE, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0xFE, 0xFE, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0xFE, 0xFE, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0x7F, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
0x7F, 0x7F, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
|
||||
0x55, 0x00, 0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00,
|
||||
0x55, 0x00, 0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xAA, 0xFF, 0x00, 0x55, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00
|
||||
};
|
||||
|
||||
int32_t main(const int32_t argc, const char **argv) {
|
||||
renderInit();
|
||||
inputInit();
|
||||
randomInit();
|
||||
#define backgroundmapWidth 40
|
||||
#define backgroundmapHeight 18
|
||||
#define backgroundmapBank 0
|
||||
|
||||
uiInit();
|
||||
mapSet(TEST_MAP);
|
||||
uint8_t backgroundmap[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
|
||||
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
|
||||
0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
|
||||
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
|
||||
0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
|
||||
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
|
||||
0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
|
||||
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
|
||||
0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x03,
|
||||
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
|
||||
0x01,0x02,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
|
||||
0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
|
||||
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04
|
||||
};
|
||||
|
||||
while(1) {
|
||||
inputUpdate();
|
||||
uiUpdate();
|
||||
mapUpdate();
|
||||
if(!renderUpdate()) break;
|
||||
void pdelay(uint8_t numVbls) {
|
||||
uint8_t i;
|
||||
for (i = 0; i < numVbls; i++) {
|
||||
renderVsync();
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
// Press F5 to compile and run the compiled game.gb in the Emulicous Emulator/Debugger
|
||||
void main(void) {
|
||||
renderInit();
|
||||
|
||||
set_bkg_data(0, 7, backgroundtiles);
|
||||
set_bkg_tiles(0, 0, backgroundmapWidth, backgroundmapHeight, backgroundmap);
|
||||
|
||||
renderDisplayOn();
|
||||
|
||||
while (1) {
|
||||
RENDER_BACKGROUND_X++;
|
||||
pdelay(3);
|
||||
|
||||
if((RENDER_STATUS & RENDER_SHOULD_EXIT) != 0) break;
|
||||
}
|
||||
|
||||
renderDispose();
|
||||
}
|
@ -1,16 +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
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(entity)
|
||||
add_subdirectory(event)
|
||||
add_subdirectory(item)
|
||||
add_subdirectory(quest)
|
||||
add_subdirectory(world)
|
@ -1,12 +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
|
||||
entity.c
|
||||
player.c
|
||||
npc.c
|
||||
)
|
@ -1,192 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "entity.h"
|
||||
#include "rpg/world/map.h"
|
||||
#include "util/math.h"
|
||||
|
||||
entitycallbacks_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT] = {
|
||||
[ENTITY_TYPE_NULL] = { 0 },
|
||||
|
||||
[ENTITY_TYPE_PLAYER] = {
|
||||
.init = playerInit,
|
||||
.update = playerUpdate,
|
||||
.interact = NULL,
|
||||
},
|
||||
|
||||
[ENTITY_TYPE_NPC] = {
|
||||
.init = npcInit,
|
||||
.update = npcUpdate,
|
||||
.interact = npcInteract,
|
||||
}
|
||||
};
|
||||
|
||||
void entityInit(entity_t *entity, const entitytype_t type) {
|
||||
assertNotNull(entity, "Entity is NULL");
|
||||
assertTrue(type < ENTITY_TYPE_COUNT, "Invalid entity type");
|
||||
assertNotNull(ENTITY_CALLBACKS[type].init, "Entity type has no init");
|
||||
|
||||
memoryZero(entity, sizeof(entity_t));
|
||||
entity->type = type;
|
||||
ENTITY_CALLBACKS[type].init(entity);
|
||||
}
|
||||
|
||||
void entityUpdate(entity_t *entity) {
|
||||
assertNotNull(entity, "Entity cannot be NULL");
|
||||
assertNotNull(
|
||||
ENTITY_CALLBACKS[entity->type].update,
|
||||
"Entity type has no update"
|
||||
);
|
||||
|
||||
// Handle subpixel movement
|
||||
if(entity->subX < 0) {
|
||||
entity->subX++;
|
||||
} else if(entity->subY < 0) {
|
||||
entity->subY++;
|
||||
} else if(entity->subX > 0) {
|
||||
entity->subX--;
|
||||
} else if(entity->subY > 0) {
|
||||
entity->subY--;
|
||||
}
|
||||
|
||||
// Entity-Type handling
|
||||
ENTITY_CALLBACKS[entity->type].update(entity);
|
||||
}
|
||||
|
||||
void entityTurn(entity_t *entity, const entitydir_t dir) {
|
||||
assertNotNull(entity, "Entity cannot be NULL");
|
||||
assertFalse(entityIsWalking(entity), "Entity is currently walking");
|
||||
entity->dir = dir;
|
||||
}
|
||||
|
||||
void entityDirGetPosition(
|
||||
const entitydir_t dir,
|
||||
const uint8_t distance,
|
||||
int8_t *outX,
|
||||
int8_t *outY
|
||||
) {
|
||||
assertTrue(dir < ENTITY_DIR_COUNT, "Invalid entity direction");
|
||||
assertNotNull(outX, "Output X cannot be NULL");
|
||||
assertNotNull(outY, "Output Y cannot be NULL");
|
||||
|
||||
switch(dir) {
|
||||
case ENTITY_DIR_UP:
|
||||
*outX = 0;
|
||||
*outY = -distance;
|
||||
break;
|
||||
case ENTITY_DIR_DOWN:
|
||||
*outX = 0;
|
||||
*outY = distance;
|
||||
break;
|
||||
case ENTITY_DIR_LEFT:
|
||||
*outX = -distance;
|
||||
*outY = 0;
|
||||
break;
|
||||
case ENTITY_DIR_RIGHT:
|
||||
*outX = distance;
|
||||
*outY = 0;
|
||||
break;
|
||||
default:
|
||||
assertUnreachable("Invalid entity direction");
|
||||
}
|
||||
}
|
||||
|
||||
entitydir_t entityGetLookDirection(
|
||||
const entity_t *entity,
|
||||
const uint8_t x,
|
||||
const uint8_t y
|
||||
) {
|
||||
assertNotNull(entity, "Entity cannot be NULL");
|
||||
assertTrue(x < MAP.width, "X coordinate out of bounds");
|
||||
assertTrue(y < MAP.height, "Y coordinate out of bounds");
|
||||
|
||||
int8_t dX = x - entity->x;
|
||||
int8_t dY = y - entity->y;
|
||||
|
||||
// More horizontal movement or more vertical movement?
|
||||
if(mathAbsI8(dX) > mathAbsI8(dY)) {
|
||||
// More horizontal movement
|
||||
if(dX < 0) return ENTITY_DIR_LEFT;
|
||||
return ENTITY_DIR_RIGHT;
|
||||
}
|
||||
|
||||
if(dY < 0) {
|
||||
return ENTITY_DIR_UP;
|
||||
}
|
||||
return ENTITY_DIR_DOWN;
|
||||
}
|
||||
|
||||
void entityWalk(entity_t *entity) {
|
||||
assertNotNull(entity, "Entity cannot be NULL");
|
||||
assertFalse(entityIsWalking(entity), "Entity is already walking");
|
||||
assertTrue(entityCanWalk(entity, entity->dir, NULL), "Entity cannot walk");
|
||||
|
||||
int8_t tX, tY;
|
||||
entityDirGetPosition(entity->dir, 1, &tX, &tY);
|
||||
|
||||
entity->y += tY;
|
||||
entity->x += tX;
|
||||
entity->subX = ENTITY_MOVE_SUBPIXEL * -tX;
|
||||
entity->subY = ENTITY_MOVE_SUBPIXEL * -tY;
|
||||
}
|
||||
|
||||
bool_t entityIsWalking(const entity_t *entity) {
|
||||
assertNotNull(entity, "Entity cannot be NULL");
|
||||
return (entity->subX != 0 || entity->subY != 0);
|
||||
}
|
||||
|
||||
bool_t entityCanWalk(
|
||||
const entity_t *entity,
|
||||
const entitydir_t dir,
|
||||
entity_t **entityInWay
|
||||
) {
|
||||
assertNotNull(entity, "Entity cannot be NULL");
|
||||
assertTrue(dir < ENTITY_DIR_COUNT, "Invalid entity direction");
|
||||
|
||||
int8_t dX, dY;
|
||||
entityDirGetPosition(dir, 1, &dX, &dY);
|
||||
|
||||
uint8_t tX = entity->x + dX;
|
||||
if(tX < 0 || tX >= MAP.width) return false;
|
||||
|
||||
uint8_t tY = entity->y + dY;
|
||||
if(tY < 0 || tY >= MAP.height) return false;
|
||||
|
||||
if(entityInWay == NULL) {
|
||||
if(mapGetEntityAt(tX, tY) != NULL) return false;
|
||||
} else {
|
||||
*entityInWay = mapGetEntityAt(tX, tY);
|
||||
if(*entityInWay != NULL) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void entityPositionSet(entity_t *entity, const uint8_t x, const uint8_t y) {
|
||||
assertNotNull(entity, "Entity cannot be NULL");
|
||||
assertTrue(x < MAP.width, "X coordinate out of bounds");
|
||||
assertTrue(y < MAP.height, "Y coordinate out of bounds");
|
||||
entity->x = x;
|
||||
entity->y = y;
|
||||
entity->subX = 0;
|
||||
entity->subY = 0;
|
||||
}
|
||||
|
||||
bool_t entityInteract(entity_t *interacted, entity_t *player) {
|
||||
assertNotNull(interacted, "Interacted entity cannot be NULL");
|
||||
assertNotNull(player, "Player entity cannot be NULL");
|
||||
assertTrue(interacted->type != ENTITY_TYPE_NULL, "Interacted entity invalid");
|
||||
assertTrue(player->type == ENTITY_TYPE_PLAYER, "Entity is not a player");
|
||||
|
||||
if(ENTITY_CALLBACKS[interacted->type].interact != NULL) {
|
||||
return ENTITY_CALLBACKS[interacted->type].interact(interacted, player);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
@ -1,158 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "player.h"
|
||||
#include "npc.h"
|
||||
|
||||
#define ENTITY_WIDTH 16
|
||||
#define ENTITY_HEIGHT 16
|
||||
#define ENTITY_MOVE_SUBPIXEL ENTITY_WIDTH
|
||||
|
||||
typedef enum {
|
||||
ENTITY_DIR_UP = 0,
|
||||
ENTITY_DIR_DOWN = 1,
|
||||
ENTITY_DIR_LEFT = 2,
|
||||
ENTITY_DIR_RIGHT = 3,
|
||||
|
||||
ENTITY_DIR_NORTH = ENTITY_DIR_UP,
|
||||
ENTITY_DIR_SOUTH = ENTITY_DIR_DOWN,
|
||||
ENTITY_DIR_WEST = ENTITY_DIR_LEFT,
|
||||
ENTITY_DIR_EAST = ENTITY_DIR_RIGHT
|
||||
} entitydir_t;
|
||||
|
||||
#define ENTITY_DIR_COUNT (ENTITY_DIR_RIGHT + 1)
|
||||
|
||||
typedef enum {
|
||||
ENTITY_TYPE_NULL = 0,
|
||||
ENTITY_TYPE_PLAYER = 1,
|
||||
ENTITY_TYPE_NPC = 2,
|
||||
} entitytype_t;
|
||||
#define ENTITY_TYPE_COUNT (ENTITY_TYPE_NPC + 1)
|
||||
|
||||
typedef struct _entity_t {
|
||||
entitytype_t type;
|
||||
uint8_t x, y;
|
||||
int8_t subX, subY;
|
||||
entitydir_t dir;
|
||||
|
||||
// Per type data
|
||||
union {
|
||||
player_t player;
|
||||
npc_t npc;
|
||||
};
|
||||
} entity_t;
|
||||
|
||||
typedef struct {
|
||||
void (*init)(entity_t *entity);
|
||||
void (*update)(entity_t *entity);
|
||||
bool_t (*interact)(entity_t *self, entity_t *player);
|
||||
} entitycallbacks_t;
|
||||
extern entitycallbacks_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT];
|
||||
|
||||
/**
|
||||
* Initializes an entity with the given type.
|
||||
*
|
||||
* @param entity Pointer to the entity to initialize.
|
||||
* @param type The type of the entity to initialize.
|
||||
*/
|
||||
void entityInit(entity_t *entity, const entitytype_t type);
|
||||
|
||||
/**
|
||||
* Updates the entity's state based on its type.
|
||||
*
|
||||
* @param entity Pointer to the entity to update.
|
||||
*/
|
||||
void entityUpdate(entity_t *entity);
|
||||
|
||||
/**
|
||||
* Turns the entity to face a specific direction.
|
||||
*
|
||||
* @param entity Pointer to the entity to turn.
|
||||
* @param dir The direction to turn the entity towards.
|
||||
*/
|
||||
void entityTurn(entity_t *entity, const entitydir_t dir);
|
||||
|
||||
/**
|
||||
* Gets the position of a specific direction at a given distance.
|
||||
*
|
||||
* @param dir The direction to get the position in.
|
||||
* @param distance The distance to move in that direction.
|
||||
* @param outX Pointer to store the resulting x-coordinate.
|
||||
* @param outY Pointer to store the resulting y-coordinate.
|
||||
*/
|
||||
void entityDirGetPosition(
|
||||
const entitydir_t dir,
|
||||
const uint8_t distance,
|
||||
int8_t *outX,
|
||||
int8_t *outY
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the look direction for a given entity to be looking at the specified
|
||||
* coordinates.
|
||||
*
|
||||
* @param entity Pointer to the entity to get the look direction for.
|
||||
* @param x The x-coordinate to look at.
|
||||
* @param Y The y-coordinate to look at.
|
||||
* @return The direction the entity should look towards.
|
||||
*/
|
||||
entitydir_t entityGetLookDirection(
|
||||
const entity_t *entity,
|
||||
const uint8_t x,
|
||||
const uint8_t Y
|
||||
);
|
||||
|
||||
/**
|
||||
* Makes the entity walk in the current direction.
|
||||
*
|
||||
* @param entity Pointer to the entity to make walk.
|
||||
*/
|
||||
void entityWalk(entity_t *entity);
|
||||
|
||||
/**
|
||||
* Checks if the entity is currently mid-walking.
|
||||
*
|
||||
* @param entity Pointer to the entity to check.
|
||||
* @return true if the entity is walking, false otherwise.
|
||||
*/
|
||||
bool_t entityIsWalking(const entity_t *entity);
|
||||
|
||||
/**
|
||||
* Checks if the entity can walk in a specific direction.
|
||||
*
|
||||
* @param entity Pointer to the entity to check.
|
||||
* @param dir The direction to check for walking capability.
|
||||
* @param inWay Pointer to store any entity in the way, if applicable.
|
||||
* @return true if the entity can walk in the specified direction, false otherwise.
|
||||
*/
|
||||
bool_t entityCanWalk(
|
||||
const entity_t *entity,
|
||||
const entitydir_t dir,
|
||||
entity_t **inWay
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets the position of the entity.
|
||||
*
|
||||
* @param entity Pointer to the entity to set the position for.
|
||||
* @param x The x-coordinate to set.
|
||||
* @param y The y-coordinate to set.
|
||||
*/
|
||||
void entityPositionSet(entity_t *entity, const uint8_t x, const uint8_t y);
|
||||
|
||||
/**
|
||||
* Handles interaction between an entity and a player.
|
||||
*
|
||||
* @param self Pointer to the entity that is being interacted with.
|
||||
* @param player Pointer to the player entity interacting with the entity.
|
||||
* @return true if interaction happened.
|
||||
*/
|
||||
bool_t entityInteract(
|
||||
entity_t *self,
|
||||
entity_t *player
|
||||
);
|
@ -1,34 +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 "ui/uitextbox.h"
|
||||
|
||||
void npcInit(entity_t *ent) {
|
||||
assertNotNull(ent, "NPC entity is NULL");
|
||||
assertTrue(ent->type == ENTITY_TYPE_NPC, "Entity is not an NPC");
|
||||
}
|
||||
|
||||
void npcUpdate(entity_t *ent) {
|
||||
assertNotNull(ent, "Entity is NULL");
|
||||
assertTrue(ent->type == ENTITY_TYPE_NPC, "Entity is not an NPC");
|
||||
}
|
||||
|
||||
bool_t npcInteract(entity_t *self, entity_t *player) {
|
||||
assertNotNull(self, "NPC entity cannot be NULL");
|
||||
assertNotNull(player, "Player entity cannot be NULL");
|
||||
assertTrue(self->type == ENTITY_TYPE_NPC, "Entity is not an NPC");
|
||||
assertTrue(player->type == ENTITY_TYPE_PLAYER, "Entity is not a player");
|
||||
|
||||
// Look at the player
|
||||
entityTurn(self, entityGetLookDirection(self, player->x, player->y));
|
||||
eventStart(self->npc.event);
|
||||
|
||||
return true;
|
||||
}
|
@ -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 "rpg/event/event.h"
|
||||
|
||||
typedef struct _entity_t entity_t;
|
||||
|
||||
typedef struct {
|
||||
const event_t *event;
|
||||
} npc_t;
|
||||
|
||||
/**
|
||||
* Initializes an NPC entity.
|
||||
*
|
||||
* @param ent Pointer to the NPC entity to initialize.
|
||||
*/
|
||||
void npcInit(entity_t *ent);
|
||||
|
||||
/**
|
||||
* Updates an NPC entity.
|
||||
*
|
||||
* @param ent Entity to update.
|
||||
*/
|
||||
void npcUpdate(entity_t *ent);
|
||||
|
||||
/**
|
||||
* Handles interaction between an NPC and a player.
|
||||
*
|
||||
* @param self Pointer to the NPC entity.
|
||||
* @param player Pointer to the player entity interacting with the NPC.
|
||||
*/
|
||||
bool_t npcInteract(entity_t *self, entity_t *player);
|
@ -1,58 +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 "input.h"
|
||||
#include "rpg/world/map.h"
|
||||
|
||||
void playerInit(entity_t *player) {
|
||||
assertNotNull(player, "Player entity is NULL");
|
||||
assertTrue(player->type == ENTITY_TYPE_PLAYER, "Entity is not a player");
|
||||
}
|
||||
|
||||
void playerUpdate(entity_t *entity) {
|
||||
entity_t *other;
|
||||
assertNotNull(entity, "Entity is NULL");
|
||||
assertTrue(entity->type == ENTITY_TYPE_PLAYER, "Entity is not a player");
|
||||
|
||||
// Handle movement
|
||||
if(entityIsWalking(entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
entitydir_t dir = 0xFF;
|
||||
if(inputIsDown(INPUT_UP)) {
|
||||
dir = ENTITY_DIR_UP;
|
||||
} else if(inputIsDown(INPUT_DOWN)) {
|
||||
dir = ENTITY_DIR_DOWN;
|
||||
} else if(inputIsDown(INPUT_LEFT)) {
|
||||
dir = ENTITY_DIR_LEFT;
|
||||
} else if(inputIsDown(INPUT_RIGHT)) {
|
||||
dir = ENTITY_DIR_RIGHT;
|
||||
}
|
||||
|
||||
if(dir != 0xFF) {
|
||||
if(dir != entity->dir) {
|
||||
entityTurn(entity, dir);
|
||||
} else {
|
||||
if(!entityCanWalk(entity, dir, &other)) return;
|
||||
entityWalk(entity);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle interaction
|
||||
if(inputWasPressed(INPUT_ACTION)) {
|
||||
int8_t dX, dY;
|
||||
entityDirGetPosition(entity->dir, 1, &dX, &dY);
|
||||
other = mapGetEntityAt(entity->x + dX, entity->y + dY);
|
||||
|
||||
assertTrue(other != entity, "Player trying to interact with itself?");
|
||||
if(other != NULL && entityInteract(other, entity)) return;
|
||||
}
|
||||
}
|
@ -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 {
|
||||
uint8_t nothing;
|
||||
} player_t;
|
||||
|
||||
/**
|
||||
* Initializes a player entity.
|
||||
*
|
||||
* @param ent Pointer to the player entity to initialize.
|
||||
*/
|
||||
void playerInit(entity_t *ent);
|
||||
|
||||
/**
|
||||
* Updates a player entity.
|
||||
*
|
||||
* @param ent Entity to update.
|
||||
*/
|
||||
void playerUpdate(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 "event.h"
|
||||
#include "assert/assert.h"
|
||||
#include "ui/uitextbox.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
event_t eventCreate() {
|
||||
event_t event;
|
||||
return event;
|
||||
}
|
||||
|
||||
void eventStart(const event_t *event) {
|
||||
assertNotNull(event, "Event cannot be NULL");
|
||||
assertTrue(event->count <= EVENT_ITEMS_MAX, "Event count exceeds maximum items");
|
||||
assertTrue(event->count > 0, "Event must have at least one item");
|
||||
|
||||
switch(event->type) {
|
||||
case EVENT_TYPE_CONVERSATION: {
|
||||
assertTrue(event->items[0].type == EVENT_ITEM_TYPE_TEXT, "First item in conversation must be text");
|
||||
uiTextboxSetText(event->items[0].text.text);
|
||||
uiTextboxShow();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assertFalse(true, "Unknown event type");
|
||||
}
|
||||
}
|
@ -1,47 +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 {
|
||||
EVENT_TYPE_CONVERSATION,
|
||||
} eventtype_t;
|
||||
|
||||
typedef enum {
|
||||
EVENT_ITEM_TYPE_TEXT
|
||||
} eventitemtype_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *text;
|
||||
} eventtext_t;
|
||||
|
||||
typedef struct {
|
||||
eventitemtype_t type;
|
||||
|
||||
union {
|
||||
eventtext_t text;
|
||||
};
|
||||
} eventitem_t;
|
||||
|
||||
#define EVENT_ITEMS_MAX 16
|
||||
|
||||
typedef struct {
|
||||
eventtype_t type;
|
||||
uint8_t count;
|
||||
eventitem_t items[EVENT_ITEMS_MAX];
|
||||
} event_t;
|
||||
|
||||
/**
|
||||
* Creates a new event.
|
||||
*/
|
||||
event_t eventCreate();
|
||||
|
||||
/**
|
||||
* Starts a given event.
|
||||
*/
|
||||
void eventStart(const event_t *event);
|
@ -1,11 +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
|
||||
itemtype.c
|
||||
inventory.c
|
||||
)
|
@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assert/assert.h"
|
||||
#include "inventory.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
void inventoryInit(inventory_t *inventory) {
|
||||
assertNotNull(inventory, "Inventory pointer cannot be NULL");
|
||||
|
||||
memoryZero(inventory, sizeof(inventory_t));
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "itemstack.h"
|
||||
|
||||
#define INVENTORY_ITEM_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
itemstack_t items[INVENTORY_ITEM_COUNT];
|
||||
uint8_t itemCount;
|
||||
} inventory_t;
|
||||
|
||||
/**
|
||||
* Initializes the inventory.
|
||||
*
|
||||
* @param inventory Pointer to the inventory to initialize.
|
||||
*/
|
||||
void inventoryInit(inventory_t *inventory);
|
@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "itemtype.h"
|
||||
|
||||
typedef struct {
|
||||
itemtype_t type;
|
||||
uint8_t count;
|
||||
} itemstack_t;
|
@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assert/assert.h"
|
||||
#include "itemtype.h"
|
||||
|
||||
iteminfo_t ITEM_INFO[ITEM_TYPE_COUNT] = {
|
||||
[ITEM_TYPE_NULL] = { 0 },
|
||||
|
||||
// Consumables
|
||||
[ITEM_TYPE_POTION] = { .stackable = true },
|
||||
|
||||
// Ingredients
|
||||
[ITEM_TYPE_ONION] = { .stackable = true },
|
||||
[ITEM_TYPE_SWEET_POTATO] = { .stackable = true },
|
||||
|
||||
// Cooked Items
|
||||
[ITEM_TYPE_BAKED_SWEET_POTATO] = { .stackable = true },
|
||||
};
|
||||
|
||||
static inline bool_t itemTypeIsStackable(const itemtype_t type) {
|
||||
assertTrue(type < ITEM_TYPE_COUNT, "Invalid item type");
|
||||
return ITEM_INFO[type].stackable;
|
||||
}
|
@ -1,38 +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 {
|
||||
ITEM_TYPE_NULL,
|
||||
|
||||
// Consumables
|
||||
ITEM_TYPE_POTION,
|
||||
|
||||
// Ingredients
|
||||
ITEM_TYPE_ONION,
|
||||
ITEM_TYPE_SWEET_POTATO,
|
||||
|
||||
// Cooked Items
|
||||
ITEM_TYPE_BAKED_SWEET_POTATO,
|
||||
} itemtype_t;
|
||||
|
||||
#define ITEM_TYPE_COUNT (ITEM_TYPE_BAKED_SWEET_POTATO + 1)
|
||||
|
||||
typedef struct {
|
||||
bool_t stackable;
|
||||
} iteminfo_t;
|
||||
extern iteminfo_t ITEM_INFO[ITEM_TYPE_COUNT];
|
||||
|
||||
/**
|
||||
* Returns true if the item type is stackable.
|
||||
*
|
||||
* @param type The item type to check.
|
||||
* @return true if the item type is stackable, false otherwise.
|
||||
*/
|
||||
static inline bool_t itemTypeIsStackable(const itemtype_t type);
|
@ -1,10 +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
|
||||
quest.c
|
||||
)
|
@ -1,13 +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
|
||||
map.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(maps)
|
@ -1,45 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "map.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
map_t MAP;
|
||||
|
||||
void mapSet(const mapinfo_t mapInfo) {
|
||||
assertTrue(mapInfo.init != NULL, "Map initialization function cannot be NULL");
|
||||
mapInfo.init();
|
||||
}
|
||||
|
||||
void mapInit(const uint8_t width, const uint8_t height) {
|
||||
memoryZero(&MAP, sizeof(map_t));
|
||||
|
||||
MAP.width = width;
|
||||
MAP.height = height;
|
||||
}
|
||||
|
||||
void mapUpdate() {
|
||||
entity_t *ent = MAP.entities;
|
||||
do {
|
||||
if(ent->type != ENTITY_TYPE_NULL) {
|
||||
entityUpdate(ent);
|
||||
}
|
||||
ent++;
|
||||
} while(ent < MAP.entities + MAP_ENTITY_COUNT);
|
||||
}
|
||||
|
||||
entity_t * mapGetEntityAt(const uint8_t x, const uint8_t y) {
|
||||
if(x >= MAP.width || y >= MAP.height) return NULL;
|
||||
entity_t *ent = MAP.entities;
|
||||
do {
|
||||
if(ent->type != ENTITY_TYPE_NULL && ent->x == x && ent->y == y) return ent;
|
||||
ent++;
|
||||
} while(ent < MAP.entities + MAP_ENTITY_COUNT);
|
||||
|
||||
return NULL;
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/entity/entity.h"
|
||||
|
||||
#define MAP_ENTITY_COUNT 16
|
||||
|
||||
typedef struct {
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
entity_t entities[MAP_ENTITY_COUNT];
|
||||
} map_t;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
void (*init)(void);
|
||||
} mapinfo_t;
|
||||
|
||||
extern map_t MAP;
|
||||
|
||||
/**
|
||||
* Sets the current map to the specified map information.
|
||||
*
|
||||
* This function initializes the map with the provided map information,
|
||||
* including its name and initialization function.
|
||||
*
|
||||
* @param mapInfo Map information containing the name and initialization function.
|
||||
*/
|
||||
void mapSet(const mapinfo_t mapInfo);
|
||||
|
||||
/**
|
||||
* Initializes the map with the given width and height.
|
||||
*
|
||||
* @param width Width of the map.
|
||||
* @param height Height of the map.
|
||||
*/
|
||||
void mapInit(const uint8_t width, const uint8_t height);
|
||||
|
||||
/**
|
||||
* Updates the map, processing all entities.
|
||||
*
|
||||
* This function should be called every frame to update the state of the map
|
||||
* and its entities.
|
||||
*/
|
||||
void mapUpdate();
|
||||
|
||||
/**
|
||||
* Gets the entity at the specified coordinates.
|
||||
*
|
||||
* @param x X coordinate of the entity.
|
||||
* @param y Y coordinate of the entity.
|
||||
* @return Pointer to the entity at the specified coordinates or NULL.
|
||||
*/
|
||||
entity_t * mapGetEntityAt(const uint8_t x, const uint8_t y);
|
@ -1,9 +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
|
||||
)
|
@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "rpg/world/map.h"
|
||||
#include "rpg/event/event.h"
|
||||
|
||||
const event_t TEST_MAP_NPC_TEST = {
|
||||
.type = EVENT_TYPE_CONVERSATION,
|
||||
.count = 1,
|
||||
.items = {
|
||||
{
|
||||
.type = EVENT_ITEM_TYPE_TEXT,
|
||||
.text = { .text = "Hello, player! How can I help you today?" }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the test map.
|
||||
* This function sets up a test map with predefined dimensions.
|
||||
*/
|
||||
void testMapInit() {
|
||||
mapInit(10, 10);
|
||||
|
||||
entity_t *ent = MAP.entities;
|
||||
entityInit(ent, ENTITY_TYPE_PLAYER);
|
||||
|
||||
ent++;
|
||||
entityInit(ent, ENTITY_TYPE_NPC);
|
||||
entityPositionSet(ent, 5, 5);
|
||||
ent->npc.event = &TEST_MAP_NPC_TEST;
|
||||
}
|
||||
|
||||
mapinfo_t TEST_MAP = {
|
||||
.name = "Test Map",
|
||||
.init = testMapInit
|
||||
};
|
@ -1,13 +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
|
||||
ui.c
|
||||
uitextbox.c
|
||||
)
|
||||
|
||||
# Subdirs
|
@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "ui.h"
|
||||
#include "util/memory.h"
|
||||
#include "ui/uitextbox.h"
|
||||
|
||||
ui_t UI;
|
||||
|
||||
void uiInit() {
|
||||
memoryZero(&UI, sizeof(ui_t));
|
||||
uiTextboxInit();
|
||||
}
|
||||
|
||||
void uiUpdate() {
|
||||
uiTextboxUpdate();
|
||||
}
|
@ -1,30 +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_FOCUS_TEXTBOX
|
||||
} uifocus_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t nothing;
|
||||
} ui_t;
|
||||
|
||||
extern ui_t UI;
|
||||
|
||||
/**
|
||||
* Initializes the UI system.
|
||||
*/
|
||||
void uiInit();
|
||||
|
||||
/**
|
||||
* Updates the UI system.
|
||||
* This function should be called every frame to update the UI state.
|
||||
*/
|
||||
void uiUpdate();
|
@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "uitextbox.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "display/render.h"
|
||||
#include "input.h"
|
||||
|
||||
uitextbox_t UI_TEXTBOX;
|
||||
|
||||
void uiTextboxInit() {
|
||||
memoryZero(&UI_TEXTBOX, sizeof(uitextbox_t));
|
||||
|
||||
UI_TEXTBOX.width = RENDER_WIDTH;
|
||||
UI_TEXTBOX.height = 58;
|
||||
UI_TEXTBOX.x = 0;
|
||||
UI_TEXTBOX.y = RENDER_HEIGHT - UI_TEXTBOX.height;
|
||||
}
|
||||
|
||||
void uiTextboxUpdate() {
|
||||
if(!UI_TEXTBOX.visible) return;
|
||||
|
||||
if(inputWasPressed(INPUT_ACTION)) {
|
||||
UI_TEXTBOX.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
void uiTextboxSetText(const char_t *text) {
|
||||
sprintf(UI_TEXTBOX.text, "%s", text);
|
||||
}
|
||||
|
||||
void uiTextboxShow() {
|
||||
UI_TEXTBOX.visible = true;
|
||||
}
|
||||
|
||||
void uiTextboxHide() {
|
||||
UI_TEXTBOX.visible = false;
|
||||
}
|
@ -1,49 +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 UI_TEXTBOX_TEXT_MAX_LENGTH 1024
|
||||
|
||||
typedef struct {
|
||||
bool_t visible;
|
||||
|
||||
char_t text[UI_TEXTBOX_TEXT_MAX_LENGTH];
|
||||
|
||||
uint16_t width, height;
|
||||
uint16_t x, y;
|
||||
} uitextbox_t;
|
||||
|
||||
extern uitextbox_t UI_TEXTBOX;
|
||||
|
||||
/**
|
||||
* Initializes the UI textbox.
|
||||
*/
|
||||
void uiTextboxInit();
|
||||
|
||||
/**
|
||||
* Updates the UI textbox.
|
||||
*/
|
||||
void uiTextboxUpdate();
|
||||
|
||||
/**
|
||||
* Sets the text of the UI textbox.
|
||||
*
|
||||
* @param text The text to set in the textbox.
|
||||
*/
|
||||
void uiTextboxSetText(const char_t *text);
|
||||
|
||||
/**
|
||||
* Shows the UI textbox.
|
||||
*/
|
||||
void uiTextboxShow();
|
||||
|
||||
/**
|
||||
* Hides the UI textbox.
|
||||
*/
|
||||
void uiTextboxHide();
|
@ -7,7 +7,4 @@
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
memory.c
|
||||
string.c
|
||||
random.c
|
||||
math.c
|
||||
)
|
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "math.h"
|
||||
|
||||
int8_t mathAbsI8(const int8_t val) {
|
||||
return (val > 0) ? val : -val;
|
||||
}
|
@ -1,17 +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"
|
||||
|
||||
/**
|
||||
* Returns the absolute (ignoring sign) value of an 8-bit integer.
|
||||
*
|
||||
* @param val The 8-bit integer value to get the absolute value of.
|
||||
* @return The absolute value of the input integer.
|
||||
*/
|
||||
int8_t mathAbsI8(const int8_t val);
|
@ -48,7 +48,7 @@ void memoryMove(void *dest, const void *src, const size_t size) {
|
||||
memmove(dest, src, size);
|
||||
}
|
||||
|
||||
ssize_t memoryCompare(
|
||||
int_t memoryCompare(
|
||||
const void *a,
|
||||
const void *b,
|
||||
const size_t size
|
||||
|
@ -83,7 +83,7 @@ void memoryMove(void *dest, const void *src, const size_t size);
|
||||
* @param size The size of the memory to compare.
|
||||
* @return 0 if the memory is equal, < 0 if a < b, > 0 if a > b.
|
||||
*/
|
||||
ssize_t memoryCompare(
|
||||
int_t memoryCompare(
|
||||
const void *a,
|
||||
const void *b,
|
||||
const size_t size
|
||||
|
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "random.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
void randomInit() {
|
||||
}
|
@ -1,18 +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"
|
||||
|
||||
/**
|
||||
* Initializes the random number generator with a random seed.
|
||||
*
|
||||
* This function should be called once at the start of the program to
|
||||
* initialize the random number generator with a random seed. It uses
|
||||
* the current time to generate a seed.
|
||||
*/
|
||||
void randomInit();
|
@ -1,127 +0,0 @@
|
||||
/**
|
||||
* 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"
|
||||
#include "util/memory.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");
|
||||
assertTrue(destSize > 0, "destSize must be greater than 0");
|
||||
assertStrLenMax(src, destSize, "src is too long");
|
||||
memoryCopy(dest, src, strlen(src) + 1);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int32_t stringFormat(
|
||||
char_t *dest,
|
||||
const size_t destSize,
|
||||
char_t *format,
|
||||
...
|
||||
) {
|
||||
assertNotNull(dest, "dest must not be NULL");
|
||||
assertNotNull(format, "format must not be NULL");
|
||||
assertTrue(destSize > 0, "destSize must be greater than 0");
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int32_t result = stringFormatVA(dest, destSize, format, args);
|
||||
va_end(args);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t stringFormatVA(
|
||||
char_t *dest,
|
||||
const size_t destSize,
|
||||
const char_t *format,
|
||||
va_list args
|
||||
) {
|
||||
assertNotNull(dest, "dest must not be NULL");
|
||||
assertNotNull(format, "format must not be NULL");
|
||||
assertTrue(destSize > 0, "destSize must be greater than 0");
|
||||
int32_t ret = vsnprintf(dest, destSize, format, args);
|
||||
assertTrue(ret >= 0, "Failed to format string.");
|
||||
assertTrue(ret < destSize, "Formatted string is too long.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool_t stringToI32(const char_t *str, int32_t *out) {
|
||||
assertNotNull(str, "str must not be NULL");
|
||||
assertNotNull(out, "out must not be NULL");
|
||||
|
||||
char_t *endptr;
|
||||
errno = 0;
|
||||
long int result = strtol(str, &endptr, 10);
|
||||
if (errno != 0 || *endptr != '\0') {
|
||||
return false;
|
||||
}
|
||||
*out = (int32_t)result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool_t stringToI64(const char_t *str, int64_t *out) {
|
||||
assertNotNull(str, "str must not be NULL");
|
||||
assertNotNull(out, "out must not be NULL");
|
||||
|
||||
char_t *endptr;
|
||||
errno = 0;
|
||||
long long int result = strtoll(str, &endptr, 10);
|
||||
if (errno != 0 || *endptr != '\0') {
|
||||
return false;
|
||||
}
|
||||
*out = (int64_t)result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool_t stringToU16(const char_t *str, uint16_t *out) {
|
||||
assertNotNull(str, "str must not be NULL");
|
||||
assertNotNull(out, "out must not be NULL");
|
||||
|
||||
char_t *endptr;
|
||||
errno = 0;
|
||||
unsigned long int result = strtoul(str, &endptr, 10);
|
||||
if (errno != 0 || *endptr != '\0' || result > UINT16_MAX) {
|
||||
return false;
|
||||
}
|
||||
*out = (uint16_t)result;
|
||||
return true;
|
||||
}
|
@ -1,109 +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"
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Formats a string.
|
||||
*
|
||||
* @param dest The destination string.
|
||||
* @param destSize The size of the destination string exc. null terminator.
|
||||
* @param format The format string.
|
||||
* @param ... The arguments to format.
|
||||
* @return The number of characters written.
|
||||
*/
|
||||
int32_t stringFormat(char_t *dest, const size_t destSize, char_t *format, ...);
|
||||
|
||||
/**
|
||||
* Formats a string using a va_list.
|
||||
*
|
||||
* @param dest The destination string.
|
||||
* @param destSize The size of the destination string exc. null terminator.
|
||||
* @param format The format string.
|
||||
* @param args The va_list of arguments.
|
||||
* @return The number of characters written.
|
||||
*/
|
||||
int32_t stringFormatVA(
|
||||
char_t *dest,
|
||||
const size_t destSize,
|
||||
const char_t *format,
|
||||
va_list args
|
||||
);
|
||||
|
||||
/**
|
||||
* Converts a string to an integer.
|
||||
*
|
||||
* @param str The string to convert.
|
||||
* @param out The output integer.
|
||||
* @return TRUE if the conversion was successful, FALSE otherwise.
|
||||
*/
|
||||
bool_t stringToI32(const char_t *str, int32_t *out);
|
||||
|
||||
/**
|
||||
* Converts a string to a signed 16-bit integer.
|
||||
*
|
||||
* @param str The string to convert.
|
||||
* @param out The output signed integer.
|
||||
* @return TRUE if the conversion was successful, FALSE otherwise.
|
||||
*/
|
||||
bool_t stringToI16(const char_t *str, int16_t *out);
|
||||
|
||||
/**
|
||||
* Converts a string to an unsigned 16-bit integer.
|
||||
*
|
||||
* @param str The string to convert.
|
||||
* @param out The output unsigned integer.
|
||||
* @return TRUE if the conversion was successful, FALSE otherwise.
|
||||
*/
|
||||
bool_t stringToU16(const char_t *str, uint16_t *out);
|
31
src/duskgb/CMakeLists.txt
Normal file
31
src/duskgb/CMakeLists.txt
Normal file
@ -0,0 +1,31 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Definitions
|
||||
target_compile_definitions(${DUSK_TARGET_NAME}
|
||||
PUBLIC
|
||||
ASSERTIONS_FAKED=1
|
||||
)
|
||||
|
||||
# Libs
|
||||
target_link_libraries(${DUSK_TARGET_NAME}
|
||||
PUBLIC
|
||||
)
|
||||
|
||||
# Includes
|
||||
target_include_directories(${DUSK_TARGET_NAME}
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(display)
|
||||
|
||||
add_gb_rom(${DUSK_TARGET_NAME} 0x10 2 4)
|
@ -1,10 +1,10 @@
|
||||
# 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
|
||||
event.c
|
||||
renderimpl.c
|
||||
)
|
23
src/duskgb/display/renderimpl.c
Normal file
23
src/duskgb/display/renderimpl.c
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "display/render.h"
|
||||
|
||||
uint8_t RENDER_STATUS = 0;
|
||||
|
||||
void renderInit(void) {
|
||||
SHOW_BKG;
|
||||
DISPLAY_ON;
|
||||
}
|
||||
|
||||
void renderVsync(void) {
|
||||
vsync();
|
||||
}
|
||||
|
||||
void renderDispose(void) {
|
||||
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "display/render.h"
|
||||
#include <raylib.h>
|
||||
#include "duskgb.h"
|
||||
|
||||
extern Font FONT;
|
||||
#define RENDER_BACKGROUND_X SCX_REG
|
||||
#define RENDER_BACKGROUND_Y SCY_REG
|
@ -7,7 +7,4 @@
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct {
|
||||
|
||||
} quest_t;
|
||||
#include <gb/gb.h>
|
@ -27,7 +27,6 @@ target_include_directories(${DUSK_TARGET_NAME}
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
input.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
|
@ -1,13 +1,10 @@
|
||||
# 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
|
||||
renderraylib.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(draw)
|
||||
renderimpl.c
|
||||
)
|
@ -1,11 +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
|
||||
drawentity.c
|
||||
drawui.c
|
||||
)
|
@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "drawentity.h"
|
||||
#include "rpg/world/map.h"
|
||||
|
||||
void drawEntities() {
|
||||
uint8_t x, y;
|
||||
entity_t *ent = MAP.entities;
|
||||
|
||||
do {
|
||||
if(ent->type == ENTITY_TYPE_NULL) {
|
||||
ent++;
|
||||
continue;
|
||||
}
|
||||
|
||||
x = ent->x * ENTITY_WIDTH + ent->subX;
|
||||
y = ent->y * ENTITY_HEIGHT + ent->subY;
|
||||
|
||||
switch(ent->dir) {
|
||||
case ENTITY_DIR_UP:
|
||||
DrawTriangle(
|
||||
(Vector2){ x, y + ENTITY_HEIGHT },
|
||||
(Vector2){ x + ENTITY_WIDTH, y + ENTITY_HEIGHT },
|
||||
(Vector2){ x + ENTITY_WIDTH / 2, y },
|
||||
RED
|
||||
);
|
||||
break;
|
||||
case ENTITY_DIR_DOWN:
|
||||
DrawTriangle(
|
||||
(Vector2){ x, y },
|
||||
(Vector2){ x + ENTITY_WIDTH / 2, y + ENTITY_HEIGHT },
|
||||
(Vector2){ x + ENTITY_WIDTH, y },
|
||||
RED
|
||||
);
|
||||
break;
|
||||
case ENTITY_DIR_LEFT:
|
||||
DrawTriangle(
|
||||
(Vector2){ x + ENTITY_WIDTH, y },
|
||||
(Vector2){ x, y + ENTITY_HEIGHT / 2 },
|
||||
(Vector2){ x + ENTITY_WIDTH, y + ENTITY_HEIGHT },
|
||||
RED
|
||||
);
|
||||
break;
|
||||
case ENTITY_DIR_RIGHT:
|
||||
DrawTriangle(
|
||||
(Vector2){ x, y },
|
||||
(Vector2){ x, y + ENTITY_HEIGHT },
|
||||
(Vector2){ x + ENTITY_WIDTH, y + ENTITY_HEIGHT / 2 },
|
||||
RED
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ent++;
|
||||
} while(ent->type != ENTITY_TYPE_NULL);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "display/renderraylib.h"
|
||||
|
||||
/**
|
||||
* Draws all entities on the map.
|
||||
*/
|
||||
void drawEntities();
|
@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "drawui.h"
|
||||
#include "ui/ui.h"
|
||||
#include "ui/uitextbox.h"
|
||||
|
||||
void drawUITextbox() {
|
||||
if(!UI_TEXTBOX.visible) return;
|
||||
|
||||
DrawRectangle(
|
||||
UI_TEXTBOX.x, UI_TEXTBOX.y,
|
||||
UI_TEXTBOX.width, UI_TEXTBOX.height,
|
||||
Fade(SKYBLUE, 0.5f)
|
||||
);
|
||||
|
||||
DrawTextEx(
|
||||
FONT,
|
||||
UI_TEXTBOX.text,
|
||||
(Vector2){ UI_TEXTBOX.x + 2, UI_TEXTBOX.y + 2 },
|
||||
FONT.baseSize, 0, BLACK
|
||||
);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "display/renderraylib.h"
|
||||
|
||||
/**
|
||||
* Draws the UI textbox.
|
||||
*/
|
||||
void drawUITextbox();
|
209
src/duskraylib/display/renderimpl.c
Normal file
209
src/duskraylib/display/renderimpl.c
Normal file
@ -0,0 +1,209 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "display/render.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
uint8_t RENDER_BACKGROUND_X = 0;
|
||||
uint8_t RENDER_BACKGROUND_Y = 0;
|
||||
uint8_t RENDER_STATUS = 0;
|
||||
|
||||
uint8_t RENDER_TILES[RENDER_TILE_COUNT] = { 0 };
|
||||
uint8_t RENDER_BACKGROUND_TILEMAP[RENDER_BACKGROUND_TILE_COUNT] = { 0 };
|
||||
|
||||
Color RENDER_PALETTE[RENDER_PALETTE_COLOR_COUNT] = {
|
||||
{ 102, 191, 47, 255 },
|
||||
{ 78, 146, 35, 255 },
|
||||
{ 48, 89, 22, 255 },
|
||||
{ 18, 33, 8, 255 }
|
||||
};
|
||||
bool_t RENDER_DISPLAY_ON = false;
|
||||
|
||||
RenderTexture2D RENDER_BACKBUFFER;
|
||||
RenderTexture2D RENDER_TILES_TEXTURE;
|
||||
|
||||
void renderInit(void) {
|
||||
InitWindow(RENDER_WIDTH_PIXELS * 4, RENDER_HEIGHT_PIXELS * 4, "Dusk");
|
||||
SetTargetFPS(60);
|
||||
SetWindowState(
|
||||
FLAG_WINDOW_RESIZABLE |
|
||||
FLAG_WINDOW_HIGHDPI |
|
||||
FLAG_VSYNC_HINT
|
||||
);
|
||||
|
||||
// Create back buffer for rendering.
|
||||
RENDER_BACKBUFFER = LoadRenderTexture(
|
||||
RENDER_WIDTH_PIXELS,
|
||||
RENDER_HEIGHT_PIXELS
|
||||
);
|
||||
|
||||
// Create texture to hold the tile data.
|
||||
RENDER_TILES_TEXTURE = LoadRenderTexture(
|
||||
RENDER_TILE_COUNT * RENDER_TILE_WIDTH,
|
||||
RENDER_TILE_HEIGHT
|
||||
);
|
||||
}
|
||||
|
||||
void renderVsync() {
|
||||
int32_t x, y, i;
|
||||
BeginDrawing();
|
||||
|
||||
if(RENDER_DISPLAY_ON) {
|
||||
// Update the texture with the new tile data
|
||||
BeginTextureMode(RENDER_TILES_TEXTURE);
|
||||
i = 0;
|
||||
for(i = 0; i < RENDER_TILE_COUNT; i++) {
|
||||
uint8_t *tile = RENDER_TILES + (i * RENDER_TILE_BYTES_PER_TILE);
|
||||
|
||||
// For each pixel in the tile...
|
||||
for(y = 0; y < RENDER_TILE_HEIGHT; y++) {
|
||||
uint8_t low = tile[y * RENDER_TILE_BYTES_PER_ROW];
|
||||
uint8_t high = tile[y * RENDER_TILE_BYTES_PER_ROW + 1];
|
||||
|
||||
for(x = 0; x < RENDER_TILE_WIDTH; x++) {
|
||||
uint8_t loBit = (low >> (7 - x)) & 1;
|
||||
uint8_t hiBit = (high >> (7 - x)) & 1;
|
||||
uint8_t paletteIndex = (hiBit << 1) | loBit;
|
||||
|
||||
// Draw the pixel to the texture
|
||||
DrawPixel(
|
||||
(i * RENDER_TILE_WIDTH) + x,
|
||||
y,
|
||||
RENDER_PALETTE[paletteIndex]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
EndTextureMode();
|
||||
|
||||
// Clear the back buffer
|
||||
BeginTextureMode(RENDER_BACKBUFFER);
|
||||
ClearBackground(RENDER_PALETTE[0]);
|
||||
|
||||
// Render background tiles
|
||||
i = 0;
|
||||
for(y = 0; y < RENDER_BACKGROUND_ROWS; y++) {
|
||||
for(x = 0; x < RENDER_BACKGROUND_COLUMNS; x++) {
|
||||
// Get the tile index from the tilemap
|
||||
uint8_t tileIndex = RENDER_BACKGROUND_TILEMAP[i++];
|
||||
|
||||
DrawTexturePro(
|
||||
RENDER_TILES_TEXTURE.texture,
|
||||
(Rectangle){
|
||||
.x = ((int32_t)tileIndex) * RENDER_TILE_WIDTH,
|
||||
.y = 0,
|
||||
.width = RENDER_TILE_WIDTH,
|
||||
.height = -RENDER_TILE_HEIGHT
|
||||
},
|
||||
(Rectangle){
|
||||
((int32_t)x * RENDER_TILE_WIDTH) - RENDER_BACKGROUND_X,
|
||||
((int32_t)y * RENDER_TILE_HEIGHT) - RENDER_BACKGROUND_Y,
|
||||
RENDER_TILE_WIDTH,
|
||||
RENDER_TILE_HEIGHT
|
||||
},
|
||||
(Vector2){ 0, 0 },
|
||||
0.0f,
|
||||
WHITE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Render the back buffer to the screen
|
||||
EndTextureMode();
|
||||
ClearBackground(WHITE);
|
||||
|
||||
// Keep aspect and center the render
|
||||
int32_t renderWidth, renderHeight, renderX, renderY;
|
||||
const int32_t width = GetScreenWidth();
|
||||
const int32_t height = GetScreenHeight();
|
||||
if (RENDER_WIDTH_PIXELS * height > RENDER_HEIGHT_PIXELS * width) {
|
||||
renderWidth = width;
|
||||
renderHeight = (RENDER_HEIGHT_PIXELS * width) / RENDER_WIDTH_PIXELS;
|
||||
renderX = 0;
|
||||
renderY = (height - renderHeight) / 2;
|
||||
} else {
|
||||
renderWidth = (RENDER_WIDTH_PIXELS * height) / RENDER_HEIGHT_PIXELS;
|
||||
renderHeight = height;
|
||||
renderX = (width - renderWidth) / 2;
|
||||
renderY = 0;
|
||||
}
|
||||
DrawTexturePro(
|
||||
RENDER_BACKBUFFER.texture,
|
||||
(Rectangle) { 0, 0, RENDER_WIDTH_PIXELS, -RENDER_HEIGHT_PIXELS },
|
||||
(Rectangle) { renderX, renderY, renderWidth, renderHeight },
|
||||
(Vector2) { 0, 0 },
|
||||
0.0f,
|
||||
WHITE
|
||||
);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
if(WindowShouldClose()) RENDER_STATUS |= RENDER_SHOULD_EXIT;
|
||||
}
|
||||
|
||||
void renderDispose() {
|
||||
UnloadRenderTexture(RENDER_TILES_TEXTURE);
|
||||
CloseWindow();
|
||||
}
|
||||
|
||||
void renderDisplayOn(void) {
|
||||
RENDER_DISPLAY_ON = true;
|
||||
}
|
||||
|
||||
void renderDisplayOff(void) {
|
||||
RENDER_DISPLAY_ON = false;
|
||||
}
|
||||
|
||||
void set_bkg_data(
|
||||
const uint8_t index,
|
||||
const uint8_t count,
|
||||
const uint8_t *tiles
|
||||
) {
|
||||
assertTrue(count > 0, "Count must be greater than zero");
|
||||
assertNotNull(tiles, "Tiles pointer must not be null");
|
||||
|
||||
// Copy data to fake vram
|
||||
memoryCopy(
|
||||
&RENDER_TILES[index * RENDER_TILE_BYTES_PER_TILE],
|
||||
tiles,
|
||||
count * RENDER_TILE_BYTES_PER_TILE
|
||||
);
|
||||
}
|
||||
|
||||
void set_bkg_tiles(
|
||||
const uint8_t xPos,
|
||||
const uint8_t yPos,
|
||||
const uint8_t width,
|
||||
const uint8_t height,
|
||||
const uint8_t *tiles
|
||||
) {
|
||||
uint8_t w = width, h = height, x = xPos, y = yPos;
|
||||
assertNotNull(tiles, "Tiles pointer must not be null");
|
||||
|
||||
// Clamp x and y to tilemap bounds
|
||||
if (x >= RENDER_BACKGROUND_COLUMNS) x = RENDER_BACKGROUND_COLUMNS - 1;
|
||||
if (y >= RENDER_BACKGROUND_ROWS) y = RENDER_BACKGROUND_ROWS - 1;
|
||||
|
||||
// Clamp width and height so we don't overflow past edges
|
||||
if (x + w > RENDER_BACKGROUND_COLUMNS) {
|
||||
w = RENDER_BACKGROUND_COLUMNS - x;
|
||||
}
|
||||
if (y + h > RENDER_BACKGROUND_ROWS) {
|
||||
h = RENDER_BACKGROUND_ROWS - y;
|
||||
}
|
||||
|
||||
if (w == 0 || h == 0) return;
|
||||
|
||||
for (uint8_t row = 0; row < h; row++) {
|
||||
memoryCopy(
|
||||
&RENDER_BACKGROUND_TILEMAP[(y + row) * RENDER_BACKGROUND_COLUMNS + x],
|
||||
&tiles[row * width],
|
||||
w
|
||||
);
|
||||
}
|
||||
}
|
56
src/duskraylib/display/renderimpl.h
Normal file
56
src/duskraylib/display/renderimpl.h
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "duskraylib.h"
|
||||
|
||||
#define RENDER_TILE_COUNT 384
|
||||
#define RENDER_TILE_WIDTH 8
|
||||
#define RENDER_TILE_BYTES_PER_ROW 2
|
||||
#define RENDER_TILE_HEIGHT 8
|
||||
#define RENDER_TILE_BYTES_PER_TILE (RENDER_TILE_BYTES_PER_ROW * RENDER_TILE_HEIGHT)
|
||||
#define RENDER_BACKGROUND_COLUMNS 32
|
||||
#define RENDER_BACKGROUND_ROWS 32
|
||||
#define RENDER_BACKGROUND_TILE_COUNT (RENDER_BACKGROUND_COLUMNS * RENDER_BACKGROUND_ROWS)
|
||||
|
||||
extern uint8_t RENDER_BACKGROUND_X;
|
||||
extern uint8_t RENDER_BACKGROUND_Y;
|
||||
extern uint8_t RENDER_TILES[RENDER_TILE_COUNT];
|
||||
|
||||
#define RENDER_PALETTE_COLOR_COUNT 4
|
||||
extern Color RENDER_PALETTE[RENDER_PALETTE_COLOR_COUNT];
|
||||
extern bool_t RENDER_DISPLAY_ON;
|
||||
|
||||
/**
|
||||
* Sets the background tile data.
|
||||
*
|
||||
* @param index The starting index of the tile data.
|
||||
* @param count The number of tiles to set.
|
||||
* @param tiles Pointer to the tile data array.
|
||||
*/
|
||||
void set_bkg_data(
|
||||
const uint8_t index,
|
||||
const uint8_t count,
|
||||
const uint8_t *tiles
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets the background tiles.
|
||||
*
|
||||
* @param x The x-coordinate of the top-left corner of the background.
|
||||
* @param y The y-coordinate of the top-left corner of the background.
|
||||
* @param width The width of the background in tiles.
|
||||
* @param height The height of the background in tiles.
|
||||
* @param tiles Pointer to the tile map data.
|
||||
*/
|
||||
void set_bkg_tiles(
|
||||
const uint8_t x,
|
||||
const uint8_t y,
|
||||
const uint8_t width,
|
||||
const uint8_t height,
|
||||
const uint8_t *tiles
|
||||
);
|
@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assert/assert.h"
|
||||
#include "display/render.h"
|
||||
#include <raylib.h>
|
||||
|
||||
#include "display/draw/drawentity.h"
|
||||
#include "display/draw/drawui.h"
|
||||
|
||||
const uint16_t RENDER_WIDTH = 480;
|
||||
const uint16_t RENDER_HEIGHT = 270;
|
||||
Font FONT;
|
||||
|
||||
void renderInit() {
|
||||
InitWindow(RENDER_WIDTH, RENDER_HEIGHT, "Dusk");
|
||||
SetTargetFPS(60);
|
||||
|
||||
FONT = LoadFontEx(
|
||||
"../assets/ark-pixel-font/12px/monospaced/ark-pixel-12px-monospaced-latin.otf",
|
||||
12, NULL, 0
|
||||
);
|
||||
}
|
||||
|
||||
bool_t renderUpdate() {
|
||||
uint8_t x, y;
|
||||
char_t buffer[64];
|
||||
|
||||
// End rendering?
|
||||
if(WindowShouldClose()) return false;
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
drawEntities();
|
||||
drawUITextbox();
|
||||
|
||||
EndDrawing();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void renderDispose() {
|
||||
CloseWindow();
|
||||
}
|
@ -6,4 +6,5 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "dusk.h"
|
||||
#include <raylib.h>
|
@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "input.h"
|
||||
#include "raylib.h"
|
||||
|
||||
typedef struct {
|
||||
int32_t key;
|
||||
uint8_t flag;
|
||||
} inputmap_t;
|
||||
|
||||
const inputmap_t INPUT_MAP[] = {
|
||||
{ KEY_W, INPUT_UP },
|
||||
{ KEY_S, INPUT_DOWN },
|
||||
{ KEY_A, INPUT_LEFT },
|
||||
{ KEY_D, INPUT_RIGHT },
|
||||
|
||||
{ KEY_SPACE, INPUT_ACTION },
|
||||
{ KEY_E, INPUT_ACTION },
|
||||
{ KEY_ENTER, INPUT_ACTION },
|
||||
|
||||
{ KEY_ESCAPE, INPUT_CANCEL },
|
||||
{ KEY_Q, INPUT_CANCEL },
|
||||
{ KEY_BACKSPACE, INPUT_CANCEL },
|
||||
|
||||
{ KEY_UP, INPUT_UP },
|
||||
{ KEY_DOWN, INPUT_DOWN },
|
||||
{ KEY_LEFT, INPUT_LEFT },
|
||||
{ KEY_RIGHT, INPUT_RIGHT },
|
||||
{ KEY_ENTER, INPUT_ACTION },
|
||||
{ KEY_BACKSPACE, INPUT_CANCEL },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
void inputInit() {
|
||||
|
||||
}
|
||||
|
||||
void inputUpdate() {
|
||||
uint8_t state = 0;
|
||||
inputmap_t *map = INPUT_MAP;
|
||||
|
||||
do {
|
||||
if(IsKeyDown(map->key)) {
|
||||
state |= map->flag;
|
||||
}
|
||||
map++;
|
||||
} while(map->key != 0);
|
||||
|
||||
INPUT.previous = INPUT.current;
|
||||
INPUT.current = state;
|
||||
}
|
||||
|
||||
void inputDispose() {
|
||||
|
||||
}
|
@ -5,5 +5,4 @@
|
||||
|
||||
# Tools
|
||||
add_subdirectory(assetstool)
|
||||
add_subdirectory(copytool)
|
||||
add_subdirectory(glsltool)
|
||||
add_subdirectory(copytool)
|
Reference in New Issue
Block a user