mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 20:48:56 +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() /🆑
376 lines
13 KiB
Plaintext
376 lines
13 KiB
Plaintext
#define TURBINE_MAX_STORED_POWER (0.2 * STANDARD_CELL_CHARGE)
|
|
#define TURBINE_ANIMATION_TICKS_PER_TILE (1)
|
|
#define TURBINE_ANIMATION_TICKS (4)
|
|
#define TURBINE_CHARGE_PER_TILE (0.002 * STANDARD_CELL_CHARGE)
|
|
#define TURBINE_ANCHORED_POWER_PER_KPA (TURBINE_CHARGE_PER_TILE * 2)
|
|
#define TURBINE_MIN_SECONDS_BETWEEN_SOUNDS (0.33 SECONDS)
|
|
|
|
/obj/item/portable_wind_turbine
|
|
name = "portable wind turbine"
|
|
icon = 'icons/obj/wind_turbine.dmi'
|
|
icon_state = "icon"
|
|
base_icon_state = "icon"
|
|
desc = "A portable wind turbine that can charge attached energy based weaponry, PDAs, and other devices. As a safety mechanism after an unprecedented amount of amputations, only charges when attached to your back / the floor."
|
|
worn_icon = 'icons/obj/wind_turbine.dmi'
|
|
worn_icon_state = "base_turbine"
|
|
inhand_icon_state = "wind_turbine"
|
|
lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
|
|
inhand_x_dimension = 64
|
|
inhand_y_dimension = 64
|
|
slot_flags = ITEM_SLOT_SUITSTORE | ITEM_SLOT_BACK
|
|
force = 10
|
|
throwforce = 6
|
|
w_class = WEIGHT_CLASS_BULKY
|
|
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 22, /datum/material/plastic = SHEET_MATERIAL_AMOUNT * 5, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 0.5)
|
|
///What item is being charged currently?
|
|
var/obj/item/charging = null
|
|
///Did we put power into "charging" last process()?
|
|
var/using_power = FALSE
|
|
|
|
///Current rotor animation frame. (floating point value).
|
|
var/rotor_tick = 0
|
|
///Power that has been generated by moving about.
|
|
var/available_power = 0
|
|
///The last time (world.time) a sound was played at.
|
|
var/last_sound_time = 0
|
|
///Capacitor currently inserted.
|
|
var/obj/item/stock_parts/capacitor/cap = null
|
|
|
|
var/static/list/allowed_devices = typecacheof(list(
|
|
/obj/item/gun/energy,
|
|
/obj/item/compact_remote,
|
|
/obj/item/controller,
|
|
/obj/item/organ/cyberimp/bci,
|
|
/obj/item/integrated_circuit,
|
|
/obj/item/melee/baton/security,
|
|
/obj/item/modular_computer,
|
|
/obj/item/stock_parts/power_store/cell,
|
|
))
|
|
|
|
/obj/item/portable_wind_turbine/Initialize(mapload)
|
|
. = ..()
|
|
AddElement(/datum/element/drag_pickup)
|
|
RegisterSignal(src, COMSIG_MOVABLE_SET_ANCHORED, PROC_REF(on_anchor))
|
|
RegisterSignal(src, COMSIG_ATOM_PRE_DIR_CHANGE, PROC_REF(block_dir_changes_unanchored))
|
|
update_appearance()
|
|
|
|
/obj/item/portable_wind_turbine/loaded/Initialize(mapload)
|
|
. = ..()
|
|
cap = new /obj/item/stock_parts/capacitor(src)
|
|
|
|
/obj/item/portable_wind_turbine/Destroy()
|
|
return ..()
|
|
|
|
///Called when src is anchored
|
|
/obj/item/portable_wind_turbine/proc/on_anchor(atom/source, is_anchored)
|
|
SIGNAL_HANDLER
|
|
|
|
if (is_anchored)
|
|
RegisterSignal(src, COMSIG_MOVABLE_RESISTED_SPACEWIND, PROC_REF(on_space_wind))
|
|
UnregisterSignal(src, COMSIG_ATOM_PRE_DIR_CHANGE)
|
|
forceMove(get_turf(src))
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
setDir(SOUTH)
|
|
else
|
|
UnregisterSignal(src, COMSIG_MOVABLE_RESISTED_SPACEWIND)
|
|
RegisterSignal(src, COMSIG_ATOM_PRE_DIR_CHANGE, PROC_REF(block_dir_changes_unanchored))
|
|
|
|
///Called when src changes direction when not equipped
|
|
/obj/item/portable_wind_turbine/proc/block_dir_changes_unanchored(atom/source, old_dir, new_dir)
|
|
SIGNAL_HANDLER
|
|
|
|
return COMPONENT_ATOM_BLOCK_DIR_CHANGE
|
|
|
|
///Called when this resists space wind
|
|
/obj/item/portable_wind_turbine/proc/on_space_wind(atom/source, pressure_difference, pressure_direction)
|
|
SIGNAL_HANDLER
|
|
|
|
var/obj/item/portable_wind_turbine/turbine = source
|
|
if (!turbine)
|
|
return
|
|
if (isnull(cap))
|
|
return
|
|
turbine.add_power(TURBINE_ANCHORED_POWER_PER_KPA * pressure_difference * cap.rating, ignore_cap = TRUE)
|
|
set_rotor_tick(rotor_tick + 1)
|
|
|
|
/obj/item/portable_wind_turbine/update_appearance(updates)
|
|
. = ..()
|
|
update_back()
|
|
|
|
/obj/item/portable_wind_turbine/equipped(mob/user, slot, initial)
|
|
. = ..()
|
|
update_appearance()
|
|
if(slot & slot_flags)
|
|
RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
|
|
RegisterSignal(user, COMSIG_ATOM_POST_DIR_CHANGE, PROC_REF(on_dir_change))
|
|
else
|
|
setDir(SOUTH)
|
|
UnregisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
|
|
UnregisterSignal(user, COMSIG_ATOM_POST_DIR_CHANGE, PROC_REF(on_dir_change))
|
|
|
|
///Called when the thing HOLDING the turbine changes direction
|
|
/obj/item/portable_wind_turbine/proc/on_dir_change(datum/source, old_dir, new_dir)
|
|
SIGNAL_HANDLER
|
|
|
|
update_appearance()
|
|
|
|
///Updates the worn back icon for the current loc
|
|
/obj/item/portable_wind_turbine/proc/update_back()
|
|
if (ishuman(loc))
|
|
var/mob/living/carbon/human/human = loc
|
|
human.update_worn_back()
|
|
|
|
///Tries to play the woosh sound effect. May not play it if it's been too soon since the last call.
|
|
/obj/item/portable_wind_turbine/proc/try_playsound()
|
|
if ((world.time - last_sound_time) < TURBINE_MIN_SECONDS_BETWEEN_SOUNDS)
|
|
return
|
|
playsound(src, 'sound/machines/woosh.ogg', 20, FALSE)
|
|
last_sound_time = world.time
|
|
|
|
///Sets the rotor animation tick to a new value. Returns TRUE if the rotor made a full rotation.
|
|
/obj/item/portable_wind_turbine/proc/set_rotor_tick(new_tick)
|
|
var/last_rotor_tick = floor(rotor_tick)
|
|
rotor_tick = new_tick
|
|
var/made_full_rotation = FALSE
|
|
if (rotor_tick >= TURBINE_ANIMATION_TICKS)
|
|
rotor_tick -= floor(rotor_tick / TURBINE_ANIMATION_TICKS) * TURBINE_ANIMATION_TICKS
|
|
try_playsound()
|
|
made_full_rotation = TRUE
|
|
var/rounded_rotor_tick = floor(rotor_tick)
|
|
if (rounded_rotor_tick != last_rotor_tick)
|
|
update_appearance()
|
|
return made_full_rotation
|
|
|
|
///Adds a certain amount of power to the internal buffer
|
|
/obj/item/portable_wind_turbine/proc/add_power(power, ignore_cap = FALSE)
|
|
if (ignore_cap)
|
|
available_power += power
|
|
else
|
|
available_power = min(available_power + power, TURBINE_MAX_STORED_POWER * (isnull(cap?.rating) ? 1 : cap.rating))
|
|
|
|
///Called when the thing HOLDING the turbine moves
|
|
/obj/item/portable_wind_turbine/proc/on_move(atom/thing, atom/old_loc, dir)
|
|
SIGNAL_HANDLER
|
|
|
|
var/mob/living/user = thing
|
|
if (!user)
|
|
return
|
|
if (isnull(cap))
|
|
return
|
|
var/distance = get_dist(old_loc, user.loc)
|
|
var/turf/open/open_turf = get_turf(user)
|
|
if (!istype(open_turf))
|
|
return
|
|
var/pressure_factor = open_turf.air.return_pressure() / 101.0
|
|
if (pressure_factor <= 0)
|
|
return
|
|
var/made_full_rotation = set_rotor_tick(rotor_tick + distance * TURBINE_ANIMATION_TICKS_PER_TILE * pressure_factor)
|
|
add_power(distance * TURBINE_CHARGE_PER_TILE * pressure_factor * cap.rating)
|
|
if (!made_full_rotation)
|
|
return
|
|
if (!HAS_TRAIT(user, TRAIT_CLUMSY))
|
|
return
|
|
var/obj/item/bodypart/head/head_to_bash = user.get_bodypart(BODY_ZONE_HEAD)
|
|
if (!head_to_bash)
|
|
return
|
|
user.Paralyze(5)
|
|
user.Knockdown(10)
|
|
user.visible_message(span_danger("[user] gets whacked in the head by the [src]'s spinning blades!"), span_userdanger("You get hit in the head by the [src] and fall over!"))
|
|
// imaginary friends call sleep in their emotes
|
|
// even though imaginary friends can't put on a wind turbine I still have to do this
|
|
INVOKE_ASYNC(user, TYPE_PROC_REF(/mob/living/, emote), "scream")
|
|
user.apply_damage(5, BRUTE, head_to_bash, attacking_item=src)
|
|
playsound(source = src, soundin = 'sound/items/weapons/smash.ogg', vol = src.get_clamped_volume(), vary = TRUE)
|
|
|
|
/obj/item/portable_wind_turbine/wrench_act(mob/living/user, obj/item/tool)
|
|
. = NONE
|
|
switch(default_unfasten_wrench(user, tool, 4 SECONDS))
|
|
if(SUCCESSFUL_UNFASTEN)
|
|
return ITEM_INTERACT_SUCCESS
|
|
if(FAILED_UNFASTEN)
|
|
return ITEM_INTERACT_BLOCKING
|
|
return .
|
|
|
|
/obj/item/portable_wind_turbine/examine(mob/user)
|
|
. = ..()
|
|
|
|
if(!in_range(user, src) && !issilicon(user) && !isobserver(user))
|
|
. += span_warning("You're too far away to examine [src]'s contents! You can still watch it spin so wonderfully though...")
|
|
if (charging && istype(charging,/obj/item/melee/baton/security/))
|
|
. += span_info("You can see the [charging] hanging precariously off the charging port...")
|
|
return
|
|
|
|
if(cap)
|
|
. += span_info("Click it with a screwdriver to eject the [cap].")
|
|
. += span_info("Wrench it on a tile to anchor it and harness space wind.")
|
|
. += span_info("The wind turbine is currently storing [floor(available_power / 100) / 10]kJ.")
|
|
if(charging)
|
|
. += {"[span_notice("\The [src] contains:")]
|
|
[span_notice("- \A [charging].")]"}
|
|
|
|
/obj/item/portable_wind_turbine/screwdriver_act(mob/living/user, obj/item/tool)
|
|
. = ..()
|
|
if(charging)
|
|
user.balloon_alert(user, "remove the [charging] first!")
|
|
return FALSE
|
|
if(cap)
|
|
tool.play_tool_sound(src, 50)
|
|
user.balloon_alert(user, "capacitor removed")
|
|
cap.forceMove(drop_location())
|
|
available_power = 0
|
|
cap = null
|
|
return TRUE
|
|
else
|
|
user.balloon_alert(user, "no capacitor!")
|
|
return FALSE
|
|
|
|
/obj/item/portable_wind_turbine/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
|
|
if(is_type_in_typecache(arrived, allowed_devices))
|
|
charging = arrived
|
|
START_PROCESSING(SSmachines, src)
|
|
using_power = TRUE
|
|
update_appearance()
|
|
return ..()
|
|
|
|
/obj/item/portable_wind_turbine/Exited(atom/movable/gone, direction)
|
|
if(gone == charging)
|
|
if(!QDELING(charging))
|
|
charging.update_appearance()
|
|
charging = null
|
|
using_power = FALSE
|
|
update_appearance()
|
|
return ..()
|
|
|
|
/obj/item/portable_wind_turbine/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
|
if(istype(tool, /obj/item/stock_parts/capacitor))
|
|
if (cap)
|
|
balloon_alert(user, "already has a capacitor!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
user.transferItemToLoc(tool, src)
|
|
cap = tool
|
|
balloon_alert(user, "inserted the [tool]")
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
if(!is_type_in_typecache(tool, allowed_devices))
|
|
return NONE
|
|
|
|
if(isnull(cap))
|
|
balloon_alert(user, "no capacitor inserted!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
if(charging)
|
|
balloon_alert(user, "already charging something!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
if(istype(tool, /obj/item/gun/energy))
|
|
var/obj/item/gun/energy/energy_gun = tool
|
|
if(!energy_gun.can_charge)
|
|
balloon_alert(user, "not rechargable!")
|
|
return ITEM_INTERACT_BLOCKING
|
|
user.transferItemToLoc(tool, src)
|
|
charging = tool
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/obj/item/portable_wind_turbine/attack_hand(mob/user, list/modifiers)
|
|
if(loc == user || (istype(loc, /turf) && !isnull(charging)))
|
|
take_charging_out(user)
|
|
return TRUE
|
|
add_fingerprint(user)
|
|
return ..()
|
|
|
|
/obj/item/portable_wind_turbine/handle_deconstruct(dissassembled)
|
|
charging?.forceMove(drop_location())
|
|
cap?.forceMove(drop_location())
|
|
return ..()
|
|
|
|
///Takes charging item out if there is one
|
|
/obj/item/portable_wind_turbine/proc/take_charging_out(mob/user)
|
|
if(isnull(charging) || user.put_in_hands(charging))
|
|
return
|
|
charging.forceMove(drop_location())
|
|
update_appearance()
|
|
|
|
/obj/item/portable_wind_turbine/attack_tk(mob/user)
|
|
if(isnull(charging))
|
|
return
|
|
charging.forceMove(drop_location())
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
/obj/item/portable_wind_turbine/process(seconds_per_tick)
|
|
using_power = FALSE
|
|
if(isnull(charging))
|
|
return PROCESS_KILL
|
|
if(isnull(cap))
|
|
// this is easier than starting/stopping the process based on capacitor state
|
|
// this code only charges the attached item, so stopping it early should not be a problem
|
|
return
|
|
var/obj/item/stock_parts/power_store/cell/charging_cell = charging.get_cell()
|
|
if (!charging_cell && istype(charging, /obj/item/stock_parts/power_store/cell))
|
|
charging_cell = charging
|
|
if (!charging_cell)
|
|
var/datum/component/shell/shell = charging.GetComponent(/datum/component/shell)
|
|
charging_cell = shell?.attached_circuit?.get_cell()
|
|
if(charging_cell)
|
|
var/wanted_power = min(charging_cell.maxcharge - charging_cell.charge, charging_cell.chargerate)
|
|
if(wanted_power > 0)
|
|
var/power_to_give = min(available_power, wanted_power) * seconds_per_tick / 2
|
|
if (power_to_give > 0)
|
|
charging_cell.give(power_to_give)
|
|
available_power -= power_to_give
|
|
if(charging_cell.charge == charging_cell.maxcharge)
|
|
playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
|
|
say("[charging] has finished recharging!")
|
|
else
|
|
using_power = TRUE
|
|
update_appearance()
|
|
|
|
/obj/item/portable_wind_turbine/emp_act(severity)
|
|
. = ..()
|
|
if (. & EMP_PROTECT_CONTENTS)
|
|
return
|
|
|
|
if(istype(charging, /obj/item/gun/energy))
|
|
var/obj/item/gun/energy/energy_gun = charging
|
|
energy_gun?.cell.emp_act(severity)
|
|
|
|
else if(istype(charging, /obj/item/melee/baton/security))
|
|
var/obj/item/melee/baton/security/batong = charging
|
|
batong?.cell.charge = 0
|
|
|
|
/obj/item/portable_wind_turbine/update_overlays()
|
|
. = ..()
|
|
var/mutable_appearance/rotor = mutable_appearance(worn_icon, "rotor_[floor(rotor_tick)]")
|
|
rotor.pixel_y -= 8
|
|
. += rotor
|
|
if (isnull(charging))
|
|
return
|
|
if (istype(charging, /obj/item/melee/baton/security/))
|
|
. += mutable_appearance(icon, "baton")
|
|
|
|
/obj/item/portable_wind_turbine/worn_overlays(mutable_appearance/standing, isinhands, icon_file, bodyshape = NONE)
|
|
. = ..()
|
|
if (isinhands)
|
|
return
|
|
var/mutable_appearance/rotor = mutable_appearance(worn_icon, "rotor_[floor(rotor_tick)]")
|
|
rotor.layer = BELOW_MOB_LAYER
|
|
if (ishuman(loc))
|
|
var/mob/living/carbon/human/user = loc
|
|
if (user.dir & NORTH)
|
|
var/mutable_appearance/just_render_above_other_things = mutable_appearance(worn_icon, worn_icon_state)
|
|
just_render_above_other_things.layer = ABOVE_MOB_LAYER
|
|
rotor.layer = ABOVE_MOB_LAYER
|
|
. += just_render_above_other_things
|
|
. += rotor
|
|
if (isnull(charging))
|
|
return
|
|
if (istype(charging, /obj/item/melee/baton/security/))
|
|
var/mutable_appearance/baton_overlay = mutable_appearance(icon, "baton")
|
|
. += baton_overlay
|
|
|
|
#undef TURBINE_MAX_STORED_POWER
|
|
#undef TURBINE_ANIMATION_TICKS_PER_TILE
|
|
#undef TURBINE_ANIMATION_TICKS
|
|
#undef TURBINE_CHARGE_PER_TILE
|
|
#undef TURBINE_ANCHORED_POWER_PER_KPA
|
|
#undef TURBINE_MIN_SECONDS_BETWEEN_SOUNDS
|