Skip to content

Commit

Permalink
[MIRROR] Fish update just dropped. New fish, aquarium type, two trait…
Browse files Browse the repository at this point in the history
…s and a research node. (#2756)

* Fish update just dropped. New fish, aquarium type, two traits and a research node. (#83508)

## About The Pull Request

### New fish

#### anxious zipzap
An incredibly anxiety-ridden and electroreceptive fish. Worried about
the walls of its tank closing in constantly. Both literally and as a
general metaphorical unease about life's direction.

It produces electricity, and HATES being with any other fish. One other
zipzap is allowed at most.


![image](https://github.com/tgstation/tgstation/assets/40974010/6a1a31f3-1c84-4b5e-b8ca-652c5007813a)

#### monocloning jumpercable
A surprisingly useful if nasty looking creation from the syndicate fish
labs. Drop one in a tank, and watch it self-feed and multiply. Generates
more and more power as a growing swarm!

A far better option for power generation than the zipzap, but it's a
syndicate fish. Get an emag or get very lucky!


![image](https://github.com/tgstation/tgstation/assets/40974010/7f4aaf32-919c-40d9-890f-72ea9f91ac3c)

Working spacebase example


![image](https://github.com/tgstation/tgstation/assets/40974010/8eeaaf18-c0ab-48a5-8ada-e0eb7f118dd9)


### Aquarium type

Bioelectricity Generator! It boosts the power of electroreceptive fish
to very dangerous levels! But, uh, you put a tesla coil, and voila! Free
power! ...Free power if you keep the fish fed! More fish, more power!


![image](https://github.com/tgstation/tgstation/assets/40974010/e6abcd5b-93df-4ffc-ac6a-78585fd4a6c6)

You can convert an aquarium into a bioelectricity generator by
researching the new node, "Marine Utility", from bio processing. Then
you build the biogen upgrade kit and apply it to an already existing
aquarium.

### Fish Traits

#### Electrogenesis

Trait turns the fish into a shock weapon while it's alive, and every
time it feeds, it releases a weak tesla bolt to anyone close to the
tank.

#### Anxiety

anxious fish die when any other fish are in the tank. Please keep them
alone :[

## Why It's Good For The Game

Fish are great, but fish don't have anything to give back to the
station, right? Well, there's some small stuff, but I wanted to add a
bit of functionality towards being able to benefit from having fish.

The anxiety trait with the zipzap gives spessmen a bit of a challenge.
You can settle for one fish generating power per tank and do a
multi-tank generation setup, or you can do some crossbreeding to make a
fish WITH electroreceptive but WITHOUT anxiety. Neat!

## Changelog
:cl:
add: New fish, the anxious zipzap
add: New syndicate fish, the monocloning jumpercable
add: New aquarium, the bioelectricity generator
fix: Mixotrophic fish now properly lack food requirements
/:cl:

* Fish update just dropped. New fish, aquarium type, two traits and a research node.

---------

Co-authored-by: tralezab <[email protected]>
Co-authored-by: NovaBot13 <[email protected]>
  • Loading branch information
3 people authored and StealsThePRs committed May 31, 2024
1 parent e4ac8fd commit 985b68d
Show file tree
Hide file tree
Showing 19 changed files with 222 additions and 20 deletions.
5 changes: 5 additions & 0 deletions code/__DEFINES/fish.dm
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,8 @@

///Fluff. The name of the aquarium company shown in the fish catalog
#define AQUARIUM_COMPANY "Aquatech Ltd."

/// how long between electrogenesis zaps
#define ELECTROGENESIS_DURATION 40 SECONDS
/// a random range the electrogenesis cooldown varies by
#define ELECTROGENESIS_VARIANCE (rand(-10 SECONDS, 10 SECONDS))
2 changes: 2 additions & 0 deletions code/__DEFINES/traits/declarations.dm
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_FISH_NO_HUNGER "fish_no_hunger"
///It comes from a fish case. Relevant for bounties so far.
#define TRAIT_FISH_FROM_CASE "fish_from_case"
///Fish will also occasionally fire weak tesla zaps
#define TRAIT_FISH_ELECTROGENESIS "fish_electrogenesis"

/// Trait given to angelic constructs to let them purge cult runes
#define TRAIT_ANGELIC "angelic"
Expand Down
1 change: 1 addition & 0 deletions code/_globalvars/traits/_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_FISH_NO_MATING" = TRAIT_FISH_NO_MATING,
"TRAIT_FISH_SELF_REPRODUCE" = TRAIT_FISH_SELF_REPRODUCE,
"TRAIT_FISH_TOXIN_IMMUNE" = TRAIT_FISH_TOXIN_IMMUNE,
"TRAIT_FISH_ELECTROGENESIS" = TRAIT_FISH_ELECTROGENESIS,
"TRAIT_RESIST_EMULSIFY" = TRAIT_RESIST_EMULSIFY,
"TRAIT_YUCKY_FISH" = TRAIT_YUCKY_FISH,
),
Expand Down
4 changes: 2 additions & 2 deletions code/datums/components/aquarium_content.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@


/// Icon used for in aquarium sprite
var/icon = 'icons/obj/aquarium.dmi'
var/icon = 'icons/obj/aquarium/fish.dmi'
/// If this is set this icon state will be used for the holder while icon_state will only be used for item/catalog. Transformation from source_width/height WON'T be applied.
var/icon_state
/// Applied to vc object only for use with greyscaled icons.
Expand Down Expand Up @@ -61,7 +61,7 @@
var/animation_update_signals


/datum/component/aquarium_content/Initialize(animation_getter, animation_update_signals)
/datum/component/aquarium_content/Initialize(icon, animation_getter, animation_update_signals)
if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE

Expand Down
33 changes: 26 additions & 7 deletions code/modules/fishing/aquarium/aquarium.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@

/obj/structure/aquarium
name = "aquarium"
desc = "A vivivarium in which aquatic fuana and flora are usually kept and displayed."
desc = "A vivarium in which aquatic fauna and flora are usually kept and displayed."
density = TRUE
anchored = TRUE

icon = 'icons/obj/aquarium.dmi'
icon = 'icons/obj/aquarium/tanks.dmi'
icon_state = "aquarium_map"

integrity_failure = 0.3

/// The icon state is used for mapping so mappers know what they're placing. This prefixes the real icon used in game.
/// For an example, "aquarium" gives the base sprite of "aquarium_base", the glass is "aquarium_glass_water", and so on.
var/icon_prefix = "aquarium"

var/fluid_type = AQUARIUM_FLUID_FRESHWATER
var/fluid_temp = DEFAULT_AQUARIUM_TEMP
var/min_fluid_temp = MIN_AQUARIUM_TEMP
Expand Down Expand Up @@ -138,20 +142,20 @@
/obj/structure/aquarium/update_icon()
. = ..()
///"aquarium_map" is used for mapping, so mappers can tell what it's.
icon_state = "aquarium_base"
icon_state = icon_prefix + "_base"

/obj/structure/aquarium/update_overlays()
. = ..()
if(panel_open)
. += "panel"
. += icon_prefix + "_panel"

///The glass overlay
var/suffix = fluid_type == AQUARIUM_FLUID_AIR ? "air" : "water"
if(broken)
suffix += "_broken"
. += mutable_appearance(icon, "aquarium_glass_cracks", layer = layer + AQUARIUM_BORDERS_LAYER)
. += mutable_appearance(icon, "aquarium_glass_[suffix]", layer = layer + AQUARIUM_GLASS_LAYER)
. += mutable_appearance(icon, "aquarium_borders", layer = layer + AQUARIUM_BORDERS_LAYER)
. += mutable_appearance(icon, icon_prefix + "_glass_cracks", layer = layer + AQUARIUM_BORDERS_LAYER)
. += mutable_appearance(icon, icon_prefix + "_glass_[suffix]", layer = layer + AQUARIUM_GLASS_LAYER)
. += mutable_appearance(icon, icon_prefix + "_borders", layer = layer + AQUARIUM_BORDERS_LAYER)

/obj/structure/aquarium/examine(mob/user)
. = ..()
Expand Down Expand Up @@ -212,6 +216,21 @@
fish.feed(item.reagents)
balloon_alert(user, "fed the fish")
return TRUE
if(istype(item, /obj/item/aquarium_upgrade))
var/obj/item/aquarium_upgrade/upgrade = item
if(upgrade.upgrade_from_type != type)
balloon_alert(user, "wrong kind of aquarium!")
return
balloon_alert(user, "upgrading...")
if(!do_after(user, 5 SECONDS, src))
return
var/obj/structure/aquarium/upgraded_aquarium = new upgrade.upgrade_to_type(loc)
for(var/atom/movable/moving in contents)
moving.forceMove(upgraded_aquarium)
balloon_alert(user, "upgraded")
qdel(upgrade)
qdel(src)
return
return ..()

/obj/structure/aquarium/proc/on_attacked(datum/source, mob/attacker, attack_flags)
Expand Down
11 changes: 6 additions & 5 deletions code/modules/fishing/aquarium/aquarium_kit.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/obj/item/fish_feed
name = "fish feed can"
desc = "A refillable can that dispenses nutritious fish feed."
icon = 'icons/obj/aquarium.dmi'
icon = 'icons/obj/aquarium/supplies.dmi'
icon_state = "fish_feed"
w_class = WEIGHT_CLASS_TINY

Expand Down Expand Up @@ -58,7 +58,7 @@
name = "ominous fish case"

/obj/item/storage/fish_case/syndicate/get_fish_type()
return pick(/obj/item/fish/donkfish, /obj/item/fish/emulsijack)
return pick(/obj/item/fish/donkfish, /obj/item/fish/emulsijack, /obj/item/fish/jumpercable)

/obj/item/storage/fish_case/tiziran
name = "imported fish case"
Expand All @@ -76,6 +76,7 @@
/obj/item/fish/boned = 1,
/obj/item/fish/clownfish/lube = 3,
/obj/item/fish/emulsijack = 1,
/obj/item/fish/jumpercable = 1,
/obj/item/fish/sludgefish/purple = 1,
/obj/item/fish/pufferfish = 3,
/obj/item/fish/slimefish = 2,
Expand All @@ -93,7 +94,7 @@
/obj/item/aquarium_kit
name = "DIY Aquarium Construction Kit"
desc = "Everything you need to build your own aquarium. Raw materials sold separately."
icon = 'icons/obj/aquarium.dmi'
icon = 'icons/obj/aquarium/supplies.dmi'
icon_state = "construction_kit"
w_class = WEIGHT_CLASS_TINY

Expand All @@ -104,14 +105,14 @@
/obj/item/aquarium_prop
name = "generic aquarium prop"
desc = "very boring"
icon = 'icons/obj/aquarium.dmi'
icon = 'icons/obj/aquarium/supplies.dmi'

w_class = WEIGHT_CLASS_TINY
var/layer_mode = AQUARIUM_LAYER_MODE_BOTTOM

/obj/item/aquarium_prop/Initialize(mapload)
. = ..()
AddComponent(/datum/component/aquarium_content)
AddComponent(/datum/component/aquarium_content, icon)

/obj/item/aquarium_prop/rocks
name = "rocks"
Expand Down
37 changes: 37 additions & 0 deletions code/modules/fishing/aquarium/aquarium_upgrades.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

/// Aquarium upgrades, can be applied to a basic aquarium to upgrade it into an advanced subtype.
/obj/item/aquarium_upgrade
name = "Aquarium Upgrade"
desc = "An upgrade."

icon = 'icons/obj/aquarium/supplies.dmi'
icon_state = "construction_kit"
/// What kind of aquarium can accept this upgrade. Strict type check, no subtypes.
var/upgrade_from_type = /obj/structure/aquarium
/// typepath of the new aquarium subtype created.
var/upgrade_to_type = /obj/structure/aquarium

/obj/item/aquarium_upgrade/bioelec_gen
name = "Aquarium Bioelectricity Kit"
desc = "All the required components to allow an aquarium to harness energy bioelectric fish."
icon_state = "bioelec_kit"
upgrade_to_type = /obj/structure/aquarium/bioelec_gen

/obj/structure/aquarium/bioelec_gen
name = "bioelectricity generator"
desc = "An unconventional type of generator that boosts and harvests the energy produced by bioelectric fish."

icon_state = "bioelec_map"
icon_prefix = "bioelec"

/obj/structure/aquarium/bioelec_gen/zap_act(power, zap_flags)
var/explosive = zap_flags & ZAP_MACHINE_EXPLOSIVE
if(!explosive)
return //immune to all other shocks to make sure power can be generated without breaking the generator itself
return ..()

/obj/structure/aquarium/bioelec_gen/examine(mob/user)
. = ..()
. += span_boldwarning("WARNING! WARNING! WARNING!")
. += span_warning("The bioelectric potential of the fish inside is magnified to dangerous levels by the generator.")
. += span_notice("Tesla coils are required to collect this magnified energy... and you'll want a grounding rod to protect yourself as well.")
24 changes: 22 additions & 2 deletions code/modules/fishing/fish/_fish.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/obj/item/fish
name = "generic looking aquarium fish"
desc = "very bland"
icon = 'icons/obj/aquarium.dmi'
icon = 'icons/obj/aquarium/fish.dmi'
icon_state = "bugfish"
lefthand_file = 'icons/mob/inhands/fish_lefthand.dmi'
righthand_file = 'icons/mob/inhands/fish_righthand.dmi'
Expand Down Expand Up @@ -138,10 +138,14 @@

/// If this fish type counts towards the Fish Species Scanning experiments
var/experisci_scannable = TRUE
/// cooldown on creating tesla zaps
COOLDOWN_DECLARE(electrogenesis_cooldown)
/// power of the tesla zap created by the fish in a bioelectric generator
var/electrogenesis_power = 10 MEGA JOULES

/obj/item/fish/Initialize(mapload, apply_qualities = TRUE)
. = ..()
AddComponent(/datum/component/aquarium_content, PROC_REF(get_aquarium_animation), list(COMSIG_FISH_STATUS_CHANGED,COMSIG_FISH_STIRRED))
AddComponent(/datum/component/aquarium_content, icon, PROC_REF(get_aquarium_animation), list(COMSIG_FISH_STATUS_CHANGED,COMSIG_FISH_STIRRED))

RegisterSignal(src, COMSIG_ATOM_ON_LAZARUS_INJECTOR, PROC_REF(use_lazarus))
if(do_flop_animation)
Expand Down Expand Up @@ -351,6 +355,9 @@
if(ready_to_reproduce())
try_to_reproduce()

if(HAS_TRAIT(src, TRAIT_FISH_ELECTROGENESIS) && COOLDOWN_FINISHED(src, electrogenesis_cooldown))
try_electrogenesis()

SEND_SIGNAL(src, COMSIG_FISH_LIFE, seconds_per_tick)

/obj/item/fish/proc/set_status(new_status)
Expand Down Expand Up @@ -605,6 +612,19 @@
if(flopping)
flop_animation()

/obj/item/fish/proc/try_electrogenesis()
if(status == FISH_DEAD || is_hungry())
return
COOLDOWN_START(src, electrogenesis_cooldown, ELECTROGENESIS_DURATION + ELECTROGENESIS_VARIANCE)
var/fish_zap_range = 1
var/fish_zap_power = 1 KILO JOULES // ~5 damage, just a little friendly "yeeeouch!"
var/fish_zap_flags = ZAP_MOB_DAMAGE
if(istype(loc, /obj/structure/aquarium/bioelec_gen))
fish_zap_range = 5
fish_zap_power = electrogenesis_power
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 random fish, using random_case_rarity probabilities.
/proc/random_fish_type(required_fluid)
var/static/probability_table
Expand Down
54 changes: 52 additions & 2 deletions code/modules/fishing/fish/fish_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ GLOBAL_LIST_INIT(fish_traits, init_subtypes_w_path_keys(/datum/fish_trait, list(
name = "Aggressive"
inheritability = 80
diff_traits_inheritability = 40
catalog_description = "This fish is agressively territorial, and may attack fish that come close to it."
catalog_description = "This fish is aggressively territorial, and may attack fish that come close to it."

/datum/fish_trait/aggressive/apply_to_fish(obj/item/fish/fish)
RegisterSignal(fish, COMSIG_FISH_LIFE, PROC_REF(try_attack_fish))
Expand Down Expand Up @@ -364,7 +364,7 @@ GLOBAL_LIST_INIT(fish_traits, init_subtypes_w_path_keys(/datum/fish_trait, list(
catalog_description = "This fish is capable of substaining itself by producing its own sources of energy (food)."
incompatible_traits = list(/datum/fish_trait/predator, /datum/fish_trait/necrophage)

/datum/fish_trait/antigrav/apply_to_fish(obj/item/fish/fish)
/datum/fish_trait/mixotroph/apply_to_fish(obj/item/fish/fish)
ADD_TRAIT(fish, TRAIT_FISH_NO_HUNGER, FISH_TRAIT_DATUM)

/datum/fish_trait/antigrav
Expand All @@ -379,3 +379,53 @@ GLOBAL_LIST_INIT(fish_traits, init_subtypes_w_path_keys(/datum/fish_trait, list(

/datum/fish_trait/antigrav/apply_to_fish(obj/item/fish/fish)
fish.AddElement(/datum/element/forced_gravity, NEGATIVE_GRAVITY)

///Anxiety means the fish will die if in a location with more than 3 fish (including itself)
///This is just barely enough to crossbreed out of anxiety, but it severely limits the potential of
/datum/fish_trait/anxiety
name = "Anxiety"
inheritability = 100
diff_traits_inheritability = 70
catalog_description = "This fish tends to die of stress when forced to be around too many other fish."

/datum/fish_trait/anxiety/apply_to_fish(obj/item/fish/fish)
RegisterSignal(fish, COMSIG_FISH_LIFE, PROC_REF(on_fish_life))

///signal sent when the anxiety fish is fed, killing it if sharing contents with too many fish.
/datum/fish_trait/anxiety/proc/on_fish_life(obj/item/fish/fish, seconds_per_tick)
SIGNAL_HANDLER
var/fish_tolerance = 3
if(!fish.loc || fish.status == FISH_DEAD)
return
for(var/obj/item/other_fish in fish.loc.contents)
if(fish_tolerance <= 0)
fish.loc.visible_message(span_warning("[fish] seems to freak out for a moment, then it stops moving..."))
fish.set_status(FISH_DEAD)
return
fish_tolerance -= 1

/datum/fish_trait/electrogenesis
name = "Electrogenesis"
inheritability = 60
diff_traits_inheritability = 30
catalog_description = "This fish is electroreceptive, and will generate electric fields. Can be harnessed inside a bioelectric generator."

/datum/fish_trait/electrogenesis/apply_to_fish(obj/item/fish/fish)
ADD_TRAIT(fish, TRAIT_FISH_ELECTROGENESIS, FISH_TRAIT_DATUM)
RegisterSignal(fish, COMSIG_ITEM_ATTACK, PROC_REF(on_item_attack))

/datum/fish_trait/electrogenesis/proc/on_item_attack(obj/item/fish/fish, mob/living/target, mob/living/user)
SIGNAL_HANDLER

if(fish.status == FISH_ALIVE)
fish.force = 16
fish.damtype = BURN
fish.attack_verb_continuous = list("shocks", "zaps")
fish.attack_verb_simple = list("shock", "zap")
fish.hitsound = 'sound/effects/sparks4.ogg'
else
fish.force = fish::force
fish.damtype = fish::damtype
fish.attack_verb_continuous = fish::attack_verb_continuous
fish.attack_verb_simple = fish::attack_verb_simple
fish.hitsound = fish::hitsound
47 changes: 45 additions & 2 deletions code/modules/fishing/fish/fish_types.dm
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,26 @@
required_temperature_min = MIN_AQUARIUM_TEMP+5
required_temperature_max = MIN_AQUARIUM_TEMP+40

/obj/item/fish/jumpercable
name = "monocloning jumpercable"
desc = "A surprisingly useful if nasty looking creation from the syndicate fish labs. Drop one in a tank, and \
watch it self-feed and multiply. Generates more and more power as a growing swarm!"
icon_state = "jumpercable"
dedicated_in_aquarium_icon_state = "jumpercable_small"
sprite_width = 17
sprite_height = 5
stable_population = 12
average_size = 110
average_weight = 10000
random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS
required_temperature_min = MIN_AQUARIUM_TEMP+10
required_temperature_max = MIN_AQUARIUM_TEMP+30
fish_traits = list(
/datum/fish_trait/parthenogenesis,
/datum/fish_trait/mixotroph,
/datum/fish_trait/electrogenesis,
)

/obj/item/fish/ratfish
name = "ratfish"
desc = "A rat exposed to the murky waters of maintenance too long. Any higher power, if it revealed itself, would state that the ratfish's continued existence is extremely unwelcome."
Expand Down Expand Up @@ -400,9 +420,9 @@
/obj/item/fish/mastodon
name = "unmarine mastodon"
desc = "A monster of exposed muscles and innards, wrapped in a fish-like skeleton. You don't remember ever seeing it on the catalog."
icon = 'icons/obj/aquarium_wide.dmi'
icon = 'icons/obj/aquarium/wide.dmi'
icon_state = "mastodon"
dedicated_in_aquarium_icon = 'icons/obj/aquarium.dmi'
dedicated_in_aquarium_icon = 'icons/obj/aquarium/fish.dmi'
dedicated_in_aquarium_icon_state = "mastodon_small"
base_pixel_x = -16
pixel_x = -16
Expand Down Expand Up @@ -612,3 +632,26 @@
return FALSE
target.apply_status_effect(/datum/status_effect/ice_block_talisman, freeze_timer SECONDS)
return FALSE

/obj/item/fish/zipzap
name = "anxious zipzap"
desc = "A fish overflowing with crippling anxiety and electric potential. Worried about the walls of its tank closing in constantly. Both literally and as a general metaphorical unease about life's direction."
icon_state = "zipzap"
icon_state_dead = "zipzap_dead"
sprite_width = 8
sprite_height = 8
stable_population = 3
average_size = 30
average_weight = 500
random_case_rarity = FISH_RARITY_VERY_RARE
favorite_bait = list(/obj/item/food/bait/doughball)
required_temperature_min = MIN_AQUARIUM_TEMP+18
required_temperature_max = MIN_AQUARIUM_TEMP+26
fish_traits = list(
/datum/fish_trait/no_mating,
/datum/fish_trait/wary,
/datum/fish_trait/anxiety,
/datum/fish_trait/electrogenesis,
)
//anxiety naturally limits the amount of zipzaps per tank, so they are stronger alone
electrogenesis_power = 20 MEGA JOULES
Loading

0 comments on commit 985b68d

Please sign in to comment.