/**
* @module control-flow
*/
/**
* Creates a spawn trigger and returns it
* @param {group} group group to be spawned
* @param {number} time delay to spawn group
* @returns {object}
*/
let spawn_trigger = (group, time = 0) => {
return trigger({
OBJ_ID: 1268,
SPAWN_DURATION: time,
TARGET: group,
});
};
let frame_loop_setup = () => {
let empty_tfn = trigger_function(_ => {});
let trig_fn = trigger_function(() => {
let move_g = unknown_g();
let frame_loop1 = unknown_b();
let frame_loop2 = unknown_b();
// col 1
$.add(object({
OBJ_ID: obj_ids.special.COLLISION_BLOCK,
BLOCK_A: frame_loop1,
X: -150,
Y: 15,
DYNAMIC_BLOCK: true
}));
// col 2
$.add(object({
OBJ_ID: obj_ids.special.COLLISION_BLOCK,
BLOCK_A: frame_loop2,
X: -150,
Y: 50,
GROUPS: move_g,
DYNAMIC_BLOCK: true
}));
on(collision(frame_loop1, frame_loop2), trigger_function(() => {
move_g.toggle_off();
empty_tfn.call();
}));
on(collision_exit(frame_loop1, frame_loop2), trigger_function(() => {
move_g.toggle_on();
empty_tfn.call();
}));
move_g.move(0, -10); // start loop
});
trig_fn.call();
return { trig_fn, empty_tfn };
};
let fl_setup;
/**
* Creates a loop that repeats every tick
* @param {group} trigger_function The group to call every tick
* @returns {group} Group that can be used to stop the loop
*/
let frame_loop = (tfn) => {
if (!fl_setup) fl_setup = frame_loop_setup();
$.extend_trigger_func(fl_setup.empty_tfn, () => {
tfn.call();
});
return fl_setup.trig_fn;
};
/**
* Waits a specific amount of ticks
* @param {number} frames How many ticks to wait for
*/
let frames = (frames) => {
let id = crypto.randomUUID();
let oldContext = Context.current;
let newContext = new Context(id);
let frame_c = counter();
let loop = frame_loop(trigger_function(() => {
frame_c.add(1);
}));
on(count(frame_c.item, frames), trigger_function(() => {
loop.stop();
newContext.group.call();
}));
Context.set(id);
Context.link(oldContext);
}
let rfl_setup = () => {
let enter_group = trigger_function(() => {});
let blockA = unknown_b();
let blockB = unknown_b();
let center = unknown_g();
let target = unknown_g();
// collision blocks
blockA.collision_block(-135, 135).with(obj_props.SCALING, 0.25).with(obj_props.GROUPS, target).add();
blockB.collision_block(-135, 105).with(obj_props.SCALING, 0.25).with(obj_props.GROUPS, center).with(obj_props.DYNAMIC_BLOCK, true).add();
// center
object({
OBJ_ID: 3807,
X: -135,
Y: 105,
GROUPS: center,
GROUP_PARENTS: center
}).add();
let area = trigger({
OBJ_ID: 3006,
155: 1,
36: 1,
222: 30000,
218: -30000,
243: 2,
249: 2,
287: 1,
TARGET: target,
CENTER: center,
263: 1,
264: 1,
276: 1,
10: 0.5
});
area.add();
let move_loop = trigger_function(() => {
move_trigger(center, -2400, 0).with(obj_props.SILENT, true).add();
ignore_context_change(() => center.move(2400, 0, 1));
$.trigger_fn_context().call(1);
});
let timer_cycle = trigger_function(() => {
timer(0, 1, $.trigger_fn_context(), false, false, true, 240).start();
blockA.if_colliding(blockB, enter_group);
});
move_loop.call();
timer_cycle.call();
return { enter_group, timer_cycle };
}
let g_setup;
/**
* Creates a loop that repeats every render frame (different from ticks, which are a constant of 1/240 seconds, while render frames are variable and can be changed in settings)
* @param {group} trigger_function The group to call every frame
* @returns {group} Group that can be used to stop the loop
*/
let render_frame_loop = (fn) => {
if (!g_setup) g_setup = rfl_setup();
$.extend_trigger_func(g_setup.enter_group, () => {
fn.call();
});
return g_setup.timer_cycle;
}
/**
* Waits a specific amount of render frames
* @param {number} frames How many frames to wait for
*/
let render_frames = (frames) => {
let id = crypto.randomUUID();
let oldContext = Context.current;
let newContext = new Context(id);
let frame_c = counter();
frame_c.display(135, 75);
let loop = render_frame_loop(trigger_function(() => {
frame_c.add(1);
}));
on(count(frame_c.item, frames), trigger_function(() => {
loop.stop();
newContext.group.call();
}));
Context.set(id);
Context.link(oldContext);
}
/**
* Returns a greater than condition
* @param {counter} counter Counter to compare to number
* @param {number} other Number to be compared to counter
* @returns {condition}
*/
let greater_than = (count, other) => ({
count,
comparison: GREATER,
other,
});
/**
* Returns a equal to condition
* @param {counter} counter Counter to compare to number
* @param {number} other Number to be compared to counter
* @returns {condition}
*/
let equal_to = (count, other) => ({ count, comparison: EQ, other });
/**
* Returns a less than condition
* @param {counter} counter Counter to compare to number
* @param {number} other Number to be compared to counter
* @returns {condition}
*/
let less_than = (count, other) => ({ count, comparison: LESS, other });
/**
* Calls a group with a delay
* @param {number} delay How much to delay by
* @param {group} group Group to call
*/
let call_with_delay = (time, func) => {
$.add(trigger({
OBJ_ID: 1268,
SPAWN_DURATION: time,
TARGET: func,
}));
};
/**
* Implementation of sequence trigger
* @param {array} sequence Sequence of groups to be called (e.g. [[group(1), 1], [group(2), 1]] is a valid input)
* @param {number} [mode=0] Mode of sequence trigger (0 = stop, 1 = loop, 2 = last)
* @param {number} [min_int=0] MinInt of sequence trigger
* @param {number} [reset=0] Reset of sequence trigger (0 = full, 1 = step)
* @returns {function} Function that steps through the sequence once
*/
let sequence = (sequence, mode = 0, min_int = 0, reset = 0) => {
let seq_gr = trigger_function(() => {
$.add(trigger({
OBJ_ID: 3607,
SEQUENCE: sequence.map(x => x[0].value + '.' + x[1]).join('.'),
MIN_INT: min_int,
RESET: reset,
MODE: mode
}));
});
return () => seq_gr.call()
};
/**
* Creates trigger function-like systems, but can be called normally with item IDs as arguments (e.g. a remappable can be called like `my_remappable(counter1.item)`)
* @param {function} fn Function that remappable uses
* @returns {function} Function to call
*/
let remappable = (fn) => {
let args_arr = Array(fn.length).fill(0).map((_, i) => i);
let r = trigger_function(() => fn(...args_arr));
return (...args) => {
// remap fn_args to args
let rmps = [];
args.forEach((x, i) => rmps.push([args_arr[i], args[i]]));
r.remap(...rmps).call();
};
}
/**
* Loops a function a specific amount of times (defined by range)
* @param {array} range Range of numbers defining how many times to loop fn by
* @param {function} fn Function to loop
* @param {number} [delay=0.05] How much to delay between cycle
*/
let for_loop = (rang, fn, delay = 0.05) => {
let c = counter(rang[0]);
while_loop(less_than(c, rang[rang.length - 1] + 1), () => {
fn();
c.add(1);
}, delay);
};
module.exports = { remappable, sequence, call_with_delay, equal_to, less_than, greater_than, for_loop, spawn_trigger, frame_loop, frames, render_frame_loop, render_frames }