// SPDX-FileCopyrightText: In 2019, Chris Pressey, the original author of this work, placed it into the public domain.
// SPDX-License-Identifier: Unlicense
// For more information, please refer to <https://unlicense.org/>
import { bless } from '../contrib/concoctor-0.2/concoctor.js';
import { concoctJaft as concoct } from '../contrib/jaft-0.2/jaftConcoctor.js';
import { get, setr, update } from './immutable.js';
/* --[ Constants ]---------------------------------------------------------------- */
const screenWidth = bless(() => 640);
const screenHeight = bless(() => 400);
/* --[ Utility functions ]-------------------------------------------------------- */
const isUndefined = bless((x) => typeof x === 'undefined');
// FIXME: obviously, this is not pure. However,
// for our purposes it is an "acceptable effect".
// Our eventual solution will be to have concoctor track
// a set of effects (instead of just "was produced by
// concoctor"), and error out if the result has any
// effects that are deemed unacceptable.
const error = bless(function(msg, arg) {
throw new Error(msg + ": " + arg);
});
const newNull = bless(() => null);
const not = bless((b) => !b);
const pi = bless((n) => Math.PI * n);
const abs = bless((n) => Math.abs(n));
const cos = bless((n) => Math.cos(n));
const sin = bless((n) => Math.sin(n));
const floor = bless((n) => Math.floor(n));
// FIXME: again, obviously not pure. See above.
const random = bless(() => Math.random());
const decr = concoct({}, `(x) => x - 1`);
const incr = concoct({}, `(x) => x + 1`);
const degreesToRadians = concoct({ pi }, `(deg) =>
(deg / 360) * pi(2)
`);
const sign = concoct({}, `(n) =>
(n > 0) ? 1 : (0 > n) ? (0 - 1) : 0
`);
const cap = concoct({ abs, sign }, `(n, absMax) =>
(abs(n) > absMax) ? absMax * sign(n) : n
`);
const limitWithin = concoct({}, `(low, high, v) =>
const range = high - low;
((((v - low) % range) + range) % range) + low
`);
const updatePosition = concoct({ setr, get, limitWithin, screenWidth, screenHeight }, `(obj) =>
const x = get(obj, "x"), y = get(obj, "y"), vx = get(obj, "vx"), vy = get(obj, "vy");
setr("x", limitWithin(0, screenWidth(), x + vx),
setr("y", limitWithin(0, screenHeight(), y + vy), obj))
`);
const countDown = concoct({ update, decr, get }, `(obj, callback) =>
const obj2 = update(obj, "timer", decr);
get(obj2, "timer") <= 0 ? callback(obj2) : obj2
`, { signature: ["object", "function"] });
// FIXME we could rewrite in terms of countDown, eventually
const countDownToMode = concoct({ update, decr, get, setr }, `(obj, toMode) =>
const obj2 = update(obj, "timer", decr);
(get(obj2, "timer") <= 0) ? setr("mode", toMode, obj2) : obj2
`);
const fireWentDown = concoct({ not }, `(action) =>
not(action.prev.firePressed) && action.firePressed
`);
const fireWentUp = concoct({ not }, `(action) =>
action.prev.firePressed && not(action.firePressed)
`);
const makeAction = bless((t) => ({ type: t }));
export {
screenWidth, screenHeight,
isUndefined, not, error, newNull,
abs, cos, sin, degreesToRadians, floor, random, sign, cap, limitWithin,
updatePosition,
decr, incr, countDown, countDownToMode, fireWentDown, fireWentUp,
makeAction
}