/* Init global variables */\
<<set $round to 0>>\
<<set $year to 2024>>\
<<set $phase to 0>>\
<<set $char_can_vote to false>>\
<<set $user_name_field to ''>>\
<<set $char_code to ''>>\
<<set $char_code_field to ''>>\
<<set $char_num_field to ''>>\
<<set $char_fullname to ''>>\
<<set $char_firstname to ''>>\
<<set $char_lastname to ''>>\
<<set $char_age_initial to 0>>\
<<set $char_age to 0>>\
<<set $char_desc_short to ''>>\
<<set $char_types to []>>\
<<set $char_ethics to []>>\
<<set $char_ethics_article>>\
<<set $char_influence to 0>>\
<<set $char_influencetoken to ''>>\
<<set $char_location to ''>>\
<<set $char_goal_short to ''>>\
<<set $char_death_age to 100>>\
<<set $char_death_reason to ''>>\
<<set $char_last_vote to ''>>\
<<set $game_ready to false>>\
<<set $game_testing to false>>\
<<set $game_maxplayers to 0>>\
<<set $game_allcharcodes to []>>\
<<set $game_complete to false>>\
<<set $ballot to []>>\
<<set $allEthics to []>>\
<<set $shadowInvestorCharNum to 1>>\
<<set $shadow_votes_2 to []>>\
/* --------------------------*/
/* START */
/* --------------------------*/<h1>WELCOME TO DIRT</h1>
LOADING...
/* Check if game is ready to play */
<<script>>
(async function() {
// isGameReady returns an obj of setup variables
const data = await window.isGameReady();
State.variables.game_ready = data.gameReady;
State.variables.game_testing = data.gameTesting;
State.variables.game_maxplayers = data.maxTotalPlayers;
State.variables.game_allcharcodes = data.allcharcodes;
console.log(State.variables);
// If game is ready to play, aka we are ready to let in audience
if (State.variables.game_ready) {Engine.play("00-Community-Agreement");}
// if not, punt to passage 'NOT READY'
else {Engine.play("00-Error-Not-Ready");}
})();
<</script>>\<h1>WELCOME TO DIRT</h1>\
<h3>>COMMUNITY AGREEMENT</h3>\
There's so much to be done!
So much to be decided together!
But a few policies have already passed:
- No racism, sexism, or homophobia.
- No touching performers or other players without consent.
- Back-room deals, rivalries, alliances, are all permitted.
- Anyone can exit and re-enter the space at any time.
If you have any questions or concerns about the above policies, check with Connor at HR.
<<script>>
document.body.classList.add("community-agreement");
<</script>>
<<button "I AGREE">><<script>>Engine.play("00-Character-Selection");<</script>><</button>><h1>WELCOME TO DIRT</h1>\
<h3>>CHOOSE YOUR CHARACTER</h3>\
<span class="player-highlight">Enter your 4 Digit Code:
<<textbox "$char_code_field" $char_code_field>>
Create a password:
<<textbox "$user_name_field" "">></span>
You can use this password to log back into your character if you navigate away.
Please remember it or write it down!
/* Button SUBMIT */
<<button "Submit">><<script>>
this.disable = true;
let charCode = State.variables.char_code_field;
charCode = charCode.trim().toUpperCase();
//console.log(State.variables.game_allcharcodes);
let charNum = State.variables.game_allcharcodes.indexOf(charCode);
State.variables.char_code = charCode;
//console.log(charCode);
//console.log(charNum);
let username = State.variables.user_name_field;
if (!username) { // check valid username -- technically this should be made optional
State.variables.user_name_field = '';
Engine.play("00-Error-no-username");
} else if (charCode.length > 4 || charNum < 1) {
State.variables.char_code_field = '';
State.variables.user_name_field = '';
Engine.play("00-Error-bad-code");
} else { // Check if $char_num has already been chosen
(async function() {
let currRoster = await window.getRoster();
// console.log('currRoster: ' + currRoster);
let existingUser = currRoster[charNum];
if (existingUser && existingUser !== username) { // if already chosen AND username does not match
State.variables.char_code_field = '';
State.variables.user_name_field = '';
Engine.play("00-Error-char-taken");
}
else { // if no name currently assigned, assign the character!
const res = await window.updateRoster(charNum, username);
const chardata = await window.getCharacterInfo(charNum);
//console.log('charnum: '+charNum+' name: '+currRoster[charNum]);
console.log(chardata);
State.variables.char_code_field = '';
State.variables.char_num = chardata.num;
State.variables.char_firstname = chardata.firstName;
State.variables.char_lastname = chardata.lastName;
State.variables.char_fullname = chardata.fullName;
State.variables.char_age_initial = chardata.age;
State.variables.char_age = chardata.age;
State.variables.char_desc_short = chardata.bioShort;
State.variables.char_types = chardata.types;
State.variables.char_ethics = chardata.ethics;
State.variables.char_influence = chardata.influence;
State.variables.char_influencetoken = chardata.influenceToken;
State.variables.char_location = chardata.location;
State.variables.char_goal_short = chardata.goalShort;
State.variables.char_death_age = chardata.ageOfDeath;
State.variables.char_death_reason = chardata.reasonOfDeath;
// very stupid duct tape method to get article for ethic
if (isVowel(State.variables.char_ethics[0].charAt(0))) {
State.variables.char_ethics_article = "an";
} else {
State.variables.char_ethics_article = "a";
}
console.log("Character selection complete: "+chardata.fullName);
Engine.play("00-Stand-By");
}
})();
}
function isVowel(c) {
return ['a', 'e', 'i', 'o', 'u'].indexOf(c.toLowerCase()) !== -1
}
<</script>><</button>>\<span id="00-Character-Header-include"><<include "00-Character-Header">></span>\
<span class="player-highlight">$char_desc_short</span>
Please take a seat and relax while we finish setting up!
Please see Connor at IT if you need assistance with the game.<h1 id="00-Character-Header-Year" class="player-highlight">$year</h1>\
Your name is <span class="player-highlight">$char_fullname</span>.
You are <span class="player-highlight" id="00-Character-Header-Age"><<if $char_fullname is "Manfred X">>???<<else>>$char_age<</if>></span> years old.
You live in <span class="player-highlight">$char_location</span>.
You have <span class="player-highlight"><<if $char_influencetoken is '$'>>💰<<else>>🌳<</if>> $char_influence Influence Point<<if $char_influence > 1>>s<</if>> <<if $char_influencetoken is '$'>>💰<<else>>🌳<</if>></span>
Your would describe yourself as <span class="player-highlight"><<if $char_fullname is "Manfred X">><<print $char_ethics[0].toUpperCase()>><<elseif $char_age < 18>>A CHILD<<else>><<print $char_ethics[0].toUpperCase()>><</if>></span>.
/* --- ERRORS FOR CHAR SELECTION INPUT --- */Please check back later. We are still setting up!
[[Refresh->Start]]Error: This character is not available.
Please select a different character.
See CONNOR at IT if you need assistance.
[[Try again->00-Character-Selection]]Error: Please enter a username.
See CONNOR at IT if you need assistance.
[[Try again->00-Character-Selection]]Error: This character has already been chosen.
See CONNOR at IT if you need assistance.
[[Try again->00-Character-Selection]]Error: Invalid code. Please enter a valid 4-digit code.
See CONNOR at IT if you need assistance.
[[Try again->00-Character-Selection]]<h1>THIS IS A TEST</h1>\
<h3>SHOULD HAVE POSTED A TIMESTAMP</h3>
<<script>>
(async function () {
/* POST timestamp for character selection START */
let ts = Date.now();
await window.postTimestamp(ts, 0);
})();
<</script>>\<span class="preamble">
. . . . . . . . . . . . . . . . . . . . We
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . begin
. . . . . . . . .
. . . . . . . with
. . . . . . . . . . . .
. . . . . . . . . . . . . . . w
. . . . . . . . . . . . . . . . . . . . . a
. . . . . . . . . . . . . . . . . . . . . . . . . . . t
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . r</span><span id="00-Character-Header-include"><<include "00-Character-Header">></span>
<span class="player-highlight">$char_goal_short</span><span id="00-Character-Header-include"><<include "00-Character-Header">></span>
<<if $round > 3>>[[Wait, what do Influence Points do again?->07-The-Rules]]<</if>><span id="00-Character-Header-include"><<include "00-Character-Header">></span>
<span id="03-Voting-Menu-include"><<include "03-Voting-Menu">></span><<if $game_testing is true>>\
Game is in TESTING MODE. Click as many options as you want above. Click link below to move on.
[[I'm done.->03-Voting-Success]]
<</if>>Thank you for participating in local government.
[[You're welcome. -> 02-Home-Page]]<div id="03-Voting-Menu-container"><ul id="03-Voting-Menu-ul" class="comic-sans"></ul><<script>>
(async function() {
console.log('voting menu script');
let sv = State.variables;
sv.ballot = await window.getBallot(); // need await here; DOM loads slower than scripts
console.log(sv.ballot);
// ------------
// FILTER
// ------------
// For July @ The Tank 2024 -- no filtering of ballots by ethics!
// sv.ballot = sv.ballot.filter(hasType);
// sv.ballot = sv.ballot.filter(hasEthics);
// sv.ballot = sv.ballot.filter(hasInfluence);
// return TRUE if character types [] includes ballot type
function hasType(b) {
console.log('filterType: '+ b.type + ' | ' + sv.char_types);
return sv.char_types.includes(b.type);
}
function hasEthics(b) {
console.log('filterEthics');
console.log(b.text + ' ' + b.ethics);
// if NO ETHICS SPECIFIED, then all people can vote
if (b.ethics[0]) {
console.log('there are ballot ethics: index 0 = ' + b.ethics[0]);
} else {
console.log('no ballot ethics specified');
return true;
}
// return TRUE if character ethics [] includes at least 1 ballot ethic []
for (let e of b.ethics) {
console.log('for loop woohoo');
if (sv.char_ethics.includes(e)) {
console.log('if statement whee');
console.log(e + sv.char_ethics);
return true;
}
}
return false;
}
function hasInfluence(b) {
//console.log('filterInfluence');
console.log('char: ' + sv.char_influence + ' : ballot: ' + b.influence);
return sv.char_influence >= b.influence;
}
// ------------------
// PUT IT ON THE DOM
// ------------------
const ul = document.getElementById("03-Voting-Menu-ul");
// iteratively add links for each ballot option
for (let i = 0; i < sv.ballot.length; i++) {
let thisBallot = sv.ballot[i];
let text = document.createTextNode(thisBallot.text);
// create link
let a = document.createElement('a');
a.onclick = async function () {
let code = thisBallot.code;
console.log('onclick, code: '+code);
console.log(thisBallot);
//sv.char_last_vote = thisBallot.text;
let charCode = State.variables.char_code;
let numOfVoteCode = parseInt(code);
let ip = State.variables.char_influence;
console.log("charcode: " + charCode + " Numofvotecode " + numOfVoteCode + " ip: "+ ip);
await window.postVote(State.variables.char_code, parseInt(code), State.variables.char_influence);
// link away to next passage IF not testing; if testing, can select many choices at once time
if (!sv.game_testing) {
Engine.play('03-Voting-Success');
}
}
// Create list element and add style
// CSS for this can be found in src/styles/03-Voting.css
console.log(thisBallot);
let li = document.createElement('li');
let type = thisBallot.type.trim().toLowerCase();
console.log('type: '+type);
switch (type) {
case 'residential': // green
a.classList.add('residential');
li.classList.add('residential');
break;
case 'manufacturing': // blue
a.classList.add('manufacturing');
li.classList.add('manufacturing');
break;
case 'commercial': // red
a.classList.add('commercial');
li.classList.add('commercial');
break;
case 'transportation': // yellow
a.classList.add('transportation');
li.classList.add('transportation');
break;
case 'parks': // purple
a.classList.add('parks');
li.classList.add('parks');
break;
case 'resubmerge': // cyan
a.classList.add('resubmerge');
li.classList.add('resubmerge');
break;
case 'special': // pink
a.classList.add('special');
li.classList.add('special');
break;
default:
}
// append finished element
a.appendChild(text);
li.appendChild(a);
ul.appendChild(li);
}
// fun fade effect
//document.getElementById("03-Voting-Menu-container").classList.remove('zero');
//document.getElementById("03-Voting-Menu-container").classList.add('full-fade');
})();
<</script>></div><span id="00-Character-Header-include"><<include "00-Character-Header">></span>
Sorry, kid. You're only <span class="player-highlight">$char_age</span> years old, and you need to be <span class="player-highlight">18</span> to ride this ride.<span id="00-Character-Header-include"><<include "00-Character-Header">></span>
The MAYOR wants to hear from ME!
Submit a suggestion:
<<textarea "$write_in_ballot" "" autofocus>>
<<button "Submit" 03-Write-In-Ballot-Success>>
/* non-blank message */
<<if $message neq "">>
<<run submitWriteInBallot($write_in_ballot)>>
<</if>>
/* chide them for blank message */
<<if $action eq "">><<replace "#ActionText">><<print "You can't submit a blank suggestion.">><</replace>><</if>>
<</button>><span class = "death-notice">
You've led a fulfilling life, <span class="player-highlight">$char_fullname.</span>
But it's come to an end. You've died of a <span class="player-highlight">$char_death_reason.</span>
Who's going to carry on your legacy?
OPTION 1: you had a kid
OPTION 2: reincarnate
</span>Congratulations, <span class="player-highlight">$char_firstname</span>.
You have <span class="player-highlight"><<if $char_influencetoken is '$'>>💰<<else>>🌳<</if>> $char_influence Influence Point<<if $char_influence > 1>>s<</if>> <<if $char_influencetoken is '$'>>💰<<else>>🌳<</if>></span>
That makes you our <span class="player-highlight">SHADOW INVESTOR</span>.
After this round of voting completes, you will see the TOP 3 BALLOT OPTIONS on this voting device, just like the MAYOR does. You will have 10 seconds to CHOOSE ONE to suggest to the MAYOR.
The MAYOR may face consequences if they do not agree with you... :)
[[Proceed to voting as usual.->03-Cast-Your-Vote]]Hello, <span class="player-highlight">$char_firstname</span>.
You may CHOOSE ONE of these options to suggest to the MAYOR:
<div id="05-Shadow-Vote-Voting-Menu-container"><ul id="05-Shadow-Vote-Voting-Menu-ul" class="comic-sans"></ul><<script>>
(async function() {
console.log('voting menu script');
let sv = State.variables;
let shadowBallot = await window.getShadowBallot(); // need await here; DOM loads slower than scripts
console.log(shadowBallot);
// ------------------
// PUT IT ON THE DOM
// ------------------
const ul = document.getElementById("05-Shadow-Vote-Voting-Menu-ul");
// iteratively add links for each ballot option
for (let i = 0; i < shadowBallot.length; i++) {
let thisBallot = shadowBallot[i];
// only if the ballot has text data
if (thisBallot.text.length > 0){
let text = document.createTextNode(thisBallot.text);
// create link
let a = document.createElement('a');
a.onclick = async function () {
let code = thisBallot.code;
console.log('onclick, code: '+code);
console.log(thisBallot);
//sv.char_last_vote = thisBallot.text;
let charCode = State.variables.char_code;
let numOfVoteCode = parseInt(code);
let ip = State.variables.char_influence;
console.log("charcode: " + charCode + " Numofvotecode " + numOfVoteCode + " ip: "+ ip);
await window.postInvestorVote0(State.variables.char_code, parseInt(code), State.variables.char_influence);
// link away to next passage IF not testing; if testing, can select many choices at once time
if (!sv.game_testing) {
Engine.play('03-Voting-Success');
}
}
// Create list element and add style
// CSS for this can be found in src/styles/03-Voting.css
console.log(thisBallot);
let li = document.createElement('li');
a.classList.add('shadow');
li.classList.add('shadow');
// append finished element
a.appendChild(text);
li.appendChild(a);
ul.appendChild(li);
}
}
})();
<</script>></div>Hello, <span class="player-highlight">$char_firstname</span>.
Looks like the MAYOR wants to cooperate. Let's try it again.
You will once again make a suggestion after this round of voting.
[[Proceed to voting as usual.->03-Cast-Your-Vote]]Hello, <span class="player-highlight">$char_firstname</span>.
Looks like the MAYOR doesn't want to cooperate. It's time for CONSEQUENCES!
You have friends in high places. Regardless of how the public votes this round, the city will build TWO options of your choosing.
[[Make your first pick.->05-Fiat-First-Pick]][[Make your second pick.->05-Fiat-Second-Pick]]<div id="05-Investor-Voting-Menu-container"><ul id="05-Investor-Voting-Menu-ul" class="comic-sans"></ul><<script>>
(async function() {
console.log('voting menu script');
let sv = State.variables;
sv.ballot = await window.getBallot(); // need await here; DOM loads slower than scripts
// console.log(sv.ballot);
// ------------------
// PUT IT ON THE DOM
// ------------------
const ul = document.getElementById("05-Investor-Voting-Menu-ul");
// iteratively add links for each ballot option
for (let i = 0; i < sv.ballot.length; i++) {
let thisBallot = sv.ballot[i];
let text = document.createTextNode(thisBallot.text);
// create link
let a = document.createElement('a');
a.onclick = async function () {
let code = thisBallot.code;
// console.log('onclick, code: '+code);
// console.log(thisBallot);
//sv.char_last_vote = thisBallot.text;
let charCode = State.variables.char_code;
let numOfVoteCode = parseInt(code);
let ip = State.variables.char_influence;
console.log("charcode: " + charCode + " Numofvotecode " + numOfVoteCode + " ip: "+ ip);
await window.postInvestorVote1(State.variables.char_code, parseInt(code), State.variables.char_influence);
// link away to next passage IF not testing; if testing, can select many choices at once time
if (!sv.game_testing) {
Engine.play('05-Fiat-Voting-Success');
}
}
// Create list element and add style
// CSS for this can be found in src/styles/03-Voting.css
// console.log(thisBallot);
let li = document.createElement('li');
let type = thisBallot.type.trim().toLowerCase();
// console.log('type: '+type);
switch (type) {
case 'residential': // green
a.classList.add('residential');
li.classList.add('residential');
break;
case 'manufacturing': // blue
a.classList.add('manufacturing');
li.classList.add('manufacturing');
break;
case 'commercial': // red
a.classList.add('commercial');
li.classList.add('commercial');
break;
case 'transportation': // yellow
a.classList.add('transportation');
li.classList.add('transportation');
break;
case 'parks': // purple
a.classList.add('parks');
li.classList.add('parks');
break;
case 'resubmerge': // cyan
a.classList.add('resubmerge');
li.classList.add('resubmerge');
break;
case 'special': // pink
a.classList.add('special');
li.classList.add('special');
break;
default:
}
// append finished element
a.appendChild(text);
li.appendChild(a);
ul.appendChild(li);
}
})();
<</script>></div><div id="05-Investor-Voting-Menu-container"><ul id="05-Investor-Voting-Menu-ul" class="comic-sans"></ul><<script>>
(async function() {
console.log('voting menu script');
let sv = State.variables;
sv.ballot = await window.getBallot(); // need await here; DOM loads slower than scripts
// console.log(sv.ballot);
// ------------------
// PUT IT ON THE DOM
// ------------------
const ul = document.getElementById("05-Investor-Voting-Menu-ul");
// iteratively add links for each ballot option
for (let i = 0; i < sv.ballot.length; i++) {
let thisBallot = sv.ballot[i];
let text = document.createTextNode(thisBallot.text);
// create link
let a = document.createElement('a');
a.onclick = async function () {
let code = thisBallot.code;
// console.log('onclick, code: '+code);
// console.log(thisBallot);
let charCode = State.variables.char_code;
let numOfVoteCode = parseInt(code);
let ip = State.variables.char_influence;
console.log("charcode: " + charCode + " Numofvotecode " + numOfVoteCode + " ip: "+ ip);
await window.postInvestorVote2(State.variables.char_code, parseInt(code), State.variables.char_influence);
// link away to next passage IF not testing; if testing, can select many choices at once time
if (!sv.game_testing) {
Engine.play('03-Voting-Success');
}
}
// Create list element and add style
// CSS for this can be found in src/styles/03-Voting.css
// console.log(thisBallot);
let li = document.createElement('li');
let type = thisBallot.type.trim().toLowerCase();
// console.log('type: '+type);
switch (type) {
case 'residential': // green
a.classList.add('residential');
li.classList.add('residential');
break;
case 'manufacturing': // blue
a.classList.add('manufacturing');
li.classList.add('manufacturing');
break;
case 'commercial': // red
a.classList.add('commercial');
li.classList.add('commercial');
break;
case 'transportation': // yellow
a.classList.add('transportation');
li.classList.add('transportation');
break;
case 'parks': // purple
a.classList.add('parks');
li.classList.add('parks');
break;
case 'resubmerge': // cyan
a.classList.add('resubmerge');
li.classList.add('resubmerge');
break;
case 'special': // pink
a.classList.add('special');
li.classList.add('special');
break;
default:
}
// append finished element
a.appendChild(text);
li.appendChild(a);
ul.appendChild(li);
}
})();
<</script>></div><<script>>
(async function () {
console.log('05-test shadow investor');
let test = await window.getShadowInvestor();
console.log(test);
State.variables.shadowInvestorCharNum = test;
})
<</script>>
[[05-Test-1]]$shadowInvestorCharNum<h1>CREDITS</h1>\
<h3>DIRT is created by SOUR MILK</h3>\
SOUR MILK is Anna Jastrzembski, Carsen Joenk, and Christina Tang
in collaboration with and performed by Enette Fremont, Joe Rivera, and Ean Sheehy
Stage managed by Liz Peterson
Video Design by Jesse Itskowitz
Original collaborating cast: Marcella Murray, Joe Rivera, and Ean Sheehy
Original scenic design by Colleen Murray
Original sound design by Sid "SD" Diamond
DIRT is made possible with support from the Foundation for Contemporary Arts' Emergency Grant.
Special thanks to:
- The Tank
- VOX Media
- ITP Equipment Room
- Matthew Perl
- Kelly ErnstYour INFLUENCE POINTS become a multiplier to your voting power. The more influence you have, the more likely your interests will appear before the MAYOR.
If the ballot option you voted for appears in the TOP 3 ballot options, you gain influence points. If it doesn't, you will lose them.
[[Got it, I think.->02-Home-Page]]