diff --git a/src/events/debugEvent.js b/src/events/debugEvent.js new file mode 100644 index 0000000000000000000000000000000000000000..8af32bffca568150ba04abb0c00402a6e0740b21 --- /dev/null +++ b/src/events/debugEvent.js @@ -0,0 +1,79 @@ +/** @param {string} eventName + * @returns {DocumentFragment} + */ +App.Events.debugEvent = function(eventName) { + const frag = document.createDocumentFragment(); + /** @type {App.Events.BaseEvent} */ + const event = eval(`new ${eventName}`); + + function makeCastList() { + const cast = document.createDocumentFragment(); + const actorReqs = event.actorPrerequisites(); + let missingCast = false; + for (let i = 0; i < actorReqs.length; ++i) { + if (!event.actors[i]) { + missingCast = true; + } + App.UI.DOM.appendNewElement("div", cast, `Actor ${i}: ${event.actors[i] ? SlaveFullName(getSlave(event.actors[i])) : 'not yet cast'}`); + } + if (!missingCast) { + App.UI.DOM.appendNewElement("div", cast, App.UI.DOM.link('Run event now', (evt) => { V.event = evt; }, [event], "JS Random Event")); + } else { + App.UI.DOM.appendNewElement("div", cast, "All actors must be cast to run event.", "note"); + } + return cast; + } + + function castSlave(slave, index) { + event.actors[index] = slave.ID; + $('#castList').empty().append(makeCastList()); + } + + function testPredicate(outDiv, p, ...args) { + let passed = false; + try { + passed = p(...args); + } catch (ex) { + App.UI.DOM.appendNewElement("div", outDiv, p.name || p.toString() + ": Exception: " + ex.toString(), "major-warning"); + } + return passed; + } + + const prereqs = App.UI.DOM.appendNewElement("div", frag); + App.UI.DOM.appendNewElement("span", prereqs, `${eventName} - Global Prerequisites:`, "note"); + if (event instanceof App.Events.BaseEvent) { + let anyFailed = false; + for (const p of event.eventPrerequisites()) { + let passed = testPredicate(prereqs, p); + anyFailed = anyFailed || !passed; + App.UI.DOM.appendNewElement("div", prereqs, p.name || p.toString(), passed ? "green" : "red"); + } + if (!anyFailed) { // actor casting + App.UI.DOM.appendNewElement("div", frag, "All global prerequisites passed, proceeding to casting...", "green"); + App.UI.DOM.appendNewElement("hr", frag); + const castList = App.UI.DOM.appendNewElement("div", frag, makeCastList()); + castList.id = "castList"; + App.UI.DOM.appendNewElement("hr", frag); + const actorReqs = event.actorPrerequisites(); + for (let i = 0; i < actorReqs.length; ++i) { + let tab = App.UI.DOM.appendNewElement("div", frag); // TODO: put these in tabs? + for (const slave of V.slaves) { + let slaveDiv = App.UI.DOM.appendNewElement("div", tab, App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name")); + let slaveFails = false; + for (const p of actorReqs[i]) { + let passed = testPredicate(slaveDiv, p, slave); + slaveFails = slaveFails || !passed; + App.UI.DOM.appendNewElement("div", slaveDiv, p.name || p.toString(), [passed ? "green" : "red", "indent"]); + } + if (!slaveFails) { + App.UI.DOM.appendNewElement("div", slaveDiv, App.UI.DOM.link("Choose this slave", castSlave, [slave, i]), "indent"); + } + App.UI.DOM.appendNewElement("hr", tab); + } + } + } + } else { + App.UI.DOM.appendNewElement("div", prereqs, "Specified name does not resolve to an event.", "major-warning"); + } + return frag; +}; diff --git a/src/events/randomEvent.js b/src/events/randomEvent.js index 9638ea3f89f4a136063c4f83794b3b10fc75fbd6..929702590a8a3403a14a66a75118f2b335963854 100644 --- a/src/events/randomEvent.js +++ b/src/events/randomEvent.js @@ -3,11 +3,10 @@ * Nonindividual events are not provided any event slave and should cast one themselves. */ -/** get a list of possible individual event based on a given available main actor - * @param {App.Entity.SlaveState} slave +/** get a list of possible individual events * @returns {Array<App.Events.BaseEvent>} */ -App.Events.getIndividualEvents = function(slave) { +App.Events.getIndividualEvents = function() { return [ // instantiate all possible random individual events here // example: new App.Events.TestEvent(), @@ -21,9 +20,7 @@ App.Events.getIndividualEvents = function(slave) { new App.Events.RECIButthole(), new App.Events.RECIFuta(), new App.Events.RECIOrientation(), - ] - .filter(e => (e.eventPrerequisites().every(p => p()) && e.castActors(slave))) - .reduce((res, cur) => res.concat(Array(cur.weight).fill(cur)), []); + ]; }; /** get a list of possible nonindividual events @@ -35,11 +32,21 @@ App.Events.getNonindividualEvents = function() { // example: new App.Events.TestEvent(), new App.Events.REDevotees(), new App.Events.RERelativeRecruiter(), - ] - .filter(e => (e.eventPrerequisites().every(p => p()) && e.castActors(null))) - .reduce((res, cur) => res.concat(Array(cur.weight).fill(cur)), []); + ]; }; +/** choose a valid, castable event from the given event list + * @param {Array<App.Events.BaseEvent>} eventList - list of events to filter + * @param {App.Entity.SlaveState} [slave] - event slave (mandatory to cast in first actor slot). omit for nonindividual events. + * @returns {Array<App.Events.BaseEvent>} + */ +App.Events.getValidEvents = function(eventList, slave) { + return eventList + .filter(e => (e.eventPrerequisites().every(p => p()) && e.castActors(slave))) + .reduce((res, cur) => res.concat(Array(cur.weight).fill(cur)), []); +}; + + /* --- below here is a bunch of workaround crap because we have to somehow persist event selection through multiple twine passages. --- * eventually all this should go away, and we should use just one simple passage for both selection and execution, so everything can be kept in object form instead of being continually serialized and deserialized. * we need to be able to serialize/deserialize the active event anyway so that saves work right, so this mechanism just piggybacks on that capability so the event passages don't need to be reworked all at once @@ -47,13 +54,13 @@ App.Events.getNonindividualEvents = function() { /** get a stringified list of possible individual events as fake passage names - TODO: kill me */ App.Events.getIndividualEventsPassageList = function(slave) { - const events = App.Events.getIndividualEvents(slave); + const events = App.Events.getValidEvents(App.Events.getIndividualEvents(), slave); return events.map(e => `JSRE ${e.eventName}:${JSON.stringify(e.toJSON())}`); }; /** get a stringified list of possible individual events as fake passage names - TODO: kill me */ App.Events.getNonindividualEventsPassageList = function() { - const events = App.Events.getNonindividualEvents(); + const events = App.Events.getValidEvents(App.Events.getNonindividualEvents()); return events.map(e => `JSRE ${e.eventName}:${JSON.stringify(e.toJSON())}`); }; diff --git a/src/uncategorized/randomEventSelect.tw b/src/uncategorized/randomEventSelect.tw index e1cb5f31aeff0100cd470b2429a35adef1120e81..18efed7f362b4816d571d74d13ac6429f62ee922 100644 --- a/src/uncategorized/randomEventSelect.tw +++ b/src/uncategorized/randomEventSelect.tw @@ -34,3 +34,15 @@ DEBUG: <br> [[RE no event]] | <<print "[[Go back to previous passage: '" + previous() + "'|previous()][$activeSlave = 0, $eventSlave = 0]] | [[Go all the way back to Scheduled Event|Scheduled Event][$activeSlave = 0, $eventSlave = 0]]">> +<br><br> + +Or enter a fully qualified event name to debug a specific unlisted JS event:<br> +<<textbox "_evtName" "" autofocus>> +<<link "Check Prerequisites and Casting">> + <<script>>$('#debugOut').empty().append(App.Events.debugEvent(State.temporary.evtName));<</script>> +<</link>><br> +//(for example, "App.Events.RESSMuscles")//<br><br> + +<span id="debugOut"> + /* results gets populated here by jQuery */ +</span>