diff --git a/code/game/objects/items/weapons/RFD.dm b/code/game/objects/items/weapons/RFD.dm
index b6e56452f2f..b95b1f87e9d 100644
--- a/code/game/objects/items/weapons/RFD.dm
+++ b/code/game/objects/items/weapons/RFD.dm
@@ -5,11 +5,14 @@
// Defines
#define MATERIALIZATION_FAIL_MESSAGE "You can't materialize two constructions of the same type."
-//
-// Rapid Fabrication Device
-//
-
+/**
+ * # Rapid Fabrication Device
+ *
+ * A device used for rapid fabrication of things, built from a compressed matter cartridge
+ */
/obj/item/rfd
+ abstract_type = /obj/item/rfd //This is an abstract, use one of the subtypes instead
+
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'
@@ -32,19 +35,25 @@
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
- // A list of atoms 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
- )
var/build_cost = 0
var/build_type
var/build_atom
@@ -141,6 +150,11 @@
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."
@@ -152,6 +166,12 @@
matter = list(DEFAULT_WALL_MATERIAL = 2000, MATERIAL_GLASS = 2000)
recyclable = TRUE
+
+/*##############
+ SUBTYPES
+##############*/
+
+
//
// RFD - Construction Class
//
@@ -159,10 +179,16 @@
/obj/item/rfd/construction
name = "\improper Rapid Fabrication Device C-Class"
desc = "A RFD, modified to construct walls and floors."
- var/list/radial_modes = list()
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(
@@ -382,7 +408,6 @@
desc = "A RFD, modified to deploy service items."
icon_state = "rfd-s"
item_state = "rfd-s"
- var/list/radial_modes = list()
/obj/item/rfd/service/Initialize()
. = ..()
@@ -466,23 +491,43 @@
stored_matter--
to_chat(user, "The RSF now holds [stored_matter]/30 fabrication-units.")
-//
-// RFD - Mining Class
-//
+
+/*#######################
+ 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/attack_self(mob/user)
- return
+/obj/item/rfd/mining/Initialize()
+ . = ..()
-/obj/item/rfd/mining/afterattack(atom/A, mob/user, proximity, click_parameters, var/report_duplicate = TRUE)
- if(!proximity)
+ 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 \"[current_mode]\"."))
+
+/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)
@@ -501,31 +546,74 @@
flick("[icon_state]-empty", src)
return
- if(!istype(A, /turf/simulated/floor) && !istype(A, /turf/unsimulated/floor))
+ //Can only be used on floors
+ if(!istype(target, /turf/simulated/floor) && !istype(target, /turf/unsimulated/floor))
return
- if(locate(/obj/structure/track) in A)
- if(report_duplicate)
- to_chat(user, SPAN_WARNING("There is already a track on \the [A]!"))
- 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 /obj/structure/track(get_turf(A))
+ new item_to_make(get_turf(target))
- to_chat(user, SPAN_NOTICE("You deploy a mine track on \the [A]."))
+ 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 [stored_matter]/30 fabrication-units."))
+ to_chat(user, SPAN_NOTICE("The RFD now holds [stored_matter]/[initial(stored_matter)] 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
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index 0d5b65970a4..7af097ea997 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -4,7 +4,11 @@
//VENDOR: Obj/item's are immediately dispensed by the vendor. Machines, structures, vehicles, and etc get spawned on the cargo shuttle.
//Think up of lots of items. Not everything needs to be unique or even mining-special, but it should be neat. Convert most of /tg/'s items. 25% of this at least
// should be bling. Things that shorten the distance between base and mining. Instant-teleporters should be one use.
-var/global/list/minevendor_list = list( //keep in order of price
+GLOBAL_LIST_INIT(minevendor_list, list(
+ /*
+ Format:
+ new /datum/data/mining_equipment( [TYPEPATH], [AMOUNT], [COST], [SHUTTLE?] ),
+ */
new /datum/data/mining_equipment(/obj/item/reagent_containers/food/snacks/liquidfood, 10, 5),
new /datum/data/mining_equipment(/obj/item/contraband/poster, 10, 20),
new /datum/data/mining_equipment(/obj/item/ore_radar, 10, 50),
@@ -13,7 +17,7 @@ var/global/list/minevendor_list = list( //keep in order of price
new /datum/data/mining_equipment(/obj/item/stack/flag/yellow, 10, 50),
new /datum/data/mining_equipment(/obj/item/stack/flag/purple, 10, 50),
new /datum/data/mining_equipment(/obj/item/storage/bag/ore, 25, 50),
- new /datum/data/mining_equipment(/obj/item/pizzabox/meat, 25, 50),
+ new /datum/data/mining_equipment(pick(subtypesof(/obj/item/pizzabox)), 25, 50),
new /datum/data/mining_equipment(/obj/item/device/flashlight/lantern, 10, 75),
new /datum/data/mining_equipment(/obj/item/shovel, 15, 100),
new /datum/data/mining_equipment(/obj/item/pickaxe, 10, 100),
@@ -38,16 +42,13 @@ var/global/list/minevendor_list = list( //keep in order of price
new /datum/data/mining_equipment(/obj/item/warp_core, 25, 500),
new /datum/data/mining_equipment(/obj/item/extraction_pack, 25, 600),
new /datum/data/mining_equipment(/obj/item/device/mine_bot_upgrade/health, 20, 600),
- new /datum/data/mining_equipment(/obj/item/rfd/mining, 10, 600),
new /datum/data/mining_equipment(/obj/item/storage/firstaid/trauma, 30, 600),
new /datum/data/mining_equipment(/obj/item/oremagnet, 10, 600),
- new /datum/data/mining_equipment(/obj/vehicle/train/cargo/trolley/mining, -1, 600, 1),
new /datum/data/mining_equipment(/obj/item/resonator, 10, 700),
new /datum/data/mining_equipment(/obj/item/device/wormhole_jaunter, 20, 750),
new /datum/data/mining_equipment(/obj/item/rig/industrial, 5, 1000),
new /datum/data/mining_equipment(/obj/item/mass_driver_diy, 5, 800),
new /datum/data/mining_equipment(/mob/living/silicon/robot/drone/mining, 15, 800),
- new /datum/data/mining_equipment(/obj/vehicle/train/cargo/engine/mining, -1, 800, 1),
new /datum/data/mining_equipment(/obj/item/device/mine_bot_upgrade/ka, 10, 800),
new /datum/data/mining_equipment(/obj/item/oreportal, 35, 800),
new /datum/data/mining_equipment(/obj/item/device/spaceflare, 5, 800),
@@ -60,7 +61,7 @@ var/global/list/minevendor_list = list( //keep in order of price
new /datum/data/mining_equipment(/obj/item/device/orbital_dropper/minecart, 5, 2000),
new /datum/data/mining_equipment(/obj/item/device/orbital_dropper/drill, 10, 3250),
new /datum/data/mining_equipment(/obj/item/device/orbital_dropper/mecha/miner, 2, 3500)
- )
+ ))
/obj/machinery/mineral/equipment_vendor
name = "mining equipment vendor"
@@ -126,7 +127,7 @@ var/global/list/minevendor_list = list( //keep in order of price
else
data["hasId"] = FALSE
var/list/prize_list = list()
- for(var/datum/data/mining_equipment/prize as anything in minevendor_list)
+ for(var/datum/data/mining_equipment/prize as anything in GLOB.minevendor_list)
prize_list += list(list("name" = prize.equipment_name, "desc" = prize.equipment_description, "cost" = prize.cost, "stock" = prize.amount, "ref" = "\ref[prize]"))
data["prizeList"] = prize_list
return data
@@ -140,7 +141,7 @@ var/global/list/minevendor_list = list( //keep in order of price
var/obj/item/card/id/ID = usr.GetIdCard()
if(ID)
var/datum/data/mining_equipment/prize = locate(params["purchase"])
- if(!prize || !(prize in minevendor_list))
+ if(!prize || !(prize in GLOB.minevendor_list))
return
if(prize.amount <= 0 && prize.amount != -1)
return
diff --git a/code/modules/research/designs/protolathe/mining_designs.dm b/code/modules/research/designs/protolathe/mining_designs.dm
index 4edd3e4acb6..db591e5da9b 100644
--- a/code/modules/research/designs/protolathe/mining_designs.dm
+++ b/code/modules/research/designs/protolathe/mining_designs.dm
@@ -1,6 +1,13 @@
/datum/design/item/mining
p_category = "Mining Equipment Designs"
+
+/datum/design/item/mining/mining_rfd
+ name = "Rapid Fabrication Device, Mining Class"
+ desc = "A Rapid Fabrication Device, modified to construct rails and mining carts, for an efficient mining operation."
+ materials = list(DEFAULT_WALL_MATERIAL = 3000, MATERIAL_GLASS = 3000)
+ build_path = /obj/item/rfd/mining
+
/datum/design/item/mining/jackhammer
req_tech = list(TECH_MATERIAL = 3, TECH_POWER = 2, TECH_ENGINEERING = 2)
materials = list(DEFAULT_WALL_MATERIAL = 2000, MATERIAL_GLASS = 500, MATERIAL_SILVER = 500)
diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm
index 676d4e04b7e..1b127e6f8c0 100644
--- a/code/modules/vehicles/cargo_train.dm
+++ b/code/modules/vehicles/cargo_train.dm
@@ -6,7 +6,8 @@
- ALT-click the truck to remove the key from the ignition.
\
- Click the truck to open a UI menu.
\
- Click the resist button or type \"resist\" in the command bar at the bottom of your screen to get off the truck.
\
- - If latched, you can use a wrench to unlatch."
+ - If latched, you can use a wrench to unlatch.
\
+ - Click-drag on a trolley to latch and tow it."
icon = 'icons/obj/vehicles.dmi'
icon_state = "cargo_engine"
on = 0
@@ -33,7 +34,7 @@
/obj/vehicle/train/cargo/trolley
name = "cargo train trolley"
- desc_info = "You can use a wrench to unlatch this."
+ desc_info = "You can use a wrench to unlatch this, click-drag to link it to another trolley to tow."
icon = 'icons/obj/vehicles.dmi'
icon_state = "cargo_trailer"
anchored = 0
@@ -242,6 +243,10 @@
if(is_train_head())
if(direction == reverse_direction(dir) && tow)
+ //Allow the engine to rotate, but only if there's not another piece in the new direction
+ //Basically, to allow the first rotation at spawn to align with the rest of the convoy, without it being a CBT
+ if(!(locate(/obj/vehicle/train) in get_step(src, direction)))
+ set_dir(direction)
return 0
if(Move(get_step(src, direction)))
return 1
@@ -277,6 +282,10 @@
if("Toggle Latching")
if(tow)
tow.unattach(user)
+ else
+ var/obj/vehicle/train/cargo/trolley/nearby_trolley = locate() in orange(src, 1)
+ if(nearby_trolley)
+ src.latch(nearby_trolley)
/obj/vehicle/train/cargo/engine/AltClick(var/mob/user)
if(Adjacent(user))
diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm
index 283e1bb9041..73f13f61a8e 100644
--- a/code/modules/vehicles/vehicle.dm
+++ b/code/modules/vehicles/vehicle.dm
@@ -191,16 +191,16 @@
//-------------------------------------------
/obj/vehicle/proc/turn_on()
if(stat)
- return 0
- if(powered && cell.charge < charge_use && !organic)
- return 0
- on = 1
+ return FALSE
+ if(powered && cell?.charge < charge_use && !organic)
+ return FALSE
+ on = TRUE
set_light(initial(light_range))
update_icon()
- return 1
+ return TRUE
/obj/vehicle/proc/turn_off()
- on = 0
+ on = FALSE
set_light(0)
update_icon()
@@ -297,49 +297,56 @@
// the vehicle load() definition before
// calling this parent proc.
//-------------------------------------------
-/obj/vehicle/proc/load(var/atom/movable/C)
+/**
+ * Loads an /atom onto the vehicle
+ *
+ * * thing_to_load - The thing to load, an `/obj` or `/mob`
+ *
+ * Returns `TRUE` if the load was successful, `FALSE` otherwise
+ */
+/obj/vehicle/proc/load(var/atom/movable/thing_to_load)
//This loads objects onto the vehicle so they can still be interacted with.
//Define allowed items for loading in specific vehicle definitions.
- if(!isturf(C.loc)) //To prevent loading things from someone's inventory, which wouldn't get handled properly.
- return 0
- if(load || C.anchored)
- return 0
+ if(!isturf(thing_to_load.loc)) //To prevent loading things from someone's inventory, which wouldn't get handled properly.
+ return FALSE
+ if(load || thing_to_load.anchored)
+ return FALSE
// if a crate/closet, close before loading
- var/obj/structure/closet/closet = C
+ var/obj/structure/closet/closet = thing_to_load
if(istype(closet))
closet.close()
- C.forceMove(loc)
- C.set_dir(dir)
- C.anchored = 1
+ thing_to_load.forceMove(loc)
+ thing_to_load.set_dir(dir)
+ thing_to_load.anchored = TRUE
- load = C
+ load = thing_to_load
- C.layer = VEHICLE_LOAD_LAYER
+ thing_to_load.layer = VEHICLE_LOAD_LAYER
if(load_item_visible)
- C.pixel_x += load_offset_x
- if(ismob(C))
- C.pixel_y += mob_offset_y
+ thing_to_load.pixel_x += load_offset_x
+ if(ismob(thing_to_load))
+ thing_to_load.pixel_y += mob_offset_y
else
- if(istype(C, /obj/structure/closet/crate))
- C.pixel_y += load_offset_y
+ if(istype(thing_to_load, /obj/structure/closet/crate))
+ thing_to_load.pixel_y += load_offset_y
else
- C.pixel_y += 10
+ thing_to_load.pixel_y += 10
- if(ismob(C))
- buckle(C, C)
+ if(ismob(thing_to_load))
+ buckle(thing_to_load, thing_to_load)
- return 1
+ return TRUE
-/obj/vehicle/buckle(var/atom/movable/C, mob/user)
+/obj/vehicle/buckle(atom/movable/buckling_atom, mob/user)
. = ..()
if(. && buckling_sound)
playsound(src, buckling_sound, 20)
-/obj/vehicle/user_unbuckle(var/mob/user, var/direction)
+/obj/vehicle/user_unbuckle(mob/user)
..()
- unload(user, direction)
+ unload(user)
return
/obj/vehicle/proc/unload(var/mob/user, var/direction)
diff --git a/html/changelogs/fluffyghost-minetrainrfd.yml b/html/changelogs/fluffyghost-minetrainrfd.yml
new file mode 100644
index 00000000000..46c60360640
--- /dev/null
+++ b/html/changelogs/fluffyghost-minetrainrfd.yml
@@ -0,0 +1,64 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# - (fixes bugs)
+# wip
+# - (work in progress)
+# qol
+# - (quality of life)
+# soundadd
+# - (adds a sound)
+# sounddel
+# - (removes a sound)
+# rscadd
+# - (adds a feature)
+# rscdel
+# - (removes a feature)
+# imageadd
+# - (adds an image or sprite)
+# imagedel
+# - (removes an image or sprite)
+# spellcheck
+# - (fixes spelling or grammar)
+# experiment
+# - (experimental change)
+# balance
+# - (balance changes)
+# code_imp
+# - (misc internal code change)
+# refactor
+# - (refactors code)
+# config
+# - (makes a change to the config files)
+# admin
+# - (makes changes to administrator tools)
+# server
+# - (miscellaneous changes to server)
+#################################
+
+# Your name.
+author: FluffyGhost
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
+# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - code_imp: "Improved / refactored some code, particularly around RFD."
+ - rscadd: "Added the ability for mining RFD to build the mining train engine and carts."
+ - rscadd: "Removed the RFD, carts and engine from the mining vendor."
+ - rscadd: "Added the RFD as a roundstart printable protolathe design."
+ - code_imp: "Made the mining vendor list a GLOB variable."
+ - bugfix: "Resolved a runtime on vehicles trying to turn on without a cell being present."
+ - rscadd: "Mining vendor pizzas now have a random pizza subtype."