Your browser lacks required capabilities. Please upgrade it or switch to another to continue.
<<set $res to {"coffee": 2,
"gas": 25,
"money": 220,
}>>
<<set $items to {"coffeeYieldMin": 21,
"coffeeYieldMax": 32,
}>>
<<set $pace to ["slow", "steady", "fast"]>>
- player
<<set $player to {"health": 100,
"sanity": 100,
"fatigue": 0,
"fatigueThreshold": 100,
"pace": "steady",
}>>
- unicorn
/* "mood" */
<<set $unicorn to {"appearances": 0,
"appearancesMax": random(3,6),
"timesRejected": 0,
"mood": 0,
"goodMood": 8,
"badMood": -8,
"sacrifices": 0,
}>>
consumption
<<set $consumption to {"gasPerKm": 0.25,
"fatiguePerMin": 1.26,
}>>
stats
<<set $stats to {"stops": 0,
"km": 0,
"kmInitial": random(200,250),
"kmToGo": 0,
"minutes": 0,
"minToGo": random(160,180),
"totalConsumptionGas": 0,
"totalConsumptionCoffee": 0,
}>>
<<set $stats.kmToGo to $stats.kmInitial>>
<<set $stats.minToGo to Math.round($stats.kmInitial * 0.70)>>
scoring
<<set $score to {"total": 0,
"best": 0,
"multiMin": 6,
"multiGas": 4,
"multiCoffee": 14,
"multiMoney": 4,
"multiFatigue": -3,
"multiDistance": -15,
"multiSacrifices": 30,
}>>
/* hand-over variables */
<<set $last_button to "n">>
<<set $last_time to 0>>
<<set $returnPassage to "Intro">>
/* inits */
<<set $stage to {}>>
<<set $ending to 0>>
<<set $game to {"incident": "",
"gameover": false,
}>>
/* setup game */
<<makeRoads>>
<<makeShops>>
/* AUDIO */
/* score */
<<cacheaudio "mus-intro"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/music/intro.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/music/intro.mp3"
>>
<<cacheaudio "mus-loop"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/music/loop.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/music/loop.mp3"
>>
<<cacheaudio "mus-ending"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/music/ending.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/music/ending.mp3"
>>
<<createaudiogroup ":score">>
<<track "mus-intro">>
<<track "mus-loop">>
<<track "mus-ending">>
<</createaudiogroup>>
- cues
<<cacheaudio "cue-unicorn-in"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/cues/unicorn-01.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/cues/unicorn-01.mp3"
>>
<<cacheaudio "cue-unicorn-out"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/cues/unicorn-02.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/cues/unicorn-02.mp3"
>>
<<createaudiogroup ":cue">>
<<track "cue-unicorn-in">>
<<track "cue-unicorn-out">>
<</createaudiogroup>>
- ui
<<cacheaudio "ui-up"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/menu-01.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/menu-01.mp3"
>>
<<cacheaudio "ui-down"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/menu-02.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/menu-02.mp3"
>>
<<cacheaudio "ui-confirm"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/menu-03.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/menu-03.mp3"
>>
<<cacheaudio "ui-travel-stat"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/chime-01.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/chime-01.mp3"
>>
<<cacheaudio "ui-travel-cont"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/chime-02.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/chime-02.mp3"
>>
<<cacheaudio "ui-travel-fail"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/fail-01.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/fail-01.mp3"
>>
<<cacheaudio "ui-score-total"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/deep-01.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/deep-01.mp3"
>>
<<cacheaudio "ui-have-coffee"
"format:ogg;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/sfx-01.ogg"
"format:mp3;https://pixelprophecy.com/games/sacrificial-trail/audio/ui/sfx-01.mp3"
>>
<<createaudiogroup ":ui">>
<<track "ui-up">>
<<track "ui-down">>
<<track "ui-confirm">>
<<track "ui-travel-stat">>
<<track "ui-travel-cont">>
<<track "ui-travel-fail">>
<<track "ui-score-total">>
<<track "ui-have-coffee">>
<</createaudiogroup>>
- set volumes
<<audio ":score" volume 0.30>>
<<audio ":cue" volume 0.50>>
<<audio ":ui" volume 0.50>><<script>>
UIBar.stow();
UIBar.destroy();
<</script>>
<<audio ":all" stop>>
<div style="text-align:center;">
<img src="https://pixelprophecy.com/games/sacrificial-trail/images/title.png" label="The Sacrificial Trail" style="width:100%;">
<br/>
Version 1.04<br>
<span style="font-size: 80%">a game by Pixel Prophecy © 2018</span><br/><br/>
<<button [[► Begin ◄|Start]]>>
<</button>>
<br/>
<br/>
<br/>
</div>
<div class="boxed">
<h4>Change log:</h4>
<b>1.04</b>
<ul>
<li></li>
</ul>
<b>1.03</b>
<ul>
<li>changed game over text when running out of time</li>
<li>slightly reduced fatigue buildup and increased base gas consumption</li>
<li>added score-keeping</li>
<li>added music and sounds</li>
<li>changed unicorn benevolence algorithm</li>
</ul>
<b>1.02</b>
<ul>
<li>fixed a few typos (thanks, ROAR!)</li>
<li>fixed brainfart-code in sacrifice handling (thanks Ratherjolly & MrPiedPiper)</li>
</ul>
<b>1.01</b>
<ul>
<li>fixed instance where unicorn would not appear</li>
<li>fixed instance where you would run out of roads</li>
<li>made interactable elements clearer (= red)</li>
</ul>
<b>1.00</b>
<ul>
<li>initial release</li>
</ul>
</div><<audio "mus-intro" play>>
<<audio ":ui" stop>>
<<audio "ui-score-total" play >>
Darkness. All-engulfing darkness.<br/>
<br/>
A person you've known for all of your life switches on the lights in the dingy garage. You see the family van, beat up and full of character.<br/>
<br/>
“It’s time,” the person next to you says. You know. You've known when the evil creatures of the forest came closer and closer to the houses every night; when it wasn't safe anymore to travel without a gun. You've known since you've learned about your family's importance.<br/>
<br/>
Something pokes you on the side. It's a few bills of money.<br/>
“Just take it already. It’s <<= $res.money >> € we collected for you.”<br/>
<br/>
[[Put it in your pocket|Look at the person]]<<widget inventory>>
/* limit to 2 decimal places */
<<set $res.money to Math.round($res.money * 100.0) / 100.0>>
<<set $res.gas to Math.round($res.gas * 100.0) / 100.0>>
/* round to integer */
<<set $res.coffee to Math.round($res.coffee)>>
<div class="inventory">
<b>You have:</b><br/>
<ul>
<li><<= $res.money>> €</li>
<li><<= $res.coffee>> coffee</li>
<li><<= $res.gas>> gasoline</li>
</ul>
</div>
<</widget>><<widget status>>
/* round to integer */
<<set $player.fatigue to Math.round($player.fatigue)>>
<div class="status">
<b>You feel:</b><br/>
<ul>
<li><<print$player.fatigue>> fatigue</li>
/*
<li><<print Math.trunc($player.sanity)>> sanity</li>
<li><<print Math.trunc($player.health)>> health</li>
*/
</ul>
</div>
<</widget>><<debug>>
<<set $stats.stops++>>
<h2>Rest Stop #<<=$stats.stops>></h2>
You make rest at a stop along the way. So far, you've traveled <<print $stats.km>> km.<br/>
<div>
<<set $shop to $gameShops.pluck()>>
There's a shop. A bright sign reading “<<= $shop.name>>" welcomes you.
</div>
<div class="prompt">
Will you visit the shop?
<div>
<<button [[Yes|Progression]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<<set $last_button to "y">>
<</button>>
<<button [[No|Progression]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<<set $last_button to "n">>
<</button>>
</div>
</div>
<<addclass "body" "map">>
<h2>Map</h2>
You still have <<=$stats.kmToGo>> km to go and <<=Math.round($stats.minToGo)>> minutes left. Change your pace if necessary and choose the road you want to travel next.
<div>
Your current pace is <<=$player.pace>>.<br/>
<div style="color:red">
<label><<radiobutton "$player.pace" "slow">> Slow</label><br/>
<label><<radiobutton "$player.pace" "steady">> Steady</label><br/>
<label><<radiobutton "$player.pace" "fast">> Fast</label><br/>
</div>
</div>
<<set _roadA to $gameRoads.pluck()>>
<<set _roadB to $gameRoads.pluck()>>
<<set _roadC to $gameRoads.pluck()>>
<<if _roadA.length gt $stats.kmToGo>>
<<set _roadA.length to $stats.kmToGo>>
<</if>>
<<if _roadB.length gt $stats.kmToGo>>
<<set _roadB.length to $stats.kmToGo>>
<</if>>
<<if _roadC.length gt $stats.kmToGo>>
<<set _roadC.length to $stats.kmToGo>>
<</if>>
<table style="width:100%">
<tr>
<td style="width:33%">
<<set _r to _roadA>>
<<button [[Road A|Progression]]>>
<<set $stage to _roadA>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>><br>
Condition: <<- _r.condition>><br/>
Inclination: <<- _r.inclination>><br/>
Length : <<- _r.length>> km<br/>
</td>
<td style="width:33%">
<<set _r to _roadB>>
<<button [[Road B|Progression]]>>
<<set $stage to _roadB>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>><br>
Condition: <<- _r.condition>><br/>
Inclination: <<- _r.inclination>><br/>
Length : <<- _r.length>> km<br/>
</td>
<td style="width:33%">
<<set _r to _roadC>>
<<button [[Road C|Progression]]>>
<<set $stage to _roadC>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>><br>
Condition: <<- _r.condition>><br/>
Inclination: <<- _r.inclination>><br/>
Length : <<- _r.length>> km<br/>
</td>
</tr>
</table><<widget makeRoads>>
/* Attributes for roads */
<<set $roadAttribs to
{
"condition": ["good", "fair", "bad", "terrible"],
"inclination": ["steep decline", "decline", "level", "incline", "steep incline"],
}
>>
<<set _noOfRoads to 50>>
/* setting the first object in the array manually so JS knows what object type to expect */
<<set $gameRoads to
[
{
"condition": either($roadAttribs.condition),
"inclination": either($roadAttribs.inclination),
"length": random(5, 50)
}
]
>>
/* "for i to 1" <-- necessary because we set the first element manually */
<<for _i to 1; _i lt _noOfRoads; _i++ >>
<<set _thisRoad to
{
"condition": either($roadAttribs.condition),
"inclination": either($roadAttribs.inclination),
"length": random(5, 50),
}
>>
/* add to array*/
<<set $gameRoads.pushUnique(_thisRoad)>>
<</for>>
<</widget>>/* this strings together individual parts to create a playthrough */
<<if $game.gameover eq true>>
<<goto "GameOver">>
<</if>>
<<switch previous()>>
<<case "Intro">>
/* fade intro music to main music */
<<audio "mus-intro" fadeoverto 3 0.0 >>
<<audio "mus-loop" loop play>>
<<goto "Map">>
<</if>>
<<case is "Prepare">>
<<goto "Map">>
<<case is "Map">>
/* "Map" should have written a "road" object to "$stage"
which the "Stage" passage expects */
<<goto "Stage">>
<<case "Stage">>
<<goto "StageEnd">>
<<case "StageEnd">>
<<if $game.incident neq "">>
<<goto $game.incident>>
<</if>>
<<if $stats.kmToGo gt 0>>
<<goto "Stop">>
<<else>>
<<goto "Victory">>
<</if>>
<<case "Stop">>
<<set $game.incident to "">> /* clear incident */
<<set $returnPassage to "Intro">> /* clear return passage */
<<if $last_button eq "y">>
<<goto "Shop">>
<<else>>
<<goto "Prepare">>
<</if>>
<<case "Shop">>
<<goto "Prepare">>
<</switch>><<addclass "body" "road">>
<h2>Travel</h2>
<div>
Your are going at a <b><<=$player.pace>></b> pace. The condition of the road is <b><<=$stage.condition>></b>, its inclination is <b><<=$stage.inclination>></b>, and it’s <b><<=$stage.length>></b> km long.
</div>
/*
<<inventory>>
<<status>>
*/
<<set _gas_multi to 1.0>>
<<set _fatigue_multi to 1.0>>
<<set _speed_multi to 1.0>>
/* speed multi defines SLOWNESS, so the bigger the multi, the slower the speed! */
/* evaluate road conditions */
<<switch $stage.condition>>
<<case "good">>
<<set _gas_multi *= 0.8>>
<<set _fatigue_multi *= 0.9>>
<<set _speed_multi *= 0.75>>
<<case "fair">>
<<set _gas_multi *= 1.0>>
<<set _fatigue_multi *= 1.0>>
<<set _speed_multi *= 1.0>>
<<case "bad">>
<<set _gas_multi *= 1.15>>
<<set _fatigue_multi *= 1.2>>
<<set _speed_multi *= 1.75>>
<<case "terrible">>
<<set _gas_multi *= 1.8>>
<<set _fatigue_multi *= 1.7>>
<<set _speed_multi *= 2.5>>
<</switch>>
/* evaluate road inclination */
<<switch $stage.inclination>>
<<case "steep decline">>
<<set _gas_multi *= 0.5>>
<<set _fatigue_multi *= 0.9>>
<<set _speed_multi *= 0.8>>
<<case "decline">>
<<set _gas_multi *= 0.85>>
<<set _fatigue_multi *= 1.00>>
<<set _speed_multi *= 0.90>>
<<case "level">>
<<set _gas_multi *= 1.0>>
<<set _fatigue_multi *= 1.0>>
<<set _speed_multi *= 1.0>>
<<case "incline">>
<<set _gas_multi *= 2.0>>
<<set _fatigue_multi *= 1.2>>
<<set _speed_multi *= 1.6>>
<<case "steep incline">>
<<set _gas_multi *= 3.5>>
<<set _fatigue_multi *= 1.3>>
<<set _speed_multi *= 2.8>>
<</switch>>
<<switch $player.pace>>
<<case "slow">>
<<set _speed_multi *= 1.2>>
<<set _gas_multi *= 0.8>>
<<set _fat_multi *= 0.8>>
<<case "steady">>
<<set _speed_multi *= 1.0>>
<<set _gas_multi *= 1.0>>
<<set _fat_multi *= 1.0>>
<<case "fast">>
<<set _speed_multi *= 0.75>>
<<set _gas_multi *= 1.6>>
<<set _fat_multi *= 1.4>>
<</switch>>
/* default pace is 100 kph, so 0.6 min per km*/
<<set _minBase to ($stage.length * 0.6)>>
<<set _gasBase to ($stage.length * $consumption.gasPerKm)>>
<<set _min to (_minBase * _speed_multi)>>
<<set _gas to (_gasBase * _gas_multi)>>
<<set _fatBase to (_min * $consumption.fatiguePerMin)>>
<<set _fat to (_fatBase * _fatigue_multi)>>
/* limit to 2 decimal places */
<<set _min to Math.round(_min * 100.0) / 100.0>>
<<set _gas to Math.round(_gas * 100.0) / 100.0>>
/* fatigue can be rounded, that's ok */
<<set _fat to Math.round(_fat)>>
<<timed .01s>>
<hr>
/*
<div class="debug" style="background:#000033">
<ul>
<li>minBase: <<= _minBase>></li>
<li>gasBase: <<= _gasBase>></li>
<li>fatBase: <<= _fatBase>></li>
<li>gas_multi: <<= _gas_multi>></li>
<li>fatigue_multi: <<= _fatigue_multi>></li>
<li>speed_multi: <<= _speed_multi>></li>
<li>min: <<= _min>></li>
<li>gas: <<= _gas>></li>
<li>fat: <<= _fat>></li>
</ul>
</div>
*/
<</timed>>
<<timed 1s t8n>>
<<audio ":ui" stop>>
<<audio "ui-travel-stat" play >>
The section took <b><<= _min >></b> minutes,<br/>
<<next>>
<<audio ":ui" stop>>
<<audio "ui-travel-stat" play >>
you spent <b><<= _gas>></b> gasoline,<br/>
<<next>>
<<audio ":ui" stop>>
<<audio "ui-travel-stat" play >>
and it caused you <b><<= _fat >></b> additional fatigue.<br/>
<<set $res.gas -= _gas>>
<<set $player.fatigue += _fat>>
<<set $lastTime to _min>> /* this is expected by StageEnd */
<<set $stats.minutes += _min>>
<<set $stats.minToGo -= _min>>
<<set $stats.km += $stage.length>>
<<set $stats.kmToGo -= $stage.length>>
/* check if anything ran out */
<<if $res.gas lte 0>>
<<set $stats.totalConsumptionGas to $res.gas>>
<<set $res.gas to 0>>
<<else>>
<<set $stats.totalConsumptionGas += _gas>>
<</if>>
/* incidents */
<<set _nextPassage to "Progression">>
/* chance for unicorn */
<<if $unicorn.appearances lt $unicorn.appearancesMax>>
<<if random($stats.stops, 10) gte 9>>
<<set _nextPassage to "InUnicorn">>
<<set $game.incident to "InUnicorn">>
<<set $returnPassage to "StageEnd">>
<</if>>
<</if>>
/* force unicorn on stop 3, if there hadn't been one before */
<<if $unicorn.appearances lt 0 and $stats.stops eq 3>>
<<set _nextPassage to "InUnicorn">>
<<set $game.incident to "InUnicorn">>
<<set $returnPassage to "StageEnd">>
<</if>>
/* incident notices */
<div>
<span id="incident-notice" style="color:#ff2222">
</span>
</div>
<<set _incidentString to "">>
<<next 1000ms>>
<<if $stats.minToGo lt 0 >>
<<timed 1s t8n>>
<<audio ":ui" stop>>
<<audio "mus-loop" stop>>
<<audio "ui-travel-fail" play >>
<<set _incidentString += "You ran out of time.<br/>">>
<<replace "#incident-notice">>
<<=_incidentString>>
<</replace>>
<<set _nextPassage to "InOutOfTime">>
<<set $game.incident to "InOutOfTime">>
<<set $returnPassage to "StageEnd">>
<</timed>>
<</if>>
<<if $player.fatigue gte $player.fatigueThreshold >>
<<timed 1s t8n>>
<<audio ":ui" stop>>
<<audio "mus-loop" stop>>
<<audio "ui-travel-fail" play >>
<<set _incidentString += "You are overly fatigued.<br/>">>
<<replace "#incident-notice">>
<<=_incidentString>>
<</replace>>
<<set _nextPassage to "InFatigued">>
<<set $game.incident to "InFatigued">>
<<set $returnPassage to "StageEnd">>
<</timed>>
<</if>>
<<if $res.gas lte 0 >>
<<timed 1s t8n>>
<<audio ":ui" stop>>
<<audio "mus-loop" stop>>
<<audio "ui-travel-fail" play >>
<<set _incidentString += "You ran out of gas along the way.<br/>">>
<<replace "#incident-notice">>
<<=_incidentString>>
<</replace>>
<<set _nextPassage to "InOutOfGas">>
<<set $game.incident to "InOutOfGas">>
<<set $returnPassage to "StageEnd">>
<</timed>>
<</if>>
/*
<div class="debug">
unicorn Encounters: <<=$unicorn.appearances>><br/>
unicorn sacrifices: <<=$unicorn.sacrifices>><br/>
</div>
*/
<<next>>
<<audio "ui-travel-cont" play >>
<<button "Continue">>
<<audio "ui-confirm" play >>
<<goto _nextPassage>>
<</button>>
<</timed>>You arrive with <<= Math.round($stats.minToGo)>> minutes left at your destination. You have never been here but seen this place so many times before. In your nightmares.<br/>
<br/>
A hooded figure emerges from the darkness of the forest and motions you to a slab of granite, half protruding from the ground. It's a crude stairwell, hewn into the ancient stone.<br/>
<<if $stats.minToGo lt 10>>
<br/>
“Hurry,” a hollow voice from under the hood urges you. You were almost running late for your special appointment tonight.<br/>
<</if>>
<br/>
As you descend you take a last look at your surroundings. A white unicorn is watching you with shiny eyes. It knows. And so do you.<br/>
<br/>
[[Keep descending…|Keep descending]]
<h2>Game Over</h2>
<div>
For one reason or another you didn't make it. The calamity engulfs the land and takes it all with nothing to stop it, devouring every living being, and then everything that's dead as well. It reigns supreme in an endless void of cosmic decadence, terror, and indifference.<br/>
<br/>
</div>
<div class="boxed">
<b>Hint:</b><br/>
<<hint>>
<br/>
</div>
<br/>
<div>
<<button [[Statistics|Score]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>>
<<button [[Do Better|TheEnd]]>>
<<script>>
UI.restart();
<</script>>
<</button>>
</div><h2>Oh?</h2>
<<audio ":cue" stop>>
<<audio ":ui" stop>>
<<audio "cue-unicorn-in" play>>
<<set $unicorn.appearances++>>
<<set $stats.incidents++>>
/* to avoid getting here twice */
<<set $game.incident to "">>
A unicorn appears in your headlights. It comes closer as you halt and roll down the window. The Unicorn kindly ask for a sacrifice.<br/>
<br/>
<<if $res.coffee lte 0>>
But you have nothing to give, so it vanishes again.
<<set $unicorn.mood -= $unicorn.timesRejected * 0.75>>
<<set $unicorn.timesRejected++>>
<<debug>>
<div>
<<timed 2s t8n>>
<<button "Sad">>
<<audio ":cue:ui" stop>>
<<audio "ui-confirm" play >>
<<audio "cue-unicorn-out" play>>
<<goto $returnPassage>>
<</button>>
<</timed>>
</div>
<<else>>
How much coffee will you spare? (You have <<=$res.coffee>>)<br/><br/>
<div style="
font-size: 150%;
padding:1em;
text-align: center;
border: 1pt white solid;
width: fit-content;
overflow: auto;
">
<<set _amount to $res.coffee>>
<div style="float: left;">
<<button "–1">>
<<audio ":ui" stop>>
<<audio "ui-down" play >>
<<set _amount-->>
<<if _amount lte 0>>
<<set _amount to 0>>
<</if>>
<<replace "#value">><<=_amount>><</replace>>
<</button>>
</div>
<div style="float: left; min-width: 4em; text-align: center;" id="value">
<<=_amount>>
</div>
<div style="float: left; clear: right;">
<<button "+1">>
<<audio ":ui" stop>>
<<audio "ui-up" play >>
<<set _amount++>>
<<if _amount gt $res.coffee>>
<<set _amount to $res.coffee>>
<</if>>
<<replace "#value">><<=_amount>><</replace>>
<</button>>
</div>
<br/>
</div>
<br/>
<div id="unicornReply">
</div>
<div id="buttonBox">
<<button "Confirm">>
<<audio ":cue:ui" stop>>
<<audio "ui-confirm" play >>
<<audio "cue-unicorn-out" play>>
<<set _t to "">>
<<if _amount eq 0>>
/* affect the unicorn's mood depending on how much the player holds back */
<<set _moodMulti to -($res.coffee / 2) >>
<<set _moodDelta to ($unicorn.timesRejected * _moodMulti) + _moodMulti>>
<<set $unicorn.mood += _moodDelta>>
<<set $unicorn.timesRejected++>>
<<set _t to "The unicorn leaves without anything. <<=_moodMulti>> <<=_moodDelta>>">>
<<else>>
/* check if we have that many */
/* to hold the variable for after this if-block */
<<set _playerCoffeeCount to $res.coffee>>
<<if $player.fatigue lte 0>>
<<set _thisFatigue to 1>>
<<else>>
<<set _thisFatigue to $player.fatigue>>
<</if>>
<<if _amount gte $res.coffee >>
<<set $unicorn.sacrifices += $res.coffee>>
<<set $res.coffee to 0>>
<<set _t to "The unicorn thanks you and leaves with all of your coffee.">>
<<else>>
<<set $unicorn.sacrifices += _amount>>
<<set $res.coffee -= _amount>>
<<set _t to "The unicorn nods and leaves. You have $res.coffee coffee left.">>
<</if>>
/* affect the unicorn's mood depending on how much the player sacrifices */
/* what fraction of the player's posessioin did they sacrifice? */
<<set _playerGenerosity to (_amount / _playerCoffeeCount)>>
/* between 0.0 (none) and 1.0 (all)
/* how many times could the player fully restore with the coffee they have? */
<<set _thisRatio to (_thisFatigue / _playerCoffeeCount / ( $items.coffeeYieldMin + $items.coffeeYieldMax) / 2 )>>
/* lt 1 - player has not enough coffee to fully restore */
/* eq 1 - player has exactly enough coffee to fully restore */
/* gt 1 - player has can more than fully restore */
/* the magic formula that determines the mood of the unicorn */
<<set _moodDelta to (((_thisRatio * 8) + (_playerGenerosity * 4) / 2 ) - 2 ) + (_amount / 3) >>
<</if>> /*end of "if amount is not 0 */
<<set $unicorn.mood += _moodDelta>>
<<set $unicorn.mood to Math.round($unicorn.mood * 100) / 100>>
<<replace "#unicornReply">>
<<=_t>>
<</replace>>
/*
<<replace "#debugbox">>
playerGenerosity to (amount / playerCoffee)<br/>
<<=_playerGenerosity>> to (<<=_amount>> / <<=_playerCoffeeCount>>)<br/><br/>
thisFatigue: <<=_thisFatigue>><br>
player.fatigue <<=$player.fatigue>><br/><br/>
thisRatio to (thisFatigue / playerCoffeeCount * ( coffeeYieldMin + coffeeYieldMax) / 2 )<br/>
<<=_thisRatio>> to (<<=_thisFatigue>> / <<=_playerCoffeeCount>> / ( <<=$items.coffeeYieldMin>> + <<=$items.coffeeYieldMax>> ) / 2 )<br/><br/>
moodDelta to ((thisRatio * 8) + (playerGenerosity * 4) / 2 ) - 2<br/>
<<=_moodDelta>> to ((<<=_thisRatio>> * 8) + (<<=_playerGenerosity>> * 4) / 2 ) - 2
thisRatio: <<=_thisRatio>><br/>
moodDelta: <<=_moodDelta>><br/>
<<debug>>
<</replace>>
*/
<<remove "button">>
<<timed 5s t8n>>
<<goto $returnPassage>>
<</timed>>
<</button>>
<div id="debugbox" class="deb">
</div>
</div>
<</if>> /* end of "if $res.coffee <= 0" */
<h2>“<<= $shop.name>>” Shop</h2>
There are some goods for sale here.
<div id="inventory">
<<inventory>>
</div>
/* shops have different amounts of goods */
<table style="width:100%" >
<tr>
<th>Item</th>
<th style="text-align:right" >Stock</th>
<th style="text-align:right" >Price</th>
<th></th>
</tr>
<tr>
<td>
Coffee
</td>
<td style="text-align:right" id="coffeeStock">
<<= $shop.coffeeStock>>
</td>
<td align="right">
<<= $shop.coffeePrice>> €
</td>
<td id="coffeeButton">
<<if $shop.coffeeStock gt 0 and $res.money gt $shop.coffeePrice>>
<<button "Buy 1">>
<<audio ":ui" stop>>
<<audio "ui-up" play >>
<<set $res.money -= $shop.coffeePrice>>
<<set $res.coffee += 1>>
<<set $shop.coffeeStock -= 1>>
<<if $shop.coffeeStock lt 0 >>
<<set $shop.coffeeStock to 0>>
<</if>>
<<replace "#coffeeStock">>
<<= $shop.coffeeStock>>
<</replace>>
<<replace "#inventory">>
<<inventory>>
<</replace>>
<<if $shop.coffeeStock lte 0 or $res.money lt $shop.coffeePrice>>
<<remove "#coffeeButton">>
<</if>>
<</button>>
<<else>>
<</if>>
</td>
</tr>
<tr>
<td>
Gasoline
</td>
<td align="right" id="gasStock">
<<= $shop.gasStock>>
</td>
<td align="right">
<<= $shop.gasPrice>> €
</td>
<td id="gasButton">
<<if $shop.gasStock gt 0 and $res.money gt $shop.gasPrice>>
<<button "Buy 1">>
<<audio ":ui" stop>>
<<audio "ui-up" play >>
<<set $res.money -= $shop.gasPrice>>
<<set $res.gas += 1>>
<<set $shop.gasStock -= 1>>
<<if $shop.gasStock lt 0 >>
<<set $shop.gasStock to 0>>
<</if>>
<<replace "#gasStock">>
<<= $shop.gasStock>>
<</replace>>
<<replace "#inventory">>
<<inventory>>
<</replace>>
<<if $shop.gasStock lte 0 or $res.money lt $shop.gasPrice>>
<<remove "#gasButton">>
<</if>>
<</button>>
<<else>>
<</if>>
</td>
</tr>
</table>
<<button [[Done|Progression]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>><<debug>>
<<addclass "body" "stage-end">>
<h2>Arrival</h2>
<div>
You covered <<= $stage.length >> km in <<= Math.round($lastTime)>> minutes.
<<if $stats.kmToGo gt 0>>
There are still <<= Math.round($stats.kmToGo) >> km ahead of you, and you have <<= Math.round($stats.minToGo) >> minutes left to the calamity.
<<else>>
<<audio ":cue" stop>>
<<audio "mus-loop" fadeout>>
<<audio "mus-ending" play volume 0.8>>
You have arrived at your final destination. You are prepared for what's to come. There are still <<= Math.round($stats.minToGo) >> minutes left to the calamity.
<</if>>
<br/>
</div>
<div>
<<inventory>>
<<status>>
</div>
<br/>
<<button [[Continue|Progression]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>>
<h2>Prepare</h2>
Prepare for the next leg of your journey.
<<if $player.fatigue gt 25>>
You might want to have some coffee.
<</if>>
<div id="statusBox">
<<inventory>>
<<status>>
</div>
<div id="effect"><em><<=$effectText>></em></div>
<<set $effectText to "">>
<<set $c to 0>>
<div id="buttonCoffee">
/* if you have more than one coffee, you might want to drink it? */
<<if $res.coffee gt 0 and $player.fatigue gt 0>>
<<button "Have 1 coffee">>
<<set $res.coffee -= 1>>
<<set $stats.totalConsumptionCoffee += 1>>
<<set $c to random($items.coffeeYieldMin, $items.coffeeYieldMax)>>
<<set $player.fatigue -= $c>>
<<if $player.fatigue lte 0>>
<<set $player.fatigue to 0>>
<</if>>
<<replace "#statusBox">>
<<inventory>>
<<status>>
<</replace>>
<<replace "#effect">>
The coffee relieved you of <<=$c>> fatigue.
<</replace>>
<<if $res.coffee lte 0 or $player.fatigue lte 0>>
<<remove "#buttonCoffee">>
<</if>>
<<audio ":ui" stop>>
<<audio "ui-have-coffee" play >>
<</button>>
<</if>>
</div>
<<button [[Continue|Progression]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>><h2>Out of Gas</h2>
You notice that you're out of gas as your car rolls to a stop. Stranded in the middle of the night in an unfamiliar environment, there's not much you can do but wait.<br/>
<br/>
As the calamity reaches you, <<= Math.round($stats.minToGo)>> minutes later, you are not surprised.<br/>
<br/>
<<set $ending to 4>>
<<set $game.gameover to true>>
<<button [[Continue|Progression]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>><h2>Fatigued</h2>
You couldn't keep your eyes open any longer, as the fatigue was too much for you. Your car leaves the road and crashes into one of the many trees along the <<= $stage.condition >> road.
<br/>
<br/>
<<if $stats.minToGo gt 0>>
As the calamity hits <<= Math.round($stats.minToGo)>> minutes later you haven't regained consciousness. A blessing, perhaps.<br/>
<<else>>
It doesn’t matter anyways, as you had been running late all along and time was not on your side, either.<br/>
<</if>>
<br/>
<<set $ending to 5>>
<<set $game.gameover to true>>
<<button [[Continue|Progression]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>><<widget makeShops>>
/* Attributes for shops */
<<set $shopAttribs to
{
"name": ["Clam", "Speedo", "Tank-Stop", "Inn", "Pump & Go", "OMV", "Peter's Pump", "OÖ Gas and Repair", "Hinterland Refuelling", "Blackstone Coop",],
"coffeePrice": random(3,8),
"coffeeStock": random(2,7),
"gasStock": random(5,20),
"gasPrice": random(80, 280) / 100,
}
>>
<<set _count to 30>>
/* setting the first object in the array manually so JS knows what object type to expect */
<<set $gameShops to
[
{
"name": either($shopAttribs.name),
"coffeePrice": random(3,8),
"coffeeStock": random(2,7),
"gasStock": random(5,20),
"gasPrice": random(80, 280) / 100,
}
]
>>
/* "for i to 1" <-- necessary because we set the first element manually */
<<for _i to 1; _i lt _count; _i++ >>
<<set _thisElement to
{
"name": either($shopAttribs.name),
"coffeePrice": random(3,8),
"coffeeStock": random(2,7),
"gasStock": random(5,20),
"gasPrice": random(80, 280) / 100,
}
>>
/* add to array*/
<<set $gameShops.pushUnique(_thisElement)>>
<</for>>
<</widget>><<widget hint>>
<<set $hint to [
"Keep your fatigue below 100 by drinking coffee. Driving fast, long distances, on bad roads fatigue you faster than going slow on good roads.",
"If you run out of gas, don't go as fast, choose declining roads in good condition.",
"If you are kind to the unicorn, it might help you get a better ending.",
"Choosing shorter roads is better when you're low on gas or high on fatigue.",
"Different shops have different prices. Sometimes it's better to wait out and hope that the next shop makes you a better offer."
]>>
<<= either($hint) >>
<</widget>>
The person pats your shoulder and casts a last mournful smile at you.<br>
“We count on you, kid. The tank is half full and there are <<= $res.coffee>> cans of coffee in the glove compartment. It's not much, but… well, good luck."<br/>
<br/>
[[“Thank you.”|Intro]]
You thank them and get into the car. It's dark and cold outside. You switch on the headlights and glance at your watch. You still got <<= $stats.minToGo>> minutes left.<br/>
<br>
With a last glance in the rearview mirror you leave the familiarity behind. Now it’s only you and the road. Your goal is <<= $stats.kmToGo>> kilometers north…<br/>
<br/>
<<button [[Don’t look back.|Progression]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>>
You enter a low chamber, deep underneath the roots and soil of the forest. It is illuminated by torches and four other hooded figures holding them. Their soot blackens the moist ceiling as you are led to a block of solid granite in the middle.<br/>
<br/>
You strip bare and lay face up onto the stone. It's terribly cold and wet but you don't care anymore. With a deep breath you close your eyes for a moment, try to calm yourself as you hear the hooded congregation recite verses in an otherworldly tongue.<br/>
<br/>
“I'm sorry,” one whispers in your direction.<br>
“Don’t be,” you whisper back.<br/>
“Sacrifices must be made,” your voice dry and as cold as the steel of the dagger with the undulating blade that’s being thrust into your chest.<br/>
<br/>
[[It hurts.]]
But not for long. You decide to close your eyes and see the shape of a unicorn dance before them for a moment.<br/><br/>
/* sacrifices */
<<set $ending to 0>>
<<set _t to "">>
<<if $unicorn.mood gte 8>>
<<set $ending to 1>>
<<set _t to "It looks at you, and after a moment of hesitation it gallops closer. You can feel the creatures of the void tearing at your soul, every fiber, every shred they want to devour, but you have made a powerful friend. With flaming hooves it hovers around you, fends off the tentacles and tendrils of the nameless things, ripping them to shreds one by one until they are no more. The two of you fade into a stellar mist, a shining light of virtue. The world is saved, but it doesn't concern you anymore as you had to leave it behind. After all, sacrifices must be made.">>
<<elseif $unicorn.mood lt 8>>
<<set $ending to 2>>
<<set _t to "It looks at you, a hint of sorrow in its eyes, but it remains rigid and unfazed as your soul gets pulled towards the uncaring emptiness of the demons. You realize that you could have treated it better, but that's just talk of the living. As you feel pain never felt before, you watch it gallop away, never to be seen again.">>
<<else>>
<<set $ending to 3>>
<<set _t to "It looks at you in contempt, sneers, and as your immortal soul keeps drifting towards the hellish void between the stars, it just watches. The nameless things will keep you for all eternity, tear you in endless agony. While the world is safe from their hellish influence, you will never be.">>
<</if>>
<div style="color:#ababff;">
<<print _t>><br/>
</div>
<br/>
Then: Darkness. All-engulfing darkness.<br/>
<br/>
<<timed 3s t8n>>
<<button [[Continue|Score]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>>
<</timed>>
Thank you for playing<br/>
<h2>THE SACRIFICIAL TRAIL</h2>
A game by Phil Strahl (a.k.a.) Pixel Prophecy, originally started as compo entry for Ludum Dare #43 in December 2018. Dedicated to my muse, Conny Strahl.<br/>
<br/>
<br/>
<em>You saw ending #<<= $ending>> of 6.</em><br/>
<br/>
<<button "Do better">>
<<script>>
UI.restart();
<</script>>
<</button>><h2>Out of Time</h2>
You took too long. Maybe you didn't check your watch often enough, maybe you didn't dare to because you knew that the inevitable would happen anyway. Maybe you never thought it would but once the black calamity rolls over your car and rips it apart like tinfoil, you know.<br/>
<br/>
<<set $ending to 6>>
<<set $game.gameover to true>>
<<button [[Continue|Progression]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>><<audio "mus-ending" fadeout>>
<h3>Score</h3>
<div class="score-table">
<div class="score-row" id="row_remainingMin"></div>
<div class="score-row" id="row_remainingGas"></div>
<div class="score-row" id="row_remainingCoffee"></div>
<div class="score-row" id="row_remainingMoney"></div>
<div class="score-row" id="row_fatigue"></div>
<div class="score-row" id="row_distance"></div>
<div class="score-row" id="row_sacrifices"></div>
<div class="score-row-t" id="row_total"></div>
</div>
<<timed 1s t8n>>
/* calculate individual scores */
<<set $score.final to 0>>
<<set _scrTime to Math.round( $score.multiMin * $stats.minToGo )>>
<<set _scrGas to Math.round( $score.multiGas * $res.gas )>>
<<set _scrCoffee to Math.round( $score.multiCoffee * $res.coffee )>>
<<set _scrMoney to Math.round( $score.multiMoney * $res.money )>>
<<set _scrFatigue to Math.round( $score.multiFatigue * $player.fatigue )>>
<<set _scrDistance to Math.round( $score.multiDistance * $stats.kmToGo )>>
<<set _scrSacrifices to Math.round( $score.multiSacrifices * $unicorn.sacrifices )>>
<<set $score.final to (_scrTime + _scrGas + _scrCoffee + _scrMoney + _scrFatigue + +_scrDistance + _scrSacrifices)>>
<<if $score.final gt $score.best>>
<<set $score.best to $score.final>>
<</if>>
<<next>>
<<audio ":ui" stop>>
<<audio "ui-travel-stat" play >>
<<replace "#row_remainingMin">>
<div class="score-label">
Time remaining:
</div>
<div class="score-value">
<<= Math.round($stats.minToGo * 100) / 100>> min
</div>
<div class="score-tally">
<<= _scrTime >>
</div>
<</replace>>
<<next>>
<<audio ":ui" stop>>
<<audio "ui-travel-stat" play >>
<<replace "#row_remainingGas">>
<div class="score-label">
Gasoline in tank:
</div>
<div class="score-value">
<<= Math.round($res.gas * 100) / 100>> l
</div>
<div class="score-tally">
<<= _scrGas >>
</div>
<</replace>>
<<next>>
<<audio ":ui" stop>>
<<audio "ui-travel-stat" play >>
<<replace "#row_remainingCoffee">>
<div class="score-label">
Remaining coffee:
</div>
<div class="score-value">
<<= $res.coffee>>
</div>
<div class="score-tally">
<<= _scrCoffee >>
</div>
<</replace>>
<<next>>
<<audio ":ui" stop>>
<<audio "ui-travel-stat" play >>
<<replace "#row_remainingMoney">>
<div class="score-label">
Remaining money:
</div>
<div class="score-value">
<<= $res.money>> €
</div>
<div class="score-tally">
<<= _scrMoney >>
</div>
<</replace>>
<<next>>
<<audio ":ui" stop>>
<<audio "ui-travel-stat" play >>
<<replace "#row_fatigue">>
<div class="score-label">
Fatigue:
</div>
<div class="score-value">
<<= $player.fatigue>>
</div>
<div class="score-tally">
<<= _scrFatigue >>
</div>
<</replace>>
<<next>>
/*<<if $stats.kmToGo gt 0>>*/
<<audio ":ui" stop>>
<<audio "ui-travel-stat" play >>
<<replace "#row_distance">>
<div class="score-label">
Distance from goal:
</div>
<div class="score-value">
<<= $stats.kmToGo>>
</div>
<div class="score-tally">
<<= _scrDistance >>
</div>
<</replace>>
/*<</if>>*/
<<next>>
<<audio ":ui" stop>>
<<audio "ui-travel-stat" play >>
<<replace "#row_sacrifices">>
<div class="score-label">
Sacrifices:
</div>
<div class="score-value">
<<= $unicorn.sacrifices>>
</div>
<div class="score-tally">
<<= _scrSacrifices >>
</div>
<</replace>>
<<next 2s>>
<<audio ":ui" stop>>
<<audio "ui-score-total" volume 0.85 play >>
<<replace "#row_total">>
<div class="score-label">
TOTAL:
</div>
<div class="score-value">
</div>
<div class="score-tally">
<<= $score.final >>
</div>
<</replace>>
<div style="clear: both;">
<br/>
<<button [[Continue|TheEnd]]>>
<<audio ":ui" stop>>
<<audio "ui-confirm" play >>
<</button>>
</div>
<<next 1s >>
<h3>More Statistics</h3>
<div class="score-table">
<div class="score-row">
<div class="score-label">
Turns played:
</div>
<div class="score-value">
<<= turns()>>
</div>
<div class="score-label">
Stops made:
</div>
<div class="score-value">
<<= $stats.stops>>
</div>
<div class="score-label">
Coffee consumed:
</div>
<div class="score-value">
<<= $stats.totalConsumptionCoffee>>
</div>
<div class="score-label">
Gasoline spent
</div>
<div class="score-value">
<<= Math.round($stats.totalConsumptionGas * 100) / 100>>
</div>
<div class="score-label">
Unicorn encounters:
</div>
<div class="score-value">
<<= $unicorn.appearances>>
</div>
<div class="score-label">
Unicorn mood:
</div>
<div class="score-value">
<<= $unicorn.mood>>
</div>
<div class="score-row">
<div class="score-value"> </div>
<div class="score-label"> </div>
<div class="score-value"> </div>
</div>
</div>
</div>
<</timed>>
<br/><<widget debug>>
/*
<div class="deb">
timeRejected: <<= $unicorn.timesRejected>><br/>
<b>unicornMood: <<=$unicorn.mood>></b><br/>
</div>*/
<</widget>>