mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-27 01:21:30 +00:00
## About The Pull Request Implements half of this (with some minor changes):  The ultimate goal of this is to split our attack chain in two: - One for non-combat item interactions - Health analyzer scanning - using tools on stuff - surgery - Niche other interactions - One for combat attacking - Item hit thing, item deal damage. - Special effects on attack would go here. This PR begins this by broadining tool act into item interact. Item interact is a catch-all proc ran at the beginning of attack chain, before `pre_attack` and such, that handles the first part of the chain. This allows us to easily catch item interaction and cancel the attack part of the chain by using deliberate bitflag return values, rather than `TRUE` / `FALSE`*. *Because right now, `TRUE` = `cancel attack`, no matter what, which is unclear to people. Instead of moving as much as possible to the new proc in this PR, I started by doing some easy, obvious things. More things can be moved in the future, or technically they don't even need to move in a lot of cases. ## Changelog 🆑 Melbert refactor: Refactored some methods of items interacting with other objects or mobs, such as surgery and health analzyers. Report if anything seems wrong /🆑
391 lines
12 KiB
Plaintext
391 lines
12 KiB
Plaintext
/// Max number of unanchored items that will be moved from a tile when attempting to add a window to a grille.
|
|
#define CLEAR_TILE_MOVE_LIMIT 20
|
|
|
|
/obj/structure/grille
|
|
desc = "A flimsy framework of iron rods."
|
|
name = "grille"
|
|
icon = 'icons/obj/structures.dmi'
|
|
icon_state = "grille"
|
|
base_icon_state = "grille"
|
|
density = TRUE
|
|
anchored = TRUE
|
|
pass_flags_self = PASSGRILLE
|
|
obj_flags = CONDUCTS_ELECTRICITY
|
|
obj_flags = CAN_BE_HIT | IGNORE_DENSITY
|
|
pressure_resistance = 5*ONE_ATMOSPHERE
|
|
armor_type = /datum/armor/structure_grille
|
|
max_integrity = 50
|
|
integrity_failure = 0.4
|
|
var/rods_type = /obj/item/stack/rods
|
|
var/rods_amount = 2
|
|
|
|
/datum/armor/structure_grille
|
|
melee = 50
|
|
bullet = 70
|
|
laser = 70
|
|
energy = 100
|
|
bomb = 10
|
|
|
|
/obj/structure/grille/Initialize(mapload)
|
|
. = ..()
|
|
AddElement(/datum/element/atmos_sensitive, mapload)
|
|
|
|
/obj/structure/grille/Destroy()
|
|
update_cable_icons_on_turf(get_turf(src))
|
|
return ..()
|
|
|
|
/obj/structure/grille/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
|
. = ..()
|
|
update_appearance()
|
|
|
|
/obj/structure/grille/update_appearance(updates)
|
|
if(QDELETED(src) || broken)
|
|
return
|
|
|
|
. = ..()
|
|
if((updates & UPDATE_SMOOTHING) && (smoothing_flags & (SMOOTH_CORNERS|SMOOTH_BITMASK)))
|
|
QUEUE_SMOOTH(src)
|
|
|
|
/obj/structure/grille/update_icon_state()
|
|
icon_state = "[base_icon_state][((atom_integrity / max_integrity) <= 0.5) ? "50_[rand(0, 3)]" : null]"
|
|
return ..()
|
|
|
|
/obj/structure/grille/examine(mob/user)
|
|
. = ..()
|
|
if(obj_flags & NO_DECONSTRUCTION)
|
|
return
|
|
|
|
if(anchored)
|
|
. += span_notice("It's secured in place with <b>screws</b>. The rods look like they could be <b>cut</b> through.")
|
|
else
|
|
. += span_notice("The anchoring screws are <i>unscrewed</i>. The rods look like they could be <b>cut</b> through.")
|
|
|
|
/obj/structure/grille/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
|
|
switch(the_rcd.mode)
|
|
if(RCD_DECONSTRUCT)
|
|
return list("delay" = 2 SECONDS, "cost" = 5)
|
|
if(RCD_WINDOWGRILLE)
|
|
var/cost = 0
|
|
var/delay = 0
|
|
|
|
if(the_rcd.rcd_design_path == /obj/structure/window)
|
|
cost = 4
|
|
delay = 2 SECONDS
|
|
else if(the_rcd.rcd_design_path == /obj/structure/window/reinforced)
|
|
cost = 6
|
|
delay = 2.5 SECONDS
|
|
else if(the_rcd.rcd_design_path == /obj/structure/window/fulltile)
|
|
cost = 8
|
|
delay = 3 SECONDS
|
|
else if(the_rcd.rcd_design_path == /obj/structure/window/reinforced/fulltile)
|
|
cost = 12
|
|
delay = 4 SECONDS
|
|
if(!cost)
|
|
return FALSE
|
|
|
|
return rcd_result_with_memory(
|
|
list("delay" = delay, "cost" = cost),
|
|
get_turf(src), RCD_MEMORY_WINDOWGRILLE,
|
|
)
|
|
return FALSE
|
|
|
|
/obj/structure/grille/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, list/rcd_data)
|
|
switch(rcd_data["[RCD_DESIGN_MODE]"])
|
|
if(RCD_DECONSTRUCT)
|
|
qdel(src)
|
|
return TRUE
|
|
if(RCD_WINDOWGRILLE)
|
|
if(!isturf(loc))
|
|
return FALSE
|
|
var/turf/T = loc
|
|
|
|
if(repair_grille())
|
|
balloon_alert(user, "grille rebuilt")
|
|
if(!clear_tile(user))
|
|
return FALSE
|
|
|
|
var/obj/structure/window/window_path = rcd_data["[RCD_DESIGN_PATH]"]
|
|
if(!ispath(window_path))
|
|
CRASH("Invalid window path type in RCD: [window_path]")
|
|
|
|
//checks if its a valid build direction
|
|
if(!initial(window_path.fulltile))
|
|
if(!valid_build_direction(loc, user.dir, is_fulltile = FALSE))
|
|
balloon_alert(user, "window already here!")
|
|
return FALSE
|
|
|
|
var/obj/structure/window/WD = new window_path(T, user.dir)
|
|
WD.set_anchored(TRUE)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/structure/grille/proc/clear_tile(mob/user)
|
|
var/at_users_feet = get_turf(user)
|
|
|
|
var/unanchored_items_on_tile
|
|
var/obj/item/last_item_moved
|
|
for(var/obj/item/item_to_move in loc.contents)
|
|
if(!item_to_move.anchored)
|
|
if(unanchored_items_on_tile <= CLEAR_TILE_MOVE_LIMIT)
|
|
item_to_move.forceMove(at_users_feet)
|
|
last_item_moved = item_to_move
|
|
unanchored_items_on_tile++
|
|
|
|
if(!unanchored_items_on_tile)
|
|
return TRUE
|
|
|
|
to_chat(user, span_notice("You move [unanchored_items_on_tile == 1 ? "[last_item_moved]" : "some things"] out of the way."))
|
|
|
|
if(unanchored_items_on_tile - CLEAR_TILE_MOVE_LIMIT > 0)
|
|
to_chat(user, span_warning("There's still too much stuff in the way!"))
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/obj/structure/grille/Bumped(atom/movable/AM)
|
|
if(!ismob(AM))
|
|
return
|
|
var/mob/M = AM
|
|
shock(M, 70)
|
|
|
|
/obj/structure/grille/attack_animal(mob/user, list/modifiers)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
if(!shock(user, 70) && !QDELETED(src)) //Last hit still shocks but shouldn't deal damage to the grille
|
|
take_damage(rand(5,10), BRUTE, MELEE, 1)
|
|
|
|
/obj/structure/grille/attack_paw(mob/user, list/modifiers)
|
|
return attack_hand(user, modifiers)
|
|
|
|
/obj/structure/grille/hulk_damage()
|
|
return 60
|
|
|
|
/obj/structure/grille/attack_hulk(mob/living/carbon/human/user)
|
|
if(shock(user, 70))
|
|
return
|
|
. = ..()
|
|
|
|
/obj/structure/grille/attack_hand(mob/living/user, list/modifiers)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
user.changeNext_move(CLICK_CD_MELEE)
|
|
user.do_attack_animation(src, ATTACK_EFFECT_KICK)
|
|
user.visible_message(span_warning("[user] hits [src]."), null, null, COMBAT_MESSAGE_RANGE)
|
|
log_combat(user, src, "hit")
|
|
if(!shock(user, 70))
|
|
take_damage(rand(5,10), BRUTE, MELEE, 1)
|
|
|
|
/obj/structure/grille/attack_alien(mob/living/user, list/modifiers)
|
|
user.do_attack_animation(src)
|
|
user.changeNext_move(CLICK_CD_MELEE)
|
|
user.visible_message(span_warning("[user] mangles [src]."), null, null, COMBAT_MESSAGE_RANGE)
|
|
if(!shock(user, 70))
|
|
take_damage(20, BRUTE, MELEE, 1)
|
|
|
|
/obj/structure/grille/CanAllowThrough(atom/movable/mover, border_dir)
|
|
. = ..()
|
|
if(!. && isprojectile(mover))
|
|
return prob(30)
|
|
|
|
/obj/structure/grille/CanAStarPass(to_dir, datum/can_pass_info/pass_info)
|
|
if(!density)
|
|
return TRUE
|
|
if(pass_info.pass_flags & PASSGRILLE)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/structure/grille/wirecutter_act(mob/living/user, obj/item/tool)
|
|
add_fingerprint(user)
|
|
if(shock(user, 100))
|
|
return
|
|
if(obj_flags & NO_DECONSTRUCTION)
|
|
return FALSE
|
|
tool.play_tool_sound(src, 100)
|
|
deconstruct()
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/obj/structure/grille/screwdriver_act(mob/living/user, obj/item/tool)
|
|
if(!isturf(loc))
|
|
return FALSE
|
|
add_fingerprint(user)
|
|
if(shock(user, 90))
|
|
return FALSE
|
|
if(obj_flags & NO_DECONSTRUCTION)
|
|
return FALSE
|
|
if(!tool.use_tool(src, user, 0, volume=100))
|
|
return FALSE
|
|
set_anchored(!anchored)
|
|
user.visible_message(span_notice("[user] [anchored ? "fastens" : "unfastens"] [src]."), \
|
|
span_notice("You [anchored ? "fasten [src] to" : "unfasten [src] from"] the floor."))
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/obj/structure/grille/attackby(obj/item/W, mob/user, params)
|
|
user.changeNext_move(CLICK_CD_MELEE)
|
|
if(istype(W, /obj/item/stack/rods) && broken && do_after(user, 1 SECONDS, target = src))
|
|
if(shock(user, 90))
|
|
return
|
|
var/obj/item/stack/rods/R = W
|
|
user.visible_message(span_notice("[user] rebuilds the broken grille."), \
|
|
span_notice("You rebuild the broken grille."))
|
|
repair_grille()
|
|
R.use(1)
|
|
return TRUE
|
|
|
|
//window placing begin
|
|
else if(is_glass_sheet(W) || istype(W, /obj/item/stack/sheet/bronze))
|
|
if (!broken)
|
|
var/obj/item/stack/ST = W
|
|
if (ST.get_amount() < 2)
|
|
to_chat(user, span_warning("You need at least two sheets of glass for that!"))
|
|
return
|
|
var/dir_to_set = SOUTHWEST
|
|
if(!anchored)
|
|
to_chat(user, span_warning("[src] needs to be fastened to the floor first!"))
|
|
return
|
|
for(var/obj/structure/window/WINDOW in loc)
|
|
to_chat(user, span_warning("There is already a window there!"))
|
|
return
|
|
if(!clear_tile(user))
|
|
return
|
|
to_chat(user, span_notice("You start placing the window..."))
|
|
if(do_after(user,20, target = src))
|
|
if(!src.loc || !anchored) //Grille broken or unanchored while waiting
|
|
return
|
|
for(var/obj/structure/window/WINDOW in loc) //Another window already installed on grille
|
|
return
|
|
if(!clear_tile(user))
|
|
return
|
|
var/obj/structure/window/WD
|
|
if(istype(W, /obj/item/stack/sheet/plasmarglass))
|
|
WD = new/obj/structure/window/reinforced/plasma/fulltile(drop_location()) //reinforced plasma window
|
|
else if(istype(W, /obj/item/stack/sheet/plasmaglass))
|
|
WD = new/obj/structure/window/plasma/fulltile(drop_location()) //plasma window
|
|
else if(istype(W, /obj/item/stack/sheet/rglass))
|
|
WD = new/obj/structure/window/reinforced/fulltile(drop_location()) //reinforced window
|
|
else if(istype(W, /obj/item/stack/sheet/titaniumglass))
|
|
WD = new/obj/structure/window/reinforced/shuttle(drop_location())
|
|
else if(istype(W, /obj/item/stack/sheet/plastitaniumglass))
|
|
WD = new/obj/structure/window/reinforced/plasma/plastitanium(drop_location())
|
|
else if(istype(W, /obj/item/stack/sheet/bronze))
|
|
WD = new/obj/structure/window/bronze/fulltile(drop_location())
|
|
else
|
|
WD = new/obj/structure/window/fulltile(drop_location()) //normal window
|
|
WD.setDir(dir_to_set)
|
|
WD.set_anchored(FALSE)
|
|
WD.state = 0
|
|
ST.use(2)
|
|
to_chat(user, span_notice("You place [WD] on [src]."))
|
|
return
|
|
//window placing end
|
|
|
|
else if((W.obj_flags & CONDUCTS_ELECTRICITY) && shock(user, 70))
|
|
return
|
|
|
|
return ..()
|
|
|
|
/obj/structure/grille/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
|
switch(damage_type)
|
|
if(BRUTE)
|
|
if(damage_amount)
|
|
playsound(src, 'sound/effects/grillehit.ogg', 80, TRUE)
|
|
else
|
|
playsound(src, 'sound/weapons/tap.ogg', 50, TRUE)
|
|
if(BURN)
|
|
playsound(src, 'sound/items/welder.ogg', 80, TRUE)
|
|
|
|
|
|
/obj/structure/grille/deconstruct(disassembled = TRUE)
|
|
if(!loc) //if already qdel'd somehow, we do nothing
|
|
return
|
|
if(!(obj_flags & NO_DECONSTRUCTION))
|
|
var/obj/R = new rods_type(drop_location(), rods_amount)
|
|
transfer_fingerprints_to(R)
|
|
qdel(src)
|
|
..()
|
|
|
|
/obj/structure/grille/atom_break()
|
|
. = ..()
|
|
if(!broken && !(obj_flags & NO_DECONSTRUCTION))
|
|
icon_state = "brokengrille"
|
|
set_density(FALSE)
|
|
atom_integrity = 20
|
|
broken = TRUE
|
|
rods_amount = 1
|
|
var/obj/item/dropped_rods = new rods_type(drop_location(), rods_amount)
|
|
transfer_fingerprints_to(dropped_rods)
|
|
|
|
/obj/structure/grille/proc/repair_grille()
|
|
if(broken)
|
|
icon_state = "grille"
|
|
set_density(TRUE)
|
|
atom_integrity = max_integrity
|
|
broken = FALSE
|
|
rods_amount = 2
|
|
return TRUE
|
|
return FALSE
|
|
|
|
// shock user with probability prb (if all connections & power are working)
|
|
// returns 1 if shocked, 0 otherwise
|
|
|
|
/obj/structure/grille/proc/shock(mob/user, prb)
|
|
if(!anchored || broken) // anchored/broken grilles are never connected
|
|
return FALSE
|
|
if(!prob(prb))
|
|
return FALSE
|
|
if(!in_range(src, user))//To prevent TK and mech users from getting shocked
|
|
return FALSE
|
|
var/turf/T = get_turf(src)
|
|
if(T.overfloor_placed)//cant be a floor in the way!
|
|
return FALSE
|
|
// Shocking hurts the grille (to weaken monkey powersinks)
|
|
if(prob(50))
|
|
take_damage(1, BURN, FIRE, sound_effect = FALSE)
|
|
var/obj/structure/cable/C = T.get_cable_node()
|
|
if(C)
|
|
if(electrocute_mob(user, C, src, 1, TRUE))
|
|
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
|
s.set_up(3, 1, src)
|
|
s.start()
|
|
return TRUE
|
|
else
|
|
return FALSE
|
|
return FALSE
|
|
|
|
/obj/structure/grille/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
|
|
return exposed_temperature > T0C + 1500 && !broken
|
|
|
|
/obj/structure/grille/atmos_expose(datum/gas_mixture/air, exposed_temperature)
|
|
take_damage(1, BURN, 0, 0)
|
|
|
|
/obj/structure/grille/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
|
if(isobj(AM))
|
|
if(prob(50) && anchored && !broken)
|
|
var/obj/O = AM
|
|
if(O.throwforce != 0)//don't want to let people spam tesla bolts, this way it will break after time
|
|
var/turf/T = get_turf(src)
|
|
if(T.overfloor_placed)
|
|
return FALSE
|
|
var/obj/structure/cable/C = T.get_cable_node()
|
|
if(C)
|
|
playsound(src, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5)
|
|
tesla_zap(source = src, zap_range = 3, power = C.newavail() * 0.01, cutoff = 1e3, zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot.
|
|
C.add_delayedload(C.newavail() * 0.0375) // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock. // What do you mean by this?
|
|
return ..()
|
|
|
|
/obj/structure/grille/get_dumping_location()
|
|
return null
|
|
|
|
/obj/structure/grille/broken // Pre-broken grilles for map placement
|
|
icon_state = "brokengrille"
|
|
density = FALSE
|
|
broken = TRUE
|
|
rods_amount = 1
|
|
|
|
/obj/structure/grille/broken/Initialize(mapload)
|
|
. = ..()
|
|
take_damage(max_integrity * 0.6)
|
|
|
|
#undef CLEAR_TILE_MOVE_LIMIT
|