we ball I guess
This commit is contained in:
@@ -0,0 +1,417 @@
|
|||||||
|
# Dusk — Claude Code rules
|
||||||
|
|
||||||
|
## File headers
|
||||||
|
Every C, H, and JS file starts with:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
JS files use `//` comment style instead.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## C conventions
|
||||||
|
|
||||||
|
### Types
|
||||||
|
Always use the project-defined aliases instead of bare C primitives:
|
||||||
|
|
||||||
|
| Use | Not |
|
||||||
|
|-----------|--------------|
|
||||||
|
| `bool_t` | `bool` |
|
||||||
|
| `int_t` | `int` |
|
||||||
|
| `float_t` | `float` |
|
||||||
|
| `char_t` | `char` |
|
||||||
|
|
||||||
|
Use `uint8_t`, `uint16_t`, `int32_t`, etc. for fixed-width integers.
|
||||||
|
All struct and enum types end in `_t` (`animation_t`, `errorret_t`, …).
|
||||||
|
|
||||||
|
### Naming
|
||||||
|
- **Functions** — snake_case, prefixed with their module:
|
||||||
|
`assetLock()`, `entityPositionInit()`, `moduleAssetBatchCtor()`
|
||||||
|
- **Struct fields** — camelCase: `keyframeCount`, `localPosition`
|
||||||
|
- **Macros / constants** — UPPER_SNAKE_CASE:
|
||||||
|
`ENTITY_ID_INVALID`, `ERROR_OK`, `COMPONENT_TYPE_COUNT`
|
||||||
|
- **Files** — snake_case matching the primary type: `entityposition.c`,
|
||||||
|
`moduleassetbatch.c`
|
||||||
|
|
||||||
|
### Header files (`.h`)
|
||||||
|
- Use `#pragma once` — no include guards.
|
||||||
|
- Declare every public function, `#define`, and `extern` global.
|
||||||
|
- Write a JSDoc block (`/** … */`) above every declaration explaining
|
||||||
|
purpose, `@param`s, and `@returns`.
|
||||||
|
- Only include headers that the `.h` file itself strictly requires for
|
||||||
|
the types it exposes. Move everything else to the `.c` file.
|
||||||
|
Do not use forward declarations as a workaround — use the real
|
||||||
|
include in the `.c` file instead.
|
||||||
|
|
||||||
|
### Implementation files (`.c`)
|
||||||
|
- Contain function bodies only; no declarations.
|
||||||
|
- Pull in whatever additional includes the implementation needs.
|
||||||
|
|
||||||
|
### Formatting
|
||||||
|
- Hard-wrap all lines at **80 characters**.
|
||||||
|
|
||||||
|
### Error handling
|
||||||
|
Return `errorret_t` from fallible functions. Use these macros:
|
||||||
|
|
||||||
|
```c
|
||||||
|
errorOk(); // return success
|
||||||
|
errorThrow("msg %d", val); // return failure with message
|
||||||
|
errorChain(someCall()); // propagate failure, continue on success
|
||||||
|
errorIsOk(ret) / errorIsNotOk(ret) // test a result
|
||||||
|
errorCatch(ret); // handle + free an error
|
||||||
|
```
|
||||||
|
|
||||||
|
Never return raw error codes or use `errno` for in-engine errors.
|
||||||
|
|
||||||
|
### Memory
|
||||||
|
Use the project allocator — never raw `malloc`/`free`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
memoryAllocate(size) // allocate
|
||||||
|
memoryFree(ptr) // free
|
||||||
|
memoryZero(dest, size) // zero a block
|
||||||
|
memoryCopy(dest, src, size) // copy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Asserts
|
||||||
|
Prefer specific assert macros over bare `assert()`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
assertNotNull(ptr, "msg");
|
||||||
|
assertTrue(cond, "msg");
|
||||||
|
assertFalse(cond, "msg");
|
||||||
|
assertUnreachable("msg");
|
||||||
|
assertIsMainThread("msg");
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Build system
|
||||||
|
Each subdirectory has its own `CMakeLists.txt` that adds sources with:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
myfile.c
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Never add source files to the root `CMakeLists.txt` directly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Platform support
|
||||||
|
|
||||||
|
### Targets
|
||||||
|
Set `DUSK_TARGET_SYSTEM` at CMake configure time to select a platform:
|
||||||
|
|
||||||
|
| `DUSK_TARGET_SYSTEM` | Macro defined | Platform |
|
||||||
|
|----------------------|-------------------|------------------|
|
||||||
|
| `linux` | `DUSK_LINUX` | Linux desktop |
|
||||||
|
| `knulli` | `DUSK_KNULLI` | Knulli (handheld)|
|
||||||
|
| `psp` | `DUSK_PSP` | Sony PSP |
|
||||||
|
| `vita` | `DUSK_VITA` | PlayStation Vita |
|
||||||
|
| `gamecube` | `DUSK_GAMECUBE` | Nintendo GameCube|
|
||||||
|
| `wii` | `DUSK_WII` | Nintendo Wii |
|
||||||
|
|
||||||
|
### Layer structure
|
||||||
|
```
|
||||||
|
src/dusk/ core, platform-agnostic game logic
|
||||||
|
src/duskgl/ OpenGL abstraction (Linux, Knulli, PSP, Vita)
|
||||||
|
src/dusksdl2/ SDL2 window + input (Linux, Knulli, PSP, Vita)
|
||||||
|
src/dusklinux/ Linux + Knulli platform impl
|
||||||
|
src/duskpsp/ PSP platform impl
|
||||||
|
src/duskvita/ Vita platform impl
|
||||||
|
src/duskdolphin/ GameCube / Wii platform impl (no SDL2/OpenGL)
|
||||||
|
```
|
||||||
|
|
||||||
|
Dolphin is the only target that bypasses SDL2 and OpenGL entirely —
|
||||||
|
it uses native GameCube/Wii rendering and input APIs.
|
||||||
|
|
||||||
|
### Platform guards
|
||||||
|
Use the compile-time macros for platform-specific code:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#ifdef DUSK_PSP
|
||||||
|
// PSP-only path
|
||||||
|
#elif defined(DUSK_GAMECUBE) || defined(DUSK_WII)
|
||||||
|
// GameCube / Wii path
|
||||||
|
#else
|
||||||
|
// Generic / Linux fallback
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
Additional capability macros set per-target:
|
||||||
|
`DUSK_SDL2`, `DUSK_OPENGL`, `DUSK_OPENGL_ES`, `DUSK_OPENGL_LEGACY`,
|
||||||
|
`DUSK_INPUT_GAMEPAD`, `DUSK_INPUT_KEYBOARD`, `DUSK_INPUT_POINTER`,
|
||||||
|
`DUSK_PLATFORM_ENDIAN_BIG` / `DUSK_PLATFORM_ENDIAN_LITTLE`.
|
||||||
|
|
||||||
|
### Abstraction pattern
|
||||||
|
Platform-specific implementations are wired in via `#define` macros in
|
||||||
|
each platform's `displayplatform.h` / `inputplatform.h` etc., which
|
||||||
|
the core calls through. Functions that a platform does not support are
|
||||||
|
simply left undefined — the core guards calls with `#ifdef`.
|
||||||
|
|
||||||
|
### Adding platform-specific code
|
||||||
|
- Put it under `src/dusk<platform>/` in the matching subsystem folder.
|
||||||
|
- Gate any core call-site with the appropriate `#ifdef DUSK_<PLATFORM>`
|
||||||
|
or capability macro.
|
||||||
|
- Keep the `src/dusk/` core free of platform ifdefs — delegate through
|
||||||
|
the platform header macros instead.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding a new asset loader type
|
||||||
|
1. Add an enum value to `assetloadertype_t` (before `_COUNT`) in
|
||||||
|
`src/dusk/asset/loader/assetloader.h`.
|
||||||
|
2. Add fields to the input/loading/output unions in `assetloader.h`.
|
||||||
|
3. Implement `assetXxxLoaderSync`, `assetXxxLoaderAsync`, and
|
||||||
|
`assetXxxDispose` in a new `src/dusk/asset/loader/xxx/` directory.
|
||||||
|
4. Register the three callbacks in `ASSET_LOADER_CALLBACKS[]` in
|
||||||
|
`src/dusk/asset/loader/assetloader.c`.
|
||||||
|
5. If user-facing, create a JS module (see below) and a `.d.ts` file.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding a new entity component
|
||||||
|
1. Create `src/dusk/entity/component/<category>/entityMyComp.h/.c` with
|
||||||
|
struct `entityMyComp_t`, `entityMyCompInit()`, and optionally
|
||||||
|
`entityMyCompDispose()`.
|
||||||
|
2. Add the include to `src/dusk/entity/componentlist.h` header block.
|
||||||
|
3. Add a row to `src/dusk/entity/componentlist.h`:
|
||||||
|
```c
|
||||||
|
X(MYCOMP, entityMyComp_t, myComp, entityMyCompInit, NULL, NULL)
|
||||||
|
```
|
||||||
|
This auto-generates the enum, union field, and definition entry.
|
||||||
|
4. If JS-facing, create the script module and `.d.ts` (see below).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding a new script (JS) module
|
||||||
|
1. Create `src/dusk/script/module/<category>/moduleMyMod.h/.c`.
|
||||||
|
- Declare `extern scriptproto_t MODULE_MYMOD_PROTO;` in the header.
|
||||||
|
- Use `moduleBaseFunction(name)` to define JS-callable functions.
|
||||||
|
- Register props/funcs in `moduleMyModInit()` with
|
||||||
|
`scriptProtoDefineProp` / `scriptProtoDefineFunc` /
|
||||||
|
`scriptProtoDefineStaticFunc`.
|
||||||
|
2. `#include` the header in
|
||||||
|
`src/dusk/script/module/modulelist.c` and call
|
||||||
|
`moduleMyModInit()` in `moduleListInit()` (and `Dispose` in
|
||||||
|
`moduleListDispose()`).
|
||||||
|
3. For component modules also register in
|
||||||
|
`src/dusk/script/module/entity/component/modulecomponentlist.c`
|
||||||
|
so `entity.add()` returns the typed wrapper.
|
||||||
|
4. Create `types/<category>/mymod.d.ts` and add a
|
||||||
|
`/// <reference path="..." />` line to `types/index.d.ts`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Script module type declarations
|
||||||
|
Whenever a `src/dusk/script/module/**/*.c` file is created or modified,
|
||||||
|
check whether the corresponding `types/**/*.d.ts` needs updating and
|
||||||
|
apply any changes before finishing the task.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## JavaScript (asset scripts)
|
||||||
|
- Use `var` for module-level state; `const` for values that never
|
||||||
|
change.
|
||||||
|
- Always use semicolons.
|
||||||
|
- Scene objects are plain objects (`var scene = {}`) with assigned
|
||||||
|
methods.
|
||||||
|
- Export via `module.exports = scene`.
|
||||||
|
- Async scene init should use `async function` and `await`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Coding style
|
||||||
|
|
||||||
|
### Indentation
|
||||||
|
2 spaces. No tabs.
|
||||||
|
|
||||||
|
### Keyword and operator spacing
|
||||||
|
No space between a keyword or function name and its opening parenthesis:
|
||||||
|
|
||||||
|
```c
|
||||||
|
if(!ptr) return;
|
||||||
|
for(uint8_t i = 0; i < count; i++) {
|
||||||
|
while(entry->state != DONE) {
|
||||||
|
switch(type) {
|
||||||
|
sizeof(assetbatch_t)
|
||||||
|
memoryZero(ptr, size)
|
||||||
|
```
|
||||||
|
|
||||||
|
Spaces around all binary operators and after every comma:
|
||||||
|
|
||||||
|
```c
|
||||||
|
pos->flags |= ENTITY_POSITION_FLAG_WORLD_DIRTY;
|
||||||
|
(size_t)end - (size_t)start
|
||||||
|
foo(a, b, c)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Braces
|
||||||
|
Opening brace on the **same line** as the statement (K&R style) for all
|
||||||
|
constructs — functions, `if`, `else`, `for`, `while`, `switch`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
void assetEntryLock(assetentry_t *entry) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dirty) {
|
||||||
|
...
|
||||||
|
} else {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Guard returns
|
||||||
|
Short guards go on one line with no braces:
|
||||||
|
|
||||||
|
```c
|
||||||
|
if(!ptr) return;
|
||||||
|
if(!b || !b->batch) return jerry_undefined();
|
||||||
|
if(!(flags & DIRTY)) return;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Blank lines
|
||||||
|
- One blank line between functions; no blank line at the start or end of
|
||||||
|
a function body.
|
||||||
|
- One blank line between logical blocks inside a function body.
|
||||||
|
- No trailing blank lines at the end of a file.
|
||||||
|
|
||||||
|
### Pointer placement
|
||||||
|
`*` is attached to the variable name, not the type:
|
||||||
|
|
||||||
|
```c
|
||||||
|
assetentry_t *entry
|
||||||
|
const char_t *name
|
||||||
|
void *ptr
|
||||||
|
uint8_t *d = (uint8_t *)dest;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Casts
|
||||||
|
Space between cast and operand:
|
||||||
|
|
||||||
|
```c
|
||||||
|
(assetbatch_t *)user
|
||||||
|
(uint8_t *)dest
|
||||||
|
(textureformat_t)v
|
||||||
|
```
|
||||||
|
|
||||||
|
### Return
|
||||||
|
No parentheses around the return value:
|
||||||
|
|
||||||
|
```c
|
||||||
|
return ptr;
|
||||||
|
return MEMORY_POINTERS_IN_USE;
|
||||||
|
```
|
||||||
|
|
||||||
|
### switch / case
|
||||||
|
`case` indented 2 spaces from `switch`; body indented 2 more from `case`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
switch(type) {
|
||||||
|
case ASSET_LOADER_TYPE_TEXTURE:
|
||||||
|
descs[i].input.texture = (textureformat_t)v;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multi-line function signatures
|
||||||
|
When parameters don't fit on one line, put each on its own line indented
|
||||||
|
2 spaces; the closing `) {` (definition) or `);` (declaration) goes on
|
||||||
|
its own line at column 0:
|
||||||
|
|
||||||
|
```c
|
||||||
|
void assetEntryInit(
|
||||||
|
assetentry_t *entry,
|
||||||
|
const char_t *name,
|
||||||
|
const assetloadertype_t type,
|
||||||
|
assetloaderinput_t *input
|
||||||
|
) {
|
||||||
|
|
||||||
|
errorret_t memoryCompare(
|
||||||
|
const void *a,
|
||||||
|
const void *b,
|
||||||
|
const size_t size
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Structs and enums
|
||||||
|
Anonymous inner struct or enum with a `typedef`, `_t` suffix, closing
|
||||||
|
brace and name on the same line:
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
errorcode_t code;
|
||||||
|
char_t *message;
|
||||||
|
} errorstate_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ASSET_LOADER_TYPE_NULL,
|
||||||
|
ASSET_LOADER_TYPE_COUNT
|
||||||
|
} assetloadertype_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Designated initialisers
|
||||||
|
Spaces inside braces; `.field = value`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
jsassetentry_t e = { .entry = entry };
|
||||||
|
assetbatchloadedpend_t init = { .batch = batch };
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ternary operator
|
||||||
|
Spaces around `?` and `:`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
const float val = psx > 0.0f ? pt[0][0] / psx : 0.0f;
|
||||||
|
```
|
||||||
|
|
||||||
|
### const placement
|
||||||
|
`const` before the type, `*` attached to the variable:
|
||||||
|
|
||||||
|
```c
|
||||||
|
const char_t *name
|
||||||
|
const void *src
|
||||||
|
const size_t size
|
||||||
|
```
|
||||||
|
|
||||||
|
### Comments in `.c` files
|
||||||
|
- Block comments that describe a section use the divider style:
|
||||||
|
```c
|
||||||
|
/* ---- Public API ---- */
|
||||||
|
```
|
||||||
|
- Multi-line explanatory comments inside function bodies use `//` lines:
|
||||||
|
```c
|
||||||
|
// Script modules are freed; orphaned JS wrapper objects now get GC'd
|
||||||
|
// so their finalizers fire before assetDispose() checks ref counts.
|
||||||
|
jerry_heap_gc(JERRY_GC_PRESSURE_HIGH);
|
||||||
|
```
|
||||||
|
- Do not use `/* */` for inline or inline-block comments inside `.c`
|
||||||
|
function bodies.
|
||||||
|
|
||||||
|
### Comments in `.h` files
|
||||||
|
Every public declaration gets a Javadoc block (`/** … */`) with
|
||||||
|
`@param` and `@returns` where relevant. Keep it on the lines immediately
|
||||||
|
above the declaration with no blank line in between.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
- Tests live in `test/` mirroring `src/dusk/` structure.
|
||||||
|
- Use cmocka; include `dusktest.h`.
|
||||||
|
- Test functions: `static void test_something(void **state)`.
|
||||||
|
- After each test, assert `memoryGetAllocatedCount() == 0` to catch
|
||||||
|
leaks.
|
||||||
|
- Build with `-DDUSK_BUILD_TESTS=ON`.
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (c) 2026 Dominic Masters
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
const PLAYER_SPEED = 5.0;
|
||||||
|
|
||||||
|
var player = {};
|
||||||
|
|
||||||
|
var _entity, _position, _physics;
|
||||||
|
|
||||||
|
player.create = function(texEntry) {
|
||||||
|
_entity = Entity.create();
|
||||||
|
_position = _entity.add(Component.POSITION);
|
||||||
|
_physics = _entity.add(Component.PHYSICS);
|
||||||
|
|
||||||
|
_physics.bodyType = Physics.DYNAMIC;
|
||||||
|
_physics.shape = Physics.SHAPE_CUBE;
|
||||||
|
_physics.gravityScale = 1.0;
|
||||||
|
|
||||||
|
var r = _entity.add(Component.RENDERABLE);
|
||||||
|
r.texture = texEntry.texture;
|
||||||
|
r.type = Renderable.SPRITEBATCH;
|
||||||
|
r.color = new Color(220, 80, 80);
|
||||||
|
// upright quad: (-0.5,0,0) → (0.5,1,0) in XY plane
|
||||||
|
r.sprites = [[-0.5, 0, 0, 0.5, 1, 0, 0, 0, 1, 1]];
|
||||||
|
|
||||||
|
_position.localPosition = new Vec3(0, 1, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
player.getPosition = function() {
|
||||||
|
return _position;
|
||||||
|
};
|
||||||
|
|
||||||
|
player.update = function() {
|
||||||
|
if(!_physics) return;
|
||||||
|
var vx = Input.axis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT) * PLAYER_SPEED;
|
||||||
|
var vz = Input.axis(INPUT_ACTION_DOWN, INPUT_ACTION_UP) * PLAYER_SPEED;
|
||||||
|
// Preserve vertical velocity so gravity and landing work correctly.
|
||||||
|
var vy = _physics.velocity.y;
|
||||||
|
_physics.velocity = new Vec3(vx, vy, vz);
|
||||||
|
};
|
||||||
|
|
||||||
|
player.dispose = function() {
|
||||||
|
Entity.dispose(_entity);
|
||||||
|
_entity = null;
|
||||||
|
_position = null;
|
||||||
|
_physics = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = player;
|
||||||
+50
-25
@@ -1,47 +1,72 @@
|
|||||||
var scene = {};
|
// Copyright (c) 2026 Dominic Masters
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
var scene = {};
|
||||||
|
var player = require('player.js');
|
||||||
|
|
||||||
var assets = AssetBatch([
|
var assets = AssetBatch([
|
||||||
{ path: 'test.png', type: Asset.TYPE_TEXTURE, format: Texture.FORMAT_RGBA }
|
{ path: 'test.png', type: Asset.TYPE_TEXTURE, format: Texture.FORMAT_RGBA }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var cam;
|
// Pokemon DS-style camera: ~34 degrees elevation (atan(6/9)).
|
||||||
var camPos;
|
// CAM_HEIGHT / CAM_DIST ratio controls the tilt — keep it under 0.7 for
|
||||||
var testEntity;
|
// the characteristically shallow DS angle.
|
||||||
var testPos;
|
const CAM_HEIGHT = 6;
|
||||||
var testRenderable;
|
const CAM_DIST = 9;
|
||||||
var texEntry;
|
|
||||||
|
var cam, camPos;
|
||||||
|
var floorEntity;
|
||||||
|
|
||||||
|
function updateCamera() {
|
||||||
|
var pp = player.getPosition().worldPosition;
|
||||||
|
// Position is offset above and behind the player; lookAt the exact player
|
||||||
|
// world position so the player projects to the center pixel every frame.
|
||||||
|
camPos.localPosition = new Vec3(pp.x, pp.y + CAM_HEIGHT, pp.z + CAM_DIST);
|
||||||
|
camPos.lookAt(new Vec3(pp.x, pp.y, pp.z));
|
||||||
|
}
|
||||||
|
|
||||||
scene.init = async function() {
|
scene.init = async function() {
|
||||||
assets.lock();
|
assets.lock();
|
||||||
await assets.loaded();
|
await assets.loaded();
|
||||||
|
|
||||||
Console.print('Scene Init');
|
var texEntry = assets.entry(0);
|
||||||
texEntry = assets.entry(0);
|
|
||||||
|
|
||||||
// Camera at (3, 3, 3) looking at origin
|
// Camera
|
||||||
cam = Entity.create();
|
cam = Entity.create();
|
||||||
camPos = cam.add(Component.POSITION);
|
camPos = cam.add(Component.POSITION);
|
||||||
cam.add(Component.CAMERA);
|
cam.add(Component.CAMERA);
|
||||||
camPos.localPosition = new Vec3(3, 3, 3);
|
|
||||||
camPos.lookAt(new Vec3(0, 0, 0));
|
|
||||||
|
|
||||||
// Test entity with textured quad at origin
|
// Floor — infinite static plane at Y=0. Rendered as a large flat blue
|
||||||
testEntity = Entity.create();
|
// slab using the default SHADER_MATERIAL (no texture needed).
|
||||||
testPos = testEntity.add(Component.POSITION);
|
floorEntity = Entity.create();
|
||||||
testRenderable = testEntity.add(Component.RENDERABLE);
|
var floorPos = floorEntity.add(Component.POSITION);
|
||||||
|
var floorPhysics = floorEntity.add(Component.PHYSICS);
|
||||||
|
floorPhysics.bodyType = Physics.STATIC;
|
||||||
|
floorPhysics.shape = Physics.SHAPE_PLANE;
|
||||||
|
|
||||||
testRenderable.texture = texEntry.texture;
|
var floorR = floorEntity.add(Component.RENDERABLE);
|
||||||
testRenderable.type = Renderable.SPRITEBATCH;
|
floorR.color = Color.BLUE;
|
||||||
testRenderable.sprites = [
|
floorPos.localScale = new Vec3(16, 0.2, 16);
|
||||||
[0, 0, 1, 1, 0, 1, 1, 0]
|
floorPos.localPosition = new Vec3(0, -0.1, 0);
|
||||||
];
|
|
||||||
// testPos.localPosition = new Vec3(0, 0, 0);
|
// Player — spawns 1 unit above the floor so physics drops it cleanly.
|
||||||
}
|
player.create(texEntry);
|
||||||
|
|
||||||
|
// Initialise camera at the correct angle from the player's spawn position.
|
||||||
|
updateCamera();
|
||||||
|
};
|
||||||
|
|
||||||
|
scene.update = function() {
|
||||||
|
player.update();
|
||||||
|
updateCamera();
|
||||||
|
};
|
||||||
|
|
||||||
scene.dispose = function() {
|
scene.dispose = function() {
|
||||||
Console.print('Scene Dispose');
|
player.dispose();
|
||||||
|
Entity.dispose(floorEntity);
|
||||||
Entity.dispose(cam);
|
Entity.dispose(cam);
|
||||||
Entity.dispose(testEntity);
|
|
||||||
assets.unlock();
|
assets.unlock();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ console_t CONSOLE;
|
|||||||
|
|
||||||
void consoleInit(void) {
|
void consoleInit(void) {
|
||||||
memoryZero(&CONSOLE, sizeof(console_t));
|
memoryZero(&CONSOLE, sizeof(console_t));
|
||||||
|
CONSOLE.visible = true;
|
||||||
|
|
||||||
#ifdef DUSK_CONSOLE_POSIX
|
#ifdef DUSK_CONSOLE_POSIX
|
||||||
threadMutexInit(&CONSOLE.printMutex);
|
threadMutexInit(&CONSOLE.printMutex);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
|
add_subdirectory(animation)
|
||||||
add_subdirectory(asset)
|
add_subdirectory(asset)
|
||||||
add_subdirectory(console)
|
add_subdirectory(console)
|
||||||
add_subdirectory(display)
|
add_subdirectory(display)
|
||||||
@@ -17,7 +18,13 @@ add_subdirectory(engine)
|
|||||||
add_subdirectory(entity)
|
add_subdirectory(entity)
|
||||||
add_subdirectory(event)
|
add_subdirectory(event)
|
||||||
add_subdirectory(input)
|
add_subdirectory(input)
|
||||||
|
add_subdirectory(item)
|
||||||
|
add_subdirectory(locale)
|
||||||
add_subdirectory(math)
|
add_subdirectory(math)
|
||||||
|
add_subdirectory(overworld)
|
||||||
add_subdirectory(require)
|
add_subdirectory(require)
|
||||||
|
add_subdirectory(save)
|
||||||
add_subdirectory(scene)
|
add_subdirectory(scene)
|
||||||
add_subdirectory(system)
|
add_subdirectory(story)
|
||||||
|
add_subdirectory(system)
|
||||||
|
add_subdirectory(ui)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
moduleanimation.c
|
||||||
|
moduleeasing.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "moduleanimation.h"
|
||||||
|
#include "animation/animation.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
keyframe_t keyframes[MODULE_ANIMATION_KEYFRAME_MAX];
|
||||||
|
animation_t anim;
|
||||||
|
} moduleanimationdata_t;
|
||||||
|
|
||||||
|
scriptproto_t MODULE_ANIMATION_PROTO;
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAnimationCtor) {
|
||||||
|
if(argc < 1 || !jerry_value_is_array(args[0])) {
|
||||||
|
return moduleBaseThrow(
|
||||||
|
"Animation: expected array of keyframe objects"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
uint32_t len = jerry_array_length(args[0]);
|
||||||
|
if(len == 0) {
|
||||||
|
return moduleBaseThrow(
|
||||||
|
"Animation: keyframe array must not be empty"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const uint16_t count = len > (uint32_t)MODULE_ANIMATION_KEYFRAME_MAX
|
||||||
|
? (uint16_t)MODULE_ANIMATION_KEYFRAME_MAX
|
||||||
|
: (uint16_t)len;
|
||||||
|
|
||||||
|
moduleanimationdata_t *d = (moduleanimationdata_t *)memoryAllocate(
|
||||||
|
sizeof(moduleanimationdata_t)
|
||||||
|
);
|
||||||
|
|
||||||
|
for(uint16_t i = 0; i < count; i++) {
|
||||||
|
jerry_value_t elem = jerry_object_get_index(args[0], (uint32_t)i);
|
||||||
|
jerry_value_t jtm = moduleBaseGetProp(elem, "time");
|
||||||
|
jerry_value_t jvl = moduleBaseGetProp(elem, "value");
|
||||||
|
jerry_value_t jea = moduleBaseGetProp(elem, "easing");
|
||||||
|
|
||||||
|
d->keyframes[i].time = moduleBaseValueFloat(jtm);
|
||||||
|
d->keyframes[i].value = moduleBaseValueFloat(jvl);
|
||||||
|
d->keyframes[i].easing = jerry_value_is_number(jea)
|
||||||
|
? (easingtype_t)moduleBaseValueInt(jea)
|
||||||
|
: EASING_LINEAR;
|
||||||
|
|
||||||
|
jerry_value_free(jea);
|
||||||
|
jerry_value_free(jvl);
|
||||||
|
jerry_value_free(jtm);
|
||||||
|
jerry_value_free(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
animationInit(&d->anim, d->keyframes, count);
|
||||||
|
|
||||||
|
jerry_object_set_native_ptr(
|
||||||
|
callInfo->this_value, &MODULE_ANIMATION_PROTO.info, d
|
||||||
|
);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAnimationGetValue) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleBaseRequireNumber(0);
|
||||||
|
moduleanimationdata_t *d = (moduleanimationdata_t *)scriptProtoGetValue(
|
||||||
|
&MODULE_ANIMATION_PROTO, callInfo->this_value
|
||||||
|
);
|
||||||
|
if(!d) return jerry_undefined();
|
||||||
|
return jerry_number(
|
||||||
|
(double)animationGetValue(&d->anim, moduleBaseArgFloat(0))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleAnimationInit(void) {
|
||||||
|
scriptProtoInit(
|
||||||
|
&MODULE_ANIMATION_PROTO, "Animation",
|
||||||
|
sizeof(moduleanimationdata_t), moduleAnimationCtor
|
||||||
|
);
|
||||||
|
scriptProtoDefineFunc(
|
||||||
|
&MODULE_ANIMATION_PROTO, "getValue", moduleAnimationGetValue
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleAnimationDispose(void) {
|
||||||
|
scriptProtoDispose(&MODULE_ANIMATION_PROTO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "script/scriptproto.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
|
||||||
|
/** Maximum keyframes per Animation instance. */
|
||||||
|
#define MODULE_ANIMATION_KEYFRAME_MAX 64
|
||||||
|
|
||||||
|
extern scriptproto_t MODULE_ANIMATION_PROTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* new Animation(keyframes) — creates an Animation from a JS array of
|
||||||
|
* `{time, value, easing?}` descriptor objects.
|
||||||
|
*
|
||||||
|
* @param args[0] Array of keyframe descriptors.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleAnimationCtor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* animation.getValue(time) — interpolates the animation at `time`.
|
||||||
|
*
|
||||||
|
* @param args[0] Time in seconds (number).
|
||||||
|
* @return Interpolated float value.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleAnimationGetValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Animation module and registers the Animation constructor.
|
||||||
|
*/
|
||||||
|
void moduleAnimationInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the Animation module.
|
||||||
|
*/
|
||||||
|
void moduleAnimationDispose(void);
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "moduleeasing.h"
|
||||||
|
#include "animation/easing.h"
|
||||||
|
|
||||||
|
scriptproto_t MODULE_EASING_PROTO;
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleEasingApply) {
|
||||||
|
moduleBaseRequireArgs(2);
|
||||||
|
moduleBaseRequireNumber(0);
|
||||||
|
moduleBaseRequireNumber(1);
|
||||||
|
const int32_t type = moduleBaseArgInt(0);
|
||||||
|
if(type < 0 || type >= (int32_t)EASING_COUNT) {
|
||||||
|
return moduleBaseThrow("Easing.apply: invalid easing type");
|
||||||
|
}
|
||||||
|
const float_t t = moduleBaseArgFloat(1);
|
||||||
|
return jerry_number((double)easingApply((easingtype_t)type, t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleEasingInit(void) {
|
||||||
|
scriptProtoInit(&MODULE_EASING_PROTO, "Easing", 0, NULL);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_EASING_PROTO, "apply", moduleEasingApply
|
||||||
|
);
|
||||||
|
|
||||||
|
moduleBaseSetInt("EASING_LINEAR", EASING_LINEAR);
|
||||||
|
moduleBaseSetInt("EASING_IN_SINE", EASING_IN_SINE);
|
||||||
|
moduleBaseSetInt("EASING_OUT_SINE", EASING_OUT_SINE);
|
||||||
|
moduleBaseSetInt("EASING_IN_OUT_SINE", EASING_IN_OUT_SINE);
|
||||||
|
moduleBaseSetInt("EASING_IN_QUAD", EASING_IN_QUAD);
|
||||||
|
moduleBaseSetInt("EASING_OUT_QUAD", EASING_OUT_QUAD);
|
||||||
|
moduleBaseSetInt("EASING_IN_OUT_QUAD", EASING_IN_OUT_QUAD);
|
||||||
|
moduleBaseSetInt("EASING_IN_CUBIC", EASING_IN_CUBIC);
|
||||||
|
moduleBaseSetInt("EASING_OUT_CUBIC", EASING_OUT_CUBIC);
|
||||||
|
moduleBaseSetInt("EASING_IN_OUT_CUBIC", EASING_IN_OUT_CUBIC);
|
||||||
|
moduleBaseSetInt("EASING_IN_QUART", EASING_IN_QUART);
|
||||||
|
moduleBaseSetInt("EASING_OUT_QUART", EASING_OUT_QUART);
|
||||||
|
moduleBaseSetInt("EASING_IN_OUT_QUART", EASING_IN_OUT_QUART);
|
||||||
|
moduleBaseSetInt("EASING_IN_BACK", EASING_IN_BACK);
|
||||||
|
moduleBaseSetInt("EASING_OUT_BACK", EASING_OUT_BACK);
|
||||||
|
moduleBaseSetInt("EASING_IN_OUT_BACK", EASING_IN_OUT_BACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleEasingDispose(void) {
|
||||||
|
scriptProtoDispose(&MODULE_EASING_PROTO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "script/scriptproto.h"
|
||||||
|
|
||||||
|
extern scriptproto_t MODULE_EASING_PROTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Easing.apply(type, t) — applies easing function `type` to normalized
|
||||||
|
* time `t` and returns the eased value.
|
||||||
|
*
|
||||||
|
* @param args[0] Easing type constant (EASING_*).
|
||||||
|
* @param args[1] Normalized input time in [0, 1].
|
||||||
|
* @return Eased value as a number.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleEasingApply);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Easing module and injects all EASING_* constants.
|
||||||
|
*/
|
||||||
|
void moduleEasingInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the Easing module.
|
||||||
|
*/
|
||||||
|
void moduleEasingDispose(void);
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "modulephysics.h"
|
#include "modulephysics.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
|
||||||
scriptproto_t MODULE_PHYSICS_PROTO;
|
scriptproto_t MODULE_PHYSICS_PROTO;
|
||||||
|
|
||||||
@@ -64,8 +65,29 @@ moduleBaseFunction(modulePhysicsSetShape) {
|
|||||||
moduleBaseRequireArgs(1);
|
moduleBaseRequireArgs(1);
|
||||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||||
if(!c) return jerry_undefined();
|
if(!c) return jerry_undefined();
|
||||||
physicsshape_t shape = entityPhysicsGetShape(c->entityId, c->componentId);
|
physicsshape_t shape;
|
||||||
|
memoryZero(&shape, sizeof(physicsshape_t));
|
||||||
shape.type = (physicshapetype_t)moduleBaseArgInt(0);
|
shape.type = (physicshapetype_t)moduleBaseArgInt(0);
|
||||||
|
switch(shape.type) {
|
||||||
|
case PHYSICS_SHAPE_CUBE:
|
||||||
|
shape.data.cube.halfExtents[0] = 0.5f;
|
||||||
|
shape.data.cube.halfExtents[1] = 0.5f;
|
||||||
|
shape.data.cube.halfExtents[2] = 0.5f;
|
||||||
|
break;
|
||||||
|
case PHYSICS_SHAPE_SPHERE:
|
||||||
|
shape.data.sphere.radius = 0.5f;
|
||||||
|
break;
|
||||||
|
case PHYSICS_SHAPE_CAPSULE:
|
||||||
|
shape.data.capsule.radius = 0.5f;
|
||||||
|
shape.data.capsule.halfHeight = 0.5f;
|
||||||
|
break;
|
||||||
|
case PHYSICS_SHAPE_PLANE:
|
||||||
|
shape.data.plane.normal[1] = 1.0f;
|
||||||
|
shape.data.plane.distance = 0.0f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
entityPhysicsSetShape(c->entityId, c->componentId, shape);
|
entityPhysicsSetShape(c->entityId, c->componentId, shape);
|
||||||
return jerry_undefined();
|
return jerry_undefined();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
moduleitem.c
|
||||||
|
modulebackpack.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "modulebackpack.h"
|
||||||
|
#include "moduleitem.h"
|
||||||
|
#include "item/backpack.h"
|
||||||
|
|
||||||
|
scriptproto_t MODULE_BACKPACK_PROTO;
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleBackpackGetIsFull) {
|
||||||
|
return jerry_boolean(inventoryIsFull(&BACKPACK));
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleBackpackGetCount) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleItemRequireId(0, "Backpack.getCount");
|
||||||
|
const itemid_t id = (itemid_t)moduleBaseArgInt(0);
|
||||||
|
return jerry_number((double)inventoryGetCount(&BACKPACK, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleBackpackHas) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleItemRequireId(0, "Backpack.has");
|
||||||
|
const itemid_t id = (itemid_t)moduleBaseArgInt(0);
|
||||||
|
return jerry_boolean(inventoryItemExists(&BACKPACK, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleBackpackIsItemFull) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleItemRequireId(0, "Backpack.isItemFull");
|
||||||
|
const itemid_t id = (itemid_t)moduleBaseArgInt(0);
|
||||||
|
return jerry_boolean(inventoryItemFull(&BACKPACK, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleBackpackSet) {
|
||||||
|
moduleBaseRequireArgs(2);
|
||||||
|
moduleItemRequireId(0, "Backpack.set");
|
||||||
|
moduleBaseRequireNumber(1);
|
||||||
|
const int32_t qty = moduleBaseArgInt(1);
|
||||||
|
if(qty < 0 || qty > (int32_t)ITEM_STACK_QUANTITY_MAX) {
|
||||||
|
return moduleBaseThrow("Backpack.set: quantity out of range (0-255)");
|
||||||
|
}
|
||||||
|
inventorySet(&BACKPACK, (itemid_t)moduleBaseArgInt(0), (uint8_t)qty);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleBackpackAdd) {
|
||||||
|
moduleBaseRequireArgs(2);
|
||||||
|
moduleItemRequireId(0, "Backpack.add");
|
||||||
|
moduleBaseRequireNumber(1);
|
||||||
|
const int32_t qty = moduleBaseArgInt(1);
|
||||||
|
if(qty < 1 || qty > (int32_t)ITEM_STACK_QUANTITY_MAX) {
|
||||||
|
return moduleBaseThrow("Backpack.add: quantity out of range (1-255)");
|
||||||
|
}
|
||||||
|
inventoryAdd(&BACKPACK, (itemid_t)moduleBaseArgInt(0), (uint8_t)qty);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleBackpackRemove) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleItemRequireId(0, "Backpack.remove");
|
||||||
|
inventoryRemove(&BACKPACK, (itemid_t)moduleBaseArgInt(0));
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleBackpackSort) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleBaseRequireNumber(0);
|
||||||
|
const inventorysort_t sortBy = (inventorysort_t)moduleBaseArgInt(0);
|
||||||
|
if((int32_t)sortBy < 0 || sortBy >= INVENTORY_SORT_COUNT) {
|
||||||
|
return moduleBaseThrow("Backpack.sort: invalid sort type");
|
||||||
|
}
|
||||||
|
const bool_t reverse = (argc > 1 && jerry_value_is_true(args[1]));
|
||||||
|
inventorySort(&BACKPACK, sortBy, reverse);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleBackpackInit(void) {
|
||||||
|
scriptProtoInit(
|
||||||
|
&MODULE_BACKPACK_PROTO, "Backpack", sizeof(uint8_t), NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
scriptProtoDefineStaticProp(
|
||||||
|
&MODULE_BACKPACK_PROTO, "isFull", moduleBackpackGetIsFull, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_BACKPACK_PROTO, "getCount", moduleBackpackGetCount
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_BACKPACK_PROTO, "has", moduleBackpackHas
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_BACKPACK_PROTO, "isItemFull", moduleBackpackIsItemFull
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_BACKPACK_PROTO, "set", moduleBackpackSet
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_BACKPACK_PROTO, "add", moduleBackpackAdd
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_BACKPACK_PROTO, "remove", moduleBackpackRemove
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_BACKPACK_PROTO, "sort", moduleBackpackSort
|
||||||
|
);
|
||||||
|
|
||||||
|
moduleBaseSetInt(
|
||||||
|
"INVENTORY_SORT_BY_ID", (int32_t)INVENTORY_SORT_BY_ID
|
||||||
|
);
|
||||||
|
moduleBaseSetInt(
|
||||||
|
"INVENTORY_SORT_BY_TYPE", (int32_t)INVENTORY_SORT_BY_TYPE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleBackpackDispose(void) {
|
||||||
|
scriptProtoDispose(&MODULE_BACKPACK_PROTO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "script/scriptproto.h"
|
||||||
|
|
||||||
|
extern scriptproto_t MODULE_BACKPACK_PROTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backpack.isFull — true when all storage slots are occupied.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleBackpackGetIsFull);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backpack.getCount(itemId) — quantity of itemId (0 if absent).
|
||||||
|
*
|
||||||
|
* @param args[0] Item ID constant (ITEM_ID_*).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleBackpackGetCount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backpack.has(itemId) — true if itemId is present with quantity > 0.
|
||||||
|
*
|
||||||
|
* @param args[0] Item ID constant (ITEM_ID_*).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleBackpackHas);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backpack.isItemFull(itemId) — true if the stack is at max quantity.
|
||||||
|
*
|
||||||
|
* @param args[0] Item ID constant (ITEM_ID_*).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleBackpackIsItemFull);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backpack.set(itemId, quantity) — set quantity; removes when 0.
|
||||||
|
*
|
||||||
|
* @param args[0] Item ID constant (ITEM_ID_*).
|
||||||
|
* @param args[1] Quantity 0–255.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleBackpackSet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backpack.add(itemId, quantity) — add quantity units of itemId.
|
||||||
|
*
|
||||||
|
* @param args[0] Item ID constant (ITEM_ID_*).
|
||||||
|
* @param args[1] Quantity to add (1–255).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleBackpackAdd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backpack.remove(itemId) — removes itemId entirely from the backpack.
|
||||||
|
*
|
||||||
|
* @param args[0] Item ID constant (ITEM_ID_*).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleBackpackRemove);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backpack.sort(sortBy[, reverse]) — sort the backpack contents.
|
||||||
|
*
|
||||||
|
* @param args[0] Sort type (INVENTORY_SORT_BY_ID or
|
||||||
|
* INVENTORY_SORT_BY_TYPE).
|
||||||
|
* @param args[1] Optional boolean; true to reverse order.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleBackpackSort);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Backpack module, registers all Backpack methods, and
|
||||||
|
* sets INVENTORY_SORT_BY_ID / INVENTORY_SORT_BY_TYPE as globals.
|
||||||
|
*/
|
||||||
|
void moduleBackpackInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the Backpack module.
|
||||||
|
*/
|
||||||
|
void moduleBackpackDispose(void);
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "moduleitem.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
scriptproto_t MODULE_ITEM_PROTO;
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleItemGetName) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleItemRequireId(0, "Item.getName");
|
||||||
|
const itemid_t id = (itemid_t)moduleBaseArgInt(0);
|
||||||
|
return jerry_string_sz(ITEMS[id].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleItemGetType) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleItemRequireId(0, "Item.getType");
|
||||||
|
const itemid_t id = (itemid_t)moduleBaseArgInt(0);
|
||||||
|
return jerry_number((double)ITEMS[id].type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleItemInit(void) {
|
||||||
|
scriptProtoInit(&MODULE_ITEM_PROTO, "Item", sizeof(uint8_t), NULL);
|
||||||
|
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_ITEM_PROTO, "getName", moduleItemGetName
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_ITEM_PROTO, "getType", moduleItemGetType
|
||||||
|
);
|
||||||
|
|
||||||
|
jerry_value_t result = jerry_eval(
|
||||||
|
(const jerry_char_t *)ITEM_SCRIPT,
|
||||||
|
strlen(ITEM_SCRIPT),
|
||||||
|
JERRY_PARSE_NO_OPTS
|
||||||
|
);
|
||||||
|
jerry_value_free(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleItemDispose(void) {
|
||||||
|
scriptProtoDispose(&MODULE_ITEM_PROTO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "script/scriptproto.h"
|
||||||
|
#include "item/item.h"
|
||||||
|
|
||||||
|
extern scriptproto_t MODULE_ITEM_PROTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates an itemid_t argument and returns a type error if invalid.
|
||||||
|
*
|
||||||
|
* @param i Argument index.
|
||||||
|
* @param ctx Context string for error messages.
|
||||||
|
*/
|
||||||
|
#define moduleItemRequireId(i, ctx) do { \
|
||||||
|
if(!jerry_value_is_number(args[(i)])) { \
|
||||||
|
return moduleBaseThrow(ctx ": itemId must be a number"); \
|
||||||
|
} \
|
||||||
|
const itemid_t _id = (itemid_t)moduleBaseArgInt(i); \
|
||||||
|
if(_id <= ITEM_ID_NULL || _id >= ITEM_ID_COUNT) { \
|
||||||
|
return moduleBaseThrow(ctx ": invalid item ID"); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item.getName(itemId) — returns the item's string name.
|
||||||
|
*
|
||||||
|
* @param args[0] Item ID constant (ITEM_ID_*).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleItemGetName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item.getType(itemId) — returns the item's type constant.
|
||||||
|
*
|
||||||
|
* @param args[0] Item ID constant (ITEM_ID_*).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleItemGetType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Item module, registers Item.getName/getType, and
|
||||||
|
* evaluates ITEM_SCRIPT to populate ITEM_ID_* and ITEM_TYPE_* constants
|
||||||
|
* as globals in the script scope.
|
||||||
|
*/
|
||||||
|
void moduleItemInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the Item module.
|
||||||
|
*/
|
||||||
|
void moduleItemDispose(void);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
modulelocale.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "modulelocale.h"
|
||||||
|
#include "asset/loader/locale/assetlocaleloader.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MODULE_LOCALE_SUBSTITUTION_MAX 4
|
||||||
|
#define MODULE_LOCALE_BUFFER_SIZE 512
|
||||||
|
#define MODULE_LOCALE_ID_SIZE 256
|
||||||
|
|
||||||
|
scriptproto_t MODULE_LOCALE_PROTO;
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleLocaleGetText) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleBaseRequireString(0);
|
||||||
|
|
||||||
|
if(LOCALE.entry == NULL) {
|
||||||
|
return moduleBaseThrow("Locale.getText: no locale loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
char_t id[MODULE_LOCALE_ID_SIZE];
|
||||||
|
moduleBaseToString(args[0], id, sizeof(id));
|
||||||
|
|
||||||
|
// Second arg is optional plural count.
|
||||||
|
int32_t plural = 1;
|
||||||
|
jerry_length_t subStart = 1;
|
||||||
|
if(argc > 1 && jerry_value_is_number(args[1])) {
|
||||||
|
plural = moduleBaseArgInt(1);
|
||||||
|
subStart = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect up to MODULE_LOCALE_SUBSTITUTION_MAX substitution args.
|
||||||
|
assetlocalearg_t subArgs[MODULE_LOCALE_SUBSTITUTION_MAX];
|
||||||
|
char_t subStrings[MODULE_LOCALE_SUBSTITUTION_MAX][128];
|
||||||
|
size_t subCount = 0;
|
||||||
|
|
||||||
|
for(jerry_length_t i = subStart; i < argc; i++) {
|
||||||
|
if(subCount >= MODULE_LOCALE_SUBSTITUTION_MAX) break;
|
||||||
|
|
||||||
|
if(jerry_value_is_string(args[i])) {
|
||||||
|
moduleBaseToString(
|
||||||
|
args[i], subStrings[subCount], sizeof(subStrings[subCount])
|
||||||
|
);
|
||||||
|
subArgs[subCount].type = ASSET_LOCALE_ARG_STRING;
|
||||||
|
subArgs[subCount].stringValue = subStrings[subCount];
|
||||||
|
} else if(jerry_value_is_number(args[i])) {
|
||||||
|
double n = jerry_value_as_number(args[i]);
|
||||||
|
if(floor(n) == n) {
|
||||||
|
subArgs[subCount].type = ASSET_LOCALE_ARG_INT;
|
||||||
|
subArgs[subCount].intValue = (int32_t)n;
|
||||||
|
} else {
|
||||||
|
subArgs[subCount].type = ASSET_LOCALE_ARG_FLOAT;
|
||||||
|
subArgs[subCount].floatValue = (float_t)n;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
subCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
char_t buf[MODULE_LOCALE_BUFFER_SIZE];
|
||||||
|
assetLocaleGetStringWithArgs(
|
||||||
|
&LOCALE.entry->data.locale,
|
||||||
|
id,
|
||||||
|
plural,
|
||||||
|
buf,
|
||||||
|
sizeof(buf),
|
||||||
|
subCount > 0 ? subArgs : NULL,
|
||||||
|
subCount
|
||||||
|
);
|
||||||
|
|
||||||
|
return jerry_string_sz(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleLocaleSetLocale) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleBaseRequireString(0);
|
||||||
|
|
||||||
|
char_t name[64];
|
||||||
|
moduleBaseToString(args[0], name, sizeof(name));
|
||||||
|
|
||||||
|
const localeinfo_t *locale = NULL;
|
||||||
|
if(strcmp(name, LOCALE_EN_US.name) == 0) locale = &LOCALE_EN_US;
|
||||||
|
|
||||||
|
if(locale == NULL) {
|
||||||
|
return moduleBaseThrow("Locale.setLocale: unknown locale name");
|
||||||
|
}
|
||||||
|
|
||||||
|
localeManagerSetLocale(locale);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleLocaleInit(void) {
|
||||||
|
scriptProtoInit(
|
||||||
|
&MODULE_LOCALE_PROTO, "Locale", sizeof(uint8_t), NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_LOCALE_PROTO, "getText", moduleLocaleGetText
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_LOCALE_PROTO, "setLocale", moduleLocaleSetLocale
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleLocaleDispose(void) {
|
||||||
|
scriptProtoDispose(&MODULE_LOCALE_PROTO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "script/scriptproto.h"
|
||||||
|
#include "locale/localemanager.h"
|
||||||
|
|
||||||
|
extern scriptproto_t MODULE_LOCALE_PROTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locale.getText(id[, pluralCount[, arg1, ...]]) — returns the
|
||||||
|
* translated string for the given message ID.
|
||||||
|
*
|
||||||
|
* @param args[0] Message ID string.
|
||||||
|
* @param args[1] Optional plural count (number). Defaults to 1.
|
||||||
|
* @param args[2..5] Optional substitution args (string or number).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleLocaleGetText);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locale.setLocale(name) — switches the active locale by name.
|
||||||
|
*
|
||||||
|
* @param args[0] Locale name string, e.g. "en-US".
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleLocaleSetLocale);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Locale module and registers Locale.getText/setLocale.
|
||||||
|
*/
|
||||||
|
void moduleLocaleInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the Locale module.
|
||||||
|
*/
|
||||||
|
void moduleLocaleDispose(void);
|
||||||
@@ -6,6 +6,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "modulelist.h"
|
#include "modulelist.h"
|
||||||
|
#include "script/module/animation/moduleanimation.h"
|
||||||
|
#include "script/module/animation/moduleeasing.h"
|
||||||
#include "script/module/asset/moduleasset.h"
|
#include "script/module/asset/moduleasset.h"
|
||||||
#include "script/module/console/moduleconsole.h"
|
#include "script/module/console/moduleconsole.h"
|
||||||
#include "script/module/display/modulecolor.h"
|
#include "script/module/display/modulecolor.h"
|
||||||
@@ -16,13 +18,22 @@
|
|||||||
#include "script/module/engine/moduletimeout.h"
|
#include "script/module/engine/moduletimeout.h"
|
||||||
#include "script/module/entity/moduleentity.h"
|
#include "script/module/entity/moduleentity.h"
|
||||||
#include "script/module/input/moduleinput.h"
|
#include "script/module/input/moduleinput.h"
|
||||||
|
#include "script/module/item/moduleitem.h"
|
||||||
|
#include "script/module/item/modulebackpack.h"
|
||||||
|
#include "script/module/locale/modulelocale.h"
|
||||||
|
#include "script/module/save/modulesave.h"
|
||||||
#include "script/module/math/modulevec3.h"
|
#include "script/module/math/modulevec3.h"
|
||||||
|
#include "script/module/overworld/moduleoverworld.h"
|
||||||
#include "script/module/require/modulerequire.h"
|
#include "script/module/require/modulerequire.h"
|
||||||
#include "script/module/scene/modulescene.h"
|
#include "script/module/scene/modulescene.h"
|
||||||
|
#include "script/module/story/modulestory.h"
|
||||||
#include "script/module/system/modulesystem.h"
|
#include "script/module/system/modulesystem.h"
|
||||||
|
#include "script/module/ui/moduletextbox.h"
|
||||||
|
|
||||||
|
|
||||||
void moduleListInit(void) {
|
void moduleListInit(void) {
|
||||||
|
moduleAnimationInit();
|
||||||
|
moduleEasingInit();
|
||||||
moduleEventInit();
|
moduleEventInit();
|
||||||
moduleTextureInit();
|
moduleTextureInit();
|
||||||
moduleColorInit();
|
moduleColorInit();
|
||||||
@@ -35,9 +46,16 @@ void moduleListInit(void) {
|
|||||||
moduleVec3Init();
|
moduleVec3Init();
|
||||||
moduleEntityInit();
|
moduleEntityInit();
|
||||||
moduleInputInit();
|
moduleInputInit();
|
||||||
|
moduleItemInit();
|
||||||
|
moduleBackpackInit();
|
||||||
|
moduleLocaleInit();
|
||||||
|
moduleSaveInit();
|
||||||
|
moduleOverworldInit();
|
||||||
moduleRequireInit();
|
moduleRequireInit();
|
||||||
moduleSceneInit();
|
moduleSceneInit();
|
||||||
|
moduleStoryInit();
|
||||||
moduleSystemInit();
|
moduleSystemInit();
|
||||||
|
moduleTextboxInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void moduleListUpdate(void) {
|
void moduleListUpdate(void) {
|
||||||
@@ -46,9 +64,18 @@ void moduleListUpdate(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void moduleListDispose(void) {
|
void moduleListDispose(void) {
|
||||||
|
moduleTextboxDispose();
|
||||||
moduleSystemDispose();
|
moduleSystemDispose();
|
||||||
|
moduleOverworldDispose();
|
||||||
|
moduleEasingDispose();
|
||||||
|
moduleAnimationDispose();
|
||||||
|
moduleStoryDispose();
|
||||||
moduleSceneDispose();
|
moduleSceneDispose();
|
||||||
moduleRequireDispose();
|
moduleRequireDispose();
|
||||||
|
moduleSaveDispose();
|
||||||
|
moduleLocaleDispose();
|
||||||
|
moduleBackpackDispose();
|
||||||
|
moduleItemDispose();
|
||||||
moduleInputDispose();
|
moduleInputDispose();
|
||||||
moduleEntityDispose();
|
moduleEntityDispose();
|
||||||
moduleVec3Dispose();
|
moduleVec3Dispose();
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
moduleoverworld.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "moduleoverworld.h"
|
||||||
|
#include "overworld/map.h"
|
||||||
|
|
||||||
|
scriptproto_t MODULE_OVERWORLD_PROTO;
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleOverworldLoadMap) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleBaseRequireString(0);
|
||||||
|
char_t handle[MAP_HANDLE_MAX];
|
||||||
|
moduleBaseToString(args[0], handle, (jerry_size_t)MAP_HANDLE_MAX);
|
||||||
|
errorret_t err = mapLoad(handle);
|
||||||
|
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleOverworldIsLoaded) {
|
||||||
|
return jerry_boolean(mapIsLoaded());
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleOverworldSetPosition) {
|
||||||
|
moduleBaseRequireArgs(3);
|
||||||
|
moduleBaseRequireNumber(0);
|
||||||
|
moduleBaseRequireNumber(1);
|
||||||
|
moduleBaseRequireNumber(2);
|
||||||
|
tilepos_t pos;
|
||||||
|
pos.x = (tileunit_t)moduleBaseArgInt(0);
|
||||||
|
pos.y = (tileunit_t)moduleBaseArgInt(1);
|
||||||
|
pos.z = (tileunit_t)moduleBaseArgInt(2);
|
||||||
|
errorret_t err = mapPositionSet(pos);
|
||||||
|
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleOverworldUpdate) {
|
||||||
|
errorret_t err = mapUpdate();
|
||||||
|
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleOverworldJsDispose) {
|
||||||
|
mapDispose();
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleOverworldInit(void) {
|
||||||
|
scriptProtoInit(&MODULE_OVERWORLD_PROTO, "Overworld", 0, NULL);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_OVERWORLD_PROTO, "loadMap", moduleOverworldLoadMap
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_OVERWORLD_PROTO, "isLoaded", moduleOverworldIsLoaded
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_OVERWORLD_PROTO, "setPosition", moduleOverworldSetPosition
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_OVERWORLD_PROTO, "update", moduleOverworldUpdate
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_OVERWORLD_PROTO, "dispose", moduleOverworldJsDispose
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleOverworldDispose(void) {
|
||||||
|
scriptProtoDispose(&MODULE_OVERWORLD_PROTO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "script/scriptproto.h"
|
||||||
|
|
||||||
|
extern scriptproto_t MODULE_OVERWORLD_PROTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overworld.loadMap(handle) — loads the map with the given handle string.
|
||||||
|
* Disposes any currently loaded map first.
|
||||||
|
*
|
||||||
|
* @param args[0] Map handle string (max 31 chars).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleOverworldLoadMap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overworld.isLoaded() — returns true when a map is currently loaded.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleOverworldIsLoaded);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overworld.setPosition(x, y, z) — slides the chunk window to the tile
|
||||||
|
* position (x, y, z).
|
||||||
|
*
|
||||||
|
* @param args[0] Tile X (integer).
|
||||||
|
* @param args[1] Tile Y (integer).
|
||||||
|
* @param args[2] Tile Z (integer).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleOverworldSetPosition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overworld.update() — advances the map one tick.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleOverworldUpdate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overworld.dispose() — unloads the current map.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleOverworldJsDispose);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Overworld module and registers the Overworld global.
|
||||||
|
*/
|
||||||
|
void moduleOverworldInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the Overworld module.
|
||||||
|
*/
|
||||||
|
void moduleOverworldDispose(void);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
modulesave.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "modulesave.h"
|
||||||
|
|
||||||
|
scriptproto_t MODULE_SAVE_PROTO;
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleSaveExists) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleSaveRequireSlot(0, "Save.exists");
|
||||||
|
return jerry_boolean(saveExists((uint8_t)moduleBaseArgInt(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleSaveLoad) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleSaveRequireSlot(0, "Save.load");
|
||||||
|
errorret_t err = saveLoad((uint8_t)moduleBaseArgInt(0));
|
||||||
|
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleSaveWrite) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleSaveRequireSlot(0, "Save.write");
|
||||||
|
errorret_t err = saveWrite((uint8_t)moduleBaseArgInt(0));
|
||||||
|
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleSaveDelete) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleSaveRequireSlot(0, "Save.delete");
|
||||||
|
errorret_t err = saveDelete((uint8_t)moduleBaseArgInt(0));
|
||||||
|
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleSaveInit(void) {
|
||||||
|
scriptProtoInit(&MODULE_SAVE_PROTO, "Save", sizeof(uint8_t), NULL);
|
||||||
|
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_SAVE_PROTO, "exists", moduleSaveExists
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_SAVE_PROTO, "load", moduleSaveLoad
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_SAVE_PROTO, "write", moduleSaveWrite
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_SAVE_PROTO, "delete", moduleSaveDelete
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleSaveDispose(void) {
|
||||||
|
scriptProtoDispose(&MODULE_SAVE_PROTO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "script/scriptproto.h"
|
||||||
|
#include "save/save.h"
|
||||||
|
|
||||||
|
extern scriptproto_t MODULE_SAVE_PROTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a save-slot argument and returns a type error if invalid.
|
||||||
|
*
|
||||||
|
* @param i Argument index.
|
||||||
|
* @param ctx Context string for error messages.
|
||||||
|
*/
|
||||||
|
#define moduleSaveRequireSlot(i, ctx) do { \
|
||||||
|
if(!jerry_value_is_number(args[(i)])) { \
|
||||||
|
return moduleBaseThrow(ctx ": slot must be a number"); \
|
||||||
|
} \
|
||||||
|
const int32_t _s = moduleBaseArgInt(i); \
|
||||||
|
if(_s < 0 || _s >= (int32_t)SAVE_FILE_COUNT_MAX) { \
|
||||||
|
return moduleBaseThrow(ctx ": invalid save slot"); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save.exists(slot) — true if a save file is present for the slot.
|
||||||
|
*
|
||||||
|
* @param args[0] Save slot index (0 to SAVE_FILE_COUNT_MAX - 1).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleSaveExists);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save.load(slot) — loads the save file for the given slot.
|
||||||
|
*
|
||||||
|
* @param args[0] Save slot index (0 to SAVE_FILE_COUNT_MAX - 1).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleSaveLoad);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save.write(slot) — writes the save file for the given slot.
|
||||||
|
*
|
||||||
|
* @param args[0] Save slot index (0 to SAVE_FILE_COUNT_MAX - 1).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleSaveWrite);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save.delete(slot) — deletes the save file for the given slot.
|
||||||
|
*
|
||||||
|
* @param args[0] Save slot index (0 to SAVE_FILE_COUNT_MAX - 1).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleSaveDelete);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Save module and registers Save.exists/load/write/delete.
|
||||||
|
*/
|
||||||
|
void moduleSaveInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the Save module.
|
||||||
|
*/
|
||||||
|
void moduleSaveDispose(void);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
modulestory.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "modulestory.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
scriptproto_t MODULE_STORY_PROTO;
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleStoryGet) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleStoryRequireFlag(0, "Story.get");
|
||||||
|
const storyflag_t flag = (storyflag_t)moduleBaseArgInt(0);
|
||||||
|
return jerry_number((double)storyFlagGet(flag));
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleStorySet) {
|
||||||
|
moduleBaseRequireArgs(2);
|
||||||
|
moduleStoryRequireFlag(0, "Story.set");
|
||||||
|
moduleBaseRequireNumber(1);
|
||||||
|
const int32_t val = moduleBaseArgInt(1);
|
||||||
|
if(val < 0 || val > 255) {
|
||||||
|
return moduleBaseThrow("Story.set: value out of range (0-255)");
|
||||||
|
}
|
||||||
|
storyFlagSet(
|
||||||
|
(storyflag_t)moduleBaseArgInt(0),
|
||||||
|
(storyflagvalue_t)val
|
||||||
|
);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleStoryInit(void) {
|
||||||
|
scriptProtoInit(&MODULE_STORY_PROTO, "Story", sizeof(uint8_t), NULL);
|
||||||
|
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_STORY_PROTO, "get", moduleStoryGet
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_STORY_PROTO, "set", moduleStorySet
|
||||||
|
);
|
||||||
|
|
||||||
|
jerry_value_t result = jerry_eval(
|
||||||
|
(const jerry_char_t *)STORY_FLAG_SCRIPT,
|
||||||
|
strlen(STORY_FLAG_SCRIPT),
|
||||||
|
JERRY_PARSE_NO_OPTS
|
||||||
|
);
|
||||||
|
jerry_value_free(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleStoryDispose(void) {
|
||||||
|
scriptProtoDispose(&MODULE_STORY_PROTO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "script/scriptproto.h"
|
||||||
|
#include "story/storyflag.h"
|
||||||
|
|
||||||
|
extern scriptproto_t MODULE_STORY_PROTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a storyflag_t argument and returns a type error if invalid.
|
||||||
|
*
|
||||||
|
* @param i Argument index.
|
||||||
|
* @param ctx Context string for error messages.
|
||||||
|
*/
|
||||||
|
#define moduleStoryRequireFlag(i, ctx) do { \
|
||||||
|
if(!jerry_value_is_number(args[(i)])) { \
|
||||||
|
return moduleBaseThrow(ctx ": flagId must be a number"); \
|
||||||
|
} \
|
||||||
|
const storyflag_t _f = (storyflag_t)moduleBaseArgInt(i); \
|
||||||
|
if(_f <= STORY_FLAG_NULL || _f >= STORY_FLAG_COUNT) { \
|
||||||
|
return moduleBaseThrow(ctx ": invalid story flag ID"); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Story.get(flagId) — returns the current uint8 value of a story flag.
|
||||||
|
*
|
||||||
|
* @param args[0] Story flag constant (STORY_FLAG_*).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleStoryGet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Story.set(flagId, value) — sets a story flag to a uint8 value.
|
||||||
|
*
|
||||||
|
* @param args[0] Story flag constant (STORY_FLAG_*).
|
||||||
|
* @param args[1] Value 0–255.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleStorySet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Story module, registers Story.get/set, and evaluates
|
||||||
|
* STORY_FLAG_SCRIPT to inject STORY_FLAG_* constants as globals.
|
||||||
|
*/
|
||||||
|
void moduleStoryInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the Story module.
|
||||||
|
*/
|
||||||
|
void moduleStoryDispose(void);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
moduletextbox.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "moduletextbox.h"
|
||||||
|
#include "ui/uitextbox.h"
|
||||||
|
#include "input/inputaction.h"
|
||||||
|
|
||||||
|
scriptproto_t MODULE_TEXTBOX_PROTO;
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleTextboxSetText) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleBaseRequireString(0);
|
||||||
|
char_t buf[UI_TEXTBOX_TEXT_MAX];
|
||||||
|
moduleBaseToString(args[0], buf, sizeof(buf));
|
||||||
|
uiTextboxSetText(buf);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleTextboxNextPage) {
|
||||||
|
uiTextboxNextPage();
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleTextboxUpdate) {
|
||||||
|
errorret_t err = uiTextboxUpdate();
|
||||||
|
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleTextboxDraw) {
|
||||||
|
errorret_t err = uiTextboxDraw();
|
||||||
|
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleTextboxSetAdvanceAction) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
moduleBaseRequireNumber(0);
|
||||||
|
const inputaction_t action = (inputaction_t)moduleBaseArgInt(0);
|
||||||
|
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
|
||||||
|
return moduleBaseThrow(
|
||||||
|
"UITextbox.setAdvanceAction: invalid action"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
UI_TEXTBOX.advanceAction = action;
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleTextboxGetIsPageComplete) {
|
||||||
|
return jerry_boolean(uiTextboxPageIsComplete());
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleTextboxGetHasNextPage) {
|
||||||
|
return jerry_boolean(uiTextboxHasNextPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleTextboxGetCurrentPage) {
|
||||||
|
return jerry_number((double)UI_TEXTBOX.currentPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleTextboxGetPageCount) {
|
||||||
|
return jerry_number((double)UI_TEXTBOX.pageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleTextboxInit(void) {
|
||||||
|
scriptProtoInit(
|
||||||
|
&MODULE_TEXTBOX_PROTO, "UITextbox", sizeof(uint8_t), NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_TEXTBOX_PROTO, "setText", moduleTextboxSetText
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_TEXTBOX_PROTO, "nextPage", moduleTextboxNextPage
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_TEXTBOX_PROTO, "update", moduleTextboxUpdate
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_TEXTBOX_PROTO, "draw", moduleTextboxDraw
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticFunc(
|
||||||
|
&MODULE_TEXTBOX_PROTO, "setAdvanceAction",
|
||||||
|
moduleTextboxSetAdvanceAction
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticProp(
|
||||||
|
&MODULE_TEXTBOX_PROTO, "isPageComplete",
|
||||||
|
moduleTextboxGetIsPageComplete, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticProp(
|
||||||
|
&MODULE_TEXTBOX_PROTO, "hasNextPage",
|
||||||
|
moduleTextboxGetHasNextPage, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticProp(
|
||||||
|
&MODULE_TEXTBOX_PROTO, "currentPage",
|
||||||
|
moduleTextboxGetCurrentPage, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineStaticProp(
|
||||||
|
&MODULE_TEXTBOX_PROTO, "pageCount",
|
||||||
|
moduleTextboxGetPageCount, NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleTextboxDispose(void) {
|
||||||
|
scriptProtoDispose(&MODULE_TEXTBOX_PROTO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "script/scriptproto.h"
|
||||||
|
|
||||||
|
extern scriptproto_t MODULE_TEXTBOX_PROTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UITextbox.setText(text) — sets the textbox content and rebuilds layout.
|
||||||
|
*
|
||||||
|
* @param args[0] Null-terminated text string.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleTextboxSetText);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UITextbox.nextPage() — advances to the next page; no-op on last page.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleTextboxNextPage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UITextbox.update() — advances the typewriter scroll by one tick.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleTextboxUpdate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UITextbox.draw() — draws the frame and visible text for this frame.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleTextboxDraw);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UITextbox.setAdvanceAction(action) — sets the input action that
|
||||||
|
* advances the textbox when held.
|
||||||
|
*
|
||||||
|
* @param args[0] Input action constant (INPUT_ACTION_*).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleTextboxSetAdvanceAction);
|
||||||
|
|
||||||
|
/** @return true when the typewriter has fully revealed the current page. */
|
||||||
|
moduleBaseFunction(moduleTextboxGetIsPageComplete);
|
||||||
|
|
||||||
|
/** @return true when at least one more page follows the current one. */
|
||||||
|
moduleBaseFunction(moduleTextboxGetHasNextPage);
|
||||||
|
|
||||||
|
/** @return Zero-based index of the current page. */
|
||||||
|
moduleBaseFunction(moduleTextboxGetCurrentPage);
|
||||||
|
|
||||||
|
/** @return Total number of pages for the current text. */
|
||||||
|
moduleBaseFunction(moduleTextboxGetPageCount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the UITextbox module and registers all methods and
|
||||||
|
* properties on the UITextbox global.
|
||||||
|
*/
|
||||||
|
void moduleTextboxInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the UITextbox module.
|
||||||
|
*/
|
||||||
|
void moduleTextboxDispose(void);
|
||||||
Vendored
+61
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** A single keyframe descriptor passed to the Animation constructor. */
|
||||||
|
interface AnimationKeyframe {
|
||||||
|
/** Time offset in seconds. */
|
||||||
|
time: number;
|
||||||
|
/** Value at this keyframe. */
|
||||||
|
value: number;
|
||||||
|
/** Easing type (EASING_* constant). Defaults to EASING_LINEAR. */
|
||||||
|
easing?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Keyframe-based float animation. */
|
||||||
|
interface AnimationInstance {
|
||||||
|
/**
|
||||||
|
* Interpolates the animation at the given time.
|
||||||
|
* @param time Time in seconds.
|
||||||
|
* @returns Interpolated value.
|
||||||
|
*/
|
||||||
|
getValue(time: number): number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Constructs a new Animation from an array of keyframe descriptors. */
|
||||||
|
declare var Animation: {
|
||||||
|
new (keyframes: AnimationKeyframe[]): AnimationInstance;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Easing function utilities. */
|
||||||
|
interface EasingNamespace {
|
||||||
|
/**
|
||||||
|
* Applies the given easing function to normalized time t.
|
||||||
|
* @param type An EASING_* constant.
|
||||||
|
* @param t Normalized time in [0, 1].
|
||||||
|
* @returns Eased value in [0, 1].
|
||||||
|
*/
|
||||||
|
apply(type: number, t: number): number;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var Easing: EasingNamespace;
|
||||||
|
|
||||||
|
declare var EASING_LINEAR: number;
|
||||||
|
declare var EASING_IN_SINE: number;
|
||||||
|
declare var EASING_OUT_SINE: number;
|
||||||
|
declare var EASING_IN_OUT_SINE: number;
|
||||||
|
declare var EASING_IN_QUAD: number;
|
||||||
|
declare var EASING_OUT_QUAD: number;
|
||||||
|
declare var EASING_IN_OUT_QUAD: number;
|
||||||
|
declare var EASING_IN_CUBIC: number;
|
||||||
|
declare var EASING_OUT_CUBIC: number;
|
||||||
|
declare var EASING_IN_OUT_CUBIC: number;
|
||||||
|
declare var EASING_IN_QUART: number;
|
||||||
|
declare var EASING_OUT_QUART: number;
|
||||||
|
declare var EASING_IN_OUT_QUART: number;
|
||||||
|
declare var EASING_IN_BACK: number;
|
||||||
|
declare var EASING_OUT_BACK: number;
|
||||||
|
declare var EASING_IN_OUT_BACK: number;
|
||||||
Vendored
+22
@@ -31,6 +31,28 @@
|
|||||||
/// <reference path="./asset/assetbatch.d.ts" />
|
/// <reference path="./asset/assetbatch.d.ts" />
|
||||||
/// <reference path="./asset/asset.d.ts" />
|
/// <reference path="./asset/asset.d.ts" />
|
||||||
|
|
||||||
|
// animation
|
||||||
|
/// <reference path="./animation/animation.d.ts" />
|
||||||
|
|
||||||
|
// overworld
|
||||||
|
/// <reference path="./overworld/overworld.d.ts" />
|
||||||
|
|
||||||
|
// item system
|
||||||
|
/// <reference path="./item/item.d.ts" />
|
||||||
|
/// <reference path="./item/backpack.d.ts" />
|
||||||
|
|
||||||
|
// story system
|
||||||
|
/// <reference path="./story/story.d.ts" />
|
||||||
|
|
||||||
|
// locale
|
||||||
|
/// <reference path="./locale/locale.d.ts" />
|
||||||
|
|
||||||
|
// save
|
||||||
|
/// <reference path="./save/save.d.ts" />
|
||||||
|
|
||||||
|
// ui
|
||||||
|
/// <reference path="./ui/textbox.d.ts" />
|
||||||
|
|
||||||
// engine systems
|
// engine systems
|
||||||
/// <reference path="./console/console.d.ts" />
|
/// <reference path="./console/console.d.ts" />
|
||||||
/// <reference path="./engine/engine.d.ts" />
|
/// <reference path="./engine/engine.d.ts" />
|
||||||
|
|||||||
Vendored
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** The player's item backpack (a fixed 20-slot inventory). */
|
||||||
|
interface BackpackNamespace {
|
||||||
|
/** `true` when all 20 storage slots are occupied by distinct items. */
|
||||||
|
readonly isFull: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quantity of `itemId` in the backpack (0 if absent).
|
||||||
|
* @param itemId - An `ITEM_ID_*` constant.
|
||||||
|
*/
|
||||||
|
getCount(itemId: ItemId): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if `itemId` is present with quantity greater than 0.
|
||||||
|
* @param itemId - An `ITEM_ID_*` constant.
|
||||||
|
*/
|
||||||
|
has(itemId: ItemId): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if the stack for `itemId` is at maximum quantity (255).
|
||||||
|
* @param itemId - An `ITEM_ID_*` constant.
|
||||||
|
*/
|
||||||
|
isItemFull(itemId: ItemId): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the quantity of `itemId`; passing 0 removes the stack entirely.
|
||||||
|
* @param itemId - An `ITEM_ID_*` constant.
|
||||||
|
* @param quantity - New quantity, 0–255.
|
||||||
|
*/
|
||||||
|
set(itemId: ItemId, quantity: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds `quantity` units of `itemId` to the backpack.
|
||||||
|
* @param itemId - An `ITEM_ID_*` constant.
|
||||||
|
* @param quantity - Amount to add, 1–255.
|
||||||
|
*/
|
||||||
|
add(itemId: ItemId, quantity: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes `itemId` entirely from the backpack.
|
||||||
|
* @param itemId - An `ITEM_ID_*` constant.
|
||||||
|
*/
|
||||||
|
remove(itemId: ItemId): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts the backpack contents.
|
||||||
|
* @param sortBy - `INVENTORY_SORT_BY_ID` or `INVENTORY_SORT_BY_TYPE`.
|
||||||
|
* @param reverse - Optional; pass `true` to reverse the sort order.
|
||||||
|
*/
|
||||||
|
sort(sortBy: number, reverse?: boolean): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var Backpack: BackpackNamespace;
|
||||||
|
|
||||||
|
// Inventory sort constants — injected as globals by the engine at startup.
|
||||||
|
declare var INVENTORY_SORT_BY_ID: number;
|
||||||
|
declare var INVENTORY_SORT_BY_TYPE: number;
|
||||||
Vendored
+39
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Opaque type alias for item identifier constants. */
|
||||||
|
type ItemId = number;
|
||||||
|
|
||||||
|
/** Opaque type alias for item type constants. */
|
||||||
|
type ItemType = number;
|
||||||
|
|
||||||
|
/** Item data lookup. */
|
||||||
|
interface ItemNamespace {
|
||||||
|
/**
|
||||||
|
* Returns the string name for the given item ID.
|
||||||
|
* @param itemId - An `ITEM_ID_*` constant.
|
||||||
|
*/
|
||||||
|
getName(itemId: ItemId): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type constant for the given item ID.
|
||||||
|
* @param itemId - An `ITEM_ID_*` constant.
|
||||||
|
* @returns An `ITEM_TYPE_*` constant.
|
||||||
|
*/
|
||||||
|
getType(itemId: ItemId): ItemType;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var Item: ItemNamespace;
|
||||||
|
|
||||||
|
// Item ID constants — injected as globals by the engine at startup.
|
||||||
|
declare var ITEM_ID_POTION: ItemId;
|
||||||
|
declare var ITEM_ID_POTATO: ItemId;
|
||||||
|
declare var ITEM_ID_APPLE: ItemId;
|
||||||
|
|
||||||
|
// Item type constants — injected as globals by the engine at startup.
|
||||||
|
declare var ITEM_TYPE_MEDICINE: ItemType;
|
||||||
|
declare var ITEM_TYPE_FOOD: ItemType;
|
||||||
Vendored
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Locale string lookup and language switching. */
|
||||||
|
interface LocaleNamespace {
|
||||||
|
/**
|
||||||
|
* Returns the translated string for the given message ID.
|
||||||
|
*
|
||||||
|
* @param id - PO message ID, e.g. `"ITEM_POTION_NAME"`.
|
||||||
|
* @param pluralCount - Optional count used to select the plural form.
|
||||||
|
* Defaults to 1 (singular).
|
||||||
|
* @param args - Optional substitution values (`%s`, `%d`, `%f`).
|
||||||
|
*/
|
||||||
|
getText(
|
||||||
|
id: string,
|
||||||
|
pluralCount?: number,
|
||||||
|
...args: Array<string | number>
|
||||||
|
): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switches the active locale.
|
||||||
|
* @param name - Locale name string, e.g. `"en-US"`.
|
||||||
|
*/
|
||||||
|
setLocale(name: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var Locale: LocaleNamespace;
|
||||||
Vendored
+40
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Map loading and world-position management. */
|
||||||
|
interface OverworldNamespace {
|
||||||
|
/**
|
||||||
|
* Loads the map with the given handle, disposing any currently loaded map.
|
||||||
|
* @param handle Map handle string (max 31 chars).
|
||||||
|
*/
|
||||||
|
loadMap(handle: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` when a map is currently loaded.
|
||||||
|
*/
|
||||||
|
isLoaded(): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slides the loaded chunk window to the given tile-space position.
|
||||||
|
* @param x Tile X.
|
||||||
|
* @param y Tile Y.
|
||||||
|
* @param z Tile Z.
|
||||||
|
*/
|
||||||
|
setPosition(x: number, y: number, z: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advances the map one tick. Call once per frame.
|
||||||
|
*/
|
||||||
|
update(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unloads the current map.
|
||||||
|
*/
|
||||||
|
dispose(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var Overworld: OverworldNamespace;
|
||||||
Vendored
+2
-3
@@ -11,9 +11,8 @@
|
|||||||
* Modules are cached after their first load. Subsequent calls with the same
|
* Modules are cached after their first load. Subsequent calls with the same
|
||||||
* resolved path return the cached exports without re-executing the file.
|
* resolved path return the cached exports without re-executing the file.
|
||||||
*
|
*
|
||||||
* Path rules: `"./foo"` / `"../foo"` resolve relative to the calling script's
|
* Path rules: the string is passed verbatim to the asset loader and resolved
|
||||||
* directory; any other string resolves from the archive root. `.js` is
|
* from the archive root. The `.js` extension must be included explicitly.
|
||||||
* appended automatically when missing.
|
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const NPC = require('./entities/NPC');
|
* const NPC = require('./entities/NPC');
|
||||||
|
|||||||
Vendored
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Slot-based save file management. */
|
||||||
|
interface SaveNamespace {
|
||||||
|
/**
|
||||||
|
* Returns `true` if a save file is present for the given slot.
|
||||||
|
* @param slot - Save slot index (0–2).
|
||||||
|
*/
|
||||||
|
exists(slot: number): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the save file for the given slot from persistent storage.
|
||||||
|
* Throws if the load fails.
|
||||||
|
* @param slot - Save slot index (0–2).
|
||||||
|
*/
|
||||||
|
load(slot: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the save file for the given slot to persistent storage.
|
||||||
|
* Throws if the write fails.
|
||||||
|
* @param slot - Save slot index (0–2).
|
||||||
|
*/
|
||||||
|
write(slot: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the save file for the given slot from persistent storage.
|
||||||
|
* Throws if the delete fails.
|
||||||
|
* @param slot - Save slot index (0–2).
|
||||||
|
*/
|
||||||
|
delete(slot: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var Save: SaveNamespace;
|
||||||
Vendored
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Opaque type alias for story flag identifier constants. */
|
||||||
|
type StoryFlag = number;
|
||||||
|
|
||||||
|
/** Story flag read/write access. */
|
||||||
|
interface StoryNamespace {
|
||||||
|
/**
|
||||||
|
* Returns the current value of a story flag (0–255).
|
||||||
|
* @param flagId - A `STORY_FLAG_*` constant.
|
||||||
|
*/
|
||||||
|
get(flagId: StoryFlag): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a story flag to a new value.
|
||||||
|
* @param flagId - A `STORY_FLAG_*` constant.
|
||||||
|
* @param value - New value, 0–255.
|
||||||
|
*/
|
||||||
|
set(flagId: StoryFlag, value: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var Story: StoryNamespace;
|
||||||
|
|
||||||
|
// Story flag constants — injected as globals by the engine at startup.
|
||||||
|
declare var STORY_FLAG_TEST: StoryFlag;
|
||||||
Vendored
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** VN-style typewriter textbox singleton. */
|
||||||
|
interface UITextboxNamespace {
|
||||||
|
/** `true` when the typewriter has fully revealed the current page. */
|
||||||
|
readonly isPageComplete: boolean;
|
||||||
|
/** `true` when at least one more page follows the current one. */
|
||||||
|
readonly hasNextPage: boolean;
|
||||||
|
/** Zero-based index of the current page. */
|
||||||
|
readonly currentPage: number;
|
||||||
|
/** Total number of pages for the current text. */
|
||||||
|
readonly pageCount: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the textbox content and rebuilds the word-wrap layout.
|
||||||
|
* Resets to page 0 and scroll 0.
|
||||||
|
* @param text - Text to display (max 1024 chars).
|
||||||
|
*/
|
||||||
|
setText(text: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advances to the next page; no-op on the last page.
|
||||||
|
*/
|
||||||
|
nextPage(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advances the typewriter scroll by one tick.
|
||||||
|
* Call once per frame before `draw()`.
|
||||||
|
*/
|
||||||
|
update(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the frame and currently visible text.
|
||||||
|
* Call once per frame after `update()`.
|
||||||
|
*/
|
||||||
|
draw(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the input action that auto-advances the textbox when held.
|
||||||
|
* @param action - An `INPUT_ACTION_*` constant.
|
||||||
|
*/
|
||||||
|
setAdvanceAction(action: InputAction): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var UITextbox: UITextboxNamespace;
|
||||||
Reference in New Issue
Block a user