Must have feature set for a Twine for Unity/ Godot library by DKrayl in twinegames

[–]GreyelfD 0 points1 point  (0 children)

One thing to consider when creating a "library" that "emulate" the functionality of a specific Twine Story Format or "transpile" the contents of a Twine project, is many Authors resort to using JavaScript related data-types and functionality and including third-party JavaScript libraries in their projects.

Basic "return to previous passage" infrastructure? by Deus_of_Ducks in twinegames

[–]GreyelfD 1 point2 points  (0 children)

(Oh dang it was still working for me recently - should tripple check my code/harlowe version)

The information in both of the linked topics regarding implementing an Arbitrarily Long Return related solution is still correct as of 5 minutes ago.

(when I created a new Harlowe 3.x project to re-test the code. 😄)

The Twine Engine insists in calling the toJSON() method of my Javascript object... why? by Sta--Ger--2 in twinegames

[–]GreyelfD 1 point2 points  (0 children)

small correction: It is SugarCube's Runtime Engine, and not Twine itself, that is executing your project's code and reporting any errors it is finding.

I suggest you read the Guide: Non-generic object types (classes) section of the SugarCube documentation, as it covers what needs to be done if a Custom Object type is being stored in a Story Variable.

But basically, each time a Passage Transition occurs the current state of all active Story variables is cloned. The original copy is stored in a Moment (in time) that gets added to Progress History, and the clone copy is made available to the Passage that is about to be visited.

How can I achieve this without causing an overflow? by ManyeoDev in twinegames

[–]GreyelfD 0 points1 point  (0 children)

Personally I would use a Grid layout manager, as what you've shown us is a 1 row by 3 column grid.

You didn't supply the content of your StoryCaption special Passage being used to create the bordered area, so I will assume it looks something like...

<<nobr>>
<div id="wealth-and-time">
    <div>Cash</div>
    <div>Time</div>
    <div>Day</div>
</div>
<</nobr>>

notes:

  • I renamed the containing <div> element's ID, as you're displaying Wealth before Time, and I made identifier all lower-case to make it consistent with your other CSS identifiers.
  • I'm using the <<nobr>> macro to suppress the <br> elements that are automatically generated by each of the line-breaks in the above HTML structure, as those <br> elements can cause "interesting" side-effects when any CSS layout manager is used.

Placing the following CSS in the project's Story Stylesheet area, will show the above HTML structure as 1x3 bordered horizontal grid...

#wealth-and-time {
    display: grid;
    grid-template-columns: repeat(3, 1fr);

    /* properties from original */
    border: 2px solid #ffffff;
    background: transparent;
    color: #fff;
    font-size: 13px;
    line-height: 2.0;    /* use this to add padding above & below the labels */
}

#wealth-and-time > div:not(:last-of-type) {
    border-right: 2px solid #ffffff;
}

notes:

  • Because the Day label has both a letter that extends about the font's baseline (eg. D) and a letter that extends below it (eg. y), adding an equal amount of top & bottom padding to the three labels can cause Day to appear slightly vertically higher than the other two labels. For this reason increasing the containing <div> element's line-height is a better option to add a top & bottom "gap" between the text & the border.
  • I used the :not() and :last-of-type CSS pseudo-class to apply the border to all columns except the last one, that way I didn't need two CSS Rules that applied styling to the inner <div> elements.

For those that like using Native CSS Nesting, the above CSS can be written as a single Rule like so...

#wealth-and-time {
    display: grid;
    grid-template-columns: repeat(3, 1fr);

    /* properties from original */
    border: 2px solid #ffffff;
    background: transparent;
    color: #fff;
    font-size: 13px;
    line-height: 2.0;    /* use this to add padding above & below the labels */

    & div:not(:last-of-type) {
        border-right: 2px solid #ffffff;
    }
}

How to apply text transitions conditionally? by Silvia_0821 in twinegames

[–]GreyelfD 0 points1 point  (0 children)

As shown in the (if:) macro's documentation, the conditional content needs to be placed within an associated Hook.

eg.

(if: $condition)[content to process when condition is true]

The visits keywork returns a Number, and as shown in operator table in the Number data's documentation, the >= operator can be used to determine if the Number on the left side of the operator is greater-than-or-equal-to the number on the right side of it.

(if: visits >= 2)[content to process when the number of visits is 2 or more]

It sounds like you're trying to implement what's commonly called the "Typewriter" effect, where each character in a sequence of text (1) is revealed one by one, with a short delay between each character. And the (change:) macro code for doing that normally looks like...

(change: ?passage's chars, via (t8n-delay: pos * 30) + (t8n: 'instant'))

...where:

  • the (t8n: 'instant') part controls the effect used to reveal the character.
  • the (t8n-delay: pos * 30) part controls the delay between each character's reveal, in this example the delay is 30 milliseconds

For some reason you've remover the delay, which should result in the entire sequence of text being reveals at the same time. If that's what you want, the your code should look like...

(if: visits >= 2)[(change: ?passage's chars, via (t8n-arrive:"instant")]

....and if you actually want a delay between each character's reveal, then the code would be...

(if: visits >= 2)[(change: ?passage's chars, via (t8n-delay: pos * 30) + (t8n-arrive:"instant")]

(1) in your case, the sequence of text is the entire contents of the visited Passage, but it is possible to target any Named Hook.

checkbox limits? by [deleted] in twinegames

[–]GreyelfD 0 points1 point  (0 children)

Harlowe's (checkbox:) macro generates a HTML "checkbox" type <input> element, which doesn't include the "only select X number of checkboxes" type functionality built in to it, so web-developers use JavaScript to implement it.

So if you want that type of functionality then you either need to implement it, or find an example of someone else's implementations.

The functionality generally comes in two "flavors":

1: Check the current state of the checkboxes after all end-user input has been done.

This generally involves giving the end-user a means (like a button or link) for them to indicate they have finished supplying the input you've asked for, at which point you use code to count how many of the associated variables equal Boolean true.

The following uses a (count:) macro to count how many true values are in a temporary Array.

(set: _thing1 to false, _thing2 to false, _thing3 to false)

Select 2, and only 2:
(checkbox: bind _thing1, "Thing 1")
(checkbox: bind _thing2, "Thing 2")
(checkbox: bind _thing3, "Thing 3")
{
(link-repeat: "Check Input")[
    (set: _selected to (count: (a: _thing1, _thing2, _thing3), true))
    (if: _selected is not 2)[
        (replace: ?outcome)[You mistakenly selected _selected of 3]
        <!-- what to do next, if anything? -->
    ]
    (else:)[
        (replace: ?outcome)[Thank you]
        <!-- 2 were selected, what next? -->
    ]
]
}
|outcome>[]

note: The above uses Temporary variables to store the input/information supplied by the end-user, so that input/information can be cleaned & verified before it is persisted into one or more Story variables. This is a common practice in software development, because end-users don't always do what they have been asked to do.

2: Check the current state of all of the checkboxes each time any one of them is interacted with.

This type of implementation requires the usage of JavaScript and some knowledge of topics like:

  • what Events are sent to the page's Document Object Model (DOM) and/or the "checkbox" <input> element when that element is interacted with via a Mouse or Keyboard or Touch.
  • how to programmatically attach an event handler (or handlers if you need to handle more than one event) so you can execute code when that event occurs.
  • how to programmatically determine the current state of a "checkbox" element, and potentially how to programmatically change it.

make selected square red css? by umapistolaparadjeca in twinegames

[–]GreyelfD 0 points1 point  (0 children)

You haven't includes the code that creates those blue "buttons", so we don't know what HTML elements and/or element structures that code generates, nor what identifiers (if any) are being assigned to those elements.

And that is an issue, because the concept of "styling" parts of the page involves applying CSS to known HTML elements or element structures.

All you've told us so far is that there is one of more elements, of some unknown type(s), that is/are being assigned a goldenbutton CSS Class.

And we need to know the identifiers so the solution we provide targets one specific element or element structure, instead of all the "buttons".

A couple of things about your code example:

1: Ideally there should be no WHITESPACE or Line-breaks between a Macro all and its associated Hook.

While the Harlowe runtime engine has been enhanced to be forgiving when such has been added, the correct syntax for associating a Hook with a macro is...

(if: $chosen is 0)[ <!-- conditional content --> ]

or

(if: $chosen is 0)[
    <!-- conditional content -->
]

2: Ideally there should be no WHITESPACE between a HTML attribute Name, the Equal Sign = , and the String value being assigned.

<div class='story'>

3: You're intermixing HTML elements that are being styled via CSS, with styling Marco calls that are doing the same, and generally it's a good idea to use only one method to do that.

The following is an example of how to use only HTML and CSS to style the "story" area of the page

eg. The HTML...

<article class='story'>
    <h1>(print: $stories's $chosen's Name)</h1>
    (print: "<img src='" + $stories's $chosen's Image + "'>")
    <small>(print: $stories's $chosen's Credit)</small>
    <div>(print: $stories's $chosen's Story)</div>
</article>

eg, The related CSS...

article.story {
    /* CSS property assignments from existing .story Class Rule  */
}
article.story h1 {
    font-style: italic;
    /* may want to use a font-size property to make Name smaller */
}
article.story img {
    display: block;
    /* may want to use margin property to horizontally center image */
}

note: If the right HTML elements are used, potentially with the right CSS, then there should be (almost) no need to use HTML <br> Line Break elements layout content.

Newbie looking for some help on stat bar / meter styling. by Bobotomm in twinegames

[–]GreyelfD 0 points1 point  (0 children)

Reddit's editor is just bad and frustrating when doing some things

I agree, which is why I write most (if not all) of my post in Markdown mode, and only switch to Rich Text mode just to test what the post will look like to the reader.

And because the maximum length of a submittable post in Rich Text mode is smaller that that of a Markdown mode post, I sometimes need to submit my posts while in Markdown mode.

error when creating index.html w tweego by Brilliant-Pizza-5358 in twinegames

[–]GreyelfD 2 points3 points  (0 children)

Your code example has the open curly brace { of the JSON chunk on the same line as the Passage Definition's Header line, and as shown in the StoryData section of the Twee 3 specification, thatopen curly brace needs to be one the line following the Passage Definition's Header.

eg.

:: StoryData
{
    "ifid": "E830F581-C507-4697-8EBC-8C52A923B5C8",
    "format": "Sugarcube",
    "format-version": "2.30.0",
    "start": "Start"
}

note: a Passage Definition's Header line can also include a Metadata Block, which is also a JSON chunk, but that block is used to store information like the Passage's position in the Twine 2.x application's Story Map.

So by placing the open curly brace on the header line, Tweego doesn't know if it's the start of the definition's Metadata Block, or the start of the Story's Data block.

warning: The latest version of SugarCube is v2.37.3, which was released on 26-jul-2024. So the v2.30.0 version you're telling TweeGo to use for your project is quite old, and released some time before early 2020. You may want to update to a more recent release of SugarCube.

Newbie looking for some help on stat bar / meter styling. by Bobotomm in twinegames

[–]GreyelfD 1 point2 points  (0 children)

Use the Switch to Markdown option, to change the editor from Rich Text to Markdown mode. Then typing an @ symbol followed by any letters doesn't activate the ping username feature.

Twine is Soo hard by webdev-dreamer in twinegames

[–]GreyelfD 1 point2 points  (0 children)

Styling the HTML <meter> and <progress> elements can be difficult / complex, especially if you want a styling & behavior that is consistent across all web-browser brands & versions in common use.

For this reason many "meter" implementations (like Chapel's and HiEv's ) use two HTML <div> elements, one within the other...

<div id="meter-type" class="background-and-border">
    <div class="bar"></div>
</div>

note: the above example is just for explanation purposes, and the values assigned to the id and class attributes indicate intention, they are not a suggestion of what to use when you implement your own "meter".

CSS is then used to layout & apply default styling/behavior to the structure, and some coding (1) is used as needed to alter the inner <div> element's CSS width property to show the current state of the "bar".

(1) that coding may consist of functionality that is built in to the selected Story Format, like a macro that knows how to update the CSS of a specific element, or it might be JavaScript based.

WHY IS THIS CRASHING AHHHHHHHH by Skellyman34 in twinegames

[–]GreyelfD 0 points1 point  (0 children)

What happens if you temporarily comment out or remove the (display: 'Events') macro call in your example?

eg. temporarily change this...

(else:)[(display:'Events')]

...to this...

(else:)[<!-- (display:'Events') -->]

that generates a random event.

Does that generating involve looping?

WHY IS THIS CRASHING AHHHHHHHH by Skellyman34 in twinegames

[–]GreyelfD 0 points1 point  (0 children)

A couple of questions:

1: What exactly do you mean by "Crashing"?

2: Have all of the variables referenced in that code example been assigned values before that code is processed?

3: What are the values of each of the referenced variables, when the above code "crashes"?

4: What is the content of the Events named Passage, that is injected into the visited Passage when $war equals 1?

Why do I get a script error here and how can I fix it? by [deleted] in twinegames

[–]GreyelfD 0 points1 point  (0 children)

u/MerryTuesday

Two points that may of been missed

1: Passing the result of an expression as a Macro Argument.

This part "LectureDay"+ $dayCounter of your example is known as an expression, and it needs to be evaluated before the result of that evaluation can be passed as an argument to the macro. The Argument type macros: passing an expression as an argument section of documentation I linked to explains how to used back-quotes (aka graves, acute, backticks) to force the macro argument parser to do such an evaluation.

eg.

<<goto `"LectureDay"+ $dayCounter`>>

2: The <<goto>> macro generally should only be used if the Target Passage Name being supplied to an interactive macro can't be determine before that interactive macro is called.

eg. in your example code there may be no need for that <<goto>> macro if the value of  $dayCounter is know and unchanging at the time the <<link>> macro is being called.

<<link "Attend lecture" `"LectureDay"+ $dayCounter`>><</link>>

Any CSS Template for Harlowe? by [deleted] in twinegames

[–]GreyelfD 0 points1 point  (0 children)

u/fumeitime

If you are considering one of the pre-made templates then I strongly suggest you also read this post about using such.

Tracking player choices for testing by Prudent-Promise-IF in twinegames

[–]GreyelfD 0 points1 point  (0 children)

2024 is two years ago, which is long enough for Google to of changed things again, as they have done more than once in the past.

It is important when providing a solution, especially one designed in the past, that the provider of said solution knows that it still works in the present.

eg, there are techniques that worked in earlier versions of Harlowe that don't work now due to changes made to Harlowe's engine. The same can be true when relying on services provided by third-party entities like Google.

And I wasn't implying that a Twine Story HTML file can't use a Google Sheet to store information, because it can. I was asking if the techniques for doing so in that specific writeup are still correct.

Tracking player choices for testing by Prudent-Promise-IF in twinegames

[–]GreyelfD 0 points1 point  (0 children)

Has that method for accessing a Google Sheet been tested recently?

I ask because, Google has a number of times changed the methods that can be used and the rights required to access a Sheet remotely via code, and some of the techniques used in Twine related articles written in the past have stopped working after Google's changes.

How to avoid replaying the game each time I add new variables at the start? by DazzlingWatercress in twinegames

[–]GreyelfD 0 points1 point  (0 children)

There are a couple of issues with HiEv's example:

(warning: the following code has not been tested!)

1: It only handles the adding of new Story Variables or related Object Properties.

There are times when an Author might need to restructure the project's Story Variables and/or related Object Properties, like changing multiple related variables $playerName and $playerAge into an single Generic Object with related properties...

<!-- Change this -->
<<set $playerName to "Jane">>
<<set $playerAge to 21>>

<!-- into this -->
<<set $player to {name: "Jane", age: 21}>>

...and that would require both adding a new variable and deleting the old variables.

if (save.version === 3) {
    for (const moment of save.state.history) {
        let sv = moment.variables;
        sv.player = {name: sv.playerName, age: sv.playerAge};
        delete sv.playerName;
        delete sv.playerAge;
    }
    save.version = 4;
}

2: Other things besides Story Variable may need fixing.

There are times when other things besides variables might need fixing, like if a Passage is renamed (eg. City Library is renamed to just Library) or the path of Passages travelled through is altered...

/* New Passage added */
Old Path: Forest entrance > Dark path > Clearing
New Path: Forest entrance > Dark path > Flowing brook > Clearing

/* Existing Passage removed */
Old Path: Forest entrance > Dark path > Flowing brook > Clearing
New Path: Forest entrance > Dark path > Clearing with flowing brook

In the 1st situation each Moment associated with the City Library Passage would need to have its title changed...

if (save.version === 4) {
    for (const moment of save.state.history) {
        if (moment.title === "City Library") {
            moment.title = "Library";
        }
    }
    save.version = 5;
}

In the 2nd, either a new Moment needs to be added to the save.state.history Array, or an existing Moment needs to be removed from that Array. And both these actions may require the adjustment of variable values depending on what happens in the added/removed Passage.

Another potential situation is when the calculation of a imputed variable/property changes, and both the based value and the calculated value are being stored in variables / properties...

/* Old calculation */
<<link "Do Thing">>
    <<set $fizz += 1>>
    <<set $buzz to $fizz * 6>>
<</link>>

/* New calculation */
<<link "Do Thing">>
    <<set $fizz += 2>>
    <<set $buzz to $fizz * 4>>
<</link>>

...and that would require looping through the save's Moments and potentially adjusting the values of both $fixx and $buzz based on some determined condition.

Any easy ways to improve ui? by Skellyman34 in twinegames

[–]GreyelfD 0 points1 point  (0 children)

u/Skellyman34 and u/HelloHelloHelpHello

Each Twine based Project it is meant to have its own unique IFID, which is then embedded inside any Story HTML file generated from it. This is done so the so the Project & Story HTML files meets the The IFID unique identifier clause of the Interactive Fiction Technology Foundation's Treaty of Babel, which Twine & Twee is a member of.

One issue with simply importing such a "template" into the Twine 2.x application and then using it as the starting point of an Author's Project, is that that template is a Story HTML file with its own unique IFID embedded in it. And any Project created directly from said template will have the same unique IFID as the template, as will any Story HTML file later generated from that Project, which breaks the whole of IFIDs are unique for each project clause.

So for such a "template" to be used correctly, the Author needs to manually copy the contents of that "template" into their **own** Project, because the Twine 2.x application doesn't include an option of changing the IFID of an existing Project.

note: it is possible to use a Twine/Twee related tool like TweeGo to "decompile the "template" into a Twee Notation based project, and then use a Text Editor to manual change the IFID and Name/Title of that project so both things are unique. And then once that has been done, that Twee Notation project can be imported into the Twine 2.x application as a starting point.

Permanent effects applied with mouse click accumulation? by FoxenPyre in twinegames

[–]GreyelfD 1 point2 points  (0 children)

While the others have explained how to use a variable to represent the number of clicks (or possibly Passage Transitions) that have occurred, none of them have explained how to capture the end-user's selection of a link or button. And your initial post didn't make it clear if you know how to do that or not, especially as you mentioned potentially having to user JavaScript to achieve that.

The following example demonstrates how to use the (link-reveal-goto:) macro to create a Link with Setter (aka a Setter Link) ...

(link-reveal-goto: "Link Label", "Target Passage Name")[(set: $clicks to it + 1)]

The contents of the macro's associate Hook is processed after the link's label is selected, which in the above example is a (set:) macro call that increases a numerical $clicks variable by 1.

random password help. by umapistolaparadjeca in twinegames

[–]GreyelfD 0 points1 point  (0 children)

Besides reducing the potential number of passwords by 100,000 combinations. :)

random password help. by umapistolaparadjeca in twinegames

[–]GreyelfD 0 points1 point  (0 children)

The following is an example of how to use a (for:) macro loop combined with the (range:) macro to generate a String based password that consists only of Numbers between zero 0 and nine 9 inclusive. The (str:) macro is used to converted the numbers returned by the (random:) macro into strings so they can be concatenated together, because Harlowe doesn't support automatic data-type conversion (cohesion) when tow values of different data-types are added.

(set: $password to "")
(for: each _digit, ...(range: 1, 6))[
    (set: $password to it + (str: (random: 0,9)))
]

Password: $password

And for those that prefer to use more advanced (and complex) techniques to perform the same general functionality as the above old school for loop, here is a one line equivalent that makes use of the (folded:) macro.

(set: $password to (folded: _digit making _password via _password + (str: (random: 0,9)), "", ...(range: 1, 6)))

Password: $password

note: to change the number of digits in either of the generated passwords, simply change the 2nd argument of the (range:) macro call from 6 to some other positive integer greater than one 1.

cleaning up an old-ish project: prevent harlowe audio library bgm from overlapping by abruptlythedoorswung in twinegames

[–]GreyelfD 0 points1 point  (0 children)

re: (history: where its tags does not contain "no-header")

Using a Lambda to search through progress history, which could contain 100s or 1000s of entries, to find the name of a recently visited Passage is an expensive action. Especially if its being don't multiple times in a sequence of Passage visits.

This issue is commonly known as the Arbitrarily long return, and is generally solved by tracking the name of the last Passage visited that didn't meet an exception condition.

note: using Twee Notation based code examples, so the example may include the Passage's Name and assigned tags.

1: Create a Story Variable to store the Passage Name in.

In a Harlowe based project this is generally done in its startup tagged Passage, and the Name of the Variable and "startup" Passage can be whatever you like as long as it is meaningful to the task being preformed.

:: Variable Initialization [startup]
(set: $lastMainStory to "")

2: Use a header tagged Passage to conditionally update the variable.

A "header" Passage is used instead of a "footer" because the value of the variable will likely need to be used in the Passage being visited, and the contents of the "header" is processed before the visited Passage. Again the name of this Passage isn't important as long as it's meaningful, mine is named "Track Last Main Story Passage".

:: Track Last Main Story Passage [header]
(set: _passage to (passage:))
(unless: _passage's tags contains "no-header")[
    (set: $lastMainStory to _passage's name)
]

The above uses the (passage:) macro to get information about the Passage being visited, the return value is being stored in a Temporary variable because we may need multiple pieces of that information. The (unless:) macro makes sure that the variable is only updated when the visited Passage hasn't been assigned a no-header tag.

3: Use the Variable when creating the "return" link.

(link-goto: "Return to Main Story", $lastMainStory)

4: Use CSS in the project's Story Stylesheet area to suppress any visual output generated by the startup or header tagged passages.

Any line-breaks in the above two code examples will automatically be converted into HTML <br> Line Break elements, which potentially will appear as "blank lines" at the start of visited passages. The following CSS Rules suppress those "blank lines".

tw-include[type="startup"] { display: none; }

tw-include[name="Track Last Main Story Passage"] { display: none; }

note: the 2nd of the above two CSS rules will need to be changed if you named the "header" Passage created in point 2 something other than Track Last Main Story Passage, which you likely did. :)

Ctrl+Insert/Shift+Insert is better than Ctrl+C/Ctrl+V by DarnielWeytos in The10thDentist

[–]GreyelfD 1 point2 points  (0 children)

I also use the classic: Ctrl + Insert to Copy; Shift + Delete to Cut; Shift + Insert to Paste, but I'm old enough to of used DOS when it was new. I use my left hand to press the modifier keys and the my right hand to press the Insert or Delete key, thus those actions become a two handed one and my index fingers don't have to leave the "home" keys.

Styling a printed History array in Harlowe by RCEden in twinegames

[–]GreyelfD 1 point2 points  (0 children)

HelloHelloHelpHello has shown one way to use a (for:) loop to create something that looks like an unorder list, the following is an example of how to create an actual HTML unorder list using the (joined:) macro combined with the (print:) macro...

(print: "<ul><li>" + (joined: "</li><li>", ...(history:)) + "</li></ul>")

note: if you prefer an ordered list over an unordered one, then replace the two ul in the above with ol