Skip to content

Tips, Tricks And Lifehacks#

The following lists a few things that can help make your life a little easier while coding. These are specialized functions or shortcuts to do things quickly and only apply to very specific situations. Neverthless it is good to have these in your repertoire when you eventually advance enough to have a need for them.

Positioning#

Positioning can be a bit tricky, which is why a helper function exists to make determining positions on screen easier.

1
2
placement_of(john).xpos
placement_of(john).ypos

Using placement_of(character), we can get the x and y coordinates of any character on the screen. These can then be used in animations or the positioning of effects and other characters.

Body modification shortcuts#

Switching Bodies#

We have already learned how the body-switcheroo thingies work if you go for the fancy option. However, sometimes you will find that you need to set up a scene and the characters without showing and transforming them for all to see. For this we provide two commands. To change a characters' body without displaying it, you can use

1
body <character_from> <character_to> [<outfit>]

Note that <outfit> is optional in this case. The following will make john look like katrina in her uniform outfit:

1
body john katrina uniform

Cloning People#

If you want to copy another characters' appearance, including pose, expressions and accessories, you can use this command:

1
clone <character_from> <character_to>
In the below example this would copy connies appearance over to john so both characters would look identical when displayed.
1
clone john connie

Please be aware that both of these functions work "behind the scenes", they will not show anything on the screen until you add an actual show statement afterwards.

Making Phone Calls#

While we added the ability to chat via text messages in the last update, we have now completed that feature-set by adding in the ability to visually show the act of making a phone call.

Making a phone call in Student Transfer

Using the statement below

1
phone_call john @ bg main room day shut : katrina @ bg main kitchen day
will result in the following visualization: Visualization of a phone call

The whole animation can be triggered via one command, the syntax of which looks like this:

1
phone_call <character> [<expression>] @ <location> : <character> [<expression>] @ <location>

Here, character is any of the available character names as they appear in the script while location is the same, but for background names. Optionally, expressions can be added after each character name (both or either one individually) to set the expression to a different one than the default a_0.

To get rid of the phone call visualization simply start a new scene like you would do in any other situation as well.

Adding custom Movies#

Student Transfer supports adding animated sprites in the form of what is called "Movies" by Ren'Py but generally refers to any kind of animated image or video. Adding a video is very similar to adding a custom background image, however instead of putting the file into the bg directory you instead put it into the movies directory. Student Transfer will automatically pick it up if it is in a valid video format that the game can understand and will make it available to use in the game with a very similar naming scheme to what custom backgrounds use. Beware though, since the naming differs slightly! While a background might be called example_bg street night a movie will instead replace all spaces in the script name with underscores (_). Additionally, it will use the movie tag instead of the bg tag to indicate its type. So the video file nuclear explosion.mp4 located in the movies folder will end up as example_movie_nuclear_explosion.

Student Transfer makes all your movies available in two ways:

  1. As a variable containing the full path to your movie file
  2. As a Movie displayable which works like any other image

We do this to support different use cases. Most people who want to show cut-scenes, intros, outros or anything of the sort will most likely be interested in Option 1 since that allows you to use your video file in renpy.movie_cutscene like this:

1
$ renpy.movie_cutscene(example_movie_fire)

Simply use the exact script name of your video file in the movie_cutscene method (without quotes) and Ren'Py will properly detect it, wherever it may reside on disk.

People who want to have more control over what happens with their videos will be interested in Option 2, which loads the video file into something that effectively behaves the same as a regular image. This means that video files can be manipulated via ATL, moved around, rotated and animated, like in this very simple example:

1
2
3
4
5
show example_movie_fire:
    size (1280, 720)
    align (0.5, 0.5)
    ease 4.0 rotate 180
    ease 0.5 alpha 0.0

Student Transfer always loads video files in both formats, so you can use both of these options at the same time.

For a more hands-on example with an existing video file, try out the example scenario which already contains a video and uses it at the very end of the scenario. If you want to toy around with an already working example, simply open up the script and take a look around.

Supported Video Formats#

When experimenting with video files in Student Transfer you will likely at some point run into the problem that your videos won't show up in the game. This is due to the fact that Ren'Py only supports a limited number of formats across all platforms. Generally, Student Transfer will always try to load video files from the movies folder and only if they have one of the following extensions:

  • .mp4
  • .webm
  • .mkv
  • .3gp

However, a correct extensions does not mean that your video will automatically work. You have to take care that it is in the correct codec, too. From our testing, we recommend that you use the VP9 codec with the .mkv file extension as that seems to work most of the time and produces the smallest file size for a given quality. Alternatively use the MPEG-4 codec with the .mp4 extension.

There are several programs out there to convert video files into different formats but we recommend Handbrake as it is free, relatively easy to use and very performant.

For more information about supported video formats please reference the original Ren'Py documentation.

Alpha Masks#

Ren'Py supports alpha masks for videos in the form of a separate video files which will be used exclusively as the alpha channel of the main video file.
To add such an alpha channel, simply add it as a new file next to the full video file and append the suffix _alpha. For example, if you had the video fire.mkv and wanted to add an alpha channel, you'd save it next to that file as fire_alpha.mkv.

Helper Characters#

Sometimes you just need a character for one or two lines, most likely without a sprite. This is supported in two distinct ways which are explained below.

Changing the name of an existing Character#

This method is very simple to use but also has the potential to mess with the game beyond a specific scenario as name changes are retained until a specific reset function is called (resetstate) or the names are manually reset. As such we discourage use of this technique unless done very carefully.

To change the name of an existing character, you can simply do the following:

1
$ <character_to_change:character>.name = <name:string>
1
$ john.name = "Jacob"

From this point onward, whenever john speaks, he will show up as Jacob instead of John. Keep in mind that his name will stay that way until you change it back!

Creating a temporary character#

It is possible to create an entirely new speaker-character which can be used in the script as if it were a full-fledged character, with the exception that this "fake" character will not have any sprites. It purely exists to speak dialogue. This is the recommended way of creating new speakers or changing the name of existing ones by having the fake character speak the lines of the existing one.

A fake character (or rather, "fake person" as they are called in Student Transfer) can be created and used like this:

1
define <script_name> = FakePerson(<display_name:string>, <body_with_voice:body>)
1
2
3
4
5
6
7
8
9
# Define the fake person
define secretary = FakePerson("Secretary", 'donna')

# Use them in the script
secretary "Hey, listen!"

# Note that you can not do this:
show secretary a_0 at center
# Fake persons do not have any sprites associated with them!

Auto-Reloading the Game#

A very nice feature for anyone working on scripts in Ren'Py is the auto-reload functionality. It can be enabled at any point in the game with the key combination Shift+R. Once enabled, the game will reload once (without closing) and from that point onward it will reload everytime a script file on disk changes (normally when you save new changes). Auto-Reload can be turned off with the same key combination, which will stop the game from reloading when modifying files.
Watch out though, because if you make a script change that breaks the game, Student Transfer will crash during the next auto-reload.

Direct Paths to Images#

Scenarios can now access the full path of any image they contain via the direct_path method. Given the script name of the image, it will return the direct path of the file on disk:

1
2
direct_path("example asset_arrow")
Return Value: "/Users/Username/Downloads/Student Transfer/game/scenario/example/assets/arrow.png"

This is the recommended way to obtain direct paths to files (if they are necessary at all) as this method will always work, even when the scenario is installed somewhere other than the default location in the game's folder.

Hooking into the main storyline#

For scenarios that extend the main storyline we support hooking them into the main game. Making use of this feature will enable your scenario to pop up in the main game at a point of your choosing and present the player with the option to either seamlessly transition to your story or continue on their merry way.

The only thing you have to do to make this feature work is to add/modify a single field to/in your scenario.json file:

1
"hook_hash": "a757c4bc"

The string next to hook_hash is a unique identifier for every piece of dialogue in the game. This includes scenarios as well, so in theory you could hook into other peoples' scenarios, too! Don't do that though, that's uncharted territory.
Anyway, in this case 0d1fe1f4 refers to a very early piece of dialogue in John's room with him saying "Of course!" we don't expect you to know how to compute this yourself, so instead you can simply press Shift + H while in-game and you'll see that in the top-right corner a small string of characters will appear. To make your life even easier, you can simply click on it to directly copy it to your clipboard. The only thing you have to do is go to the position in the game where you want to hook into, copy the corresponding code, and paste it into the hook_hash field of your scenario. If the field does not exist in your original scenario.json file, you can simply add it, making it look something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "author": "Jcjace45, CobaltCore",
    "title": "Writing Scenarios in Ren'Py",
    "description": "A quick and dirty guide to creating scenarios. For more information, read the official {a=https://www.tfgamessite.com/phpbb3/viewtopic.php?f=72&t=8846#p347156}guide{/a}.",
    "label": "scenario_example",
    "tags": ["official", "tutorial", "guide"],
    "version": "2.0.0",
    "prefix": "example",
    "hook_hash": "0d1fe1f4"
}

Once that is done, everything else will be taken care of automagically. As a convenience function we also expose the boolean variable _scenario to your code, which you can use to determine if the player came from the main storyline or started it through the scenario mode. That way you have the chance to do some additional setup for players starting your scenario normally or insert some glue-narrative for people coming directly from the story, which you can do like this:

1
2
3
if _scenario:
    john "Hah! You came from the main storyline!"
    john "Anyways, let's get on with it..."

Advanced Scenario Hooks#

Starting with v4.3 of Student Transfer it is possible to register multiple hooks as well as a add small description for each. This works by supplying a hooks field in the scenario.json file, like so:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
    "author": "Jcjace45, CobaltCore",
    "title": "Writing Scenarios in Ren'Py",
    "description": "A quick and dirty guide to creating scenarios. For more information, read the official {a=https://www.tfgamessite.com/phpbb3/viewtopic.php?f=72&t=8846#p347156}guide{/a}.",
    "label": "scenario_example",
    "tags": ["official", "tutorial", "guide"],
    "version": "2.0.0",
    "prefix": "example",
    "hooks": {
        "7151120f": "Perhaps you should wish to understand your new powers",
        "a757c4bc": null
    }
}

You can use this functionality to hook into as many different parts of the story as you like.
To allow you to tell apart where each player came from, the _scenario variable that is passed to your scenario now contains the original hash value of the block of dialogue the player branched off from.

For reasons of backwards compatibility, both fields (hook_hash and hooks) will work, even simulatenously.

Recommendations of the Team#

This section will elaborate a bit on our stance on certain things and explain why they are the way that they are. This is something of a please-do and please-don't list, mixed with best practices for scenario authors.

CG Usage#

In short: Don't.
The long version is that we'd like to hog the few existing CG's of established characters to ourselves, as egocentric as that may sound. The reason is simple: There are only a limited number of CG's available, even fewer that fit the tone of the game and even then they have to fit the scenes we're writing and the outfits the characters are wearing. As such, and to avoid spoiling the surprise before the main game gets to it, we'd like scenario authors to refrain from using CG's of existing characters, tempting as it might be.

Using CG's of other characters that do not exist in the base game is fine by us. If you're in doubt, just hit up someone from the dev-team to verify whether what you're doing is too close for comfort or not. Generally, you're free to use whatever CG's you like as long as they either a) don't belong to Candysoft games (which is where we get most of our sprites for the base game from) or b) don't show any of the characters from the base game.

Best Practices#

  • Character images should be in PNG or WebP format.
  • While characters can work without their character.json being given, it is advisable to fill in at least the correct name and name color for a character.
  • Characters should be prescaled as much as possible. If you have to set the scale outside of the range 0.8 to 1.2 you should consider rescaling your images beforehand.
  • Optimise your images with software like PngGauntlet (Windows), ImageOptim (macOS) or Trimage (Linux / Unix) for filesize savings. Make sure you use lossless compression in all cases to avoid artifacts!
  • If you use just a few characters from another scenario (less than 5), copy them into your scenario so that you don't depend on the other scenario.
  • If you use many characters from another scenario (more than or equal to 5), use them directly without copying them. Make sure you notify your players of the fact that they will have to install a second scenario, preferably in big-bold letters right next to your main download link and provide a link to that scenario.
  • If you want to extend an existing character, either from another scenario or from the base game, copy them into your scenario and modify them there. This ensures that modified characters of the same name don't conflict and that all scenarios and the base game display as they should.
  • Use as little custom characters as possible. The cast we provide is already rather large and we generally pay attention to file size and RAM requirements. This is especially important because a large amount of sprites might lead to Out Of Memory issues when too many scenarios are installed. So please take care to keep your scenarios as lightweight as possible.