Skip to content

Instantly share code, notes, and snippets.

@Akjosch
Last active May 21, 2020 11:02
Show Gist options
  • Save Akjosch/df444197e6ac9694f97487aa7b53878b to your computer and use it in GitHub Desktop.
Save Akjosch/df444197e6ac9694f97487aa7b53878b to your computer and use it in GitHub Desktop.
Random event engine for SugarCube/TweeGo
:: Backup Event [event]
/*
PRIORITY: Number.MIN_SAFE_INTEGER
*/
<div class="error-view"><span class="error">No valid events found. Write some?</span></div>
setup.GameEvent = (function() {
const _target = Symbol("target");
const _trigger = Symbol("trigger definition");
const _weight = Symbol("weight definition");
const _priority = Symbol("priority definition");
const _triggerFunc = Symbol("trigger function");
const _weightFunc = Symbol("weight function");
const _priorityFunc = Symbol("priority function");
class GameEvent {
/**
* @param {string} target
* @param {string=} trigger
* @param {string=} weight
* @param {string=} priority
*/
constructor(target, trigger, weight, priority) {
if(arguments.length < 1) {
throw new TypeError("Target has to be specified");
}
this[_target] = String(target);
if(!this[_target]) {
throw new TypeError("Target has to be a non-empty string");
}
this[_trigger] = trigger;
this[_weight] = weight;
this[_priority] = priority;
if(trigger) {
this[_triggerFunc] = new Function("c", "return !!(" + trigger + ")");
}
if(weight) {
this[_weightFunc] = new Function("c", "return Number(" + weight + ")");
}
if(priority) {
this[_priorityFunc] = new Function("c", "return Math.round(" + priority + ")");
}
}
get target() { return this[_target]; }
get trigger() { return this[_trigger]; }
get weight() { return this[_weight]; }
get priority() { return this[_priority]; }
/**
* @param {any=} context
* @returns {boolean} - true if the event is possible in this context
*/
isPossible(context) {
try {
return this[_triggerFunc] ? this[_triggerFunc](context || {}) : true;
} catch(ex) {
console.log(ex);
return false;
}
}
/**
* @param {any=} context
* @returns {number}
*/
calcWeight(context) {
try {
return this[_weightFunc] ? this[_weightFunc](context || {}) : 1.0;
} catch(ex) {
console.log(ex);
return 0.0;
}
}
/**
* @param {any=} context
* @returns {number}
*/
calcPriority(context) {
try {
return this[_priorityFunc] ? this[_priorityFunc](context || {}) : 0;
} catch(ex) {
console.log(ex);
return Number.MIN_SAFE_INTEGER;
}
}
}
return GameEvent;
})();
/**
* @property {GameEvent[]}
*/
setup.events = Story.lookup("tags", "event")
.map(function(p) {
var triggersRE = /^TRIGGER:\s*(\S.*?)$/m;
var weightsSE = /^WEIGHT:\s*(\S.*?)$/m;
var prioritiesSE = /^PRIORITY:\s*(\S.*?)$/m;
var trigger = triggersRE.exec(p.text);
var weight = weightsSE.exec(p.text);
var priority = prioritiesSE.exec(p.text);
return new setup.GameEvent(p.title, trigger ? trigger[1] : "", weight ? weight[1] : "", priority ? priority[1] : "");
});
/**
* Return an array of possible events and their current weights given the context.
* @param {any=} context
*/
setup.pickEvent = function(context) {
var possibleEvents = setup.events
.filter((ev) => ev.isPossible(context))
.map((ev) => ({ event: ev, weight: ev.calcWeight(context), prio: ev.calcPriority(context) }))
.sort((d1, d2) => (d1.prio - d2.prio));
if(possibleEvents.length > 0) {
const maxPrio = possibleEvents.last().prio;
possibleEvents = possibleEvents.filter((evData) => evData.prio === maxPrio);
}
return possibleEvents;
}
:: Orcs Attack! [event]
/*
TRIGGER: c.isNight() && c.partyHealth() > 25 && c.isAreaTag("wilderness") && c.isAreaTag("orc")
WEIGHT: 5 + (c.partyHealth() / 30)
PRIORITY: 0
*/
This is an example event.
/**
* @param {any[]} weights
* @param {() => number} [rnd]
*/
function weightedRandom(weights, rnd) {
if(!weights || !weights.length) {
return undefined;
}
rnd = rnd || Math.random;
var fallback = weights.last();
var pick = rnd() * weights.reduce((sum, ch) => sum + ch.weight, 0);
return (weights.find((ch) => (pick -= ch.weight) <= 0) || fallback);
}
setup.weightedRandom = weightedRandom;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment