mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-07 05:05:22 +01:00
cca0dfe7b6
Part one of our nefarious plans to destroy lag forever, and also accomplish some cool shit. This replaces our renderer system with plane masters, this will also be used to turn skyboxes into backdrops and thus totally remove skybox updating lag. Additionally, this will let us manipulate entire planes very easily to do all sorts of zany shit. All credit goes to the original coders, this is some seriously cool stuff. Also fixes some bizarre smoothing behaviour, reduces updateoverlays calls since now not every single structure in the game tries smoothing with nothing. <img width="1349" height="1349" alt="image" src="https://github.com/user-attachments/assets/9b7cecd7-3c47-448b-9dd8-9b904640bf82" /> <img width="1349" height="1349" alt="image" src="https://github.com/user-attachments/assets/647d75a2-1bff-45ca-ab92-0aea10631afd" /> --------- Co-authored-by: Matt Atlas <liermattia@gmail.com>
252 lines
7.4 KiB
Plaintext
252 lines
7.4 KiB
Plaintext
/obj/structure/weapons_rack
|
|
name = "weapon rack"
|
|
desc = "A rack designed to store weapons."
|
|
icon = 'icons/obj/machinery/weapons_rack.dmi'
|
|
icon_state = "rack_base"
|
|
anchored = TRUE
|
|
density = TRUE
|
|
|
|
///The maximum number of weapons that can be stored in the rack
|
|
VAR_PRIVATE/max_weapons_loaded = 4
|
|
|
|
///Boolean, if the rack is locked (no weapon can be added or removed)
|
|
VAR_PRIVATE/locked = FALSE
|
|
|
|
///Boolean, if the rack is forced open (eg. it was cut open, melted open or whatever)
|
|
VAR_PRIVATE/forced_open = FALSE
|
|
|
|
VAR_PRIVATE/obj/effect/visual_holder
|
|
|
|
/obj/structure/weapons_rack/feedback_hints(mob/user, distance, is_adjacent)
|
|
. += ..()
|
|
|
|
if(locate(/obj/item/gun) in src)
|
|
. += "<br/>It contains:<br/>"
|
|
for(var/obj/item/gun/G in src.contents)
|
|
. += "\A [G.name]"
|
|
|
|
if(locked)
|
|
. += SPAN_WARNING("It is locked.")
|
|
|
|
/obj/structure/weapons_rack/Initialize(mapload)
|
|
..()
|
|
visual_holder = new()
|
|
visual_holder.vis_flags |= VIS_INHERIT_ID
|
|
visual_holder.appearance_flags |= KEEP_TOGETHER|RESET_TRANSFORM
|
|
|
|
//This is used to hide any stray pixels that the rifles could have, eg. for overboarding the rack sprite
|
|
var/mask_for_rifles_filter = filter(type="alpha", icon = icon(src.icon, "rack_mask"))
|
|
visual_holder.filters += mask_for_rifles_filter
|
|
|
|
src.vis_contents += visual_holder
|
|
|
|
return INITIALIZE_HINT_LATELOAD
|
|
|
|
/obj/structure/weapons_rack/LateInitialize()
|
|
. = ..()
|
|
|
|
for(var/obj/item/gun in get_turf(src))
|
|
gun.forceMove(src)
|
|
|
|
//This protects us from mapper mistakes
|
|
//don't worry, they will find a way to get this to bug out, just not this particular one
|
|
if(length(src.contents) > max_weapons_loaded)
|
|
stack_trace("Weapon rack at [src.x],[src.y],[src.z] is full and still find weapons to load on init in the turf!")
|
|
qdel(gun)
|
|
|
|
if(length(req_one_access))
|
|
locked = TRUE
|
|
|
|
update_icon()
|
|
|
|
/obj/structure/weapons_rack/Destroy()
|
|
QDEL_NULL(visual_holder)
|
|
|
|
. = ..()
|
|
|
|
/obj/structure/weapons_rack/attackby(obj/item/attacking_item, mob/user, params)
|
|
. = ..()
|
|
|
|
//Hit with a gun, to add it to the rack
|
|
if(istype(attacking_item, /obj/item/gun))
|
|
//No adding or removing weapons from the rack while locked
|
|
if(locked)
|
|
to_chat(user, SPAN_WARNING("The rack is locked."))
|
|
return
|
|
|
|
if(length(src.contents) >= max_weapons_loaded)
|
|
to_chat(user, SPAN_WARNING("The rack is full."))
|
|
return
|
|
|
|
if(!user.unEquip(attacking_item))
|
|
return
|
|
|
|
attacking_item.forceMove(src)
|
|
update_icon()
|
|
|
|
//Hit with ID, to lock/unlock the rack
|
|
else if(istype(attacking_item, /obj/item/card/id))
|
|
var/obj/item/card/id/identification_card = attacking_item
|
|
if(!forced_open && has_access(req_one_access = src.req_one_access, accesses = identification_card.access))
|
|
balloon_alert_to_viewers("[locked ? "unlocked" : "locked"]")
|
|
playsound(src, 'sound/items/metal_shutter.ogg', 50, TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE)
|
|
toggle_lock(user)
|
|
|
|
else
|
|
balloon_alert(user, "it won't budge!")
|
|
to_chat(user, SPAN_WARNING("You lack the required access to operate this rack's lock, or the lock mechanism is broken."))
|
|
|
|
else if(locked && attacking_item.iswelder())
|
|
var/obj/item/weldingtool/WT = attacking_item
|
|
|
|
balloon_alert_to_viewers("cutting through the lock...")
|
|
|
|
if(WT.use_tool(src, user, 20 SECONDS, extra_checks = CALLBACK(src, PROC_REF(can_be_opened))))
|
|
//Last check because use_tool() is shitcoded
|
|
if(forced_open || !can_be_opened())
|
|
return
|
|
toggle_lock(user)
|
|
balloon_alert_to_viewers("lock cut")
|
|
forced_open = TRUE
|
|
|
|
else
|
|
to_chat(user, SPAN_NOTICE("\The [src] was unlocked while you were working on it!"))
|
|
|
|
|
|
/obj/structure/weapons_rack/attack_hand(mob/living/user)
|
|
. = ..()
|
|
if(length(src.contents))
|
|
//No adding or removing weapons from the rack while locked
|
|
if(locked)
|
|
to_chat(user, SPAN_WARNING("The rack is locked."))
|
|
return
|
|
|
|
//Build a list of options for the radial menu, based on our content
|
|
var/list/radial_options = list()
|
|
for(var/obj/item/gun/gun_in_rack in src.contents)
|
|
radial_options[gun_in_rack] = image(gun_in_rack.icon, gun_in_rack.icon_state)
|
|
|
|
//Show the user the radial menu
|
|
var/obj/item/gun/rifle_to_take = show_radial_menu(user, src, radial_options, require_near = TRUE, tooltips = TRUE)
|
|
|
|
//No choice was made, return
|
|
if(isnull(rifle_to_take))
|
|
return
|
|
|
|
//Assuming the rifle is still in the rack when the user chooses it, deliver the rifle
|
|
if(rifle_to_take in src.contents)
|
|
rifle_to_take.forceMove(get_turf(user))
|
|
user.put_in_hands(rifle_to_take)
|
|
update_icon()
|
|
|
|
else
|
|
to_chat(user, SPAN_WARNING("\The [rifle_to_take] is not in the rack anymore!"))
|
|
|
|
|
|
#define BASE_OFFSET_RIFLE_SLOT -1
|
|
#define INTER_OFFSET_RIFLE_SLOT 7
|
|
/obj/structure/weapons_rack/update_icon()
|
|
. = ..()
|
|
visual_holder.overlays.Cut()
|
|
ClearOverlays()
|
|
|
|
for(var/i in 1 to length(src.contents))
|
|
var/obj/item/gun/G = src.contents[i]
|
|
var/matrix/transform_matrix = matrix(G.transform)
|
|
|
|
transform_matrix.Turn(-90)
|
|
transform_matrix.Scale(0.8, 0.8)
|
|
transform_matrix.Translate((((world.icon_size/2)+BASE_OFFSET_RIFLE_SLOT) - world.icon_size) + (i*INTER_OFFSET_RIFLE_SLOT), 0)
|
|
|
|
//Why not the rifle itself you might ask? Because there's the safety icon on it
|
|
var/mutable_appearance/weapon_appearance = mutable_appearance(G.icon, G.icon_state, plane = src.plane, layer = G.layer)
|
|
weapon_appearance.transform = transform_matrix
|
|
|
|
visual_holder.overlays += weapon_appearance
|
|
|
|
if(locked)
|
|
AddOverlays(image(src.icon, "locked_overlay", layer = ABOVE_OBJ_LAYER))
|
|
|
|
#undef BASE_OFFSET_RIFLE_SLOT
|
|
#undef INTER_OFFSET_RIFLE_SLOT
|
|
|
|
/obj/structure/weapons_rack/emag_act(remaining_charges, mob/user, emag_source)
|
|
. = ..()
|
|
|
|
to_chat(user, SPAN_NOTICE("You start to fiddle with the electronic lock of \the [src]."))
|
|
if(do_after(user, 10 SECONDS, src, extra_checks = CALLBACK(src, PROC_REF(can_be_opened))))
|
|
to_chat(user, SPAN_NOTICE("You manage to unlock \the [src]."))
|
|
toggle_lock(user)
|
|
|
|
/obj/structure/weapons_rack/ex_act(severity)
|
|
if(severity > 1 && can_be_opened())
|
|
toggle_lock()
|
|
forced_open = TRUE
|
|
|
|
if(severity > 2)
|
|
for(var/obj/item/gun/G in src.contents)
|
|
if(prob(10))
|
|
//Uh oh, the munitions cooked in the gun!
|
|
fragem(get_turf(G), 4, 7, 3, 3, 10, 1, TRUE)
|
|
qdel(G)
|
|
else
|
|
throw_at_random(TRUE, 4, 7)
|
|
|
|
. = ..()
|
|
|
|
/obj/structure/weapons_rack/fire_act(exposed_temperature, exposed_volume)
|
|
. = ..()
|
|
|
|
if(exposed_temperature > 1811) //Melting temperature of steel, in kelvin
|
|
//You melted the door
|
|
if(can_be_opened())
|
|
if(prob(20))
|
|
toggle_lock()
|
|
forced_open = TRUE
|
|
|
|
else
|
|
var/picked = pick_weight(list("burn_weapon" = 2, "explode_ammos" = 10, "nothing" = 80))
|
|
|
|
//Burn down one of the guns
|
|
if(picked == "burn_weapon" && length(src.contents))
|
|
var/obj/item/gun/G = pick(src.contents)
|
|
G.forceMove(get_turf(src))
|
|
qdel(G)
|
|
|
|
//Just some explosion effect
|
|
else if(picked == "explode_ammos")
|
|
INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(fragem), get_turf(src), 2, 3, 3, 3, 10, 1, TRUE)
|
|
|
|
|
|
/**
|
|
* Locks/unlocks the rack
|
|
*
|
|
* * user - A `/mob` that is unlocking the rack, optional
|
|
*/
|
|
/obj/structure/weapons_rack/proc/toggle_lock(mob/user, force_lock_state)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
|
|
if(user)
|
|
add_fibers(user)
|
|
add_fingerprint(user)
|
|
|
|
locked = !locked
|
|
update_icon()
|
|
|
|
/**
|
|
* Checks if the locker can be opened (NOT permissions, as in "did someone else already open it" kind of thing)
|
|
*
|
|
*/
|
|
/obj/structure/weapons_rack/proc/can_be_opened()
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
SHOULD_BE_PURE(TRUE)
|
|
|
|
//Can't open it, it's forced open
|
|
if(forced_open)
|
|
return FALSE
|
|
|
|
if(locked)
|
|
return TRUE
|
|
else
|
|
return FALSE
|