mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 10:11:09 +00:00
You can release fish after catching it (#86126)
## About The Pull Request This PR nerfs the mood event from fishing from 5 to 4. In exchange, after catching a fish, you can release it in the appropriate fishing spot for a minor positive mood event (if it's alive, or if the user has either the morbid or naive traits). It also counts towards fish population for fish that are limited in the amount of times they can be catched. Mobs with the naive trait (clowns) get the positive mood event even if the fish is dead or being released in a bad place like lava Some fishing spots like toilets and moisture traps don't have this option, but that's because they've their own interactions with fish that'd otherwise be overridden by it. This PR also fixes mobs with the morbid trait (coroners) not enjoying aquarium in their own morbid ways and add a few touches pertaining the naive trait like alternative chat messages when interacting with the fish. ## Why It's Good For The Game This gives players a way to get rid of unwanted fish without leaving it to die on the floor, also it's in the spirit of recreational fishing. ## Changelog 🆑 fix: Fixed morbid mobs (coroners) not enjoying room beauty and aquariums in their own weird ways. add: You an now release fish after catching it for a positive moodlet (or to repopulate certain fishing spot with rare fish). /🆑 --------- Co-authored-by: necromanceranne <40847847+necromanceranne@users.noreply.github.com>
This commit is contained in:
@@ -33,6 +33,9 @@
|
||||
///From /obj/item/fish/update_fish_force: (weight_rank, bonus_malus)
|
||||
#define COMSIG_FISH_FORCE_UPDATED "fish_force_updated"
|
||||
|
||||
///From /obj/item/fish/interact_with_atom_secondary, sent to the target: (fish)
|
||||
#define COMSIG_FISH_RELEASED_INTO "fish_released_into"
|
||||
|
||||
/// Rolling a reward path for a fishing challenge
|
||||
#define COMSIG_FISHING_CHALLENGE_ROLL_REWARD "fishing_roll_reward"
|
||||
/// Adjusting the difficulty of a rishing challenge, often based on the reward path
|
||||
|
||||
@@ -231,6 +231,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
#define TRAIT_EXAMINE_FISHING_SPOT "examine_fishing_spot"
|
||||
///lobstrosities and carps will prioritize/flee from those that have this trait (given by the skill-locked hat)
|
||||
#define TRAIT_SCARY_FISHERMAN "scary_fisherman"
|
||||
/// Atoms with this trait can be right-clicked with a fish to release them, presumably back in the fishing spot they were caught from.
|
||||
#define TRAIT_CATCH_AND_RELEASE "catch_and_release"
|
||||
///This trait lets you get the size and weight of the fish by examining them
|
||||
#define TRAIT_EXAMINE_FISH "examine_fish"
|
||||
///This trait lets you roughly know if the fish is dead, starving, drowning or sick by examining them
|
||||
|
||||
@@ -10,6 +10,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_AI_PAUSED" = TRAIT_AI_PAUSED,
|
||||
"TRAIT_BANNED_FROM_CARGO_SHUTTLE" = TRAIT_BANNED_FROM_CARGO_SHUTTLE,
|
||||
"TRAIT_BEING_SHOCKED" = TRAIT_BEING_SHOCKED,
|
||||
"TRAIT_CATCH_AND_RELEASE" = TRAIT_CATCH_AND_RELEASE,
|
||||
"TRAIT_COMMISSIONED" = TRAIT_COMMISSIONED,
|
||||
"TRAIT_CLIMBABLE" = TRAIT_CLIMBABLE,
|
||||
"TRAIT_CURRENTLY_CLEANING" = TRAIT_CURRENTLY_CLEANING,
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
GLOBAL_LIST_INIT(admin_visible_traits, list(
|
||||
/atom = list(
|
||||
"TRAIT_UNHITTABLE_BY_PROJECTILES" = TRAIT_UNHITTABLE_BY_PROJECTILES,
|
||||
"TRAIT_CATCH_AND_RELEASE" = TRAIT_CATCH_AND_RELEASE,
|
||||
"TRAIT_KEEP_TOGETHER" = TRAIT_KEEP_TOGETHER,
|
||||
"TRAIT_UNHITTABLE_BY_PROJECTILES" = TRAIT_UNHITTABLE_BY_PROJECTILES,
|
||||
),
|
||||
/atom/movable = list(
|
||||
"TRAIT_ASHSTORM_IMMUNE" = TRAIT_ASHSTORM_IMMUNE,
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
RegisterSignal(parent, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_examined_more))
|
||||
RegisterSignal(parent, COMSIG_NPC_FISHING, PROC_REF(return_fishing_spot))
|
||||
RegisterSignal(parent, COMSIG_ATOM_EX_ACT, PROC_REF(explosive_fishing))
|
||||
RegisterSignal(parent, COMSIG_FISH_RELEASED_INTO, PROC_REF(fish_released))
|
||||
ADD_TRAIT(parent, TRAIT_FISHING_SPOT, REF(src))
|
||||
|
||||
/datum/component/fishing_spot/Destroy()
|
||||
@@ -82,3 +83,7 @@
|
||||
/datum/component/fishing_spot/proc/explosive_fishing(atom/location, severity)
|
||||
SIGNAL_HANDLER
|
||||
fish_source.spawn_reward_from_explosion(location, severity)
|
||||
|
||||
/datum/component/fishing_spot/proc/fish_released(datum/source, obj/item/fish/fish, mob/living/releaser)
|
||||
SIGNAL_HANDLER
|
||||
fish_source.readd_fish(fish, releaser)
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
for(var/mob/living/living in location)
|
||||
living.update_turf_movespeed()
|
||||
|
||||
/// Signals and components are carried over when the turf is changed, so they've to be readded post-change.
|
||||
/// Signals are carried over when the turf is changed, but traits aren't, so they've to be readded post-change.
|
||||
/datum/element/give_turf_traits/proc/pre_change_turf(turf/changed, path, list/new_baseturfs, flags, list/post_change_callbacks)
|
||||
SIGNAL_HANDLER
|
||||
post_change_callbacks += CALLBACK(src, PROC_REF(reoccupy_turf))
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined))
|
||||
RegisterSignal(target, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_examined_more))
|
||||
RegisterSignal(target, COMSIG_ATOM_EX_ACT, PROC_REF(explosive_fishing))
|
||||
RegisterSignal(target, COMSIG_FISH_RELEASED_INTO, PROC_REF(fish_released))
|
||||
|
||||
/datum/element/lazy_fishing_spot/Detach(datum/target)
|
||||
UnregisterSignal(target, list(
|
||||
COMSIG_FISH_RELEASED_INTO,
|
||||
COMSIG_PRE_FISHING,
|
||||
COMSIG_NPC_FISHING,
|
||||
COMSIG_ATOM_EXAMINE,
|
||||
@@ -66,3 +68,8 @@
|
||||
|
||||
/datum/element/lazy_fishing_spot/proc/return_glob_fishing_spot(datum/source, list/fish_spot_container)
|
||||
fish_spot_container[NPC_FISHING_SPOT] = GLOB.preset_fish_sources[configuration]
|
||||
|
||||
/datum/element/lazy_fishing_spot/proc/fish_released(datum/source, obj/item/fish/fish, mob/living/releaser)
|
||||
SIGNAL_HANDLER
|
||||
var/datum/fish_source/fish_source = GLOB.preset_fish_sources[configuration]
|
||||
fish_source.readd_fish(fish, releaser)
|
||||
|
||||
@@ -406,7 +406,7 @@
|
||||
clear_mood_event(MOOD_CATEGORY_AREA_BEAUTY)
|
||||
return
|
||||
|
||||
if(HAS_TRAIT(mob_parent, TRAIT_MORBID))
|
||||
if(HAS_MIND_TRAIT(mob_parent, TRAIT_MORBID))
|
||||
if(HAS_TRAIT(mob_parent, TRAIT_SNOB))
|
||||
switch(area_to_beautify.beauty)
|
||||
if(BEAUTY_LEVEL_DECENT to BEAUTY_LEVEL_GOOD)
|
||||
|
||||
@@ -333,9 +333,23 @@
|
||||
|
||||
/datum/mood_event/fishing
|
||||
description = "Fishing is relaxing."
|
||||
mood_change = 5
|
||||
mood_change = 4
|
||||
timeout = 3 MINUTES
|
||||
|
||||
/datum/mood_event/fish_released
|
||||
description = "Go, fish, swim and be free!"
|
||||
mood_change = 1
|
||||
timeout = 2 MINUTES
|
||||
|
||||
/datum/mood_event/fish_released/add_effects(morbid, obj/item/fish/fish)
|
||||
if(!morbid)
|
||||
description = "Go, [fish.name], swim and be free!"
|
||||
return
|
||||
if(fish.status == FISH_DEAD)
|
||||
description = "Some scavenger will surely find a use for the remains of [fish.name]. How pragmatic."
|
||||
else
|
||||
description = "Returned to the burden of the deep. But is this truly a mercy, [fish.name]? There will always be bigger fish..."
|
||||
|
||||
/datum/mood_event/kobun
|
||||
description = "You are all loved by the Universe. I’m not alone, and you aren’t either."
|
||||
mood_change = 14
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
return NONE
|
||||
balloon_alert(user, "dug hole")
|
||||
AddComponent(/datum/component/fishing_spot, GLOB.preset_fish_sources[/datum/fish_source/ice_fishing])
|
||||
ADD_TRAIT(src, TRAIT_CATCH_AND_RELEASE, INNATE_TRAIT)
|
||||
add_overlay(mutable_appearance('icons/turf/overlays.dmi', "ice_hole"))
|
||||
can_make_hole = FALSE
|
||||
RemoveElement(/datum/element/contextual_screentip_tools, tool_screentips)
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
. = ..()
|
||||
if(fish_source_type)
|
||||
AddElement(/datum/element/lazy_fishing_spot, fish_source_type)
|
||||
// You can release chrabs and lavaloops and likes in lava, or be an absolute scumbag and drop other fish there too.
|
||||
ADD_TRAIT(src, TRAIT_CATCH_AND_RELEASE, INNATE_TRAIT)
|
||||
refresh_light()
|
||||
if(!smoothing_flags)
|
||||
update_appearance()
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
AddElement(/datum/element/watery_tile)
|
||||
if(!isnull(fishing_datum))
|
||||
AddElement(/datum/element/lazy_fishing_spot, fishing_datum)
|
||||
ADD_TRAIT(src, TRAIT_CATCH_AND_RELEASE, INNATE_TRAIT)
|
||||
|
||||
/turf/open/water/jungle
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@
|
||||
else
|
||||
dead_fish++
|
||||
|
||||
var/morb = HAS_TRAIT(user, TRAIT_MORBID)
|
||||
var/morb = HAS_MIND_TRAIT(user, TRAIT_MORBID)
|
||||
//Check if there are live fish - good mood
|
||||
//All fish dead - bad mood.
|
||||
//No fish - nothing.
|
||||
|
||||
@@ -181,6 +181,34 @@
|
||||
update_size_and_weight()
|
||||
|
||||
register_evolutions()
|
||||
register_item_context()
|
||||
|
||||
/obj/item/fish/add_context(atom/source, list/context, obj/item/held_item, mob/user)
|
||||
if(HAS_TRAIT(source, TRAIT_CATCH_AND_RELEASE))
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Release"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
return NONE
|
||||
|
||||
/obj/item/fish/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
|
||||
if(!HAS_TRAIT(interacting_with, TRAIT_CATCH_AND_RELEASE))
|
||||
return NONE
|
||||
if(HAS_TRAIT(src, TRAIT_NODROP))
|
||||
balloon_alert(user, "it's stuck to your hand!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
balloon_alert(user, "releasing fish...")
|
||||
if(!do_after(src, 3 SECONDS, interacting_with))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
balloon_alert(user, "fish released")
|
||||
var/goodbye_text = "Bye bye [name]."
|
||||
if(status == FISH_DEAD && !HAS_MIND_TRAIT(user, TRAIT_NAIVE))
|
||||
goodbye_text = "May it rest in peace..."
|
||||
user.visible_message(span_notice("[user] releases [src] into [interacting_with]"), \
|
||||
span_notice("You release [src] into [interacting_with]. [goodbye_text]"), \
|
||||
span_notice("You hear a splash."))
|
||||
playsound(interacting_with, 'sound/effects/splash.ogg', 50)
|
||||
SEND_SIGNAL(interacting_with, COMSIG_FISH_RELEASED_INTO, src)
|
||||
qdel(src)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
///Main proc that makes the fish edible.
|
||||
/obj/item/fish/proc/make_edible()
|
||||
@@ -361,29 +389,30 @@
|
||||
if(!istype(item, /obj/item/fish_feed))
|
||||
return ..()
|
||||
if(!item.reagents.total_volume)
|
||||
balloon_alert(user, "[item] is empty!")
|
||||
balloon_alert(user, "[item.name] is empty!")
|
||||
return TRUE
|
||||
if(status == FISH_DEAD)
|
||||
balloon_alert(user, "[src] is dead!")
|
||||
balloon_alert(user, "[name] [HAS_MIND_TRAIT(user, TRAIT_NAIVE) ? "isn't hungry" : "is dead!"]")
|
||||
return TRUE
|
||||
feed(item.reagents)
|
||||
balloon_alert(user, "fed [src]")
|
||||
balloon_alert(user, "fed [name]")
|
||||
return TRUE
|
||||
|
||||
/obj/item/fish/examine(mob/user)
|
||||
. = ..()
|
||||
if(HAS_MIND_TRAIT(user, TRAIT_EXAMINE_DEEPER_FISH))
|
||||
if(status == FISH_DEAD)
|
||||
. += span_deadsay("it's dead.")
|
||||
var/list/warnings = list()
|
||||
if(is_hungry())
|
||||
warnings += "starving"
|
||||
if(!HAS_TRAIT(src, TRAIT_FISH_STASIS) && !proper_environment())
|
||||
warnings += "drowning"
|
||||
if(health < initial(health) * 0.6)
|
||||
warnings += "sick"
|
||||
if(length(warnings))
|
||||
. += span_warning("it's [english_list(warnings)]")
|
||||
. += span_deadsay("It's [HAS_MIND_TRAIT(user, TRAIT_NAIVE) ? "taking the big snooze" : "dead"].")
|
||||
else
|
||||
var/list/warnings = list()
|
||||
if(is_hungry())
|
||||
warnings += "starving"
|
||||
if(!HAS_TRAIT(src, TRAIT_FISH_STASIS) && !proper_environment())
|
||||
warnings += "drowning"
|
||||
if(health < initial(health) * 0.6)
|
||||
warnings += "sick"
|
||||
if(length(warnings))
|
||||
. += span_warning("It's [english_list(warnings)].")
|
||||
if(HAS_MIND_TRAIT(user, TRAIT_EXAMINE_FISH))
|
||||
. += span_notice("It's [size] cm long.")
|
||||
. += span_notice("It weighs [weight] g.")
|
||||
|
||||
@@ -53,12 +53,14 @@
|
||||
|
||||
/obj/machinery/fishing_portal_generator/proc/activate(datum/fish_source/selected_source)
|
||||
active = AddComponent(/datum/component/fishing_spot, selected_source)
|
||||
ADD_TRAIT(src, TRAIT_CATCH_AND_RELEASE, INNATE_TRAIT)
|
||||
use_power = ACTIVE_POWER_USE
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/fishing_portal_generator/proc/deactivate()
|
||||
QDEL_NULL(active)
|
||||
use_power = IDLE_POWER_USE
|
||||
REMOVE_TRAIT(src, TRAIT_CATCH_AND_RELEASE, INNATE_TRAIT)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/fishing_portal_generator/on_set_is_operational(old_value)
|
||||
|
||||
@@ -220,7 +220,7 @@
|
||||
return BEAM_CANCEL_DRAW
|
||||
|
||||
/obj/item/fishing_rod/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
|
||||
//this prevent trying to use telekinesis to fish (which would be broken anyway)
|
||||
//this prevent trying to use telekinesis to fish (which would be broken anyway), also whacking people with a rod.
|
||||
if(!user.contains(src) || (user.combat_mode && !isturf(interacting_with)) ||HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION))
|
||||
return ..()
|
||||
return ranged_interact_with_atom(interacting_with, user, modifiers)
|
||||
|
||||
@@ -275,13 +275,16 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons())
|
||||
SEND_SIGNAL(src, COMSIG_FISH_SOURCE_REWARD_DISPENSED, reward)
|
||||
return reward
|
||||
|
||||
/datum/fish_source/proc/regen_count(reward_path, regen_time)
|
||||
/datum/fish_source/proc/regen_count(reward_path)
|
||||
if(!LAZYACCESS(currently_on_regen, reward_path))
|
||||
return
|
||||
fish_counts[reward_path] += 1
|
||||
currently_on_regen[reward_path] -= 1
|
||||
if(!currently_on_regen[reward_path])
|
||||
if(currently_on_regen[reward_path] <= 0)
|
||||
LAZYREMOVE(currently_on_regen, reward_path)
|
||||
else
|
||||
addtimer(CALLBACK(src, PROC_REF(regen_count), reward_path), regen_time)
|
||||
return
|
||||
var/regen_time = fish_count_regen[reward_path]
|
||||
addtimer(CALLBACK(src, PROC_REF(regen_count), reward_path), regen_time)
|
||||
|
||||
/// Spawns a reward from a atom path right where the fisherman is. Part of the dispense_reward() logic.
|
||||
/datum/fish_source/proc/spawn_reward(reward_path, atom/spawn_location, turf/fishing_spot)
|
||||
@@ -464,6 +467,24 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons())
|
||||
if(severity >= EXPLODE_DEVASTATE)
|
||||
reward.ex_act(EXPLODE_LIGHT)
|
||||
|
||||
///Called when releasing a fish in a fishing spot with the TRAIT_CATCH_AND_RELEASE trait.
|
||||
/datum/fish_source/proc/readd_fish(obj/item/fish/fish, mob/living/releaser)
|
||||
var/is_morbid = HAS_MIND_TRAIT(releaser, TRAIT_MORBID)
|
||||
var/is_naive = HAS_MIND_TRAIT(releaser, TRAIT_NAIVE)
|
||||
if(fish.status == FISH_DEAD) //ded fish won't repopulate the sea.
|
||||
if(is_naive || is_morbid)
|
||||
releaser.add_mood_event("fish_released", /datum/mood_event/fish_released, is_morbid && !is_naive, fish)
|
||||
return
|
||||
if(((fish.type in fish_table) != is_morbid) || is_naive)
|
||||
releaser.add_mood_event("fish_released", /datum/mood_event/fish_released, is_morbid && !is_naive, fish)
|
||||
if(isnull(fish_counts[fish.type])) //This fish can be caught indefinitely so it won't matter.
|
||||
return
|
||||
//If this fish population isn't recovering from recent losses, we just increase it.
|
||||
if(!LAZYACCESS(currently_on_regen, fish.type))
|
||||
fish_counts[fish.type] += 1
|
||||
else
|
||||
regen_count(fish.type)
|
||||
|
||||
/**
|
||||
* Called by /datum/autowiki/fish_sources unless the catalog entry for this fish source is null.
|
||||
* It should Return a list of entries with keys named "name", "icon", "weight" and "notes"
|
||||
|
||||
Reference in New Issue
Block a user