diff --git a/baystation12.dme b/baystation12.dme index d0ec0e3ae0a..91a79ef86af 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1467,6 +1467,7 @@ #include "code\modules\surgery\surgery.dm" #include "code\modules\vehicles\ambulance.dm" #include "code\modules\vehicles\cargo_train.dm" +#include "code\modules\vehicles\janicart.dm" #include "code\modules\vehicles\train.dm" #include "code\modules\vehicles\vehicle.dm" #include "code\modules\virus2\analyser.dm" diff --git a/code/modules/vehicles/janicart.dm b/code/modules/vehicles/janicart.dm new file mode 100644 index 00000000000..7b476c80129 --- /dev/null +++ b/code/modules/vehicles/janicart.dm @@ -0,0 +1,357 @@ +/obj/vehicle/train/janitor/engine + name = "janitor train tug" + desc = "A ridable electric car designed for pulling janitor trolleys." + icon = 'icons/obj/vehicles.dmi' + icon_state = "pussywagon" //mulebot icons until I get some proper icons + on = 0 + powered = 1 + locked = 0 + layer = MOB_LAYER + 0.1 + standing_mob = 1 + load_item_visible = 1 + load_offset_x = 0 + load_offset_y = 7 + + var/car_limit = 3 //how many cars an engine can pull before performance degrades + active_engines = 1 + var/obj/item/weapon/key/janitor_train/key + flags = OPENCONTAINER + var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite + var/obj/item/weapon/storage/bag/trash/mybag = null + +/obj/item/weapon/key/janitor_train + name = "key" + desc = "A keyring with a small steel key, and a yellow fob reading \"Choo Choo!\"." + icon = 'icons/obj/vehicles.dmi' + icon_state = "keys" + w_class = 1 + +/obj/vehicle/train/janitor/trolley + name = "janitor train trolley" + icon = 'icons/obj/janitor.dmi' + icon_state = "trashcart" + anchored = 0 + passenger_allowed = 0 + locked = 0 + standing_mob = 0 + load_item_visible = 1 + load_offset_x = 1 + load_offset_y = 7 + + var/openTop = 0 + +//------------------------------------------- +// Standard procs +//------------------------------------------- +/obj/vehicle/train/janitor/engine/New() + ..() + cell = new /obj/item/weapon/cell/high + verbs -= /atom/movable/verb/pull + key = new() + var/datum/reagents/R = new/datum/reagents(100) + reagents = R + R.my_atom = src + +/obj/vehicle/train/janitor/engine/Move() + if(on && cell.charge < power_use) + turn_off() + update_stats() + if(load && is_train_head()) + load << "The drive motor briefly whines, then drones to a stop." + + if(is_train_head() && !on) + return 0 + + handle_rotation() + update_mob() + + return ..() + +/obj/vehicle/train/janitor/trolley/attackby(obj/item/weapon/W as obj, mob/user as mob) + openTop = !openTop + user.visible_message("[user] [openTop ? "opens" : "closes"] a the top of [src].","You [openTop ? "open" : "close"] the the top of [src].") + update_icon() + ..() + +/obj/vehicle/train/janitor/trolley/update_icon() + if(openTop) + icon_state = "trashcartopen" + else + icon_state = initial(icon_state) + +/obj/vehicle/train/janitor/engine/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/key/janitor_train)) + if(!key) + user.drop_item() + key = W + W.loc = src + verbs += /obj/vehicle/train/janitor/engine/verb/remove_key + return + else if(istype(W, /obj/item/weapon/mop)) + if(reagents.total_volume >= 2) + reagents.trans_to(W, 2) + user << "You wet the mop in the pimpin' ride." + playsound(src.loc, 'sound/effects/slosh.ogg', 25, 1) + if(reagents.total_volume < 1) + user << "This pimpin' ride is out of water!" + return + else if(istype(W, /obj/item/weapon/storage/bag/trash)) + user << "You hook the trashbag onto the pimpin' ride." + user.drop_item() + W.loc = src + mybag = W + return + ..() + +/obj/vehicle/train/janitor/engine/attack_hand(mob/user) + if(mybag) + mybag.loc = get_turf(user) + user.put_in_hands(mybag) + mybag = null + else + ..() + +/obj/vehicle/train/janitor/update_icon() + if(open) + icon_state = "mulebot-hatch" + else + icon_state = initial(icon_state) + +/obj/vehicle/train/janitor/engine/Emag(mob/user as mob) + ..() + flick("mulebot-emagged", src) + +/obj/vehicle/train/janitor/trolley/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H) + return + +/obj/vehicle/train/janitor/engine/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H) + ..() + update_stats() + +/obj/vehicle/train/janitor/engine/remove_cell(var/mob/living/carbon/human/H) + ..() + update_stats() + +/obj/vehicle/train/janitor/engine/Bump(atom/Obstacle) + var/obj/machinery/door/D = Obstacle + var/mob/living/carbon/human/H = load + if(istype(D) && istype(H)) + D.Bumped(H) //a little hacky, but hey, it works, and repects access rights + + ..() + +/obj/vehicle/train/janitor/trolley/Bump(atom/Obstacle) + if(!lead) + return //so people can't knock others over by pushing a trolley around + ..() + +/obj/vehicle/train/janitor/engine/proc/handle_rotation() + if(dir == SOUTH) + layer = FLY_LAYER + else + layer = OBJ_LAYER + +/obj/vehicle/train/janitor/engine/proc/update_mob() + if(load) + load.dir = dir + switch(dir) + if(SOUTH) + load.pixel_x = 0 + load.pixel_y = 7 + if(WEST) + load.pixel_x = 13 + load.pixel_y = 7 + if(NORTH) + load.pixel_x = 0 + load.pixel_y = 4 + if(EAST) + load.pixel_x = -13 + load.pixel_y = 7 + + +//------------------------------------------- +// Train procs +//------------------------------------------- +/obj/vehicle/train/janitor/engine/turn_on() + if(!key) + return + else + ..() + update_stats() + +/obj/vehicle/train/janitor/RunOver(var/mob/living/carbon/human/H) + var/list/parts = list("head", "chest", "l_leg", "r_leg", "l_arm", "r_arm") + + H.apply_effects(5, 5) + for(var/i = 0, i < rand(1,3), i++) + H.apply_damage(rand(1,5), BRUTE, pick(parts)) + +/obj/vehicle/train/janitor/trolley/RunOver(var/mob/living/carbon/human/H) + ..() + attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])") + +/obj/vehicle/train/janitor/engine/RunOver(var/mob/living/carbon/human/H) + ..() + + if(is_train_head() && istype(load, /mob/living/carbon/human)) + var/mob/living/carbon/human/D = load + D << "\red \b You ran over [H]!" + visible_message("\red \The [src] ran over [H]!") + attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey]), driven by [D.name] ([D.ckey])") + msg_admin_attack("[D.name] ([D.ckey]) ran over [H.name] ([H.ckey]). (JMP)") + else + attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])") + + +//------------------------------------------- +// Interaction procs +//------------------------------------------- +/obj/vehicle/train/janitor/engine/relaymove(mob/user, direction) + if(user != load) + return 0 + + if(is_train_head()) + if(direction == reverse_direction(dir)) + return 0 + if(Move(get_step(src, direction))) + return 1 + return 0 + else + return ..() + + +/obj/vehicle/train/janitor/engine/examine() + ..() + + usr << "\icon[src] This [name] contains [reagents.total_volume] unit\s of [reagents]!" + if(mybag) + usr << "\A [mybag] is hanging on the [name]." + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(get_dist(usr,src) <= 1) + usr << "The power light is [on ? "on" : "off"].\nThere are[key ? "" : " no"] keys in the ignition." + +/obj/vehicle/train/janitor/engine/verb/check_power() + set name = "Check power level" + set category = "Object" + set src in view(1) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(!cell) + usr << "There is no power cell installed in [src]." + return + + usr << "The power meter reads [round(cell.percent(), 0.01)]%" + +/obj/vehicle/train/janitor/engine/verb/start_engine() + set name = "Start engine" + set category = "Object" + set src in view(1) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(on) + usr << "The engine is already running." + return + + turn_on() + if (on) + usr << "You start [src]'s engine." + else + if(cell.charge < power_use) + usr << "[src] is out of power." + else + usr << "[src]'s engine won't start." + +/obj/vehicle/train/janitor/engine/verb/stop_engine() + set name = "Stop engine" + set category = "Object" + set src in view(1) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(!on) + usr << "The engine is already stopped." + return + + turn_off() + if (!on) + usr << "You stop [src]'s engine." + +/obj/vehicle/train/janitor/engine/verb/remove_key() + set name = "Remove key" + set category = "Object" + set src in view(1) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(!key || (load && load != usr)) + return + + if(on) + turn_off() + + key.loc = usr.loc + if(!usr.get_active_hand()) + usr.put_in_hands(key) + key = null + + verbs -= /obj/vehicle/train/janitor/engine/verb/remove_key + +//------------------------------------------- +// Loading/unloading procs +//------------------------------------------- +/obj/vehicle/train/janitor/trolley/load(var/atom/movable/C) + return 0 + +/obj/vehicle/train/janitor/engine/load(var/atom/movable/C) + if(!ismob(C)) + return 0 + + return ..() + + +//------------------------------------------------------- +// Stat update procs +// +// Update the trains stats for speed calculations. +// The longer the train, the slower it will go. car_limit +// sets the max number of cars one engine can pull at +// full speed. Adding more cars beyond this will slow the +// train proportionate to the length of the train. Adding +// more engines increases this limit by car_limit per +// engine. +//------------------------------------------------------- +/obj/vehicle/train/janitor/engine/update_train_stats() + ..() + + update_move_delay() + +/obj/vehicle/train/janitor/trolley/update_train_stats() + ..() + + if(!lead && !tow) + anchored = 0 + if(verbs.Find(/atom/movable/verb/pull)) + return + else + verbs += /atom/movable/verb/pull + else + anchored = 1 + verbs -= /atom/movable/verb/pull + +/obj/vehicle/train/janitor/engine/proc/update_move_delay() + if(!is_train_head() || !on) + move_delay = initial(move_delay) //so that engines that have been turned off don't lag behind + else + move_delay = max(0, (-car_limit * active_engines) + train_length - active_engines) //limits base overweight so you cant overspeed trains + move_delay *= (1 / max(1, active_engines)) * 2 //overweight penalty (scaled by the number of engines) + move_delay += config.run_speed //base reference speed + move_delay *= 1.05 diff --git a/icons/obj/janitor.dmi b/icons/obj/janitor.dmi index 07b236e1abc..92a8c6c528f 100644 Binary files a/icons/obj/janitor.dmi and b/icons/obj/janitor.dmi differ diff --git a/maps/cyberiad.dmm b/maps/cyberiad.dmm index 184d31c5f31..97b189a25ec 100644 --- a/maps/cyberiad.dmm +++ b/maps/cyberiad.dmm @@ -4767,8 +4767,8 @@ "bNI" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor,/area/hallway/primary/aft) "bNJ" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor{dir = 2; icon_state = "yellowcorner"},/area/hallway/primary/aft) "bNK" = (/obj/machinery/power/apc{dir = 8; name = "Custodial Closet APC"; pixel_x = -24},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/simulated/floor,/area/janitor) -"bNL" = (/obj/structure/stool,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/effect/landmark/start{name = "Janitor"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 9},/turf/simulated/floor,/area/janitor) -"bNM" = (/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor,/area/janitor) +"bNL" = (/obj/structure/stool,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/effect/landmark/start{name = "Janitor"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 9},/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/turf/simulated/floor,/area/janitor) +"bNM" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor,/area/janitor) "bNN" = (/obj/effect/landmark/start{name = "Janitor"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor,/area/janitor) "bNO" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/turf/simulated/floor,/area/janitor) "bNP" = (/obj/structure/mopbucket,/obj/item/weapon/mop,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor,/area/janitor) @@ -4831,10 +4831,10 @@ "bOU" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden,/obj/structure/disposalpipe/segment,/turf/simulated/floor{dir = 8; icon_state = "cautioncorner"},/area/hallway/primary/aft) "bOV" = (/obj/machinery/atmospherics/unary/vent_pump{on = 1},/turf/simulated/floor,/area/hallway/primary/aft) "bOW" = (/obj/machinery/firealarm{dir = 4; pixel_x = 24},/turf/simulated/floor{dir = 2; icon_state = "yellowcorner"},/area/hallway/primary/aft) -"bOX" = (/obj/structure/table,/obj/item/weapon/paper_bin{pixel_x = -3; pixel_y = 7},/obj/item/weapon/pen,/turf/simulated/floor,/area/janitor) -"bOY" = (/obj/structure/table,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/machinery/requests_console{department = "Janitorial"; departmentType = 1; pixel_y = -29},/obj/item/weapon/reagent_containers/spray/cleaner,/turf/simulated/floor,/area/janitor) -"bOZ" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 1},/obj/machinery/light,/turf/simulated/floor,/area/janitor) -"bPa" = (/obj/structure/stool/bed/chair/cart/janicart,/turf/simulated/floor,/area/janitor) +"bOX" = (/obj/structure/table,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/machinery/requests_console{department = "Janitorial"; departmentType = 1; pixel_y = -29},/obj/item/weapon/reagent_containers/spray/cleaner,/turf/simulated/floor,/area/janitor) +"bOY" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 1},/turf/simulated/floor,/area/janitor) +"bOZ" = (/obj/machinery/light,/obj/vehicle/train/janitor/trolley,/turf/simulated/floor,/area/janitor) +"bPa" = (/obj/vehicle/train/janitor/engine,/turf/simulated/floor,/area/janitor) "bPb" = (/obj/item/weapon/legcuffs/beartrap,/obj/item/weapon/legcuffs/beartrap,/obj/item/weapon/storage/box/mousetraps,/obj/item/weapon/storage/box/mousetraps,/turf/simulated/floor,/area/janitor) "bPc" = (/obj/structure/reagent_dispensers/watertank,/obj/machinery/atmospherics/unary/vent_pump{dir = 4; on = 1},/turf/simulated/floor,/area/janitor) "bPd" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/maintenance/asmaint)