Files
Bubberstation/code/modules/fishing/fish/fish_evolution.dm
Ghom ff2760e908 Adds new tasty fish to deep fryers. (#86690)
## About The Pull Request
This PR introduces three new fish that can be caught from deep fryers.
That's right, deep fryers are also fishing spots now. Is it silly? Yeah,
but this is more or less the reason I made a whole PR to make fish
edible. They've two gimmicks: one is that they're already fried, and
neither raw nor gorey and can be cut into nuggets. The other is that
they can evolve into the next type just by growing, no need of pairing
them with each other, starting from the 'fryish', then the 'fritterish'
(and its two variants: 'bernard-fish' and 'matthew-fish', big pun on the
english food company) and finally the 'nessie-fish' which is very rare
and big and you'd probably get 20 nuggets by cutting it alone.

Other than that, this PR adds a simple growth mechanic to fish, where
they get a bit larger each time they're fed. The gained size and weight
depends on several factors like hunger, their current size and weight
and how much until they hit the maximum cap of twice the initial size
and weight. This means bigger fish grow slowier, and it's better to feed
them once in a while but not every other second. Obviously size and
weight influence a lot of fish mechanics, so it's good to have a way to
increase these values outside of breeding RNG (which is very shallow).
TL;DR: Feed the fish once their hunger reaches 50% circa for maximum
growth.

Included in the PR are a few tidbits, like fixing a little mistake
around the 'picky eater' fish trait, more readable code around the
fish_growth component (unrelated to the aforementioned growth mechanic)
and hunger or adding the fish evolution datum for armored pikes (normal
pikes plus stinger trait, which I basically forgot to), and adjusting
how weight and size of offsprings is calculated.

## Why It's Good For The Game
First and foremost, a brand new on-station fishing spot that is not the
fishing portal, toilets (or the rare moisture traps in maint). Second, a
fish growth mechanic through which weight and size can be increased.
Third, a few code things. Four, little bugs, now fixed.

Fifth, have a screenshot of me fucking around to find out how many bites
it takes to eat all of the deepfried gargantuan nessie (53, and I had to
spawn another 10 humans to finish it):

![immagine](https://github.com/user-attachments/assets/a7054cac-6f94-4327-891e-f171894a71d6)


## Changelog

🆑
add: You can now fish new, tasty treats by the station deep fryers.
add: You can now grow fish inside an aquarium by feeding them regularly
(at 50% hunger for maximum growth).
add: Added the evolution for pikes to armored pikes.
/🆑
2024-09-22 18:43:27 +00:00

182 lines
7.8 KiB
Plaintext

///A global list of fish evolutions, which are singletons.
GLOBAL_LIST_INIT(fish_evolutions, init_subtypes_w_path_keys(/datum/fish_evolution, list()))
///A list of fish evolution types, each having an associated list containing all fish types that have it.
GLOBAL_LIST_EMPTY(fishes_by_fish_evolution)
/**
* Fish evolution datums
*
* If present in a fish's evolution_types list, and other conditions are met in check_conditions()
* then there's a chance the offspring may be of a new type rather than the same as its source or mate (if any).
*/
/datum/fish_evolution
///The name of the evolution. If not set, it'll be generated on runtime from the name of the new fish type.
var/name
///The probability that this evolution can happen.
var/probability = 0
///The obj/item/fish path of the new fish
var/obj/item/fish/new_fish_type = /obj/item/fish
///The minimum required temperature for the evolved fish to spawn
var/required_temperature_min = 0
///The maximum required temperature for the evolved fish to spawn
var/required_temperature_max = INFINITY
///A list of traits added to the new fish. These take priority over the parents' traits.
var/list/new_traits
///If set, these traits will be removed from the new fish.
var/list/removed_traits
///A text string shown in the catalog, containing information on conditions specific to this evolution.
var/conditions_note
///Is this evolution shown on the wiki?
var/show_on_wiki = TRUE
///Is the result of this evolution shown on the wiki?
var/show_result_on_wiki = TRUE
/datum/fish_evolution/New()
..()
SHOULD_CALL_PARENT(TRUE)
if(!ispath(new_fish_type, /obj/item/fish))
stack_trace("[type] instantiated with a new fish type of [new_fish_type]. That's not a fish, hun, things will break.")
if(!name)
name = full_capitalize(initial(new_fish_type.name))
/**
* The main proc that checks whether this can happen or not.
* Keep in mind the mate and aquarium arguments may be null if
* the fish is self-reproducing or this evolution is a result of a fish_growth component
*/
/datum/fish_evolution/proc/check_conditions(obj/item/fish/source, obj/item/fish/mate, obj/structure/aquarium/aquarium)
SHOULD_CALL_PARENT(TRUE)
if(aquarium)
//chances are halved if only one parent has this evolution.
var/real_probability = (mate && (type in mate.evolution_types)) ? probability : probability/2
if(!prob(real_probability))
return FALSE
if(!ISINRANGE(aquarium.fluid_temp, required_temperature_min, required_temperature_max))
return FALSE
else if(!source.proper_environment(required_temperature_min, required_temperature_max))
return FALSE
return TRUE
///This is called when the evolution is set as the result type of a fish_growth component
/datum/fish_evolution/proc/growth_checks(obj/item/fish/source, seconds_per_tick, growth)
SIGNAL_HANDLER
SHOULD_CALL_PARENT(TRUE)
if(source.health < initial(source.health) * 0.5)
return COMPONENT_DONT_GROW
if(source.get_hunger() >= 0.5) //too hungry to grow
return COMPONENT_DONT_GROW
var/obj/structure/aquarium/aquarium = source.loc
if(istype(aquarium) && !aquarium.reproduction_and_growth) //the aquarium has breeding disabled
return COMPONENT_DONT_GROW
else
aquarium = null
if(!check_conditions(source, aquarium = aquarium))
return COMPONENT_DONT_GROW
///Called by the fish analyzer right click function. Returns a text string used as tooltip.
/datum/fish_evolution/proc/get_evolution_tooltip()
. = ""
if(required_temperature_min > 0 || required_temperature_max < INFINITY)
var/max_temp = required_temperature_max < INFINITY ? " and [required_temperature_max]" : ""
. = "An aquarium temperature between [required_temperature_min][max_temp] is required."
if(conditions_note)
. += " [conditions_note]"
return .
///Proc called to let evolution register signals that are needed for various conditions.
/datum/fish_evolution/proc/register_fish(obj/item/fish/fish)
return
/datum/fish_evolution/lubefish
probability = 25
new_fish_type = /obj/item/fish/clownfish/lube
new_traits = list(/datum/fish_trait/lubed)
conditions_note = "The fish must be fed lube beforehand."
/datum/fish_evolution/lubefish/register_fish(obj/item/fish/fish)
RegisterSignal(fish, COMSIG_FISH_FED, PROC_REF(check_for_lube))
/datum/fish_evolution/lubefish/proc/check_for_lube(obj/item/fish/source, datum/reagents/fed_reagents, wrong_reagent_type)
SIGNAL_HANDLER
if((wrong_reagent_type == /datum/reagent/lube) || fed_reagents.remove_reagent(/datum/reagent/lube, 0.1))
ADD_TRAIT(source, TRAIT_FISH_FED_LUBE, FISH_EVOLUTION)
addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_FISH_FED_LUBE, FISH_EVOLUTION), source.feeding_frequency)
/datum/fish_evolution/lubefish/check_conditions(obj/item/fish/source, obj/item/fish/mate, obj/structure/aquarium/aquarium)
if(!HAS_TRAIT(source, TRAIT_FISH_FED_LUBE))
return FALSE
return ..()
/datum/fish_evolution/purple_sludgefish
probability = 5
new_fish_type = /obj/item/fish/sludgefish/purple
new_traits = list(/datum/fish_trait/recessive)
removed_traits = list(/datum/fish_trait/no_mating)
/datum/fish_evolution/mastodon
name = "???" //The resulting fish is not shown on the catalog.
probability = 40
new_fish_type = /obj/item/fish/mastodon
new_traits = list(/datum/fish_trait/heavy, /datum/fish_trait/amphibious, /datum/fish_trait/predator, /datum/fish_trait/aggressive)
conditions_note = "The fish (and its mate) needs to be unusually big both in size and weight."
show_result_on_wiki = FALSE
/datum/fish_evolution/mastodon/check_conditions(obj/item/fish/source, obj/item/fish/mate, obj/structure/aquarium/aquarium)
if((source.size < 120 || source.weight < 3000) || (mate && (mate.size < 120 || mate.weight < 3000)))
return FALSE
return ..()
/datum/fish_evolution/chasm_chrab
probability = 50
new_fish_type = /obj/item/fish/chasm_crab
required_temperature_min = MIN_AQUARIUM_TEMP+14
required_temperature_max = MIN_AQUARIUM_TEMP+15
/datum/fish_evolution/ice_chrab
probability = 50
new_fish_type = /obj/item/fish/chasm_crab/ice
required_temperature_min = MIN_AQUARIUM_TEMP+9
required_temperature_max = MIN_AQUARIUM_TEMP+10
/datum/fish_evolution/three_eyes
probability = 3
new_fish_type = /obj/item/fish/goldfish/three_eyes
new_traits = list(/datum/fish_trait/recessive)
/datum/fish_evolution/chainsawfish
probability = 30
new_fish_type = /obj/item/fish/chainsawfish
new_traits = list(/datum/fish_trait/predator, /datum/fish_trait/aggressive)
conditions_note = "The fish needs to be unusually big and aggressive"
/datum/fish_evolution/chainsawfish/check_conditions(obj/item/fish/source, obj/item/fish/mate, obj/structure/aquarium/aquarium)
var/double_avg_size = /obj/item/fish/goldfish::average_size * 2
var/double_avg_weight = /obj/item/fish/goldfish::average_weight * 2
if(source.size >= double_avg_size && source.weight >= double_avg_weight && (/datum/fish_trait/aggressive in source.fish_traits))
return ..()
return FALSE
/datum/fish_evolution/armored_pike
probability = 75
new_fish_type = /obj/item/fish/pike/armored
conditions_note = "The fish needs to have the stinger trait"
/datum/fish_evolution/armored_pike/check_conditions(obj/item/fish/source, obj/item/fish/mate, obj/structure/aquarium/aquarium)
if(HAS_TRAIT(source, TRAIT_FISH_STINGER))
return ..()
return FALSE
/datum/fish_evolution/fritterish
new_fish_type = /obj/item/fish/fryish/fritterish
conditions_note = "Fryish will grow into it over time."
/datum/fish_evolution/nessie
name = "???"
new_fish_type = /obj/item/fish/fryish/nessie
conditions_note = "The final stage of fritterfish growth. It gotta be big!"
show_result_on_wiki = FALSE
/datum/fish_evolution/nessiefish/check_conditions(obj/item/fish/source, obj/item/fish/mate, obj/structure/aquarium/aquarium)
if(source.size >= (/obj/item/fish/fryish/fritterish::average_size * 1.5) && source.size >= (/obj/item/fish/fryish/fritterish::average_weight * 1.5))
return ..()
return FALSE