Tutorial: Adding a New Fish

From Stardew Modding Wiki
Jump to navigation Jump to search

Adding a new fish to the game has never been easier than in 1.6; nowadays, fish are a simple set of patches via Content Patcher. There are four required steps: you need to load sprite images, define the fish (as an item, and as a fish) and add it to locations. Optionally, you can add aquarium sprites and data, and fish pond data. I'll be using Not You Again as a reference as it adds five fish and does nothing else.


Sprites

Fish have two sprites - the 16x16 pixel item (what you see when you fish) and the 24x24 aquarium sprite (what you see when you place the fish in an aquarium).

The item sprites are typically (but not always) angled with the nose at top right and the tail at bottom left. Aquarium sprites are horizontal with the nose to the right. You can change the angle on the aquarium sprites, but they'll look weird if you keep the default animation. Also technically they're not *required*, but your fish will not be placeable in an aquarium (or show up with Visible Fish) so it's recommended. The actual size of the aquarium sprite is 24 x 48, but the bottom half isn't used and typically just has a copy of the item sprite, as above.

In 1.6, you now have the ability to combine sprites of the same type, so you can have one .png for your item sprites and one for your aquarium sprites. Convenient!

Content File Setup

Okay, let's start the code. In addition to your image files, you'll need a manifest.json (tutorial here) and a content.json. Start with this:

{
    "Format": "2.7.0",

"Changes":
	[

]
}

Everything we're going to add next will be inbetween the [square brackets]. Starting with....

Sprite Loading

Let's load all the sprites we did in step one:

		
		{
			"LogName": "Aquarium fish load", //A logname is not required, but helpful for troubleshooting
			"Action": "Load",
			"Target": "Mods/tiakall.seabass/AquariumFish, Mods/tiakall.seabass/SeaBass, Mods/tiakall.seabass/DuskyGrouper, Mods/tiakall.seabass/PinkMaomao, Mods/tiakall.seabass/PotatoCod, Mods/tiakall.seabass/RedbandedPerch", 
			"FromFile": "assets/{{TargetWithoutPath}}.png" 
		},

What this is doing is telling the game to load your images into a designated spot in the game files that's tied to your mod (the Mods/tiakall.seabass/ part, which is tied to your mod's unique ID - so Mods/{{ModId}}/ also works!) You will need a Target for everything you want to load in - in this case, my Aquarium sprites are on one spritesheet (AquariumFish) whereas my fish all have separate images.

FromFile is using a nice little trick here: {{TargetWithoutPath}}. If your file name matches the name you want to load into Target (which it should, no reason to make it different since there's no real requirement for file names here), you can use this to load everything all at once, instead of having to patch Target "Mods/tiakall.seabass/AquariumFish" to FromFile "assets/AquariumFish.png" and so on down the list. They do have to be in the same folder within your mod - in this case, my assets folder.

Add fish as items

We need to load the fish data itself in two separate spots - Data/Objects adds it as an item you can buy and sell, while Data/Fish adds some fish-specific data. Let's start with the Data/Objects entry:

        {
            "LogName": "Fish as items",
            "Action": "EditData",
            "Target": "Data/Objects",
            "Entries": {
                "tiakall.bass.SeaBass": //This is your item's ID, so it's important to make sure it's unique - your mod ID can help here again - <nowiki>{{ModId}}.fish</nowiki> works and would output tiakall.seabass.fish in this case
				{
                    "Name": "Sea Bass",
                    "DisplayName": "Sea Bass", //This is the name that shows up in game.  Can be [[How_to_make_your_mod_compatible_with_other_languages|i18n'd]].
                    "Description": "I caught a sea bass! It's more like a sea PLUS.", //I apologize for no puns. Can be [[How_to_make_your_mod_compatible_with_other_languages|i18n'd]].
                    "Edibility": "10", //how much health/energy restored when eaten - corresponds to about 2.5x health and 1.25x stamina. 
                    "Type": "Fish", //Generally you want this to be "Fish" for integration with fish-specific things like Angler profession boosts and any_fish recipes, but it's not required
                    "Category": -4, //Same as Type, generally you will leave this to -4, but it's not required
                    "Price": "200", //Note: this will be the sell price.  If the fish can be bought the buy price is usually 2x. Affected by quality.
                    "Texture": "Mods\\tiakall.seabass\\SeaBass", //This should match the target you loaded into above, with <code>\\</code> in the place of the original backslashes.
                    "SpriteIndex": 0, //If you loaded each sprite as its own image, this will be 0, otherwise it should correspond with the position on your spritesheet (left to right).
                    "ContextTags": [
                        "color_green",
						"fish_talk_bass",
						"fish_has_roe"
					]
				},
        },

Some additional notes:

  • For edibility, you can use -300 to make it inedible, -299 to -1 to reduce health/energy (poisonous), and 0 will be edible but do nothing if you wish to be mean.
  • Context Tags will add additional functionality or compatibility with mods. Some suggestions:
    • color_[color] and other colors are used for dye pots and to color roe. A full list is on [the official wiki].
    • fish_talk_[name] will allow you to use the default fish talks for requests (e.g., fish_talk_carnivorous or allow you to define your own. (More on that below)
    • fish_has_roe is required for 1.6.9+ for roe-producing fish.
    • fish_pond_ignore will prevent a fish from being added to fish ponds (useful if you haven't added fish pond data or don't want it to be pond-able)
    • fish_legendary marks your fish as a legendary one, which will do a few things like change the fish pond color to legendary purple.
    • fish_upright will keep your fish from being rotated 45 degrees when it's drawn in the fish pond.
    • Tags like food_nonvegetarian and allergen_fish can add compatibility with custom NPCs or mods like Allergies.
    • You can also add your own tags to group your items together (e.g., {{ModId}}_fish) so you can write custom interactions for them as a group (e.g., making all your custom NPCs love your items).

Adding fish as fish

Next, let's load some fish-specific data:

		{			
			"Action": "EditData",
			"Target": "Data/Fish",
			"Entries": {
				"tiakall.bass.SeaBass": "Sea Bass/25/mixed/32/45/600 2600/spring summer fall winter/both/690 .4 685 .1/1/.50/.1/0",
				"tiakall.bass.DuskyGrouper": "Dusky Grouper/30/mixed/36/60/600 2600/spring summer fall winter/both/690 .4 685 .1/1/.45/.1/0",
				"tiakall.bass.PinkMaomao": "Pink Maomao/30/mixed/4/8/600 2600/spring summer fall winter/both/690 .4 685 .1/1/.45/.1/0",
				"tiakall.bass.PotatoCod": "Potato Cod/30/mixed/32/80/600 2600/spring summer fall winter/both/690 .4 685 .1/1/.45/.1/0",
				"tiakall.bass.RedbandedPerch": "Redbanded Perch/30/mixed/4/8/600 2600/spring summer fall winter/both/690 .4 685 .1/1/.45/.1/0"
			},
		},

Note: your entry names here need to match the item ID you defined in the item data.

There's a lot going on here! Each of the spaces between /backslashes/ is defining a different part of the fish. So let's break down one of these as an example:

  • Sea Bass: your fish name. Should match the name you defined in the item data (note: not the display name)
  • 25: Chance to dart. The higher (up to 100), the more likely it is and thus, the more difficult it will be to catch. Here, this fish is a little more difficult than a carp (which is 15).
  • mixed: The movement pattern of your fish: you can choose between mixed, smooth, floater, sinker, or dart.
  • 32: Minimum fish size (in inches, will be automatically converted in non-US languages)
  • 45: Maximum fish size (in inches, will be automatically converted in non-US languages)
  • 600 2600: What time your fish shows up - can range from 6AM (600) to 2AM (2600).
  • spring summer fall winter: This field looks like it should pick which seasons your fish shows up in, but it actually does nothing (it's defined when you add fish to locations). Just leave it like this.
  • both: This one is used and determines what weather your fish shows up in: sunny, rainy, or both.
  • 690 .4 685 .1: This is another field that's no longer used (it's related to the location data that's now elsewhere.) You can just copy these values.
  • 1: This is the minimum depth your fish can be caught at; lower numbers are closer to shore/require fewer levels of fishing.
  • .50/.1: These two fields are the spawn multiplier and the depth multiplier. You can see the details of how it's calculated on the wiki, but it's complex so I'd just copy the values of a fish that's about as rare as you want yours to be.
  • 0: First catch tutorial eligible: if it can be caught as your first fish. Generally this should be 0 for no.

Note that if you're making a crabpot fish rather than a fishing pole fish, the fields are fewer and slightly different: you can see them here.

Add fish to locations

Now let's add our fish to the Data/Locations we referenced a bit ago:

		//adds fish to Beach
		{
			"Action": "EditData",
			"Target": "Data/Locations",
			"TargetField": [
				"Beach", //name of the map where you want to spawn the fish
				"Fish" //required
			],
			"Entries": {
				"tiakall.seabass.beach": { //does *not* need to match your item IDs, just needs to be unique (so it's still suggested to use {{ModId}})
					"Chance": 1.0, //chance to pick a fish if this entry is selected; defaults to 1 (guaranteed). 
					"Id": "tiakall.seabass.beach", //should match your entry name
					"ItemId": null, //Normally this would be your item ID, but I've set it to null here to use RandomItemId to add all three fish at once below
					"RandomItemId": [
						"tiakall.bass.SeaBass",
						"tiakall.bass.RedbandedPerch",
						"tiakall.bass.DuskyGrouper",
					],
				}
			}
		},

(Note: You will need a separate patch for each map you want to add fish to.)

This is a bare minimum patch that will add your fish (randomized between three in this case) to a location in all bodies of water in that location, in all seasons. If you want to add more specific fields, you can with the fields that apply to [Data/Locations. Some possible uses:

  • Condition: Uses game state queries to restrict spawning based on the conditions specified. For example, you could use "Condition": "LOCATION_SEASON Here spring" to specify a fish that only shows up in spring, or "Condition": "PLAYER_HAS_MAIL Current landslideDone" to specify that the player must have received the letter about Joja clearing the landslide in front of the mine.
  • CatchLimit: This defaults to -1 for unlimited, but you can set it to 1 for a legendary (or maybe you want it catchable five times - set it to 5!)
  • FishAreaId: Most areas only have one type of fishable location, but for areas with more than one (e.g., IslandWest), you can specify the type of area as defined in the location's data (e.g., for IslandWest, you can have "Freshwater" or "Ocean".
  • IsBossFish: Treats your fish like a legendary (adds the little hat on the fishing bar and gives boosted XP)


Aquarium Data

Aquarium data got so much easier in 1.6. Nowadays, all you need to do is add the sprites and patch Data/Aquariums like below:

			{
			"LogName": "Aquarium data",
			"Action": "EditData",
			"Target": "Data/AquariumFish",
			"Entries": { "tiakall.bass.SeaBass": "0/fish/////Mods\\tiakall.seabass\\AquariumFish",
				"tiakall.bass.DuskyGrouper": "1/fish/////Mods\\tiakall.seabass\\AquariumFish",
				"tiakall.bass.PinkMaomao": "2/fish/////Mods\\tiakall.seabass\\AquariumFish",
				"tiakall.bass.PotatoCod": "3/fish/////Mods\\tiakall.seabass\\AquariumFish",
			"tiakall.bass.RedbandedPerch": "4/fish/////Mods\\tiakall.seabass\\AquariumFish" }
		},


This gif shows how different fish are animated. You can choose between doing a little wiggly tail (sturgeon), animated frames (squid) or a combination of both (stingray).

So what's going on here?

  • 0: The first field is the index of your sprite on the spritesheet you loaded (the Mods\\ part at the end.) If it's the only thing on the sheet, use 0; otherwise, use whichever spot it is on your combined sheet starting with 0. (If you have a custom animation, this is the index where it starts.)
  • fish: What type of movement/where it is it has in the tank. You can choose from:
    • fish (drifts through the middle of the tank, animates its tail movement)
    • eel (drifts through the middle of the tank, combines tail animation with defined custom animation)
    • cephalopod (drifts through the middle of the tank, uses custom animation)
    • crawl (moves back and forth along the bottom of the tank)
    • ground (stationary at the bottom of the tank
    • front crawl (use if you have clipping issues with crawl).
  • The third field, which is blank here, defines custom animations when idle. This will default to your single sprite. If you want to have a custom animation, list out your indexes here (starting with the index your first frame is on, eg. 0 1 2 2 2 1 0)
  • The next three fields after that (also blank here) are for a custom animation when idle. It's broken into beginning frame/middle frames/ending frame similar to an NPC's animation.
  • After that is the location you loaded the aquarium data to with the initial sprite load (the Target).
  • If you want, you can add another slash and X/Y coordinates (e.g., /12 4) to define where you can add a hat on your fish. Because of course you needs hats on your fish :D


Fish Pond Data

Fish pond data is optional; if you don't want to do anything with it, add fish_pond_ignore to your context tags. Otherwise, here's what your next patch will look like:

		{
			"LogName": "Fish Pond Data",
			"Action": "EditData",
			"Target": "Data/FishPondData",
			"Entries": {
				"id_(o)tiakall.bass.SeaBass": { //does not have to match your fish item name, but that does make it easier
					"Id": "id_(o)tiakall.bass.SeaBass",
					"RequiredTags": [
						"id_(o)tiakall.bass.SeaBass" //use your ID in this format to specify your particular fish, or you can use less specific context tags (e.g., if you added <code><nowiki>{{ModId}}_fish</nowiki></code> to all your fish, you can use this to define rules for them all at once.  Note: if there are no rules with tags that match your fish, it will only produce roe.)
					],
					"SpawnTime": 3, //how many days until the population increases
					"ProducedItems": [
						{
							"RequiredPopulation": 10, //can range from 1 to 10, with as many different items as you want to define
							"Chance": 0.4, //chance ranges from 0 to 1 and is independent for each item - for example, there is a 40% chance for this item; if it fails, it goes to the next applicable choice)
							"ItemID": "FLAVORED_ITEM Wine (O)tiakall.bass.SeaBass", //Hey did you know you can make fish-flavored pond items? You're welcome.
							"MinQuantity": 1,
							"MaxQuantity": 1
						},
						{
							"RequiredPopulation": 10,
							"Chance": 1.0, 
							"ItemID": "812", //812 is fish roe, will produce roe for your particular fish
							"MinQuantity": 1,
							"MaxQuantity": 5
						},
					],
					"PopulationGates": { //This sets the quests to unlock more fish.  You can have up to one per level up to 10, or if you don't want fish quests, leave this out.
						"3": [
							"(O)684 5" //The first part is the required item, the second part is the quantity. You need your qualified IDs for these--if you're using a custom item for your fish quests, add <code>(o)</code> to the front of it.
						],
						"5": [
							"(O)136 3", //If there's more than one item listed, the game will randomly pick one.
							"(O)137 3",
						],
						"7": [
							"(O)586"
						],
					},
				},
          }

Other fields you might find useful: MaxPopulation (if you want fewer than 10) and WaterColor (if you want to make your ponds fun colors). More here.

Fish Pond Talk

Did you know you can change what the fish say when a fish quest is activated? By default, you can use the context tags fish_talk_demanding, fish_talk_stiff, fish_talk_rude, and fish_talk_carnivore to use the vanilla alternates - or you can define your own by adding fish_talk_nameofyouruniquetag as a context tag to your fish. You can have up to 3 variants (0, 1 and 2) and gender them with _Male or _Female at the end.

Here's how you would patch in your new lines:

		{
			"Action": "EditData",
			"Target": "Strings/UI",
			"Entries": {
				"PondQuery_StatusRequestPending_bass0": "Can you KELP us out with {1} {0}?", //<nowiki>{1}</nowiki> is the quantity of the item from PopulationGates, while <nowiki>{0}</nowiki> is the display name of the item.
				"PondQuery_StatusRequestPending_bass1": "Want to FISH us up {1} {0}?",
				"PondQuery_StatusRequestPending_bass2": "CURRENTly we're in need of {1} {0}.",
				"PondQuery_StatusRequestComplete_bass0": "You're a sea PLUS plus!",
				"PondQuery_StatusRequestComplete_bass1": "This should TIDE us over!",
				"PondQuery_StatusRequestComplete_bass2": "This SEAms good!",
                     },
        }


And that's all there is to it! Happy fishing!