mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 04:30:44 +01:00
981 lines
37 KiB
Plaintext
981 lines
37 KiB
Plaintext
/obj/item/fishing_rod
|
|
name = "fishing rod"
|
|
desc = "You can fish with this."
|
|
icon = 'icons/obj/fishing.dmi'
|
|
icon_state = "fishing_rod"
|
|
icon_angle = -45
|
|
lefthand_file = 'icons/mob/inhands/equipment/fishing_rod_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/equipment/fishing_rod_righthand.dmi'
|
|
inhand_icon_state = "rod"
|
|
inhand_x_dimension = 64
|
|
inhand_y_dimension = 64
|
|
force = 8
|
|
w_class = WEIGHT_CLASS_HUGE
|
|
|
|
/// How far can you cast this
|
|
var/cast_range = 3
|
|
/// Fishing minigame difficulty modifier (additive)
|
|
var/difficulty_modifier = 0
|
|
/// Explaination of rod functionality shown in the ui and the autowiki
|
|
var/ui_description = "A classic fishing rod, with no special qualities."
|
|
/// More explaination shown in the wiki after ui_description
|
|
var/wiki_description = ""
|
|
/// Is this fishing rod shown in the wiki
|
|
var/show_in_wiki = TRUE
|
|
|
|
var/obj/item/bait
|
|
var/obj/item/fishing_line/line = /obj/item/fishing_line
|
|
var/obj/item/fishing_hook/hook = /obj/item/fishing_hook
|
|
|
|
/// Currently hooked item for item reeling
|
|
var/atom/movable/currently_hooked
|
|
|
|
/// Fishing line visual for the hooked item
|
|
var/datum/beam/fishing_line/fishing_line
|
|
|
|
/// Are we currently casting
|
|
var/casting = FALSE
|
|
|
|
/// The default color for the reel overlay if no line is equipped.
|
|
var/default_line_color = "gray"
|
|
|
|
/// Is this currently being used by the profound fisher component?
|
|
var/internal = FALSE
|
|
|
|
/// The name of the icon state of the reel overlay
|
|
var/reel_overlay = "reel_overlay"
|
|
|
|
/// Icon state of the frame overlay this rod uses for the minigame
|
|
var/frame_state = "frame_wood"
|
|
|
|
/**
|
|
* A list with two keys delimiting the spinning interval in which a mouse click has to be pressed while fishing.
|
|
* Inherited from baits, passed down to the minigame lure.
|
|
*/
|
|
var/list/spin_frequency
|
|
|
|
///Prevents spamming the line casting, without affecting the player's click cooldown.
|
|
COOLDOWN_DECLARE(casting_cd)
|
|
|
|
///The chance of catching fish made of the same material of the fishing rod (if MATERIAL_EFFECTS is enabled)
|
|
var/material_fish_chance = 10
|
|
///The multiplier of how much experience is gained when fishing with this rod.
|
|
var/experience_multiplier = 1
|
|
///The multiplier of the completion gain during the minigame
|
|
var/completion_speed_mult = 1
|
|
///The multiplier of the speed of the bobber/bait during the minigame
|
|
var/bait_speed_mult = 1
|
|
///The multiplier of the decelaration during the minigame
|
|
var/deceleration_mult = 1
|
|
///The multiplier of the bounciness of the bobber/bait upon hitting the edges of the minigame area
|
|
var/bounciness_mult = 1
|
|
/// The multiplier of negative velocity that pulls the bait/bobber down when not holding the click
|
|
var/gravity_mult = 1
|
|
/**
|
|
* The multiplier of the bait height. Influenced by the strength_modifier of a material,
|
|
* unlike the other variables, lest we add too many vars to materials.
|
|
* Also materials with a strength_modifier lower than 1 don't do anything, since
|
|
* they're already likely to be quite bad
|
|
*/
|
|
var/bait_height_mult = 1
|
|
|
|
/obj/item/fishing_rod/Initialize(mapload)
|
|
. = ..()
|
|
register_context()
|
|
register_item_context()
|
|
|
|
if(ispath(bait))
|
|
set_slot(new bait(src), ROD_SLOT_BAIT)
|
|
if(ispath(hook))
|
|
set_slot(new hook(src), ROD_SLOT_HOOK)
|
|
if(ispath(line))
|
|
set_slot(new line(src), ROD_SLOT_LINE)
|
|
|
|
update_appearance()
|
|
AddComponent(/datum/component/bane, \
|
|
damage_multiplier = 2.25, \
|
|
should_bane_callback = CALLBACK(src, PROC_REF(should_bane_fish_infusions)), \
|
|
on_bane_callback = CALLBACK(src, PROC_REF(on_bane_fish_infusions)), \
|
|
label_text = "fishpeople", \
|
|
)
|
|
|
|
/obj/item/fishing_rod/add_context(atom/source, list/context, obj/item/held_item, mob/user)
|
|
if(src == held_item)
|
|
if(currently_hooked)
|
|
context[SCREENTIP_CONTEXT_LMB] = "Reel in"
|
|
context[SCREENTIP_CONTEXT_RMB] = "Modify"
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
return NONE
|
|
|
|
/obj/item/fishing_rod/add_item_context(obj/item/source, list/context, atom/target, mob/living/user)
|
|
. = ..()
|
|
var/gone_fishing = GLOB.fishing_challenges_by_user[user]
|
|
if(currently_hooked || gone_fishing)
|
|
context[SCREENTIP_CONTEXT_LMB] = (gone_fishing && spin_frequency) ? "Spin" : "Reel in"
|
|
if(!gone_fishing)
|
|
context[SCREENTIP_CONTEXT_RMB] = "Unhook"
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
return NONE
|
|
|
|
/obj/item/fishing_rod/examine(mob/user)
|
|
. = ..()
|
|
var/list/equipped_stuff = list()
|
|
if(line)
|
|
equipped_stuff += "[icon2html(line, user)] <b>[line.name]</b>"
|
|
if(hook)
|
|
equipped_stuff += "[icon2html(hook, user)] <b>[hook.name]</b>"
|
|
if(bait)
|
|
equipped_stuff += "[icon2html(bait, user)] <b>[bait]</b>"
|
|
if(length(equipped_stuff))
|
|
. += span_notice("It has \a [english_list(equipped_stuff)] equipped.")
|
|
if(!bait)
|
|
. += span_warning("It doesn't have a bait attached to it. Fishing will be more tedious!")
|
|
if(HAS_MIND_TRAIT(user, TRAIT_EXAMINE_FISH))
|
|
. += "" //add a new line
|
|
. += span_notice("Thanks to your fishing skills, you can examine it again for more in-depth information.")
|
|
return
|
|
if(HAS_TRAIT(src, TRAIT_ROD_MANSUS_INFUSED))
|
|
if(IS_HERETIC(user))
|
|
. += span_purple("This rod has been <b>infused</b> by a heretic, improving its ability to catch glimpses of the Mansus. And fish.")
|
|
else
|
|
. += span_purple("It's glowing an eerie purple...")
|
|
else if(IS_HERETIC(user))
|
|
. += span_purple("As a Heretic, you can infuse this fishing rod with your <b>Mansus Grasp</b> by activating the spell while wielding it, to enhance its fishing power.")
|
|
|
|
/obj/item/fishing_rod/examine_more(mob/user)
|
|
. = ..()
|
|
if(!HAS_MIND_TRAIT(user, TRAIT_EXAMINE_FISH))
|
|
return
|
|
|
|
var/list/block = list()
|
|
var/get_percent = HAS_MIND_TRAIT(user, TRAIT_EXAMINE_DEEPER_FISH)
|
|
block += span_info("You think you can cast it up to [get_cast_range()] tiles away.")
|
|
block += get_stat_info(get_percent, difficulty_modifier * 0.01, "Fishing will be", "easier", "harder", "with this fishing rod")
|
|
block += get_stat_info(get_percent, experience_multiplier - 1, "You will gain experience", "faster", "slower")
|
|
block += get_stat_info(get_percent, completion_speed_mult - 1, "The minigame completion speed is", "faster", "slower")
|
|
block += get_stat_info(get_percent, bait_speed_mult - 1, "Reeling is", "faster", "slower")
|
|
block += get_stat_info(get_percent, deceleration_mult - 1, "Deceleration is", "faster", "slower")
|
|
block += get_stat_info(get_percent, bounciness_mult - 1, "This fishing rod is ", "bouncier", "less bouncy", "than a normal one", less_is_better = TRUE)
|
|
block += get_stat_info(get_percent, gravity_mult - 1, "The lure will sink", "faster", "slower", span_info = TRUE)
|
|
|
|
list_clear_nulls(block)
|
|
. += boxed_message(block.Join("\n"))
|
|
|
|
if(get_percent && (material_flags & MATERIAL_EFFECTS) && length(custom_materials))
|
|
. += boxed_message(span_info("Right now, fish caught by this fishing rod have a [get_material_fish_chance(user)]% of being made of its same materials."))
|
|
|
|
block = list()
|
|
if(HAS_TRAIT(src, TRAIT_ROD_ATTRACT_SHINY_LOVERS))
|
|
block += span_info("This fishing rod will attract shiny-loving fish.")
|
|
if(HAS_TRAIT(src, TRAIT_ROD_IGNORE_ENVIRONMENT))
|
|
block += span_info("Environment and light shouldn't be an issue with this rod.")
|
|
if(HAS_TRAIT_NOT_FROM(src, TRAIT_ROD_REMOVE_FISHING_DUD, INNATE_TRAIT)) // Duds are innately removed by baits, we all know that.
|
|
block += span_info("You won't catch duds with this rod.")
|
|
if(HAS_TRAIT(src, TRAIT_ROD_LAVA_USABLE))
|
|
block += span_info("This fishing rod can be used to fish on lava.")
|
|
if(length(block))
|
|
. += boxed_message(block.Join("\n"))
|
|
|
|
///Used in examine_more to reduce all the copypasta when getting more information about the various stats of the fishing rod.
|
|
/obj/item/fishing_rod/proc/get_stat_info(get_percent, value, prefix, easier, harder, suffix = "with this fishing rod", span_info = FALSE, less_is_better = FALSE)
|
|
if(!value)
|
|
return
|
|
var/percent = get_percent ? "[abs(value * 100)]% " : ""
|
|
var/harder_easier = value > 0 ? easier : harder
|
|
. = "[prefix] [percent][harder_easier] [suffix]."
|
|
if(span_info)
|
|
return span_info(.)
|
|
if(less_is_better ? value < 0 : value > 0)
|
|
return span_nicegreen(.)
|
|
return span_danger(.)
|
|
|
|
/obj/item/fishing_rod/apply_single_mat_effect(datum/material/custom_material, amount, multiplier)
|
|
. = ..()
|
|
cast_range += round(2 - custom_material.get_property(MATERIAL_DENSITY) / 2) * multiplier
|
|
bait_speed_mult *= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_REFLECTIVITY) - 4) * 0.1, multiplier)
|
|
deceleration_mult *= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_HARDNESS) - 4) * 0.1, multiplier)
|
|
bounciness_mult *= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_FLEXIBILITY) - 4) * 0.1, multiplier)
|
|
gravity_mult *= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_DENSITY) - 4) * 0.1, multiplier)
|
|
|
|
/obj/item/fishing_rod/remove_single_mat_effect(datum/material/custom_material, amount, multiplier)
|
|
. = ..()
|
|
cast_range -= round(2 - custom_material.get_property(MATERIAL_DENSITY) / 2) * multiplier
|
|
bait_speed_mult /= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_REFLECTIVITY) - 4) * 0.1, multiplier)
|
|
deceleration_mult /= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_HARDNESS) - 4) * 0.1, multiplier)
|
|
bounciness_mult /= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_FLEXIBILITY) - 4) * 0.1, multiplier)
|
|
gravity_mult /= GET_MATERIAL_MODIFIER(1 + (custom_material.get_property(MATERIAL_DENSITY) - 4) * 0.1, multiplier)
|
|
|
|
/**
|
|
* Is there a reason why this fishing rod couldn't fish in target_fish_source?
|
|
* If so, return the denial reason as a string, otherwise return `null`.
|
|
*
|
|
* Arguments:
|
|
* * target_fish_source - The /datum/fish_source we're trying to fish in.
|
|
*/
|
|
/obj/item/fishing_rod/proc/reason_we_cant_fish(datum/fish_source/target_fish_source)
|
|
return hook?.reason_we_cant_fish(target_fish_source)
|
|
|
|
///Called at the end of on_challenge_completed() once the reward has been spawned
|
|
/obj/item/fishing_rod/proc/on_reward_caught(atom/movable/reward, mob/user)
|
|
if(isnull(reward))
|
|
return
|
|
var/isfish = isfish(reward)
|
|
if((material_flags & MATERIAL_EFFECTS) && isfish && length(custom_materials) && HAS_TRAIT(reward, TRAIT_FISH_JUST_SPAWNED))
|
|
if(prob(get_material_fish_chance(user)))
|
|
var/obj/item/fish/fish = reward
|
|
var/datum/material/material = get_master_material()
|
|
fish.set_custom_materials(list(material.type = fish.weight))
|
|
// catching things that aren't fish or alive mobs doesn't consume baits.
|
|
if(isnull(bait) || HAS_TRAIT(bait, TRAIT_BAIT_UNCONSUMABLE))
|
|
return
|
|
if(isliving(reward))
|
|
var/mob/living/caught_mob = reward
|
|
if(caught_mob.stat == DEAD)
|
|
return
|
|
else
|
|
if(!isfish)
|
|
return
|
|
var/obj/item/fish/fish = reward
|
|
if(HAS_TRAIT(bait, TRAIT_POISONOUS_BAIT) && !HAS_TRAIT(fish, TRAIT_FISH_TOXIN_IMMUNE))
|
|
var/kill_fish = TRUE
|
|
for(var/bait_identifer in fish.favorite_bait)
|
|
if(is_matching_bait(bait, bait_identifer))
|
|
kill_fish = FALSE
|
|
break
|
|
if(kill_fish)
|
|
fish.set_status(FISH_DEAD, silent = TRUE)
|
|
|
|
qdel(bait)
|
|
update_icon()
|
|
|
|
///Returns the probability that a fish caught by this (custom material) rod will be of the same material.
|
|
/obj/item/fishing_rod/proc/get_material_fish_chance(mob/user)
|
|
var/material_chance = material_fish_chance
|
|
if(bait)
|
|
if(HAS_TRAIT(bait, TRAIT_GREAT_QUALITY_BAIT))
|
|
material_chance += 16
|
|
else if(HAS_TRAIT(bait, TRAIT_GOOD_QUALITY_BAIT))
|
|
material_chance += 8
|
|
else if(HAS_TRAIT(bait, TRAIT_BASIC_QUALITY_BAIT))
|
|
material_chance += 4
|
|
material_chance += user.mind?.get_skill_level(/datum/skill/fishing) * 1.5
|
|
return material_chance
|
|
|
|
/obj/item/fishing_rod/proc/should_bane_fish_infusions(mob/living/target)
|
|
return force > 0 && HAS_TRAIT(target, TRAIT_WATER_ADAPTATION)
|
|
|
|
/obj/item/fishing_rod/proc/on_bane_fish_infusions(mob/living/target, mob/living/attacker)
|
|
target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 4 SECONDS)
|
|
target.adjust_confusion_up_to(1.5 SECONDS, 3 SECONDS)
|
|
target.adjust_wet_stacks(-4)
|
|
|
|
/obj/item/fishing_rod/interact(mob/user)
|
|
if(currently_hooked)
|
|
reel(user)
|
|
|
|
/obj/item/fishing_rod/proc/reel(mob/user)
|
|
if(DOING_INTERACTION_WITH_TARGET(user, currently_hooked))
|
|
return
|
|
|
|
playsound(src, SFX_REEL, 50, vary = FALSE)
|
|
var/time = (0.8 - round(user.mind?.get_skill_level(/datum/skill/fishing) * 0.04, 0.1)) SECONDS * bait_speed_mult
|
|
if(!do_after(user, time, currently_hooked, timed_action_flags = IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE, extra_checks = CALLBACK(src, PROC_REF(fishing_line_check))))
|
|
return
|
|
|
|
if(currently_hooked.anchored || currently_hooked.move_resist >= MOVE_FORCE_STRONG)
|
|
balloon_alert(user, "[currently_hooked.p_they()] won't budge!")
|
|
return
|
|
|
|
//About thirty minutes of non-stop reeling to get from zero to master... not worth it but hey, you do what you do.
|
|
user.mind?.adjust_experience(/datum/skill/fishing, time * 0.13 * experience_multiplier)
|
|
|
|
//Try to move it 'till it's under the user's feet, then try to pick it up
|
|
//Not an item, so just delete the line if it's adjacent to the user.
|
|
if(!isitem(currently_hooked) && get_dist(currently_hooked, get_turf(src)) < 1)
|
|
QDEL_NULL(fishing_line)
|
|
return
|
|
|
|
if(line?.fishing_line_traits & FISHING_LINE_PHASE)
|
|
currently_hooked.forceMove(get_step_towards(currently_hooked, get_turf(src)))
|
|
else
|
|
step_towards(currently_hooked, get_turf(src))
|
|
|
|
if(!isitem(currently_hooked))
|
|
if(get_dist(currently_hooked,get_turf(src)) <= 1)
|
|
QDEL_NULL(fishing_line)
|
|
return
|
|
|
|
var/obj/item/item = currently_hooked
|
|
if(item.loc == user.loc && (item.interaction_flags_item & INTERACT_ITEM_ATTACK_HAND_PICKUP))
|
|
user.put_in_inactive_hand(item)
|
|
QDEL_NULL(fishing_line)
|
|
|
|
/obj/item/fishing_rod/proc/fishing_line_check()
|
|
return !QDELETED(fishing_line)
|
|
|
|
/obj/item/fishing_rod/attack_self_secondary(mob/user, modifiers)
|
|
. = ..()
|
|
ui_interact(user)
|
|
|
|
/// Generates the fishing line visual from the current user to the target and updates inhands
|
|
/obj/item/fishing_rod/proc/create_fishing_line(atom/movable/target, mob/living/firer, target_py = null)
|
|
if(internal)
|
|
return null
|
|
if(fishing_line)
|
|
QDEL_NULL(fishing_line)
|
|
var/beam_color = line?.line_color || default_line_color
|
|
fishing_line = new(firer, target, icon_state = "fishing_line", beam_color = beam_color, emissive = FALSE, override_target_pixel_y = target_py)
|
|
fishing_line.lefthand = IS_LEFT_INDEX(firer.get_held_index_of_item(src))
|
|
RegisterSignal(fishing_line, COMSIG_BEAM_BEFORE_DRAW, PROC_REF(check_los))
|
|
RegisterSignal(fishing_line, COMSIG_QDELETING, PROC_REF(clear_line))
|
|
INVOKE_ASYNC(fishing_line, TYPE_PROC_REF(/datum/beam/, Start))
|
|
if(QDELETED(fishing_line))
|
|
return null
|
|
firer.update_held_items()
|
|
return fishing_line
|
|
|
|
/obj/item/fishing_rod/proc/clear_line(datum/source)
|
|
SIGNAL_HANDLER
|
|
if(ismob(loc))
|
|
var/mob/user = loc
|
|
user.update_held_items()
|
|
fishing_line = null
|
|
currently_hooked = null
|
|
|
|
/obj/item/fishing_rod/proc/get_cast_range(mob/living/user)
|
|
. = max(cast_range + line?.cast_range, 1)
|
|
user = user || loc
|
|
if (!isliving(user) || !user.mind || !user.is_holding(src))
|
|
return
|
|
. += round(user.mind.get_skill_level(/datum/skill/fishing) * 0.3)
|
|
return max(., 1)
|
|
|
|
/obj/item/fishing_rod/dropped(mob/user, silent)
|
|
. = ..()
|
|
QDEL_NULL(fishing_line)
|
|
|
|
/// Hooks the item
|
|
/obj/item/fishing_rod/proc/hook_item(mob/user, atom/target_atom)
|
|
if(currently_hooked)
|
|
return
|
|
if(!hook.can_be_hooked(target_atom))
|
|
return
|
|
if(!create_fishing_line(target_atom, user))
|
|
return
|
|
currently_hooked = target_atom
|
|
hook.hook_attached(target_atom, src)
|
|
SEND_SIGNAL(src, COMSIG_FISHING_ROD_HOOKED_ITEM, target_atom, user)
|
|
|
|
// Checks fishing line for interruptions and range
|
|
/obj/item/fishing_rod/proc/check_los(datum/beam/source)
|
|
SIGNAL_HANDLER
|
|
|
|
var/cast_range = get_cast_range()
|
|
if(!(line?.fishing_line_traits & FISHING_LINE_PHASE))
|
|
if(!CheckToolReach(src, source.target, cast_range))
|
|
qdel(source)
|
|
return BEAM_CANCEL_DRAW
|
|
return NONE
|
|
|
|
|
|
//Bluespace fishing lines are simplier and only check the distance and if there're r-walls in the way.
|
|
if(source.target.z != loc.z || get_dist(loc, source.target) > cast_range)
|
|
qdel(source)
|
|
return BEAM_CANCEL_DRAW
|
|
|
|
//Check that there are no r-walls in the way of our bluespace fishing line
|
|
var/list/bresenham_line = get_line(loc, source.target)
|
|
bresenham_line -= get_turf(source.target) //We don't check if the target is on a r-wall already, just the turfs separating us from it.
|
|
bresenham_line -= get_turf(loc) //ditto with our own turf.
|
|
for(var/turf/turf as anything in bresenham_line)
|
|
if(isindestructiblewall(turf) || istype(turf, /turf/closed/wall/r_wall))
|
|
qdel(source)
|
|
return BEAM_CANCEL_DRAW
|
|
return NONE
|
|
|
|
/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), 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)
|
|
|
|
/obj/item/fishing_rod/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
|
|
if(!hook)
|
|
balloon_alert(user, "install a hook first!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
// Reel in if able
|
|
if(currently_hooked)
|
|
reel(user)
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
cast_line(interacting_with, user)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/obj/item/fishing_rod/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
|
|
return ranged_interact_with_atom_secondary(interacting_with, user, modifiers)
|
|
|
|
/obj/item/fishing_rod/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
|
|
//Stop reeling, delete the fishing line
|
|
if(currently_hooked)
|
|
QDEL_NULL(fishing_line)
|
|
return ITEM_INTERACT_BLOCKING
|
|
return ..()
|
|
|
|
/// If the line to whatever that is is clear and we're not already busy, try fishing in it
|
|
/obj/item/fishing_rod/proc/cast_line(atom/target, mob/user)
|
|
if(casting || currently_hooked)
|
|
return
|
|
if(!hook)
|
|
balloon_alert(user, "install a hook first!")
|
|
return
|
|
if(!COOLDOWN_FINISHED(src, casting_cd))
|
|
return
|
|
var/cast_range = get_cast_range(user)
|
|
// Inside of storages, or camera weirdness
|
|
if(target.z != user.z || get_dist(user, target) > (cast_range + 3))
|
|
return
|
|
COOLDOWN_START(src, casting_cd, 1 SECONDS)
|
|
// skip firing a projectile if the target is adjacent and can be reached (no order windows in the way),
|
|
// otherwise it may end up hitting other things on its turf, which is problematic
|
|
// especially for entities with the profound fisher component, which should only work on
|
|
// proper fishing spots.
|
|
if(target.Adjacent(user, null, null, 0))
|
|
hook_hit(target, user)
|
|
return
|
|
casting = TRUE
|
|
var/obj/projectile/fishing_cast/cast_projectile = new(get_turf(src))
|
|
cast_projectile.range = get_cast_range(user)
|
|
cast_projectile.maximum_range = get_cast_range(user)
|
|
cast_projectile.owner = src
|
|
cast_projectile.original = target
|
|
cast_projectile.fired_from = src
|
|
cast_projectile.firer = user
|
|
cast_projectile.impacted = list(WEAKREF(user) = TRUE)
|
|
if(line?.fishing_line_traits & FISHING_LINE_PHASE)
|
|
cast_projectile.pass_flags = ALL
|
|
cast_projectile.aim_projectile(target, user)
|
|
cast_projectile.fire()
|
|
|
|
/// Called by hook projectile when hitting things
|
|
/obj/item/fishing_rod/proc/hook_hit(atom/atom_hit_by_hook_projectile, mob/user)
|
|
if(!hook)
|
|
return
|
|
if(SEND_SIGNAL(atom_hit_by_hook_projectile, COMSIG_FISHING_ROD_CAST, src, user) & FISHING_ROD_CAST_HANDLED)
|
|
return
|
|
/// If you can't fish in it, try hooking it
|
|
hook_item(user, atom_hit_by_hook_projectile)
|
|
|
|
/obj/item/fishing_rod/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "FishingRod", name)
|
|
ui.set_autoupdate(FALSE)
|
|
ui.open()
|
|
|
|
/obj/item/fishing_rod/ui_state()
|
|
if(internal)
|
|
return GLOB.deep_inventory_state
|
|
else
|
|
return GLOB.default_state
|
|
|
|
/obj/item/fishing_rod/update_overlays()
|
|
. = ..()
|
|
. += get_fishing_overlays()
|
|
|
|
/obj/item/fishing_rod/proc/get_fishing_overlays()
|
|
. = list()
|
|
var/line_color = line?.line_color || default_line_color
|
|
/// Line part by the rod.
|
|
if(reel_overlay)
|
|
var/mutable_appearance/reel_appearance = mutable_appearance(icon, reel_overlay, appearance_flags = RESET_COLOR|KEEP_APART)
|
|
reel_appearance.color = line_color
|
|
. += reel_appearance
|
|
|
|
// Line & hook is also visible when only bait is equipped but it uses default appearances then
|
|
if(hook || bait)
|
|
var/mutable_appearance/line_overlay = mutable_appearance(icon, "line_overlay", appearance_flags = RESET_COLOR|KEEP_APART)
|
|
line_overlay.color = line_color
|
|
. += line_overlay
|
|
. += hook?.rod_overlay_icon_state || "hook_overlay"
|
|
|
|
if(bait)
|
|
var/bait_state = "worm_overlay" //default to worm overlay for anything without specific one
|
|
if(istype(bait, /obj/item/food/bait))
|
|
var/obj/item/food/bait/real_bait = bait
|
|
bait_state = real_bait.rod_overlay_icon_state
|
|
if(istype(bait, /obj/item/stock_parts/power_store/cell/lead))
|
|
bait_state = "battery_overlay"
|
|
. += bait_state
|
|
|
|
/obj/item/fishing_rod/worn_overlays(mutable_appearance/standing, isinhands, icon_file)
|
|
. = ..()
|
|
. += get_fishing_worn_overlays(standing, isinhands, icon_file)
|
|
|
|
/obj/item/fishing_rod/proc/get_fishing_worn_overlays(mutable_appearance/standing, isinhands, icon_file)
|
|
. = list()
|
|
var/line_color = line?.line_color || default_line_color
|
|
var/mutable_appearance/reel_overlay = mutable_appearance(icon_file, "reel_overlay", appearance_flags = RESET_COLOR|KEEP_APART)
|
|
reel_overlay.color = line_color
|
|
. += reel_overlay
|
|
/// if we don't have anything hooked show the dangling hook & line
|
|
if(isinhands && !fishing_line)
|
|
var/mutable_appearance/line_overlay = mutable_appearance(icon_file, "line_overlay", appearance_flags = RESET_COLOR|KEEP_APART)
|
|
line_overlay.color = line_color
|
|
. += line_overlay
|
|
. += mutable_appearance(icon_file, "hook_overlay")
|
|
|
|
/obj/item/fishing_rod/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers)
|
|
if(slot_check(attacking_item,ROD_SLOT_LINE))
|
|
use_slot(ROD_SLOT_LINE, user, attacking_item)
|
|
SStgui.update_uis(src)
|
|
return TRUE
|
|
else if(slot_check(attacking_item,ROD_SLOT_HOOK))
|
|
use_slot(ROD_SLOT_HOOK, user, attacking_item)
|
|
SStgui.update_uis(src)
|
|
return TRUE
|
|
else if(slot_check(attacking_item,ROD_SLOT_BAIT) || istype(attacking_item, /obj/item/bait_can)) //Can click on the fishing rod with bait can directly
|
|
use_slot(ROD_SLOT_BAIT, user, attacking_item)
|
|
SStgui.update_uis(src)
|
|
return TRUE
|
|
. = ..()
|
|
|
|
/obj/item/fishing_rod/ui_data(mob/user)
|
|
. = ..()
|
|
var/list/data = list()
|
|
|
|
data["bait_name"] = format_text(bait?.name)
|
|
data["bait_icon"] = bait != null ? icon2base64(icon(bait.icon, bait.icon_state, frame = 1)) : null
|
|
|
|
data["line_name"] = format_text(line?.name)
|
|
data["line_icon"] = line != null ? icon2base64(icon(line.icon, line.icon_state, frame = 1)) : null
|
|
|
|
data["hook_name"] = format_text(hook?.name)
|
|
data["hook_icon"] = hook != null ? icon2base64(icon(hook.icon, hook.icon_state, frame = 1)) : null
|
|
|
|
data["busy"] = fishing_line
|
|
|
|
data["description"] = ui_description
|
|
|
|
return data
|
|
|
|
/// Checks if the item fits the slot
|
|
/obj/item/fishing_rod/proc/slot_check(obj/item/item,slot)
|
|
if(!istype(item))
|
|
return FALSE
|
|
switch(slot)
|
|
if(ROD_SLOT_HOOK)
|
|
if(!istype(item,/obj/item/fishing_hook))
|
|
return FALSE
|
|
if(ROD_SLOT_LINE)
|
|
if(!istype(item,/obj/item/fishing_line))
|
|
return FALSE
|
|
if(ROD_SLOT_BAIT)
|
|
if(!HAS_TRAIT(item, TRAIT_FISHING_BAIT))
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/obj/item/fishing_rod/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
|
. = ..()
|
|
if(.)
|
|
return .
|
|
var/mob/user = usr
|
|
switch(action)
|
|
if("slot_action")
|
|
// Simple click with empty hand to remove, click with item to insert/switch
|
|
var/obj/item/held_item = user.get_active_held_item()
|
|
use_slot(params["slot"], user, held_item == src ? null : held_item)
|
|
return TRUE
|
|
|
|
/// Ideally this will be replaced with generic slotted storage datum + display
|
|
/obj/item/fishing_rod/proc/use_slot(slot, mob/user, obj/item/new_item)
|
|
if(fishing_line || GLOB.fishing_challenges_by_user[user])
|
|
return
|
|
// If the new item is a bait can, try to get bait from it
|
|
if(slot == ROD_SLOT_BAIT && istype(new_item, /obj/item/bait_can))
|
|
var/obj/item/bait_can/can = new_item
|
|
var/bait = can.retrieve_bait(user)
|
|
if(!bait)
|
|
return
|
|
new_item = bait
|
|
var/obj/item/current_item
|
|
switch(slot)
|
|
if(ROD_SLOT_BAIT)
|
|
current_item = bait
|
|
if(ROD_SLOT_HOOK)
|
|
current_item = hook
|
|
if(ROD_SLOT_LINE)
|
|
current_item = line
|
|
if(!new_item && !current_item)
|
|
return
|
|
// Trying to remove the item
|
|
if(!new_item && current_item)
|
|
user.put_in_hands(current_item)
|
|
balloon_alert(user, "[slot] removed")
|
|
// Trying to insert item into empty slot
|
|
else if(new_item && !current_item)
|
|
if(!slot_check(new_item, slot))
|
|
return
|
|
if(user.transferItemToLoc(new_item,src))
|
|
set_slot(new_item, slot)
|
|
balloon_alert(user, "[slot] installed")
|
|
else
|
|
balloon_alert(user, "stuck to your hands!")
|
|
return
|
|
/// Trying to swap item
|
|
else if(new_item && current_item)
|
|
if(!slot_check(new_item,slot))
|
|
return
|
|
if(user.transferItemToLoc(new_item, src))
|
|
user.put_in_hands(current_item)
|
|
set_slot(new_item, slot)
|
|
balloon_alert(user, "[slot] swapped")
|
|
else
|
|
balloon_alert(user, "stuck to your hands!")
|
|
return
|
|
|
|
update_icon()
|
|
playsound(src, 'sound/items/click.ogg', 50, TRUE)
|
|
|
|
///assign an item to the given slot and its standard effects, while Exited() should handle unsetting the slot.
|
|
/obj/item/fishing_rod/proc/set_slot(obj/item/equipment, slot)
|
|
switch(slot)
|
|
if(ROD_SLOT_BAIT)
|
|
bait = equipment
|
|
if(!HAS_TRAIT(bait, TRAIT_BAIT_ALLOW_FISHING_DUD))
|
|
ADD_TRAIT(src, TRAIT_ROD_REMOVE_FISHING_DUD, INNATE_TRAIT)
|
|
if(ROD_SLOT_HOOK)
|
|
hook = equipment
|
|
if(ROD_SLOT_LINE)
|
|
line = equipment
|
|
else
|
|
CRASH("set_slot called with an undefined slot: [slot]")
|
|
|
|
SEND_SIGNAL(equipment, COMSIG_ITEM_FISHING_ROD_SLOTTED, src, slot)
|
|
|
|
/obj/item/fishing_rod/Exited(atom/movable/gone, direction)
|
|
. = ..()
|
|
var/slot
|
|
if(gone == bait)
|
|
slot = ROD_SLOT_BAIT
|
|
bait = null
|
|
REMOVE_TRAIT(src, TRAIT_ROD_REMOVE_FISHING_DUD, INNATE_TRAIT)
|
|
if(gone == line)
|
|
slot = ROD_SLOT_LINE
|
|
line = null
|
|
if(gone == hook)
|
|
slot = ROD_SLOT_HOOK
|
|
QDEL_NULL(fishing_line)
|
|
hook = null
|
|
|
|
if(slot)
|
|
SEND_SIGNAL(gone, COMSIG_ITEM_FISHING_ROD_UNSLOTTED, src, slot)
|
|
|
|
/obj/item/fishing_rod/proc/get_frame(datum/fishing_challenge/challenge)
|
|
return mutable_appearance('icons/hud/fishing_hud.dmi', frame_state)
|
|
|
|
///Found in the fishing toolbox (the hook and line are separate items)
|
|
/obj/item/fishing_rod/unslotted
|
|
hook = null
|
|
line = null
|
|
show_in_wiki = FALSE
|
|
|
|
///From the mining order console, meant to help miners rescue their fallen brethren
|
|
/obj/item/fishing_rod/rescue
|
|
hook = /obj/item/fishing_hook/rescue
|
|
show_in_wiki = FALSE
|
|
|
|
/obj/item/fishing_rod/bone
|
|
name = "bone fishing rod"
|
|
desc = "A humble rod, made with whatever happened to be on hand."
|
|
ui_description = "A fishing rod crafted with leather, sinew and bones."
|
|
icon_state = "fishing_rod_bone"
|
|
reel_overlay = "reel_bone"
|
|
default_line_color = "red"
|
|
frame_state = "frame_bone"
|
|
line = null //sinew line (usable to fish in lava) not included
|
|
hook = /obj/item/fishing_hook/bone
|
|
custom_materials = list(/datum/material/bone = SHEET_MATERIAL_AMOUNT * 2)
|
|
|
|
/obj/item/fishing_rod/telescopic
|
|
name = "telescopic fishing rod"
|
|
icon_state = "fishing_rod_telescopic"
|
|
desc = "A lightweight, ergonomic, easy to store telescopic fishing rod. "
|
|
inhand_icon_state = null
|
|
custom_price = PAYCHECK_CREW * 9
|
|
force = 0
|
|
w_class = WEIGHT_CLASS_NORMAL
|
|
ui_description = "A collapsible fishing rod that can fit within a backpack."
|
|
wiki_description = "<b>It has to be bought from Cargo</b>."
|
|
reel_overlay = "reel_telescopic"
|
|
frame_state = "frame_telescopic"
|
|
completion_speed_mult = 1.1
|
|
bait_speed_mult = 1.1
|
|
deceleration_mult = 1.1
|
|
bounciness_mult = 0.9
|
|
gravity_mult = 0.9
|
|
///The force of the item when extended.
|
|
var/active_force = 8
|
|
|
|
/obj/item/fishing_rod/telescopic/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/transforming, force_on = 8, hitsound_on = hitsound, w_class_on = WEIGHT_CLASS_HUGE, clumsy_check = FALSE)
|
|
RegisterSignal(src, COMSIG_TRANSFORMING_PRE_TRANSFORM, PROC_REF(pre_transform))
|
|
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
|
|
|
|
/obj/item/fishing_rod/telescopic/reason_we_cant_fish(datum/fish_source/target_fish_source)
|
|
if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))
|
|
return "You need to extend your fishing rod before you can cast the line."
|
|
return ..()
|
|
|
|
/obj/item/fishing_rod/telescopic/cast_line(atom/target, mob/user, proximity_flag)
|
|
if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))
|
|
if(!proximity_flag)
|
|
balloon_alert(user, "extend the rod first!")
|
|
return
|
|
return ..()
|
|
|
|
/obj/item/fishing_rod/telescopic/get_fishing_overlays()
|
|
if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))
|
|
return list()
|
|
return ..()
|
|
|
|
/obj/item/fishing_rod/telescopic/get_fishing_worn_overlays(mutable_appearance/standing, isinhands, icon_file)
|
|
if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))
|
|
return list()
|
|
return ..()
|
|
|
|
///Stops the fishing rod from being collapsed while fishing.
|
|
/obj/item/fishing_rod/telescopic/proc/pre_transform(obj/item/source, mob/user, active)
|
|
SIGNAL_HANDLER
|
|
if(HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))
|
|
return
|
|
//the fishing minigame uses the attack_self signal to let the user end it early without having to drop the rod.
|
|
if(GLOB.fishing_challenges_by_user[user])
|
|
return COMPONENT_BLOCK_TRANSFORM
|
|
|
|
///Gives feedback to the user, makes it show up inhand, toggles whether it can be used for fishing.
|
|
/obj/item/fishing_rod/telescopic/proc/on_transform(obj/item/source, mob/user, active)
|
|
SIGNAL_HANDLER
|
|
|
|
inhand_icon_state = active ? "rod" : null // When inactive, there is no inhand icon_state.
|
|
if(user)
|
|
balloon_alert(user, active ? "extended" : "collapsed")
|
|
playsound(src, 'sound/items/weapons/batonextend.ogg', 50, TRUE)
|
|
update_appearance()
|
|
QDEL_NULL(fishing_line)
|
|
return COMPONENT_NO_DEFAULT_MESSAGE
|
|
|
|
/obj/item/fishing_rod/telescopic/update_icon_state()
|
|
. = ..()
|
|
icon_state = "[initial(icon_state)][!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE) ? "_collapsed" : ""]"
|
|
|
|
/obj/item/fishing_rod/telescopic/master
|
|
name = "master fishing rod"
|
|
desc = "The mythical rod of a lost fisher king. Said to be imbued with unparalleled fishing power. There's writing on the back of the pole. \"中国航天制造\""
|
|
difficulty_modifier = -10
|
|
ui_description = "A mythical telescopic fishing rod that makes fishing quite easier."
|
|
wiki_description = null
|
|
icon_state = "fishing_rod_master"
|
|
reel_overlay = "reel_master"
|
|
frame_state = "frame_master"
|
|
active_force = 13 //It's that sturdy
|
|
cast_range = 5
|
|
line = /obj/item/fishing_line/bouncy
|
|
hook = /obj/item/fishing_hook/weighted
|
|
completion_speed_mult = 1.55
|
|
bait_speed_mult = 1.2
|
|
deceleration_mult = 1.2
|
|
bounciness_mult = 0.3
|
|
gravity_mult = 1.2
|
|
material_fish_chance = 33 //if somehow you metalgen it.
|
|
bait_height_mult = 1.4
|
|
|
|
/obj/item/fishing_rod/tech
|
|
name = "advanced fishing rod"
|
|
desc = "An embedded universal constructor along with micro-fusion generator makes this marvel of technology never run out of bait. Interstellar treaties prevent using it outside of recreational fishing. And you can fish with this. "
|
|
ui_description = "A rod with an infinite supply of synthetic bait. Doubles as an Experi-Scanner for fish."
|
|
wiki_description = "<b>It requires the Advanced Fishing Technology Node to be researched to be printed.</b>"
|
|
icon_state = "fishing_rod_science"
|
|
reel_overlay = "reel_science"
|
|
frame_state = "frame_science"
|
|
bait = /obj/item/food/bait/doughball/synthetic/unconsumable
|
|
completion_speed_mult = 1.1
|
|
bait_speed_mult = 1.1
|
|
deceleration_mult = 1.1
|
|
gravity_mult = 1.2
|
|
|
|
/obj/item/fishing_rod/tech/Initialize(mapload)
|
|
. = ..()
|
|
|
|
var/static/list/fishing_signals = list(
|
|
COMSIG_FISHING_ROD_HOOKED_ITEM = TYPE_PROC_REF(/datum/component/experiment_handler, try_run_handheld_experiment),
|
|
COMSIG_FISHING_ROD_CAUGHT_FISH = TYPE_PROC_REF(/datum/component/experiment_handler, try_run_handheld_experiment),
|
|
COMSIG_ITEM_PRE_ATTACK = TYPE_PROC_REF(/datum/component/experiment_handler, try_run_handheld_experiment),
|
|
COMSIG_ITEM_AFTERATTACK = TYPE_PROC_REF(/datum/component/experiment_handler, ignored_handheld_experiment_attempt),
|
|
)
|
|
AddComponent(/datum/component/experiment_handler, \
|
|
config_mode = EXPERIMENT_CONFIG_ALTCLICK, \
|
|
allowed_experiments = list(/datum/experiment/scanning/fish), \
|
|
config_flags = EXPERIMENT_CONFIG_SILENT_FAIL|EXPERIMENT_CONFIG_IMMEDIATE_ACTION, \
|
|
experiment_signals = fishing_signals, \
|
|
)
|
|
|
|
/obj/item/fishing_rod/tech/examine(mob/user)
|
|
. = ..()
|
|
. += span_notice("<b>Alt-Click</b> to access the Experiment Configuration UI")
|
|
|
|
/obj/item/fishing_rod/tech/use_slot(slot, mob/user, obj/item/new_item)
|
|
if(slot == ROD_SLOT_BAIT)
|
|
return
|
|
return ..()
|
|
|
|
/obj/item/fishing_rod/material
|
|
name = "material fishing rod" //name shown on the autowiki.
|
|
desc = "A custom fishing rod from your local autolathe."
|
|
icon_state = "fishing_rod_material"
|
|
reel_overlay = "reel_material"
|
|
frame_state = "frame_material"
|
|
ui_description = "An autolathe-printable fishing rod made of some material."
|
|
wiki_description = "Different materials can have different effects. They also catch fish made of the same material used to print the rod."
|
|
material_flags = MATERIAL_EFFECTS|MATERIAL_AFFECT_STATISTICS|MATERIAL_COLOR|MATERIAL_ADD_PREFIX
|
|
|
|
/obj/item/fishing_rod/material/Initialize(mapload)
|
|
. = ..()
|
|
name = "fishing rod"
|
|
|
|
/obj/item/fishing_rod/material/finalize_remove_material_effects(list/materials)
|
|
. = ..()
|
|
name = "fishing rod" //so it doesn't reset to "material fishing rod"
|
|
|
|
/obj/item/fishing_rod/material/get_frame(datum/fishing_challenge/challenge)
|
|
var/mutable_appearance/frame = ..()
|
|
frame.color = color
|
|
return frame
|
|
|
|
#undef ROD_SLOT_BAIT
|
|
#undef ROD_SLOT_LINE
|
|
#undef ROD_SLOT_HOOK
|
|
|
|
/obj/projectile/fishing_cast
|
|
name = "fishing hook"
|
|
icon = 'icons/obj/fishing.dmi'
|
|
icon_state = "hook"
|
|
damage = 0
|
|
range = 5
|
|
suppressed = SUPPRESSED_VERY
|
|
can_hit_turfs = TRUE
|
|
projectile_angle = 180
|
|
var/obj/item/fishing_rod/owner
|
|
|
|
/obj/projectile/fishing_cast/fire(angle, atom/direct_target)
|
|
if(owner.hook)
|
|
icon_state = owner.hook.icon_state
|
|
. = ..()
|
|
if(!QDELETED(src))
|
|
owner.create_fishing_line(src, firer)
|
|
|
|
///If the fishing line is phasing, we don't care about anything entering our turf
|
|
/obj/projectile/fishing_cast/on_entered(datum/source, atom/movable/entered_atom)
|
|
if(owner.line?.fishing_line_traits & FISHING_LINE_PHASE)
|
|
return
|
|
return ..()
|
|
|
|
///Override of the generic scan_moved_turf so we don't scan for mobs when we move. Also cannot phase through r-walls for balance reasons (stealing from the armory *wink wink*)
|
|
/obj/projectile/fishing_cast/scan_moved_turf()
|
|
if(can_hit_target(original, TRUE, FALSE))
|
|
impact(original)
|
|
return
|
|
if(isindestructiblewall(loc) || istype(loc, /turf/closed/wall/r_wall))
|
|
qdel(src)
|
|
|
|
/obj/projectile/fishing_cast/on_hit(atom/target, blocked = 0, pierce_hit)
|
|
. = ..()
|
|
QDEL_NULL(owner.fishing_line) //we need to delete the old beam datum, otherwise it won't let you fish.
|
|
owner.casting = FALSE //set the casting value to false so we don't delete the new fishing line (different target) on Destroy()
|
|
if(blocked >= 100)
|
|
return
|
|
owner.hook_hit(target, firer)
|
|
|
|
if(!isturf(target) || owner.fishing_line)
|
|
return
|
|
|
|
//So, the target is a turf and we couldn't enstablish a fishing line to it, so let's pick a random thing from that turf.
|
|
var/list/possible_picks = list()
|
|
for(var/atom/movable/movable as anything in get_turf(src))
|
|
if(movable == src)
|
|
continue
|
|
if(can_hit_target(movable, direct_target = TRUE, ignore_loc = TRUE))
|
|
possible_picks += movable
|
|
if(length(possible_picks))
|
|
impact(pick(possible_picks))
|
|
return
|
|
|
|
/obj/projectile/fishing_cast/Destroy()
|
|
if(owner?.casting)
|
|
owner.casting = FALSE
|
|
QDEL_NULL(owner.fishing_line)
|
|
owner = null
|
|
return ..()
|
|
|
|
/datum/beam/fishing_line
|
|
// Is the fishing rod held in left side hand
|
|
var/lefthand = FALSE
|
|
|
|
// Make these inline with final sprites
|
|
var/righthand_s_px = 13
|
|
var/righthand_s_py = 16
|
|
|
|
var/righthand_e_px = 18
|
|
var/righthand_e_py = 16
|
|
|
|
var/righthand_w_px = -20
|
|
var/righthand_w_py = 18
|
|
|
|
var/righthand_n_px = -14
|
|
var/righthand_n_py = 16
|
|
|
|
var/lefthand_s_px = -13
|
|
var/lefthand_s_py = 15
|
|
|
|
var/lefthand_e_px = 24
|
|
var/lefthand_e_py = 18
|
|
|
|
var/lefthand_w_px = -17
|
|
var/lefthand_w_py = 16
|
|
|
|
var/lefthand_n_px = 13
|
|
var/lefthand_n_py = 15
|
|
|
|
/datum/beam/fishing_line/Start()
|
|
update_offsets(origin.dir)
|
|
. = ..()
|
|
RegisterSignal(origin, COMSIG_ATOM_DIR_CHANGE, PROC_REF(handle_dir_change))
|
|
|
|
/datum/beam/fishing_line/Destroy()
|
|
UnregisterSignal(origin, COMSIG_ATOM_DIR_CHANGE)
|
|
. = ..()
|
|
|
|
/datum/beam/fishing_line/proc/handle_dir_change(atom/movable/source, olddir, newdir)
|
|
SIGNAL_HANDLER
|
|
update_offsets(newdir)
|
|
INVOKE_ASYNC(src, TYPE_PROC_REF(/datum/beam, redrawing))
|
|
|
|
/datum/beam/fishing_line/proc/update_offsets(user_dir)
|
|
switch(user_dir)
|
|
if(SOUTH)
|
|
override_origin_pixel_x = lefthand ? lefthand_s_px : righthand_s_px
|
|
override_origin_pixel_y = lefthand ? lefthand_s_py : righthand_s_py
|
|
if(EAST)
|
|
override_origin_pixel_x = lefthand ? lefthand_e_px : righthand_e_px
|
|
override_origin_pixel_y = lefthand ? lefthand_e_py : righthand_e_py
|
|
if(WEST)
|
|
override_origin_pixel_x = lefthand ? lefthand_w_px : righthand_w_px
|
|
override_origin_pixel_y = lefthand ? lefthand_w_py : righthand_w_py
|
|
if(NORTH)
|
|
override_origin_pixel_x = lefthand ? lefthand_n_px : righthand_n_px
|
|
override_origin_pixel_y = lefthand ? lefthand_n_py : righthand_n_py
|
|
|
|
override_origin_pixel_x += origin.pixel_x
|
|
override_origin_pixel_y += origin.pixel_y
|