mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 05:30:05 +01:00
## About The Pull Request 50 files. Sorry about that, I was faster today. Just merge without looking, it'll be fine. This is the end of `/machinery/` & `/stack/` `attackby()`s(that aren't actually meant for being attacked) when these are all merged. Like, 200 left? I think? Also, this one will make light replacer reloading slightly more difficult until whichever one converted the light replacer is merged. If, for some ungodly reason, this one gets merged first. Changes beyond conversion: if a `/porta_turret_construct` somehow became anchored out of sync with its construction steps, it's no longer softlocked you can no longer place an infinite amount of blackboxes into the blackbox recorder a TTV will no longer keep its ghost on your back when you cut its wires while wearing it RCLs will properly update their appearance when initially given their first coil The creator of `robot_suit/attackby()` has been cursed to spend a thousand years in the lake of fire ## Why It's Good For The Game Now that all of these are remade, you can find bugs in them and then get GBP for fixing them(not that my code would ever have bugs). ## Changelog 🆑 fix: It's no longer possible to softlock building a turret(if it ever was) fix: you can no longer stuff the blackbox recorder full with as many blackboxes as you've somehow collected fix: TTVs will no longer remain on your back as a ghost when you cut their wire straps fix: RCLs will now properly update their appearance when given their first coil of cleaners code: 50 files have been converted from attackby() to item_interaction() /🆑
435 lines
14 KiB
Plaintext
435 lines
14 KiB
Plaintext
/obj/item/transfer_valve
|
|
icon = 'icons/obj/devices/assemblies.dmi'
|
|
name = "tank transfer valve"
|
|
icon_state = "valve_1"
|
|
base_icon_state = "valve"
|
|
inhand_icon_state = "ttv"
|
|
lefthand_file = 'icons/mob/inhands/weapons/bombs_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/weapons/bombs_righthand.dmi'
|
|
worn_icon = 'icons/mob/clothing/back/backpack.dmi'
|
|
worn_icon_state = "ttv"
|
|
desc = "Regulates the transfer of air between two tanks."
|
|
w_class = WEIGHT_CLASS_BULKY
|
|
|
|
var/obj/item/tank/tank_one
|
|
var/obj/item/tank/tank_two
|
|
var/obj/item/assembly/attached_device
|
|
var/mob/attacher = null
|
|
var/valve_open = FALSE
|
|
var/toggle = TRUE
|
|
///do we have cables attached to be able to be put on the back?
|
|
var/wired = FALSE
|
|
///our overlay when wired = true
|
|
var/mutable_appearance/cable_overlay
|
|
|
|
/obj/item/transfer_valve/Initialize(mapload)
|
|
. = ..()
|
|
AddElement(/datum/element/cuffable_item)
|
|
RegisterSignal(src, COMSIG_ITEM_FRIED, PROC_REF(on_fried))
|
|
register_context()
|
|
register_item_context()
|
|
|
|
/obj/item/transfer_valve/Destroy()
|
|
attached_device = null
|
|
return ..()
|
|
|
|
/obj/item/transfer_valve/examine(mob/user)
|
|
. = ..()
|
|
if(tank_one)
|
|
. += span_notice("A [tank_one] is attached to the primary port.")
|
|
if(tank_two)
|
|
. += span_notice("A [tank_two] is attached to the secondary port.")
|
|
if(!tank_one || !tank_two)
|
|
. += span_notice("You could attach a gas tank onto the open port.")
|
|
if(attached_device)
|
|
. += span_notice("A [attached_device] is attached to the fuse input.")
|
|
if(wired)
|
|
. += span_notice("It looks like some nutjob added makeshift backpack straps with [EXAMINE_HINT("wires")]...")
|
|
. += span_notice("You could cut off the straps with [EXAMINE_HINT(TOOL_WIRECUTTER)].")
|
|
|
|
/obj/item/transfer_valve/add_context(atom/source, list/context, obj/item/held_item, mob/user)
|
|
. = ..()
|
|
|
|
if(tank_one || tank_two)
|
|
context[SCREENTIP_CONTEXT_ALT_LMB] = "Remove [tank_one || tank_two]"
|
|
. = CONTEXTUAL_SCREENTIP_SET
|
|
if(istype(held_item) && is_type_in_list(held_item, list(/obj/item/tank, /obj/item/assembly)))
|
|
context[SCREENTIP_CONTEXT_LMB] = "Attach [held_item]"
|
|
. = CONTEXTUAL_SCREENTIP_SET
|
|
|
|
return . || NONE
|
|
|
|
/obj/item/transfer_valve/add_item_context(obj/item/source, list/context, atom/target, mob/living/user)
|
|
. = NONE
|
|
if(istype(target, /obj/vehicle/ridden/wheelchair))
|
|
var/obj/vehicle/ridden/wheelchair/chair = target
|
|
if(!chair.bell_attached)
|
|
context[SCREENTIP_CONTEXT_LMB] = "Attach TTV to wheelchair."
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
|
|
/obj/item/transfer_valve/click_alt(mob/user)
|
|
if(tank_one)
|
|
split_gases()
|
|
valve_open = FALSE
|
|
tank_one.forceMove(drop_location())
|
|
else if(tank_two)
|
|
split_gases()
|
|
valve_open = FALSE
|
|
tank_two.forceMove(drop_location())
|
|
|
|
return CLICK_ACTION_SUCCESS
|
|
|
|
/obj/item/transfer_valve/IsAssemblyHolder()
|
|
return TRUE
|
|
|
|
/obj/item/transfer_valve/Exited(atom/movable/gone, direction)
|
|
. = ..()
|
|
if(gone == tank_one)
|
|
tank_one = null
|
|
update_appearance()
|
|
else if(gone == tank_two)
|
|
tank_two = null
|
|
update_appearance()
|
|
|
|
/obj/item/transfer_valve/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
|
|
. = ..()
|
|
if(istype(interacting_with, /obj/vehicle/ridden/wheelchair))
|
|
var/obj/vehicle/ridden/wheelchair/chair = interacting_with
|
|
|
|
if (chair.bomb_attached)
|
|
user.balloon_alert(user, "already has a TTV!")
|
|
return ITEM_INTERACT_FAILURE
|
|
user.balloon_alert(user, "attaching TTV...")
|
|
if (!do_after(user, 0.5 SECONDS, chair))
|
|
return ITEM_INTERACT_FAILURE
|
|
|
|
chair.attach_bomb(src)
|
|
user.log_message("attached [src] to [chair]", LOG_GAME)
|
|
return ITEM_INTERACT_SUCCESS
|
|
else if(istype(interacting_with, /obj/item/tank))
|
|
if(try_attach_tank(interacting_with, user))
|
|
return ITEM_INTERACT_SUCCESS
|
|
else
|
|
return ITEM_INTERACT_FAILURE
|
|
else if(isassembly(interacting_with))
|
|
if(try_attach_assembly(interacting_with))
|
|
return ITEM_INTERACT_SUCCESS
|
|
else
|
|
return ITEM_INTERACT_FAILURE
|
|
return NONE
|
|
|
|
/obj/item/transfer_valve/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
|
if(istype(tool, /obj/item/tank))
|
|
try_attach_tank(tool, user)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
//TODO: Have this take an assemblyholder <-- commit five years ago
|
|
if(isassembly(tool))
|
|
try_attach_assembly(tool, user)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
if(istype(tool, /obj/item/stack/cable_coil) && !wired)
|
|
var/obj/item/stack/cable_coil/coil = tool
|
|
if (coil.get_amount() < 15)
|
|
to_chat(user, span_warning("You need fifteen lengths of coil for this!"))
|
|
return ITEM_INTERACT_BLOCKING
|
|
coil.use(15)
|
|
to_chat(user, span_notice("You add some cables, not being really sure why. Looks like <i>backpack</i> straps."))
|
|
wired = TRUE
|
|
slot_flags |= ITEM_SLOT_BACK
|
|
update_appearance()
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
return NONE
|
|
|
|
/obj/item/transfer_valve/wirecutter_act(mob/living/user, obj/item/tool)
|
|
if(!wired)
|
|
return ITEM_INTERACT_SKIP_TO_ATTACK
|
|
tool.play_tool_sound(src)
|
|
to_chat(user, span_notice("You remove the cables."))
|
|
wired = FALSE
|
|
slot_flags &= ~ITEM_SLOT_BACK
|
|
forceMove(drop_location())
|
|
new /obj/item/stack/cable_coil(drop_location(), 15)
|
|
update_appearance()
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
|
|
/obj/item/transfer_valve/proc/try_attach_tank(obj/item/tank/new_tank, mob/user)
|
|
if(!tank_one)
|
|
if(!user.transferItemToLoc(new_tank, src))
|
|
return FALSE
|
|
tank_one = new_tank
|
|
to_chat(user, span_notice("You attach the [new_tank] to the transfer valve's primary port."))
|
|
else if(!tank_two)
|
|
if(!user.transferItemToLoc(new_tank, src))
|
|
return FALSE
|
|
tank_two = new_tank
|
|
to_chat(user, span_notice("You attach the [new_tank] to the transfer valve's secondary port."))
|
|
else
|
|
to_chat(user, span_warning("There are already two tanks attached, remove one first!"))
|
|
return FALSE
|
|
|
|
update_appearance()
|
|
return TRUE
|
|
|
|
/obj/item/transfer_valve/proc/try_attach_assembly(obj/item/assembly/A, mob/user)
|
|
if(A.secured)
|
|
to_chat(user, span_notice("The [A] is secured; unsecure it first."))
|
|
return FALSE
|
|
if(attached_device)
|
|
to_chat(user, span_warning("There is already a device attached to the valve, remove it first!"))
|
|
return FALSE
|
|
if(!user.transferItemToLoc(A, src))
|
|
return FALSE
|
|
attached_device = A
|
|
to_chat(user, span_notice("You attach the [A] to the valve controls and secure it."))
|
|
A.holder = src
|
|
A.on_attach()
|
|
A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb).
|
|
log_bomber(user, "attached a [A.name] to a ttv -", src, null, FALSE)
|
|
attacher = user
|
|
return TRUE
|
|
|
|
//These keep attached devices synced up, for example a TTV with a mouse trap being found in a bag so it's triggered, or moving the TTV with an infrared beam sensor to update the beam's direction.
|
|
/obj/item/transfer_valve/Move()
|
|
. = ..()
|
|
if(attached_device)
|
|
attached_device.holder_movement()
|
|
|
|
/obj/item/transfer_valve/dropped()
|
|
. = ..()
|
|
if(attached_device)
|
|
attached_device.dropped()
|
|
|
|
/obj/item/transfer_valve/on_found(mob/finder)
|
|
if(attached_device)
|
|
attached_device.on_found(finder)
|
|
|
|
//Triggers mousetraps
|
|
/obj/item/transfer_valve/attack_hand(mob/user, list/modifiers)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
if(attached_device)
|
|
attached_device.attack_hand()
|
|
|
|
/obj/item/transfer_valve/proc/process_activation(obj/item/D)
|
|
if(toggle)
|
|
toggle = FALSE
|
|
toggle_valve()
|
|
addtimer(CALLBACK(src, PROC_REF(toggle_off)), 5) //To stop a signal being spammed from a proxy sensor constantly going off or whatever
|
|
|
|
/obj/item/transfer_valve/proc/toggle_off()
|
|
toggle = TRUE
|
|
|
|
/obj/item/transfer_valve/update_icon_state()
|
|
icon_state = "[base_icon_state][(!tank_one && !tank_two && !attached_device) ? "_1" : null]"
|
|
return ..()
|
|
|
|
/obj/item/transfer_valve/update_overlays()
|
|
. = ..()
|
|
if(tank_one)
|
|
. += "[tank_one.icon_state]"
|
|
|
|
if(!tank_two)
|
|
underlays = null
|
|
else
|
|
var/mutable_appearance/J = mutable_appearance(icon, icon_state = "[tank_two.icon_state]")
|
|
var/matrix/T = matrix()
|
|
T.Translate(-13, 0)
|
|
J.transform = T
|
|
underlays = list(J)
|
|
|
|
if(wired)
|
|
cable_overlay = mutable_appearance(icon, icon_state = "valve_cables", layer = layer + 0.05, appearance_flags = KEEP_TOGETHER)
|
|
add_overlay(cable_overlay)
|
|
|
|
else if(cable_overlay)
|
|
cut_overlay(cable_overlay, TRUE)
|
|
cable_overlay = null
|
|
|
|
worn_icon_state = "[initial(worn_icon_state)][tank_two ? "l" : ""][tank_one ? "r" : ""]"
|
|
if(ishuman(loc)) //worn
|
|
var/mob/living/carbon/human/human = loc
|
|
human.update_worn_back()
|
|
|
|
if(!attached_device)
|
|
return
|
|
|
|
. += "device"
|
|
if(!istype(attached_device, /obj/item/assembly/infra))
|
|
return
|
|
var/obj/item/assembly/infra/sensor = attached_device
|
|
if(sensor.on && sensor.visible)
|
|
. += "proxy_beam"
|
|
|
|
|
|
/// Merge both gases into a single tank. Combine the volume by default. If target tank isn't specified default to tank_two
|
|
/obj/item/transfer_valve/proc/merge_gases(obj/item/tank/target, change_volume = TRUE)
|
|
if(!target)
|
|
target = tank_two
|
|
|
|
if(!istype(target) || (target != tank_one && target != tank_two))
|
|
return FALSE
|
|
|
|
for(var/obj/effect/forcefield/cosmic_field/potential_field as anything in GLOB.active_cosmic_fields)
|
|
if(get_dist(potential_field, src) < 3)
|
|
new /obj/effect/temp_visual/revenant(get_turf(src))
|
|
return FALSE
|
|
|
|
// Throw both tanks into processing queue
|
|
var/datum/gas_mixture/target_mix = target.return_air()
|
|
var/datum/gas_mixture/other_mix
|
|
other_mix = (target == tank_one ? tank_two : tank_one).return_air()
|
|
|
|
if(change_volume)
|
|
target_mix.volume += other_mix.volume
|
|
|
|
target_mix.merge(other_mix.remove_ratio(1))
|
|
return TRUE
|
|
|
|
/obj/item/transfer_valve/proc/split_gases()
|
|
if (!valve_open || !tank_one || !tank_two)
|
|
return
|
|
var/datum/gas_mixture/mix_one = tank_one.return_air()
|
|
var/datum/gas_mixture/mix_two = tank_two.return_air()
|
|
|
|
var/volume_ratio = mix_one.volume/mix_two.volume
|
|
var/datum/gas_mixture/temp
|
|
temp = mix_two.remove_ratio(volume_ratio)
|
|
mix_one.merge(temp)
|
|
mix_two.volume -= mix_one.volume
|
|
|
|
/*
|
|
Exadv1: I know this isn't how it's going to work, but this was just to check
|
|
it explodes properly when it gets a signal (and it does).
|
|
*/
|
|
/obj/item/transfer_valve/proc/toggle_valve(obj/item/tank/target, change_volume = TRUE)
|
|
playsound(src, 'sound/effects/valve_opening.ogg', 50)
|
|
if(!valve_open && tank_one && tank_two)
|
|
var/turf/bombturf = get_turf(src)
|
|
|
|
var/attachment
|
|
var/attachment_signal_log
|
|
if(attached_device)
|
|
if(issignaler(attached_device))
|
|
var/obj/item/assembly/signaler/attached_signaller = attached_device
|
|
attachment = "<A href='byond://?_src_=holder;[HrefToken()];secrets=list_signalers'>[attached_signaller]</A>"
|
|
attachment_signal_log = attached_signaller.last_receive_signal_log ? "The following log entry is the last one associated with the attached signaller<br>[attached_signaller.last_receive_signal_log]" : "There is no signal log entry."
|
|
else
|
|
attachment = attached_device
|
|
|
|
var/admin_attachment_message
|
|
var/attachment_message
|
|
if(attachment)
|
|
admin_attachment_message = "The bomb had [attachment], which was attached by [attacher ? ADMIN_LOOKUPFLW(attacher) : "Unknown"]"
|
|
attachment_message = " with [attachment] attached by [attacher ? key_name_admin(attacher) : "Unknown"]"
|
|
|
|
var/mob/bomber = get_mob_by_key(fingerprintslast)
|
|
var/admin_bomber_message
|
|
var/bomber_message
|
|
if(bomber)
|
|
admin_bomber_message = "The bomb's most recent set of fingerprints indicate it was last touched by [ADMIN_LOOKUPFLW(bomber)]"
|
|
bomber_message = " - Last touched by: [key_name_admin(bomber)]"
|
|
bomber.log_message("opened bomb valve", LOG_GAME, log_globally = FALSE)
|
|
|
|
if(istype(attachment, /obj/item/assembly/voice))
|
|
var/obj/item/assembly/voice/spoken_trigger = attachment
|
|
attachment_message += " with the following activation message: \"[spoken_trigger.recorded]\""
|
|
admin_attachment_message += " with the following activation message: \"[spoken_trigger.recorded]\""
|
|
|
|
var/admin_bomb_message = "Bomb valve opened in [ADMIN_VERBOSEJMP(bombturf)]<br>[admin_attachment_message]<br>[admin_bomber_message]<br>[attachment_signal_log]"
|
|
GLOB.bombers += admin_bomb_message
|
|
message_admins(admin_bomb_message)
|
|
log_game("Bomb valve opened in [AREACOORD(bombturf)][attachment_message][bomber_message]")
|
|
|
|
valve_open = merge_gases(target, change_volume)
|
|
|
|
if(!valve_open)
|
|
stack_trace("TTV gas merging failed.")
|
|
|
|
for(var/i in 1 to 6)
|
|
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_appearance)), 20 + (i - 1) * 10)
|
|
|
|
else if(valve_open && tank_one && tank_two)
|
|
split_gases()
|
|
valve_open = FALSE
|
|
update_appearance()
|
|
/*
|
|
This doesn't do anything but the timer etc. expects it to be here
|
|
eventually maybe have it update icon to show state (timer, prox etc.) like old bombs
|
|
*/
|
|
/obj/item/transfer_valve/proc/c_state()
|
|
return
|
|
|
|
///Signal when deep fried, so it can have an explosive reaction!
|
|
/obj/item/transfer_valve/proc/on_fried(datum/source, fry_time)
|
|
SIGNAL_HANDLER
|
|
log_bomber(null, "TTV valve opened via deepfrying", src, "last fingerprints = [fingerprintslast]")
|
|
toggle_valve()
|
|
|
|
/obj/item/transfer_valve/ui_state(mob/user)
|
|
return GLOB.hands_state
|
|
|
|
/obj/item/transfer_valve/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "TransferValve", name)
|
|
ui.open()
|
|
|
|
/obj/item/transfer_valve/ui_data(mob/user)
|
|
var/list/data = list()
|
|
data["tank_one"] = tank_one ? tank_one.name : null
|
|
data["tank_two"] = tank_two ? tank_two.name : null
|
|
data["attached_device"] = attached_device ? attached_device.name : null
|
|
data["valve"] = valve_open
|
|
return data
|
|
|
|
/obj/item/transfer_valve/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
|
|
switch(action)
|
|
if("tankone")
|
|
if(tank_one)
|
|
split_gases()
|
|
valve_open = FALSE
|
|
tank_one.forceMove(drop_location())
|
|
. = TRUE
|
|
if("tanktwo")
|
|
if(tank_two)
|
|
split_gases()
|
|
valve_open = FALSE
|
|
tank_two.forceMove(drop_location())
|
|
. = TRUE
|
|
if("toggle")
|
|
toggle_valve()
|
|
. = TRUE
|
|
if("device")
|
|
if(attached_device)
|
|
attached_device.attack_self(usr)
|
|
. = TRUE
|
|
if("remove_device")
|
|
if(attached_device)
|
|
attached_device.on_detach()
|
|
attached_device = null
|
|
. = TRUE
|
|
|
|
update_appearance()
|
|
|
|
/**
|
|
* Returns if this is ready to be detonated. Checks if both tanks are in place.
|
|
*/
|
|
/obj/item/transfer_valve/proc/ready()
|
|
return tank_one && tank_two
|
|
|
|
/obj/item/transfer_valve/fake/Initialize(mapload)
|
|
. = ..()
|
|
|
|
tank_one = new /obj/item/tank/internals/plasma (src)
|
|
tank_two = new /obj/item/tank/internals/oxygen (src)
|
|
|
|
update_appearance()
|