The Team
Charcuterie
MINI
Ghosts & Japes
Patreon


Ghost Gallery
Eka's Portal
Nothing here
This guide is for 1.0! Please go to 2.0 for up-to-date info!
Up-To-Date info can be found within the modding_guides folder you get bundled with the game.

Ghosts & Japes - Mod Guides (1.0)

Welcome to the Mod Guides page.
Here we'll try to explain how to correctly make your mods for the game Ghosts & Japes.
If you'd like to read the TXT file all this info is coming from, please click right here. README.txt
This file can also be found in the same folder as the game's exe file.
Please scroll down and read at least the first paragraph before diving into game files.

Let's start of quick and easy, use this TOC (Table of Contents) to easily find what you're looking for.

Basic Knowledge

About the folders within /resources/
- enemy
Folder where you can edit or place modded json files for custom ghosts / enemies.
- house
Folder where certain (minor) game flags are set, such as if you have already seen the intro dialog once.
- lang
Folder where a bit of text is loaded from.
Do note the game's font (probably) only supports A-Z.
Only a very select few characters can display of the special category, such as ~.
- sound
Sounds obvious on what this folder is for. ;)
Folder where the game loads SFX, the game can only understand OGG files!
- sprite
Majority of the in-game sprites are stored in this folder, vanilla and modded sprites.
The largest folder in particular is the sprites folder.
Before going into depth, here is an important note you should know.
Due to the way the game functions, content can be loaded from both the game's /resources/ folder and from its AppData folder.
Content inside the /AppData/Local/ folder have priority over the folder within the installation directory, which is the /resources/ folder.
You can find /AppData/Local/ folder by following these steps.
  1. Open your Windows Explorer
  2. Type %appdata% into the directory bar on the top
  3. Optional: You can also open the folder by pressing Windows Key + R and typing in %appdata%.
  4. Once inside the the folder, you may be inside a folder called Roaming
  5. Go up one level out of that directory, you should be in the Local Folder instead now
  6. The game's AppData folder is located in this file path AppData\Local\Ghosts_and_Japes
  7. You now should be inside the game's AppData folder :)
If you've played at least up till the 2nd floor within the game, a new file would be within the folder called main.sav
It is encoded in Base64, if you wish to edit your save file.
You can use a website such as this to easily edit the Base64 encoded save file.
When any permanent flags are set, these will go into this folder within /resources/house/.
Now it's time to explain /sprites/.

=== /_progen/ ===

In here, every type of room is stored.
The naming of them is important, as most of the sprites with how they are labelled.
If you want to add a room of your own, you must use the specific colors and name them in a certain way.
Beside the README.txt is another file called KEY.png, this file can be used to color pick the exact color code, every color tells the game what to place where within your custom room, go wild!
More info about the KEY.png can be found here: KEY Colors.

If you plan on using a tool, please make sure any anti-aliasing is disabled!
We recommend using Aseprite for making the rooms.
Please use EXACT colorations as per the KEY.png file, it is also recommended that you draw using the brush size at 1 or the pencil tool, to make it easier for you to make rooms or sprites.
When naming your custom rooms, you must name them with the prefix "spr_progen_".
If it has this prefix, the game's room compiler will recognize it.
After this prefix you must specify what kind of room this is.
Here is a list of some room types you can choose from, with a brief explanation of what they are:
  • branchb - Room with doors that go up, right, and left.
  • branchl - Room with doors that go up, right, and down.
  • branchr - Room with doors that go up, left, and down.
  • brancht - Room with doors that go left, right, and down.
  • cornerbl - Room with doors that go up and right.
  • cornertl - Room with doors that go up and left.
  • cornertr - Room with doors that go left and down.
  • cross - Room with doors that go up, down, left, and right.
  • hallh - Room with doors that go left and right.
  • hallv - Room with doors that go up and down.
  • roomb - Room with a door that goes up.
  • rooml - Room with a door that goes right.
  • roomr - Room with a door that goes left.
  • roomt - Room with a door that goes down.
  • start - The starting room of a floor.
    About "start", it must have a door that goes left, right, and upstairs.
Aside the room sprite files, you should normally see files called .progen.
These files are pre-compiled versions of the room sprites that are stored into a file.
If they are deleted, or the corresponding .png sprite file in any way, the game will automatically regenerate the files for you.
Even room sprites that you added yourself!
It is recommended you structure your custom rooms in the exact way that you see some of the existing rooms use.
If a room type requires certain doors, you should include those, or else the game is probably going to break, crash or become unplayable.
Your room sprites also don't need to be even dimensions - you can make them 16x16, 16x29, 31x8, whatever you want.
Keep in mind though, that the larger your room is, the more it can take to have the game compile it, the game may perform worse inside of them.
When the game compiles a new .progen file, it will not go into the installation directory's resource folder.
Instead, it'll go into its /AppData/Local/Ghosts_and_Japes/ directory, as explained previously.
Also, if you delete a .png file, the game will not add it to the rooms that will generate in-game list, even if the .progen file exists.
Now, if you want an example for naming the files, here is one:
spr_progen_hallv_my_cool_hall.png
To quickly recap, you need the spr_progen_ prefix followed by the type of room it is, such as the example used hallv.
Then you can put any name afterwards to make it distinctly named from other rooms within the folder.
Once the game is ran once, it should generate the .progen files for you inside the folder /AppData/Local/Ghosts_and_Japes.

KEY.png

Now let's talk about the KEY.png file we mentioned a bit ago.
Color Codes for Custom Room Sprites
Above this text you should see an image of the KEY.png file and below this text you should see all the Color Codes.
  • ■ Painting #3a5bff
  • ■ Chest #4cff00
  • ■ Box #4f4c67
  • ■ Chair #ff563b
  • ■ Rug #ffa3f4
  • ■ Table #8f563b
  • ■ Door Up #ce6700
  • ■ Door Down #b51200
  • ■ Door Left #7a00d1
  • ■ Door Right #f7009b
  • ■ Door Upstairs #80ae9b
  • ■ Floor #b5a27e
  • Solid #000000
  • ■ Shop #3affff
  • ■ Lamp #ffce30
  • ■ Bed #0000ff
  • ■ Full Heal #ff0000

=== /(insert enemy name here)/ ===

You'll see every enemy's sprites are stored in their own folder with their name.
Them being named this way actually doesn't matter, it is for organization purposes, keeping everything dust free.
You could, for example, have one of the custom ghosts named cool_ghost but it loads the sprites from the uncool_ghost folder just fine.
Each and every enemy is required to at least have these sprites:
eat, gameover, grabbed, idle, MASK and painting.
Another important thing that is required is that the color used for transparency is the top-left most pixel.
If your custom ghost/enemy, or any other sprites, is rendering weirdly in-game, check the color you used for transparency. Also, any animated sprite needs to have square-shaped frames.
So, if you wanted an animated sprite with 4 frames, and your enemy is 16x16 pixels, the sprite sheet should end up being the size of 64x16. The dialog portraits are completely optional, if you want your custom ghost to have a voice at all.
The names are generally self-explanatory; here is what all of them mean when they are used:
  • eat - When the enemy is currently attacking the player.
  • gameover - Displays after the enemy has defeated the player.
  • grabbed - Frame 1 displays when the enemy is stunned by the player's flash.
    The whole sprite animation plays while the enemy is being siphoned by the player's wand.
  • idle - The general animation that the enemy uses.
  • MASK - The enemy's interaction range.
    If the player's MASK collides with the enemy's MASK, interactions can happen; such as the enemy beginning to attack the player or the player being allowed to talk to the enemy.
  • painting - When an enemy spawns in a room, they are able to replace pre-existing paintings with their own.
  • portraits - Optional: Can be used in the strings_en.txt file to make a textbox sequence render that portrait.

=== /painting/ ===

Inside of this folder, random paintings that are placed around the household are loaded here.
These MUST be named with the prefix "spr_obj_painting_".
Anything after that is fine though.
Once again to remind, make sure the top-left most pixel is the color you want to have for transparency, or it will render not as desired in-game.
So, as an example, you can have a painting sprite file named "spr_obj_painting_my_coolpainting.png"

=== /player/ ===

The sprite names for the player character are hard-coded into the game.
the portraits are optional as before, as they are only used for the textbox sequences seen in the strings_en.txt file.
If you are going to make a custom player, you must them in the exact same way as you find them in the folder.
The player must have at least these sprites:
  • spr_player_down_idle
  • spr_player_down_move
  • spr_player_generic_gameover
  • spr_player_ko
  • spr_player_left_idle
  • spr_player_left_move
  • spr_player_MASK
  • spr_player_right_idle
  • spr_player_right_move
  • spr_player_up_idle
  • spr_player_up_move
The player's MASK sprite is used for the player's interaction collision range.
If it is overlapping with an enemy's interaction mask, interactions such as attacking or chatting can occur.
The generic gameover sprite is used for if the player is somehow defeated by something other than a ghost.
Basically you get the Generic Game Over if you reach 0 HP while outside of a ghost.

=== /projectile/ ===

All projectile animations are loaded from here, you can add your own projectiles to your custom enemies.
Now, the /sound/ folder.

=== /sound/ ===

This folder is simple; if you want to add your own custom sounds for your enemies, their projectiles, or dialog, you place them here.
All they have to be is in .ogg format.
If they sound wrong in-game, make sure your sound file does not have a strange sample rate.

Advanced

=== /lang/ ===

The /lang/ folder is where nearly all text, aside from a few hard-coded in-game ones, are stored inside of.
You can also make and add your own new dialog in here with certain special effects.
Per-enemy dialog should be placed in their own respective JSON files, unless there's something specific you need a dialog they speak to do.
I will explain how our text formatting system works, strap yourself in for some learning.
Here, I will list an example text:
{
"txt.cool_string_name.0": "[speaker.spr_portrait_player_neutral.snd_vox_player][color.rgb.0,255,0][motion.wavy.20]Hello,[wait.amount.5] [reset][motion.rando.1]world!"
}
The first value, '"txt.cool_string_name.0":' is the text's identifier.
This is to be used in the enemy JSON files to make it actually load and be used in-game!
The second value is where the actual text contents are.
There are a few text formatting options to make your dialog more fun to read.
I will explain them in order of how they appear in the example text above, in order, then list all of the text formatting options below that:
  • [speaker.spr_portrait_player_neutral.snd_vox_player] - Here, you can set who is speaking aloud the dialog.
    If you remove this entirely, it will be read generically by the game.
    After the first ., the name of the portrait sprite must be specific.
    Then, after the second ., you specify the voice sound they use for reading their dialog.
  • [color.rgb.0,255,0] - You can color your text to any color by supplying RGB values.
    In the example text, the text Hello, would show up in green.
  • [wait.amount.5] - How long to wait before reading the letters after this tag. In this case, it's 5, which means it waits 5 frames. This game runs in 30 FPS.
  • [motion.wavy.20] - This moves every individual letter it affects in an orbit around its origin point.
    The 20 means its orbit rotates 20 degrees every frame.
  • [reset] - This is used to reset and remove all previous text formatting that were applied to the text. So, after the green Hello, that had wavy letters as well, the text after the [reset] would no longer have wavy motion or green applied.
  • [motion.rando.1] - Moves each letter in a random direction around its origin point, which has the effect of looking jittery. The number specified, 1, means each letter moves between -1 to 1 around the letter's origin point on its x- and y- axis.
  • IMPORTANT!!!
    With these text formatters, you should never put them at the very end of a string.
    If you want to do this, you must add a blank space directly after it.
    If the string ends with a formatting tag, but no space afterwards, the game will crash once it reads the text formatter.
    This is an important none, for things such as enemies talking to you automatically while attacking you.
    For those, you will have to place, for example, a [wait.amount.30] afterwards or else the ghost's dialog disappears immediately as soon as the ghost is done talking to the player.
Next, here is a list of every single one of your text formatting options:
  • [speaker.sprite_name_here.audio_name_here] - With this tag, you place it at the start of a text, and that will tell the textbox to render sprite_name_here on the left inside of the textbox, and play audio_name_here for every time a letter (a-z) is read in the textbox.
    This is used to make text be spoken by a character, for instance.
  • [color.rgb.255,255,255] - With this tag, you can color text after its position in the text using RGB values separated by commas.
    With a value of 255,255,255 this results in the text after it being rendered as white.
    Note that by default, in textboxes with no color tag, the text is rendered in white.
    This applies to after a [reset] tag is read.
    (see below for more info on [reset])
  • [motion.motion_name_here.value] - There are a few different options with this tag.
    For the first argument, motion_name_here, you have these options:
  •  - rando makes the text have a jittery appearance.
    value dictates how much the text jitters away from its origin point, in pixels. Values MUST be whole numbers (integers).
     - wavy makes the text orbit around is origin point.
    value dictates how many degrees to rotate around its origin per frame. Note that the game runs in 30 FPS. Value must be whole numbers (integers).
     - singsongy is the exact same as wavy, but it will not move left or right. Value must be whole numbers (integers).
     - wobbly is the exact same as wavy, but it will not move up or down. Value must be whole numbers (integers).
  • [wait.amount.value] - Use this tag to indicate when the text should wait a certain amount of frames before continuing.
    Replace value with the number of frames to wait before continuing to read the text.
    So, for example, [wait.amount.30] would make the textbox wait 30 frames (or 1 second, since the game runs in 30 FPS) before continuing to read.
Finally, depending on the contents of the text identifier key, the textbox can behave differently.
  • Text identifier ends with .choicec - You can specify choices the player can input, at the end of the string, separating them with |
  • Text identifier ends with .grab_player - After this text finishes, the initiator of the text (if an enemy) will grab the player and begin attacking them.

=== /house/ ===

The /house/ folder is where certain specific permanent game flags are set.
At the time of writing this, there are currently 4 "house" files, as I will continue to refer to them by.
These files are files that have no file extension, and continue 1 line of very basic info.
If you can't find a specific house file, check /AppData/Local/Ghosts_and_Japes/resources/house/ and the game installation's directory's /resources/house/ folder.
Here is what each one does currently:
  • size - Here, you can specify how large every floor of the game should be.
    It is a default of 16, has a minimum of 8, and a maximum of 3072.
    Note: If you set the value to below 8 or above 3072 will immediately crash the game on loading.
    It is highly recommended you leave this alone, as 16 feels best to play.
    8 means every floor is very short, and 3072 means every floor is gigantic.
    Your computer may crash or be unhappy if you do anything especially in the thousands.
    IMPORTANT!!! Sad Kaishi because you can't beat the floors above a thousand in value.
    The game is probably also impossible to beat with floor sizes that large.
  • grave - This file keeps track of how many enemies you have defeated across all playthroughs.
  • intro1 - A simple file that keeps track of whether or not you saw the player's intro dialog from playing for the first time.
  • item_swap_explanation - Similar to "intro1", keeps track of whether or not you had alternate item hand swapping explained to you yet.
  • opt_music - Options menu setting; where the music toggle is stored.
  • opt_window_fullscreen - Options menu setting; where the fullscreen toggle is stored.
  • opt_window_scale - Options menu setting; where the window scale is stored.

=== /enemy/ ===

Now this is where the fun begins, with the /enemy/ folder.
Here, you can add your own enemies just like how you've seen all the others in-game.
You'll see that there may be .inactive files.
These are example files to help you, as some things might not even be used in the game currently.
Similarly, if you ever want to disable an enemy, just delete them or change their file extension from .json to anything else that doesn't start with .json.
It would be most easiest to explain how you make your own enemy by looking over existing ones, copying their file, then modifying it to how you see fit.
Open up angello.json and look over its contents, for example:
There are 3 main structs (things that go between {}) in enemy json files, with 1 of them being entirely optional.

=== "Anim" ===

The 1st required main struct.
Here, you specify the way your character looks in-game.
Your enemy is required to have these animations, or it will not be imported at all:
  • idle - The general sprite the enemy uses.
  • grabbed - The 1st frame is shown when the enemy is stunned by a flash of light. While it is being attacked by a player, the entire animation plays.
  • eat - Plays while the enemy attacks the player.
  • painting - The enemy's room painting replacement. If you didn't know, when enemies spawn, if there's a painting in a room, there's a chance they can possess a painting when spawning.
  • game_over - The enemy's game over art that is displayed if it defeats the player.
  • MASK - The enemy's interaction range collision mask.
Some of these have sub-values of "sprite", "speed", "glow" and "offset" as you can see.
  • With "sprite", you specify the name of the sprite file.
  • With "speed", you specify the frames per second of the sprite's animation speed. If you set it to 0, it will not animate.
  • With "glow", you specify the sprite's visibility. If it's set to true, the enemy will render above darkness and fog layer.
    NOTE that this only applies to anims of "idle", "grabbed", "eat", and "projectile".
  • With "offset", you specify how far on the x- and y- axis it should be rendered from its origin point.
    This is only used by the anim "game_over", to adjust the sprite's positioning.
Depending on the enemy's behavior, specified in the main struct "Specs", there will also be an anim section labelled "projectile", which is an array of structs.
See magi.json, for example. Here, this enemy has a list of structs for anim "projectile".
Enemies do not have a shooting animation, but here is where you specify what projectile they should randomly shoot.
If you only list one projectile, that one will be chosen every time, of course.
I will now explain the "projectile" struct and what each value means.
  • sprite - The sprite that the projectile uses. It can be animated or not.
  • speed - The animation speed (in frames per second) that the projectile sprite animates.
  • move_speed - How fast the projectile should move, in units per frame.
  • shoot_speed - How fast the enemy should shoot when it is time to shoot, in seconds.
    Note that this doesn't have to be a whole number.
    So, for example, 0.5 seconds is okay. With "shooter" behavior, this means it will shoot "shoot_speed" seconds after it re-appears from disappearing.
    With the "polluter" behavior, it means it will shoot this projectile every "shoot_speed" seconds while it's around.
  • behavior - The projectile's behavior. Currently, there are 3:
  •  - "homing" - Will follow the player
     - "normal" - Will travel in a line in the direction it was shot out from
     - "normal_rotate" - Same as "normal", but it rotates towards where it's going
  • lifetime - How long, in seconds, the projectile should (at most) be allowed to live for before disappearing. Again, non-whole numbers are okay.
  • glow - Similar to how enemy glow value behaves. If it's set to true, it will render above the darkness and fog layers, and vice versa for false.
  • hit - Here, you specify what the projectile should do upon it hitting the player.
  • For "effect", you can set it to...
     - "entrance" - Causes the player to forcefully walk towards whoever hit it.
     - "shrink" - Causes the player to shrink, rendering them unable to fight back.
     - "damage" - Deals flat damage to the player.
    For "amount", what you specify here depends on the "effect".
     - "entrance" - How long the player should be entranced.
     - "shrink" - How long the player should stay shrunken.
     - "damage" - How much damage to deal to the player.
  • sound - The sound effect to play when the projectile is shot.

=== Specs ===

The 2nd required main struct. Here is an explanation of each sub-value of "Specs":
  • behavior - How the enemy should behave. You can set it to:
  •  - "normal": Enemy chases the player as usual.
     - "shooter": Enemy chases the player, but also shoots a projectile towards the player after it re-appears.
     - "polluter": Enemy chases the player, but also shoots a projectile towards the player in a certain interval.
     - "friendly": Enemy roams around randomly, and can be spoken to if the player is near.
  • appearances - An array of where this enemy should spawn. Currently, there are 6 unique values you can enter:
  •  - "normal"
     - "dungeon"
     - "overgrowth"
     - "water"
     - "boiler"
     - "dark"
    If your enemies in the enemy folder lack an enemy for a specific floor of the house, that floor will use completely random enemies.
    So for instance, if there's no enemies in your folder that spawn on the boiler room floor, then it will just choose from every enemy at random.
  • health - Has 2 sub-values:
  •  - "amount": The amount of health the enemy has.  - "loss": How fast the enemy loses health from being siphoned by the player.
  • damage - How much damage the enemy does to the player every time it attacks it.
  • struggle - How many times a player must press left or right to escape from it.
  • speedup - How many "eat" "Anim" loops must play before the enemy begins to attack faster.
  • sound - The sound to play every time the enemy attacks a player.
  • speed - How fast the enemy should move, in units per frame. Can be a non-whole number.
  • panic - Has 2 sub-values:
  •  - "panic": The movement speed multiplier for how fast the enemy should move while being siphoned by a player.
     - "randomness": A random range of angles for movement direction that the enemy should move in away from the player that is siphoning it. Larger numbers make it behave more erratically, while lower numbers make it move in a more straight-like line. Can be non-whole numbers.
  • pull - Has 2 sub-values:
  •  - "amount": How long a player can pull on the enemy while siphoning them, in seconds. Can be a non-whole number.
     - "cooldown": How long a player has to wait, after pulling for "pull.amount" seconds, before a player can pull on it again, in seconds. Can be a non-whole number.

=== "Dialog" ===

The 3rd, and final, OPTIONAL main struct.
Here, you can make your enemy talk to the player as it interacts with them.
It is best that you look over the enemy json files to understand how you structure your own.
Basically, every dialog is an array of arrays (lists of lists), meaning it's lists of text sequences to display.
The sequences are chosen at random, so if you only specify one sequence in the list, it will be that one every time.
Every dialog entry is optional, so if one is missing, the enemy just won't talk for that specific trigger.
See kaishi.json for an example of using both lang file-loaded strings and embedded strings.
With enemies, you can directly write their dialog into their JSON.
Alternatively, you can write their dialog entries as lang file keys, for example, "txt.my_enemy.0", and so on.
You must use the lang file if you want certain special effects from dialog triggering; this is most useful for ghosts such as friendly ghosts.
You must have a lang file entry with ".choicec" in its key if you want to be able to make a dialog with choices.
You can also put ".grab_player" in a lang file entry's key to make it so once that dialog entry ends, the enemy speaking immediately grabs the player.
Again, it is best to look over existing files and see how it works.
Copy over existing json code and change it to your needs.
Now, instead of providing exhaustive examples, I will explain what every trigger is:
  • initial_grab - When the enemy initially grabs the player.
  • hide_and_seek - When the enemy initially grabs a player that was hiding in a box.
  • entrancement - When the enemy initially grabs a player under the effects of entrancement.
  • shrunk - When the enemy initially grabs a player under the effects of being shrunk. This dialog takes priority over the entrancement dialog.
  • taking_too_long - When the player has not resisted against the enemy for a long time.
  • power_outage - When the power goes out and the enemy exists.
  • health_milestone - Sub-values:
  •  - sixtypercent - When the player being attacked by the enemy has reached 60% health remaining, as long as the enemy can deal more than 0 damage.
     - thirtypercent - When the player being attacked by the enemy has reached 30% health remaining, as long as the enemy can deal more than 0 damage.
     - love_two - First dialog that plays after a while of the enemy healing the player, as long as the enemy deals less than 0 damage (is a healer).
     - love_three - Second dialog that plays after a while of the enemy healing the player, as long as the enemy deals less than 0 damage (is a healer).
     - love_four - Third and final dialog that plays after a while of the enemy healing the player, as long as the enemy deals less than 0 damage (is a healer).
  • gameover - Sub-values:
  •  - attempted - When the enemy has defeated the player, and the player has resisted at least once.
     - gaveup - When the enemy has defeated the player, and the player didn't resist at any point.
  • absorbed - After the game over sequence, if the player waits until the enemy has stolen all of the player's max health, this dialog will replace the game over sequence.
  • talk_to - Only applicable for enemies with a behavior value of " friendly". Sub-values:
  •  - main - The main dialog to display upon talking to the enemy for the first time.
     - response1 - The dialog to display upon selecting choice 1 in the main dialog.
     - response2 - Same as above, but with 2nd choice from main dialog.
     - response3 - Same as above, but with 3rd choice from main dialog.
     - response4 - Same as above, but with 4th choice from main dialog.
     - response5 - Same as above, but with 5th choice from main dialog.
     - response6 - Same as above, but with 6th choice from main dialog.
     - response7 - Same as above, but with 7th choice from main dialog.
     - response8 - Same as above, but with 8th choice from main dialog.
     - response9 - Same as above, but with 9th choice from main dialog.

If you read everything above, you are awesome. Happy modding! <3