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 99)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if(NOT DEFINED DUSK_TARGET_SYSTEM)
|
||||||
|
set(DUSK_TARGET_SYSTEM "raylib")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Prep cache
|
# Prep cache
|
||||||
set(DUSK_CACHE_TARGET "dusk-target")
|
set(DUSK_CACHE_TARGET "dusk-target")
|
||||||
|
|
||||||
# Platform configs
|
|
||||||
|
|
||||||
# Build variables
|
# Build variables
|
||||||
set(DUSK_ROOT_DIR "${CMAKE_SOURCE_DIR}")
|
set(DUSK_ROOT_DIR "${CMAKE_SOURCE_DIR}")
|
||||||
set(DUSK_BUILD_DIR "${CMAKE_BINARY_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_BUILD_BINARY ${DUSK_BUILD_DIR}/Dusk CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
set(DUSK_ASSETS "" 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
|
# Create directories
|
||||||
file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR})
|
file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR})
|
||||||
file(MAKE_DIRECTORY ${DUSK_ASSETS_BUILD_DIR})
|
file(MAKE_DIRECTORY ${DUSK_ASSETS_BUILD_DIR})
|
||||||
@ -36,7 +43,7 @@ project(${DUSK_TARGET_NAME}
|
|||||||
LANGUAGES C
|
LANGUAGES C
|
||||||
)
|
)
|
||||||
|
|
||||||
# Executable
|
# Executable
|
||||||
add_executable(${DUSK_TARGET_NAME})
|
add_executable(${DUSK_TARGET_NAME})
|
||||||
|
|
||||||
# Add tools
|
# 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
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
add_subdirectory(dusk)
|
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
|
# Libs
|
||||||
target_link_libraries(${DUSK_TARGET_NAME}
|
target_link_libraries(${DUSK_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
m
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Includes
|
# Includes
|
||||||
@ -19,12 +18,9 @@ target_include_directories(${DUSK_TARGET_NAME}
|
|||||||
target_sources(${DUSK_TARGET_NAME}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
main.c
|
main.c
|
||||||
input.c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
add_subdirectory(assert)
|
add_subdirectory(assert)
|
||||||
add_subdirectory(display)
|
add_subdirectory(display)
|
||||||
add_subdirectory(rpg)
|
add_subdirectory(util)
|
||||||
add_subdirectory(util)
|
|
||||||
add_subdirectory(ui)
|
|
@ -7,118 +7,79 @@
|
|||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
|
||||||
void assertTrueImpl(
|
#ifndef ASSERTIONS_FAKED
|
||||||
const char *file,
|
void assertTrueImpl(
|
||||||
const int32_t line,
|
const char *file,
|
||||||
const bool x,
|
const int32_t line,
|
||||||
const char *message
|
const bool x,
|
||||||
) {
|
const char *message
|
||||||
if(x != true) {
|
) {
|
||||||
fprintf(
|
if(x != true) {
|
||||||
stderr,
|
fprintf(
|
||||||
"Assertion Failed in %s:%i\n\n%s\n",
|
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,
|
file,
|
||||||
line,
|
line,
|
||||||
|
pointer != NULL,
|
||||||
message
|
message
|
||||||
);
|
);
|
||||||
abort();
|
|
||||||
|
// Ensure we can touch it
|
||||||
|
volatile char temp;
|
||||||
|
temp = *((char*)pointer);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void assertFalseImpl(
|
void assertNullImpl(
|
||||||
const char *file,
|
const char *file,
|
||||||
const int32_t line,
|
const int32_t line,
|
||||||
bool x,
|
const void *pointer,
|
||||||
const char *message
|
const char *message
|
||||||
) {
|
) {
|
||||||
assertTrueImpl(file, line, !x, message);
|
assertTrueImpl(
|
||||||
}
|
file,
|
||||||
|
line,
|
||||||
|
pointer == NULL,
|
||||||
|
message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void assertUnreachableImpl(
|
void assertDeprecatedImpl(
|
||||||
const char *file,
|
const char *file,
|
||||||
const int32_t line,
|
const int32_t line,
|
||||||
const char *message
|
const char *message
|
||||||
) {
|
) {
|
||||||
assertTrueImpl(file, line, false, message);
|
assertUnreachableImpl(file, line, message);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
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
|
|
||||||
// );
|
|
||||||
// }
|
|
@ -8,124 +8,136 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
#include "dusk.h"
|
||||||
|
|
||||||
/**
|
#ifndef ASSERTIONS_FAKED
|
||||||
* Assert a given value to be true.
|
/**
|
||||||
*
|
* 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 file File that the assertion is being made from.
|
||||||
* @param x Value to assert as true.
|
* @param line Line that the assertion is being made from.
|
||||||
* @param message Message to throw against assertion failure.
|
* @param x Value to assert as true.
|
||||||
*/
|
* @param message Message to throw against assertion failure.
|
||||||
void assertTrueImpl(
|
*/
|
||||||
const char *file,
|
void assertTrueImpl(
|
||||||
const int32_t line,
|
const char *file,
|
||||||
const bool x,
|
const int32_t line,
|
||||||
const char *message
|
const bool_t x,
|
||||||
);
|
const char *message
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts a given statement to be false.
|
* Asserts a given statement to be false.
|
||||||
*
|
*
|
||||||
* @param file File that the assertion is being made from.
|
* @param file File that the assertion is being made from.
|
||||||
* @param line Line 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 x Value to assert as false.
|
||||||
* @param message Message to throw against assertion failure.
|
* @param message Message to throw against assertion failure.
|
||||||
*/
|
*/
|
||||||
void assertFalseImpl(
|
void assertFalseImpl(
|
||||||
const char *file,
|
const char *file,
|
||||||
const int32_t line,
|
const int32_t line,
|
||||||
const bool x,
|
const bool_t x,
|
||||||
const char *message
|
const char *message
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that a given line of code is unreachable. Essentially a forced
|
* Asserts that a given line of code is unreachable. Essentially a forced
|
||||||
* assertion failure, good for "edge cases"
|
* assertion failure, good for "edge cases"
|
||||||
*
|
*
|
||||||
* @param file File that the assertion is being made from.
|
* @param file File that the assertion is being made from.
|
||||||
* @param line Line 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.
|
* @param message Message to throw against assertion failure.
|
||||||
*/
|
*/
|
||||||
void assertUnreachableImpl(
|
void assertUnreachableImpl(
|
||||||
const char *file,
|
const char *file,
|
||||||
const int32_t line,
|
const int32_t line,
|
||||||
const char *message
|
const char *message
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assert a given pointer to not point to a null pointer.
|
* Assert a given pointer to not point to a null pointer.
|
||||||
*
|
*
|
||||||
* @param file File that the assertion is being made from.
|
* @param file File that the assertion is being made from.
|
||||||
* @param line Line 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 pointer Pointer to assert is not a null pointer.
|
||||||
* @param message Message to throw against assertion failure.
|
* @param message Message to throw against assertion failure.
|
||||||
*/
|
*/
|
||||||
void assertNotNullImpl(
|
void assertNotNullImpl(
|
||||||
const char *file,
|
const char *file,
|
||||||
const int32_t line,
|
const int32_t line,
|
||||||
const void *pointer,
|
const void *pointer,
|
||||||
const char *message
|
const char *message
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts a given pointer to be a nullptr.
|
* Asserts a given pointer to be a nullptr.
|
||||||
*
|
*
|
||||||
* @param file File that the assertion is being made from.
|
* @param file File that the assertion is being made from.
|
||||||
* @param line Line 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 pointer Pointer to assert is nullptr.
|
||||||
* @param message Message to throw against assertion failure.
|
* @param message Message to throw against assertion failure.
|
||||||
*/
|
*/
|
||||||
void assertNullImpl(
|
void assertNullImpl(
|
||||||
const char *file,
|
const char *file,
|
||||||
const int32_t line,
|
const int32_t line,
|
||||||
const void *pointer,
|
const void *pointer,
|
||||||
const char *message
|
const char *message
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts a function as being deprecated.
|
* Asserts a function as being deprecated.
|
||||||
*
|
*
|
||||||
* @param file File that the assertion is being made from.
|
* @param file File that the assertion is being made from.
|
||||||
* @param line Line 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.
|
* @param message Message to throw against assertion failure.
|
||||||
*/
|
*/
|
||||||
void assertDeprecatedImpl(
|
void assertDeprecatedImpl(
|
||||||
const char *file,
|
const char *file,
|
||||||
const int32_t line,
|
const int32_t line,
|
||||||
const char *message
|
const char *message
|
||||||
);
|
);
|
||||||
|
|
||||||
void assertMemoryRangeMatchesImpl(
|
void assertMemoryRangeMatchesImpl(
|
||||||
const char *file,
|
const char *file,
|
||||||
const int32_t line,
|
const int32_t line,
|
||||||
const void *start,
|
const void *start,
|
||||||
const void *end,
|
const void *end,
|
||||||
const size_t size,
|
const size_t size,
|
||||||
const char *message
|
const char *message
|
||||||
);
|
);
|
||||||
|
|
||||||
#define assertTrue(x, message) \
|
#define assertTrue(x, message) \
|
||||||
assertTrueImpl(__FILE__, __LINE__, x, message)
|
assertTrueImpl(__FILE__, __LINE__, x, message)
|
||||||
|
|
||||||
#define assertFalse(x, message) \
|
#define assertFalse(x, message) \
|
||||||
assertFalseImpl(__FILE__, __LINE__, x, message)
|
assertFalseImpl(__FILE__, __LINE__, x, message)
|
||||||
|
|
||||||
#define assertUnreachable(message) \
|
#define assertUnreachable(message) \
|
||||||
assertUnreachableImpl(__FILE__, __LINE__, message)
|
assertUnreachableImpl(__FILE__, __LINE__, message)
|
||||||
|
|
||||||
#define assertNotNull(pointer, message) \
|
#define assertNotNull(pointer, message) \
|
||||||
assertNotNullImpl(__FILE__, __LINE__, pointer, message)
|
assertNotNullImpl(__FILE__, __LINE__, pointer, message)
|
||||||
|
|
||||||
#define assertNull(pointer, message) \
|
#define assertNull(pointer, message) \
|
||||||
assertNullImpl(__FILE__, __LINE__, pointer, message)
|
assertNullImpl(__FILE__, __LINE__, pointer, message)
|
||||||
|
|
||||||
#define assertDeprecated(message) \
|
#define assertDeprecated(message) \
|
||||||
assertDeprecatedImpl(__FILE__, __LINE__, message)
|
assertDeprecatedImpl(__FILE__, __LINE__, message)
|
||||||
|
|
||||||
#define assertStrLenMax(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) \
|
||||||
assertTrue(strlen(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
|
# 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
|
||||||
|
render.c
|
||||||
)
|
)
|
@ -5,4 +5,4 @@
|
|||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "quest.h"
|
#include "render.h"
|
@ -6,22 +6,37 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
#include "display/renderimpl.h"
|
||||||
|
|
||||||
extern const uint16_t RENDER_WIDTH;
|
#define RENDER_WIDTH_PIXELS 160
|
||||||
extern const uint16_t RENDER_HEIGHT;
|
#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.
|
* This software is released under the MIT License.
|
||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
@ -7,20 +7,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdbool.h>
|
||||||
#include <ctype.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
typedef bool bool_t;
|
typedef bool bool_t;
|
||||||
typedef char char_t;
|
typedef int int_t;
|
||||||
|
|
||||||
#define DUSK_NAME "Dusk"
|
|
||||||
#define DUSK_VERSION "1.0.0"
|
|
@ -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 "display/render.h"
|
||||||
|
|
||||||
#include "ui/ui.h"
|
uint8_t backgroundtiles[] = {
|
||||||
#include "rpg/entity/entity.h"
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
#include "rpg/world/maps/testmap.h"
|
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) {
|
#define backgroundmapWidth 40
|
||||||
renderInit();
|
#define backgroundmapHeight 18
|
||||||
inputInit();
|
#define backgroundmapBank 0
|
||||||
randomInit();
|
|
||||||
|
|
||||||
uiInit();
|
uint8_t backgroundmap[] = {
|
||||||
mapSet(TEST_MAP);
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,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) {
|
void pdelay(uint8_t numVbls) {
|
||||||
inputUpdate();
|
uint8_t i;
|
||||||
uiUpdate();
|
for (i = 0; i < numVbls; i++) {
|
||||||
mapUpdate();
|
renderVsync();
|
||||||
if(!renderUpdate()) break;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
memory.c
|
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);
|
memmove(dest, src, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t memoryCompare(
|
int_t memoryCompare(
|
||||||
const void *a,
|
const void *a,
|
||||||
const void *b,
|
const void *b,
|
||||||
const size_t size
|
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.
|
* @param size The size of the memory to compare.
|
||||||
* @return 0 if the memory is equal, < 0 if a < b, > 0 if a > b.
|
* @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 *a,
|
||||||
const void *b,
|
const void *b,
|
||||||
const size_t size
|
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
|
# 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
|
||||||
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
|
#pragma once
|
||||||
#include "display/render.h"
|
#include "duskgb.h"
|
||||||
#include <raylib.h>
|
|
||||||
|
|
||||||
extern Font FONT;
|
#define RENDER_BACKGROUND_X SCX_REG
|
||||||
|
#define RENDER_BACKGROUND_Y SCY_REG
|
@ -7,7 +7,4 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
#include "dusk.h"
|
||||||
|
#include <gb/gb.h>
|
||||||
typedef struct {
|
|
||||||
|
|
||||||
} quest_t;
|
|
@ -27,7 +27,6 @@ target_include_directories(${DUSK_TARGET_NAME}
|
|||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
input.c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
# 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
|
||||||
|
|
||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
renderraylib.c
|
renderimpl.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
|
||||||
add_subdirectory(draw)
|
|
@ -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
|
#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
|
# Tools
|
||||||
add_subdirectory(assetstool)
|
add_subdirectory(assetstool)
|
||||||
add_subdirectory(copytool)
|
add_subdirectory(copytool)
|
||||||
add_subdirectory(glsltool)
|
|
Reference in New Issue
Block a user