From 36ca9a8559a1eafc8572641461008859c40beeaf Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Wed, 31 Jul 2024 16:18:23 +0200 Subject: [PATCH] Raising lobstrosities from chrabs is now a component. Adds in tadpoles which become frogs. (#85346) ## About The Pull Request I've componentized part of the code that manages raising lobstrosities from chrabs so that it can be added to other fish too. As proof of concept, I've added tadpoles. Tadpoles are not fished like the rest, instead you merely right-click a puddle and after 5 seconds you'll get one. Tadpoles are fairly fragile, cannot be butchered, don't reproduce, require lukewarm freshwater, need to be feed frequently, and become frogs after about 3 minutes. ## Why It's Good For The Game A small needed refactor for the chrab code, plus another small fish to make it easier to complete the first fish scanning experiment. ## Changelog :cl: add: Added tadpoles, which can be scooped from puddles with right-click. Functionally they're like most fish, which require an aquarium to survive, and also need to be fed fairly frequently, however they quickly become frogs after about 3 minutes of care. add: Every station now has a couple puddles. One at the public garden and the other in prison. qol: Changed the name of an aquarium UI button from "Reproduction Prevention" to "Reproduction and Growth", as it controls both fish breeding and growth. /:cl: --- _maps/map_files/Birdshot/birdshot.dmm | 19 ++- .../map_files/Deltastation/DeltaStation2.dmm | 64 ++++----- .../map_files/IceBoxStation/IceBoxStation.dmm | 25 ++-- _maps/map_files/MetaStation/MetaStation.dmm | 32 +++-- _maps/map_files/NorthStar/north_star.dmm | 35 +++-- _maps/map_files/tramstation/tramstation.dmm | 14 +- _maps/map_files/wawastation/wawastation.dmm | 7 +- code/__DEFINES/dcs/signals/signals_fish.dm | 6 + code/datums/components/fish_growth.dm | 57 +++++++++ .../water_structures/water_source.dm | 26 ++++ code/modules/cargo/exports/fish.dm | 6 +- code/modules/fishing/fish/_fish.dm | 8 ++ code/modules/fishing/fish/fish_types.dm | 121 +++++++++++------- code/modules/mob/living/basic/basic.dm | 6 + code/modules/unit_tests/fish_unit_tests.dm | 7 +- icons/obj/aquarium/fish.dmi | Bin 32063 -> 32486 bytes tgstation.dme | 1 + tgui/packages/tgui/interfaces/Aquarium.tsx | 6 +- 18 files changed, 297 insertions(+), 143 deletions(-) create mode 100644 code/datums/components/fish_growth.dm diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index 9de921e10fe..840a759cea7 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -20161,8 +20161,8 @@ }, /area/station/science/lobby) "hqH" = ( -/obj/structure/reagent_dispensers/watertank, /obj/item/reagent_containers/cup/watering_can/wood, +/obj/structure/table, /turf/open/floor/plating, /area/station/maintenance/starboard/greater) "hqM" = ( @@ -32189,6 +32189,10 @@ /obj/item/camera, /turf/open/floor/iron, /area/station/security/prison/workout) +"lhd" = ( +/obj/structure/water_source/puddle, +/turf/open/floor/grass, +/area/station/security/prison/garden) "lhi" = ( /obj/machinery/airalarm/directional/north, /obj/machinery/button/door/directional/north{ @@ -33927,7 +33931,6 @@ "lGO" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/sink/directional/west, /turf/open/floor/iron, /area/station/security/prison/garden) "lGT" = ( @@ -54428,6 +54431,10 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/grimy, /area/station/commons/vacant_room/office) +"sJf" = ( +/obj/structure/water_source/puddle, +/turf/open/misc/asteroid, +/area/station/maintenance/starboard/greater) "sJg" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/general/hidden, /obj/machinery/door/airlock/command{ @@ -86198,7 +86205,7 @@ xjz xjz xjz xjz -dDB +xjz dDB blb blb @@ -86454,7 +86461,7 @@ hJC aHJ wmy tBm -xjz +tBm xjz blb blb @@ -86711,7 +86718,7 @@ aWt sis sis sis -tBm +lhd xjz blb dDB @@ -129058,7 +129065,7 @@ ylD hqH vzv brz -cgM +sJf ylD wyj dYR diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 07982e7dabc..8959abab558 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -10390,14 +10390,12 @@ /area/station/command/corporate_showroom) "czg" = ( /obj/machinery/hydroponics/soil, -/obj/effect/decal/cleanable/dirt, /obj/item/plant_analyzer, /obj/machinery/camera/directional/east{ c_tag = "Permabrig - Garden"; network = list("ss13","prison") }, -/obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/plating, +/turf/open/misc/sandy_dirt, /area/station/security/prison/garden) "czi" = ( /obj/effect/decal/cleanable/dirt, @@ -19613,10 +19611,8 @@ /area/station/engineering/atmos) "eQx" = ( /obj/machinery/hydroponics/soil, -/obj/effect/decal/cleanable/dirt, /obj/item/shovel/spade, -/obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/plating, +/turf/open/misc/sandy_dirt, /area/station/security/prison/garden) "eQB" = ( /obj/machinery/door/airlock/public/glass{ @@ -27561,10 +27557,8 @@ "gLT" = ( /obj/machinery/hydroponics/soil, /obj/item/cultivator, -/obj/effect/decal/cleanable/dirt, /obj/structure/sign/warning/electric_shock/directional/west, -/obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/plating, +/turf/open/misc/sandy_dirt, /area/station/security/prison/garden) "gMd" = ( /obj/structure/window/reinforced/spawner/directional/west, @@ -30877,23 +30871,10 @@ /turf/open/floor/iron, /area/station/commons/vacant_room/commissary) "hHi" = ( -/obj/structure/closet/crate/hydroponics, -/obj/item/paper/guides/jobs/hydroponics, -/obj/item/seeds/onion, -/obj/item/seeds/garlic, -/obj/item/seeds/potato, -/obj/item/seeds/tomato, -/obj/item/seeds/carrot, -/obj/item/seeds/grass, -/obj/item/seeds/ambrosia, -/obj/item/seeds/wheat, -/obj/item/seeds/pumpkin, -/obj/effect/spawner/random/contraband/prison, /obj/structure/window/spawner/directional/south, -/obj/effect/decal/cleanable/dirt, -/obj/item/seeds/tower, /obj/structure/sign/poster/official/random/directional/north, -/turf/open/floor/iron, +/obj/structure/water_source/puddle, +/turf/open/misc/sandy_dirt, /area/station/security/prison/garden) "hHo" = ( /obj/structure/disposalpipe/trunk, @@ -59532,13 +59513,23 @@ /area/station/service/chapel) "oWp" = ( /obj/structure/window/spawner/directional/south, -/obj/structure/sink/directional/south, -/obj/structure/reagent_dispensers/watertank, -/obj/item/reagent_containers/cup/watering_can, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/cobweb, /obj/structure/cable, /obj/machinery/power/apc/auto_name/directional/west, +/obj/structure/closet/crate/hydroponics, +/obj/item/seeds/tower, +/obj/effect/spawner/random/contraband/prison, +/obj/item/seeds/pumpkin, +/obj/item/seeds/wheat, +/obj/item/seeds/ambrosia, +/obj/item/seeds/grass, +/obj/item/seeds/carrot, +/obj/item/seeds/tomato, +/obj/item/seeds/potato, +/obj/item/seeds/garlic, +/obj/item/seeds/onion, +/obj/item/paper/guides/jobs/hydroponics, /turf/open/floor/iron, /area/station/security/prison/garden) "oWt" = ( @@ -78609,11 +78600,9 @@ /area/station/command/corporate_showroom) "tGW" = ( /obj/machinery/hydroponics/soil, -/obj/effect/decal/cleanable/dirt, /obj/item/radio/intercom/directional/east, -/obj/effect/mapping_helpers/burnt_floor, /obj/machinery/light/small/directional/east, -/turf/open/floor/plating, +/turf/open/misc/sandy_dirt, /area/station/security/prison/garden) "tHc" = ( /obj/structure/table/wood/fancy, @@ -79874,10 +79863,8 @@ dir = 1 }, /obj/machinery/firealarm/directional/west, -/obj/effect/turf_decal/tile/green{ - dir = 8 - }, -/turf/open/floor/iron, +/obj/structure/water_source/puddle, +/turf/open/misc/sandy_dirt, /area/station/service/hydroponics/garden) "tXe" = ( /obj/effect/turf_decal/loading_area/red{ @@ -84678,6 +84665,7 @@ /obj/machinery/hydroponics/constructable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/tile/green, +/obj/item/reagent_containers/cup/watering_can, /turf/open/floor/iron, /area/station/security/prison/garden) "veD" = ( @@ -90301,10 +90289,8 @@ "wAt" = ( /obj/machinery/hydroponics/soil, /obj/item/cultivator, -/obj/effect/decal/cleanable/dirt, /obj/machinery/airalarm/directional/east, -/obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/plating, +/turf/open/misc/sandy_dirt, /area/station/security/prison/garden) "wAz" = ( /obj/structure/table/wood, @@ -91828,11 +91814,9 @@ /area/space) "wVy" = ( /obj/machinery/hydroponics/soil, -/obj/effect/decal/cleanable/dirt, /obj/machinery/light/small/directional/west, -/obj/effect/mapping_helpers/burnt_floor, /obj/structure/sign/poster/contraband/ambrosia_vulgaris/directional/west, -/turf/open/floor/plating, +/turf/open/misc/sandy_dirt, /area/station/security/prison/garden) "wVJ" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 3737277c465..71b333277b0 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -9036,6 +9036,9 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted{ dir = 4 }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, /turf/open/floor/iron, /area/station/service/hydroponics/garden) "cBG" = ( @@ -43794,6 +43797,7 @@ /obj/structure/cable, /obj/machinery/power/apc/auto_name/directional/south, /obj/item/radio/intercom/directional/west, +/obj/structure/reagent_dispensers/watertank, /turf/open/floor/iron, /area/station/service/hydroponics/garden) "nhT" = ( @@ -49552,6 +49556,10 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood, /area/station/maintenance/aft/lesser) +"oNW" = ( +/obj/structure/water_source/puddle, +/turf/open/floor/grass, +/area/station/security/prison/garden) "oNX" = ( /obj/machinery/airalarm/directional/west, /turf/open/floor/iron/dark, @@ -52423,6 +52431,9 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, /turf/open/floor/iron/dark, /area/station/service/hydroponics/garden) "pGJ" = ( @@ -54284,10 +54295,10 @@ /turf/open/floor/iron, /area/station/command/heads_quarters/qm) "qiT" = ( -/obj/structure/reagent_dispensers/watertank, /obj/effect/turf_decal/tile/green/anticorner/contrasted{ dir = 4 }, +/obj/item/kirbyplants/random, /turf/open/floor/iron/dark, /area/station/service/hydroponics/garden) "qjb" = ( @@ -73913,7 +73924,6 @@ /turf/open/floor/iron/large, /area/station/command/heads_quarters/ce) "wcz" = ( -/obj/structure/sink/directional/south, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/effect/turf_decal/tile/green/half/contrasted{ dir = 1 @@ -77700,15 +77710,12 @@ /turf/open/floor/carpet/blue, /area/station/hallway/secondary/entry) "xhg" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, /obj/machinery/camera/directional/east{ c_tag = "Garden" }, -/obj/item/kirbyplants/random, /obj/machinery/status_display/ai/directional/east, -/turf/open/floor/iron/dark, +/obj/structure/water_source/puddle, +/turf/open/floor/grass, /area/station/service/hydroponics/garden) "xhk" = ( /turf/open/floor/iron/dark, @@ -167765,7 +167772,7 @@ jlF jNf dpC cGQ -whr +oNW nmr hVY gjq @@ -168280,7 +168287,7 @@ jNf qIo tau dWK -ozX +whr hVY gjq gjq diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index efec99c47fc..a719ae4c671 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -15537,13 +15537,10 @@ /turf/open/floor/plating/airless, /area/station/solars/port/fore) "fzr" = ( -/obj/structure/table, -/obj/effect/turf_decal/stripes/line, -/obj/effect/spawner/random/food_or_drink/seed{ - spawn_all_loot = 1; - spawn_random_offset = 1 - }, -/turf/open/floor/iron, +/obj/structure/window/spawner/directional/south, +/obj/structure/window/spawner/directional/west, +/obj/structure/water_source/puddle, +/turf/open/floor/grass, /area/station/service/hydroponics/garden) "fzE" = ( /obj/structure/sign/warning/vacuum/external/directional/north, @@ -38988,6 +38985,7 @@ /obj/effect/turf_decal/trimline/green/filled/line{ dir = 9 }, +/obj/structure/cable, /turf/open/floor/iron, /area/station/security/prison/garden) "nNw" = ( @@ -39526,6 +39524,10 @@ /obj/structure/table, /obj/structure/extinguisher_cabinet/directional/west, /obj/effect/turf_decal/stripes/line, +/obj/effect/spawner/random/food_or_drink/seed{ + spawn_all_loot = 1; + spawn_random_offset = 1 + }, /turf/open/floor/iron, /area/station/service/hydroponics/garden) "nYU" = ( @@ -40407,7 +40409,6 @@ /obj/machinery/hydroponics/soil, /obj/item/cultivator, /obj/effect/decal/cleanable/dirt, -/obj/structure/cable, /turf/open/floor/grass, /area/station/security/prison/garden) "opG" = ( @@ -50757,8 +50758,6 @@ /turf/open/floor/iron/white, /area/station/medical/virology) "rVb" = ( -/obj/structure/sink/directional/west, -/obj/item/reagent_containers/cup/watering_can, /obj/effect/turf_decal/trimline/green/filled/line{ dir = 4 }, @@ -51191,7 +51190,6 @@ "sbX" = ( /obj/machinery/hydroponics/soil, /obj/effect/decal/cleanable/dirt, -/obj/structure/cable, /obj/item/plant_analyzer, /turf/open/floor/grass, /area/station/security/prison/garden) @@ -55372,6 +55370,7 @@ /obj/effect/turf_decal/trimline/green/filled/line{ dir = 8 }, +/obj/structure/cable, /turf/open/floor/iron, /area/station/security/prison/garden) "tCF" = ( @@ -63868,6 +63867,12 @@ /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/iron, /area/station/science/robotics/mechbay) +"wsG" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/water_source/puddle, +/obj/item/reagent_containers/cup/watering_can, +/turf/open/floor/grass, +/area/station/security/prison/garden) "wsI" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -65136,7 +65141,6 @@ /turf/open/floor/iron/white, /area/station/science/robotics/lab) "wRF" = ( -/obj/structure/window/spawner/directional/west, /obj/structure/flora/rock/pile, /turf/open/floor/grass, /area/station/service/hydroponics/garden) @@ -87401,7 +87405,7 @@ aaa lMJ aaa aaa -aaa +cmB cmB cmB cmB @@ -87659,7 +87663,7 @@ lMJ aaa aaa cmB -cmB +wsG opF sbX jTi diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index 4e9080ef499..b4168c7d54d 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -18356,6 +18356,18 @@ /obj/machinery/duct, /turf/open/floor/iron/dark, /area/station/hallway/floor3/fore) +"eJy" = ( +/obj/effect/turf_decal/weather/dirt{ + dir = 8 + }, +/obj/effect/turf_decal/tile/dark_blue, +/obj/effect/turf_decal/weather/dirt{ + dir = 1 + }, +/turf/open/floor/iron/dark/side{ + dir = 8 + }, +/area/station/security/prison/garden) "eJF" = ( /obj/machinery/airalarm/directional/south, /obj/item/kirbyplants/random, @@ -54107,7 +54119,9 @@ /area/station/maintenance/floor1/starboard) "nSz" = ( /obj/effect/decal/cleanable/dirt, -/obj/structure/sink/kitchen/directional/south, +/obj/effect/turf_decal/weather/dirt{ + dir = 8 + }, /turf/open/floor/iron/dark/side{ dir = 5 }, @@ -59391,6 +59405,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/pod/light, /area/station/maintenance/floor1/starboard/aft) +"ppf" = ( +/obj/effect/turf_decal/weather/sand/light, +/turf/closed/wall/r_wall, +/area/station/security/execution/education) "ppi" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/table, @@ -64263,15 +64281,9 @@ /turf/open/floor/iron/dark, /area/station/command/teleporter) "qzQ" = ( -/obj/effect/turf_decal/weather/dirt{ - dir = 8 - }, -/obj/item/reagent_containers/cup/watering_can, -/obj/effect/turf_decal/tile/dark_blue, /obj/machinery/newscaster/directional/north, -/turf/open/floor/iron/dark/side{ - dir = 9 - }, +/obj/structure/water_source/puddle, +/turf/open/misc/dirt/jungle, /area/station/security/prison/garden) "qzX" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper, @@ -68264,6 +68276,7 @@ /obj/effect/mapping_helpers/broken_floor, /obj/effect/turf_decal/tile/dark_blue/opposingcorners, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/item/reagent_containers/cup/watering_can, /turf/open/floor/iron/dark/corner{ dir = 4 }, @@ -329837,7 +329850,7 @@ oyh oyh oyh fkA -fkA +ppf wmD fkA kUZ @@ -331381,7 +331394,7 @@ oyh wMF wMF qzQ -pfL +eJy pfL pfL yfr diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index b4d767bd2dd..469e5ec80fb 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -8387,6 +8387,10 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron, /area/station/engineering/atmos) +"bRl" = ( +/obj/structure/water_source/puddle, +/turf/open/misc/asteroid, +/area/station/security/prison/workout) "bRE" = ( /obj/structure/lattice/catwalk, /turf/open/floor/plating/airless, @@ -10804,14 +10808,13 @@ /turf/open/floor/iron, /area/station/security/brig) "cGm" = ( -/obj/effect/turf_decal/bot, -/obj/structure/reagent_dispensers/watertank, /obj/machinery/airalarm/directional/east, /obj/effect/turf_decal/trimline/neutral/line, /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 4 }, -/turf/open/floor/iron, +/obj/structure/water_source/puddle, +/turf/open/floor/grass, /area/station/service/hydroponics/garden) "cGy" = ( /obj/structure/chair/stool/directional/north, @@ -46719,7 +46722,6 @@ /area/station/hallway/secondary/exit) "pzw" = ( /obj/effect/turf_decal/bot, -/obj/structure/reagent_dispensers/watertank, /obj/machinery/power/apc/auto_name/directional/east, /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 4 @@ -47444,10 +47446,10 @@ /turf/open/floor/iron/white, /area/station/science/lower) "pMz" = ( -/obj/structure/table/glass, /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 5 }, +/obj/structure/reagent_dispensers/watertank, /turf/open/floor/iron, /area/station/service/hydroponics/garden) "pMG" = ( @@ -88126,7 +88128,7 @@ abM aal lPV kPC -lFk +bRl lFk lFk mAB diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm index 5673421142a..0c4222ee5e7 100644 --- a/_maps/map_files/wawastation/wawastation.dmm +++ b/_maps/map_files/wawastation/wawastation.dmm @@ -17276,6 +17276,7 @@ /area/station/science/research) "ggl" = ( /obj/machinery/camera/autoname/directional/west, +/obj/structure/water_source/puddle, /turf/open/floor/grass, /area/station/service/hydroponics/garden) "ggu" = ( @@ -39047,6 +39048,10 @@ /obj/effect/turf_decal/tile/dark_blue, /turf/open/floor/iron, /area/station/command/bridge) +"nPw" = ( +/obj/structure/water_source/puddle, +/turf/open/floor/grass, +/area/station/security/prison/garden) "nPM" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 4 @@ -82449,7 +82454,7 @@ iUF dUc xrb xrb -dEG +nPw dEG iqf cKn diff --git a/code/__DEFINES/dcs/signals/signals_fish.dm b/code/__DEFINES/dcs/signals/signals_fish.dm index 8f7483d9416..2fbf99446ab 100644 --- a/code/__DEFINES/dcs/signals/signals_fish.dm +++ b/code/__DEFINES/dcs/signals/signals_fish.dm @@ -46,3 +46,9 @@ /// From /obj/item/fish_analyzer/proc/analyze_status: (fish, user) #define COMSIG_FISH_ANALYZER_ANALYZE_STATUS "fish_analyzer_analyze_status" + +/// From /datum/component/fish_growth/on_fish_life: (seconds_per_tick) +#define COMSIG_FISH_BEFORE_GROWING "fish_before_growing" + #define COMPONENT_DONT_GROW (1 << 0) +/// From /datum/component/fish_growth/finish_growing: (result) +#define COMSIG_FISH_FINISH_GROWING "fish_finish_growing" diff --git a/code/datums/components/fish_growth.dm b/code/datums/components/fish_growth.dm new file mode 100644 index 00000000000..bc7c8a9869e --- /dev/null +++ b/code/datums/components/fish_growth.dm @@ -0,0 +1,57 @@ +///A simple component that manages raising things from aquarium fish. +/datum/component/fish_growth + dupe_mode = COMPONENT_DUPE_SELECTIVE + ///the type of the movable that's spawned when the fish grows up. + var/result_type + ///The progress, from 0 to 100 + var/maturation + ///How much maturation is gained per tick + var/growth_rate + ///Is the result moved on the nearest drop location? + var/use_drop_loc + ///Is the parent deleted once the result is spawned? + var/del_on_grow + +/datum/component/fish_growth/Initialize(result_type, growth_rate, use_drop_loc = TRUE, del_on_grow = TRUE) + . = ..() + if(!isfish(parent)) + return COMPONENT_INCOMPATIBLE + RegisterSignal(parent, COMSIG_FISH_LIFE, PROC_REF(on_fish_life)) + src.result_type = result_type + src.growth_rate = growth_rate + src.use_drop_loc = use_drop_loc + src.del_on_grow = del_on_grow + +/datum/component/fish_growth/CheckDupeComponent(result_type, growth_rate, use_drop_loc = TRUE, del_on_grow = TRUE) + if(result_type == src.result_type) + src.growth_rate = growth_rate + return TRUE //copy the growth rate and kill the new component + return FALSE + +/datum/component/fish_growth/proc/on_fish_life(obj/item/fish/source, seconds_per_tick) + SIGNAL_HANDLER + if(SEND_SIGNAL(source, COMSIG_FISH_BEFORE_GROWING, seconds_per_tick) & COMPONENT_DONT_GROW) + return + maturation += growth_rate * seconds_per_tick + if(maturation >= 100) + finish_growing(source) + +/datum/component/fish_growth/proc/finish_growing(obj/item/fish/source) + var/atom/location = use_drop_loc ? source.drop_location() : source.loc + var/atom/movable/result = new result_type (location) + if(location != source.loc) + result.visible_message(span_boldnotice("\A [result] jumps out of [source.loc]!")) + playsound(result, 'sound/effects/fish_splash.ogg', 60) + if(isbasicmob(result)) + for(var/trait_type in source.fish_traits) + var/datum/fish_trait/trait = GLOB.fish_traits[trait_type] + trait.apply_to_mob(result) + + addtimer(CALLBACK(result, TYPE_PROC_REF(/mob/living/basic, hop_on_nearby_turf)), 0.1 SECONDS) + + SEND_SIGNAL(source, COMSIG_FISH_FINISH_GROWING, result) + + if(del_on_grow) + qdel(parent) + else + maturation = 0 diff --git a/code/game/objects/structures/water_structures/water_source.dm b/code/game/objects/structures/water_structures/water_source.dm index b7ad26a65ea..e06cd8c6771 100644 --- a/code/game/objects/structures/water_structures/water_source.dm +++ b/code/game/objects/structures/water_structures/water_source.dm @@ -137,6 +137,15 @@ base_icon_state = "puddle" resistance_flags = UNACIDABLE +/obj/structure/water_source/puddle/Initialize(mapload) + . = ..() + register_context() + +/obj/structure/water_source/puddle/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(isnull(held_item)) + context[SCREENTIP_CONTEXT_RMB] = "Scoop Tadpoles" + //ATTACK HAND IGNORING PARENT RETURN VALUE /obj/structure/water_source/puddle/attack_hand(mob/user, list/modifiers) icon_state = "[base_icon_state]-splash" @@ -147,3 +156,20 @@ icon_state = "[base_icon_state]-splash" . = ..() icon_state = base_icon_state + +/obj/structure/water_source/puddle/attack_hand_secondary(mob/living/carbon/human/user, list/modifiers) + . = ..() + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) + return + if(DOING_INTERACTION_WITH_TARGET(user, src)) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + icon_state = "[base_icon_state]-splash" + balloon_alert(user, "scooping tadpoles...") + if(do_after(user, src, 5 SECONDS)) + playsound(loc, 'sound/effects/slosh.ogg', 15, TRUE) + balloon_alert(user, "got a tadpole") + var/obj/item/fish/tadpole/tadpole = new(loc) + tadpole.randomize_size_and_weight() + user.put_in_hands(tadpole) + icon_state = base_icon_state + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN diff --git a/code/modules/cargo/exports/fish.dm b/code/modules/cargo/exports/fish.dm index 3860dff904b..9c34fd3afca 100644 --- a/code/modules/cargo/exports/fish.dm +++ b/code/modules/cargo/exports/fish.dm @@ -6,8 +6,4 @@ /datum/export/fish/get_cost(obj/item/fish/fish, apply_elastic) var/elastic_cost = ..() var/elastic_percent = elastic_cost / init_cost - var/size_weight_exponentation = (fish.size * fish.weight * 0.01)^0.85 - var/new_cost = elastic_cost + size_weight_exponentation * elastic_percent - if(HAS_TRAIT(fish, TRAIT_FISH_FROM_CASE)) //Avoid printing money by simply ordering fish and sending it back. - new_cost *= 0.05 - return round(new_cost) + return fish.get_export_price(elastic_cost, elastic_percent) diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index 081f7940290..19a20a40a81 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -627,6 +627,14 @@ fish_zap_flags |= (ZAP_GENERATES_POWER | ZAP_MOB_STUN) tesla_zap(source = get_turf(src), zap_range = fish_zap_range, power = fish_zap_power, cutoff = 1 MEGA JOULES, zap_flags = fish_zap_flags) +///Returns the price of this fish, for the fish export. +/obj/item/fish/proc/get_export_price(price, percent) + var/size_weight_exponentation = (size * weight * 0.01)^0.85 + var/calculated_price = price + size_weight_exponentation * percent + if(HAS_TRAIT(src, TRAIT_FISH_FROM_CASE)) //Avoid printing money by simply ordering fish and sending it back. + calculated_price *= 0.05 + return round(calculated_price) + /// Returns random fish, using random_case_rarity probabilities. /proc/random_fish_type(required_fluid) var/static/probability_table diff --git a/code/modules/fishing/fish/fish_types.dm b/code/modules/fishing/fish/fish_types.dm index 11f9ab317d2..ce9f36f0553 100644 --- a/code/modules/fishing/fish/fish_types.dm +++ b/code/modules/fishing/fish/fish_types.dm @@ -81,6 +81,55 @@ required_temperature_max = MIN_AQUARIUM_TEMP+30 beauty = FISH_BEAUTY_GOOD +/obj/item/fish/tadpole + name = "tadpole" + desc = "The larval spawn of an amphibian. A very minuscle, round creature with a long tail it uses to swim around." + icon_state = "tadpole" + dedicated_in_aquarium_icon_state = "tadpole small" + average_size = 3 + average_weight = 10 + sprite_width = 3 + sprite_height = 1 + health = 50 + feeding_frequency = 1.5 MINUTES + required_temperature_min = MIN_AQUARIUM_TEMP+15 + required_temperature_max = MIN_AQUARIUM_TEMP+20 + fillet_type = null + fish_traits = list(/datum/fish_trait/no_mating) //They grow into frogs and that's it. + beauty = FISH_BEAUTY_NULL + random_case_rarity = FISH_RARITY_NOPE //Why would you want generic frog tadpoles you get from ponds inside fish cases? + /// Once dead, tadpoles disappear after a dozen seconds, since you can get infinite tadpoles. + var/del_timerid + +/obj/item/fish/tadpole/Initialize(mapload, apply_qualities = TRUE) + . = ..() + AddComponent(/datum/component/fish_growth, /mob/living/basic/frog, 100 / rand(2.5, 3 MINUTES) * 10) + RegisterSignal(src, COMSIG_FISH_BEFORE_GROWING, PROC_REF(growth_checks)) + RegisterSignal(src, COMSIG_FISH_FINISH_GROWING, PROC_REF(on_growth)) + +/obj/item/fish/tadpole/set_status(new_status) + . = ..() + if(status == FISH_DEAD) + del_timerid = QDEL_IN_STOPPABLE(src, 12 SECONDS) + else + deltimer(del_timerid) + +/obj/item/fish/tadpole/proc/growth_checks(datum/source, seconds_per_tick) + SIGNAL_HANDLER + var/hunger = CLAMP01((world.time - last_feeding) / feeding_frequency) + if(hunger >= 0.7) //too hungry to grow + return COMPONENT_DONT_GROW + var/obj/structure/aquarium/aquarium = loc + if(!aquarium.allow_breeding) //the aquarium has breeding disabled + return COMPONENT_DONT_GROW + +/obj/item/fish/tadpole/proc/on_growth(datum/source, mob/living/basic/frog/result) + SIGNAL_HANDLER + playsound(result, result.attack_sound, 50, TRUE) // reeeeeeeeeeeeeee... + +/obj/item/fish/tadpole/get_export_price(price, percent) + return 2 //two credits. Tadpoles aren't really that valueable. + // Saltwater fish below /obj/item/fish/clownfish @@ -270,8 +319,6 @@ evolution_types = list(/datum/fish_evolution/ice_chrab) compatible_types = list(/obj/item/fish/chasm_crab/ice) beauty = FISH_BEAUTY_GOOD - ///Chasm crabs mature into juveline lobstrositiess with time. This is the progess from 0 to 100 - var/maturation = 0 ///This value represents how much the crab needs aren't being met. Higher values translate to a more likely hostile lobstrosity. var/anger = 0 ///The lobstrosity type this matures into @@ -279,6 +326,11 @@ ///at which rate the crab gains maturation var/growth_rate = 100 / (10 MINUTES) * 10 +/obj/item/fish/chasm_crab/Initialize(mapload, apply_qualities = TRUE) + . = ..() + RegisterSignal(src, COMSIG_FISH_BEFORE_GROWING, PROC_REF(growth_checks)) + RegisterSignal(src, COMSIG_FISH_FINISH_GROWING, PROC_REF(on_growth)) + ///A chasm crab growth speed is determined by its initial weight and size, ergo bigger crabs for faster lobstrosities /obj/item/fish/chasm_crab/update_size_and_weight(new_size = average_size, new_weight = average_weight) . = ..() @@ -298,62 +350,41 @@ else if(weight >= 1500) multiplier += min(0.1 * round((weight - 1000) / 500), 2) - growth_rate = initial(growth_rate) * multiplier + AddComponent(/datum/component/fish_growth, lob_type, initial(growth_rate) * multiplier) -/obj/item/fish/chasm_crab/process(seconds_per_tick) - . = ..() - grow_up(seconds_per_tick) - -///Slowly grow up each process tick (in an aquarium). This is its own proc so that it can be used in the unit test. -/obj/item/fish/chasm_crab/proc/grow_up(seconds_per_tick) +/obj/item/fish/chasm_crab/proc/growth_checks(datum/source, seconds_per_tick) + SIGNAL_HANDLER var/hunger = CLAMP01((world.time - last_feeding) / feeding_frequency) if(health <= initial(health) * 0.6 || hunger >= 0.6) //if too hurt or hungry, don't grow. anger += growth_rate * 2 * seconds_per_tick - return + return COMPONENT_DONT_GROW - if(!isaquarium(loc)) //can't grow outside an aquarium. + if(hunger >= 0.4) //I'm hungry and angry + anger += growth_rate * 0.6 * seconds_per_tick + + if(!isaquarium(loc)) return var/obj/structure/aquarium/aquarium = loc if(!aquarium.allow_breeding) //the aquarium has breeding disabled - return - if(hunger >= 0.4) //I'm hungry and angry - anger += growth_rate * 0.6 * seconds_per_tick + return COMPONENT_DONT_GROW if(!locate(/obj/item/aquarium_prop) in aquarium) //the aquarium deco is quite barren anger += growth_rate * 0.25 * seconds_per_tick var/fish_count = length(aquarium.get_fishes()) if(!ISINRANGE(fish_count, 3, AQUARIUM_MAX_BREEDING_POPULATION * 0.5)) //too lonely or overcrowded anger += growth_rate * 0.3 * seconds_per_tick - if(fish_count <= AQUARIUM_MAX_BREEDING_POPULATION * 0.5) //check if there's enough room to maturate. - maturation += growth_rate * seconds_per_tick + if(fish_count > AQUARIUM_MAX_BREEDING_POPULATION * 0.5) //check if there's enough room to maturate. + return COMPONENT_DONT_GROW - if(maturation >= 100) - return finish_growing() - -///spawn a juvenile lobstrosity on the aquarium turf -/obj/item/fish/chasm_crab/proc/finish_growing() - var/mob/living/basic/mining/lobstrosity/juvenile/lob = new lob_type(get_turf(src)) - for(var/trait_type in fish_traits) - var/datum/fish_trait/trait = GLOB.fish_traits[trait_type] - trait.apply_to_mob(lob) +/obj/item/fish/chasm_crab/proc/on_growth(datum/source, mob/living/basic/mining/lobstrosity/juvenile/result) + SIGNAL_HANDLER if(!prob(anger)) - lob.AddElement(/datum/element/ai_retaliate) - qdel(lob.ai_controller) - lob.ai_controller = new /datum/ai_controller/basic_controller/lobstrosity/juvenile/calm(lob) + result.AddElement(/datum/element/ai_retaliate) + qdel(result.ai_controller) + result.ai_controller = new /datum/ai_controller/basic_controller/lobstrosity/juvenile/calm(result) else if(anger < 30) //not really that mad, just a bit unstable. - qdel(lob.ai_controller) - lob.ai_controller = new /datum/ai_controller/basic_controller/lobstrosity/juvenile/capricious(lob) - - animate(lob, pixel_y = 18, time = 0.4 SECONDS, flags = ANIMATION_RELATIVE, easing = CUBIC_EASING|EASE_OUT) - animate(pixel_y = -18, time = 0.4 SECONDS, flags = ANIMATION_RELATIVE, easing = CUBIC_EASING|EASE_IN) - loc.visible_message(span_boldnotice("\A [lob] jumps out of [loc]!")) - playsound(loc, 'sound/effects/fish_splash.ogg', 60) - - ///make sure it moves the next tick so that it properly glides to the next location after jumping off the aquarium. - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(random_step), lob, 1, 100), 0.1 SECONDS) - - qdel(src) - return lob + qdel(result.ai_controller) + result.ai_controller = new /datum/ai_controller/basic_controller/lobstrosity/juvenile/capricious(result) /obj/item/fish/chasm_crab/ice name = "arctic chrab" @@ -434,7 +465,7 @@ ) beauty = FISH_BEAUTY_DISGUSTING -/obj/item/fish/ratfish/Initialize(mapload) +/obj/item/fish/ratfish/Initialize(mapload, apply_qualities = TRUE) . = ..() //stable pop reflects the config for how many mice migrate. powerful... stable_population = CONFIG_GET(number/mice_roundstart) @@ -566,7 +597,7 @@ fish_traits = list(/datum/fish_trait/no_mating) //just to be sure, these shouldn't reproduce experisci_scannable = FALSE -/obj/item/fish/holo/Initialize(mapload) +/obj/item/fish/holo/Initialize(mapload, apply_qualities = TRUE) . = ..() var/area/station/holodeck/holo_area = get_area(src) if(!istype(holo_area)) @@ -655,7 +686,7 @@ fish_traits = list(/datum/fish_trait/antigrav, /datum/fish_trait/mixotroph) beauty = FISH_BEAUTY_GREAT -/obj/item/fish/starfish/Initialize(mapload) +/obj/item/fish/starfish/Initialize(mapload, apply_qualities = TRUE) . = ..() update_appearance(UPDATE_OVERLAYS) @@ -693,7 +724,7 @@ ///maximum bonus damage when winded up var/maximum_bonus = 25 -/obj/item/fish/lavaloop/Initialize(mapload) +/obj/item/fish/lavaloop/Initialize(mapload, apply_qualities = TRUE) . = ..() ADD_TRAIT(src, TRAIT_BYPASS_RANGED_ARMOR, INNATE_TRAIT) AddComponent(/datum/component/boomerang, throw_range, TRUE) diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index 98a771a06a9..582af27c316 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -318,3 +318,9 @@ /mob/living/basic/get_body_temp_cold_damage_limit() return minimum_survivable_temperature + +/mob/living/basic/proc/hop_on_nearby_turf() + var/dir = pick(GLOB.cardinals) + Move(get_step(src, dir), dir) + animate(src, pixel_y = 18, time = 0.4 SECONDS, flags = ANIMATION_RELATIVE, easing = CUBIC_EASING|EASE_OUT) + animate(pixel_y = -18, time = 0.4 SECONDS, flags = ANIMATION_RELATIVE, easing = CUBIC_EASING|EASE_IN) diff --git a/code/modules/unit_tests/fish_unit_tests.dm b/code/modules/unit_tests/fish_unit_tests.dm index 1db534c5e07..5cb582ca969 100644 --- a/code/modules/unit_tests/fish_unit_tests.dm +++ b/code/modules/unit_tests/fish_unit_tests.dm @@ -226,10 +226,11 @@ /datum/unit_test/raise_a_chasm_crab/Run() var/obj/structure/aquarium/crab/aquarium = allocate(/obj/structure/aquarium/crab) - var/mob/living/basic/mining/lobstrosity/juvenile/lobster = aquarium.crabbie.grow_up(1) //one stands for a second - TEST_ASSERT(lobster, "The test aquarium's chasm crab didn't grow up into a lobstrosity.[aquarium.crabbie ? " The aquarium crab is still here and at about [aquarium.crabbie.maturation]% maturation" : ""]") - allocated |= lobster //make sure it's allocated and thus properly deleted when the test is over + SEND_SIGNAL(aquarium.crabbie, COMSIG_FISH_LIFE, 1) //give the fish growth component a small push. + var/mob/living/basic/mining/lobstrosity/juvenile/lobster = locate() in aquarium.loc TEST_ASSERT_EQUAL(lobster.loc, get_turf(aquarium), "The lobstrosity didn't spawn on the aquarium's turf") + TEST_ASSERT(QDELETED(aquarium.crabbie), "The test aquarium's chasm crab didn't delete itself.") + allocated |= lobster //make sure it's allocated and thus properly deleted when the test is over //While ideally impossible to have all traits because of incompatible ones, I want to be sure they don't error out. for(var/trait_type in GLOB.fish_traits) var/datum/fish_trait/trait = GLOB.fish_traits[trait_type] diff --git a/icons/obj/aquarium/fish.dmi b/icons/obj/aquarium/fish.dmi index ab282e1681be9d7b17ca3243b244bb90c77bb54d..638c8300f304a001f1e8dcd2abb8a9f7e836cde1 100644 GIT binary patch delta 13840 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

qK>Y+Cc)b~7-eDDuDPL#>v0b+I+#A} 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�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�SXTW8tucK`;LCYo3LkOK%jQaL3`ldkpNU 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 { ))} - +