mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-13 00:55:20 +01:00
f640a0e972
## About The Pull Request Depends on #94064 for the unit test but offers a better method for finding an atom to mount on - Finding a mount now takes into consideration the objects pixel x & y offsets meaning diagonal mounting is now supported. Gives great flexibility for mappers - If you don't want to use pixel offsets but default back to using the objects direction that behaviour is still preserved. Useful if your object uses directional icon states(lights & cameras for now) AND don't use offsets - If no direction could be specified then as the last resort it defaults back to the objects local turf for mounting ## Changelog 🆑 fix: all mounted objects on tables, fences, windows & walls should fall of correctly when the atom it is placed on is destroyed fix: security telescreen now falls off when their mounted wall is destroyed fix: defib wall mount falls off when their mounted wall is destroyed fix: floor lights are mounted to the ground/catwalk/tram floor they are sitting on meaning destroying it will destroy the light fix: wall mounted plaques now fall off when their mounted wall is destroyed /🆑
212 lines
7.9 KiB
Plaintext
212 lines
7.9 KiB
Plaintext
/obj/item/wallframe/fish
|
|
name = "fish mount"
|
|
desc = "The frame of a mount for trophy fish, to show off your proudest catch."
|
|
icon = 'icons/obj/wallmounts.dmi'
|
|
icon_state = "fish_mount_item"
|
|
result_path = /obj/structure/fish_mount
|
|
custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 2)
|
|
pixel_shift = 31
|
|
///Reference to the persistent_id of the mount this was spawned from.
|
|
var/persistence_id
|
|
|
|
/obj/item/wallframe/fish/after_attach(obj/structure/fish_mount/mount)
|
|
. = ..()
|
|
mount.persistence_id = persistence_id
|
|
|
|
///A wallmounted structure on which a fish can be attached to be used as room decoration.
|
|
/obj/structure/fish_mount
|
|
name = "fish mount"
|
|
desc = "A mount for trophy fish, to show off your proudest catch."
|
|
icon = 'icons/obj/wallmounts.dmi'
|
|
icon_state = "fish_mount"
|
|
anchored = TRUE
|
|
opacity = FALSE
|
|
density = FALSE
|
|
layer = SIGN_LAYER
|
|
max_integrity = 100
|
|
custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT)
|
|
armor_type = /datum/armor/structure_sign
|
|
resistance_flags = FLAMMABLE
|
|
/// The instance of the fish mounted on this.
|
|
var/obj/item/fish/mounted_fish
|
|
/// The identifier for mounts that carry the trophy between rounds.
|
|
var/persistence_id
|
|
/// Trophies from persistence have a good chance to be dusted if removal is attempted, though rarely it pays off.
|
|
var/persistence_loaded_fish = FALSE
|
|
|
|
/obj/structure/fish_mount/Initialize(mapload)
|
|
. = ..()
|
|
//Mounted fish shouldn't flop. It should also show size and weight to everyone.
|
|
add_traits(list(TRAIT_STOP_FISH_FLOPPING, TRAIT_EXAMINE_FISH), INNATE_TRAIT)
|
|
if(mapload)
|
|
find_and_mount_on_atom()
|
|
if(!persistence_id)
|
|
return
|
|
if(SSfishing.initialized)
|
|
load_trophy_fish()
|
|
else
|
|
RegisterSignal(SSfishing, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(load_trophy_fish))
|
|
|
|
/obj/structure/fish_mount/Destroy(force)
|
|
QDEL_NULL(mounted_fish)
|
|
return ..()
|
|
|
|
/obj/structure/fish_mount/proc/load_trophy_fish(datum/source)
|
|
SIGNAL_HANDLER
|
|
SSpersistence.load_trophy_fish(src)
|
|
UnregisterSignal(SSfishing, COMSIG_SUBSYSTEM_POST_INITIALIZE)
|
|
if(!mounted_fish)
|
|
add_first_fish()
|
|
|
|
/obj/structure/fish_mount/screwdriver_act(mob/living/user, obj/item/item)
|
|
. = ..()
|
|
balloon_alert(user, "removing mount...")
|
|
if(!item.use_tool(src, user, 3 SECONDS, volume = 50))
|
|
return ITEM_INTERACT_BLOCKING
|
|
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
|
|
balloon_alert_to_viewers("fish mount removed")
|
|
deconstruct()
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/obj/structure/fish_mount/proc/add_first_fish()
|
|
var/list/valid_picks = subtypesof(/obj/item/fish) - typesof(/obj/item/fish/holo) - /obj/item/fish/starfish/chrystarfish // chrystarfish immediately shatters when placed
|
|
var/obj/item/fish/fish_path = pick(valid_picks)
|
|
if(fish_path.fish_id_redirect_path)
|
|
fish_path = fish_path.fish_id_redirect_path
|
|
var/fluff_name = pick("John Trasen III", "a nameless intern", "Pun Pun", AQUARIUM_COMPANY, "Unknown", "Central Command")
|
|
add_fish(new fish_path(loc), from_persistence = TRUE, catcher = fluff_name)
|
|
mounted_fish.randomize_size_and_weight()
|
|
mounted_fish.set_status(FISH_DEAD)
|
|
SSpersistence.save_trophy_fish(src)
|
|
|
|
/obj/structure/fish_mount/atom_deconstruct(disassembled = TRUE)
|
|
. = ..()
|
|
if(disassembled)
|
|
var/obj/item/wallframe/fish/frame = new (loc)
|
|
frame.persistence_id = persistence_id
|
|
mounted_fish?.forceMove(loc)
|
|
|
|
/obj/structure/fish_mount/item_interaction(mob/living/user, obj/item/item, list/modifiers)
|
|
if(!isfish(item) || user.combat_mode)
|
|
return ..()
|
|
if(mounted_fish)
|
|
balloon_alert(user, "remove other fish first!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
if(item.flags_1 & HOLOGRAM_1)
|
|
balloon_alert(user, "fish not mountable!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
balloon_alert(user, "mounting fish...")
|
|
if(!do_after(user, 3 SECONDS, src) || mounted_fish)
|
|
return ITEM_INTERACT_BLOCKING
|
|
add_fish(item, catcher = user.name)
|
|
balloon_alert_to_viewers("fish mounted")
|
|
playsound(loc, 'sound/machines/click.ogg', 30, TRUE)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/obj/structure/fish_mount/IsContainedAtomAccessible(atom/contained, atom/movable/user)
|
|
return TRUE
|
|
|
|
/obj/structure/fish_mount/proc/add_fish(obj/item/fish/fish, from_persistence = FALSE, catcher)
|
|
if(QDELETED(src)) // don't ever try to add a fish to one of these that's already been deleted - and get rid of the one that was created
|
|
qdel(fish)
|
|
return
|
|
if(QDELETED(fish)) // no adding deleted fishies either
|
|
return
|
|
if(mounted_fish)
|
|
mounted_fish.forceMove(loc)
|
|
fish.forceMove(src)
|
|
vis_contents += fish
|
|
fish.vis_flags |= (VIS_INHERIT_PLANE|VIS_INHERIT_LAYER)
|
|
fish.interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP
|
|
fish.obj_flags &= ~UNIQUE_RENAME
|
|
fish.remove_fillet_type()
|
|
fish.anchored = TRUE
|
|
mounted_fish = fish
|
|
|
|
if(!fish.catcher_name)
|
|
fish.catcher_name = catcher
|
|
if(!fish.catch_date)
|
|
fish.catch_date = "[time2text(world.realtime, "Day, Month DD", NO_TIMEZONE)], [CURRENT_STATION_YEAR]"
|
|
|
|
AddElement(/datum/element/beauty, get_fish_beauty())
|
|
RegisterSignals(fish, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW), PROC_REF(on_fish_attack_hand))
|
|
if(from_persistence)
|
|
persistence_loaded_fish = TRUE
|
|
fish.add_traits(list(TRAIT_NO_FISHING_ACHIEVEMENT, TRAIT_FISH_LOW_PRICE), INNATE_TRAIT)
|
|
else if(persistence_id)
|
|
SSpersistence.save_trophy_fish(src)
|
|
|
|
/obj/structure/fish_mount/proc/get_fish_beauty()
|
|
var/beauty = 100 + mounted_fish.beauty * 1.2
|
|
var/datum/material/main_material = mounted_fish.get_master_material()
|
|
if(main_material)
|
|
beauty += main_material.beauty_modifier * mounted_fish.weight
|
|
return round(beauty)
|
|
|
|
/obj/structure/fish_mount/proc/on_fish_attack_hand(datum/source, mob/living/user)
|
|
SIGNAL_HANDLER
|
|
INVOKE_ASYNC(src, PROC_REF(remove_fish), user)
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
/obj/structure/fish_mount/attack_hand_secondary(mob/living/user, list/modifiers)
|
|
. = ..()
|
|
if(!mounted_fish)
|
|
balloon_alert(user, "no fish mounted!")
|
|
else
|
|
remove_fish(user)
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
/obj/structure/fish_mount/proc/remove_fish(mob/living/user)
|
|
balloon_alert(user, "removing fish...")
|
|
if(!do_after(user, (persistence_loaded_fish ? 6 : 3) SECONDS, src) || !mounted_fish)
|
|
return
|
|
|
|
var/obj/item/fish/fish_reference = mounted_fish
|
|
if(persistence_loaded_fish)
|
|
roll_for_safe_removal(user)
|
|
|
|
if(QDELETED(fish_reference))
|
|
var/ash_type = /obj/effect/decal/cleanable/ash
|
|
if(fish_reference.w_class >= WEIGHT_CLASS_BULKY)
|
|
ash_type = /obj/effect/decal/cleanable/ash/large
|
|
new ash_type(loc)
|
|
visible_message("[fish_reference] turns into dust as [fish_reference.p_theyre()] removed from [src].")
|
|
else
|
|
user.put_in_hands(mounted_fish)
|
|
balloon_alert_to_viewers("fish removed")
|
|
|
|
/obj/structure/fish_mount/Exited(atom/movable/gone)
|
|
if(gone != mounted_fish)
|
|
return ..()
|
|
RemoveElement(/datum/element/beauty, get_fish_beauty())
|
|
if(!QDELETED(mounted_fish) && (!persistence_loaded_fish || roll_for_safe_removal()))
|
|
UnregisterSignal(mounted_fish, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW))
|
|
mounted_fish.vis_flags &= ~(VIS_INHERIT_PLANE|VIS_INHERIT_LAYER)
|
|
mounted_fish.interaction_flags_item |= INTERACT_ITEM_ATTACK_HAND_PICKUP
|
|
mounted_fish.obj_flags |= UNIQUE_RENAME
|
|
mounted_fish.add_fillet_type()
|
|
mounted_fish.anchored = FALSE
|
|
persistence_loaded_fish = FALSE
|
|
mounted_fish = null
|
|
return ..()
|
|
|
|
/obj/structure/fish_mount/proc/roll_for_safe_removal(mob/living/user)
|
|
if(isnull(mounted_fish))
|
|
return FALSE
|
|
|
|
///the base success rate is calculated considering the item inventory size and the heaviness of the fish.
|
|
var/success_prob = 100/(mounted_fish.w_class + GET_FISH_WEIGHT_RANK(mounted_fish.weight))
|
|
var/fishing_prowess = user?.mind?.get_skill_level(/datum/skill/fishing)
|
|
success_prob += fishing_prowess * 4 // up to 28% fixed bonus chance to safely retrieve the trophy depending on skill.
|
|
if(!prob(success_prob))
|
|
qdel(mounted_fish)
|
|
return FALSE
|
|
|
|
persistence_loaded_fish = FALSE //this way we don't roll again on Exited()
|
|
return TRUE
|
|
|
|
/obj/structure/fish_mount/bar
|
|
persistence_id = "Bar"
|
|
|
|
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fish_mount/bar, /obj/item/wallframe/fish::pixel_shift)
|