mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-13 08:03:43 +01:00
Refactors Fish
Cleans up fish code to not be (as) reliant on some ugly associated lists and strings. Tweaks fish breeding: - Breeding now only requires an additional 0.2 food level, instead of the previous 2.0 food level - Fish may refuse to cross-breed with other fish, resulting in dud eggs unless another member of their species is present. Currently, shrimp and eels refuse to breed with other types of fish. - When breeding, fish will attempt to pick a partner and base their success off the pair - If the first parent will not cross-breed, they will successfully lay an egg of their type if at least one other fish of their species is present, otherwise they will always lay a dud - If the first parent will cross-breed but the second parent will not, the egg will always be a dud - If both fish are the same type of cross-breeders, there is a 90% chance of them successfully laying an egg of their type, otherwise the result is a dud egg - If the fish are different types of cross-breeders, there is a 30% chance of them laying a dud egg, otherwise they will lay an egg of the same type as one of the parents Code refactor includes making adding more fish with their own special interactions with the tank (like the catfish and feeder fish interactions) cleaner and hopefully easier. - New "fish" are on the way, hopefully coming soon once sprites are available. - Fish mutating will be added at such time to accomodate the obtaining of new and exciting sea-life. 🆑 tweak: Fish breeding has been tweaked to support fish refusing to cross-breed and improved egg chances with same-species parents. /🆑
This commit is contained in:
@@ -5,81 +5,70 @@
|
||||
icon = 'icons/obj/fish_items.dmi'
|
||||
icon_state = "eggs"
|
||||
w_class = 2
|
||||
var/fish_type = null //Holds the name of the fish that the egg is for
|
||||
var/datum/fish/fish_type = null //Holds the datum of the fish that the egg is for, null means dud eggs
|
||||
|
||||
/obj/item/fish_eggs/New()
|
||||
..()
|
||||
|
||||
var/global/list/fish_eggs_list = list("dud" = /obj/item/fish_eggs,
|
||||
"goldfish" = /obj/item/fish_eggs/goldfish,
|
||||
"clownfish" = /obj/item/fish_eggs/clownfish,
|
||||
"shark" = /obj/item/fish_eggs/shark,
|
||||
"baby space carp" = /obj/item/fish_eggs/babycarp,
|
||||
"catfish" = /obj/item/fish_eggs/catfish,
|
||||
"feederfish" = /obj/item/fish_eggs/feederfish,
|
||||
"salmon" = /obj/item/fish_eggs/salmon,
|
||||
"shrimp" = /obj/item/fish_eggs/shrimp,
|
||||
"electric eel" = /obj/item/fish_eggs/electric_eel,
|
||||
"glofish" = /obj/item/fish_eggs/glofish,
|
||||
)
|
||||
if(fish_type)
|
||||
fish_type = new fish_type
|
||||
|
||||
/obj/item/fish_eggs/goldfish
|
||||
name = "goldfish eggs"
|
||||
desc = "Goldfish eggs, surprisingly, don't contain actual gold."
|
||||
icon_state = "gold_eggs"
|
||||
fish_type = "goldfish"
|
||||
fish_type = /datum/fish/goldfish
|
||||
|
||||
/obj/item/fish_eggs/clownfish
|
||||
name = "clownfish eggs"
|
||||
desc = "Even as eggs, they are funnier than the clown. HONK!"
|
||||
icon_state = "clown_eggs"
|
||||
fish_type = "clownfish"
|
||||
fish_type = /datum/fish/clownfish
|
||||
|
||||
/obj/item/fish_eggs/shark
|
||||
name = "shark eggs"
|
||||
desc = "We're gonna need a- Oh wait, they're still eggs."
|
||||
icon_state = "shark_eggs"
|
||||
fish_type = "shark"
|
||||
fish_type = /datum/fish/shark
|
||||
|
||||
/obj/item/fish_eggs/babycarp
|
||||
name = "baby space carp eggs"
|
||||
desc = "Eggs from the substantially smaller form of the intergalactic terror."
|
||||
icon_state = "babycarp_eggs"
|
||||
fish_type = "baby space carp"
|
||||
fish_type = /datum/fish/babycarp
|
||||
|
||||
/obj/item/fish_eggs/catfish
|
||||
name = "catfish eggs"
|
||||
desc = "A bottom-feeding species noted for their similarity to cats and Tajaran."
|
||||
icon_state = "catfish_eggs"
|
||||
fish_type = "catfish"
|
||||
fish_type = /datum/fish/catfish
|
||||
|
||||
/obj/item/fish_eggs/feederfish
|
||||
name = "feeder fish eggs"
|
||||
desc = "These generic fish are commonly found being eaten by larger fish."
|
||||
icon_state = "feederfish_eggs"
|
||||
fish_type = "feederfish"
|
||||
fish_type = /datum/fish/feederfish
|
||||
|
||||
/obj/item/fish_eggs/salmon
|
||||
name = "salmon eggs"
|
||||
desc = "A collection of salmon eggs."
|
||||
icon_state = "salmon_eggs"
|
||||
fish_type = "salmon"
|
||||
fish_type = /datum/fish/salmon
|
||||
|
||||
/obj/item/fish_eggs/shrimp
|
||||
name = "shrimp eggs"
|
||||
desc = "Eggs for shrimp. You figured they'd be smaller though..."
|
||||
icon_state = "shrimp_eggs"
|
||||
fish_type = "shrimp"
|
||||
fish_type = /datum/fish/shrimp
|
||||
|
||||
/obj/item/fish_eggs/electric_eel
|
||||
name = "electric eel eggs"
|
||||
desc = "A pile of eggs for a slimy, shocking, sea-serpent."
|
||||
icon_state = "electric_eel_eggs"
|
||||
fish_type = "electric eel"
|
||||
fish_type = /datum/fish/electric_eel
|
||||
|
||||
/obj/item/fish_eggs/glofish
|
||||
name = "glofish eggs"
|
||||
desc = "A cluster of bright neon eggs belonging to a bio-luminescent species of fish."
|
||||
icon_state = "glofish_eggs"
|
||||
fish_type = "glofish"
|
||||
fish_type = /datum/fish/glofish
|
||||
|
||||
|
||||
@@ -1,17 +1,4 @@
|
||||
|
||||
var/global/list/fish_items_list = list("goldfish" = /obj/item/weapon/fish/goldfish,
|
||||
"clownfish" = /obj/item/weapon/grown/bananapeel/clownfish,
|
||||
"shark" = /obj/item/weapon/fish/shark,
|
||||
"baby space carp" = /obj/item/weapon/fish/babycarp,
|
||||
"catfish" = /obj/item/weapon/fish/catfish,
|
||||
"feederfish" = /obj/item/weapon/reagent_containers/food/snacks/feederfish,
|
||||
"salmon" = /obj/item/weapon/fish/salmon,
|
||||
"shrimp" = /obj/item/weapon/reagent_containers/food/snacks/shrimp,
|
||||
"electric eel" = /obj/item/weapon/fish/electric_eel,
|
||||
"glofish" = /obj/item/weapon/fish/glofish
|
||||
,
|
||||
)
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Aquarium Supplies //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
|
||||
/datum/fish
|
||||
var/fish_name = "generic fish"
|
||||
var/egg_item = /obj/item/fish_eggs
|
||||
var/fish_item = /obj/item/weapon/fish
|
||||
var/crossbreeder = 1 //determines if the fish will attempt to breed with other types, set to 0 if you want the fish to only lay eggs with its own species
|
||||
|
||||
/datum/fish/proc/special_interact(obj/machinery/fishtank/my_tank)
|
||||
return
|
||||
|
||||
/datum/fish/goldfish
|
||||
fish_name = "goldfish"
|
||||
egg_item = /obj/item/fish_eggs/goldfish
|
||||
fish_item = /obj/item/weapon/fish/goldfish
|
||||
|
||||
/datum/fish/glofish
|
||||
fish_name = "glofish"
|
||||
egg_item = /obj/item/fish_eggs/glofish
|
||||
fish_item = /obj/item/weapon/fish/glofish
|
||||
|
||||
/datum/fish/clownfish
|
||||
fish_name = "clownfish"
|
||||
egg_item = /obj/item/fish_eggs/clownfish
|
||||
fish_item = /obj/item/weapon/grown/bananapeel/clownfish
|
||||
|
||||
/datum/fish/shark
|
||||
fish_name = "shark"
|
||||
egg_item = /obj/item/fish_eggs/shark
|
||||
fish_item = /obj/item/weapon/fish/shark
|
||||
|
||||
/datum/fish/babycarp
|
||||
fish_name = "baby space carp"
|
||||
egg_item = /obj/item/fish_eggs/babycarp
|
||||
fish_item = /obj/item/weapon/fish/babycarp
|
||||
|
||||
/datum/fish/catfish
|
||||
fish_name = "catfish"
|
||||
egg_item = /obj/item/fish_eggs/catfish
|
||||
fish_item = /obj/item/weapon/fish/catfish
|
||||
|
||||
/datum/fish/catfish/special_interact(obj/machinery/fishtank/my_tank)
|
||||
if(!my_tank || !istype(my_tank))
|
||||
return
|
||||
if(my_tank.filth_level > 0 && prob(33))
|
||||
my_tank.filth_level -= 0.1
|
||||
|
||||
/datum/fish/salmon
|
||||
fish_name = "salmon"
|
||||
egg_item = /obj/item/fish_eggs/salmon
|
||||
fish_item = /obj/item/weapon/fish/salmon
|
||||
|
||||
/datum/fish/shrimp
|
||||
fish_name = "shrimp"
|
||||
egg_item = /obj/item/fish_eggs/shrimp
|
||||
fish_item = /obj/item/weapon/reagent_containers/food/snacks/shrimp
|
||||
crossbreeder = 0
|
||||
|
||||
/datum/fish/feederfish
|
||||
fish_name = "feeder fish"
|
||||
egg_item = /obj/item/fish_eggs/feederfish
|
||||
fish_item = /obj/item/weapon/reagent_containers/food/snacks/feederfish
|
||||
|
||||
/datum/fish/feederfish/special_interact(obj/machinery/fishtank/my_tank)
|
||||
if(!my_tank || !istype(my_tank))
|
||||
return
|
||||
if(my_tank.fish_count < 2)
|
||||
return
|
||||
if(my_tank.food_level <= 5 && prob(25))
|
||||
my_tank.food_level += 1
|
||||
my_tank.kill_fish(src)
|
||||
|
||||
/datum/fish/electric_eel
|
||||
fish_name = "electric eel"
|
||||
egg_item = /obj/item/fish_eggs/electric_eel
|
||||
fish_item = /obj/item/weapon/fish/electric_eel
|
||||
crossbreeder = 0
|
||||
@@ -112,7 +112,7 @@
|
||||
if(light_switch)
|
||||
set_light(2,2,"#a0a080")
|
||||
else
|
||||
set_light(0)
|
||||
adjust_light()
|
||||
|
||||
//////////////////////////////
|
||||
// NEW() PROCS //
|
||||
@@ -176,6 +176,7 @@
|
||||
/obj/machinery/fishtank/process()
|
||||
//Start by counting fish in the tank
|
||||
fish_count = 0
|
||||
var/ate_food = 0
|
||||
for(var/fish in fish_list)
|
||||
if(fish)
|
||||
fish_count++
|
||||
@@ -194,15 +195,14 @@
|
||||
|
||||
//Check breeding conditions
|
||||
if(fish_count >=2 && egg_count < max_fish) //Need at least 2 fish to breed, but won't breed if there are as many eggs as max_fish
|
||||
if(food_level > 2 && filth_level <=5) //Breeding is going to use extra food, and the filth_level shouldn't be too high
|
||||
if(food_level >= 0.2 && filth_level <=5) //Breeding is going to use extra food, and the filth_level shouldn't be too high
|
||||
if(prob(((fish_count - 2) * 5)+10)) //Chances increase with each additional fish, 10% base + 5% per additional fish
|
||||
egg_count++ //A new set of eggs were laid, increase egg_count
|
||||
egg_list.Add(select_egg_type()) //Add the new egg to the egg_list for storage
|
||||
food_level -= 2 //Remove extra food for the breeding process
|
||||
breed_fish()
|
||||
food_level -= 0.2 //Remove extra food for the breeding process
|
||||
ate_food = 1
|
||||
|
||||
//Handle standard food and filth adjustments
|
||||
check_food_level()
|
||||
var/ate_food = 0
|
||||
if(food_level > 0 && prob(50)) //Chance for the fish to eat some food
|
||||
if(food_level >= (fish_count * 0.1)) //If there is at least enough food to go around, feed all the fish
|
||||
food_level -= fish_count * 0.1
|
||||
@@ -238,44 +238,35 @@
|
||||
//////////////////////////////
|
||||
|
||||
/obj/machinery/fishtank/proc/handle_special_interactions()
|
||||
var/glo_light = 0
|
||||
for(var/fish in fish_list)
|
||||
switch(fish)
|
||||
if("catfish") //Catfish have a small chance of cleaning some filth since they are a bottom-feeder
|
||||
if((filth_level > 0) && prob(30))
|
||||
filth_level -= 0.1
|
||||
if("feederfish") //Feeder fish have a small chance of sacrificing themselves to produce some food
|
||||
if(fish_count < 2) //Don't sacrifice the last fish, there's nothing to eat it
|
||||
continue
|
||||
if(food_level <= 5 && prob(25))
|
||||
kill_fish("feederfish") //Kill the fish to reflect it's sacrifice, but don't increase the filth_level
|
||||
food_level += 1 //The corpse became food for the other fish, ecology at it's finest
|
||||
if("glofish")
|
||||
glo_light++
|
||||
if(!light_switch && (glo_light > 0))
|
||||
set_light(2,glo_light,"#99FF66")
|
||||
for(var/datum/fish/fish in fish_list)
|
||||
fish.special_interact(src)
|
||||
check_food_level()
|
||||
check_filth_level()
|
||||
check_water_level()
|
||||
adjust_light()
|
||||
|
||||
/obj/machinery/fishtank/proc/adjust_light()
|
||||
if(light_switch) //tank light overrides fish lights
|
||||
return
|
||||
else
|
||||
var/glo_light = 0
|
||||
for(var/datum/fish/fish in fish_list)
|
||||
if(istype(fish, /datum/fish/glofish))
|
||||
glo_light ++
|
||||
if(glo_light)
|
||||
set_light(2, glo_light, "#99FF66")
|
||||
else
|
||||
set_light(0, 0)
|
||||
|
||||
/obj/machinery/fishtank/proc/check_water_level()
|
||||
if(water_level < 0) //Water_level cannot be negative, set it to 0 if it is
|
||||
water_level = 0
|
||||
if(water_level > water_capacity) //Water_level cannot exceed capacity, set it to capacity if it does
|
||||
water_level = water_capacity
|
||||
water_level = min(water_capacity, max(0, water_level))
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/fishtank/proc/check_filth_level()
|
||||
if(filth_level < 0) //Filth_level cannot be negative, set it to 0 if it is
|
||||
filth_level = 0
|
||||
if(filth_level > 10) //Filth_level cannot exceed 10 (cap), set it to 10 if it does
|
||||
filth_level = 10
|
||||
filth_level = min(10, max(0, filth_level))
|
||||
|
||||
/obj/machinery/fishtank/proc/check_food_level()
|
||||
if(food_level < 0) //Food_level cannot be negative, set it to 0 if it is
|
||||
food_level = 0
|
||||
if(food_level > 10) //Food_level cannot exceed 10 (cap), set it to 10 if it does
|
||||
food_level = 10
|
||||
food_level = min(10, max(0, food_level))
|
||||
|
||||
/obj/machinery/fishtank/proc/check_health()
|
||||
//Max value check
|
||||
@@ -292,37 +283,26 @@
|
||||
if(cur_health <= 0) //The tank is broken, destroy it
|
||||
destroy()
|
||||
|
||||
/obj/machinery/fishtank/proc/kill_fish(var/type = null)
|
||||
/obj/machinery/fishtank/proc/kill_fish(datum/fish/fish_type = null)
|
||||
//Check if we were passed a fish to kill, otherwise kill a random one
|
||||
if(type)
|
||||
fish_list.Remove(type) //Kill a fish of the specified type
|
||||
fish_count -- //Lower fish_count to reflect the death of a fish, so the everything else works fine
|
||||
else
|
||||
fish_list.Remove(pick(fish_list)) //Kill a random fish
|
||||
fish_count -- //Lower fish_count to reflect the death of a fish, so the everything else works fine
|
||||
if(!fish_type)
|
||||
fish_type = pick(fish_list)
|
||||
fish_list.Remove(fish_type) //Kill a fish of the specified type
|
||||
fish_count -- //Lower fish_count to reflect the death of a fish, so the everything else works fine
|
||||
if(istype(type, /datum/fish/glofish))
|
||||
adjust_light()
|
||||
|
||||
/obj/machinery/fishtank/proc/add_fish(var/type = null)
|
||||
/obj/machinery/fishtank/proc/add_fish(datum/fish/fish_type = null)
|
||||
//Check if we were passed a fish type
|
||||
if(type)
|
||||
fish_list.Add("[type]") //Add a fish of the specified type
|
||||
if(fish_type)
|
||||
fish_list.Add(fish_type) //Add a fish of the specified type
|
||||
fish_count++ //Increase fish_count to reflect the introduction of a fish, so the everything else works fine
|
||||
//Announce the new fish
|
||||
src.visible_message("A new [type] has hatched in \the [src]!")
|
||||
src.visible_message("A new [fish_type.fish_name] has hatched in \the [src]!")
|
||||
//Null type fish are dud eggs, give a message to inform the player
|
||||
else
|
||||
to_chat(usr, "The eggs disolve in the water. They were duds!")
|
||||
|
||||
/obj/machinery/fishtank/proc/select_egg_type()
|
||||
var/fish = pick(fish_list) //Select a fish from the fish in the tank
|
||||
if(prob(25)) //25% chance to be a dud (blank) egg
|
||||
fish = "dud"
|
||||
var/obj/item/fish_eggs/egg_path = null //Create empty variable to receive the egg_path
|
||||
egg_path = fish_eggs_list[fish] //Locate the corresponding path from fish_eggs_list that matches the fish
|
||||
if(!egg_path) //The fish wasn't located in the fish_eggs_list, potentially due to a typo, so return a dud egg
|
||||
return /obj/item/fish_eggs
|
||||
else //The fish was located in the fish_eggs_list, so return the proper egg
|
||||
return egg_path
|
||||
|
||||
/obj/machinery/fishtank/proc/harvest_eggs(var/mob/user)
|
||||
if(!egg_count) //Can't harvest non-existant eggs
|
||||
return
|
||||
@@ -342,17 +322,17 @@
|
||||
if(!fish_count) //Can't catch non-existant fish!
|
||||
to_chat(usr, "There are no fish in \the [src] to catch!")
|
||||
return
|
||||
|
||||
var/caught_fish
|
||||
caught_fish = input("Select a fish to catch.", "Fishing", caught_fish) in fish_list //Select a fish from the tank
|
||||
var/list/fish_names_list = list()
|
||||
for(var/datum/fish/fish_type in fish_list)
|
||||
fish_names_list += list("[fish_type.fish_name]" = fish_type)
|
||||
var/caught_fish = input("Select a fish to catch.", "Fishing") as null|anything in fish_names_list //Select a fish from the tank
|
||||
if(caught_fish)
|
||||
var/dead_fish = null
|
||||
dead_fish = fish_items_list[caught_fish] //Locate the appropriate fish_item for the caught fish
|
||||
if(!dead_fish) //No fish_item found, possibly due to typo or not being listed. Do nothing.
|
||||
return
|
||||
kill_fish(caught_fish) //Kill the caught fish from the tank
|
||||
user.visible_message("[user.name] harvests \a [caught_fish] from \the [src].", "You scoop \a [caught_fish] out of \the [src].")
|
||||
new dead_fish(get_turf(user)) //Spawn the appropriate fish_item at the user's feet.
|
||||
var/datum/fish/fish_type = fish_names_list[caught_fish]
|
||||
var/fish_item = fish_type.fish_item
|
||||
if(fish_item)
|
||||
new fish_item(get_turf(user)) //Spawn the appropriate fish_item at the user's feet.
|
||||
kill_fish(fish_type) //Kill the caught fish from the tank
|
||||
|
||||
/obj/machinery/fishtank/proc/destroy(var/deconstruct = 0)
|
||||
var/turf/T = get_turf(src) //Store the tank's turf for atmos updating after deletion of tank
|
||||
@@ -392,6 +372,34 @@
|
||||
var/turf/simulated/S = T
|
||||
S.MakeSlippery()
|
||||
|
||||
/obj/machinery/fishtank/proc/breed_fish()
|
||||
var/list/breed_candidates = fish_list.Copy()
|
||||
var/datum/fish/parent1 = pick_n_take(breed_candidates)
|
||||
var/datum/fish/parent2 = null
|
||||
if(!parent1.crossbreeder) //fish with crossbreed = 0 will only breed with their own species, and only leave duds if they can't breed
|
||||
if(parent1 in breed_candidates)
|
||||
egg_list.Add(parent1.egg_item)
|
||||
else
|
||||
egg_list.Add(/obj/item/fish_eggs)
|
||||
else
|
||||
parent2 = pick(breed_candidates)
|
||||
if(!parent2.crossbreeder) //second fish refuses to crossbreed, spawn a dud
|
||||
egg_list.Add(/obj/item/fish_eggs)
|
||||
else if(parent1 == parent2) //both fish are the same type
|
||||
if(prob(90)) //90% chance to get that type of egg
|
||||
egg_list.Add(parent1.egg_item)
|
||||
else //10% chance to get a dud
|
||||
egg_list.Add(/obj/item/fish_eggs)
|
||||
else //different types of fish
|
||||
if(prob(30)) //30% chance to get dud
|
||||
egg_list.Add(/obj/item/fish_eggs)
|
||||
else
|
||||
if(prob(50)) //chance to get egg for either parent type (50/50 for either parent, 35% overall each)
|
||||
egg_list.Add(parent1.egg_item)
|
||||
else
|
||||
egg_list.Add(parent2.egg_item)
|
||||
egg_count++
|
||||
|
||||
////////////////////////////// Note from FalseIncarnate:
|
||||
// EXAMINE PROC // This proc is massive, messy, and probably could be handled better.
|
||||
////////////////////////////// Feel free to try cleaning it up if you think of a better way to do it.
|
||||
@@ -464,9 +472,11 @@
|
||||
var/fish_num = fish_count
|
||||
var/message = "You spot "
|
||||
while(fish_num > 0)
|
||||
var/datum/fish/fish_type = fish_list[fish_num]
|
||||
var/fish_name = fish_type.fish_name
|
||||
if(fish_count > 1 && fish_num == 1) //If there were at least 2 fish, and this is the last one, add "and" to the message
|
||||
message += "and "
|
||||
message += "a [fish_list[fish_num]]"
|
||||
message += "\an [fish_name]"
|
||||
fish_num --
|
||||
if(fish_num > 0) //There's more fish, add a comma to the message
|
||||
message +=", "
|
||||
|
||||
@@ -1325,6 +1325,7 @@
|
||||
#include "code\modules\ext_scripts\python.dm"
|
||||
#include "code\modules\fish\fish_eggs.dm"
|
||||
#include "code\modules\fish\fish_items.dm"
|
||||
#include "code\modules\fish\fish_types.dm"
|
||||
#include "code\modules\fish\fishtank.dm"
|
||||
#include "code\modules\flufftext\Dreaming.dm"
|
||||
#include "code\modules\flufftext\Hallucination.dm"
|
||||
|
||||
Reference in New Issue
Block a user