You can now link fishing portal generators to other fishing spots. (#86291)

## About The Pull Request
You can now interact with the fishing portal generator with a multitool
to load it in the buffer and subsequently link fishing spots to it by
tapping them with the same multitool. The maximum number of fishing
spots that can be linked at once depends on the tier of the matter bins
of the machinery. Normally, while you can link fishing spots from other
z-levels, they can only be activated if they're on the same z-level as
the machinery (or if both are on station for multi-z stations). This
limitation can be bypassed by upgrading the machinery with a tier 3 or
higher capacitator.

While it's possible, I'm not spriting new fishing portal overlays and
icons for the radial menu for every fish source out there (yet). The
code is enough work for now.

This also comes with a unit test, because there is no such thing as too
many unit tests for fishing.

## Why It's Good For The Game
Fish portal generators are designed to let players fish a different
bunch of things while being able to be moved wherever you like, unlike a
lake or an ocean, with all the comfort of being able to able to catch
fish from distant locations. Allowing players to link other fishing
spots to it fits its design. It also means that you can go out and
explore, find more fishing spots and then return to the station without
having to detach yourself from the ongoing round for several more
minutes.

## Changelog

🆑
add: You can now link fishing portal generators to other fishing spots
with a multitool. The number of fishing spots that can be linked at once
and whether the link can be activated from different z levels depends on
the tier of the stock parts it's built with.
/🆑

---------

Co-authored-by: Emmett Gaines <ninjanomnom@gmail.com>
This commit is contained in:
Ghom
2024-09-18 16:14:04 +02:00
committed by GitHub
parent 4687b1725a
commit 1aad3e118c
12 changed files with 291 additions and 16 deletions
@@ -194,6 +194,8 @@
#define COMSIG_TOOL_IN_USE "tool_in_use"
///from base of [/obj/item/proc/tool_start_check]: (mob/living/user)
#define COMSIG_TOOL_START_USE "tool_start_use"
/// From /obj/item/multitool/remove_buffer(): (buffer)
#define COMSIG_MULTITOOL_REMOVE_BUFFER "multitool_remove_buffer"
///from [/obj/item/proc/disableEmbedding]:
#define COMSIG_ITEM_DISABLE_EMBED "item_disable_embed"
///from [/obj/effect/mine/proc/triggermine]:
+2
View File
@@ -239,6 +239,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_EXAMINE_DEEPER_FISH "examine_deeper_fish"
///Trait given to turfs or objects that can be fished from
#define TRAIT_FISHING_SPOT "fishing_spot"
///This trait prevents the fishing spot from being linked to the fish-porter when a multitool is being used.
#define TRAIT_UNLINKABLE_FISHING_SPOT "unlinkable_fishing_spot"
///Trait given to mobs that can fish without a rod
#define TRAIT_PROFOUND_FISHER "profound_fisher"
/// If an atom has this trait, then you can toss a bottle with a message in it.
+2 -1
View File
@@ -18,6 +18,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_DO_NOT_SPLASH" = TRAIT_DO_NOT_SPLASH,
"TRAIT_DRIED" = TRAIT_DRIED,
"TRAIT_DRYABLE" = TRAIT_DRYABLE,
"TRAIT_FISHING_SPOT" = TRAIT_FISHING_SPOT,
"TRAIT_FOOD_CHEF_MADE" = TRAIT_FOOD_CHEF_MADE,
"TRAIT_FOOD_FRIED" = TRAIT_FOOD_FRIED,
"TRAIT_QUALITY_FOOD_INGREDIENT" = TRAIT_QUALITY_FOOD_INGREDIENT,
@@ -30,6 +31,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_SPINNING" = TRAIT_SPINNING,
"TRAIT_STICKERED" = TRAIT_STICKERED,
"TRAIT_UNHITTABLE_BY_PROJECTILES" = TRAIT_UNHITTABLE_BY_PROJECTILES,
"TRAIT_UNLINKABLE_FISHING_SPOT" = TRAIT_UNLINKABLE_FISHING_SPOT,
),
/atom/movable = list(
"TRAIT_ACTIVE_STORAGE" = TRAIT_ACTIVE_STORAGE,
@@ -676,7 +678,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_CONTAINMENT_FIELD" = TRAIT_CONTAINMENT_FIELD,
"TRAIT_ELEVATED_TURF" = TRAIT_ELEVATED_TURF,
"TRAIT_FIREDOOR_STOP" = TRAIT_FIREDOOR_STOP,
"TRAIT_FISHING_SPOT" = TRAIT_FISHING_SPOT,
"TRAIT_HYPERSPACE_STOPPED" = TRAIT_HYPERSPACE_STOPPED,
"TRAIT_IMMERSE_STOPPED" = TRAIT_IMMERSE_STOPPED,
"TRAIT_LAVA_STOPPED" = TRAIT_LAVA_STOPPED,
+8
View File
@@ -20,9 +20,11 @@
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))
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(link_to_fish_porter))
ADD_TRAIT(parent, TRAIT_FISHING_SPOT, REF(src))
/datum/component/fishing_spot/Destroy()
REMOVE_TRAIT(parent, TRAIT_FISHING_SPOT, REF(src))
fish_source.on_fishing_spot_del(src)
fish_source = null
REMOVE_TRAIT(parent, TRAIT_FISHING_SPOT, REF(src))
@@ -84,6 +86,12 @@
SIGNAL_HANDLER
fish_source.spawn_reward_from_explosion(location, severity)
/datum/component/fishing_spot/proc/link_to_fish_porter(atom/source, mob/user, obj/item/multitool/tool)
SIGNAL_HANDLER
if(istype(tool.buffer, /obj/machinery/fishing_portal_generator))
var/obj/machinery/fishing_portal_generator/portal = tool.buffer
return portal.link_fishing_spot(fish_source, source, user)
/datum/component/fishing_spot/proc/fish_released(datum/source, obj/item/fish/fish, mob/living/releaser)
SIGNAL_HANDLER
fish_source.readd_fish(fish, releaser)
+10
View File
@@ -21,6 +21,7 @@
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))
RegisterSignal(target, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(link_to_fish_porter))
/datum/element/lazy_fishing_spot/Detach(datum/target)
UnregisterSignal(target, list(
@@ -30,6 +31,7 @@
COMSIG_ATOM_EXAMINE,
COMSIG_ATOM_EXAMINE_MORE,
COMSIG_ATOM_EX_ACT,
COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL),
))
REMOVE_TRAIT(target, TRAIT_FISHING_SPOT, REF(src))
return ..()
@@ -69,6 +71,14 @@
/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/link_to_fish_porter(atom/source, mob/user, obj/item/multitool/tool)
SIGNAL_HANDLER
if(!istype(tool.buffer, /obj/machinery/fishing_portal_generator))
return
var/datum/fish_source/fish_source = GLOB.preset_fish_sources[configuration]
var/obj/machinery/fishing_portal_generator/portal = tool.buffer
return portal.link_fishing_spot(fish_source, source, user)
/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]
+9 -2
View File
@@ -35,6 +35,11 @@
var/apc_scanner = TRUE
COOLDOWN_DECLARE(next_apc_scan)
/obj/item/multitool/Destroy()
if(buffer)
remove_buffer(buffer)
return ..()
/obj/item/multitool/examine(mob/user)
. = ..()
. += span_notice("Its buffer [buffer ? "contains [buffer]." : "is empty."]")
@@ -70,9 +75,10 @@
/obj/item/multitool/proc/set_buffer(datum/buffer)
if(src.buffer)
UnregisterSignal(src.buffer, COMSIG_QDELETING)
remove_buffer(src.buffer)
src.buffer = buffer
if(!QDELETED(buffer))
RegisterSignal(buffer, COMSIG_QDELETING, PROC_REF(on_buffer_del))
RegisterSignal(buffer, COMSIG_QDELETING, PROC_REF(remove_buffer))
/**
* Called when the buffer's stored object is deleted
@@ -80,8 +86,9 @@
* This proc does not clear the buffer of the multitool, it is here to
* handle the deletion of the object the buffer references
*/
/obj/item/multitool/proc/on_buffer_del(datum/source)
/obj/item/multitool/proc/remove_buffer(datum/source)
SIGNAL_HANDLER
SEND_SIGNAL(src, COMSIG_MULTITOOL_REMOVE_BUFFER, source)
buffer = null
// Syndicate device disguised as a multitool; it will turn red when an AI camera is nearby.
+197 -9
View File
@@ -11,6 +11,46 @@
///The current fishing spot loaded in
var/datum/component/fishing_spot/active
///A list of fishing spot it's linked to with a multitool.
var/list/linked_fishing_spots
///The maximum number of fishing spots it can be linked to
var/max_fishing_spots = 1
///If true, the fishing portal can stay connected to a linked fishing spot even on different z-levels
var/long_range_link = FALSE
/obj/machinery/fishing_portal_generator/Initialize(mapload)
. = ..()
var/static/list/tool_screentips = list(
TOOL_MULTITOOL = list(
SCREENTIP_CONTEXT_LMB = "Link",
SCREENTIP_CONTEXT_RMB = "Unlink fishing spots"
),
)
AddElement(/datum/element/contextual_screentip_tools, tool_screentips)
ADD_TRAIT(src, TRAIT_UNLINKABLE_FISHING_SPOT, INNATE_TRAIT)
/obj/machinery/fishing_portal_generator/Destroy()
deactivate()
linked_fishing_spots = null
return ..()
///Higher tier parts let you link to more fishing spots at once and eventually let you connect through different zlevels.
/obj/machinery/fishing_portal_generator/RefreshParts()
. = ..()
max_fishing_spots = 0
long_range_link = FALSE
for(var/datum/stock_part/matter_bin/matter_bin in component_parts)
max_fishing_spots += matter_bin.tier * 0.5
max_fishing_spots = ROUND_UP(max_fishing_spots)
for(var/datum/stock_part/capacitor/capacitor in component_parts)
if(capacitor.tier >= 3)
long_range_link = TRUE
if(!long_range_link)
check_fishing_spot_z()
if(length(linked_fishing_spots) > max_fishing_spots)
if(active)
deactivate()
linked_fishing_spots.len = max_fishing_spots
/obj/machinery/fishing_portal_generator/on_set_panel_open()
update_appearance()
@@ -21,9 +61,94 @@
default_unfasten_wrench(user, tool)
return ITEM_INTERACT_SUCCESS
/obj/machinery/fishing_portal_generator/multitool_act(mob/living/user, obj/item/multitool/tool)
if(machine_stat & NOPOWER)
balloon_alert(user, "no power!")
return ITEM_INTERACT_BLOCKING
var/unlink = tool.buffer == src
tool.set_buffer(unlink ? null : src)
balloon_alert(user, "fish-porter [unlink ? "un" : ""]linked")
if(!unlink)
tool.item_flags |= ITEM_HAS_CONTEXTUAL_SCREENTIPS
RegisterSignal(tool, COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET, PROC_REF(multitool_context))
RegisterSignal(tool, COMSIG_MULTITOOL_REMOVE_BUFFER, PROC_REF(multitool_unbuffered))
return ITEM_INTERACT_SUCCESS
/obj/machinery/fishing_portal_generator/multitool_act_secondary(mob/living/user, obj/item/tool)
if(machine_stat & NOPOWER)
balloon_alert(user, "no power!")
return ITEM_INTERACT_BLOCKING
if(!length(linked_fishing_spots))
balloon_alert(user, "nothing to unlink!")
return ITEM_INTERACT_BLOCKING
var/list/fishing_list = list()
var/id = 1
for(var/atom/spot as anything in linked_fishing_spots)
var/choice_name = "[spot.name] ([id])"
fishing_list[choice_name] = spot
id++
var/list/choices = list()
for(var/radial_name in fishing_list)
var/datum/fish_source/source = fishing_list[radial_name]
var/mutable_appearance/appearance = mutable_appearance('icons/hud/radial_fishing.dmi', source.radial_state)
appearance.add_overlay('icons/hud/radial_fishing.dmi', "minus_sign")
choices[radial_name] = appearance
var/choice = show_radial_menu(user, src, choices, radius = 38, custom_check = CALLBACK(src, TYPE_PROC_REF(/atom, can_interact), user), tooltips = TRUE)
if(!choice)
return
var/atom/spot = fishing_list[choice]
if(QDELETED(spot) || !(spot in linked_fishing_spots) || !can_interact(user))
return
unlink_fishing_spot(spot)
balloon_alert(user, "fishing spot unlinked")
/obj/machinery/fishing_portal_generator/proc/multitool_context(obj/item/source, list/context, atom/target, mob/living/user)
SIGNAL_HANDLER
if(HAS_TRAIT(target, TRAIT_FISHING_SPOT) && !HAS_TRAIT(target, TRAIT_UNLINKABLE_FISHING_SPOT))
context[SCREENTIP_CONTEXT_LMB] = "Link to fish-porter"
return CONTEXTUAL_SCREENTIP_SET
return NONE
/obj/machinery/fishing_portal_generator/proc/multitool_unbuffered(datum/source, datum/buffer)
SIGNAL_HANDLER
UnregisterSignal(source, list(COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET, COMSIG_MULTITOOL_REMOVE_BUFFER))
///Called when using a multitool on any other fishing source.
/obj/machinery/fishing_portal_generator/proc/link_fishing_spot(datum/fish_source/source, atom/spot, mob/living/user)
if(istype(spot, /obj/machinery/fishing_portal_generator)) //Don't link it to itself or other fishing portals.
return
if(length(linked_fishing_spots) >= max_fishing_spots)
spot.balloon_alert(user, "cannot link more!")
return ITEM_INTERACT_BLOCKING
for(var/other_spot in linked_fishing_spots)
var/datum/fish_source/stored = linked_fishing_spots[other_spot]
if(stored == source)
spot.balloon_alert(user, "already linked!")
playsound(src, 'sound/machines/buzz-sigh.ogg', 15, FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE)
return ITEM_INTERACT_BLOCKING
if(HAS_TRAIT(spot, TRAIT_UNLINKABLE_FISHING_SPOT))
spot.balloon_alert(user, "unlinkable fishing spot!")
playsound(src, 'sound/machines/buzz-sigh.ogg', 15, FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE)
return ITEM_INTERACT_BLOCKING
LAZYSET(linked_fishing_spots, spot, source)
RegisterSignal(spot, SIGNAL_REMOVETRAIT(TRAIT_FISHING_SPOT), PROC_REF(unlink_fishing_spot))
spot.balloon_alert(user, "fishing spot linked")
playsound(spot, 'sound/machines/ping.ogg', 15, TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE)
return ITEM_INTERACT_SUCCESS
/obj/machinery/fishing_portal_generator/proc/unlink_fishing_spot(atom/spot)
SIGNAL_HANDLER
var/datum/fish_source/source = linked_fishing_spots[spot]
if(active?.fish_source == source)
deactivate()
LAZYREMOVE(linked_fishing_spots, spot)
UnregisterSignal(spot, SIGNAL_REMOVETRAIT(TRAIT_FISHING_SPOT))
/obj/machinery/fishing_portal_generator/examine(mob/user)
. = ..()
. += span_notice("You can unlock further portal settings by completing fish scanning experiments.")
. += span_notice("You can unlock further portal settings by completing fish scanning experiments, \
or by connecting it to other fishing spots with a multitool.")
/obj/machinery/fishing_portal_generator/emag_act(mob/user, obj/item/card/emag/emag_card)
if(obj_flags & EMAGGED)
@@ -47,21 +172,78 @@
if(!active)
return
. += "portal_on"
var/datum/fish_source/portal/portal = active.fish_source
var/datum/fish_source/portal = active.fish_source
. += portal.overlay_state
. += emissive_appearance(icon, "portal_emissive", src)
/obj/machinery/fishing_portal_generator/proc/activate(datum/fish_source/selected_source)
/obj/machinery/fishing_portal_generator/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
. = ..()
check_fishing_spot_z()
/obj/machinery/fishing_portal_generator/proc/check_fishing_spot_z()
if(!active || long_range_link || istype(active.fish_source, /datum/fish_source/portal))
return
var/turf/new_turf = get_turf(src)
if(!new_turf)
deactivate()
return
for(var/atom/spot as anything in linked_fishing_spots)
if(linked_fishing_spots[spot] != active.fish_source)
continue
var/turf/turf = get_turf(spot)
if(turf.z != new_turf.z && !(is_station_level(turf.z) && is_station_level(new_turf.z)))
deactivate()
/obj/machinery/fishing_portal_generator/proc/activate(datum/fish_source/selected_source, mob/user)
if(QDELETED(selected_source))
return
if(machine_stat & NOPOWER)
balloon_alert(user, "no power!")
return ITEM_INTERACT_BLOCKING
if(!istype(selected_source, /datum/fish_source/portal)) //likely from a linked fishing spot
var/abort = TRUE
for(var/atom/spot as anything in linked_fishing_spots)
if(linked_fishing_spots[spot] != selected_source)
continue
if(long_range_link)
abort = FALSE
var/turf/spot_turf = get_turf(spot)
var/turf/turf = get_turf(src)
if(turf.z == spot_turf.z || (is_station_level(turf.z) && is_station_level(spot_turf.z)))
abort = FALSE
if(!abort)
RegisterSignal(spot, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_fishing_spot_z_level_changed))
break
if(abort)
balloon_alert(user, "cannot reach linked!")
return
active = AddComponent(/datum/component/fishing_spot, selected_source)
ADD_TRAIT(src, TRAIT_CATCH_AND_RELEASE, INNATE_TRAIT)
use_power = ACTIVE_POWER_USE
if(use_power != NO_POWER_USE)
use_power = ACTIVE_POWER_USE
update_icon()
/obj/machinery/fishing_portal_generator/proc/deactivate()
if(!active)
return
if(!istype(active.fish_source, /datum/fish_source/portal))
for(var/atom/spot as anything in linked_fishing_spots)
if(linked_fishing_spots[spot] == active.fish_source)
UnregisterSignal(spot, COMSIG_MOVABLE_Z_CHANGED)
QDEL_NULL(active)
use_power = IDLE_POWER_USE
REMOVE_TRAIT(src, TRAIT_CATCH_AND_RELEASE, INNATE_TRAIT)
update_icon()
if(!QDELETED(src))
if(use_power != NO_POWER_USE)
use_power = IDLE_POWER_USE
update_icon()
/obj/machinery/fishing_portal_generator/proc/on_fishing_spot_z_level_changed(atom/spot, turf/old_turf, turf/new_turf, same_z_layer)
SIGNAL_HANDLER
var/turf/turf = get_turf(src)
if(turf.z != new_turf.z && !(is_station_level(turf.z) && is_station_level(new_turf.z)))
deactivate()
/obj/machinery/fishing_portal_generator/on_set_is_operational(old_value)
if(old_value)
@@ -90,18 +272,24 @@
var/datum/fish_source/portal/reward = GLOB.preset_fish_sources[experiment.fish_source_reward]
available_fish_sources[reward.radial_name] = reward
var/id = 1
for(var/atom/spot as anything in linked_fishing_spots)
var/choice_name = "[spot.name] ([id])"
available_fish_sources[choice_name] = linked_fishing_spots[spot]
id++
if(length(available_fish_sources) == 1)
activate(default)
activate(default, user)
return
var/list/choices = list()
for(var/radial_name in available_fish_sources)
var/datum/fish_source/portal/source = available_fish_sources[radial_name]
var/datum/fish_source/source = available_fish_sources[radial_name]
choices[radial_name] = image(icon = 'icons/hud/radial_fishing.dmi', icon_state = source.radial_state)
var/choice = show_radial_menu(user, src, choices, radius = 38, custom_check = CALLBACK(src, TYPE_PROC_REF(/atom, can_interact), user), tooltips = TRUE)
if(!choice || !can_interact(user))
return
activate(available_fish_sources[choice])
activate(available_fish_sources[choice], user)
/obj/machinery/fishing_portal_generator/emagged
obj_flags = parent_type::obj_flags | EMAGGED
@@ -82,6 +82,10 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons())
var/explosive_malus = FALSE
/// If explosive_malus is true, this will be used to keep track of the turfs where an explosion happened for when we'll spawn the loot.
var/list/exploded_turfs
///When linked to a fishing portal, this will be the icon_state of this option in the radial menu
var/radial_state = "default"
///When selected by the fishing portal, this will be the icon_state of the overlay shown on the machine.
var/overlay_state = "portal_aquarium"
/// Mindless mobs that can fish will never pull up items on this list
var/static/list/profound_fisher_blacklist = typecacheof(list(
/mob/living/basic/mining/lobstrosity,
+7 -4
View File
@@ -106,12 +106,9 @@
/obj/item/fish/goldfish/three_eyes = 3,
)
catalog_description = "Aquarium dimension (Fishing portal generator)"
radial_state = "fish_tank"
///The name of this option shown in the radial menu on the fishing portal generator
var/radial_name = "Aquarium"
///The icon state shown for this option in the radial menu
var/radial_state = "fish_tank"
///The icon state of the overlay shown on the machine when active.
var/overlay_state = "portal_aquarium"
/datum/fish_source/portal/beach
fish_table = list(
@@ -404,6 +401,12 @@
)
fishing_difficulty = FISHING_EASY_DIFFICULTY
/datum/fish_source/holographic/on_fishing_spot_init(datum/component/fishing_spot/spot)
ADD_TRAIT(spot.parent, TRAIT_UNLINKABLE_FISHING_SPOT, REF(src)) //You would have to be inside the holodeck anyway...
/datum/fish_source/holographic/on_fishing_spot_del(datum/component/fishing_spot/spot)
REMOVE_TRAIT(spot.parent, TRAIT_UNLINKABLE_FISHING_SPOT, REF(src))
/datum/fish_source/holographic/generate_wiki_contents(datum/autowiki/fish_sources/wiki)
var/obj/item/fish/prototype = /obj/item/fish/holo/checkered
return LIST_VALUE_WRAP_LISTS(list(
@@ -190,6 +190,54 @@
. = ..()
probability = 0 //works around the global list initialization skipping abstract/impossible evolutions.
///A test that checks that fishing portals can be linked and function as expected
/datum/unit_test/fish_portal_gen_linking
/datum/unit_test/fish_portal_gen_linking/Run()
var/mob/living/carbon/human/consistent/user = allocate(/mob/living/carbon/human/consistent)
var/obj/machinery/fishing_portal_generator/portal = allocate(/obj/machinery/fishing_portal_generator/no_power)
var/obj/structure/toilet/unit_test/fishing_spot = new(get_turf(user)) //This is deleted during the test
var/obj/structure/moisture_trap/extra_spot = allocate(/obj/structure/moisture_trap)
var/obj/machinery/hydroponics/constructable/inaccessible = allocate(/obj/machinery/hydroponics/constructable)
ADD_TRAIT(inaccessible, TRAIT_UNLINKABLE_FISHING_SPOT, INNATE_TRAIT)
var/obj/item/multitool/tool = allocate(/obj/item/multitool)
var/datum/fish_source/toilet/fish_source = GLOB.preset_fish_sources[/datum/fish_source/toilet]
portal.max_fishing_spots = 1 //We've no scrying orb to know if it'll be buffed or nerfed this in the future. We only have space for one here.
portal.activate(fish_source, user)
TEST_ASSERT(!portal.active, "[portal] was activated with a fish source from an unlinked fishing spot")
portal.multitool_act(user, tool)
TEST_ASSERT_EQUAL(tool.buffer, portal, "[portal] wasn't set as buffer for [tool]")
tool.melee_attack_chain(user, fishing_spot)
TEST_ASSERT_EQUAL(LAZYACCESS(portal.linked_fishing_spots, fishing_spot), fish_source, "We tried linking [portal] to the fishing spot but didn't succeed.")
portal.activate(fish_source, user)
TEST_ASSERT(portal.active?.fish_source == fish_source, "[portal] can't acces a fish source from a linked fishing spot")
//Let's move the fishing spot away. This is fine as long as the portal moves to another z level, away from the toilet
var/turf/other_z_turf = pick(GLOB.newplayer_start)
portal.forceMove(other_z_turf)
TEST_ASSERT(!portal.active, "[portal] (not upgraded) is still active though the fishing spot is on another z-level.[portal.z == fishing_spot.z ? " Actually they're still on the same level!" : ""]")
portal.long_range_link = TRUE
portal.activate(fish_source, user)
TEST_ASSERT(portal.active?.fish_source == fish_source, "[portal] can't acces a fish source from a linked fishing spot on a different z-level despite being upgraded")
fishing_spot.forceMove(other_z_turf)
portal.forceMove(get_turf(user))
TEST_ASSERT(portal.active?.fish_source == fish_source, "[portal] (upgraded) deactivated while changing z-level")
tool.melee_attack_chain(user, extra_spot)
TEST_ASSERT_EQUAL(length(portal.linked_fishing_spots), 1, "We managed to link to another fishing spot when there's only space for one")
TEST_ASSERT_EQUAL(LAZYACCESS(portal.linked_fishing_spots, fishing_spot), fish_source, "linking to another fishing spot fouled up the other linked spots")
QDEL_NULL(fishing_spot)
TEST_ASSERT(!portal.active, "[portal] is still linked to the fish source of the deleted fishing spot it's associated to")
tool.melee_attack_chain(user, inaccessible)
TEST_ASSERT(!length(portal.linked_fishing_spots), "We managed to link to an unlinkable fishing spot")
/obj/machinery/fishing_portal_generator/no_power
use_power = NO_POWER_USE
/obj/structure/toilet/unit_test/Initialize(mapload)
. = ..()
if(!HAS_TRAIT(src, TRAIT_FISHING_SPOT)) //Ensure this toilet has a fishing spot because only maploaded ones have it.
AddElement(/datum/element/lazy_fishing_spot, /datum/fish_source/toilet)
// we want no default spawns in this unit test
/datum/chasm_detritus/restricted/bodies/no_defaults
default_contents_chance = 0
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

+2
View File
@@ -15,6 +15,8 @@ You may find worms by digging through sand, ash and snow.
You can revive fish by using a Lazarus Injector on them. However, using Strange Reagent would be a smarter option here.
You can feed fish outside of an aquarium by tapping them with a can of fish feed.
More fishing rods and fish cases can be printed at the autolathe.
You can link the fish portal generator to other fishing spots with a multitool. The maximum amount of fishing spots that can be linked and whether or not the link works on different z-levels depends on the quality of the machinery components.
The actual name of the fishing portal generator is 'fish-porter 3000'. They're totally the same thing however.
Seeking alternative ways to catch fish without bothering to do it yourself? Explosives can be thrown at fishing spots to get several (dead) fishes in a pinch.
You can raise lobstrosities from chasm chrabs. However, lobstrosities can only be tamed with spare limbs or lavaloop fish while still young.
Lavaloop fish make for dangerous yet somewhat effective throwing weapons against big fauna.