Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e98abcdda7 |
@@ -1,8 +0,0 @@
|
||||
[dependencies]
|
||||
extramath = "https://gitea.pockle.world/john/extramath@master"
|
||||
|
||||
[system]
|
||||
ar_timer = 60 # seconds before idle actor reclamation
|
||||
actor_memory = 0 # MB of memory an actor can use; 0 for unbounded
|
||||
net_service = 0.1 # seconds per net service pull
|
||||
reply_timeout = 60 # seconds to hold callback for reply messages; 0 for unbounded
|
||||
@@ -1,6 +0,0 @@
|
||||
[modules]
|
||||
[modules.extramath]
|
||||
hash = "MCLZT3JABTAENS4WVXKGWJ7JPBLZER4YQ5VN2PE7ZD2Z4WYGTIMA===="
|
||||
url = "https://gitea.pockle.world/john/extramath@master"
|
||||
downloaded = "Monday June 2 12:07:20.42 PM -5 2025 AD"
|
||||
commit = "84d81a19a8455bcf8dc494739e9e6d545df6ff2c"
|
||||
13
.gitignore
vendored
@@ -6,18 +6,27 @@ build/
|
||||
*.o
|
||||
*.a
|
||||
*.d
|
||||
tags
|
||||
Jenkinsfile
|
||||
*~
|
||||
*.log
|
||||
*.gz
|
||||
*.tar
|
||||
.nova/
|
||||
packer*
|
||||
primum
|
||||
sokol-shdc*
|
||||
source/shaders/*.h
|
||||
core.cdb
|
||||
primum.exe
|
||||
core.cdb.h
|
||||
jsc
|
||||
.DS_Store
|
||||
*.html
|
||||
.vscode
|
||||
*.icns
|
||||
game.zip
|
||||
icon.ico
|
||||
steam/
|
||||
subprojects/*/
|
||||
build_dbg/
|
||||
modules/
|
||||
build_dbg/
|
||||
20
.moth/log
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"console": {
|
||||
"outputs": ["console"]
|
||||
},
|
||||
"info": {
|
||||
"outputs": ["file:logs/info.log"]
|
||||
},
|
||||
"warning": {
|
||||
"outputs": ["console", "file:logs/warnings.log"]
|
||||
},
|
||||
"error": {
|
||||
"outputs": ["console", "file:logs/errors.log", "actor:localhost:5678"]
|
||||
},
|
||||
"debug": {
|
||||
"outputs": ["file:logs/debug.log"]
|
||||
},
|
||||
"audit": {
|
||||
"outputs": ["file:logs/audit.log", "actor:audit-server:9000"]
|
||||
}
|
||||
}
|
||||
21
CLAUDE.md
@@ -5,7 +5,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
## Build Commands
|
||||
|
||||
### Build variants
|
||||
- `make` - Make and install debug version. Usually all that's needed.
|
||||
- `make debug` - Build debug version (uses meson debug configuration)
|
||||
- `make fast` - Build optimized version
|
||||
- `make release` - Build release version with LTO and optimizations
|
||||
- `make small` - Build minimal size version
|
||||
@@ -13,10 +13,10 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
- `make crosswin` - Cross-compile for Windows using mingw32
|
||||
|
||||
### Testing
|
||||
After install with 'make', just run 'cell' and point it at the actor you want to launch. "cell tests/toml" runs the actor "tests/toml.js"
|
||||
|
||||
## Scripting language
|
||||
This is called "cell", but it is is a variant of javascript and extremely similar.
|
||||
- `meson test -C build_dbg` - Run all tests in debug build
|
||||
- `meson test -C build_<variant>` - Run tests in specific build variant
|
||||
- `./build_dbg/prosperon tests/<testname>.js` - Run specific test
|
||||
- Available tests: `spawn_actor`, `empty`, `nota`, `wota`, `portalspawner`, `overling`, `send`, `delay`
|
||||
|
||||
### Common development commands
|
||||
- `meson setup build_<variant>` - Configure build directory
|
||||
@@ -126,7 +126,7 @@ meson test -C build_dbg
|
||||
### Debugging
|
||||
- Use debug build: `make debug`
|
||||
- Tracy profiler support when enabled
|
||||
- Console logging available via `log.console()`, `log.error()`, etc.
|
||||
- Console logging available via `console.log()`, `console.error()`, etc.
|
||||
- Log files written to `.prosperon/log.txt`
|
||||
|
||||
# Project Structure Notes
|
||||
@@ -202,11 +202,6 @@ meson test -C build_dbg
|
||||
|
||||
### Utility Modules
|
||||
- `time` - Time management and delays
|
||||
- **Must be imported with `use('time')`**
|
||||
- No `time.now()` function - use:
|
||||
- `time.number()` - Number representation of current time
|
||||
- `time.record()` - Struct representation of current time
|
||||
- `time.text()` - Text representation of current time
|
||||
- `io` - File I/O operations
|
||||
- `json` - JSON parsing and serialization
|
||||
- `util` - General utilities
|
||||
@@ -239,7 +234,7 @@ When sending a message with a callback, respond by sending to the message itself
|
||||
```javascript
|
||||
// Sender side:
|
||||
send(actor, {type: 'status'}, response => {
|
||||
log.console(response); // Handle the response
|
||||
console.log(response); // Handle the response
|
||||
});
|
||||
|
||||
// Receiver side:
|
||||
@@ -284,7 +279,7 @@ $_.receiver(msg => {
|
||||
- Custom formats: Aseprite animations, etc.
|
||||
|
||||
### Developer Tools
|
||||
- Built-in documentation system with `cell.DOC`
|
||||
- Built-in documentation system with `prosperon.DOC`
|
||||
- Tracy profiler integration for performance monitoring
|
||||
- Imgui debugging tools
|
||||
- Console logging with various severity levels
|
||||
|
||||
10
Makefile
@@ -1,22 +1,22 @@
|
||||
debug: FORCE
|
||||
meson setup build_dbg -Dbuildtype=debug
|
||||
meson install --only-changed -C build_dbg
|
||||
meson compile -C build_dbg
|
||||
|
||||
fast: FORCE
|
||||
meson setup build_fast
|
||||
meson install -C build_fast
|
||||
meson compile -C build_fast
|
||||
|
||||
release: FORCE
|
||||
meson setup -Dbuildtype=release -Db_lto=true -Db_lto_mode=thin -Db_ndebug=true build_release
|
||||
meson install -C build_release
|
||||
meson compile -C build_release
|
||||
|
||||
sanitize: FORCE
|
||||
meson setup -Db_sanitize=address -Db_sanitize=memory -Db_sanitize=leak -Db_sanitize=undefined build_sani
|
||||
meson install -C build_sani
|
||||
meson compile -C build_sani
|
||||
|
||||
small: FORCE
|
||||
meson setup -Dbuildtype=minsize -Db_lto=true -Db_ndebug=true build_small
|
||||
meson install -C build_small
|
||||
meson compile -C build_small
|
||||
|
||||
web: FORCE
|
||||
meson setup -Deditor=false -Dbuildtype=minsize -Db_lto=true -Db_ndebug=true --cross-file emscripten.cross build_web
|
||||
|
||||
@@ -49,28 +49,28 @@ function getStats(arr) {
|
||||
}
|
||||
|
||||
// Pretty print results
|
||||
log.console("\n=== Performance Test Results (100 iterations) ===");
|
||||
log.console("\nJSON Decoding (ms):");
|
||||
console.log("\n=== Performance Test Results (100 iterations) ===");
|
||||
console.log("\nJSON Decoding (ms):");
|
||||
const jsonDecStats = getStats(jsonDecodeTimes);
|
||||
log.console(`Average: ${jsonDecStats.avg.toFixed(2)} ms`);
|
||||
log.console(`Min: ${jsonDecStats.min.toFixed(2)} ms`);
|
||||
log.console(`Max: ${jsonDecStats.max.toFixed(2)} ms`);
|
||||
console.log(`Average: ${jsonDecStats.avg.toFixed(2)} ms`);
|
||||
console.log(`Min: ${jsonDecStats.min.toFixed(2)} ms`);
|
||||
console.log(`Max: ${jsonDecStats.max.toFixed(2)} ms`);
|
||||
|
||||
log.console("\nJSON Encoding (ms):");
|
||||
console.log("\nJSON Encoding (ms):");
|
||||
const jsonEncStats = getStats(jsonEncodeTimes);
|
||||
log.console(`Average: ${jsonEncStats.avg.toFixed(2)} ms`);
|
||||
log.console(`Min: ${jsonEncStats.min.toFixed(2)} ms`);
|
||||
log.console(`Max: ${jsonEncStats.max.toFixed(2)} ms`);
|
||||
console.log(`Average: ${jsonEncStats.avg.toFixed(2)} ms`);
|
||||
console.log(`Min: ${jsonEncStats.min.toFixed(2)} ms`);
|
||||
console.log(`Max: ${jsonEncStats.max.toFixed(2)} ms`);
|
||||
|
||||
log.console("\nNOTA Encoding (ms):");
|
||||
console.log("\nNOTA Encoding (ms):");
|
||||
const notaEncStats = getStats(notaEncodeTimes);
|
||||
log.console(`Average: ${notaEncStats.avg.toFixed(2)} ms`);
|
||||
log.console(`Min: ${notaEncStats.min.toFixed(2)} ms`);
|
||||
log.console(`Max: ${notaEncStats.max.toFixed(2)} ms`);
|
||||
console.log(`Average: ${notaEncStats.avg.toFixed(2)} ms`);
|
||||
console.log(`Min: ${notaEncStats.min.toFixed(2)} ms`);
|
||||
console.log(`Max: ${notaEncStats.max.toFixed(2)} ms`);
|
||||
|
||||
log.console("\nNOTA Decoding (ms):");
|
||||
console.log("\nNOTA Decoding (ms):");
|
||||
const notaDecStats = getStats(notaDecodeTimes);
|
||||
log.console(`Average: ${notaDecStats.avg.toFixed(2)} ms`);
|
||||
log.console(`Min: ${notaDecStats.min.toFixed(2)} ms`);
|
||||
log.console(`Max: ${notaDecStats.max.toFixed(2)} ms`);
|
||||
console.log(`Average: ${notaDecStats.avg.toFixed(2)} ms`);
|
||||
console.log(`Min: ${notaDecStats.min.toFixed(2)} ms`);
|
||||
console.log(`Max: ${notaDecStats.max.toFixed(2)} ms`);
|
||||
|
||||
@@ -75,8 +75,8 @@ const benchmarks = [
|
||||
];
|
||||
|
||||
// Print a header
|
||||
log.console("Wota Encode/Decode Benchmark");
|
||||
log.console("============================\n");
|
||||
console.log("Wota Encode/Decode Benchmark");
|
||||
console.log("============================\n");
|
||||
|
||||
// We'll run each benchmark scenario in turn.
|
||||
for (let bench of benchmarks) {
|
||||
@@ -96,11 +96,11 @@ for (let bench of benchmarks) {
|
||||
let elapsedSec = measureTime(runAllData, bench.iterations);
|
||||
let opsPerSec = (totalIterations / elapsedSec).toFixed(1);
|
||||
|
||||
log.console(`${bench.name}:`);
|
||||
log.console(` Iterations: ${bench.iterations} × ${bench.data.length} data items = ${totalIterations}`);
|
||||
log.console(` Elapsed: ${elapsedSec.toFixed(3)} s`);
|
||||
log.console(` Throughput: ${opsPerSec} encode+decode ops/sec\n`);
|
||||
console.log(`${bench.name}:`);
|
||||
console.log(` Iterations: ${bench.iterations} × ${bench.data.length} data items = ${totalIterations}`);
|
||||
console.log(` Elapsed: ${elapsedSec.toFixed(3)} s`);
|
||||
console.log(` Throughput: ${opsPerSec} encode+decode ops/sec\n`);
|
||||
}
|
||||
|
||||
// All done
|
||||
log.console("Benchmark completed.\n");
|
||||
console.log("Benchmark completed.\n");
|
||||
@@ -53,11 +53,6 @@ const libraries = [
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const benchmarks = [
|
||||
{
|
||||
name: "Empty object",
|
||||
data: [{}, {}, {}, {}],
|
||||
iterations: 10000
|
||||
},
|
||||
{
|
||||
name: "Small Integers",
|
||||
data: [0, 42, -1, 2023],
|
||||
@@ -130,8 +125,8 @@ function runBenchmarkForLibrary(lib, bench) {
|
||||
let encodeTime = measureTime(() => {
|
||||
for (let i = 0; i < bench.iterations; i++) {
|
||||
// For each data item, encode it
|
||||
for (let j = 0; j < bench.data.length; j++) {
|
||||
let e = lib.encode(bench.data[j]);
|
||||
for (let d of bench.data) {
|
||||
let e = lib.encode(d);
|
||||
// store only in the very first iteration, so we can decode them later
|
||||
// but do not store them every iteration or we blow up memory.
|
||||
if (i === 0) {
|
||||
@@ -160,12 +155,12 @@ function runBenchmarkForLibrary(lib, bench) {
|
||||
// 5. Main driver: run across all benchmarks, for each library.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
log.console("Benchmark: Wota vs Nota vs JSON");
|
||||
log.console("================================\n");
|
||||
console.log("Benchmark: Wota vs Nota vs JSON");
|
||||
console.log("================================\n");
|
||||
|
||||
for (let bench of benchmarks) {
|
||||
log.console(`SCENARIO: ${bench.name}`);
|
||||
log.console(` Data length: ${bench.data.length} | Iterations: ${bench.iterations}\n`);
|
||||
console.log(`SCENARIO: ${bench.name}`);
|
||||
console.log(` Data length: ${bench.data.length} | Iterations: ${bench.iterations}\n`);
|
||||
|
||||
for (let lib of libraries) {
|
||||
let { encodeTime, decodeTime, totalSize } = runBenchmarkForLibrary(lib, bench);
|
||||
@@ -175,15 +170,13 @@ for (let bench of benchmarks) {
|
||||
let encOpsPerSec = (totalOps / encodeTime).toFixed(1);
|
||||
let decOpsPerSec = (totalOps / decodeTime).toFixed(1);
|
||||
|
||||
log.console(` ${lib.name}:`);
|
||||
log.console(` Encode time: ${encodeTime.toFixed(3)}s => ${encOpsPerSec} encodes/sec [${(encodeTime/bench.iterations)*1000000000} ns/try]`);
|
||||
log.console(` Decode time: ${decodeTime.toFixed(3)}s => ${decOpsPerSec} decodes/sec [${(decodeTime/bench.iterations)*1000000000}/try]`);
|
||||
log.console(` Total size: ${totalSize} bytes (or code units for JSON)`);
|
||||
log.console("");
|
||||
console.log(` ${lib.name}:`);
|
||||
console.log(` Encode time: ${encodeTime.toFixed(3)}s => ${encOpsPerSec} encodes/sec`);
|
||||
console.log(` Decode time: ${decodeTime.toFixed(3)}s => ${decOpsPerSec} decodes/sec`);
|
||||
console.log(` Total size: ${totalSize} bytes (or code units for JSON)`);
|
||||
console.log("");
|
||||
}
|
||||
log.console("---------------------------------------------------------\n");
|
||||
console.log("---------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
log.console("Benchmark complete.\n");
|
||||
|
||||
os.exit()
|
||||
console.log("Benchmark complete.\n");
|
||||
@@ -47,7 +47,7 @@ Certain functions are intrinsic to the program and cannot be overridden. They’
|
||||
- **Example**:
|
||||
```js
|
||||
this.delay(_ => {
|
||||
log.console("3 seconds later!")
|
||||
console.log("3 seconds later!")
|
||||
}, 3)
|
||||
```
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
|
||||
Provides a consistent way to create documentation for prosperon elements. Objects are documented by adding docstrings directly to object-like things (functions, objects, ...), or to an object's own "doc object".
|
||||
|
||||
Docstrings are set to the symbol `cell.DOC`
|
||||
Docstrings are set to the symbol `prosperon.DOC`
|
||||
|
||||
```js
|
||||
// Suppose we have a module that returns a function
|
||||
function greet(name) { log.console("Hello, " + name) }
|
||||
function greet(name) { console.log("Hello, " + name) }
|
||||
|
||||
// We can attach a docstring
|
||||
greet.doc = `
|
||||
@@ -21,12 +21,12 @@ return greet
|
||||
```js
|
||||
// Another way is to add a docstring object to an object
|
||||
var greet = {
|
||||
hello() { log.console('hello!') }
|
||||
hello() { console.log('hello!') }
|
||||
}
|
||||
|
||||
greet[cell.DOC] = {}
|
||||
greet[cell.DOC][cell.DOC] = 'An object full of different greeter functions'
|
||||
greet[cell.DOC].hello = 'A greeter that says, "hello!"'
|
||||
greet[prosperon.DOC] = {}
|
||||
greet[prosperon.DOC][prosperon.DOC] = 'An object full of different greeter functions'
|
||||
greet[prosperon.DOC].hello = 'A greeter that says, "hello!"'
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ return {
|
||||
This will cause prosperon to launch a 500x500 window with the title 'Hello World'. In your ```main.js```, write the following:
|
||||
|
||||
```
|
||||
log.console("Hello world")
|
||||
console.log("Hello world")
|
||||
|
||||
this.delay(_ => {
|
||||
this.kill();
|
||||
@@ -62,6 +62,6 @@ this.delay(_ => {
|
||||
The global object called `prosperon` has a variety of engine specific settings on it that can be set to influence how the engine behaves. For example, `prosperon.argv` contains a list of the command line arguments given to prosperon; `prosperon.PATH` is an array of paths to resolve resources such as modules and images. `prosperon` is fully documented in the API section.
|
||||
|
||||
## Getting help
|
||||
The `prosperon` global has a 'doc' function, which can be invoked on any engine object to see a description of it and its members. For example, to learn about `prosperon`, try printing out `cell.DOC(prosperon)` in your `main.js`.
|
||||
The `prosperon` global has a 'doc' function, which can be invoked on any engine object to see a description of it and its members. For example, to learn about `prosperon`, try printing out `prosperon.doc(prosperon)` in your `main.js`.
|
||||
|
||||
Writing documentation for your own modules and game components will be explored in the chapter on actors & modules.
|
||||
|
Before Width: | Height: | Size: 449 B After Width: | Height: | Size: 449 B |
@@ -5,7 +5,6 @@ var sprite = use('sprite')
|
||||
var geom = use('geometry')
|
||||
var input = use('controller')
|
||||
var config = use('config')
|
||||
var color = use('color')
|
||||
|
||||
var bunnyTex = graphics.texture("bunny")
|
||||
|
||||
@@ -66,5 +65,5 @@ this.hud = function() {
|
||||
draw.images(bunnyTex, bunnies)
|
||||
|
||||
var msg = 'FPS: ' + fpsAvg.toFixed(2) + ' Bunnies: ' + bunnies.length
|
||||
draw.text(msg, {x:0, y:0, width:config.width, height:40}, undefined, 0, color.white, 0)
|
||||
draw.text(msg, {x:0, y:0, width:config.width, height:40}, undefined, 0, Color.white, 0)
|
||||
}
|
||||
|
Before Width: | Height: | Size: 390 B After Width: | Height: | Size: 390 B |
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 438 B |
|
Before Width: | Height: | Size: 398 B After Width: | Height: | Size: 398 B |
|
Before Width: | Height: | Size: 337 B After Width: | Height: | Size: 337 B |
|
Before Width: | Height: | Size: 390 B After Width: | Height: | Size: 390 B |
|
Before Width: | Height: | Size: 379 B After Width: | Height: | Size: 379 B |
@@ -1,9 +1,16 @@
|
||||
/* main.js – runs the demo with your prototype-based grid */
|
||||
|
||||
var moth = use('moth', $_.delay)
|
||||
var json = use('json')
|
||||
var draw2d = use('prosperon/draw2d')
|
||||
|
||||
var blob = use('blob')
|
||||
var res = 160
|
||||
var internal_res = 480
|
||||
|
||||
moth.initialize({ width:res, height:res, resolution_x:internal_res, resolution_y:internal_res, mode:'letterbox' });
|
||||
|
||||
var os = use('os');
|
||||
var draw2d = use('draw2d');
|
||||
var gfx = use('graphics');
|
||||
|
||||
/*──── import our pieces + systems ───────────────────────────────────*/
|
||||
var Grid = use('grid'); // your new ctor
|
||||
@@ -48,7 +55,7 @@ function updateTitle() {
|
||||
break;
|
||||
}
|
||||
|
||||
log.console(title)
|
||||
prosperon.window.title = title
|
||||
}
|
||||
|
||||
// Initialize title
|
||||
@@ -63,7 +70,7 @@ var opponentMousePos = null;
|
||||
var opponentHoldingPiece = false;
|
||||
var opponentSelectPos = null;
|
||||
|
||||
function handleMouseButtonDown(e) {
|
||||
prosperon.on('mouse_button_down', function(e) {
|
||||
if (e.which !== 0) return;
|
||||
|
||||
// Don't allow piece selection unless we have an opponent
|
||||
@@ -89,9 +96,9 @@ function handleMouseButtonDown(e) {
|
||||
} else {
|
||||
selectPos = null;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function handleMouseButtonUp(e) {
|
||||
prosperon.on('mouse_button_up', function(e) {
|
||||
if (e.which !== 0 || !holdingPiece || !selectPos) return;
|
||||
|
||||
// Don't allow moves unless we have an opponent and it's our turn
|
||||
@@ -110,16 +117,16 @@ function handleMouseButtonUp(e) {
|
||||
}
|
||||
|
||||
if (mover.tryMove(grid.at(selectPos)[0], c)) {
|
||||
log.console("Made move from", selectPos, "to", c);
|
||||
console.log("Made move from", selectPos, "to", c);
|
||||
// Send move to opponent
|
||||
log.console("Sending move to opponent:", opponent);
|
||||
console.log("Sending move to opponent:", opponent);
|
||||
send(opponent, {
|
||||
type: 'move',
|
||||
from: selectPos,
|
||||
to: c
|
||||
});
|
||||
isMyTurn = false; // It's now opponent's turn
|
||||
log.console("Move sent, now opponent's turn");
|
||||
console.log("Move sent, now opponent's turn");
|
||||
selectPos = null;
|
||||
updateTitle();
|
||||
}
|
||||
@@ -132,9 +139,9 @@ function handleMouseButtonUp(e) {
|
||||
type: 'piece_drop'
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function handleMouseMotion(e) {
|
||||
prosperon.on('mouse_motion', function(e) {
|
||||
var mx = e.pos.x;
|
||||
var my = e.pos.y;
|
||||
|
||||
@@ -155,18 +162,7 @@ function handleMouseMotion(e) {
|
||||
selectPos: selectPos
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeyDown(e) {
|
||||
// S key - start server
|
||||
if (e.scancode === 22 && gameState === 'waiting') { // S key
|
||||
startServer();
|
||||
}
|
||||
// J key - join server
|
||||
else if (e.scancode === 13 && gameState === 'waiting') { // J key
|
||||
joinServer();
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/*──── drawing helpers ───────────────────────────────────────────────*/
|
||||
/* ── constants ─────────────────────────────────────────────────── */
|
||||
@@ -197,8 +193,7 @@ function drawBoard() {
|
||||
|
||||
draw2d.rectangle(
|
||||
{ x: x*S, y: y*S, width: S, height: S },
|
||||
{ thickness: 0 },
|
||||
{ color: color }
|
||||
{ thickness: 0, color: color }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -240,7 +235,7 @@ function drawPieces() {
|
||||
var r = { x: piece.coord[0]*S, y: piece.coord[1]*S,
|
||||
width:S, height:S };
|
||||
|
||||
draw2d.image(piece.sprite, r);
|
||||
draw2d.image(piece.sprite, r, 0, [0,0], [0,0], {mode:"nearest"});
|
||||
});
|
||||
|
||||
// Draw the held piece at the mouse position if we're holding one
|
||||
@@ -250,7 +245,7 @@ function drawPieces() {
|
||||
var r = { x: hoverPos[0]*S, y: hoverPos[1]*S,
|
||||
width:S, height:S };
|
||||
|
||||
draw2d.image(piece.sprite, r);
|
||||
draw2d.image(piece.sprite, r, 0, [0,0], [0,0], {mode:"nearest"});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,25 +257,29 @@ function drawPieces() {
|
||||
width:S, height:S };
|
||||
|
||||
// Draw with slight transparency to show it's the opponent's piece
|
||||
draw2d.image(opponentPiece.sprite, r);
|
||||
draw2d.image(opponentPiece.sprite, r, 0, [0,0], [0,0], {mode:"nearest", color: [1, 1, 1, 0.7]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function update(dt)
|
||||
{
|
||||
return {}
|
||||
}
|
||||
var graphics = use('graphics')
|
||||
|
||||
function draw()
|
||||
{
|
||||
draw2d.clear()
|
||||
prosperon.on('draw', function() {
|
||||
drawBoard()
|
||||
drawPieces()
|
||||
draw2d.text("HELL", {x: 100, y: 100}, 'fonts/c64.ttf', 16, [1,1,1,1])
|
||||
return draw2d.get_commands()
|
||||
}
|
||||
draw2d.text("HELL", [100,100])
|
||||
})
|
||||
|
||||
prosperon.on('key_down', function(e) {
|
||||
// S key - start server
|
||||
if (e.scancode === 22 && gameState === 'waiting') { // S key
|
||||
startServer();
|
||||
}
|
||||
// J key - join server
|
||||
else if (e.scancode === 13 && gameState === 'waiting') { // J key
|
||||
joinServer();
|
||||
}
|
||||
})
|
||||
|
||||
function startServer() {
|
||||
gameState = 'server_waiting';
|
||||
@@ -290,11 +289,11 @@ function startServer() {
|
||||
updateTitle();
|
||||
|
||||
$_.portal(e => {
|
||||
log.console("Portal received contact message");
|
||||
console.log("Portal received contact message");
|
||||
// Reply with this actor to establish connection
|
||||
log.console (json.encode($_))
|
||||
console.log (json.encode($_))
|
||||
send(e, $_);
|
||||
log.console("Portal replied with server actor");
|
||||
console.log("Portal replied with server actor");
|
||||
}, 5678);
|
||||
}
|
||||
|
||||
@@ -303,10 +302,10 @@ function joinServer() {
|
||||
updateTitle();
|
||||
|
||||
function contact_fn(actor, reason) {
|
||||
log.console("CONTACTED!", actor ? "SUCCESS" : "FAILED", reason);
|
||||
console.log("CONTACTED!", actor ? "SUCCESS" : "FAILED", reason);
|
||||
if (actor) {
|
||||
opponent = actor;
|
||||
log.console("Connection established with server, sending join request");
|
||||
console.log("Connection established with server, sending join request");
|
||||
|
||||
// Send a greet message with our actor object
|
||||
send(opponent, {
|
||||
@@ -314,7 +313,7 @@ function joinServer() {
|
||||
client_actor: $_
|
||||
});
|
||||
} else {
|
||||
log.console(`Failed to connect: ${json.encode(reason)}`);
|
||||
console.log(`Failed to connect: ${json.encode(reason)}`);
|
||||
gameState = 'waiting';
|
||||
updateTitle();
|
||||
}
|
||||
@@ -326,38 +325,51 @@ function joinServer() {
|
||||
});
|
||||
}
|
||||
|
||||
var os = use('os')
|
||||
var actor = use('actor')
|
||||
for (var i in actor) console.log(i)
|
||||
|
||||
// Set up IO actor subscription
|
||||
var ioguy = {
|
||||
__ACTORDATA__: {
|
||||
id: actor.ioactor()
|
||||
}
|
||||
};
|
||||
|
||||
send(ioguy, {
|
||||
type: "subscribe",
|
||||
actor: $_
|
||||
});
|
||||
|
||||
$_.receiver(e => {
|
||||
if (e.kind == 'update')
|
||||
send(e, update(e.dt))
|
||||
else if (e.kind == 'draw')
|
||||
send(e, draw())
|
||||
else if (e.type === 'game_start' || e.type === 'move' || e.type === 'greet')
|
||||
log.console("Receiver got message:", e.type, e);
|
||||
if (e.type === 'game_start' || e.type === 'move' || e.type === 'greet')
|
||||
console.log("Receiver got message:", e.type, e);
|
||||
if (e.type === 'quit') os.exit()
|
||||
|
||||
if (e.type === 'greet') {
|
||||
log.console("Server received greet from client");
|
||||
console.log("Server received greet from client");
|
||||
// Store the client's actor object for ongoing communication
|
||||
opponent = e.client_actor;
|
||||
log.console("Stored client actor:", json.encode(opponent));
|
||||
console.log("Stored client actor:", json.encode(opponent));
|
||||
gameState = 'connected';
|
||||
updateTitle();
|
||||
|
||||
// Send game_start to the client
|
||||
log.console("Sending game_start to client");
|
||||
console.log("Sending game_start to client");
|
||||
send(opponent, {
|
||||
type: 'game_start',
|
||||
your_color: 'black'
|
||||
});
|
||||
log.console("game_start message sent to client");
|
||||
console.log("game_start message sent to client");
|
||||
}
|
||||
else if (e.type === 'game_start') {
|
||||
log.console("Game starting, I am:", e.your_color);
|
||||
console.log("Game starting, I am:", e.your_color);
|
||||
myColor = e.your_color;
|
||||
isMyTurn = (myColor === 'white');
|
||||
gameState = 'connected';
|
||||
updateTitle();
|
||||
} else if (e.type === 'move') {
|
||||
log.console("Received move from opponent:", e.from, "to", e.to);
|
||||
console.log("Received move from opponent:", e.from, "to", e.to);
|
||||
// Apply opponent's move
|
||||
var fromCell = grid.at(e.from);
|
||||
if (fromCell.length) {
|
||||
@@ -365,12 +377,12 @@ $_.receiver(e => {
|
||||
if (mover.tryMove(piece, e.to)) {
|
||||
isMyTurn = true; // It's now our turn
|
||||
updateTitle();
|
||||
log.console("Applied opponent move, now my turn");
|
||||
console.log("Applied opponent move, now my turn");
|
||||
} else {
|
||||
log.console("Failed to apply opponent move");
|
||||
console.log("Failed to apply opponent move");
|
||||
}
|
||||
} else {
|
||||
log.console("No piece found at from position");
|
||||
console.log("No piece found at from position");
|
||||
}
|
||||
} else if (e.type === 'mouse_move') {
|
||||
// Update opponent's mouse position
|
||||
@@ -385,13 +397,7 @@ $_.receiver(e => {
|
||||
// Opponent dropped their piece
|
||||
opponentHoldingPiece = false;
|
||||
opponentSelectPos = null;
|
||||
} else if (e.type === 'mouse_button_down') {
|
||||
handleMouseButtonDown(e)
|
||||
} else if (e.type === 'mouse_button_up') {
|
||||
handleMouseButtonUp(e)
|
||||
} else if (e.type === 'mouse_motion') {
|
||||
handleMouseMotion(e)
|
||||
} else if (e.type === 'key_down') {
|
||||
handleKeyDown(e)
|
||||
}
|
||||
})
|
||||
|
||||
prosperon.dispatch(e.type, e)
|
||||
})
|
||||
|
Before Width: | Height: | Size: 376 B After Width: | Height: | Size: 376 B |
|
Before Width: | Height: | Size: 403 B After Width: | Height: | Size: 403 B |
|
Before Width: | Height: | Size: 381 B After Width: | Height: | Size: 381 B |
|
Before Width: | Height: | Size: 313 B After Width: | Height: | Size: 313 B |
|
Before Width: | Height: | Size: 378 B After Width: | Height: | Size: 378 B |
|
Before Width: | Height: | Size: 378 B After Width: | Height: | Size: 378 B |
@@ -101,7 +101,7 @@ $_.receiver(function(msg) {
|
||||
break;
|
||||
|
||||
case 'status':
|
||||
log.console(`got status request. current is ${json.encode(get_status())}`)
|
||||
console.log(`got status request. current is ${json.encode(get_status())}`)
|
||||
send(msg, {
|
||||
type: 'status_response',
|
||||
...get_status()
|
||||
@@ -8,13 +8,13 @@ var waiting_client = null;
|
||||
var match_id = 0;
|
||||
|
||||
$_.portal(e => {
|
||||
log.console("NAT server: received connection request");
|
||||
console.log("NAT server: received connection request");
|
||||
|
||||
if (!is_actor(e.actor))
|
||||
send(e, {reason: "Must provide the actor you want to connect."});
|
||||
|
||||
if (waiting_client) {
|
||||
log.console(`sending out messages! to ${json.encode(e.actor)} and ${json.encode(waiting_client.actor)}`)
|
||||
console.log(`sending out messages! to ${json.encode(e.actor)} and ${json.encode(waiting_client.actor)}`)
|
||||
send(waiting_client, e.actor)
|
||||
send(e, waiting_client.actor)
|
||||
|
||||
@@ -25,5 +25,5 @@ $_.portal(e => {
|
||||
|
||||
waiting_client = e
|
||||
|
||||
log.console(`actor ${json.encode(e.actor)} is waiting ...`)
|
||||
console.log(`actor ${json.encode(e.actor)} is waiting ...`)
|
||||
}, 4000);
|
||||
@@ -1,11 +1,11 @@
|
||||
log.console(`nat client starting`)
|
||||
console.log(`nat client starting`)
|
||||
|
||||
$_.contact((actor, reason) => {
|
||||
if (actor) {
|
||||
log.console(`trying to message ${json.encode(actor)}`)
|
||||
console.log(`trying to message ${json.encode(actor)}`)
|
||||
send(actor, {type:"greet"})
|
||||
} else {
|
||||
log.console(json.encode(reason))
|
||||
console.log(json.encode(reason))
|
||||
}
|
||||
}, {
|
||||
address: "108.210.60.32", // NAT server's public IP
|
||||
@@ -16,7 +16,7 @@ $_.contact((actor, reason) => {
|
||||
$_.receiver(e => {
|
||||
switch(e.type) {
|
||||
case 'greet':
|
||||
log.console(`hello!`)
|
||||
console.log(`hello!`)
|
||||
break
|
||||
}
|
||||
})
|
||||
@@ -2,7 +2,6 @@
|
||||
var draw = use('draw2d')
|
||||
var input = use('controller')
|
||||
var config = use('config')
|
||||
var color = use('color')
|
||||
|
||||
prosperon.camera.transform.pos = [0,0]
|
||||
|
||||
@@ -74,13 +73,13 @@ this.hud = function() {
|
||||
draw.rectangle({x:0, y:0, width:config.width, height:config.height}, [0,0,0,1])
|
||||
|
||||
// Draw paddles
|
||||
draw.rectangle({x:p1.x - paddleW*0.5, y:p1.y - paddleH*0.5, width:paddleW, height:paddleH}, color.white)
|
||||
draw.rectangle({x:p2.x - paddleW*0.5, y:p2.y - paddleH*0.5, width:paddleW, height:paddleH}, color.white)
|
||||
draw.rectangle({x:p1.x - paddleW*0.5, y:p1.y - paddleH*0.5, width:paddleW, height:paddleH}, Color.white)
|
||||
draw.rectangle({x:p2.x - paddleW*0.5, y:p2.y - paddleH*0.5, width:paddleW, height:paddleH}, Color.white)
|
||||
|
||||
// Draw ball
|
||||
draw.rectangle({x:ball.x - ball.size*0.5, y:ball.y - ball.size*0.5, width:ball.size, height:ball.size}, color.white)
|
||||
draw.rectangle({x:ball.x - ball.size*0.5, y:ball.y - ball.size*0.5, width:ball.size, height:ball.size}, Color.white)
|
||||
|
||||
// Simple score display
|
||||
var msg = score1 + " " + score2
|
||||
draw.text(msg, {x:0, y:10, width:config.width, height:40}, undefined, 0, color.white, 0)
|
||||
draw.text(msg, {x:0, y:10, width:config.width, height:40}, undefined, 0, Color.white, 0)
|
||||
}
|
||||
@@ -4,7 +4,6 @@ var render = use('render')
|
||||
var graphics = use('graphics')
|
||||
var input = use('input')
|
||||
var config = use('config')
|
||||
var color = use('color')
|
||||
|
||||
prosperon.camera.transform.pos = [0,0]
|
||||
|
||||
@@ -84,15 +83,15 @@ this.hud = function() {
|
||||
// Draw snake
|
||||
for (var i=0; i<snake.length; i++) {
|
||||
var s = snake[i]
|
||||
draw.rectangle({x:s.x*cellSize, y:s.y*cellSize, width:cellSize, height:cellSize}, color.green)
|
||||
draw.rectangle({x:s.x*cellSize, y:s.y*cellSize, width:cellSize, height:cellSize}, Color.green)
|
||||
}
|
||||
|
||||
// Draw apple
|
||||
draw.rectangle({x:apple.x*cellSize, y:apple.y*cellSize, width:cellSize, height:cellSize}, color.red)
|
||||
draw.rectangle({x:apple.x*cellSize, y:apple.y*cellSize, width:cellSize, height:cellSize}, Color.red)
|
||||
|
||||
if (gameState === "gameover") {
|
||||
var msg = "GAME OVER! Press SPACE to restart."
|
||||
draw.text(msg, {x:0, y:config.height*0.5-10, width:config.width, height:20}, undefined, 0, color.white)
|
||||
draw.text(msg, {x:0, y:config.height*0.5-10, width:config.width, height:20}, undefined, 0, Color.white)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,23 +23,23 @@ var stats_loaded = false;
|
||||
// Initialize Steam
|
||||
function init_steam() {
|
||||
if (!steam) {
|
||||
log.console("Steam module not available");
|
||||
console.log("Steam module not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
log.console("Initializing Steam...");
|
||||
console.log("Initializing Steam...");
|
||||
steam_available = steam.steam_init();
|
||||
|
||||
if (steam_available) {
|
||||
log.console("Steam initialized successfully");
|
||||
console.log("Steam initialized successfully");
|
||||
|
||||
// Request current stats/achievements
|
||||
if (steam.stats.stats_request()) {
|
||||
log.console("Stats requested");
|
||||
console.log("Stats requested");
|
||||
stats_loaded = true;
|
||||
}
|
||||
} else {
|
||||
log.console("Failed to initialize Steam");
|
||||
console.log("Failed to initialize Steam");
|
||||
}
|
||||
|
||||
return steam_available;
|
||||
@@ -59,13 +59,13 @@ function unlock_achievement(achievement_name) {
|
||||
// Check if already unlocked
|
||||
var unlocked = steam.achievement.achievement_get(achievement_name);
|
||||
if (unlocked) {
|
||||
log.console("Achievement already unlocked:", achievement_name);
|
||||
console.log("Achievement already unlocked:", achievement_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Unlock it
|
||||
if (steam.achievement.achievement_set(achievement_name)) {
|
||||
log.console("Achievement unlocked:", achievement_name);
|
||||
console.log("Achievement unlocked:", achievement_name);
|
||||
|
||||
// Store stats to make it permanent
|
||||
steam.stats.stats_store();
|
||||
@@ -87,7 +87,7 @@ function update_stat(stat_name, value, is_float) {
|
||||
}
|
||||
|
||||
if (success) {
|
||||
log.console("Stat updated:", stat_name, "=", value);
|
||||
console.log("Stat updated:", stat_name, "=", value);
|
||||
steam.stats.stats_store();
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ function start_game() {
|
||||
total_score = get_stat(STATS.TOTAL_SCORE, false);
|
||||
current_score = 0;
|
||||
|
||||
log.console("Starting game #" + (games_played + 1));
|
||||
console.log("Starting game #" + (games_played + 1));
|
||||
}
|
||||
|
||||
function end_game(score) {
|
||||
@@ -167,7 +167,7 @@ function load_from_cloud() {
|
||||
function cleanup_steam() {
|
||||
if (steam_available) {
|
||||
steam.steam_shutdown();
|
||||
log.console("Steam shut down");
|
||||
console.log("Steam shut down");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
var draw = use('draw2d')
|
||||
var input = use('input')
|
||||
var config = use('config')
|
||||
var color = use('color')
|
||||
|
||||
prosperon.camera.transform.pos = [0,0]
|
||||
|
||||
@@ -249,7 +248,7 @@ this.hud = function() {
|
||||
}
|
||||
|
||||
// Next piece window
|
||||
draw.text("Next", {x:70, y:5, width:50, height:10}, undefined, 0, color.white)
|
||||
draw.text("Next", {x:70, y:5, width:50, height:10}, undefined, 0, Color.white)
|
||||
if (nextPiece) {
|
||||
for (var i=0; i<nextPiece.blocks.length; i++) {
|
||||
var nx = nextPiece.blocks[i][0]
|
||||
@@ -262,10 +261,10 @@ this.hud = function() {
|
||||
|
||||
// Score & Level
|
||||
var info = "Score: " + score + "\nLines: " + linesCleared + "\nLevel: " + level
|
||||
draw.text(info, {x:70, y:30, width:90, height:50}, undefined, 0, color.white)
|
||||
draw.text(info, {x:70, y:30, width:90, height:50}, undefined, 0, Color.white)
|
||||
|
||||
if (gameOver) {
|
||||
draw.text("GAME OVER", {x:10, y:config.height*0.5-5, width:config.width-20, height:20}, undefined, 0, color.red)
|
||||
draw.text("GAME OVER", {x:10, y:config.height*0.5-5, width:config.width-20, height:20}, undefined, 0, Color.red)
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 867 B After Width: | Height: | Size: 867 B |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |