Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Inline Conditions for Ren'Py

Use if/else logic right inside dialogue lines in Ren'Py · By Feniks

Fixing unrecognized text tag errors when using the built in linter

A topic by franklygeorge created Dec 30, 2023 Views: 264 Replies: 4
Viewing posts 1 to 2
(1 edit)

If you like to use Ren'Py's built in linter like me then these lint errors start to get annoying fast. So I am glad to provide a simple 8 step solution for you guys.


These operations were performed on Ren'Py 8.1.3, your version may vary. If you break your launcher without having a backup to restore from, that's your problem not mine. Do this at your own risk (If you make a backup first you should be completely fine).


1. Inside of your Ren'Py launcher folder find renpy/text/extras.py

2. I suggest making a backup just in case. Copying extras.py to extras.py.bac should do.

3. Open extras.py in your preferred code/text editor.

4. Find:

        if text not in all_tags:

            return "Text tag '%s' is not known." % text


In my case it's on line 117 (If not Ctrl+F is your friend)


5. Replace lines 117 and 118 with:

        if text not in all_tags:

            if text.startswith("if "):

                continue

            elif text.startswith("elif "):

                continue

            return "Text tag '%s' is not known." % text


6. Restart the Ren'Py launcher.

7. Lint your project in peace.

8. Profit???


It would be nice if Feniks or someone else could figure out a way to implement this via a one time patch script.

Developer

This is what the extra lint file in this project does - it still runs the regular Ren'Py linter, just adds some extra functionality to properly lint conditions for correctness, and also doesn't flag the tags as being unknown. So if you are looking for a one-time patch script to do this and also lint the conditions for correctness, that is what the extra lint file does.

The extra file runs lint from in-game instead of from the launcher since the file is intended to be put into your project rather than replace Ren'Py engine files (which would then be reset or potentially cause issues if you ever updated the engine or made a mistake). The extra lint file passes the majority of the work off to the Ren'Py linter to ensure that engine updates do not interrupt its ability to lint the project, even if the engine linting changes.

Ah, I was just blind and missed the part about still using the built-in linter in the readme. Testing it out now.

(1 edit)

So in testing your custom lint function I have found two major issues that would affect my workflow greatly.

1. Your custom linter closes the game each time it is ran. Ren'Py's built in linter can be ran with the game open. Which is great for fast refactoring when paired with Ren'Py's auto reload feature.

2. Your custom linter doesn't run any other custom lint functions. One of the other custom lint functions I use is the amazing Word Counter + by Kigyo. When using your linter his never runs.

Copies of the two different lints for comparison:

custom_lint.txt:

Ren'Py 8.1.3.23091805 lint report, generated at: Sun Dec 31 09:57:04 2023
Statistics:
The game contains 275 dialogue blocks, containing 4,611 words and 24,964
characters, for an average of 16.8 words and 91 characters per block.
The game contains 9 menus, 0 images, and 27 screens.
The game contains 9 inline conditions.
The game contains 1 inline Python expressions.
Lint is not a substitute for thorough testing. Remember to update Ren'Py
before releasing. New releases fix bugs and improve compatibility.

lint.txt [built in lint using my patch]:

Ren'Py 8.1.3.23091805 lint report, generated at: Sun Dec 31 10:02:05 2023
Character statistics:
 * narrator has 189 blocks of dialogue, and 3,646 words.
 * mc has 34 blocks of dialogue, and 266 words.
 * npc1 has 27 blocks of dialogue, and 466 words.
 * npc2 has 10 blocks of dialogue, and 103 words.
 * npc3 has 8 blocks of dialogue, and 68 words.
 * npc4 has 7 blocks of dialogue, and 71 words.
File statistics:
 * [script.rpy] contains 275 dialogue blocks and 4,620 words.
Detailed File statistics:
[script.rpy] contains 275 dialogue blocks and 4,620 words:
 * narrator has 189 blocks of dialogue, and 3,646 words.
 * mc has 34 blocks of dialogue, and 266 words.
 * npc1 has 27 blocks of dialogue, and 466 words.
 * npc2 has 10 blocks of dialogue, and 103 words.
 * npc3 has 8 blocks of dialogue, and 68 words.
 * npc4 has 7 blocks of dialogue, and 71 words.
Menu statistics:
The game has 9 menus, with a total of 36 possible choices, 
for an average of 4.00 choices per menu.
Statistics:
The game contains 275 dialogue blocks, containing 4,620 words and 24,919
characters, for an average of 16.8 words and 91 characters per block.
The game contains 9 menus, 0 images, and 27 screens.
The game contains 9 inline conditions.
The game contains 1 inline Python expressions.
Lint is not a substitute for thorough testing. Remember to update Ren'Py
before releasing. New releases fix bugs and improve compatibility.


Until these two functions have feature parity I seen no reason why I wouldn't prefer my method over the original.

Developer

You bring up a good point with other lint hook compatibility - I had overlooked that my lint features require a specific print function to work. I've made an update which will replace print with the custom lint version so that other lint hooks can also print to the final file. I'll update the itch with it sometime this weekend. 

As for closing the game - this is more out of caution than anything, as I do modify the internal AST nodes when running lint (the built-in linter does also; it runs a separate version of your game to lint). You're welcome to remove the line renpy.exports.quit(save=False) towards the end of the custom_lint file, but I make no guarantees on behaviour. I suggest instead that you just launch another window of your game to quickly run the lint, as it won't close or affect any previously-open windows of the game aside from the one which ran the lint operation.

Otherwise, the main feature offered in this linter which you won't get with the built-in linter is properly linted conditions. Turning off warnings for text tags will hide that particular warning about unknown or unclosed text tags, but the built-in linter doesn't know what inline conditions are and therefore can't properly evaluate that something like {if apples => 3} is malformed (it should be {if apples >= 3}). You would need to run through the game and get to that particular line (which would likely cause a crash) to find out that it's incorrect. There are different levels of strictness you can enforce through the custom linter which will do things like flag if you haven't properly defaulted a variable before you use it in an inline condition.