Kailey's Interior Door Guide

From Stardew Modding Wiki
Jump to navigation Jump to search

This is a mildly advanced guide for modders that assumes familiarity with Tiled, Content Patcher, and map modding fundamentals such as the difference between Map Properties and Tile Properties.

Interior doors, such as the one in Figure 1, are interactive map elements with hardcoded behaviour (see InteriorDoor.cs). There are three types in the base game: the Standard Door, Clinic Door, and Saloon Door1. All three can be used in custom maps, but completely new types are not possible without C#. The existing types can, however, be reskinned via Content Patcher to allow functional, customized interior doors.

1The Saloon Door is actually two doors. See Notes, Exceptions, and Hardcoding.

A screenshot of the interior door connecting Pierre's shop to the aerobics area. The bottom tile of the door is outlined in red and the top two tiles of the door are outlined in blue.
Figure 1: The red highlighted tile is on the Buildings layer, while the blue highlighted tiles are on the Front layer.

Getting Started With Interior Doors

An interior door has four elements:

  1. The translucent door sprite, found on Maps/townInterior
  2. The door animation, found on LooseSprites/Cursors
  3. The Tile Property Action Door
  4. The Map Property Doors

These four elements are covered in order below.

A screenshot of townInterior with the three interior doors outlined in red, with arrows pointing to them.
Figure 2: The location of all three doors on townInterior is highlighted in red.

townInterior Door Sprite

This is the sprite that is placed on your map. The bottom tile is placed on the Buildings layer, while the top two tiles are placed on the Front layer. See Figure 1 for an example.

In the case of the Clinic Door, the topmost tile is empty; it must still be placed on the Front layer regardless of this.

If all three door tiles are not placed on the correct layers, the door will not work. Offset layers such as Buildings2 or Front-1 will not work; only the original Buildings and Front will.

See Figure 2 for the location of all three doors on townInterior.

Cursors Door Animation

A screenshot of the Cursors tilesheet with the three door animations outlined in red with an arrow pointing to them.
Figure 3: The location of the door animations on Cursors is highlighted in red.

The animation for the door opening, found on Cursors, plays when an NPC or player interacts with the door. The first frame of the animation is drawn behind the corresponding doors at all times when they are closed; this is why the doors do not appear translucent in-game despite appearing that way when viewed in Tiled.

All of this happens via hardcoding in InteriorDoor.cs; modders do not need to worry about making it work beyond what is explained in this tutorial. See Figure 3 for the location of all three doors animations on Cursors.

A screenshot of Tiled showing a Door action tile, the tiledata information, and the layers tab. A red arrow points to the Buildings object layer and a blue arrow points to the tiledata information.
Figure 4: The red arrow highlights which layer the 'Door' Action Tile must be on. The blue arrow highlights how the properties of said tile should look.

Tile Property: Action Door

The Tile Property Action Door must be placed on the Buildings Object Layer of your map, on the same tile position as the bottom of the door. Note that Object Layers and Tile Layers are different things; Object Layers contain TileData instead of tiles, and are marked with pink icons in the Layers Tab. See Figure 4 for an example.

For a door that can be opened at any time, leave the property as simply Door as shown in Figure 4. For a door that requires two or more hearts with an NPC to open, such as most bedroom doors in the game, append the NPC’s name after Door (e.g, Door Abigail).

Map Property: Door

All maps with interior doors on them must have the Map Property Door with the following data structure:

Door [XPosition YPosition TilesheetID TileID]

Field Explanation Type
XPosition The X coordinate of the Action Door Tile Property int
YPosition The Y coordinate of the Action Door Tile Property int
TilesheetID The name of the Tileset that the door is on, as it is identified in Tiled, for this specific map. This can be different from the asset name (townInterior). Look at the Tilesets window in Tiled to identify this; in the example on Figure 5, it is “1” (highlighted by the red arrow). string
TileID The Tile Index of the bottom tile of the door sprite on townInterior. To find this, click ‘Edit Tileset’ (highlighted in Figure 5 by the red star), and then in the new tab that opens click the tile whose Index you are trying to find. The Tile Index will be displayed in the information panel on the left (highlighted in Figure 5 by the blue arrow).

The TileID of the Standard Door is 120. The TileID of the Clinic Door is 838. The TileIDs of the left and right Saloon Doors are 824 and 825 respectively.

int

The four entries (XPosition, YPosition, TilesheetID, TileID) of the Map Property must be repeated for every interior door on the map. For our example of Pierre’s Shop, there are three interior doors to account for. This comes together for a final result like so:

Doors 13 11 1 120 20 11 1 120 14 16 1 120

See Figure 6 for a breakdown of this data structure.

A screenshot of Tiled with the TileSheet ID of "1" highlighted by a red arrow, the Edit Tileset button highlighted by a red star, and the tile index of the Standard Door (120) highlighted with a blue arrow.
Figure 5: The TileSheet ID is highlighted by the red arrow. The Edit Tileset button is highlighted by the red star; click it to open the Tileset and find the Tile Index of a tile.
A screenshot of the Doors map property data for Pierre's shop, cropped and overlayed with arrows and text explaining each number.
Figure 6: The 'Doors' map property for Pierre’s Shop with the data for each door labelled, and the fields of the first door broken down.


With the door sprite, Tile Action, and Map Properties set up properly, your map should have working interior doors that both NPCs and players can use. See Common Problems if needed.

Notes, Exceptions, and Hardcoding

  • The Cursors animation of the Saloon Door (Right) is hardcoded to always be a mirrored version of Saloon Door (Left). This can be used to your advantage to make double doors without needing a second mirrored asset, but limits any other use.
  • The Clinic Door is hardcoded to always be mirrored if it is on tile 10,5 of any map. This hardcoding is how the double door leading to Harvey’s room is handled, but there are no guardrails preventing this from applying on other maps. Make note of the placement of any Clinic Doors to avoid accidentally mirroring them.
  • Doors must have tiles on the Back layer underneath them to function. There should, however, always be something on the Back layer in a location that the player can walk, so this is unlikely to cause problems.

Custom Interior Doors

Because custom interior doors are just reskins of the base-game interior doors, rather than separate entities, the interior door setup from the previous section must be carried out. This method also comes with the following limitations as a result:

  • Maximum three types of custom interior doors can be on the same map, due to there being three base-game door types to replace.
  • A base-game interior door that is used as a base for a custom door cannot appear on the same map as itself (e.g. you can’t turn the clinic door into a custom door and also use the clinic door on the same map).
  • Doors can exclusively be one tile wide and three tiles tall. A double door can be faked using the Saloon Doors, but a truly two or more tile wide door is not possible.
  • Patching both townInterior and Cursors every time the player enters or leaves your custom map can be resource intensive.
  • The custom door will not be visible in Tiled, only in-game. See Figure 7.
    A screenshot of Tiled showing my custom map with notably mismatched standard doors where the changing stall doors will be.
    Figure 7: My custom map, the gym from my upcoming overhaul of the Bathhouse, with the base-game doors in place. It’s not important that it looks strange in Tiled; the player will never see it.

The process of creating a custom interior door has four steps:

  1. Place base-game doors on your map where the custom doors will go
  2. Create a custom door asset
  3. Patch Cursors with your custom door
  4. Patch townInterior with your custom door

These four steps are covered in order below.

Place Base-Game Doors

Choose where on your map you would like custom doors, and then choose which base-game doors you will be replacing. Place them accordingly, following the guide above. The base-game doors may look strange in place on your map (Figure 7), but we’ll be changing their look in-game soon.

A screenshot comparing a custom door animation with the animation of the Standard Door from cursors. Their size and layout is identical.
Figure 8: Your custom door tilesheet must match the size and layout of the base-game doors on Cursors exactly.

Create a Custom Door Asset

Your custom door tilesheet must follow the size and layout of the door animations on Cursors. It must be 64 pixels wide, 48 pixels tall, and depict four frames: the door closed, the door partly open, the door more open, and the door fully open. Each frame must be 16 pixels wide and 48 pixels tall, with the ‘closed’ frame first and the ‘open’ frame last. Any other size or order will not work.

Patch Cursors

Using an EditImage patch to Cursors, replace the door animation that corresponds to the base-game door placed on your map with your custom door tilesheet:

		{
		"LogName": "Kailey Door Edit- Cursors",
		"Action": "EditImage",
		"Target": "LooseSprites/Cursors",
		"FromFile": "assets/Kailey_CustomDoor.png",
		"FromArea": { "X": 0, "Y": 0, "Width": 64, "Height": 48 },
		"ToArea": { "X": 512, "Y": 144, "Width": 64, "Height": 48 },
		"PatchMode": "Replace",
		"When": { 
				"LocationName": "Kailey_DoorExampleMod_DoorMap"
			},
		"Update": "OnLocationChange",
		"Priority": "Late"
		},

Your FromFile should be the name of your custom door tilesheet.

Your FromArea X and Y should specify where on the tilesheet your custom door begins. Your Width and Height should always be 64 and 48 respectively. In cases like this example where the entire custom tilesheet is being used, starting at 0,0, this line can be optionally removed.

Your ToArea X and Y will depend on which vanilla door you are editing (table below). Your Width and Height should always be 64 and 48 respectively.

Your patch mode should be Replace, as Overlay will likely leave parts of the original door visible.

Your When condition should be set to only apply the edit when the player is on the map where the custom door is, so as to avoid editing every other instance of the base door.

An Update rate of OnLocationChange is necessary due to the locational condition above.

A Priority of Late helps prevent other mods (eg recolours) from overriding your edits and reverting the door to the base-game version.


The ToArea of the base-game doors on Cursors is as follows:

Door Type ToArea X,Y
Standard Door 512,144
Clinic Door 576,144
Saloon Door 640,144

Patch townInterior

If townInterior is not patched with EditImage, the transparent version of the base-game door will still be visible in-game. This patch only needs the first frame of your custom door tilesheet, so the Width of the ToArea and FromArea patches is 16, while the rest of the patch is similar:

		{
		"LogName": "Kailey Door Edit- Towninterior",
		"Action": "EditImage",
		"Target": "Maps/townInterior",
		"FromFile": "assets/Kailey_CustomDoor.png",
		"FromArea": { "X": 0, "Y": 0, "Width": 16, "Height": 48 },
		"ToArea": { "X": 384, "Y": 16, "Width": 16, "Height": 48 },
		"PatchMode": "Replace",
		"When": { 
				"LocationName": "Kailey_DoorExampleMod_DoorMap"
			},
		"Update": "OnLocationChange",
		"Priority": "Late"
		}
An in-game screenshot of my custom map with the EditImage patches to townInterior and Cursors applied
Figure 9: The custom doors will appear in-game, but not in Tiled, if both EditImage patches were successful and the doors were set up properly on the map.

The ToArea of the base-game doors on townInterior is as follows:

Door Type ToArea X,Y
Standard Door 384, 16
Clinic Door 96, 384
Saloon Door (Left) 384, 368
Saloon Door (Right) 400, 368

After a successful patch to both Cursors and townInterior, your doors should appear in game. See Figure 9.

Troubleshooting and Common Problems

Doors Not Appearing

If your edits to the base-game doors are not appearing in game, perform a patch export on townInterior and Cursors to see if your edits are applying.

If your patch exports show the edits are applying, but your doors still don’t appear in game:

  • Remove any vanilla tilesheets from your assets folder before running the game, especially townInterior and Cursors. Content Patcher will use the local versions of these tilesheets in your assets folder instead of the versions in Content/Maps, which prevents your changes from being seen.

If your patch exports show the edits are not applying:

  • Check for other mods that may be overriding your edits. Run a patch summary on Cursors and townInterior to see who else is editing them.
  • Confirm that your When conditions are set to what you intended. Test without the conditions and see if the edit applies to every door as a quick check- if it works without your conditions, they’re the problem.
  • Check that your doors open in-game. If they were improperly set up on the map, the Cursors assets won’t be visible and the door won’t work.

Ghost Doors

If there is a transparent overlay of the base-game door visible, it means that your Cursors EditImage patch was successful but your townInterior EditImage patch was not. See Doors Not Appearing.

Custom Doors on Existing Maps

Adding a custom door to an existing map using a map patch? Remember that the Doors Map Property must apply to the parent map, and must include all interior doors on the parent map. Consider using Content Patcher to edit the parent map’s Doors property, and adding your data via the append text operation to avoid overwriting the existing data. Also, remember that your EditImage changes will apply to all instances of the same door type on the map; use a door type not found on the parent map to avoid replacing the existing doors.