mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-01-16 20:32:14 +00:00
Refactored the attack proc signature. Added signals and components for the attack proc. Added signals and components for the attackby proc. Adjusted some leftover attackby procs signatures. Added grep test to ensure people don't keep adding attack/attackby procs with the wrong signature.
872 lines
27 KiB
Plaintext
872 lines
27 KiB
Plaintext
//
|
|
// Rapid Fabrication Devices
|
|
//
|
|
|
|
// Defines
|
|
#define MATERIALIZATION_FAIL_MESSAGE "You can't materialize two constructions of the same type."
|
|
|
|
/**
|
|
* # Rapid Fabrication Device
|
|
*
|
|
* A device used for rapid fabrication of things, built from a compressed matter cartridge
|
|
*/
|
|
ABSTRACT_TYPE(/obj/item/rfd)
|
|
name = "\improper Rapid Fabrication Device"
|
|
desc = "A device used for rapid fabrication. The matter decompression matrix is untuned, rendering it useless."
|
|
icon = 'icons/obj/rfd.dmi'
|
|
icon_state = "rfd"
|
|
item_state = "rfd"
|
|
item_icons = list(
|
|
slot_l_hand_str = 'icons/mob/items/lefthand_tools.dmi',
|
|
slot_r_hand_str = 'icons/mob/items/righthand_tools.dmi'
|
|
)
|
|
opacity = FALSE
|
|
density = FALSE
|
|
anchored = FALSE
|
|
obj_flags = OBJ_FLAG_CONDUCTABLE
|
|
force = 11
|
|
throwforce = 10
|
|
throw_speed = 1
|
|
throw_range = 5
|
|
w_class = WEIGHT_CLASS_NORMAL
|
|
origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 2)
|
|
matter = list(DEFAULT_WALL_MATERIAL = 50000)
|
|
drop_sound = 'sound/items/drop/gun.ogg'
|
|
pickup_sound = 'sound/items/pickup/gun.ogg'
|
|
|
|
/**
|
|
* A K-V list of modes that the RFD will show as selectable in the radial menu
|
|
*
|
|
* Key is a string, the name of the mode
|
|
* Value is an image, to be displayed inside the radial menu button
|
|
*/
|
|
var/list/radial_modes = list()
|
|
|
|
var/stored_matter = 30 // Starts of full.
|
|
var/working = FALSE
|
|
|
|
///The mode the RFD is currently operating in
|
|
var/mode = RFD_FLOORS_AND_WALL
|
|
|
|
var/number_of_modes = 1
|
|
var/list/modes
|
|
var/crafting = FALSE
|
|
|
|
var/build_cost = 0
|
|
var/build_type
|
|
var/build_atom
|
|
var/build_delay
|
|
var/last_fail = 0
|
|
|
|
/obj/item/rfd/Initialize()
|
|
. = ..()
|
|
update_icon()
|
|
|
|
/obj/item/rfd/attack(mob/living/target_mob, mob/living/user, target_zone)
|
|
return FALSE
|
|
|
|
/obj/item/rfd/proc/can_use(var/mob/user,var/turf/T)
|
|
return (user.Adjacent(T) && user.get_active_hand() == src && !user.stat && !user.restrained())
|
|
|
|
/obj/item/rfd/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
|
|
. = ..()
|
|
if(loc == user)
|
|
. += "It currently holds [stored_matter]/30 matter units."
|
|
|
|
/obj/item/rfd/attack_self(mob/user)
|
|
//Change the mode
|
|
if(++mode > number_of_modes)
|
|
mode = RFD_FLOORS_AND_WALL
|
|
to_chat(user, SPAN_NOTICE("The mode selection dial is now at [modes[mode]]."))
|
|
playsound(get_turf(src), 'sound/weapons/laser_safetyon.ogg', 50, FALSE)
|
|
|
|
/obj/item/rfd/attackby(obj/item/attacking_item, mob/user)
|
|
if(istype(attacking_item, /obj/item/rfd_ammo))
|
|
if((stored_matter + 10) > 30)
|
|
to_chat(user, SPAN_NOTICE("The RFD can't hold any more matter units."))
|
|
return
|
|
user.drop_from_inventory(attacking_item, src)
|
|
qdel(attacking_item)
|
|
stored_matter += 10
|
|
playsound(src.loc, 'sound/weapons/laser_reload1.ogg', 50, FALSE)
|
|
to_chat(user, SPAN_NOTICE("The RFD now holds [stored_matter]/30 matter units."))
|
|
update_icon()
|
|
return TRUE
|
|
|
|
if(attacking_item.isscrewdriver()) // Turning it into a crossbow
|
|
crafting = !crafting
|
|
if(!crafting)
|
|
to_chat(user, SPAN_NOTICE("You reassemble the RFD."))
|
|
else
|
|
to_chat(user, SPAN_NOTICE("The RFD can now be modified."))
|
|
src.add_fingerprint(user)
|
|
return TRUE
|
|
|
|
if(crafting)
|
|
var/obj/item/crossbow // the thing we're gonna add, check what it is below
|
|
if(istype(attacking_item, /obj/item/crossbowframe))
|
|
var/obj/item/crossbowframe/F = attacking_item
|
|
if(F.buildstate != 5)
|
|
to_chat(user, SPAN_WARNING("You need to fully assemble the crossbow frame first!"))
|
|
return TRUE
|
|
crossbow = F
|
|
else if(istype(attacking_item, /obj/item/gun/launcher/crossbow) && !istype(attacking_item, /obj/item/gun/launcher/crossbow/RFD))
|
|
var/obj/item/gun/launcher/crossbow/C = attacking_item
|
|
if(C.bolt)
|
|
to_chat(user, SPAN_WARNING("You need to remove \the [C.bolt] from \the [C] before you can attach it to \the [src]."))
|
|
return TRUE
|
|
if(C.cell)
|
|
to_chat(user, SPAN_WARNING("You need to remove \the [C.cell] from \the [C] before you can attach it to \the [src]."))
|
|
return TRUE
|
|
crossbow = C
|
|
|
|
if(crossbow)
|
|
qdel(crossbow)
|
|
var/obj/item/gun/launcher/crossbow/RFD/CB = new(get_turf(user)) // Can be found in "crossbow.dm".
|
|
forceMove(CB)
|
|
CB.stored_matter = src.stored_matter
|
|
user.drop_from_inventory(src)
|
|
qdel(src)
|
|
user.put_in_hands(CB)
|
|
return TRUE
|
|
return ..()
|
|
|
|
|
|
/obj/item/rfd/proc/useResource(var/amount, var/mob/user)
|
|
if(stored_matter < amount)
|
|
return FALSE
|
|
stored_matter -= amount
|
|
update_icon()
|
|
return TRUE
|
|
|
|
/obj/item/rfd/update_icon() // For the fancy "ammo" counter.
|
|
overlays.Cut()
|
|
|
|
var/ratio = 0
|
|
ratio = stored_matter / 30 //30 is the hardcoded max capacity of the RFD
|
|
ratio = max(round(ratio, 0.10) * 100, 10)
|
|
|
|
overlays += "[icon_state]-[ratio]"
|
|
|
|
/**
|
|
* # RFD Compressed Matter Cartridge
|
|
*
|
|
* Highly compressed matter for the RFD, basically RFD ammos
|
|
*/
|
|
/obj/item/rfd_ammo
|
|
name = "compressed matter cartridge"
|
|
desc = "Highly compressed matter for the RFD."
|
|
icon = 'icons/obj/ammo.dmi'
|
|
icon_state = "rfd"
|
|
item_state = "rfdammo"
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
origin_tech = list(TECH_MATERIAL = 2)
|
|
matter = list(DEFAULT_WALL_MATERIAL = 2000, MATERIAL_GLASS = 2000)
|
|
recyclable = TRUE
|
|
|
|
|
|
/*##############
|
|
SUBTYPES
|
|
##############*/
|
|
|
|
|
|
//
|
|
// RFD - Construction Class
|
|
//
|
|
|
|
/obj/item/rfd/construction
|
|
name = "\improper Rapid Fabrication Device C-Class"
|
|
desc = "A RFD, modified to construct walls and floors."
|
|
var/can_rwall = FALSE
|
|
var/disabled = FALSE
|
|
|
|
///A list of types that will be sent to the alter_atom proc if we click on them, rather than their turf.
|
|
var/list/valid_atoms = list(
|
|
/obj/machinery/door/airlock,
|
|
/obj/structure/window_frame,
|
|
/obj/structure/window/full
|
|
)
|
|
|
|
/obj/item/rfd/construction/Initialize()
|
|
. = ..()
|
|
radial_modes = list(
|
|
"Floor and Wall" = image(icon = 'icons/mob/screen/radial.dmi', icon_state = "wallfloor"),
|
|
"Window and Window Frame" = image(icon = 'icons/mob/screen/radial.dmi', icon_state = "windowframe"),
|
|
"Airlock" = image(icon = 'icons/mob/screen/radial.dmi', icon_state = "airlock"),
|
|
"Deconstruct" = image(icon = 'icons/mob/screen/radial.dmi', icon_state = "delete")
|
|
)
|
|
|
|
/obj/item/rfd/construction/attack_self(mob/user)
|
|
var/current_mode = RADIAL_INPUT(user, radial_modes)
|
|
switch(current_mode)
|
|
if("Floor and Wall")
|
|
mode = RFD_FLOORS_AND_WALL
|
|
if("Window and Window Frame")
|
|
mode = RFD_WINDOW_AND_FRAME
|
|
if("Deconstruct")
|
|
mode = RFD_DECONSTRUCT
|
|
if("Airlock")
|
|
mode = RFD_AIRLOCK
|
|
else
|
|
mode = RFD_DECONSTRUCT
|
|
if(current_mode)
|
|
to_chat(user, SPAN_NOTICE("You switch the selection dial to <i>\"[current_mode]\"</i>."))
|
|
if(mode == 3)
|
|
playsound(get_turf(src), 'sound/weapons/laser_safetyoff.ogg', 50, FALSE)
|
|
else
|
|
playsound(get_turf(src), 'sound/weapons/laser_safetyon.ogg', 50, FALSE)
|
|
|
|
/obj/item/rfd/construction/afterattack(atom/A, mob/user, proximity)
|
|
if(!proximity)
|
|
return
|
|
if((!isturf(A) && !isturf(A.loc)) || istype(A, /obj/structure/table))
|
|
return
|
|
if(disabled && !isrobot(user))
|
|
return FALSE
|
|
var/area/Area = get_area(A)
|
|
if(Area.centcomm_area || istype(Area, /area/shuttle) || istype(Area, /turf/space/transit))
|
|
to_chat(user, SPAN_NOTICE("\The [src] can't be used here."))
|
|
return FALSE
|
|
if(is_type_in_list(A, valid_atoms))
|
|
return alter_atom(A, user, (mode == RFD_DECONSTRUCT))
|
|
return alter_atom(get_turf(A), user, (mode == RFD_DECONSTRUCT))
|
|
|
|
/obj/item/rfd/construction/proc/alter_atom(var/atom/A, var/mob/user, var/deconstruct)
|
|
if(working)
|
|
return FALSE
|
|
|
|
var/turf/T = isturf(A) ? A : null // the lower istypes will return false if T is null, which means we don't have to check whether it's an atom or a turf
|
|
if(mode == RFD_FLOORS_AND_WALL)
|
|
if(istype(T, /turf/space) || istype(T, T.baseturf))
|
|
build_cost = 1
|
|
build_type = "floor"
|
|
build_atom = /turf/simulated/floor/airless
|
|
else if(istype(T, /turf/simulated/open))
|
|
build_cost = 1
|
|
build_type = "floor"
|
|
build_atom = /turf/simulated/floor/airless
|
|
else if(istype(T, /turf/simulated/floor))
|
|
build_delay = 20
|
|
build_cost = 3
|
|
build_type = "wall"
|
|
build_atom = /turf/simulated/wall
|
|
else if(mode == RFD_WINDOW_AND_FRAME)
|
|
if(istype(T, /turf/simulated/floor))
|
|
if(locate(/obj/structure/window_frame) in get_turf(A))
|
|
to_chat(user, SPAN_NOTICE(MATERIALIZATION_FAIL_MESSAGE))
|
|
return
|
|
build_cost = 3
|
|
build_delay = 20
|
|
build_type = "window frame"
|
|
build_atom = /obj/structure/window_frame
|
|
else if(istype(A, /obj/structure/window_frame))
|
|
if(locate(/obj/structure/window/full/reinforced) in get_turf(A))
|
|
to_chat(user, SPAN_NOTICE(MATERIALIZATION_FAIL_MESSAGE))
|
|
return
|
|
build_cost = 3
|
|
build_delay = 20
|
|
build_type = "window"
|
|
build_atom = /obj/structure/window/full/reinforced
|
|
else if(mode == RFD_AIRLOCK)
|
|
if(istype(T, /turf/simulated/floor))
|
|
build_cost = 3
|
|
build_delay = 20
|
|
build_type = "airlock"
|
|
build_atom = /obj/machinery/door/airlock
|
|
else if(mode == RFD_DECONSTRUCT)
|
|
// Airlocks
|
|
if(istype(A, /obj/machinery/door/airlock))
|
|
build_cost = 10
|
|
build_delay = 50
|
|
build_type = "airlock"
|
|
// Walls
|
|
else if(istype(T, /turf/simulated/wall))
|
|
var/turf/simulated/wall/W = T
|
|
build_cost = 5
|
|
build_delay = 50
|
|
build_type = (!can_rwall && W.reinf_material) ? null : "wall"
|
|
build_atom = W.under_turf
|
|
// Floors
|
|
else if(istype(T, /turf/simulated/floor))
|
|
build_cost = 10
|
|
build_delay = 50
|
|
build_type = "floor"
|
|
build_atom = T.baseturf
|
|
// Window Frames
|
|
if(istype(A, /obj/structure/window_frame))
|
|
if(locate(/obj/structure/window/full) in get_turf(A))
|
|
to_chat(user, SPAN_NOTICE("You can't deconstruct \the [A] if it has glass installed."))
|
|
return
|
|
build_cost = 3
|
|
build_delay = 20
|
|
build_type = "window frame"
|
|
// Full Windows
|
|
else if(istype(A, /obj/structure/window/full))
|
|
build_cost = 5
|
|
build_delay = 50
|
|
build_type = "window"
|
|
|
|
if(!build_type)
|
|
working = FALSE
|
|
return FALSE
|
|
|
|
if(mode == RFD_DECONSTRUCT && istype(A, /obj/machinery/door) && !A.density)
|
|
to_chat(user, SPAN_WARNING("\The [build_type] must be closed before you can deconstruct it."))
|
|
return FALSE
|
|
|
|
if(stored_matter < build_cost)
|
|
to_chat(user, SPAN_NOTICE("The \"Matter Units Low\" light on the device blinks yellow."))
|
|
flick("[icon_state]-empty", src)
|
|
return FALSE
|
|
|
|
playsound(get_turf(src), 'sound/items/rfd_start.ogg', 50, FALSE)
|
|
|
|
working = TRUE
|
|
user.visible_message(SPAN_NOTICE("[user] holds \the [src] towards \the [A]."), SPAN_NOTICE("You start [deconstruct ? "deconstructing" : "constructing"] \a [build_type]..."))
|
|
var/obj/effect/constructing_effect/rfd_effect = new(get_turf(A), src.build_delay, src.mode)
|
|
|
|
if((build_delay && !do_after(user, build_delay)) || (!useResource(build_cost, user)))
|
|
working = FALSE
|
|
rfd_effect.end_animation()
|
|
return FALSE
|
|
|
|
working = FALSE
|
|
if(build_delay && !can_use(user, A))
|
|
return FALSE
|
|
|
|
if(ispath(build_atom, /turf))
|
|
var/original_type = T.type
|
|
T.ChangeTurf(build_atom)
|
|
if(istype(T, /turf/simulated/wall))
|
|
var/turf/simulated/wall/W = T
|
|
W.under_turf = original_type
|
|
else if(ispath(build_atom, /obj))
|
|
new build_atom(get_turf(A))
|
|
else
|
|
qdel(A)
|
|
|
|
rfd_effect.end_animation()
|
|
playsound(get_turf(src), 'sound/items/rfd_end.ogg', 50, FALSE)
|
|
build_cost = null
|
|
build_delay = null
|
|
build_type = null
|
|
build_atom = null // So that it resets and any unintended functionality is avoided.
|
|
return TRUE
|
|
|
|
/obj/item/rfd/construction/borg
|
|
can_rwall = TRUE
|
|
|
|
/obj/item/rfd/construction/borg/useResource(var/amount, var/mob/user)
|
|
if(isrobot(user))
|
|
var/mob/living/silicon/robot/R = user
|
|
if(R.cell)
|
|
var/cost = (amount * 30)
|
|
if(R.cell.charge >= cost)
|
|
R.cell.use(cost)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/item/rfd/construction/borg/infinite/useResource()
|
|
return TRUE
|
|
|
|
/obj/item/rfd/construction/borg/attackby()
|
|
return
|
|
|
|
/obj/item/rfd/construction/borg/can_use(var/mob/user,var/turf/T)
|
|
return (user.Adjacent(T) && !user.stat)
|
|
|
|
/obj/item/rfd/construction/mounted/useResource(var/amount, var/mob/user)
|
|
var/cost = (amount * 130) // So that a rig with default powercell can build ~2.5x the stuff a fully-loaded RFD-C can.
|
|
if(istype(loc, /obj/item/rig_module))
|
|
var/obj/item/rig_module/module = loc
|
|
if(module.holder && module.holder.cell)
|
|
if(module.holder.cell.charge >= cost)
|
|
module.holder.cell.use(cost)
|
|
return TRUE
|
|
else if(istype(user, /mob/living/heavy_vehicle))
|
|
var/obj/item/cell/c = user.get_cell()
|
|
if(c && c.charge >= cost)
|
|
c.use(cost)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/item/rfd/construction/mounted/attackby()
|
|
return
|
|
|
|
/obj/item/rfd/construction/mounted/can_use(var/mob/user,var/turf/T)
|
|
return (user.Adjacent(T) && !user.stat && !user.restrained())
|
|
|
|
|
|
//
|
|
// RFD - Service Class
|
|
//
|
|
|
|
/obj/item/rfd/service
|
|
name = "\improper Rapid Fabrication Device S-Class"
|
|
desc = "A RFD, modified to deploy service items."
|
|
icon_state = "rfd-s"
|
|
item_state = "rfd-s"
|
|
|
|
/obj/item/rfd/service/Initialize()
|
|
. = ..()
|
|
radial_modes = list(
|
|
"Cigarette" = image(icon = 'icons/obj/clothing/masks.dmi', icon_state = "cigoff"),
|
|
"Drinking Glass" = image(icon = 'icons/obj/drinks.dmi', icon_state = "glass_empty"),
|
|
"Paper" = image(icon = 'icons/obj/bureaucracy.dmi', icon_state = "paper"),
|
|
"Pen" = image(icon = 'icons/obj/bureaucracy.dmi', icon_state = "pen"),
|
|
"Dice Pack" = image(icon = 'icons/obj/dice.dmi', icon_state = "dicebag"),
|
|
)
|
|
|
|
/obj/item/rfd/service/attack_self(mob/user)
|
|
var/current_mode = RADIAL_INPUT(user, radial_modes)
|
|
switch(current_mode)
|
|
if("Cigarette")
|
|
mode = 1
|
|
if("Drinking Glass")
|
|
mode = 2
|
|
if("Paper")
|
|
mode = 3
|
|
if("Pen")
|
|
mode = 4
|
|
if("Dice Pack")
|
|
mode = 5
|
|
if(current_mode)
|
|
to_chat(user, SPAN_NOTICE("You switch the selection dial to <i>\"[current_mode]\"</i>."))
|
|
playsound(src.loc, 'sound/effects/pop.ogg', 50, 0)
|
|
|
|
/obj/item/rfd/service/resolve_attackby(atom/A, mob/user as mob, var/click_parameters)
|
|
if(istype(user,/mob/living/silicon/robot))
|
|
var/mob/living/silicon/robot/R = user
|
|
if(R.stat || !R.cell || R.cell.charge <= 0)
|
|
return
|
|
else
|
|
if(stored_matter <= 0)
|
|
if(last_fail <= world.time - 20) // Spam limiter.
|
|
last_fail = world.time
|
|
to_chat(user, SPAN_NOTICE("The \"Matter Units Low\" light on the device blinks yellow."))
|
|
playsound(get_turf(src), 'sound/items/rfd_empty.ogg', 50, FALSE)
|
|
flick("[icon_state]-empty", src)
|
|
return
|
|
|
|
if(!istype(A, /obj/structure/table) && !istype(A, /turf/simulated/floor))
|
|
return
|
|
|
|
playsound(src.loc, 'sound/items/rfd_dispense.ogg', 20, FALSE)
|
|
sleep(2)
|
|
var/used_energy = 0
|
|
var/obj/product
|
|
|
|
switch(mode)
|
|
if(1)
|
|
product = new /obj/item/clothing/mask/smokable/cigarette()
|
|
used_energy = 10
|
|
if(2)
|
|
product = new /obj/item/reagent_containers/food/drinks/drinkingglass()
|
|
used_energy = 50
|
|
if(3)
|
|
product = new /obj/item/paper()
|
|
used_energy = 10
|
|
if(4)
|
|
product = new /obj/item/pen()
|
|
used_energy = 50
|
|
if(5)
|
|
product = new /obj/item/storage/pill_bottle/dice()
|
|
used_energy = 200
|
|
|
|
to_chat(user, "Dispensing [product ? product : "product"]...")
|
|
product.forceMove(get_turf(A))
|
|
playsound(src.loc, 'sound/machines/click.ogg' , 10, 1)
|
|
if(istype(A, /obj/structure/table))
|
|
var/obj/structure/table/T = A
|
|
T.auto_align(product, click_parameters)
|
|
update_icon()
|
|
|
|
if(isrobot(user))
|
|
var/mob/living/silicon/robot/R = user
|
|
if(R.cell)
|
|
R.cell.use(used_energy)
|
|
else
|
|
stored_matter--
|
|
to_chat(user, "The RSF now holds [stored_matter]/30 fabrication-units.")
|
|
|
|
|
|
|
|
/*#######################
|
|
RFD - Mining Class
|
|
#######################*/
|
|
|
|
#define RFD_MINING_MODE_MINE_TRACK "Mine Track"
|
|
#define RFD_MINING_MODE_MINE_CART "Mine Cart"
|
|
#define RFD_MINING_MODE_MINE_CART_ENGINE "Mine Cart Engine"
|
|
/obj/item/rfd/mining
|
|
name = "\improper Rapid Fabrication Device M-Class"
|
|
desc = "A RFD, modified to deploy mine tracks."
|
|
icon_state = "rfd-m"
|
|
item_state = "rfd-m"
|
|
|
|
/obj/item/rfd/mining/Initialize()
|
|
. = ..()
|
|
|
|
radial_modes = list(
|
|
RFD_MINING_MODE_MINE_TRACK = image(/obj/structure/track),
|
|
RFD_MINING_MODE_MINE_CART_ENGINE = image(/obj/vehicle/train/cargo/engine/mining),
|
|
RFD_MINING_MODE_MINE_CART = image(/obj/vehicle/train/cargo/trolley/mining)
|
|
)
|
|
|
|
/obj/item/rfd/mining/attack_self(mob/user)
|
|
var/current_mode = RADIAL_INPUT(user, radial_modes)
|
|
if(current_mode in radial_modes)
|
|
mode = current_mode
|
|
|
|
if(current_mode)
|
|
to_chat(user, SPAN_NOTICE("You switch the selection dial to <i>\"[current_mode]\"</i>."))
|
|
|
|
/obj/item/rfd/mining/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
|
if(!proximity_flag)
|
|
return
|
|
|
|
//Handle consumption of resources, either from the RFD matter cartridge or from a robot cell
|
|
if(isrobot(user))
|
|
var/mob/living/silicon/robot/R = user
|
|
if(R.stat || !R.cell || R.cell.charge <= 200)
|
|
if(last_fail <= world.time - 20) //Spam limiter.
|
|
last_fail = world.time
|
|
to_chat(user, SPAN_WARNING("You are unable to produce enough charge to use \the [src]!"))
|
|
playsound(get_turf(src), 'sound/items/rfd_empty.ogg', 50, FALSE)
|
|
flick("[icon_state]-empty", src)
|
|
return
|
|
else
|
|
if(stored_matter <= 0)
|
|
if(last_fail <= world.time - 20) //Spam limiter.
|
|
last_fail = world.time
|
|
to_chat(user, SPAN_NOTICE("The \"Matter Units Low\" light on the device blinks yellow."))
|
|
playsound(get_turf(src), 'sound/items/rfd_empty.ogg', 50, FALSE)
|
|
flick("[icon_state]-empty", src)
|
|
return
|
|
|
|
//Can only be used on floors
|
|
if(!istype(target, /turf/simulated/floor) && !istype(target, /turf/unsimulated/floor))
|
|
return
|
|
|
|
var/item_to_make = null
|
|
switch(mode)
|
|
if(RFD_MINING_MODE_MINE_TRACK)
|
|
if(locate(/obj/structure/track) in target)
|
|
to_chat(user, SPAN_WARNING("There is already a track on \the [target]!"))
|
|
return
|
|
item_to_make = /obj/structure/track
|
|
|
|
if(RFD_MINING_MODE_MINE_CART_ENGINE)
|
|
//Check that there's a track
|
|
if(!(locate(/obj/structure/track) in target))
|
|
to_chat(user, SPAN_WARNING("There is no track on \the [target]!"))
|
|
return
|
|
|
|
//Check that there's no trolley or engine already
|
|
if(locate(/obj/vehicle/train/cargo) in target)
|
|
to_chat(user, SPAN_WARNING("There is already an engine or trolley on \the [target]!"))
|
|
return
|
|
item_to_make = /obj/vehicle/train/cargo/engine/mining
|
|
|
|
if(RFD_MINING_MODE_MINE_CART)
|
|
//Check that there's a track
|
|
if(!(locate(/obj/structure/track) in target))
|
|
to_chat(user, SPAN_WARNING("There is no track on \the [target]!"))
|
|
return
|
|
|
|
//Check that there's no trolley or engine already
|
|
if(locate(/obj/vehicle/train/cargo) in target)
|
|
to_chat(user, SPAN_WARNING("There is already an engine or trolley on \the [target]!"))
|
|
return
|
|
|
|
item_to_make = /obj/vehicle/train/cargo/trolley/mining
|
|
|
|
else
|
|
to_chat(user, SPAN_WARNING("There's no valid mode selected for this RFD!"))
|
|
return
|
|
|
|
playsound(src.loc, 'sound/machines/click.ogg', 10, 1)
|
|
|
|
new item_to_make(get_turf(target))
|
|
|
|
to_chat(user, SPAN_NOTICE("You deploy \a [mode] on \the [target]."))
|
|
update_icon()
|
|
|
|
|
|
//In case of success, consume the resources
|
|
if(isrobot(user))
|
|
var/mob/living/silicon/robot/R = user
|
|
if(R.cell)
|
|
R.cell.use(200)
|
|
else
|
|
stored_matter--
|
|
to_chat(user, SPAN_NOTICE("The RFD now holds <b>[stored_matter]/[initial(stored_matter)]</b> fabrication-units.")) //As they start full, initial(stored_matter) also gives the maximum
|
|
|
|
return TRUE
|
|
|
|
/obj/item/rfd/mining/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
|
|
. = ..()
|
|
. += FONT_SMALL(SPAN_WARNING("The printed mining units have to either be placed down in order, or linked manually after deployment."))
|
|
|
|
#undef RFD_MINING_MODE_MINE_TRACK
|
|
#undef RFD_MINING_MODE_MINE_CART
|
|
#undef RFD_MINING_MODE_MINE_CART_ENGINE
|
|
|
|
|
|
// Malf AI RFD Transformer
|
|
|
|
/obj/item/rfd/transformer
|
|
name = "\improper Rapid Fabrication Device T-Class"
|
|
desc = "A device used for rapid fabrication, modified to deploy a transformer. It can only be used once and there can not be more than one made."
|
|
stored_matter = 30
|
|
var/malftransformermade = 0
|
|
|
|
/obj/item/rfd/transformer/attack_self(mob/user)
|
|
return
|
|
|
|
/obj/item/rfd/transformer/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
|
|
. = ..()
|
|
if(loc == user)
|
|
if(malftransformermade)
|
|
. += "There is already a transformer machine made!"
|
|
else
|
|
. += "It is ready to deploy a transformer machine."
|
|
|
|
/obj/item/rfd/transformer/afterattack(atom/A, mob/user as mob, proximity)
|
|
|
|
if(!proximity) return
|
|
|
|
if(istype(user,/mob/living/silicon/robot))
|
|
var/mob/living/silicon/robot/R = user
|
|
if(R.stat || !R.cell || R.cell.charge <= 0)
|
|
return
|
|
|
|
if(!istype(A, /turf/simulated/floor))
|
|
return
|
|
|
|
if(malftransformermade)
|
|
if(last_fail <= world.time - 20) //Spam limiter.
|
|
last_fail = world.time
|
|
to_chat(user, "There is already a transformer machine made!")
|
|
playsound(get_turf(src), 'sound/items/rfd_empty.ogg', 50, FALSE)
|
|
flick("[icon_state]-empty", src)
|
|
return
|
|
|
|
playsound(src.loc, 'sound/machines/click.ogg', 10, 1)
|
|
var/used_energy = 100
|
|
to_chat(user, "Fabricating machine...")
|
|
playsound(get_turf(src), 'sound/items/rfd_start.ogg', 50, FALSE)
|
|
if(do_after(user, 30 SECONDS, src, DO_UNIQUE))
|
|
var/obj/product = new /obj/machinery/transformer
|
|
malftransformermade = 1
|
|
product.forceMove(get_turf(A))
|
|
stored_matter = 0
|
|
update_icon()
|
|
playsound(get_turf(src), 'sound/items/rfd_end.ogg', 50, FALSE)
|
|
if(isrobot(user))
|
|
var/mob/living/silicon/robot/R = user
|
|
if(R.cell)
|
|
R.cell.use(used_energy)
|
|
|
|
return TRUE
|
|
|
|
|
|
//
|
|
// RFD - Piping Class
|
|
//
|
|
|
|
#define STANDARD_PIPE "Standard Pipes"
|
|
#define SUPPLY_PIPE "Supply Pipes"
|
|
#define SCRUBBER_PIPE "Scrubber Pipes"
|
|
#define FUEL_PIPE "Fuel Pipes"
|
|
#define AUX_PIPE "Auxiliary Pipes"
|
|
#define DEVICES "Devices"
|
|
|
|
/obj/item/rfd/piping
|
|
name = "\improper Rapid Fabrication Device P-Class"
|
|
desc = "A heavily modified RFD, modified to construct pipes and piping accessories."
|
|
icon_state = "rfd-p"
|
|
item_state = "rfd-p"
|
|
modes = list(STANDARD_PIPE, SUPPLY_PIPE, SCRUBBER_PIPE, DEVICES)
|
|
var/selected_mode = STANDARD_PIPE
|
|
var/pipe_examine = "Pipe" // used in the examine proc to see what you're putting down at a glance
|
|
var/selected_pipe = 0 // default is standard pipe, used for the new pipe creation
|
|
build_cost = 1 // this RFD only uses 1 unit of power per pipe, but can be modified if need be in future
|
|
build_delay = 10
|
|
|
|
// The numbers below refer to the numberized designator for each pipe, which is used in obj/item/pipe's new
|
|
// Take a look at code\game\machinery\pipe\construction.dm line 69 for more information. - Geeves
|
|
var/list/standard_pipes = list(
|
|
"Pipe" = PIPE_SIMPLE_STRAIGHT,
|
|
"Bent Pipe" = PIPE_SIMPLE_BENT,
|
|
"Manifold" = PIPE_MANIFOLD,
|
|
"Manual Valve" = PIPE_MVALVE,
|
|
"4-Way Manifold" = PIPE_MANIFOLD4W,
|
|
"Manual T-Valve" = PIPE_MTVALVE,
|
|
"Upward Pipe" = PIPE_UP,
|
|
"Downward Pipe" = PIPE_DOWN
|
|
)
|
|
|
|
var/list/supply_pipes = list(
|
|
"Pipe" = PIPE_SUPPLY_STRAIGHT,
|
|
"Bent Pipe" = PIPE_SUPPLY_BENT,
|
|
"Manifold" = PIPE_SUPPLY_MANIFOLD,
|
|
"4-Way Manifold" = PIPE_SUPPLY_MANIFOLD4W,
|
|
"Upward Pipe" = PIPE_SUPPLY_UP,
|
|
"Downward Pipe" = PIPE_SUPPLY_DOWN
|
|
)
|
|
|
|
var/list/scrubber_pipes = list(
|
|
"Pipe" = PIPE_SCRUBBERS_STRAIGHT,
|
|
"Bent Pipe" = PIPE_SCRUBBERS_BENT,
|
|
"Manifold" = PIPE_SCRUBBERS_MANIFOLD,
|
|
"4-Way Manifold" = PIPE_SCRUBBERS_MANIFOLD4W,
|
|
"Upward Pipe" = PIPE_SCRUBBERS_UP,
|
|
"Downward Pipe" = PIPE_SCRUBBERS_DOWN
|
|
)
|
|
|
|
var/list/fuel_pipes = list(
|
|
"Pipe" = PIPE_FUEL_STRAIGHT,
|
|
"Bent Pipe" = PIPE_FUEL_BENT,
|
|
"Manifold" = PIPE_FUEL_MANIFOLD,
|
|
"4-Way Manifold" = PIPE_FUEL_MANIFOLD4W,
|
|
"Upward Pipe" = PIPE_FUEL_UP,
|
|
"Downward Pipe" = PIPE_FUEL_DOWN
|
|
)
|
|
|
|
var/list/aux_pipes = list(
|
|
"Pipe" = PIPE_AUX_STRAIGHT,
|
|
"Bent Pipe" = PIPE_AUX_BENT,
|
|
"Manifold" = PIPE_AUX_MANIFOLD,
|
|
"4-Way Manifold" = PIPE_AUX_MANIFOLD4W,
|
|
"Upward Pipe" = PIPE_AUX_UP,
|
|
"Downward Pipe" = PIPE_AUX_DOWN
|
|
)
|
|
|
|
var/list/devices = list(
|
|
"Universal Pipe Adapter" = PIPE_UNIVERSAL,
|
|
"Connector" = PIPE_CONNECTOR,
|
|
"Unary Vent" = PIPE_UVENT,
|
|
"Auxiliary Unary Vent" = PIPE_AUX_UVENT,
|
|
"Scrubber" = PIPE_SCRUBBER,
|
|
"Gas Pump" = PIPE_PUMP,
|
|
"Fuel Gas Pump" = PIPE_PUMP_FUEL,
|
|
"Pressure Regulator" = PIPE_PASSIVE_GATE,
|
|
"High Power Gas Pump" = PIPE_VOLUME_PUMP,
|
|
"Gas Filter" = PIPE_GAS_FILTER_M,
|
|
"Omni Gas Filter" = PIPE_OMNI_FILTER
|
|
)
|
|
|
|
/obj/item/rfd/piping/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
|
|
. = ..()
|
|
. += FONT_SMALL(SPAN_NOTICE("Change pipe category by ALT-clicking, change pipe selection by using in-hand."))
|
|
. += SPAN_NOTICE("Selected pipe category: <b>[selected_mode]</b>.")
|
|
. += SPAN_NOTICE("Selected pipe: <b>[pipe_examine]</b>.")
|
|
|
|
/obj/item/rfd/piping/afterattack(atom/A, mob/user, proximity)
|
|
if(!proximity || !isturf(A))
|
|
return
|
|
if(istype(get_area(A), /area/shuttle) || istype(get_area(A), /turf/space))
|
|
to_chat(user, SPAN_WARNING("You can't materialize a pipe here!"))
|
|
return FALSE
|
|
var/turf/T = get_turf(A)
|
|
if(!is_station_level(T.z))
|
|
to_chat(user, SPAN_WARNING("You can't materialize a pipe on this level!"))
|
|
return FALSE
|
|
return do_pipe(T, user)
|
|
|
|
/obj/item/rfd/piping/proc/do_pipe(var/turf/T, var/mob/user)
|
|
if(working)
|
|
return FALSE
|
|
|
|
if(stored_matter < build_cost)
|
|
to_chat(user, SPAN_NOTICE("The \"Matter Units Low\" light on the device blinks yellow."))
|
|
playsound(get_turf(src), 'sound/items/rfd_empty.ogg', 50, FALSE)
|
|
flick("[icon_state]-empty", src)
|
|
return FALSE
|
|
|
|
playsound(get_turf(src), 'sound/items/rfd_start.ogg', 50, FALSE)
|
|
|
|
working = TRUE
|
|
user.visible_message(SPAN_NOTICE("[user] holds \the [src] towards \the [T]."), SPAN_NOTICE("You start laying down a pipe..."))
|
|
|
|
if((build_delay && !do_after(user, build_delay)) || (!useResource(build_cost, user)))
|
|
playsound(get_turf(src), 'sound/items/rfd_interrupt.ogg', 50, FALSE)
|
|
working = FALSE
|
|
return FALSE
|
|
|
|
if(build_delay && !can_use(user, T))
|
|
return FALSE
|
|
|
|
// Special case handling for bent pipes. They require a non-cardinal direction
|
|
var/pipe_dir = NORTH
|
|
if(selected_pipe in list(PIPE_SIMPLE_BENT, PIPE_SUPPLY_BENT, PIPE_SCRUBBERS_BENT, PIPE_FUEL_BENT, PIPE_AUX_BENT))
|
|
pipe_dir = NORTHEAST
|
|
new /obj/item/pipe(T, selected_pipe, pipe_dir)
|
|
|
|
playsound(get_turf(src), 'sound/items/rfd_end.ogg', 50, FALSE)
|
|
working = FALSE
|
|
return TRUE
|
|
|
|
/obj/item/rfd/piping/attack_self(mob/user)
|
|
playsound(get_turf(src), 'sound/weapons/laser_safetyon.ogg', 50, FALSE)
|
|
var/list/pipe_selection = list()
|
|
switch(selected_mode)
|
|
if(STANDARD_PIPE)
|
|
pipe_selection = standard_pipes
|
|
if(SUPPLY_PIPE)
|
|
pipe_selection = supply_pipes
|
|
if(SCRUBBER_PIPE)
|
|
pipe_selection = scrubber_pipes
|
|
if(FUEL_PIPE)
|
|
pipe_selection = fuel_pipes
|
|
if(AUX_PIPE)
|
|
pipe_selection = aux_pipes
|
|
if(DEVICES)
|
|
pipe_selection = devices
|
|
pipe_examine = tgui_input_list(user, "Choose the pipe you want to deploy.", "Pipe Selection", pipe_selection, selected_pipe)
|
|
selected_pipe = pipe_selection[pipe_examine]
|
|
|
|
/obj/item/rfd/piping/AltClick(mob/user)
|
|
selected_mode = tgui_input_list(user, "Choose the category you want to change to.", "Pipe Categories", modes, selected_mode)
|
|
switch(selected_mode)
|
|
if(STANDARD_PIPE)
|
|
pipe_examine = "Pipe"
|
|
selected_pipe = PIPE_SIMPLE_STRAIGHT
|
|
if(SUPPLY_PIPE)
|
|
pipe_examine = "Pipe"
|
|
selected_pipe = PIPE_SUPPLY_STRAIGHT
|
|
if(SCRUBBER_PIPE)
|
|
pipe_examine = "Pipe"
|
|
selected_pipe = PIPE_SCRUBBERS_STRAIGHT
|
|
if(FUEL_PIPE)
|
|
pipe_examine = "Pipe"
|
|
selected_pipe = PIPE_FUEL_STRAIGHT
|
|
if(AUX_PIPE)
|
|
pipe_examine = "Pipe"
|
|
selected_pipe = PIPE_AUX_STRAIGHT
|
|
if(DEVICES)
|
|
pipe_examine = "Universal Pipe Adapter"
|
|
selected_pipe = PIPE_UNIVERSAL
|
|
|
|
/obj/item/rfd/piping/borg/useResource(var/amount, var/mob/user)
|
|
if(isrobot(user))
|
|
var/mob/living/silicon/robot/R = user
|
|
if(R.cell)
|
|
var/cost = amount * 30
|
|
if(R.cell.charge >= cost)
|
|
R.cell.use(cost)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/item/rfd/piping/borg/attackby()
|
|
return
|
|
|
|
#undef STANDARD_PIPE
|
|
#undef SUPPLY_PIPE
|
|
#undef SCRUBBER_PIPE
|
|
#undef FUEL_PIPE
|
|
#undef AUX_PIPE
|
|
#undef DEVICES
|
|
#undef MATERIALIZATION_FAIL_MESSAGE
|