/r/twinegames

Photograph via snooOG

r/twinegames is a subreddit dedicated to discussion of the game creation tool Twine.

WHAT IS TWINE?

Twine is a game creation tool that allows anyone to create their own interactive stories and games.

WHAT IS /R/TWINEGAMES?

/r/twinegames is a subreddit dedicated to the discussion of Twine and Twine games. Feel free to share your games here! You can ask technical questions here or at IntFiction.org's official Twine Section.

WHAT SHOULD I KNOW BEFORE I POST HERE?

  • Be nice.

  • Please follow Reddiquette.

  • Please do not delete your post if it contains useful information in the replies, as it may be useful to others.

  • We have a Discord server.


INTRODUCTIONS TO TWINE

WORKING WITH TWINE


STORY FORMATS

COMPILERS


TWINE GAME REPOSITORIES

/r/twinegames

9,932 Subscribers

2

Need help with syntax to show an image inside script

Hey all.

I'm trying to get help from ChatGPT but it seems his knowledge in sugarcube is limited.

I defined a list with images URL's and I'm trying to show an image based on that list:

<<script>>

const svars = State.variables;

const tvars = State.temporary;

State.variables.enemyImageUrls = {

"Homeless": "Images/Homeless.png",

"Thief": "Images/Thief.png",

"Lawyer": "Images/Lawyer.png",

};

<</script>>

<div class="enemy-container">

<<for _enemy range $spawnedEnemies>>

<div class="enemy-card"><img src="<<= enemyImageUrls\[\_enemy.type\] >>" class="enemy-image" alt="Enemy Image"><div class="enemy-stats"><p>Type: <<print \_enemy.type>></p><p>Strength: <<print \_enemy.baseStrength>></p><p>Agility: <<print \_enemy.baseAgility>></p><p>Violence: <<print \_enemy.baseViolence>></p></div></div>

<</for>>

</div>

It seems in the chrome console that the URL isn't being recognized properly:

Error: <<=>>: bad evaluation: svars is not defined

<<= svars.enemyImageUrls\[\_enemy.type\] >>

and:

Failed to load resource: net::ERR_FILE_NOT_FOUND, file:///C:/Users/user/Documents/Twine/Stories/Story/%3C%3C=%20enemyImageUrls[_enemy.type]%20%3E%3E

Appreciate your help!

2 Comments
2024/10/31
18:01 UTC

4

Only shows one of the two links, whichever code is on top.

It was initially working and then I added some additional pronouns and it just broke down. Depending on which section of code is at the top, it only shows that one link. At first it would show both links if ...her was up top but now that's not working either. Any help would be appreciated, this is my first time doing any sort of coding so I'm just trying to figure it out :)

Here is my code:

<<link '...him'>>

<<set $Damien to "Damien";

$dhe to "he";

$dhe's to "he's";

$dhis to "his";

$dhim to "him";

$dhimself to "himself";

$dmerman to "merman";

$dmale to "male";

$dman to "man";

$dson to "son";

$dhandsome to "handsome";

$dmaster to "master";

$dHe to "He";

$dHe's to "He's";

$dHim to "Him";

$dHis to "His";

$dHimself to "Himself";

$dMerman to "Merman";

$dSon to "Son";

$dMale to "Male";

$dMan to "Man";

$dHandsome to "Handsome";

$dMaster to "Master">>

<<set $D to "1">>

<<goto [[...him]]>>

<</link>>

<<link '...her'>>

<<set $Damien to "Dahlia";

$dhe to "she";

$dhe's to "she's";

$dhis to "hers";

$dhim to "her";

$dhimself to "herself";

$dmerman to "mermaid";

$dmale to "female";

$dman to "woman";

$dson to "daughter";

$dhandsome to "beautiful";

$dmaster to "mistress";

$dHe to "She";

$dHe's to "She's";

$dHim to "Her";

$dHis to "Hers";

$dHimself to "Herself";

$dMerman to "Mermaid";

$dSon to "Daughter";

$dMale to "Female";

$dMan to "Woman";

$dHandsome to "Beautiful";

$dMaster to "Mistress">>

<<set $D to "2">>

<<goto [[...her]]>>

<</link>>

5 Comments
2024/10/31
17:01 UTC

3

Learning Twine: How do I…

Hey! I’m currently learning Twine(very VERY new to it) and am unsure how to approach something.

I’m creating a prototype for an exploration/choice narrative game. The player can choose to click things in the environment, once all 4 options are chosen, the environment changes slightly to add a new interact-able thing within the environment. How would I code that/link that up?

Thank you!

2 Comments
2024/10/31
15:51 UTC

3

How to make this work (if checkbox selected it sets a variable to a number)

Hey everyone, I’m relatively new to Twine and I'm working on a project for history and I want to add a store and for this I am trying to make it so each time the one checkbox is selected it with add 1 to $bacon_cont but this code is not working. Does anyone know? (needs answer quick)

(b4r:"solid","solid","solid","solid")+(b4r-size:2,2)+(b4r-colour:black,black,black,black)[Price: $0.30]
[<img src="https://png.pngtree.com/png-vector/20240825/ourmid/pngtree-crispy-bacon-clipart-illustration-digital-watercolor-style-food-png-image_13613539.png" width="150" height="150" style="position: absolute; top: 3; left: 0;">[(checkbox: bind $bacon_cont_T_or_F,"BUY $bacon_cont")]]

(if: (checkbox: bind $bacon_cont_T_or_F) is 'true')[(set: $bacon_cont to (num: it) + 1)]
1 Comment
2024/10/31
14:24 UTC

5

Creating an image Carousel?

Hi there,

For my Twine project, I want to make an image carousel that allows the player to interactively look through different images and content. Think kind of like the top of a Steam page where you have thumbnail images at the bottom for a game and you can click the thumbnails to show it bigger on the main feature. I'd also like to be able to embed a video as well , if possible. However, I'm not sure where to start on this.

Is there an existing method to do this in Twine that's, hopefully, not too complex? Is there a plugin or process that can be used to do this? I'd love any advice you can give. Pleae let me know.

2 Comments
2024/10/31
09:30 UTC

2

Tweenode - A neat JS wrapper for Tweego

Easily download and setup Tweego, then compile using a JS API

Why:

I wanted an easy way to use Tweego as part of a more complex pipeline For example, bundling with Webpack or Rollup And an automatic way to set up Tweego for any project, making getting started with contributions thought git as simple as using npm install On my testing, it seems stable enough, but testers and bug reports are appreciated, as well as suggestions

Basic Usage

import { Tweenode, setupTweego } from 'tweenode'

// Will create a folder called .tweenode and download Tweego to it
// Won't download again if the folder is already there
await setupTweego()

// Instantiate Tweenode, you can pass some setup configs
const tweego = new Tweenode()

await tweego.process({
  input: {
    storyDir: 'path/to/story',
  },
  output: {
    mode: 'file', // Write to a file or return as a string
    fileName: 'path/to/output.html',
  },
})

Links

For suggestions and bug reports, check out the issue tracker

1 Comment
2024/10/30
01:27 UTC

5

Can someone write or recommend so something like an 'except' function?

So I'm looking for a shortcut, maybe as a macro or something. I have a lot of instances where I want to avoid using long loops and just single out specific array instances for js functions, particularly .delete. Or can someone direct me to resources on how to build myself such a shortcut? Unfortunately I'm not very good with js but happy to try.

Example:

I want to delete all the captives from awayteam except 'spock' and 'bones'.

Right now:

<<for _i to 0; _i lt $awayteam.length; _i ++>>

<<if $captives.includes($awayteam[_i]) and $awayteam[_i] neq 'spock' and $awayteam[_i] neq 'bones'>>

<<set $awayteam.delete($awayteam[_i])>>

<</if>>

<</for>>

This method works okay for simple examples like the above but is getting precarious when I start including more detailed conditions or deleting groups arrays from other arrays under specific conditions, and is just quite tedious.

My absolute dream would be something like:

<<set $awayteam.delete($captives) except ['bones', 'spock']>>

<<set $awayteam.delete($captives) except $cantbecaptured>>

It would be cool to be able to do this for push and slice as well.

I don't know how doable or practical this would be, or whether something like this exists. Any thoughts? Many thanks!!

2 Comments
2024/10/30
18:55 UTC

3

How to stop the string data in my click macro from highlighting multiple instances?

Sorry if this is a very simple question but I'm having difficulty using the click macro (click-append:). I want the word "her" to be clickable to reveal the next line of text, however, it's also highlighting the "her" in the word "there" as clickable.

Is there a way I can specify the string data only to attach the macro to the actual word?

Here's the code:

And there, in the middle of it all, the stocks hold her. (click-append: "her")[Her once flowing copper hair hangs limp.]
2 Comments
2024/10/30
16:45 UTC

5

Need help please

Hi, I'm having issues with a game I'm writing. I've got a variable in my character creation to set a custom profession for the MC. But, if the profession is something like engineer the text comes out as I'm a engineer instead of I'm an engineer. I'm not sure how to code this so the text uses a or an depending on what the profession is.

4 Comments
2024/10/30
14:57 UTC

1

Let's make a game! 183: Starvation

0 Comments
2024/10/30
05:02 UTC

6

Help to make a minigame (rhythm style).

So, one update, success, i guess? I finally got a code to work, its pretty simple but functionable, anyway, i deleted the comments cuz it was a mess, but i'll repost here. Hope this help somebody.

Hello everyone! I'm a complete dumass when it comes to coding, but alas, i'm trying to make a game in SugarCube, and course, i want to put averything and anything in it. I'm using the 2.9.2 version of it. here is the question. I want to sorta put a "battle system" that is pressing the keys in a set period of time. For example, the screen is going to show the four direction arrows,up, down, left, right and a bar below, flow of the battle(?). when the battle start a random arrow would be highlighted if the player input the wrong key, he would lose a little bit of the battle flow(bf), and another arrow would be highlighted. If the player is too slow or don't press any keys, he would keep losing bf until he loses all bf or press something. And to win it would be just pressing the right keys until he fills the bf in his favor. Can it be done? I used chatGPT a lot to help me, but 99% of the time it screws me over cuz i don't know what i'm doing, then i try to go to the Twine cookbook and get even more lost. Sorry if its too confusing. Oh right, and to complete everything, this is my firdt Reddit post, so... sorry if i screwded something up!

*latest code*
this code is suposed to go in the passage where you want the mini game to run.

:: Minigame Passage
<div id="arrowDisplay">
    <span id="up" class="arrow">↑</span>
    <span id="down" class="arrow">↓</span>
    <span id="left" class="arrow">←</span>
    <span id="right" class="arrow">→</span>
</div>

<div id="score">
    Correct Presses: <span id="correctCount">0</span><br>
    Missed Presses: <span id="missedCount">0</span>
</div>

<<linkreplace"start">> 
<<run startDemoGame()>>
<</linkreplace>>

<div id="resultMessage"><!-- Placeholder for win/lose message and link --></div>

<script>
    // Only define the game functions and variables if they haven’t been defined before
    if (typeof startDemoGame === 'undefined') {
        window.arrowKeys = ["up", "down", "left", "right"];

        function startDemoGame() {
            if (SugarCube.State.variables.gameStarted) return;
            SugarCube.State.variables.gameStarted = true;
            SugarCube.State.variables.correctPresses = 0;
            SugarCube.State.variables.missedPresses = 0;
            SugarCube.State.variables.gameEnded = false;
            document.getElementById("correctCount").textContent = SugarCube.State.variables.correctPresses;
            document.getElementById("missedCount").textContent = SugarCube.State.variables.missedPresses;
            document.getElementById("resultMessage").innerHTML = ""; // Clear any previous messages

            showArrow();
            SugarCube.State.variables.intervalId = setInterval(showArrow, 2000);
        }

        function showArrow() {
            window.arrowKeys.forEach((arrow) => {
                const arrowElem = document.getElementById(arrow);
                arrowElem.classList.remove("highlight", "correct", "incorrect");
            });
            
            SugarCube.State.variables.currentArrow = window.arrowKeys[Math.floor(Math.random() * window.arrowKeys.length)];
            document.getElementById(SugarCube.State.variables.currentArrow).classList.add("highlight");
        }

        window.addEventListener("keydown", function(event) {
            if (!SugarCube.State.variables.gameStarted || SugarCube.State.variables.gameEnded) return;

            const keyMap = { "ArrowUp": "up", "ArrowDown": "down", "ArrowLeft": "left", "ArrowRight": "right" };
            const playerChoice = keyMap[event.key];

            if (playerChoice) {
                event.preventDefault();
                
                const arrowElem = document.getElementById(SugarCube.State.variables.currentArrow);
                if (playerChoice === SugarCube.State.variables.currentArrow) {
                    SugarCube.State.variables.correctPresses++;
                    arrowElem.classList.add("correct");
                } else {
                    SugarCube.State.variables.missedPresses++;
                    arrowElem.classList.add("incorrect");
                }
                
                document.getElementById("correctCount").textContent = SugarCube.State.variables.correctPresses;
                document.getElementById("missedCount").textContent = SugarCube.State.variables.missedPresses;

                if (SugarCube.State.variables.correctPresses >= 10) {
                    endGame("win");
                } else if (SugarCube.State.variables.missedPresses >= 10) {
                    endGame("lose");
                } else {
                    setTimeout(showArrow, 500); // Delay before showing the next arrow
                }
            }
        });

        function endGame(result) {
            clearInterval(SugarCube.State.variables.intervalId);
            SugarCube.State.variables.gameStarted = false;
            SugarCube.State.variables.gameEnded = true;

            // Set win/lose state variables
            SugarCube.State.variables.win = (result === "win");
            SugarCube.State.variables.lose = (result === "lose");

            // Display the result message and link to the next passage
            let message = SugarCube.State.variables.win ? "Great, you won!" : "Oh no, you lost.";
            message += `<br><a href="javascript:void(0);" onclick="SugarCube.Engine.play('4');">Continue to the next passage</a>`;
            $("#resultMessage").html(message);
        }
    }
</script>

<style>
#arrowDisplay {
    font-size: 2em;
    text-align: center;
    margin: 10px 0;
}
.arrow {
    opacity: 0.3;
    transition: opacity 0.3s;
}
.highlight {
    opacity: 1;
    color: yellow;
}
.correct {
    color: blue;
}
.incorrect {
    color: red;
}
#score {
    margin-top: 10px;
    font-size: 1.2em;
}
</style>

This is in a next passage, so that you can condition a win/lose situation

<<print (SugarCube.State.variables.correctPresses)>>
<<if (SugarCube.State.variables.correctPresses >= 10)>>
YOU WIN! 
[[Next]]
<<elseif (SugarCube.State.variables.missedPresses >= 10)>>
YOU LOSE!
[[Next]]
<</if>>

This last passage i just included to show that you can go to the mini game passage again no problem.

Start minigame again!

[[1]]

0 Comments
2024/10/29
18:46 UTC

4

Suggest some female pov games or transformation games.

Basically the title don't mind the nsfw games as well.

3 Comments
2024/10/29
05:30 UTC

5

Utilizing/making a function to run a if/elseif/else statement in SugarCube

So, I'm very new to coding in general - I've done maybe a dozen hours of codecademy for a few different things (some HTML and CSS a while back, then a tiny bit of Python and some JavaScript in the past couple days), so this is probably a super basic question, but the SugarCube documentation is roughly 90% Greek to me. All this to say that I would appreciate a good deal of over-explanation and layman's terms.

I'm trying to set up a basic stat system for the player, and I'd like to have menus display a string rather than the raw variable (which is an integer/number between 0 and 4, depending on how many points they've put into that stat.

Good news: I've already figured out the SugarCube code to do what I want:

<<if $height == 4>> "Towering"

<<elseif $height == 3>> "Tall"

<<elseif $height == 2>> "Average"

<<elseif $height == 1>> "Short"

<<else>> "Very Short"

<</if>>

However, copying and scanning through this for four different variables/stats when I'm trying to troubleshoot/bugfix is a pain, so I figured, 'why not set up a function to run this if/elseif/else statement? It'll be, like, one-fifth the size and super-simple to check over! Eureka!

The Problem: I can't figure out how to set up such a function. Some googling around made me wonder about doing it via JavaScript (and I figured out the transliterated(?) version for that if/elseif/else statement in JavaScript, but then I ran into the issue of passing SugarCube variables into JavaScript and spitting them back out, which was a headache to say the least), but some other forum interactions makes me think that macros and/or widgets would work, but again - the documentation's mostly Greek to me, and doesn't give anywhere near enough hand-holding context for me to figure out how to actually utilize anything.

Any help would be appreciated!

6 Comments
2024/10/29
04:18 UTC

5

Conditional images + Widgets in links?

Hi ! Sorry for the dumb question, I'm a novice at Twine (or any kind of coding).

I've figured out how to do a lot of things myself, but I've been banging my head against the wall over the last two days trying to do this.

I'm using Sugarcube 2.37 and I'm working a fast travel map that does these things:

  • You can click on a link to go to the place/passage
  • Characters' icons are shown on the map (in the links) so you can see where they are
  • Clicking on a link adds time in the counter based on the distance between your current neighborhood and your destination neighborhood
  • Links are greyed out if certain requirements are not met (i.e. time, relationships, skills, etc)

So far, I have these two types of links:

Links that can show character's icons, and can be greyed out with the span :

<span class = "link-inactive">
  <a data-passage="Passage name" class="link-internal link-image"> Place name
    <<if ($character1.Location is "Place name")>><img src="character img source"><<else>><</if>>
    <<if ($character2.Location is "Place name")>><img src="character img source"><<else>><</if>>
    <<if ($character3.Location is "Place name")>><img src="character img source"><<else>><</if>>
    <<if ($character4.Location is "Place name")>><img src="character img source"><<else>><</if>>
    <<if ($character5.Location is "Place name")>><img src="character img source"><<else>><</if>>
  </a>
</span>\ 

It's a link, in which the text is followed by the icons of any character that is presently marked at that location. If the character is elsewhere, their icon just doesn't appear.

Links that can have conditionals to add time through a widget:

<<link "Place name" 'Passage name'>>
  <<if _currentNeighborhood !== "Destination Neighborhood">>
    <<addmins 30>>
      <<else>>
    <<addmins 5>>
  <</if>>
<</link>>

Simple enough. When you click on the link, it adds minutes to the clock. If you're already in the same neighborhood, you less time is added. If you're in any other neighborhood, more time is added. The variable for the neighborhood is set temporarily in the same passage.

I just can't figure out how to merge these two behaviors so I can have one link that adds time when clicked depending on an IF, and also allows me to have conditional images in them.

Thank you so much !

9 Comments
2024/10/28
23:57 UTC

6

Set an input text box to be "censored"?

I'm using Harlowe 3.3.9 and I've managed to make an input text box that binds the input to a variable. Pretty simple stuff, but I'm also wondering if it's possible to "censor" the text input as it's entered, so to speak?

Basically I want it to be like the player is entering a password, so as they type in the text box it's censored with asterisks or something like that. I understand you can force a specific input as the player types, however I need to still be able to save whatever the player types, I just don't want it shown on screen as the player types it.

Thanks!

3 Comments
2024/10/27
15:09 UTC

6

How do i change <<cycle>> macro's hover color? +1 additional question.

For some reason, i can't seem to figure out how to change the color of the cycle macro. I figured out how to change the color of the macro itself, but not the hover color. In my stylesheet I have:

.macro-cycle {

color: darkseagreen;

font-weight: bold;

font-family: serif, sans-serif;

font-size: 19px;

text-decoration: none;

}

But when I do:

.macro-cycle a:hover {

color: lightpink;

}

it doesn't work.

also another question, how do I decrease/increase the paragraph spacing? like the:

https://preview.redd.it/um54b398naxd1.png?width=377&format=png&auto=webp&s=4ae1f410493706cca79f47240a43c39758124e76

1 Comment
2024/10/27
12:37 UTC

7

What does an underlined red link mean?

The red passage

The code making the red passage

I think I wrote the code right. The (set:doorisdone to true) is just something I put in to test.

5 Comments
2024/10/26
20:17 UTC

5

Are there any Sugarcube games out there that have visible changing character portraits a la 'Doom'?

What the title says, that the main character's portrait in the sidebar gradually changes based on things like new stats, afflictions, damage taken, etc. I'd like to know, primarily for research purposes. (And yes, NSFW games are fine too.)

1 Comment
2024/10/26
19:07 UTC

5

Best way to recreate a passage conditioned by a dice roll

I'm writing a DnD inspired game. The charater needs to climb a wall and there's a skill roll. If the character passes it, it leads to a text, if they fail, it leads to another.

So far I've come with fourideas.

-Using an intermediate passage with the roll code, then GOTO the right passage. Pros: easy to code. Cons: in the long run it leads to passage bloat.

-Everything inside the passage link, then redirect to the right passage. Pros: fewer passages than the previous, but still bloating the number of passages.

-Just one passage but <<include>> from other passages. Pro: neat and clean. Cons, many many unconncted passages.

-Just one passage, and everything is inside <<ifs>>. Pros: less passages. Cons: since invisible <<if>>s still count as <br>, it can be messy to edit properly.

What do you guys think? Anyone has a better method? I'd be happy to hear it.

5 Comments
2024/10/26
12:32 UTC

7

Resizing solutions

Is it possible to make my twine game, when opened on mobile, look like a mini and zoomed out version of the game instead of making the elements (imgs and texts) resized and pushed around?

I'm new to coding and I don't think I'm patient enough to make a new css just for mobile😭 so I'm thinking maybe I can do it in the global(?) JavaScript and stylesheet??

4 Comments
2024/10/26
08:00 UTC

3

Background Blurring?

Blurred background

Code

Is there anyway to make the image not blur?, I'm assuming it has something to do with the "background-size:cover;" prompt of code upscaling the image.

1 Comment
2024/10/26
02:53 UTC

5

how to make javascript macros that outputs/yields something?

I know i can create a macro like so in sugarcube:

Macro.add("foo", 
{handler: function()
  {
    
  }
});

but how exactly do i make this macro generate / yield something? Like when i use the <<widget "foo">> macro, whatever i put in the body gets placed where <<foo>> is. How would i do that with a macro i created via javascript? I see the MacroContext has a "ouput" field but im not really sure how / what to set it to? i tried just assigning it a string like so this.output = "<h1>test</h1>" but that doesn't work

3 Comments
2024/10/26
00:23 UTC

4

Help with Conditional Background Image

Hi everyone,

I'm struggling with implementing dynamic backgrounds in my Twine 2 project (using the Harlowe format). Initially, I tried using the following code in a footer to set the background image for each passage based on a variable:

(if: $lastPhase is "FirstDay" or $lastPhase is "DayPhase1")[
    (change: ?Page, (bg: "https://i.imgur.com/9DRdI8c.jpeg") + (text-color: black))
] <!--Day Background 1-->
(else-if: $lastPhase is "DayPhase2")[
    (change: ?Page, (bg: "https://i.imgur.com/jtVBrqx.jpeg") + (text-color: black))
] <!--Day Background 2-->
(else-if: $lastPhase is "DayPhase3")[
    (change: ?Page, (bg: "https://i.imgur.com/4zR9srE.jpeg") + (text-color: black))
] <!--Day Background 3-->
(else-if: $lastPhase is "NightPhase1" or $lastPhase is "NightChoice")[
    (change: ?Page, (bg: "https://i.imgur.com/HWAL6Eg.jpeg"))
] <!--Night Background 1-->
(else-if: $lastPhase is "NightPhase2")[
    (change: ?Page, (bg: "https://i.imgur.com/zO3FC5a.jpeg") + (text-color: white))
] <!--Night Background 2-->
(else:)[
    (change: ?Page, (bg: "https://i.imgur.com/Ewvav1I.jpeg") + (text-color: white))
] <!--Night Background 3-->

This worked fine until I tried to add the following code to change the color of links and hover effects:

(if: $phase is "Day")[
    (change: ?Page, (text-color: black) + (link-style: via (text-color: black) + (hover-style: (text-color: black))))
]
(else:)[
    (change: ?Page, (text-color: white) + (link-style: via (text-color: white) + (hover-style: (text-color: white + red))))
]

After adding this, the backgrounds stopped loading correctly and started stacking strangely instead of replacing each other as intended.

I also tried a simpler approach:

tw-story [tags="Day"] {
  background-image: url("https://i.imgur.com/9DRdI8c.jpeg");
    background-size: cover;
}

tw-story [tags="Night"] {
  background-image: url("https://i.imgur.com/HWAL6Eg.jpeg");
    background-size: cover;
}

However, this didn’t work either, even when using `~=` instead of `=`.

Any advice or ideas on how to achieve smooth background changes? I'm new to development and still figuring things out.

Thank you so much for any guidance!

1 Comment
2024/10/25
18:04 UTC

8

I made a programmable video recorder for my 3D Twine game--here is a spooky concept video I made with it!

1 Comment
2024/10/25
16:49 UTC

18

As an experiment, I made a real-time-based idle / clicker game in Twine (Harlowe)

I am always trying to test the limits of what is possible in Harlowe, so I gave myself the challenge to create a simple, real-time-based idle / clicker game (like Cookie Clicker) using Twine and little to no extra JavaScript.

Personally, I find Twine lends itself perfectly to incremental games as long as they’re turn-based, but for an idle game based on real-time-progression with a global clock, Twine in general and Harlowe in particular probably won’t be the first tool that comes to mind.

As an experiment and proof of concept I’ve just released “Idle Judgment Day” for Halloween, a very simple and short idle game with real-time progression, created in Harlowe (with the only extra JavaScript being the Harlowe Audio Library). As a parody of idle games, the big numbers go down, instead of up. Anyway, here it is and I’m very excited to share the results of my experiment with you:

https://oddpizza.itch.io/idlejudgmentday

EDIT: It goes without saying, but it's free of course and there's no monetization.

I am not claiming this is the best way to make it work, but it definitely is a way. I’m sure someone will say “that would’ve been easy / easier in SugarCube”, which probably is true, but a) I don’t really know my way around SugarCube, and b) the challenge was to make it in Harlowe, and the possibilities Harlowe has never cease to amaze me.

0.9.0

  • functional on all devices and browsers, except iOS Safari
  • 15 levels and 20+ automation & one-time upgrades
  • real-time-based progression (global clock)
  • Multiple timed events
  • save functionality (browser local storage)
  • on desktop: Plays idle in background if browser tab is open (including in separate browser window if it’s the open tab)
  • audio FX and music (both mutable, thanks to Chapel's Audio Library)

Obviously, there are some limitations, some inherent to Twine, like: Offline progress doesn’t work (which makes it impractical for mobile). There is some input lag due to the refresh rate.

In terms of bugs: For a reason I haven’t been able to figure out yet it doesn’t work in Safari in iOS (the Twine debugger doesn’t return an error, and I couldn’t find it manually, and it works just fine in MacOS Safari).

Some background on development:

The biggest challenge was the global clock. Not even counting seconds, minutes and hours, that was the easy part – but getting it to count days + 1 after 24 hours proved to be a bit of hassle. I will be sharing my code for the global clock in a separate post for better searchability, but here’s sneak peek of what I did to get the day counter work based how many hours, minutes and seconds had passed:

<!-- I defined the "sum of time" which is quite literally the sum of 23 hours, 59 minutes and 59 seconds = 141 -->

(set: $sumoftime to ($hours + $minutes + $seconds))

<!-- Somewhere inside the code I check whether the sum of time is 141 -->

(if: $sumoftime is 141)[(set: $hours to 0)(set: $minutes to 0)(set: $seconds to 0)(set: $days to it +1)

This actually works, and with this method I was able to get a global clock that not only counts hours, minutes, seconds but also days.

It just turned out that I don’t really need the Day counter for this project due to the length of playtime (around 5 to 6 hours), but I was still happy to make it work, and as mentioned, I’ll be sharing the full code for the global clock and how to implement it in a separate post, as I’ve seen a recurring demand for a global clock.

4 Comments
2024/10/25
13:07 UTC

12

Werewolf in the Senate | A Supernatural Political Thriller

So, I wrote a game for NaNoWriMo last year and had no idea where to tell anyone about it. Discovered this sub recently and figured some of you might be interested.

https://monkeybrains12.itch.io/werewolf-in-the-senate

1 Comment
2024/10/24
19:28 UTC

7

Chapbook: Variables and Booleans

Hi,

I'm working on a twine game for an assignment and I'm confusing myself to death, hopefully someone can help. So I have a passage with 3 choices that all lead to the same next passage. What I want to do is have a variable change depending on which one the player chose, and I can't figure out how to do it. I'm sorry if this is confusing to explain but I'll try.

health: 0

--

You've been hurt, what will you use?

>[[Bandage->passage2]]

>[[Knife->passage2]]

>[[Nothing->passage2]]

I want bandage to +1 health, knife to -1, and nothing to +/-0. I'm really confused about how to do about this without creating 3 new passages, which isn't an option because I have a passage amount limit for this assignment.

I basically want to say, for example, if Bandage is picked, health = health +1. Is this possible? Thanks in advance.

EDIT: I've been reading some forums, and I had the idea to just create 2 new passages, one called increase and one called decrease that do exactly that to the health. If i did that, could I embed them somehow and say "if bandage, embed 'increase'" or something like that?? Then, I could just reference those passages each for other branches that have the same problem. Sorry, I'm so confused! I'm new to twine and coding really isn't my thing, any help is appreciated.

1 Comment
2024/10/24
19:14 UTC

2

Let's make a game! 181: A new system for movement

0 Comments
2024/10/24
05:09 UTC

Back To Top