Files
Bubberstation/code/modules/fishing/fish/fish_evolution.dm
Ghom 940d73aeae replaces the health variable for fishes with integrity (#92192)
## About The Pull Request
Because fish is an item, it inherits the use of integrity from objects,
however it also has its own health variable. For consistency, ~~damaging
its integrity should also lower its health and healing it should also
recover its integrity. Fish has a max integrity that's double its
health.
I've also renamed `adjust_health` to `set_health` since it doesn't
adjust the health by the provided value but sets it to said value.~~
I've scrapped the latter to instead use integrity.

## Why It's Good For The Game
A small bit of consistency. If you shoot a fish with a laser gun,
wouldn't it die?
2025-08-04 22:30:53 -05:00

204 lines
8.6 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, atom/movable/aquarium)
SHOULD_CALL_PARENT(TRUE)
//the fish don't reproduce outside of aquariums but can still grow there, so we just check if the temperature is right.
if(!aquarium)
return source.proper_environment(required_temperature_min, required_temperature_max)
if(SEND_SIGNAL(aquarium, COMSIG_AQUARIUM_CHECK_EVOLUTION_CONDITIONS, source, mate, src) & COMPONENT_ALLOW_EVOLUTION)
return TRUE
return FALSE
///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.get_health_percentage() < 0.5)
return COMPONENT_DONT_GROW
if(source.get_hunger() >= 0.5) //too hungry to grow
return COMPONENT_DONT_GROW
if(HAS_TRAIT(source.loc, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH)) //the aquarium has breeding disabled
return COMPONENT_DONT_GROW
if(!check_conditions(source))
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/temp_reqs = ""
if(required_temperature_min == 0)
temp_reqs = "below [required_temperature_max]"
else if(required_temperature_max == INFINITY)
temp_reqs = "above [required_temperature_min]"
else
temp_reqs = "of [required_temperature_min] to [required_temperature_max]"
. = "An aquarium temperature [temp_reqs]K is required."
if(conditions_note)
. += " [conditions_note]"
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/check_conditions(obj/item/fish/source, obj/item/fish/mate, atom/movable/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/territorial)
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, atom/movable/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/territorial)
conditions_note = "The fish needs to be unusually big and territorial"
/datum/fish_evolution/chainsawfish/check_conditions(obj/item/fish/source, obj/item/fish/mate, atom/movable/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/territorial 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, atom/movable/aquarium)
if(HAS_TRAIT(source, TRAIT_FISH_STINGER))
return ..()
return FALSE
/datum/fish_evolution/fritterish
new_fish_type = /obj/item/fish/fryish/fritterish
removed_traits = list(/datum/fish_trait/no_mating)
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, atom/movable/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
/datum/fish_evolution/moonfish
probability = 200 //guaranteed if the conditions are met
new_fish_type = /obj/item/fish/moonfish
conditions_note = "Requires the dwarf moonfish to be big enough."
/datum/fish_evolution/moonfish/check_conditions(obj/item/fish/source, obj/item/fish/mate, obj/structure/aquarium/aquarium)
if(source.size < (/obj/item/fish/moonfish/dwarf::average_size * 1.5) && source.size < (/obj/item/fish/moonfish/dwarf::average_weight * 1.5))
return FALSE
if(mate && (mate.size < (/obj/item/fish/moonfish::average_size * 1.3) && mate.size < (/obj/item/fish/moonfish::average_weight * 1.3)))
return FALSE
return ..()
/datum/fish_evolution/dwarf_moonfish
probability = 200 //guaranteed if the conditions are met
new_fish_type = /obj/item/fish/moonfish/dwarf
conditions_note = "Requires the moonfish to be small enough."
/datum/fish_evolution/dwarf_moonfish/check_conditions(obj/item/fish/source, obj/item/fish/mate, obj/structure/aquarium/aquarium)
if(source.size > (/obj/item/fish/moonfish::average_size * 0.66) && source.size > (/obj/item/fish/moonfish::average_weight * 0.66))
return FALSE
if(mate && (mate.size > (/obj/item/fish/moonfish::average_size * 0.7) && mate.size > (/obj/item/fish/moonfish::average_weight * 0.7)))
return FALSE
return ..()
/datum/fish_evolution/lavaloop
probability = 85
new_fish_type = /obj/item/fish/lavaloop
required_temperature_min = MIN_AQUARIUM_TEMP + 60
/datum/fish_evolution/plasmaloop
probability = 85
new_fish_type = /obj/item/fish/lavaloop/plasma_river
required_temperature_max = MIN_AQUARIUM_TEMP + 60