/*
Set Flag X to value Y (Y defaults to True).
Flag names are NOT case sensitive.
<<setFlag "Mentor" "Bob">> sets Mentor flag to "Bob"
<<setFlag "TrialMed">> sets TrialMed flag to True
<<setFlag "flag" false>> remove the flag from flag array
*/
<<widget "setFlag">>
<<set _name = _args[0].toLowerCase()>>
<<if ndef $flags>><<set $flags = {}>><</if>>
<<if def _args[1]>>
<<if _args[1] == false>>
<<if def $flags[_name]>><<run delete $flags[_name]>><</if>>
<<else>><<set $flags[_name] = _args[1]>>
<</if>>
<<else>><<set $flags[_name] = true>>
<</if>>
<</widget>><cite><<include "StoryDisplayTitle">></cite> is written
by <<include "StoryAuthor">>.
<br><br>
[[Twine by Chris Klimas|https://twinery.org]]
<br>
[[Sugarcube 2 by Thomas Michael Edwards|https://www.motoslave.net/sugarcube/2]]
<br>
macros by [[Chapel|https://github.com/ChapelR/custom-macros-for-sugarcube-2]] and [[CyrusFirheir|https://github.com/cyrusfirheir/cycy-wrote-custom-macros]]
<br>
[[OpenDyslexic Font by Abbie Gonzalez|https://opendyslexic.org]]
<br><h2 class="center">Foreword</h2>
This is a collection of code used in Twine [[SugarCube|https://www.motoslave.net/sugarcube/2/]] projects to emulate the look of [[ChoiceScript|https://www.choiceofgames.com/make-your-own-games/choicescript-intro/]] games, but it has added features (such as rewind and save-to-disk) that come with the storyformat (SugarCube version 2.36.1).
<br><br>
Unfortunately it is not easy for an absolute beginner to use this code right out of the box, as it requires some basic understanding of SugarCube's default behavior, and this code is structured with the assumption that the [[Tweego Compiler|https://www.motoslave.net/tweego/]] will be used. You can still try to copy-and-paste code from this collection into the [[Twine editor|https://twinery.org/]], but that still assumes some familiarity with the original Twine editor and the [[twee notation (version 3)|https://github.com/iftechfoundation/twine-specs/blob/master/twee-3-specification.md]]. And if you "Save As..." the complete page to get a compiled HTML version, remember to change the IFID for each new project instead of just directly building on top of this imported HTML file in the Twine editor.
<br><br>
Note that this passage has the "noheader" tag (in the code), which removes the heading. You can change the tag name or remove this feature. But stat screen might not show any default values at this point when StoryInit passage has not been executed.
<br><br>
[[NEXT|overview]]ChoiceScript-like SugarCube Templatebrushmen<<set $text = "">> /% used in widget "text" %/
<<set $pronounplural = false>> /% used in vendor code "pronouns.js" %/
<<set $fname = "Ellie">>
<<set $skintone = "beige", $eyecolor = "brown">>
<<set $hairlength = "long", $haircolor = "black">>
<<set $gender = "girl">>
<<run gender.setPronouns("female")>> /% see vendor code "pronouns.js" %/
<<set $money = 0, $energy = 50>>
<<set $bold = 50, $kind = 50>>
<<set $rel_a = 0, $rel_p = 0>>
<<set $parent = "dad">>
/% achievement is optional just like in ChoiceScript;
if you don't define any, the menu option for achievement
should not show either
%/
<<achievement "end" true 10 "finishing the demo" "you went through the demo story" "The end!">>/* custom widgets go in here */
/* similar to ChoiceScript's image syntax, but image file has to be included in the images folder
<<image file alignment alt-text>>
*/
<<widget "image">>
<<set _file = _args[0]>>
<<set _align = _args[1]>>
<<set _alt = _args[2]>>
<<set _dir = setup.imgPath>>
<<if _alt>>
<img @class="_align" @src="_dir + _file" @alt="_alt">
<<elseif not (_align eq "left" or
_align eq "right" or
_align eq "center")>>
<<set _alt = _align>>
<img class="center" @src="_dir + _file" @alt="_alt">
<<elseif _align>>
<img @class="_align" @src="_dir + _file">
<<else>>
<img class="center" @src="_dir + _file">
<</if>>
<</widget>>
/* capitalize first letter of a given variable's content;
if you want to keep the original value but display the content with first letter capitalized, add false as a parameter
default usage (value is changed, but nothing is displayed):
<<capfirst "$var">>
capitalize $var temporarily for display:
<<capfirst "$var" false>>
*/
<<widget "capfirst">>
<<set _v = _args[0]>>
<<if _args.length gt 1>>
<<set _change = _args[1]>>
<<else>>
<<set _change = true>>
<</if>>
<<if _change and State.getVar(_v)>>
<<run State.setVar(_v, State.getVar(_v).toUpperFirst())>>
<<else>>
<<print State.getVar(_v).toUpperFirst()>>
<</if>>
<</widget>>
/* for when having a short line of text to a choice selection */
<<widget "text">>
<<if $text neq "">>$text<br><br><</if>>
<<set $text = "">>
<</widget>>
/* for stat bar with two values like opposed stats in ChoiceScript:
<<statbar "$statvar" "word on the left" "word on the right">>
for stat bar with only one value like percentage stat in CS:
<<statbar "$statvar" "word on the left">>
*/
<<widget "statbar">>
<<set _stat = _args[0]>>
<<set _left = _args[1]>>
<<if _args[2]>>
<<set _right = _args[2]>>
<<else>><<set _right = "">>
<</if>>
<<set _p = State.getVar(_stat)>>
<<if _p>>
<<if _right>>
<<set _right = _right + " " + (100 - _p) + "%">>
<</if>>
<div class="stat-bar rounded">
<span class="value rounded" @style="'width: ' + _p + '%;'">
<span class="statbarlefttext">_left _p%</span>
</span>
<span class="statbarrighttext">_right</span>
</div>
<</if>>
<</widget>>This is not about a small town where I ghostwrite to keep the lights on at home.
<br><br>
This is not a story about love.
<br><br>
It is about friendship, and being bold.
<br><br>
My name is <<textbox "$fname" $fname autofocus>>. I'm a
<<set _skinColors = ["beige", "pale", "brown", "tan", "olive", "black", "dark-brown"]>>
<<listbox "$skintone" autoselect>>
<<optionsfrom _skinColors>>
<</listbox>>
skinned
<<set _eyeColors = ["brown", "blue", "green", "hazel", "dark brown"]>>
<<listbox "$eyecolor" autoselect>>
<<optionsfrom _eyeColors>>
<</listbox>>
eyed
<<set _gender = ["girl", "boy", "gender-rebel"]>>
<<listbox "$gender" autoselect>>
<<optionsfrom _gender>>
<</listbox>>
with
<<set _hairLengths = ["long", "shoulder-length", "short", "no"]>>
<<listbox "$hairlength" autoselect>>
<<optionsfrom _hairLengths>>
<</listbox>>
<<set _hairColors = ["black", "brown", "blonde", "red", "graying", "dyed"]>>
<<listbox "$haircolor" autoselect>>
<<optionsfrom _hairColors>>
<</listbox>>
hair. And I suppose if anyone wants to make a fuss about my <<link "pronoun of choice">><<pronouns>><</link>>, this year would be their last chance to do so.
<br><br>
Hard to believe it's almost May of my final year in high school... Anyway, [[let's make the most of it|profilecheck]]./% fix name capitalization by first convert all to lower case, then capitalize the first letter %/
<<set $fname = $fname.toLowerCase()>>
<<capfirst "$fname">>
<<if $fname eq "Aster">>
Wait, I would rather not be confused with Aster the popular girl in our school. So how about I call myself something else?
<<set $fname = "Ellie">>
<br><br>
As for the other details,
<<elseif $fname eq "Paul" or $fname eq "Tyler">>
Wait, I would rather not be confused with the big-name jocks in our school. So how about I call myself something else?
<<set $fname = "Bruce">>
<br><br>
As for the other details,
<<elseif $fname eq "Jeremy" or $fname eq "Bobby">>
On second thought, I would rather not be confused with someone in my grade with the same name. How about I call myself something else?
<<set $fname = "Andrew">>
<br><br>
<<else>>
$fname here,
<</if>>
I go by ?they/?them, I'm a $skintone skinned $eyecolor eyed $gender with <<if $hairlength eq "no">>no<<else>>$hairlength $haircolor<</if>> hair.
<br><br>
That sounds about right?
<br><br>
[[Yes, more or less|c1_begin]].
<br>
<<back "No, I need to change something.">><h2 class="center">Chapter 1</h2>
"Hey, wait, essay ?kid," Paul the football star catches up to me in the school parking lot.
<br><br>
<<set _next = "c1_middle">>
<<choice_shown "Wait for him to say his piece." _next>>
<<fairmath "$bold" -5>>
<<set $text = `I stare at the dude wordlessly, waiting for him to explain himself.`>>
<</choice_shown>>
<<choice_shown '"The answer is no." I keep walking.' _next>>
<<fairmath "$kind" -5>>
<<fairmath "$bold" 5>>
<<set $text = `"Whatever you want to ask me," I keep walking, "the answer is no."<br><br>He blocks my path. "Hear me out, please."<br><br>I sigh in exasperation. "What?"`>>
<</choice_shown>>
<<choice_shown '"I have a name, you know."' _next>>
<<set $guess = "Ellie">>
<<if $gender eq "boy">><<set $guess = "Alex">><</if>>
<<set $text = `"I have a name, you know." I frown at him.<br><br>"Uh, it's ` + $guess + `, right?" He scratches his head.<br><br>`>>
<<if $fname neq $guess>>
<<set $text += `"No, it's $fname," I turn to go.<br><br>"$fname! I'm sorry!" He cuts me off again, "Hear me out, please!"`>>
<<else>>
<<set $text += `I nod. He continues. "Hear me out, please."`>>
<</if>>
<</choice_shown>>
<<choice_shown '"Twenty dollars for three pages. Ten for each page over."' _next>>
<<fairmath "$bold" 5>>
<<set $text = `"Twenty dollars for three pages. Ten for each page over," I give him my spiel. "Fifty if you want it today."`>>
<</choice_shown>>
/% [[c1_middle]] %/<<unset $guess>> /% don't need it anymore %/
<<text>>
"Can you help me write a love letter to Aster Wu?" Paul rubs his neck. "I'll pay you."
<br><br>
"Love le-?" I fumble to catch my armful of essays that almost scatter all over the floor. "No, no way."
<br><br>
"Why not? You wrote Jeremy's paper on <<whatis "Romeo And Juliet" "William Shakespeare's stageplay about a tragic romance">>..." he takes out a twenty.
<br><br>
<<set _next = "c1_twist", _skip = "c1_end">>
<<choice_shown '"How are those two types of writing comparable, you idiot."' _next>>
<<fairmath "$kind" -5>>
<<set $text = `"That's a literary analysis in the third person perspective, not first person proclamation of romantic intent," I turn to go. "Idiot!"<br><br>"Wait- look, I know I'm an idiot, that's why I need your help," he cuts me off again.`>>
<</choice_shown>>
<<choice_shown '"Because she already has a boyfriend." <i>And I would be writing from my heart instead of yours.</i>' _next>>
<<setFlag "crushAster">>
<<set $text = `"Because she already has a boyfriend... You are wasting your time," I turn to go, annoyed by the reminder that Aster is already spoken for.<br><br>"No, wait, I-I think she deserves better," he cuts me off again.`>>
<</choice_shown>>
<<choice_shown '"...Make that fifty, or no deal."' _skip>>
<<fairmath "$bold" 5>>
<<set $money += 50>>
<<fairmath "$rel_p" 10>>
<<set $text = `"...Make that fifty, or no deal," I could use the money.<br><br>Paul smiles ear-to-ear and fishes out tens and fives from his other pockets. One of the papers turns out to be his rough draft. And I mean rough. He says sheepishly, "See... I could really use your help."<br><br>"I got it," I sigh.`>>
<</choice_shown>>
/% [[c1_twist]] %/<<text>>
Paul hands me his rough draft. And it is <i>rough</i>.
<br><br>
"Look, this is such a personal declaration that it has to come from you," I stuff his draft into my folder to save both of us. "And I don't really know you to write from your perspective."
<br><br>
"Then let's hang out more, so you can get to know me," he shrugs.
<br><br>
<<set _next = "c1_end">>
<<choice_shown '"You know what, I\'m just going to write something vague. Ten bucks."' _next>>
<<fairmath "$kind" -5>>
<<set $money += 10>>
<<fairmath "$rel_p" -10>>
<<set $text = `"I don't have time to hang out with you. I've got bills to pay, Romeo," I sigh. "You know what, I'm just going to write something vague. Ten bucks."<br><br>"Uh..." he reaches into his pocket, but he sounds hesitant.<br><br>"You want it or not?" I rest a hand on my hips.<br><br>He reluctantly hands over a ten. I take it and leave.`>>
<</choice_shown>>
<<choice_shown 'I sigh. "Fine, meet me at lunch time outside the English classroom."' _next>>
<<fairmath "$kind" 5>>
<<setFlag "hangoutPaul">>
<<set $money += 20>>
<<fairmath "$rel_p" 10>>
<<set $text = `I sigh. "Fine, meet me at lunch time outside the English classroom."<br><br>Paul beams and hands me the twenty. I take it and leave.`>>
<</choice_shown>>
/% [[c1_end]] %/<<text>>
I have to hurry to get to my first class, but my mind is already working on ideas for the letter.
<<if $kind gt 50>>
Poor guy. Even if his own words aren't impressive, at least they're sincere.
<<else>>
What a doofus. Oh well. At least the doofus is paying.
<</if>>
<br><br>
<<link "End of Chapter" "c2_begin">><</link>><h2 class="center">Chapter 2</h2>
"Hey, essay wiz," Bobby the ex-student-president accosts me outside the English classroom during lunch time. "Where're the goods?"
<br><br>
"Here," I stuff a folder into his hands and try to walk in the other direction.
<br><br>
"Wait, what's this...?" He starts to read something. "Dear Aster, you are the nicest person I have ever met, and you are prettier than the lead singer of-"
<br><br>
"That's not yours," I snatch Paul's letter from him. I must have forgotten to throw it away!
<br><br>
"Wow, tell me you didn't write this," Bobby cackles, "or I think you owe me a refund."
<br><br>
<<if flag("hangoutPaul")>>
"?They didn't write it," Paul shows up out of nowhere. "I did."
<br><br>
"Now that makes more sense," Bobby bumps against Paul's arm on his way down the hall. "But Aster's out of your league, lover boy, just sayin'."
<br><br>
Paul doesn't seem bothered by that remark. He turns to me instead. "[[You okay|c2_chat]]?"
<<set $text = `"How can you stand that guy?" <i>Why am I upset for him?</i><br><br>He shrugs. "I'm used to it."`>>
<<else>>
<<set _next = "c2_middle">>
<<choice_enabled 'I feel my face burning. "There\'s no way I would\'ve written that!"' _next `flag("crushAster")`>>
<<fairmath "$bold" 5>>
<<set $text = `If only I could deny the blushing too. Curses!<br><br>He turns to leaves, but not before getting another laugh at my expense. "All the better, it's not like she needs more reasons to reject you."`>>
<</choice_enabled>>
<<choice_shown '"If you want a refund, hand over those essays," I don\'t need to out the poor guy.' _next>>
<<fairmath "$bold" -5>>
<<fairmath "$kind" 5>>
<<set $text = `"It's just a draft," I reach out a hand. "And if you want a refund, hand over the goods."<br><br>He turns to leave. "Naw, I'm sure it wasn't you, Shakespeare."`>>
<</choice_shown>>
<</if>>
/% [[c2_middle]] %/<<text>>
<<set _next = passage(), _done = "c2_end">>
<<choice_shown '"How much do you know about Aster?"' _next `notsaid("aster")`>>
<<run say("aster")>>
<<fairmath "$energy" -5>>
<<set $text = `"I know she moved here last year. She's super nice, never mean to anybody. One time she came to watch the regional championship with her boyfriend, I swear she's prettier than every cheerleaders there..." he trails off.<br><br>"She's more than just pretty, you know," I shake my head.<br><br>"Well of course, she's the nicest person-"<br><br>"-you've ever met, yes," I sigh.<br><br>"Right, you get me," he smiles.`>>
<</choice_shown>>
<<choice_shown '"So you know Aster already has a boyfriend..."' _next `notsaid("boyfriend")`>>
<<run say("boyfriend")>>
<<fairmath "$energy" -5>>
<<set $text = `"I know," Paul nods. "But I can't help how I feel about her. And I just want her to know that."<br><br>"You're forcing her to reject you," I shake my head.<br><br>He looks at me like a sad puppy. "Can you make sure I don't sound like a jerk, please?"<br><br>I sigh. "No promises."`>>
<</choice_shown>>
<<choice_shown '"What are your favorite things?"' _next `notsaid("fav")`>>
<<run say("fav")>>
<<fairmath "$energy" -5>>
<<set $text = `"Sausage tacos!" Paul blurts out his top choice, then lists out the rest. "Scoring a touchdown. Listening to Aster sing during music class..." he trails off.<br><br>"Hey, focus," I cross my arms. "Anything else?"<br><br>"Uh... I like... long walks in the park?" He shrugs.<br><br>I wonder if my head will fall off if I keep shaking it.`>>
<</choice_shown>>
<<choice_shown '"All right, gotta get started," I crack my knuckles.' _done>>
<<if saidnothing()>>
<<fairmath "$bold" -5>>
<<set $text = `"Oh, okay," Paul rubs his neck.`>>
<<else>>
<<set $text = `"Right," Paul looks relieved.`>>
<</if>>
<<set $text += `<br><br>Just then, Aster and a friend of hers appear around the corner. They wave at us, but continue down the other hall. Paul is transfixed at the sight of Aster, even for those brief few seconds until they disappear behind the other corner...`>>
<<setFlag "hangoutPaul" false>> /% don't need it anymore, event same as hasVisited("c2_chat") %/
<<run clearsaid()>>
<</choice_shown>>
/% [[c2_chat]] [[c2_end]] %/<<text>>
I crumple up the letter and walk over to a recycle bin, just as Aster appears from the corner with a friend of hers. They walk down the other hall without noticing me, but I
<<if flag("crushAster")>>
nearly trip over myself when I hear her say my name.
<<else>>
sure notice them when she says my name.
<</if>>
<br><br>
"...$fname could get into any school ?they <<verb 'wants' 'want'>>. I mean, have you seen ?their grades?" There is not a trace of sarcasm in her voice.
<br><br>
<i>I can't believe it.
<<if flag("crushAster")>>
She knows me too.
<<else>>
The most popular girl in school knows me.
<</if>>
</i>
<br><br>
<<set _next = "c2_end">>
<<choice_shown "I turn to watch her go..." _next>>
<<set $text = `I watch the two of them walk further down the hall.`>>
<</choice_shown>>
<<choice_shown "Run away." _next `flag("crushAster")`>>
<<fairmath "$bold" -10>>
<<set $text = `I try to run the other way so she doesn't see me.`>>
<</choice_shown>>
/% [[c2_end]] %/<<text>>
<i>It's going to be...
<<if flag("crushAster")>>
a bitter-sweet
<<else>>
an interesting
<</if>>
writing experience.
</i>
<br><br>
<<link "End of Chapter" "c3_begin">><</link>><h2 class="center">Chapter 3</h2>
I come home from the morning paper route to do the dishes that had been left soaking in the sink overnight. Well, at least food was eaten. I grab a sandwich from the freezer, hoping it wouldn't suddenly sprout the fuzzies since it's long past its expiration date. Speaking of which, there are due dates for my assignments too, technically not mine, but when money's on the line everything's my responsibility.
<br><br>
"$fname? Can you wash the dishes-"
<br><br>
"Already did!" I swing the backpack over my shoulder and head for the door.
<br><br>
"The milk had gone bad-"
<br><br>
"Sorry gotta go I'm late!" I close the front door and lock it. The door bell is busted. I wouldn't want some rando to just push into the house when no one responds.
<br><br>
<<set _next = "c3_middle">>
<<choice_shown "Dad is in no condition to deal with that shit, not since Mom passed away." _next>>
<<set $parent = "dad">>
<</choice_shown>>
<<choice_shown "Mom is in no condition to deal with that shit, not since Dad passed away." _next>>
<<set $parent = "mom">>
<</choice_shown>>
/% [[c3_middle]] %/I probably have all kinds of messed up feelings about my $parent letting grief take over ?their_sp life, but at the end of the day, I'm just glad ?they_sp is hanging in there. I'm old enough to take care of myself anyway.
<<if $money gte 10>>
Still got some green in my pocket to last a day<<if $money gt 20>> or two<</if>>.
<</if>>
<br><br>
Cross-legged on the floor somewhere among the disorganized shelves at the school library, I speed-read a poetry anthology in order to pick out pairs for compare-and-contrasts. And since there were three commissions from that class, I can't simply write about the same two poems three times.
<br><br>
"What I'm saying is you don't need to go to Juilliard to shine, babe," Tyler Carson's grating voice startles me, but I soon realize he is speaking to his girlfriend... Aster. "Dad said he can pay for your tuition at Georgia if their music program doesn't offer you a full scholarship."
<br><br>
They settle down at a small desk by the window at the end of the aisle, seemingly unaware that they are not alone in this isolated corner. I try to focus on the poetry, but my attention is already split.
<br><br>
"Let's make sure you pass the chemistry test, then," Aster replies softly as textbooks are being put onto the desk, "Did you already turn in the essay for the college application?"
<br><br>
"Of course, babe, and I didn't skimp on the treatment either," Tyler gloats, "you can't trust cheap labor for something so important." I remember turning him down for the rush job. Frankly, I only regret not being able to take the credit for getting him rejected from his dream college.
<br><br>
"I think they would have appreciated your true voice," Aster says.
<br><br>
Tyler scoffs. "They just want a star to make them more money, who cares about what I think?"
<br><br>
"I do, for starters," Aster flips a page, "All right, so this question, the equilibrium constant is a value that relates the ratio of the concentrations of what, once the reaction has reached chemical equilibrium?"
<br><br>
"Uh... pssh, whatever, D, products to temperature," Tyler chuckles, "everything calms down after blowing up, right?"
<br><br>
[[NEXT|c3_twist]]Aster patiently coaches him through what I assume is a practice test, until the jock stands up. "Great, now let's go get a drink! Need more reactant to this boring constant! Ha!"
<br><br>
If I had been keeping track, he would have gotten 47 percent of that test correctly. I wonder if his achievements in football is enough for the admissions office to overlook the other shortcomings. But then again, he will always have money as a backup plan.
<br><br>
"Sorry, I need to study for my exams now," Aster says with a resigned tone, "You go on ahead. Just read over these notes tonight."
<br><br>
"Oh, com'on, babe, you study everyday anyway, what's a few hours gonna do? At worst an A minus, am I right?" Tyler eggs her on. "You need to loosen up more, and the team loves you, come on! Everybody's gonna be there with their girlfriends, you wouldn't want me to look like a chump, do you?"
<br><br>
<<set _next = "c3_quiet", _inter = "c3_interrupt">>
<<choice_shown '"Only you can make yourself look like a chump!" I stand up to reveal myself.' _inter>>
<<fairmath "$bold" 10>>
<</choice_shown>>
<<choice_shown "I roll my eyes, but stay out of it." _next>>
<<fairmath "$bold" -5>>
<<if flag("crushAster")>><<fairmath "$bold" -5>><</if>>
<</choice_shown>>
<<choice_shown "Aster is her own person. She can handle this chump." _next>>
<<fairmath "$bold" -5>>
<<fairmath "$kind" 5>>
<</choice_shown>>
/% [[c3_interrupt]] [[c3_quiet]] %/Tyler turns to me with an annoyed look on his face. "Keep your nose down and write your essays, ?kid, or are you ticked I paid somebody else to do your job?"
<br><br>
"Leave ?them alone, Tyler," Aster keeps her voice gentle, but her stance is firm, "I know you are frustrated, but don't take it out on $fname who had saved you so many times before."
<br><br>
It takes Tyler a few seconds to get over her reaction, then he gathers up his things, murmurs a "I'm the one saving you hobos" before striding away from the window seat.
<br><br>
<<set _next = "c3_end">>
<<choice_shown '"Better remember what you learned for the test, or you might flunk out and not get to go to Georgia."' _next>>
<<fairmath "$bold" 5>>
<<fairmath "$kind" -5>>
<<set $text = `"Shut up, bookworm," Tyler throws back a half-hearted insult as he leaves, "at least I have a life."`>>
<</choice_shown>>
<<choice_shown '"We can\'t all buy our grades. Some of us have to put in extra hours after spending it on you.' _next>>
<<fairmath "$bold" 5>>
<<set $text = `"Then drop out and get a real job," Tyler throws back a half-hearted insult as he leaves, "maybe you aren\'t that great of a writer."`>>
<</choice_shown>>
<<choice_shown '"Aster is right, you should\'ve written that essay yourself."' _next>>
<<fairmath "$kind" 5>>
<<set $text = `Tyler snorts and walks away faster. "Yeah, whatevs, spykid."`>>
<</choice_shown>>
/% [[c3_end]] %/"I want to go to Juilliard, Tyler," Aster says in a calm voice, "so A minus would be disappointing."
<br><br>
Tyler scoffs. "But I'm not going there, babe, and I'm not sure a long-distance thing's gonna work out."
<br><br>
When Aster does not respond, Tyler repeats again, "Look, I promise you that we can give you a music career no matter where you go, so why not go with me?"
<br><br>
"Excuse me, Mr. Carson," the librarian sneaks onto the scene and whispers, "but can you keep it down? Your classmates are trying to study for exams." She then startles me with a well-meaning, "Please don't sit on the floor, young ?person, you'll catch a cold that way."
<br><br>
By the time I stand up to reveal myself to Tyler and Aster, I catch an annoyed look from the jock as he strides away from the window seat. "Whatevs, lady, none of y'all would even be here without my dad."
<br><br>
The librarian shakes her head and leaves after him.
<br><br>
[[NEXT|c3_end]]<<text>>
"Sorry about that," Aster tries to smile at me.
<br><br>
<<if flag("crushAster")>>
I rub my elbow.
<<else>>
I shrug.
<</if>>
"You didn't do anything wrong."
<br><br>
Aster's already weak smile falters as she looks down at her book, but she quickly regains her composure and offers the seat across from her. "Would you like to sit up here instead of the floor?"
<br><br>
<<set _next = "c3_chat">>
<<set _same = `Seeing me settling down with my mess of papers, she shifts back a little to give me more space.`>>
<<choice_shown '"N-no, I should let you get back to studying."' "end">>
<<fairmath "$bold" -5>>
<<fairmath "$kind" 5>>
<<set $text = `She nods, and resumes studying. `>>
<<if flag("crushAster")>>
<<set $text += `I steal another glance at her while `>>
<</if>>
<<set $text += `I gather up my things, then awkwardly exit the library.`>>
<</choice_shown>>
<<choice_shown 'I nod, then move my stuff to the small desk. "Thanks for standing up for me."' _next `hasVisited("c3_interrupt")`>>
<<fairmath "$rel_a" 5>>
<<set $text = `"Us bookworms have to stick together," her smile is more natural this time. ` + _same>>
<</choice_shown>>
<<choice_shown 'I nod. "Thanks."' _next>>
<<fairmath "$rel_a" 5>>
<<set $text = _same>>
<</choice_shown>>
/% [[c3_chat]] %/<<text>>
<<set _next = passage(), _done = "end">>
<<choice_shown '"Are you also studying for a Chemistry test?"' "c3_chat_whose" `notsaid("study")`>>
<<run say("study")>>
<<set $text = `"Not really," she shakes her head as she closes the Chemistry textbook to reveal another booklet underneath. "It's..." she hesitates to explain, and ends up changing the topic with a knowing smile. "So, whose assignments are those?"`>>
<</choice_shown>>
<<choice_shown '"Could I ask you about something?"' "c3_chat_ask" `notsaid("ask")`>>
<<run say("ask")>>
<<set $text = `She lifts her eyes to look at me. "Sure."`>>
<</choice_shown>>
<<choice_shown "Silence falls again as we return to working on our assignments." _done>>
<<if saidnothing(_topic)>>
<<fairmath "$bold" -5>>
<</if>>
<<set $text = `Not that I could really focus on the essays, since my mind keeps wandering to the thought of maybe, just maybe... <i>`>>
<<if flag("crushAster")>>
<<set $text += `I`>>
<<else>>
<<set $text += `?pnick`>>
<</if>>
<<set $text += ` might have a chance after all...</i>`>>
<<run clearsaid(_topic)>>
<</choice_shown>>
/% [[c3_chat_whose]] [[c3_chat_ask]] %/<<text>>
<<set _next = "c3_chat">>
<<choice_shown '"Uh... it\'s just for fun."' _next>>
<<fairmath "$bold" -5>>
<<set $text = `Aster's lips curl into the tiniest of smiles, but she does not press me further.`>>
<</choice_shown>>
<<choice_shown '"Wha, I mean," I fiddle with the papers, "um... well, confidentiality and all. Sorry."' _next>>
<<fairmath "$kind" 5>>
<<set $text = `Aster nods. "I can respect that."`>>
<</choice_shown>>
<<choice_shown "I give her a straight answer." _next>>
<<fairmath "$bold" 5>>
<<fairmath "$kind" -5>>
<<set $text = `Aster nods and looks down at her booklet. "Don't worry, your secret is safe with me."`>>
<</choice_shown>>
/% [[c3_chat]] %/<<text>>
<<set _next = passage(), _topic = "ask", _done = "c3_chat">>
<<choice_shown '"Do you know Paul Brickson, the... the football player in our school?"' _next `notsaid("paul", _topic)`>>
<<run say("paul", _topic)>>
<<fairmath "$rel_p" 5>>
<<set $text = `She nods. "He's one of Tyler's teammates."<br><br>"But I mean, more than just that," I'm not sure why a simple question can feel so awkward, "like, did he ever have a longer conversation with you besides saying hi or waving in the hallway, ugh... `>>
<<if $bold lt 50>>
<<set $text += `I don't know what I'm saying..."`>>
<<else>>
<<set $text += `yeah."`>>
<</if>>
<<set $text += `<br><br>Aster looks puzzled for a moment, but she considers my question earnestly. "He seemed nice, quite humble about his achievements in the games too, though honestly we had never spoken to each other directly, no more than the occasional greeting, as you said."<br><br>`>>
<<if $bold gt 50>>
<<set $text += `"I see," `>>
<</if>>
<<set $text += `I nod.`>>
<</choice_shown>>
<<choice_shown '"Was what happened just then... a low-key breakup?"' "c3_chat_breakup" `notsaid("breakup", _topic)`>>
<<run say("breakup", _topic)>>
<<fairmath "$bold" 10>>
<<fairmath "$kind" -10>>
<<fairmath "$rel_a" -5>>
<</choice_shown>>
<<choice_shown '"Is it going to be difficult getting into Juilliard?"' "c3_chat_challenge" `notsaid("jui", _topic)`>>
<<run say("jui", _topic)>>
<</choice_shown>>
<<choice_shown "<i>What else I can talk about...?</i>" _done `saidsomething()`>>
<<set $text = `...`>>
<<run clearsaid(_topic)>>
<</choice_shown>>
/% [[c3_chat_ask]] [[c3_chat_breakup]] [[c3_chat_challenge]] [[c3_chat]] %/Aster looks down, then turns toward the window, uncertain where to keep her gaze. "I, I don't know what that was."
<br><br>
<<set _next = "c3_chat_ask">>
<<choice_shown '"I\'m sorry, that was rude of me."' _next>>
<<fairmath "$bold" -5>>
<<fairmath "$kind" 5>>
<<set $text = `"It\'s all right," she looks down at the page.`>>
<</choice_shown>>
<<choice_shown '"If you ask me, I think you deserve more respect than just assuming you would give up your dream for him."' _next>>
<<fairmath "$bold" 5>>
<<set $text = `Aster shifts slightly in her seat, but doesn't seem to disagree with my comment.`>>
<</choice_shown>>
<<choice_shown '"I didn\'t mean to listen in, but I hope he doesn\'t treat you like this all the time."' _next>>
<<fairmath "$bold" -5>>
<<fairmath "$kind" 5>>
<<fairmath "$rel_a" 5>>
<<set $text = `She lets out a quiet sigh, then smiles. "Tyler means well."`>>
<</choice_shown>>
/% [[c3_chat_ask]] %/She slowly brushes a finger over the spine of the Chemistry textbook. "Yes, but that won't deter me."
<br><br>
<<set _next = "c3_chat_ask">>
<<choice_shown '"If there\'s anything I can do to help, just let me know."' _next `flag("crushAster")`>>
<<fairmath "$bold" 5>>
<<fairmath "$rel_a" 5>>
<<set $text = `"Thank you, I'll keep it in mind," Aster responds with a smile that feels less genuine than I had hoped, but I suppose a popular girl like her must be used to people tripping over themselves to cater to her every need...`>>
<</choice_shown>>
<<choice_shown '"That\'s the spirit," I give her the best smile I can muster.' _next>>
<<fairmath "$kind" 5>>
<<set $text = `She smiles back, even if a little awkwardly. "Thanks... I think."`>>
<</choice_shown>>
<<choice_shown '"Although I hate to agree with Tyler about you not needing Juilliard to shine," I glance at her before quickly looking down at the books on the desk, "I think this is a good path to pursue."' _next>>
<<fairmath "$bold" -5>>
<<fairmath "$kind" 5>>
<<fairmath "$rel_a" 5>>
<<set $text = `Aster stifles a giggle. "Thanks for the vote of confidence."`>>
<</choice_shown>>
/% [[c3_chat_ask]] %/<<text>>
<br>
<h2>End of Demo</h2>
<br>
Thanks for reading.
<<achieve "end">><h2>Overview</h2>
<ul style="list-style-type: none;">
<li>
📁 project
<ul style="list-style-type: none;">
<li>📁 fonts</li>
<li>📁 images</li>
<li>📁 src
<ul style="list-style-type: none;">
<li>📁 css</li>
<li>📁 js</li>
<li>📁 twee
<ul style="list-style-type: none;">
<li>📁 meta</li>
<li>📁 story</li>
<li>📁 ui</li>
</ul>
</li>
</ul>
</li>
<li>📁 vendor
<ul style="list-style-type: none;">
<li>📁 chapel</li>
<li>📁 cyrus</li>
<li>📁 HiEV</li>
<li>📁 tme</li>
</ul>
</li>
<li>📄 compile.bat</li>
</ul>
</li>
</ul>
<b>Notes</b>
<ul>
<li>
I prefer to include all needed fonts locally with the project as opposed to linking to a URL, because the former method allows the game to be playable when there is no internet connection.
</li>
<li>
My current code tries to look for a "favicon.ico" in the images folder, but you can remove/disable that code in ui.js, which can be found inside "src/js" folder.
</li>
<li>
If you want to use the Twine editor, copy-paste content from every .js file under "src/js" into the Story Javascript section of your project, and copy-paste content from every .css file under "src/css" into the Story Stylesheet section of your project. For passages, you will have to create each passages in the Twine editor, then copy-paste from the corresponding passages in the .tw files under the "src/twee" folder. With Twine editor, StoryData passage content won't be needed, and the Twine editor should generate a new IFID when you create a new project in the editor.
</li>
<li>
Assuming you have Tweego compiler downloaded and prepared with all the necessary storyformat files, I created a Windows batch file named "compile.bat" that contains Tweego command (and there is a commented-out command that could auto-zip your project files for uploading to itch.io, but you have to have a Zip program that works in command line). This is optional for your workflow.
</li>
<li>
Code for statbar generation and image inclusion are in "src/twee/meta/widgets.tw". Code for achievements is in "src/twee/ui/achievements.tw". Code for fairmath is in "src/js/calculation.js". Code for a multireplace that is specifically for singular or plural verb conjugation is in "src/js/pverb.js". The MC's singular/plural verb conjugation widget (<<verb>>) is part of chapel's pronouns code, which can be found in "vendor/chapel/pronouns.js". Code for notification is in "vendor/chapel/notify.js" and styled with "vendor/chapel/notify.css".
</li>
<li>
When editing the "src/js/config.js" file for options such as adding more levels of undo and more save slots, consult the [[Config API|https://www.motoslave.net/sugarcube/2/docs/#config-api]] documentation for SugarCube.
</li>
</ul>
[[Play a demo story|prologue]], or read notes on
<<link "link syntax" "linksyntax">><</link>>,
<<link "stat page" "statspage">><</link>>,
<<link "templates" "templates">><</link>>, or
<<link "choice loops" "choiceloops">><</link>><h2>Notes on link syntax</h2>
The usual wiki style bracket linking syntax works fine, and they will create arrows in the Twine editor, whereas the <<link>> syntax will not (this behavior might or might not be desirable). My <<choice_shown>> and <<choice_enabled>> widgets were tweaked based on <<link>> widget, so they won't generate arrows in the Twine editor, nor when using the [[dotgraph|https://mcdemarco.net/tools/scree/dotgraph/]] storyformat to create a flowchart. You can force arrow-generation by using SugarCube comments around the bracket link: /% [[linkname]] %/ (the Twine editor will recognize it while the viewer will not see it)
<br><br>
<<choice_shown>> or <<choice_enabled>> widgets will accept a third <i>optional</i> parameter that is a condition check. Use tick mark (the symbol under the tilda sign to the left of the 1 key) to wrap the conditional statement. Examples:
<pre>
/% like wrapping a choice within an if in ChoiceScript %/
<br>
<<choice_shown "link text" "targetpassage" `($kind gt 50)`>>
<br>
...
<br>
<</choice_shown>>
<br><br>
/% like selectable_if in ChoiceScript %/
<br>
<<choice_enabled "link text" "targetpassage" `($kind gt 50)`>>
<br>
...
<br>
<</choice_enabled>>
</pre>
<br>
If you get tired of typing such a long macro name all the time, and that you feel confident you won't get confused by an abbreviated name, consider adding the following to the end of "src/js/choices.js":
<pre>
/* alias for choice links */<br>
Macro.add('cs', 'choice_shown');<br>
Macro.add('ce', 'choice_enabled');
</pre>
<br>
<<set _next = "statspage">>
<<choice_shown "this link does not check for condition, so will always be visible and clickable" _next>>
<</choice_shown>>
<<choice_enabled "this link will never be clickable because I gave it the condition 'false'" _next `false`>>
<</choice_enabled>>
/% [[statspage]] %/<h2>Notes on stat page</h2>
I'm not yet skilled enough to not mess up the SugarCube history system in an attempt to keep stat page at the passage level as opposed to using the popup dialog system to display pages that I don't want to be tracked by the history system. I want the engine to only remember what it needs to remember and no more, because I expect my project to be long and may already have too many variables and passages to keep track of. If you are comfortable with remembering the last main story page in some kind of "return" variable and then generate a back link to return to the story from the stat (or any extra information) page, feel free to use that approach and not depend on dialog popups. There are existing SugarCube template on itch.io that tries that method, which is fine if coded carefully. The clear advantage of that method is how the information displayed at the passage level feel less cramped than when forced into an even smaller dialog box.
<br><br>
The CSS of the current statbar is not yet perfect, but it is the simplest I can prepare for relative beginners who are coming in from having coded in ChoiceScript. If you feel confident with CSS and/or Javascript, please don't hesitate to use more complex setup (such as chapel's [[Meter macros|https://github.com/ChapelR/custom-macros-for-sugarcube-2/blob/master/docs/meter-macros.md]]).
<br><br>
You do not need chapel's dialog macro set, but I find it keeps the code clean when there's a call to open a dialog window, i.e:
<pre>
<<link 'About'>><br>
<<popup 'credits-passage' 'Credits'>><br>
<</link>>
</pre>
compared to default SugarCube version:
<pre>
<<link 'About'>><br>
Dialog.setup("Credits");<br>
Dialog.wiki(Story.get("credits-passage").processText());<br>
Dialog.open();<br>
<</link>>
</pre>
<<back "BACK">><h2>Notes on Template</h2>
[[Templates|https://www.motoslave.net/sugarcube/2/docs/#template-api]] are useful for pronoun-related words, especially when your story have gender-flippable non-player characters. The inspiration came from chapel's pronouns.js code, which manages the template for MC's pronoun-related words, like ?they or ?them. So as an example, you can define the same set of templates for a character b, and can name the templates something like ?bthey or ?bthem, etc. Templates save storage space because they are not copied multiple times if your project tracks several history states. They are like the static <b>setup</b> object, where everything associated with them only have one instance in the entire project.
<br><br>
Another way I use template in my main project is to vary how the MC or another character may be referred to by others based on their relationship with the said person. Whether you save the new "name they use to call the person" in a standard variable or template, it will require calculation at the time of referencing the person (ie. if relationship value is over a certain threshold for X, call them X; if less than, call them something else, etc.), and I find that coding using the template saves typing instead of having to call a function. Your mileage might vary, of course.
<br><br>
<<back "BACK">><h2>A note on choice loops</h2>
Unlike the simplified "disable_reuse" and "hide_reuse" in ChoiceScript, I thought to make a generalized choice loop logic. You can find the exact code in "src/js/chats.js", but the gist is using an array variable named $chats to keep track of what has been said for the scope of the conversation (in other words, if you want to remember a specific thing someone said in the story long into the future, still use a separate flag variable).
<br><br>
Combined with the custom choice link coding, you can either let an already-said line be disabled using <<choice_enabled>>, or remove it from the list with <<choice_shown>>. In general I keep something like this for copy-and-pasting into the story:
<pre>
<<set _next = passage(), _done = "">><br>
<<choice_shown '""' _next `notsaid("")`>><br>
<<run say("")>><br>
<<set $text = ``>><br>
<</choice_shown>><br>
<<choice_shown '""' _next `notsaid("")`>><br>
<<run say("")>><br>
<<set $text = ``>><br>
<</choice_shown>><br>
<<choice_shown '""' _next `notsaid("")`>><br>
<<run say("")>><br>
<<set $text = ``>><br>
<</choice_shown>><br>
<<choice_shown "" _done>><br>
<<if saidnothing()>><br>
<<set $text = ``>><br>
<<else>><br>
<<set $text = ``>><br>
<</if>><br>
<<run clearsaid()>><br>
<</choice_shown>><br>
</pre>
This is a top-level choice loop, but if you want to go into another level of choice/dialog loop, that template would look like:
<pre>
<<set _next = passage(), _topic = "", _done = "">><br>
<<choice_shown '""' _next `notsaid("", _topic)`>><br>
<<run say("", _topic)>><br>
<<set $text = ``>><br>
<</choice_shown>><br>
<<choice_shown '""' _next `notsaid("", _topic)`>><br>
<<run say("", _topic)>><br>
<<set $text = ``>><br>
<</choice_shown>><br>
<<choice_shown '""' _next `notsaid("", _topic)`>><br>
<<run say("", _topic)>><br>
<<set $text = ``>><br>
<</choice_shown>><br>
<<choice_shown "" _done>><br>
<<if saidnothing(_topic)>><br>
<<set $text = ``>><br>
<<else>><br>
<<set $text = ``>><br>
<</if>><br>
<<run clearsaid(_topic)>><br>
<</choice_shown>><br>
</pre>
Just remember to clearsaid() and clearsaid(_topic) when both conversations were to be considered finished. Otherwise future choice loops that might unintentionally share the same topic name will be skipped over.
<br><br>
<<back "BACK">><<if $achieved>><<set _n = Object.keys($achieved).length>>
<<else>><<set _n = 0>>
<</if>>
<<if setup.achievements>>
<<set _total = Object.keys(setup.achievements).length>>
<<else>><<set _total = 0>>
<</if>>
You have unlocked _n of _total possible achievements.
<br><br>
<<if setup.achievements>>
<<for _i, _a range setup.achievements>>
<<if $achieved>><<set _unlocked = $achieved.hasOwnProperty(_i)>>
<<else>><<set _unlocked = false>>
<</if>>
<<if _unlocked>><i class="icon-lock-open"></i>
<<else>><i class="icon-lock"></i>
<</if>>
<<if _a['visible'] or _unlocked>>
<b><<= _a['title']>>:</b>
<<if _unlocked>><<= _a['post']>>
<<else>><<= _a['pre']>>
<</if>>
(<<= _a['points']>> pts)
<<else>>?
<</if>>
<br>
<</for>>
<</if>>/* usage: <<achieve "achievementid">> */
<<widget "achieve">>
<<set _id = _args[0]>>
<<set _title = setup.getAchievementTitle(_id)>>
<<set _alert = setup.getAchievementAlert(_id)>>
/* use square bracket to force object key interpretation */
/* don't use persistent storage for achievements; always starts from 0 unlocked per play-through */
<<if $achieved === undefined>>
<<set $achieved = {}>>
<</if>>
<<set $achieved[_id] = true>>
<<notify 2s>>
<b>Achievement:</b> _title
<hr>
_alert
<</notify>>
<</widget>>
/* set up potential achievements */
<<widget "achievement">>
<<set _id = _args[0]>>
<<set _visible = _args[1]>>
<<set _points = _args[2]>>
<<set _title = _args[3]>>
<<set _pre = _args[4]>>
<<set _post = _args[5]>>
<<if _args.length eq 6>>
<<if setup.achievements === undefined>>
<<set setup.achievements = {}>>
<</if>>
<<set _obj = { 'id': _id, 'visible': _visible, 'points': _points, 'title': _title, 'pre': _pre, 'post': _post}>>
<<set setup.achievements[_id] = _obj>>
<</if>>
<</widget>><<if hasVisited("c1_begin")>>
My name is $fname. I'm a $skintone skinned $eyecolor eyed $gender with <<if $hairlength eq "no">>no<<else>>$hairlength $haircolor<</if>> hair. It's my final year in high school.
<<else>>
I'm a high-school senior.
<</if>>
<br>
I have $money buck<<if $money gt 1>>s<</if>> at the moment.
<br>
<<statbar "$energy" "Energy">>
<br>
<b>Personality:</b><br>
<<statbar "$bold" "Bold" "Timid">>
<<statbar "$kind" "Mean" "Kind">>
<b>Relationships:</b><br>
<<statbar "$rel_a" "Aster">>
<<statbar "$rel_p" "Paul">><div id="interface">
<div id="header" data-passage="Header"></div>
<div id="passages"></div>
<div id="footer" data-passage="Footer"></div>
</div><div id="storytitle"><<include "StoryDisplayTitle">></div>
<div id="menu"><<include "Menu">></div><<include "MenuBack">>
<<include "MenuStats">>
<<include "MenuSave">>
<<if setup.achievements>><<include "MenuAchievements">><</if>>
<<include "MenuSettings">>
<<include "MenuRestart">><<set _text = '<i class="icon-ccw"></i>'>>
<<if State.length gt 1>>
<span class="menuicon" aria-label="rewind once" title="go backward once, in case of misclick">
<<link _text>><<script>>Engine.backward();<</script>><</link>>
</span>
<span class="menutext">
<<link "back">><<script>>Engine.backward();<</script>><</link>>
</span>
<<else>>
<span class="menuicon disabled"><<link _text>><</link>></span>
<span class="menutext disabled"><<link "back">><</link>></span>
<</if>><span aria-label="information about the main character and other relevant details" title="information about the main character and other relevant details">
<span class="menuicon">
<<set _text = '<i class="icon-info"></i>'>>
<<link _text>><<popup 'Stats' "Stats">><</link>>
</span>
<span class="menutext">
<<link "stats">><<popup 'Stats' "Stats">><</link>>
</span>
</span><span aria-label="save or load progress" title="save or load progress">
<span class="menuicon">
<<set _text = '<i class="icon-floppy"></i>'>>
<<link _text>><<ui 'saves'>><</link>>
</span>
<span class="menutext">
<<link "save">><<ui 'saves'>><</link>>
</span>
</span><span aria-label="show achievements" title="show achievements">
<span class="menuicon">
<<set _text = '<i class="icon-star"></i>'>>
<<link _text>><<popup 'Achievements' "Achievements">><</link>>
</span>
<span class="menutext">
<<link "achievements">><<popup 'Achievements' "Achievements">><</link>>
</span>
</span><span aria-label="change color scheme or font for reading" title="change color scheme or font for reading">
<span class="menuicon">
<<set _text = '<i class="icon-cog"></i>'>>
<<link _text>><<ui 'settings'>><</link>>
</span>
<span class="menutext">
<<link "settings">><<ui 'settings'>><</link>>
</span>
</span><span aria-label="restart from title screen" title="start over from title screen">
<span class="menuicon">
<<set _text = '<i class="icon-to-start"></i>'>>
<<link _text>><<ui 'restart'>><</link>>
</span>
<span class="menutext">
<<link "restart">><<ui 'restart'>><</link>>
</span>
</span><<link "credits">><<popup 'credits' "credits">><</link>>