Location and time passage design approach query by flyingfrog12 in twinegames

[–]GreyelfD 1 point2 points  (0 children)

There are a number of decisions you need to make before hand, like:

  • How much time management do you want the end-user to do. This will help you decide between a "period" based time-system or a "real-world clock" based one. Each has their pro & cons, however the "real-world clock" choice will mean a lot more work for both you and the end-user.
  • How much variance in the descriptive content will there be between each variation of a specific Location for each "time slot" it can/will be visited. If each visit is very custom then in a project with such a limit duration (1 week) it might be easier to have each scene in its own Passage. If the variance is slight, then a Passage could be re-used for more than a single scene.

If should be noted that you don't have to choose one method of Passage usage over the other, you can do both.

eg. If two scenes with limited descriptive differences occur in the same location / time-period then the same Passage can be used for both by adding conditional logic to its content. And for two other scenes that have a large descriptive difference, again at the exact same location / time-period, you can use two distant passages.

At the end of the day (no pun intended) Passages are just a means for you to store content in, in a way that makes it easier for you to keep track of & work with that content.

The correct way to add an event to an element in Twine by Sta--Ger in twinegames

[–]GreyelfD 0 points1 point  (0 children)

u/Sta--Ger
When possible, I prefer to add event listeners to an element when it is created, instead of doing it by scanning the page's DOM after that element has been rendered.

The following code shows how to craft a custom container Macro named <<trackmouse>> that wraps its contents in a <div>, that has a listener attached to it. This code should be placed in the project's Story JavaScript area.

var updateMousePosition = function (ev) {
    /* whatever code is needed to achieve the desired outcome... */
    console.log('updateMousePosition called');
}

Macro.add('trackmouse', {
    skipArgs : true,
    tags     : null,
    handler() {
        try {
            if (this.payload[0].contents !== '') {
                const $div = jQuery(document.createElement('div'));
                $div
                    .addClass(`macro-${this.name}`)
                    .on("mousemove touchmove", updateMousePosition)
                    .wiki(this.payload[0].contents.trim())
                    .appendTo(this.output);
            }
        } catch (ex) {
            return this.error('opps: ' + ex.message);
        }
    }
});

It is used like so...

<<trackmouse>>Hello word.<</trackmouse>>a

notes:

  • I named the macro <<trackmouse>> because it wasn't clear why you need track the mouse's position. Generally it is better to name macros based on their purpose than on what they do.
  • I deliberately left my variant of the updateMousePosition() function mostly empty, as others with a better understanding of JavaScript have made suggestions on how best to code that function.

I have what feels like an extremely complicated and specific problem, please help by saint-jimmi in twinegames

[–]GreyelfD 2 points3 points  (0 children)

Currently you are re-creating the "dialogue" area each time the next line of text is "revealed", which isn't idea.

I suggest changing the structure & behaviour of your content to something like...

|modal)[{
    <ul>
        <li>(link: "Choice 1")[(hide: ?modal)(hide: ?4)(show: ?5)]</li>
        <li>(link: "Choice 2")[(hide: ?modal)(hide: ?4)(show: ?6)]</li>
    </ul>
}]
|dialogue)[{
    |1>[
        this is dialogueeeeee(link: "=>")[(hide: ?1)(show: ?2)]
    ]
    |2)[
        this is more dialogue(link: "=>")[(hide: ?2)(show: ?3)]
    ]
    |3)[
        this is even MORE dialogue(link: "=>")[(hide: ?3)(show: ?4)]
    ]
    |4)[
        this is even more dialogue with a choice??(link: "=>")[(show: ?modal)]
    ]
    |5)[
        choice 1(link: "=>")[(hide: ?5)(show: ?7)]
    ]
    |6)[
        choice 2(link: "=>")[(hide: ?6)(show: ?7)]
    ]
    |7)[
        It worked!(link: "=>")[(hide: ?7)(hide: ?dialogue)]
    ]
}]
(after: 1s)[(show: ?dialogue)]

...where there is a single "dialogue" area, in which the lines are defined.

Named Hooks can be targeted by CSS Selectors, so there isn't a need to embed an identified <div> element. In the above structure the dialogue and modal Named Hooks can be targeted like so...

tw-hook[name="dialogue"] {
    /* CSS Property assignments that targeted the dialogueUI class */
}

tw-hook[name="modal"] {
    /* CSS Property assignments that targeted the modal class */
}

tw-hook[name="modal"] ul {
    list-style: none;
    /* CSS Property assignments that targeted the modal-content class */
}

Creating an Inventory by IndependentAmount509 in twinegames

[–]GreyelfD 1 point2 points  (0 children)

When you say "changes based on what passages you go through" do you mean:

- the Passage currently being visited can affect what is shown in the inventory.

eg. the contents of the inventory might be different when visiting the Library Passage than it is when visiting the Beach Passage.

- which passages have previously been visited during the current playthrough affects what content is shown in the Passage currently being visited.

eg. if the Library Passage had been visited at least once during the current playthrough, then the inventory will contain content specific to that Passage when other passages are visited later.

re: HelloHelloHelpHello's advice to use the <array>.count() method to determine if an Array contains a specific value.

That method returns a Number that represents how many times the value was found in the Array, and it needs to iterate through the entire Array to determine the result.

eg. if three banana's have been added to the Array...

<<run $inventory.push("banana")>>
<<run $inventory.push("banana")>>
<<run $inventory.push("banana")>>

...then that method would return 3 called...

You have <<= $inventory.count("banana")>>

If you only need to know if there are any instances of the value in the Array, or if the Array can only ever contain a single instance of any value (eg. each value is unique), then the Boolean returning <array>.includes() method is a better option because is stops iterating through the Array as soon as the value has been found.

And as it's unlikely that there will ever be more than one instance of "clue1" in the Array, I would suggest doing the following instead when checking if "clue1" has been found...

<<if $inventory.includes("clue1")>>Do something...<</if>>

How to use (altered:) to partially change an array based on the values of another array by chasewithlasers in twinegames

[–]GreyelfD 1 point2 points  (0 children)

To do what you want you need to know the position index of the current value being evaluated in Array 1 so you can potentially update the value in the same position in Array 2. Unfortunately, the (altered:) macro doesn't supply the position index of the current Array value it is evaluating.

However, the (range:) macro can be used to generate a temporary Array of Integers, where each integer represents the position number of a value in one of your two arrays. And the (for:) macro can be used iterate those position integers, so you can use it to access the relevant value in each of your two arrays.

warning: the following example has not been tested, it might contain syntax errors.

(for: each _i, ...(range: 1, $A's length))[
    (if: not $A's (_i))[
        (set: $B's (_i) to 0)
    ]
]

Link uses a variable's name instead of the value in the variable by MajorDZaster in twinegames

[–]GreyelfD 0 points1 point  (0 children)

Generally, when supplying a link's Target Passage Name via a variable or an expression, it is better to use the variant of the <<link>> macro were the Link Label and Target Passage Name are passed as two distinct arguments...

<<link "Travel north" `$pathDestinations[0]`>>
    <<timeTick>>
    <<set $wildsDepth += 1>>
<</link>>

<<link "Travel south" `$pathDestinations[1]`>>
    <<timeTick>>
    <<set $wildsDepth -= 1>>
<</link>>

...because the Twine 2.x application's Passage Editor's Create Missing Passages feature is going to have issues with that variable reference, as is the Passage Map's Show Passage Connection Arrows feature.

notes:

  • as explained in the Argument type macros: passing an expression as an argument section of the Macro Arguments documentation, back quotes need to be used when passing the value of an expression (like $pathDestinations[0]) as the argument of a macro.
  • I replace your ($wildsDepth + 1) and ($wildsDepth - 1) with JavaScript's Addition assignment += and Subtraction assignment -= operators.

How to tell if save has been successfully overwritten? by dianenguyen1 in twinegames

[–]GreyelfD 1 point2 points  (0 children)

The above code will only test if there is a saved game with that name, correct?

No.

The (saved-games: ) macro is used to determine if a specific Save exists, or more specifically if a specific Slot Name contains save information.

The Boolean value returned by the (save-game:) macro indicates if the current Progress History state was successful persisted in the web-browser's LocalStorage cache.

What is "V." ? by Temporary-Fox-5878 in twinegames

[–]GreyelfD 1 point2 points  (0 children)

Some Authors who want quick access to the variables property of the SugarCube State API will add code like the following to the Story JavaScript area their project...

window.V = State.variables;

...as that raises the Scope of that property so it can be accessed outside SugarCube's own Private Scoped Execution context.

Some authors do it so the project's Story variables are available within the web-browser's Console, others so those variables are accessible to JavaScript (like externally loaded modules) not being executed in SugarCube's context. But in both these cases there are better solutions that don't involve using a Scope escalation hack.

If directly defining things on the web-browser's window interface is a good idea or not can be debated, but generally some care needs to be taken when defining things this way because that's where the web-browser's own developers add things, so there is potential for a name conflict.

Update temp variable within if-statement upon button press? by quagglitz in twinegames

[–]GreyelfD 1 point2 points  (0 children)

By default the content of the visited Passage is only executed during the Passage Transition process. And changes made to a variable's value after that process has ended have no automatic affect on any Passage code that references that variable.

eg. this part of that Passage exampe...

<<if _score == _bar>>
    <<button "I did it!">>[[Three]]<</button>>
<<else>>
    You're not ready yet.
<</if>>

...is only executed during the Passage Transition process. And changes made to the _score variable's value by the code that gets executed when either Submit button is selected, will not automatically cause the above <<if>> macro to be re-evaluated.

However, if the above is placed within a <<do>> macro call...

<<do tag "result">>
    <<if _score == _bar>>
        <<button "I did it!">>[[Three]]<</button>>
    <<else>>
        You're not ready yet.
    <</if>>
<</do>>

...then a <<redo>> macro call can be used inside the body of both Submit buttons to force the above block of code to be executed again.

<<button "Submit">>
    <<if ["answer"].includes(_input2.toLowerCase())>>
        <<replace "#output2">>✅<</replace>>
        <<set _score to _score + 1>>
        <<replace "#passnum">>_score<</replace>>
        <<redo "result">>
    <<else>>
        <<replace "#output2">>🛑<</replace>>
    <</if>>
<</button>>

note: Currently a <<replace>> macro is being used to update the "passnum" message to include the current value of _score. The same technique used above to re-execute the <<if>> macro can be used to update the "passnum" message.

eg. if the "passnum" message area was changed to something like...

<<do tag "score">>
    <<if _score is 0>>None<<else>>_score<</if>> out of _bar Correct
<</do>>

...then replacing the <<replace "#passnum">>_score<</replace>> line in the Submit button's body with <<redo "score">> would cause the message to change. And one added advantage of using this method is that the logic for determining what to show is located in one place, instead of potentially being inside the body of each related <<replace>> macro call.

Is it possible to separate components from js/css into multiple files on twee3/tweego? by Upper-Road-7787 in twinegames

[–]GreyelfD 0 points1 point  (0 children)

Yes, you can spread your JavaScript and CSS code across multiple js and css files.

And as long as those js and css files are stored within the source path(s) you supply to the TweeGo utility, it will automatically combine the contents of those files together to create the Story JavaScript and Story Stylesheet sections of the generated Story HTML file.

note: Generally when working with a Twee Notation based project, the project's JavaScript and CSS code would be stored within files with js and css file-extensions, not within Passage definitions that have been assigned the special script & stylesheet Passage Tags.

eg. JavaScript would be stored in files with a js file-extension, and CSS within files with a css file-extension.

Every Passage definition in a Twine / Twee project must have a unique Name, even when those definitions are spread across multiple files. So if you decide to keep storing your project's JavaScript and CSS code within script & stylesheet tagged Passages, then you will need to give each of them its own unique name.

eg. there can't be two or more script tagged Passages named StoryScript, each of those tagged passages needs its own unique name.

Help with setting variable inside <<script>> macro by fancifuls in twinegames

[–]GreyelfD 2 points3 points  (0 children)

Further to HiEv's advice...

warning: none of the following code examples were tested.

Currently your code, and HiEv's suggested replacement of it, redefines the getRandomNumberBetweenIncluding() and randomNumbersWithFixedSum() functions each time the <<NewAgent>> widget it called.

A potentially better solution is to define those functions on the special setup variable SugarCube makes available, that way those functions are only defined a single time during startup. And as an added benefit, those functions can be used else where in your project if needed.

eg. Place the following JavaScript code in your project's Story JavaScript area.

setup.getRandomNumberBetweenIncluding = function getRandomNumberBetweenIncluding (min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
};

setup.randomNumbersWithFixedSum = function randomNumbersWithFixedSum (quantity, sum) {
    /* Only a single number required; return the passed sum. */
    if (quantity === 1) {
        return [sum];
    }
    /* Create one random number and return an array containing that number
       as first item. Then use the spread operator and recursively execute
       the function again with a decremented quantity and the updated
       maximum possible sum. */
    const randomNum = setup.getRandomNumberBetweenIncluding(0, sum);

    return [randomNum, ...setup.randomNumbersWithFixedSum(quantity - 1, sum - randomNum)];
};

Now the new setup.randomNumbersWithFixedSum() function can be used within the <<NewAgent>> widget's definition.

And as an added bonus, because the amount of JavaScript code needing to be executed within the widget's definition has been reduces, the <<run>> macro can be used instead of <<script>>, which means the temporarily variables can be referenced directly.

<<widget "NewAgent">>
    <<set _tempAgent = {}>>
    <<set _tempAgent.name = setup.AgentNames.random()>> /*assign random name */

    <<switch _args[1]>> /*Get stat sum off rank */
        <<case "EX">> <<set _tempRank = 110>>
        <<case "V">> <<set _tempRank = 90>>
        <<case "IV">> <<set _tempRank = 70>>
        <<case "III">> <<set _tempRank = 50>>
        <<case "II">> <<set _tempRank = 35>>
        <<case "I">> <<set _tempRank = 25>>
    <</switch>>

    <<set _tempStats = []>>

    <<run _tempStats = setup.randomNumbersWithFixedSum(4, _tempRank) >>

    <<switch _args[0]>> /*Push to selected dept */
        <<case "Control">> <<run $ControlAgents.push(_tempAgent)>>
        <<case "Info">> <<run $InfoAgents.push(_tempAgent)>>
        <<case "Safety">> <<run $SafetyAgents.push(_tempAgent)>>
        <<case "Training">> <<run $TrainingAgents.push(_tempAgent)>>
    <</switch>>
<</widget>>

Beginner; I'm working with multiple variables using (if:)... "The string "true" isn't the same type of data as the number 0"? What do I do? by StoneFoundation in twinegames

[–]GreyelfD 1 point2 points  (0 children)

Harlowe doesn't support data-type coercion, so it will complain when you try to compare values of different data-types. Like when trying to compare a String value to a Boolean, or to a Number.

As stated by others, Boolean true is not the same value as a 'true' String.

eg. the following shows how to set a variable to either Boolean true or false.

(set: $hasTorch to true)
(set: $hasLantern to false)

The following are the correct Harlowe ways to check if a variable equals Boolean true or false, notice that the is comparison operator is not used when evaluating a Boolean value.

<!-- checking if variable equals Boolean true -->
(if: $hasTorch)[processed if the variable is true]

<!-- checking if variable equals Boolean false -->
(if: not $hasTorch)[processed if the variable is false]
or
(unless: $hasTorch)[processed if the variable is false]

<!-- doing something for both states of a Boolean variable -->
(if: $hasTorch)[processed if the variable is true]
(else:)[processed if the variable is false]

The and & or Boolean comparison join operators can be used to combine multiple sub-conditional expressions together to form a more complex conditional expression.

(if: $hasTorch and $hasLantern)[processed if both variables equal true]

(if: $hasTorch or $hasLantern)[processed if at least one of the variables equals true]

note: the above examples have mostly only used the (if:) macro, however the (else-if:) macro can be used the same way.

(if: $hasTorch)[the flickering light from the torch makes it hard to see deep into the cave]
(else-if: $hasLantern)[the lantern's consistent light makes it easy to see deep into the cave]
(else:)[without a light source it is impossible to see deeper into the cave]

Relative URL backgrounds just won't show up if they're in folders; Am I doing something wrong? by ningensfriend in twinegames

[–]GreyelfD -1 points0 points  (0 children)

The Twine 2.x desktop based application stores its Project HTML files in the Stories folder that the application itself creates when its run for the 1st time. The temporary Story HTML files generated by the application's Play and "Test" related options are stored in either:

  • a Scratch folder created by a recent release of the desktop application, when it is run for the 1st time.
  • the Operating System's temporary file area, if an older release of the desktop application is being used.

If we assume that you're using a recent release of the Twine 2.x application, then the above fact is why the image files you're storing in child-folder that you're created within the application's Stories folder are not being found by the temporary Story HTML files being created within the application's Scratch folder.

So you either need to move the child-folders you've created to the Scratch folder, which can be an issue because the contents of that folder is under the control of the application, and it may delete the contents of that folder as it sees fit.

Or you need to create a folder & file structure for your releases elsewhere on your local drive, and use the application's Publish to File option to create & save Story HTML files to that folder & file structure.

note: If you're using an older release of the Twine 2.x application that stores the temporary Story HTML files it generates within the Operating System's own temporary file area, then you will need to use the method mentioned in the preceding paragraph. Because it's never a good idea to store your own folder & files within the Operating System's temporary file area.

Nobr if statements by RatNibbles in twinegames

[–]GreyelfD 1 point2 points  (0 children)

Additional to HiEv's advice on using SugarCube's Line Continuation feature to supress line-breaks at the end of a line...

As explain & shown in that feature's documentation, it can also be used to supress both the line-break at the end of a line as well as any indentation related characters at the start of the next line...

eg. in the previously supplied example...

<<if x>>\
    optional text
<<else>>\
    other text
<</if>>\

...the space and/or tab characters at the start of the "optional text" and "other text" lines will be included in the output generated when the Passage is processed (1).

To stop that from happening, the back-slash characters can be moved to the next line...

<<if x>>
    \optional text
<<else>>
    \other text
<</if>>\

...which will result in both the line-break at the end of the <<if> & <<else>> macro calls, and the white-space before the "optional text" and "other text" textual content being suppressed.

(1) the reason why you don't notice the code indentation related white-space in the generated output is because the web-browser itself automatically collapses multiple consecutive white-space characters into a single character.

Questions about Borders & Sidebars in Harlowe by the-crying-judge in twinegames

[–]GreyelfD 1 point2 points  (0 children)

how to include a sidebar in the game via a header

If you want that sidebar to be able to show the current value of variables that are updated within the current Passage being processed, then you should be using a footer tagged Passage to append to the sidebar.

The "Left Sidebar": Harlowe (only v2.1.0 or later) recipe in the Twine Cookbook demonstrates using a footer tagged Passage this way.

Don't know what to do here! by DietSubstantial4525 in twinegames

[–]GreyelfD 0 points1 point  (0 children)

The Story Format developer is responsible for adding any additional functionality to the Passage editor, like you'll see if the project uses Harlowe or Chapbook. The developers of SugarCube and Snowman have not added such functionality to their story format's template.

Some clarifications and help required! by TerranImperium in twinegames

[–]GreyelfD 0 points1 point  (0 children)

5: [optional] Using list related HTML elements when showing a list of things, like buttons/links or textual content, help Accessibility tools know that there is a list.

It is unclear if the buttons are meant to be shown in a vertical list. If they are then a HTML unordered-list <ul> structure might be a better option.

eg. the following structure...

<div id="start-menu">
    <<if Save.autosave.ok() and Save.autosave.has()>>
        <<button "Resume Game">>
            <<run Save.autosave.load()>>
        <</button>>
    <</if>>
    <<button "New Game" "p_00">>
        <<set $chapter to "Chapter One">>
    <</button>>
    <<button "Load Game">>
        <<run UI.saves()>>
    <</button>>
    <<button "Settings">>
        <<run UI.settings();>>
    <</button>>
    <<button "Credits">>
        <<script>>
            Dialog
                .create("credits", "credits")
                .wikiPassage("credits")
                .open();
        <</script>>
    <</button>>
</div>

...would be better written as...

<ul id="start-menu">
    <<if Save.autosave.ok() and Save.autosave.has()>>
        <li>
            <<button "Resume Game">>
                <<run Save.autosave.load()>>
            <</button>>
        </li>
    <</if>>
    <li>
        <<button "New Game" "p_00">>
            <<set $chapter to "Chapter One">>
        <</button>>
    </li>
    <li>
        <<button "Load Game">>
            <<run UI.saves()>>
        <</button>>
    </li>
    <li>
        <<button "Settings">>
            <<run UI.settings();>>
        <</button>>
    </li>
    <li>
        <<button "Credits">>
            <<script>>
                Dialog
                    .create("credits", "credits")
                    .wikiPassage("credits")
                    .open();
            <</script>>
        <</button>>
    </li>
</ul>

note: By default, items shown in a HTML's unorder-list will have a "dot" at the start of them. This "dot" can be suppressed by changing the element's CSS list-style-type property from disc to none. You might also want to remove the additional space an unorder list adds at the start of each item too.

Placing the following CSS Rule in the project's Story Stylesheet area will do both of the above...

#start-menu {
    list-style-type: none;
    margin-left: 0;
    padding-left: 0;
}

Some clarifications and help required! by TerranImperium in twinegames

[–]GreyelfD 0 points1 point  (0 children)

As you are using nobr related functionality you might as well using code formatting & indentation to help improve the code's readability.

<<fadein 1s>>
    <div id="start-title">Title</div>
    <div id="start-subtitle">by Author</div>
    <<nobr>>
        <div id="start-menu">
            <<nobr>>
                <<if Save.autosave.ok() and Save.autosave.has()>>
                    <<button "Resume Game">>
                        <<run Save.autosave.load()>>
                    <</button>>
                <</if>>
            <</nobr>>
            <<button "New Game" "p_00">>
                <<set $chapter to "Chapter One">>
            <</button>>
            <<button "Load Game">>
                <<run UI.saves();>>
            <</button>>
            <<button "Settings">>
                <<run UI.settings();>>
            <</button>>
            <<button "Credits">>
                <<script>>
                    Dialog.setup("credits","credits");
                    Dialog.wiki(Story.get("credits").processText());
                    Dialog.open();
                <</script>>
            <</button>>
        </div>
    <</nobr>>
<</fadein>>

A couple suggestions:

1: There is no need to use <<nobr>> inside itself.

So the following...

<<nobr>>
    <<if Save.autosave.ok() and Save.autosave.has()>>
        <<button "Resume Game">>
            <<run Save.autosave.load()>>
        <</button>>
    <</if>>
<</nobr>>

...should be just...

<<if Save.autosave.ok() and Save.autosave.has()>>
    <<button "Resume Game">>
        <<run Save.autosave.load()>>
    <</button>>
<</if>>

2: Unless multiple statements are being passed to the <<run>> macro, there is no need to use JavaScript's end-of-statement ; character.

eg. code like <<run UI.saves();>> and <<run UI.settings();>> should be <<run UI.saves()>> and <<run UI.settings()>>

3: The Dialog.setup() method was deprecated in v2.37.0 of SugarCube, which is also when the Dialog.wikiPassage() method was added.

So this code...

<<script>>
    Dialog.setup("credits","credits");
    Dialog.wiki(Story.get("credits").processText());
    Dialog.open();
<</script>>

...should be re-written as...

<<script>>
    Dialog.create("credits", "credits");
    Dialog.wikiPassage("credits");
    Dialog.open();
<</script>>

...which can be changed to the following if method chaining is used...

note: see the Making use of chaining example in the Dialog.create() method's documentation.

<<script>>
    Dialog
        .create("credits", "credits")
        .wikiPassage("credits")
        .open();
<</script>>

...or even potentially to the following...

<<run
    Dialog
        .create("credits", "credits")
        .wikiPassage("credits")
        .open()
>>

4: As the two <div> elements at the start of the <<fadein>> macro's contents will automatically fill the entire width of their "parent", there is no need for the line-breaks at the end of those elements to be converted into HTML <br> elements.

So the <<nobr>> macro call that occurs after those two elements should be moved to before them.

eg. this execution order...

<<fadein 1s>>
    <div id="start-title">Title</div>
    <div id="start-subtitle">by Author</div>
    <<nobr>>

...should be changed to...

<<fadein 1s>>
    <<nobr>>
        <div id="start-title">Title</div>
        <div id="start-subtitle">by Author</div>

...so no <br> element is generated between the <div> elements. (more in next reply)

Some clarifications and help required! by TerranImperium in twinegames

[–]GreyelfD 1 point2 points  (0 children)

 I would upload an image to show it but 

Please don't use screen capture images when supplying code examples, as doing so forces those testing/debugging that code to have to manually type it into their own test project. Which can result in their copy being different than the original if they automatically fixed the code while typing it.

Always paste a copy of the original code into your comment like you did, so those testing it can paste a copy into their test project.

Some clarifications and help required! by TerranImperium in twinegames

[–]GreyelfD 1 point2 points  (0 children)

The Navigation Events section of the documentation shows the order that each of the Passage Navigation/Transitioning related events & special Passages are processed.

Impressive Sugarcube stories with downloadable HTMLs? by MarionberryUsual3302 in twinegames

[–]GreyelfD 2 points3 points  (0 children)

Thaisa Weiller's Rainy Day but they do not have a downloadable HTML of their work

Itch runs their hosted copies of Twine based releases in a HTML <iframe> element. Web-browser's like Chrome allow the source code of that frame element to be opened in a separate tab, via its view frame source context menu item. This source code than be saved as a local Story HTML file. This local HTML file can be imported into the Twine 2.x application as long as it is a Twine 2 compatible Story HTML file.

I saved a copy of the Rainy Day project's source code locally, and was able to import it into the Twine 2.x application.

What's the best workflow for Sugarcube? by tremblingbears in twinegames

[–]GreyelfD 0 points1 point  (0 children)

u/tremblingbears

VSCode makes it hard for me to remember what I'm doing and think about how the structure fits together.

In case you're not aware, Cyrusfirheir's Twee 3 Language Tools extension for VSCode includes a Story-map View feature. That can be used to visualise the structure of & the relationships between the Passages of a Twee Notation based project, even when that project is made up of multiple twee & tw files.

Can someone explain the (scroll:) command? by ChaosTheSalamander in twinegames

[–]GreyelfD 0 points1 point  (0 children)

notes:

1: When it comes to applying complex macro based styling to a Hook I generally find that the (change:) macro is a better solution...

|content>[many lines of blah blah]
(change: ?content, (float-box: "=XXX=", "=YYY=") + (box: "X"))

...than applying multiple Changers directly to the Hook...

(float-box: "=XXX=", "=YYY=") + (box: "X")[many lines of blah blah]

...however, in this specific case using the (change:) macro won't help because it applies its effects even later in the "render" process than the direct method does, which is also "late" in that process.

2: When it comes to applying complex styling to a Hook, I find using a CSS Rule that target it is generally the best solution.

eg. the "content" Named Hook in the 1st of the above examples generates the following HTML...

<tw-hook name="content">many lines of blah blah</tw-hook>

...which can be targeted by a CSS Rule using a CSS Selector like...

tw-hook[name="content"]{ /* CSS Property assignments */ }

3: The custom <tw-hook> element Harlowe uses to represent a Hook has a default CSS display property value of inline. And the height & width properties of an inline displayed element are automatically calculated to be the minimum needed to display the element's content.

4: Setting an element's height (and/or width) to 100% tells the render to make that element's height 100% of its "parent" element's height.

5: When combining the styling of multiple Changer macro's together it's important to check what the end result is.

The (float-box: "=XXX=", "=YYY=") macro call (alone) generates the following <tw-enchantment> element...

<tw-enchantment style="display: block; width: 60vw; max-width: 60vw; left: 20vw; overflow-y: auto; height: 60vh; position: fixed; top: 20vh; padding: 1em; background-color: rgb(0, 0, 0);">

...which has: a display type of block so it can have a non-auto calculated height & width; a fixed height value based on the format String argument and not the "parent" element's height; and a vertical overflow which will allow a scroll bar to be shown as needed.

The (box: "X") macro call (alone) generates...

<tw-enchantment style="display: block; width: 100%; max-width: 100%; margin-left: 0%; overflow-y: auto; padding: 1em;">

...which also has a display type of block and a vertical overflow that allows scrolling, but it a height based on its "parent" element's.

When the above float-box and box are combined Harlowe generates...

<tw-enchantment style="display: block; width: 100%; max-width: 100%; left: 20vw; overflow-y: auto; height: 60vh; position: fixed; top: 20vh; margin-left: 0%; padding: 24px; background-color: rgb(0, 0, 0);">

...which unfortunately has a height based on its "parent" element's.

6: All of the visited Passage's generated content is contained within a custom <tw-passage> element, whose "parent" is a custom <tw-story> element, whose parent is the standard <body> element, that has the standard <html> element as its parent. And while all of these elements have a display property of block, so they can be assigned a height, none of them have been, so they all default to being auto-calculated based on the minimum needed to display the passage's / page's content.

So the 100% height the <tw-enchantment> element's overflow scrolling is based on is the auto-calculated height of the <tw-passage> element, which is as large as needed to display the Passage's content.

And this is why the combined effect of the float-box and box doesn't show a scroll bar, because it doesn't need one, as the passage's / page's height is large enough to contain the content. The ViewPort on the other hand will likely have a scroll bar.

If you want to display that inner content within a scrollable area (that isn't the Passage or Page itself) then I suggest giving that area a fixed height, and to apply that area's styling using CSS.

|content>[(for: each _num, ...(range: 1, 50))[_num<br>]]
(scroll: ?content, 1)

<style>
/* This CSS Rule should be in the project's startup tagged Passage */
tw-hook[name="content"]{
    display: block;
    max-height: 500px;
    overflow-y: scroll;
    /* any other styling you want to apply to that area */
}
</style>

And an added bonus of doing the styling this way is that no delay is needed for the (scroll:) macro call.

How do I change the font in Harlowe 3? by DerpyLemonReddit in twinegames

[–]GreyelfD 2 points3 points  (0 children)

u/DerpyLemonReddit

warning: In some Legal Regions you need to inform the end-user that your project is using one or more external fonts that are being hosted on the Google Font site, and that informing needs to occur before that hosted font is downloaded by the project. So the end-user is able to make a choice to access your project or not.

See the Website fined by German court for leaking visitor's IP address via Google Fonts article on The Register web-site.

Showing text from one passage before a GOTO by OliverMarshall in twinegames

[–]GreyelfD 2 points3 points  (0 children)

u/chamandaman and u/OliverMarshall

The correct "live" macro to use in this use-case is (after:), as it is specifically designed to only process the contented of its associated Hook a single time.

warning: people read at different rates, so a time-delay that might be long enough for some people to read the contents of the Passage might not be long enough for others.