Files
Bubberstation/code/modules/fishing/fish_mount.dm
TiviPlus 88c2213f1e Force UTC±0 for time2text logging and IC times (#90347)
## About The Pull Request
This won't actually do anything on live, since those are all set to
UTC±0 currently

Pins logging and IC uses of time2text to UTC±0 instead of using the
system timezone (byond default)
Timezones not being set to utc0 caused issues before (and is again)

All timezones are now passed explicitly to make it more likely it's
cargo culted properly at least

Deletes worldtime2text cus it was gameTimestamp default args

## Why It's Good For The Game
Server timezone changes probably shouldn't affect logging, round times,
file hashes, IC time, when you caught fish, etc

## Changelog
🆑
refactor: Logging and IC timestamps will now always use UTC±0 and not be
affected by server system timezone changes
fix: Station and round times will not longer be incorrect if the system
timezone is not UTC±0
/🆑

---------

Co-authored-by: TiviPlus <572233640+TiviPlus@users.noreply.com>
2025-04-01 22:08:15 +02:00

227 lines
8.3 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)
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, floor_to_wall_dir)
. = ..()
//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(floor_to_wall_dir)
setDir(floor_to_wall_dir)
find_and_hang_on_wall()
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/obj/item/fish/fish_path = pick(subtypesof(/obj/item/fish) - list(typesof(/obj/item/fish/holo) + list(/obj/item/fish/starfish/chrystarfish))) // chrystarfish immediately shatters when placed
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/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.flags_1 |= IS_ONTOP_1
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))
rotate_fish(dir)
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/rotate_fish(direction, old_direction)
var/rotation = angle2dir(REVERSE_DIR(direction))
if(old_direction)
rotation -= angle2dir(REVERSE_DIR(old_direction))
if(!rotation)
return
mounted_fish.transform = mounted_fish.transform.Turn(rotation)
/obj/structure/fish_mount/setDir(newdir)
var/old_dir = dir
. = ..()
rotate_fish(dir, old_dir)
/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()))
rotate_fish(0, dir)
UnregisterSignal(mounted_fish, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW))
mounted_fish.flags_1 &= ~IS_ONTOP_1
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)