mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-01-01 05:02:33 +00:00
Programmable cargo machines
This commit is contained in:
797
code/WorkInProgress/Sayu/cargoprofile.dm
Normal file
797
code/WorkInProgress/Sayu/cargoprofile.dm
Normal file
@@ -0,0 +1,797 @@
|
||||
/datum/cargoprofile
|
||||
var/name = "All Items"
|
||||
var/id = "all" // unique ID for the UI
|
||||
var/enabled = 1
|
||||
var/eject_speed = 1 // will change when emagged
|
||||
var/const/BIG_OBJECT_WORK = 10
|
||||
var/const/MOB_WORK = 10
|
||||
var/obj/machinery/programmable/master = null
|
||||
var/universal = 0 // set when both unary and binary machines work
|
||||
var/mobcheck = 0
|
||||
|
||||
var/list/whitelist = list(/obj/item,/obj/structure/closet,/obj/structure/bigDelivery,/obj/machinery/portable_atmospherics)
|
||||
var/list/blacklist = null
|
||||
var/dedicated_path = null // When constructing a new machine with this as default program, create a machine of the specified type instead.
|
||||
|
||||
|
||||
//contains: called to determine if an object/mob will be sorted by this profile
|
||||
//return 1 for any sortable item
|
||||
proc/contains(var/atom/A)
|
||||
if(!istype(A,/obj))
|
||||
if(!mobcheck || !istype(A,/mob))
|
||||
return 0
|
||||
else
|
||||
var/obj/O = A
|
||||
if(O.anchored)
|
||||
return 0
|
||||
//If you are using both white and blacklists, blacklists are absoulte, no matter what is whitelisted.
|
||||
//I understand this has some limitations. You cannot whitelist all items, blacklist weapons,
|
||||
// and then whitelist a specific weapon. Them's the breaks, kid.
|
||||
if(blacklist)
|
||||
for(var/T in blacklist)
|
||||
if(istype(A,T))
|
||||
return 0
|
||||
if(whitelist)
|
||||
for(var/T in whitelist)
|
||||
if(istype(A,T))
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
//inlet_reaction: called when a filtered item is chosen by this profile.
|
||||
//W: Item chosen
|
||||
//S: input turf location
|
||||
//remaining: counts down how much more work the unloader wants to do this turn.
|
||||
//return the amount of work done.
|
||||
proc/inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
if(!W || !S || !master)
|
||||
return 0
|
||||
|
||||
if(istype(W,/obj/item))
|
||||
var/obj/item/I = W
|
||||
if(I.w_class > remaining)
|
||||
return 0
|
||||
I.loc = master
|
||||
master.types[W.type] = src
|
||||
return I.w_class
|
||||
|
||||
|
||||
if(istype(W,/obj/structure) || istype(W,/obj/machinery)) // closets, big deliveries, portable atmospherics, unconnected stuff
|
||||
if(remaining < BIG_OBJECT_WORK)
|
||||
return 0
|
||||
var/obj/O = W
|
||||
O.loc = master
|
||||
master.types[O.type] = src
|
||||
return BIG_OBJECT_WORK
|
||||
|
||||
//Not item, structure, machinery, or mob
|
||||
return 0
|
||||
|
||||
//outlet_reaction: called when a stored object is ejected
|
||||
//W: the item in question
|
||||
//D: the destination turf
|
||||
proc/outlet_reaction(var/atom/W,var/turf/D)
|
||||
if(!W || !D || !master)
|
||||
return
|
||||
|
||||
if(master.emagged)
|
||||
// emagging is not an industry-approved practice.
|
||||
// some malfunctions may occur.
|
||||
eject_speed = rand(0,4)
|
||||
D = get_step(D,master.outdir)
|
||||
while(prob(20))
|
||||
if(master.outdir == NORTH || master.outdir == SOUTH)
|
||||
D = get_step(D,pick(EAST,WEST,master.outdir))
|
||||
else
|
||||
D = get_step(D,pick(NORTH,SOUTH,master.outdir))
|
||||
|
||||
if(istype(W,/obj))
|
||||
var/obj/O = W
|
||||
O.loc = master.loc
|
||||
O.dir = master.outdir
|
||||
O.throw_at(D,eject_speed,eject_speed)
|
||||
return
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Profiles
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/datum/cargoprofile/boxes
|
||||
name = "Move Small Containers"
|
||||
id = "boxes"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/weapon/storage, /obj/item/weapon/moneybag, /obj/item/weapon/evidencebag,
|
||||
/obj/item/weapon/tray, /obj/item/pizzabox, /obj/item/weapon/clipboard,
|
||||
/obj/item/smallDelivery, /obj/structure/bigDelivery)
|
||||
|
||||
/datum/cargoprofile/cargo
|
||||
name = "Move Large Containers"
|
||||
id = "cargo"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/structure/closet,/obj/structure/ore_box)
|
||||
|
||||
// Make an honest attempt to move other things out of the way
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
for(var/obj/O in D)
|
||||
if(O.density && !O.anchored)
|
||||
step_away(O,src) // move forward first
|
||||
if(O.loc == D)
|
||||
step_away(O,D) // move anywhere
|
||||
..(W,D)
|
||||
|
||||
/datum/cargoprofile/cargo/empty
|
||||
name = "Move Empty Large Containers"
|
||||
id = "cargo-empty"
|
||||
contains(var/atom/A)
|
||||
return (..(A) && (A.contents.len == 0))
|
||||
/datum/cargoprofile/cargo/full
|
||||
name = "Move Full Large Containers"
|
||||
id = "cargo-full"
|
||||
contains(var/atom/A)
|
||||
return (..(A) && (A.contents.len > 0))
|
||||
|
||||
/datum/cargoprofile/supplies
|
||||
name = "Building Supplies"
|
||||
id = "supplies"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/weapon/cable_coil,/obj/item/stack/rods,
|
||||
/obj/item/stack/sheet/metal,/obj/item/stack/sheet/plasteel,
|
||||
/obj/item/stack/sheet/glass,/obj/item/stack/sheet/rglass,
|
||||
/obj/item/stack/tile,/obj/item/weapon/light,
|
||||
/obj/item/weapon/table_parts)
|
||||
//todo: maybe stack things while we're here?
|
||||
|
||||
/datum/cargoprofile/exotics
|
||||
name = "Exotic materials"
|
||||
id = "exotics"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/weapon/coin, /obj/item/weapon/spacecash, /obj/item/seeds,
|
||||
/obj/item/stack/sheet/mineral,/obj/item/stack/sheet/wood,/obj/item/stack/sheet/leather)
|
||||
|
||||
/datum/cargoprofile/organics
|
||||
name = "Organics, chemicals, and Paraphernalia"
|
||||
id = "organics"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/weapon/tank,/obj/item/weapon/reagent_containers,
|
||||
/obj/item/stack/medical,/obj/item/weapon/storage/pill_bottle,/obj/item/weapon/gun/syringe,
|
||||
/obj/item/weapon/plastique,/obj/item/weapon/grenade,/obj/item/ammo_box,
|
||||
/obj/item/weapon/gun/grenadelauncher,/obj/item/weapon/flamethrower, /obj/item/weapon/lighter,
|
||||
/obj/item/weapon/match,/obj/item/weapon/weldingtool)
|
||||
|
||||
/datum/cargoprofile/food
|
||||
name = "Food"
|
||||
id = "food"
|
||||
blacklist = null // something should probably go here
|
||||
whitelist = list(/obj/item/weapon/reagent_containers/food)
|
||||
|
||||
/datum/cargoprofile/chemical
|
||||
name = "Chemicals and Paraphernalia"
|
||||
id = "chemical"
|
||||
blacklist = list(/obj/item/weapon/reagent_containers/food)
|
||||
whitelist = list(/obj/item/weapon/reagent_containers,/obj/item/stack/medical,/obj/item/weapon/storage/pill_bottle,
|
||||
/obj/item/weapon/gun/syringe,/obj/item/weapon/grenade/chem_grenade,/obj/item/weapon/dnainjector,
|
||||
/obj/item/weapon/storage/belt/medical,/obj/item/weapon/storage/firstaid,/obj/item/weapon/implanter)
|
||||
|
||||
/datum/cargoprofile/pressure
|
||||
name = "air tanks"
|
||||
id = "pressure"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/weapon/tank,/obj/machinery/portable_atmospherics,
|
||||
/obj/item/weapon/flamethrower)
|
||||
//Am I missing any?
|
||||
/datum/cargoprofile/pressure/empty
|
||||
name = "empty air tanks"
|
||||
id = "pressure-low"
|
||||
var/lowpressure = ONE_ATMOSPHERE
|
||||
|
||||
contains(var/atom/A)
|
||||
if(..())
|
||||
var/pressure = ONE_ATMOSPHERE * 10 // In case of fallthrough, fail test
|
||||
if(istype(A,/obj/item/weapon/tank))
|
||||
var/obj/item/weapon/tank/T = A
|
||||
pressure = T.air_contents.return_pressure()
|
||||
if(istype(A,/obj/item/weapon/flamethrower))
|
||||
var/obj/item/weapon/flamethrower/T = A
|
||||
if(!T.ptank)
|
||||
return 0
|
||||
pressure = T.ptank.air_contents.return_pressure()
|
||||
if(istype(A,/obj/machinery/portable_atmospherics))
|
||||
var/obj/machinery/portable_atmospherics/P = A
|
||||
pressure = P.air_contents.return_pressure()
|
||||
|
||||
if(pressure < lowpressure)
|
||||
return 1
|
||||
|
||||
return 0// Not container or failed low pressure check
|
||||
|
||||
/datum/cargoprofile/pressure/full
|
||||
name = "full air tanks"
|
||||
id = "pressure-high"
|
||||
var/highpressure = ONE_ATMOSPHERE * 15 // stolen from canister.dm; Is this right?
|
||||
|
||||
contains(var/atom/A)
|
||||
if(..())
|
||||
var/pressure = 0 // In case of fallthrough, fail test
|
||||
if(istype(A,/obj/item/weapon/tank))
|
||||
var/obj/item/weapon/tank/T = A
|
||||
pressure = T.air_contents.return_pressure()
|
||||
if(istype(A,/obj/item/weapon/flamethrower))
|
||||
var/obj/item/weapon/flamethrower/T = A
|
||||
if(!T.ptank)
|
||||
return 0
|
||||
pressure = T.ptank.air_contents.return_pressure()
|
||||
if(istype(A,/obj/machinery/portable_atmospherics))
|
||||
var/obj/machinery/portable_atmospherics/P = A
|
||||
pressure = P.air_contents.return_pressure()
|
||||
|
||||
if(pressure > highpressure)
|
||||
return 1
|
||||
|
||||
return 0// Not container or failed high pressure check
|
||||
|
||||
/datum/cargoprofile/clothing
|
||||
name = "Crew Kit"
|
||||
id = "clothing"
|
||||
blacklist = list(/obj/item/weapon/tank/plasma,/obj/item/weapon/tank/anesthetic, // the rest are air tanks
|
||||
/obj/item/clothing/mask/facehugger) // NOT CLOTHING AT ALLLLL
|
||||
whitelist = list(/obj/item/clothing,/obj/item/weapon/storage/belt,/obj/item/weapon/storage/backpack,
|
||||
/obj/item/device/radio/headset,/obj/item/device/pda,/obj/item/weapon/card/id,/obj/item/weapon/tank,
|
||||
/obj/item/weapon/handcuffs, /obj/item/weapon/legcuffs)
|
||||
|
||||
/datum/cargoprofile/trash
|
||||
name = "Trash"
|
||||
id = "trash"
|
||||
//Note that this filters out blueprints because they are a paper item. Do NOT throw out the station blueprints unless you be trollin'.
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/trash,/obj/item/toy,/obj/item/weapon/ectoplasm,/obj/item/weapon/bananapeel,/obj/item/weapon/broken_bottle,/obj/item/weapon/bikehorn,
|
||||
/obj/item/weapon/cigbutt,/obj/item/weapon/contraband,/obj/item/weapon/corncob,/obj/item/weapon/paper,/obj/item/weapon/shard,
|
||||
/obj/item/weapon/sord,/obj/item/weapon/photo,/obj/item/weapon/folder,
|
||||
/obj/item/blueprints,/obj/item/weapon/contraband,/obj/item/weapon/kitchen,/obj/item/weapon/book,/obj/item/clothing/mask/facehugger)
|
||||
|
||||
/datum/cargoprofile/weapons
|
||||
name = "Weapons & Illegals"
|
||||
id = "weapons"
|
||||
blacklist = null
|
||||
//This one is hard since 'weapon contains a lot of things better categorized as devices
|
||||
whitelist = list(/obj/item/weapon/banhammer,/obj/item/weapon/sord,/obj/item/weapon/butch,/obj/item/weapon/claymore,/obj/item/weapon/holo/esword,
|
||||
/obj/item/weapon/flamethrower,/obj/item/weapon/grenade,/obj/item/weapon/gun,/obj/item/weapon/hatchet,/obj/item/weapon/katana,
|
||||
/obj/item/weapon/kitchenknife,/obj/item/weapon/melee,/obj/item/weapon/nullrod,/obj/item/weapon/pickaxe,/obj/item/weapon/twohanded,
|
||||
/obj/item/weapon/plastique,/obj/item/weapon/scalpel,/obj/item/weapon/shield,/obj/item/weapon/grown/deathnettle)
|
||||
|
||||
/datum/cargoprofile/tools
|
||||
name = "Devices & Tools"
|
||||
id = "tools"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/device,/obj/item/weapon/card,/obj/item/weapon/cartridge,/obj/item/weapon/cautery,/obj/item/weapon/cell,/obj/item/weapon/circuitboard,
|
||||
/obj/item/weapon/aiModule,/obj/item/weapon/airalarm_electronics,/obj/item/weapon/airlock_electronics,/obj/item/weapon/circular_saw,
|
||||
/obj/item/weapon/cloaking_device,/obj/item/weapon/crowbar,/obj/item/weapon/disk,/obj/item/weapon/firealarm_electronics,/obj/item/weapon/hand_tele,
|
||||
/obj/item/weapon/hand_labeler,/obj/item/weapon/hemostat,/obj/item/weapon/mop,/obj/item/weapon/locator,/obj/item/weapon/minihoe,
|
||||
/obj/item/weapon/packageWrap,/obj/item/weapon/pen,/obj/item/weapon/pickaxe,/obj/item/weapon/pinpointer,
|
||||
/obj/item/weapon/rcd,/obj/item/weapon/rcd_ammo,/obj/item/weapon/retractor,/obj/item/weapon/rsf,/obj/item/weapon/rsp,/obj/item/weapon/scalpel,
|
||||
/obj/item/weapon/screwdriver,/obj/item/weapon/shovel,/obj/item/weapon/soap,/obj/item/weapon/stamp,/obj/item/weapon/tray,/obj/item/weapon/weldingtool,
|
||||
/obj/item/weapon/wirecutters,/obj/item/weapon/wrench,/obj/item/weapon/extinguisher)
|
||||
|
||||
/datum/cargoprofile/finished
|
||||
name = "Completed Robots"
|
||||
id = "finished"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/mecha,/obj/machinery/bot,/mob/living/silicon/robot)
|
||||
mobcheck = 1
|
||||
//todo: detect and allow finished cyborg endoskeletons with no brain
|
||||
contains(var/atom/A)
|
||||
if(..())
|
||||
return 1
|
||||
if(istype(A,/mob))
|
||||
if(blacklist)
|
||||
for(var/T in blacklist)
|
||||
if(istype(A,T))
|
||||
return 0
|
||||
if(whitelist)
|
||||
for(var/T in whitelist)
|
||||
if(istype(A,T))
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/cargoprofile/stripping
|
||||
name = "Auto-Frisker"
|
||||
id = "frisk"
|
||||
blacklist = null
|
||||
whitelist = list(/mob/living/carbon/human)
|
||||
mobcheck = 1
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Overrides (Special Functions)
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/datum/cargoprofile/cargo/unload
|
||||
name = "Unload Cargo Boxes"
|
||||
id = "cargounload"
|
||||
enabled = 0
|
||||
dedicated_path = /obj/machinery/programmable/unloader
|
||||
|
||||
//override the detection to only accept crates with something in it.
|
||||
//if it doesn't, this object may be handled by another handler.
|
||||
contains(var/atom/A)
|
||||
if(..(A))
|
||||
if(istype(A,/obj/structure/closet))
|
||||
var/obj/structure/closet/C = A
|
||||
if(!C.can_open() && !C.opened && !master.emagged) // must be able to access the contents
|
||||
return 0
|
||||
if(A.contents.len)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//instead of moving the box, strip it of its contents
|
||||
inlet_reaction(var/obj/W,var/turf/S, var/remaining)
|
||||
//W should only be crate or ore box, although this will work on anything with contents...
|
||||
var/I = 0
|
||||
if(istype(W,/obj/structure/closet))
|
||||
var/obj/structure/closet/C = W
|
||||
if(!C.can_open() && !C.opened) // must be able to access the contents
|
||||
if(master.emagged && remaining >= BIG_OBJECT_WORK)
|
||||
if(prob(10))
|
||||
C.welded = 0
|
||||
if("broken" in C.vars)
|
||||
C:broken = 1
|
||||
C.open()
|
||||
C.update_icon()
|
||||
master.visible_message("\red [master] breaks open [C]!")
|
||||
else
|
||||
master.visible_message("\blue [master] is trying to force [C] open!")
|
||||
|
||||
master.sleep += 1 // mechanical strain
|
||||
return BIG_OBJECT_WORK
|
||||
master.visible_message("\blue [master] is trying to open [C], but can't!")
|
||||
master.sleep = 5
|
||||
return 0
|
||||
|
||||
for(var/obj/item/O in W.contents)
|
||||
if(I > remaining)
|
||||
return
|
||||
if(O.w_class > (remaining - I))
|
||||
continue
|
||||
O.loc = master
|
||||
master.types[O.type] = src
|
||||
if(O.w_class > 0)
|
||||
I += O.w_class
|
||||
else
|
||||
I++
|
||||
if(!W.contents.len && istype(W,/obj/structure/closet))
|
||||
var/obj/structure/closet/C = W
|
||||
C.open()
|
||||
return I
|
||||
|
||||
|
||||
//Inlet stacker: used when the output is a volatile space (conveyor or another unit's input).
|
||||
//Does not output a stack until it is full.
|
||||
/datum/cargoprofile/in_stacker
|
||||
name = "Hold and Stack"
|
||||
id = "instacker"
|
||||
universal = 1
|
||||
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/stack,/obj/item/weapon/cable_coil)
|
||||
|
||||
dedicated_path = /obj/machinery/programmable/stacker
|
||||
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
if(istype(W,/obj/item/stack))
|
||||
var/obj/item/stack/I = W
|
||||
if(!I.amount) // todo: am I making a bad assumption here?
|
||||
del I
|
||||
return
|
||||
for(var/obj/item/stack/O in master.contents)
|
||||
if(O.type == I.type && O.amount < O.max_amount)
|
||||
if(I.amount + O.amount <= O.max_amount)
|
||||
O.amount += I.amount
|
||||
del I
|
||||
return O.w_class
|
||||
var/leftover = I.amount + O.amount - O.max_amount
|
||||
O.amount = O.max_amount
|
||||
I.amount = leftover
|
||||
continue
|
||||
//end for
|
||||
I.loc = master
|
||||
master.types[I.type] = src
|
||||
return I.w_class
|
||||
if(istype(W,/obj/item/weapon/cable_coil))
|
||||
var/obj/item/weapon/cable_coil/I = W
|
||||
if(!I.amount) // todo: am I making a bad assumption here?
|
||||
del I
|
||||
return
|
||||
for(var/obj/item/weapon/cable_coil/O in master.contents)
|
||||
if(O.type == I.type && O.amount < MAXCOIL)
|
||||
if(I.amount + O.amount <= MAXCOIL)
|
||||
O.amount += I.amount
|
||||
del I
|
||||
return O.w_class
|
||||
var/leftover = I.amount + O.amount - MAXCOIL
|
||||
O.amount = MAXCOIL
|
||||
I.amount = leftover
|
||||
continue
|
||||
//end for
|
||||
I.loc = master
|
||||
master.types[I.type] = src
|
||||
return I.w_class
|
||||
|
||||
//If the stack isn't finished yet, don't eject it
|
||||
//unless this profile has been disabled.
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
if(istype(W,/obj/item/stack))
|
||||
var/obj/item/stack/I = W
|
||||
if(src.enabled && (I.amount < I.max_amount))
|
||||
return // Still needs to be stacked
|
||||
..(W,D)
|
||||
if(istype(W,/obj/item/weapon/cable_coil))
|
||||
var/obj/item/weapon/cable_coil/I = W
|
||||
if(src.enabled && (I.amount < MAXCOIL))
|
||||
return // Still needs to be stacked
|
||||
..(W,D)
|
||||
|
||||
//Outlet stacker: used when the output square can be trusted.
|
||||
//Outputs immediately, adding to stacks in the outlet.
|
||||
/datum/cargoprofile/unary/stacker
|
||||
name = "Stack Items"
|
||||
id = "ustacker"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/stack,/obj/item/weapon/cable_coil)
|
||||
|
||||
dedicated_path = /obj/machinery/programmable/unary/stacker
|
||||
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
|
||||
//Only pick it up if you are going to stack it
|
||||
|
||||
if(istype(W,/obj/item/stack))
|
||||
var/obj/item/stack/I = W
|
||||
if(I.amount >= I.max_amount)
|
||||
return 0
|
||||
for(var/obj/item/stack/other in S.contents)
|
||||
if(other.type == I.type && other != I && other.amount < other.max_amount)
|
||||
return ..(W,S,remaining)
|
||||
return 0
|
||||
|
||||
if(istype(W,/obj/item/weapon/cable_coil))
|
||||
var/obj/item/weapon/cable_coil/I = W
|
||||
if(I.amount >= MAXCOIL)
|
||||
return 0
|
||||
for(var/obj/item/weapon/cable_coil/other in S.contents)
|
||||
if(other != I && other.amount < MAXCOIL)
|
||||
return ..(W,S,remaining)
|
||||
return 0
|
||||
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
if(istype(W,/obj/item/stack))
|
||||
var/obj/item/stack/I = W
|
||||
for(var/obj/item/stack/O in D.contents)
|
||||
if(O.type == I.type && O.amount < O.max_amount)
|
||||
if(I.amount + O.amount <= O.max_amount)
|
||||
O.amount += I.amount
|
||||
del I
|
||||
return
|
||||
var/leftover = I.amount + O.amount - O.max_amount
|
||||
O.amount = O.max_amount
|
||||
I.amount = leftover
|
||||
continue
|
||||
//end for
|
||||
I.loc = D
|
||||
return
|
||||
if(istype(W,/obj/item/weapon/cable_coil))
|
||||
var/obj/item/weapon/cable_coil/I = W
|
||||
for(var/obj/item/weapon/cable_coil/O in D.contents)
|
||||
if(O.type == I.type && O.amount < MAXCOIL)
|
||||
if(I.amount + O.amount <= MAXCOIL) // Why did they make it a #define.
|
||||
O.amount += I.amount
|
||||
O.update_icon()
|
||||
del I
|
||||
return
|
||||
var/leftover = I.amount + O.amount - MAXCOIL // That wasn't a question
|
||||
O.amount = MAXCOIL // It was a complaint
|
||||
I.amount = leftover
|
||||
continue
|
||||
//end for
|
||||
I.loc = D
|
||||
return
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Dubious Overrides (For emag use)
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//Clogs up the unloader. And, there may be devious uses for it...
|
||||
/datum/cargoprofile/slow
|
||||
name = "Slow unloader"
|
||||
id = "slow"
|
||||
whitelist = list(/obj/item,/obj/structure/closet,/obj/structure/bigDelivery,/obj/machinery/portable_atmospherics)
|
||||
blacklist = list()
|
||||
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
if(..())
|
||||
return remaining
|
||||
|
||||
/datum/cargoprofile/unary/shredder
|
||||
name = "Paper Shredder"
|
||||
id = "shredder"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/weapon/paper,/obj/item/weapon/book,/obj/item/weapon/clipboard,/obj/item/weapon/folder,/obj/item/weapon/photo)
|
||||
universal = 1
|
||||
|
||||
dedicated_path = /obj/machinery/programmable/unary/shredder
|
||||
|
||||
|
||||
|
||||
proc/cliptags(var/Text)
|
||||
//Removes all html tags
|
||||
var/index
|
||||
var/index2
|
||||
index = findtextEx(Text,"<")
|
||||
while(index)
|
||||
index2 = findtextEx(Text,">",index)
|
||||
if(!index2)
|
||||
return copytext(Text,1,index)
|
||||
Text = "[copytext(Text,1,index)][copytext(Text,index2+1,0)]"
|
||||
index = findtextEx(Text,"<")
|
||||
//should have trimmed that text there pretty good
|
||||
return Text
|
||||
|
||||
|
||||
//Recurses through the text, removing large chunks
|
||||
proc/garbletext(var/Text)
|
||||
var/l = length(Text)
|
||||
if(l <= 3)
|
||||
if(prob(20))
|
||||
return pick("#","|","/","*",".","."," ","."," "," ")
|
||||
return Text
|
||||
if(prob(50))
|
||||
return "[garbletext(copytext(Text,1,l/2))][garbletext(copytext(Text,l/2,0))]"
|
||||
if(prob(50))
|
||||
return "[pick("#","|","/","*",".","."," ","."," "," ")][garbletext(copytext(Text,1,l/2))]"
|
||||
return "[garbletext(copytext(Text,l/2,0))][pick("#","|","/","*",".","."," ","."," "," ")]"
|
||||
|
||||
proc/garble_keeptags(var/Text)
|
||||
var/list/L = stringsplit(Text,">")
|
||||
var/result = ""
|
||||
for(var/string in L)
|
||||
var/index = findtextEx(string,"<")
|
||||
if(index!=1)
|
||||
result += "[garbletext(copytext(string,1,index))][copytext(string,index)]>"
|
||||
else
|
||||
result += "[string]>"
|
||||
return copytext(result,1,lentext(result))
|
||||
|
||||
|
||||
|
||||
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
if(istype(W,/obj/item/weapon/paper/crumpled))
|
||||
del W
|
||||
return
|
||||
if(istype(W,/obj/item/weapon/clipboard) || istype(W,/obj/item/weapon/folder))
|
||||
// destroy folder, various effects on contents
|
||||
for(var/obj/item/I in W.contents)
|
||||
if(prob(25))//JUNK IT
|
||||
del I
|
||||
else if(prob(50)) //We've been over this. I can't just take it apart with a crowbar.
|
||||
var/obj/item/weapon/paper/crumpled/P = new(master.loc)
|
||||
if(I.name)
|
||||
P.name = garbletext(I.name)
|
||||
if(prob(66))
|
||||
P.fingerprints = I.fingerprints
|
||||
P.fingerprintshidden = I.fingerprintshidden
|
||||
if(istype(I,/obj/item/weapon/paper))
|
||||
var/obj/item/weapon/paper/O = I
|
||||
P.info = garble_keeptags(O.info)
|
||||
del I
|
||||
..(P,D)
|
||||
else
|
||||
..(I,D) // Eject
|
||||
del W //destroy container
|
||||
return
|
||||
if(prob(50)) //JUNK IT NOW!
|
||||
var/obj/item/weapon/paper/crumpled/P = new(master.loc)
|
||||
P.name = W.name
|
||||
var/obj/item/I = W
|
||||
if(prob(66))
|
||||
P.fingerprints = I.fingerprints
|
||||
P.fingerprintshidden = I.fingerprintshidden
|
||||
if(istype(I,/obj/item/weapon/paper))
|
||||
var/obj/item/weapon/paper/O = I
|
||||
if(O.info)
|
||||
P.info = garble_keeptags(O.info)
|
||||
if(istype(I,/obj/item/weapon/book))
|
||||
var/obj/item/weapon/book/B = I
|
||||
if(B.dat)
|
||||
P.info = garble_keeptags(B.dat)
|
||||
if(B.carved && B.store)
|
||||
..(B.store,D)
|
||||
del W
|
||||
..(P,D)
|
||||
else //I want it junked
|
||||
del W
|
||||
return
|
||||
|
||||
/datum/cargoprofile/unary/gibber
|
||||
name = "human shredding"
|
||||
id = "flesh"
|
||||
whitelist = list(/mob/living/carbon,/mob/living/simple_animal)
|
||||
blacklist = null
|
||||
mobcheck = 1
|
||||
contains(var/atom/A)
|
||||
if(!istype(A,/mob))
|
||||
return
|
||||
if(blacklist)
|
||||
for(var/T in blacklist)
|
||||
if(istype(A,T))
|
||||
return 0
|
||||
if(whitelist)
|
||||
for(var/T in whitelist)
|
||||
if(istype(A,T))
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
var/mob/living/M = W
|
||||
if(istype(M) && (remaining > MOB_WORK))
|
||||
//this is necessarily damaging
|
||||
var/damage = rand(1,5)
|
||||
M << "\red <B>The unloading machine grabs you with a hard metallic claw!</B>"
|
||||
if(M.client)
|
||||
M.client.eye = master
|
||||
M.client.perspective = EYE_PERSPECTIVE
|
||||
M.loc = master
|
||||
master.types[M.type] = src
|
||||
M.apply_damage(damage) // todo: ugly
|
||||
M.visible_message("\red [M.name] gets pulled into the machine!")
|
||||
return MOB_WORK
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
var/mob/living/M = W
|
||||
var/bruteloss = M.bruteloss
|
||||
if(istype(M,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/C = M
|
||||
for(var/datum/organ/external/L in C.organs)
|
||||
bruteloss += L.brute_dam
|
||||
if(bruteloss < 100) // requires tenderization
|
||||
M.apply_damage(rand(5,15),BRUTE)
|
||||
M << "The machine is tearing you apart!"
|
||||
master.visible_message("\red [master] makes a squishy grinding noise.")
|
||||
return
|
||||
M.loc = master.loc
|
||||
M.gib()
|
||||
return
|
||||
|
||||
|
||||
/datum/cargoprofile/people
|
||||
name = "Manhandling"
|
||||
id = "people"
|
||||
|
||||
whitelist = null
|
||||
blacklist = list(/mob/camera,/mob/new_player,/mob/living/simple_animal/hostile/blobspore,/mob/living/simple_animal/hostile/creature,
|
||||
/mob/living/simple_animal/space_worm,/mob/living/simple_animal/shade,/mob/living/simple_animal/hostile/faithless,/mob/dead)
|
||||
universal = 1
|
||||
mobcheck = 1
|
||||
|
||||
|
||||
contains(var/atom/A)
|
||||
if(!istype(A,/mob))
|
||||
return
|
||||
if(blacklist)
|
||||
for(var/T in blacklist)
|
||||
if(istype(A,T))
|
||||
return 0
|
||||
if(whitelist)
|
||||
for(var/T in whitelist)
|
||||
if(istype(A,T))
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
var/mob/living/M = W
|
||||
if(remaining > MOB_WORK)
|
||||
//this is necessarily damaging
|
||||
var/damage = rand(1,5)
|
||||
M << "\red <B>The unloading machine grabs you with a hard metallic claw!</B>"
|
||||
if(M.client)
|
||||
M.client.eye = master
|
||||
M.client.perspective = EYE_PERSPECTIVE
|
||||
M.loc = master
|
||||
master.types[M.type] = src
|
||||
M.apply_damage(damage) // todo: ugly
|
||||
M.visible_message("\red [M.name] gets pulled into the machine!")
|
||||
return MOB_WORK
|
||||
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
var/mob/living/M = W
|
||||
M.loc = master.loc
|
||||
M.dir = master.outdir
|
||||
if(M.client)
|
||||
M.client.eye = M.client.mob
|
||||
M.client.perspective = MOB_PERSPECTIVE
|
||||
|
||||
D = get_step(D,master.outdir) // throw attempt
|
||||
eject_speed = rand(0,4)
|
||||
|
||||
M.visible_message("\blue [M.name] is ejected from the unloader.")
|
||||
M.throw_at(D,eject_speed,eject_speed)
|
||||
return
|
||||
|
||||
/datum/cargoprofile/unary/trainer
|
||||
name = "Boxing Trainer"
|
||||
id = "trainer"
|
||||
blacklist = list()
|
||||
whitelist = list(/mob/living/carbon/human)
|
||||
mobcheck = 1
|
||||
|
||||
var/const/PUNCH_WORK = 6
|
||||
|
||||
dedicated_path = /obj/machinery/programmable/unary/trainer
|
||||
|
||||
contains(var/atom/A)
|
||||
if(!istype(A,/mob))
|
||||
return 0
|
||||
if(blacklist)
|
||||
for(var/T in blacklist)
|
||||
if(istype(A,T))
|
||||
return 0
|
||||
if(whitelist)
|
||||
for(var/T in whitelist)
|
||||
if(istype(A,T))
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
|
||||
proc/punch(var/mob/living/carbon/human/M,var/maxpunches)
|
||||
//stolen from holographic boxing gloves code
|
||||
//This should probably be done BY the mob, however, the attack code will be expecting a source mob.
|
||||
|
||||
var/damage
|
||||
if(prob(75))
|
||||
damage = rand(0, 6) // pap
|
||||
else
|
||||
damage = rand(0, 12) // thwack
|
||||
|
||||
if(!damage)
|
||||
playsound(master.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
|
||||
master.visible_message("\red \The [src] punched at [M], but whiffed!")
|
||||
|
||||
if(maxpunches > 1 && prob(50)) // Follow through on a miss, 50% chance
|
||||
return punch(M,maxpunches - 1) + 1
|
||||
return 1
|
||||
var/datum/organ/external/affecting = M.get_organ(ran_zone("chest",50))
|
||||
var/armor_block = M.run_armor_check(affecting, "melee")
|
||||
|
||||
playsound(master.loc, "punch", 25, 1, -1)
|
||||
master.visible_message("\red <B>\The [src] has punched [M]!</B>")
|
||||
if(!master.emagged)
|
||||
M.apply_damage(damage, HALLOSS, affecting, armor_block) // Clean fight
|
||||
else
|
||||
M.apply_damage(damage, BRUTE, affecting, armor_block) // Foul! Foooul!
|
||||
|
||||
if(damage >= 9)
|
||||
master.visible_message("\red <B>\The [src] has weakened [M]!</B>")
|
||||
M.apply_effect(4, WEAKEN, armor_block)
|
||||
if(!master.emagged)
|
||||
master.sleep = 1
|
||||
return maxpunches // The machine is not so sophisticated as to not gloat
|
||||
else
|
||||
if(prob(25)) // Follow through on a hit, 25% chance. Pause after.
|
||||
return punch(M,maxpunches-1) + 1
|
||||
return 1
|
||||
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
//stolen from boxing gloves code
|
||||
var/mob/living/carbon/human/M = W
|
||||
if((M.lying || (M.health - M.halloss < 25))&& !master.emagged)
|
||||
M << "\The [src] gives you a break."
|
||||
master.sleep+=5
|
||||
return 0 // Be polite
|
||||
var/punches = punch(M,remaining / PUNCH_WORK)
|
||||
if(punches>1)master.sleep++
|
||||
return punches * PUNCH_WORK
|
||||
745
code/WorkInProgress/Sayu/programmable.dm
Normal file
745
code/WorkInProgress/Sayu/programmable.dm
Normal file
@@ -0,0 +1,745 @@
|
||||
|
||||
// TODO: Check access
|
||||
// TODO: Renameable circuit boards
|
||||
// TODO: Disks? Disassembly?
|
||||
|
||||
/obj/machinery/programmable
|
||||
name = "Programmable Unloader"
|
||||
icon = 'icons/obj/machines/mining_machines.dmi'
|
||||
icon_state = "unloader"
|
||||
density = 1
|
||||
anchored = 1.0
|
||||
|
||||
var/debug = 0 // When set, this WILL spam people around the machine.
|
||||
// Identifies profile used and on which item.
|
||||
|
||||
var/on = 1
|
||||
var/indir = 8
|
||||
var/outdir = 4
|
||||
var/turf/input = null
|
||||
var/turf/output = null
|
||||
var/typename = "Unloader"
|
||||
var/ident = "#1"
|
||||
|
||||
var/const/workmax = 20
|
||||
var/datum/cargoprofile/default = new()
|
||||
var/list/profiles = list(new/datum/cargoprofile/cargo(),new/datum/cargoprofile/boxes(),new/datum/cargoprofile/supplies(),
|
||||
new/datum/cargoprofile/exotics(),new/datum/cargoprofile/tools(),new/datum/cargoprofile/weapons(),
|
||||
new/datum/cargoprofile/pressure(),new/datum/cargoprofile/chemical(),
|
||||
new/datum/cargoprofile/food(),new/datum/cargoprofile/clothing(),new/datum/cargoprofile/trash())
|
||||
var/list/overrides = list(new/datum/cargoprofile/cargo/unload(),new/datum/cargoprofile/in_stacker())
|
||||
var/list/emag_overrides = list(new/datum/cargoprofile/people(),new/datum/cargoprofile/unary/shredder(),new/datum/cargoprofile/unary/trainer())
|
||||
var/list/types = list()
|
||||
|
||||
anchored = 1
|
||||
var/unwrenched = 0
|
||||
use_power = 1
|
||||
var/sleep = 0 // When set, the machine will skip the next however-many updates (to avoid spam)
|
||||
var/open = 0
|
||||
var/circuit_removed = 0
|
||||
|
||||
|
||||
|
||||
/obj/machinery/programmable/New()
|
||||
..()
|
||||
if(default)
|
||||
default.master = src
|
||||
if(!default.enabled)
|
||||
default.enabled = 1
|
||||
for(var/datum/cargoprofile/p in emag_overrides + overrides + profiles)
|
||||
p.master = src
|
||||
input = get_step(src.loc,indir)
|
||||
output = get_step(src.loc,outdir)
|
||||
var/count = 0
|
||||
for(var/obj/machinery/programmable/other in world)
|
||||
if(other.typename == typename)
|
||||
count++
|
||||
ident = "#[count]"
|
||||
name = "[typename] [ident]"
|
||||
|
||||
/obj/machinery/programmable/RefreshParts()
|
||||
//This is called when the machine was constructed.
|
||||
//Unfortunately, it puts machine parts in our contents list, which we're using.
|
||||
//Fortunately, we aren't likely to ever need the components list, circuitboard excepted.
|
||||
|
||||
for(var/obj/O in contents)
|
||||
if(istype(O,/obj/item/weapon/circuitboard/programmable))//retrieve settings here
|
||||
|
||||
var/obj/item/weapon/circuitboard/programmable/C = O
|
||||
|
||||
default = C.default
|
||||
emagged = C.emagged
|
||||
profiles = C.profiles
|
||||
overrides = C.overrides
|
||||
emag_overrides = C.emag_overrides
|
||||
|
||||
//unary and binary methods (one vs two locales) don't mix
|
||||
|
||||
if(istype(src,/obj/machinery/programmable/unary))
|
||||
for(var/datum/cargoprofile/P in profiles)
|
||||
if(!istype(P,/datum/cargoprofile/unary) && !P.universal)
|
||||
profiles -= P
|
||||
for(var/datum/cargoprofile/P in overrides)
|
||||
if(!istype(P,/datum/cargoprofile/unary) && !P.universal)
|
||||
overrides -= P
|
||||
for(var/datum/cargoprofile/P in emag_overrides)
|
||||
if(!istype(P,/datum/cargoprofile/unary) && !P.universal)
|
||||
emag_overrides -= P
|
||||
else
|
||||
for(var/datum/cargoprofile/P in profiles)
|
||||
if(istype(P,/datum/cargoprofile/unary) && !P.universal)
|
||||
profiles -= P
|
||||
for(var/datum/cargoprofile/P in overrides)
|
||||
if(istype(P,/datum/cargoprofile/unary) && !P.universal)
|
||||
overrides -= P
|
||||
for(var/datum/cargoprofile/P in emag_overrides)
|
||||
if(istype(P,/datum/cargoprofile/unary) && !P.universal)
|
||||
emag_overrides -= P
|
||||
if(default)
|
||||
default.master = src
|
||||
for(var/datum/cargoprofile/p in emag_overrides + overrides + profiles)
|
||||
p.master = src
|
||||
|
||||
del C
|
||||
else
|
||||
del O
|
||||
|
||||
/obj/machinery/programmable/attack_hand(mob/user as mob)
|
||||
if(stat) // moved, or something else
|
||||
return
|
||||
usr.set_machine(src)
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/programmable/proc/printlist(var/list/L)
|
||||
var/dat
|
||||
for(var/datum/cargoprofile/p in L)
|
||||
dat += "[p.name]: <A href='?src=\ref[src];operation=[p.id]'>[p.enabled?"<B>YES</B>":"NO"]</A><BR>"
|
||||
return dat
|
||||
|
||||
/obj/machinery/programmable/proc/buildMenu()
|
||||
var/dat
|
||||
dat += "<B>PROGRAMMABLE UNLOADER</B><BR><TT>"
|
||||
dat += "POWER: <A href='?src=\ref[src];operation=start'>[on ? "ON" : "OFF"]</A><BR>"
|
||||
dat += "INLET: <A href='?src=\ref[src];operation=inlet'>[capitalize(dir2text(indir))]</A> "
|
||||
dat += "OUTLET: <A href='?src=\ref[src];operation=outlet'>[capitalize(dir2text(outdir))]</A>"
|
||||
dat += " (<A href='?src=\ref[src];operation=swapdir'>SWAP</A>)</TT><HR>"
|
||||
if(default)
|
||||
dat += "MAIN PROGRAM: "
|
||||
dat += "<TT>[default.name]: <A href='?src=\ref[src];operation=default'>[default.enabled ? "<B>YES</B>" : "NO"]</A><BR>"
|
||||
if(profiles.len)
|
||||
if(!default || !default.enabled)
|
||||
dat += printlist(profiles)
|
||||
dat += "</TT>"
|
||||
if(overrides.len)
|
||||
dat += "<HR>OVERRIDES:<BR><TT>"
|
||||
dat += printlist(overrides)
|
||||
dat += "</TT>"
|
||||
return dat
|
||||
|
||||
/obj/machinery/programmable/interact(mob/user as mob)
|
||||
var/dat = buildMenu()
|
||||
user << browse("<HEAD><TITLE>Unloader</TITLE></HEAD>[dat]", "window=progreload")
|
||||
onclose(user, "progreload")
|
||||
return
|
||||
|
||||
/obj/machinery/programmable/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
add_fingerprint(usr)
|
||||
switch(href_list["operation"])
|
||||
if("start")
|
||||
on = (on ? 0 : 1)
|
||||
if(on) use_power = 1
|
||||
else use_power = 0
|
||||
updateUsrDialog()
|
||||
return
|
||||
if("inlet")
|
||||
indir *= 2 // N S E W
|
||||
if(indir > 8)
|
||||
indir = 1 // W N
|
||||
if(indir == src.outdir)
|
||||
indir *= 2
|
||||
if(indir > 8)
|
||||
indir = 1
|
||||
input = get_step(src,indir) // todo: check for glasswalls / no path to target?
|
||||
updateUsrDialog()
|
||||
return
|
||||
if("outlet")
|
||||
outdir *= 2
|
||||
if(outdir > 8)
|
||||
outdir = 1
|
||||
if(outdir == indir)
|
||||
outdir *= 2
|
||||
if(outdir > 8)
|
||||
outdir = 1
|
||||
output = get_step(src,outdir) // todo: check for walls / glasswalls / invalid output locations
|
||||
updateUsrDialog()
|
||||
return
|
||||
if("swapdir")
|
||||
var/temp = outdir
|
||||
outdir = indir
|
||||
indir = temp
|
||||
input = get_step(src,indir)
|
||||
output = get_step(src,outdir)
|
||||
updateUsrDialog()
|
||||
return
|
||||
if("default")
|
||||
default.enabled = (default.enabled ? 0 : 1)
|
||||
updateUsrDialog()
|
||||
return
|
||||
var/which = href_list["operation"]
|
||||
for(var/datum/cargoprofile/p in overrides + profiles)
|
||||
if(which == p.id)
|
||||
p.enabled = (p.enabled? 0 : 1)
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/programmable/attackby(obj/item/I as obj, mob/user as mob)
|
||||
if(istype(I,/obj/item/weapon/card/emag))
|
||||
if(emagged)
|
||||
return
|
||||
user << "You swipe the unloader with your card. After a moment's grinding, it beeps in a sinister fashion."
|
||||
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
|
||||
emagged = 1
|
||||
overrides += emag_overrides
|
||||
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(2, 1, src)
|
||||
s.start()
|
||||
|
||||
return
|
||||
if(istype(I,/obj/item/weapon/wrench)) // code borrowed from pipe dispenser
|
||||
if (unwrenched==0)
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "\blue You begin to unfasten \the [src] from the floor..."
|
||||
if (do_after(user, 40))
|
||||
user.visible_message( \
|
||||
"[user] unfastens \the [src].", \
|
||||
"\blue You have unfastened \the [src]. Now it can be pulled somewhere else.", \
|
||||
"You hear ratchet.")
|
||||
src.anchored = 0
|
||||
src.stat |= MAINT
|
||||
src.unwrenched = 1
|
||||
if (usr.machine==src)
|
||||
usr << browse(null, "window=pipedispenser")
|
||||
else /* unwrenched */
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "\blue You begin to fasten \the [src] to the floor..."
|
||||
if (do_after(user, 20))
|
||||
user.visible_message( \
|
||||
"[user] fastens \the [src].", \
|
||||
"\blue You fastened \the [src] into place.", \
|
||||
"You hear ratchet.")
|
||||
src.anchored = 1
|
||||
src.input = get_step(src.loc,src.indir)
|
||||
src.output = get_step(src.loc,src.outdir)
|
||||
if(!open && !circuit_removed)
|
||||
src.stat &= ~MAINT
|
||||
src.unwrenched = 0
|
||||
power_change()
|
||||
if(istype(I,/obj/item/weapon/screwdriver))
|
||||
if(open)
|
||||
open = 0
|
||||
if(!unwrenched && !circuit_removed)
|
||||
src.stat &= ~MAINT
|
||||
user << "You open the [src]'s maintenance panel."
|
||||
else
|
||||
open = 1
|
||||
src.stat |= MAINT
|
||||
user << "You close the [src]'s maintenance panel."
|
||||
if(istype(I,/obj/item/weapon/crowbar))
|
||||
if(open)
|
||||
user << "\blue You begin to pry out the [src]'s circuits."
|
||||
if(do_after(user,40))
|
||||
user << "\blue You remove the circuitboard."
|
||||
circuit_removed = 1
|
||||
use_power = 0
|
||||
on = 0
|
||||
|
||||
var/obj/item/weapon/circuitboard/programmable/P = new(src.loc)
|
||||
P.emagged = src.emagged
|
||||
P.default = src.default
|
||||
src.default = null
|
||||
P.profiles = src.profiles
|
||||
src.profiles = null
|
||||
P.overrides = src.overrides
|
||||
src.overrides = null
|
||||
P.emag_overrides = src.emag_overrides
|
||||
src.emag_overrides = null
|
||||
return
|
||||
else
|
||||
..(I,user)
|
||||
if(istype(I,/obj/item/weapon/circuitboard/programmable))
|
||||
if(!open)
|
||||
user << "You have to open the machine first!"
|
||||
return
|
||||
if(!circuit_removed)
|
||||
user << "There is already a circuitboard present!"
|
||||
return
|
||||
circuit_removed = 0
|
||||
I.loc = src
|
||||
RefreshParts()
|
||||
|
||||
|
||||
|
||||
/obj/machinery/programmable/process()
|
||||
if (!output || !input)
|
||||
return
|
||||
|
||||
if(!on || stat || sleep)
|
||||
if(sleep > 0) // prevent input or output errors from happening every tick
|
||||
sleep--
|
||||
use_power = 0
|
||||
|
||||
//Do not let things get stuck inside. That's broken behavior.
|
||||
for(var/obj/O in contents)
|
||||
O.loc = loc
|
||||
for(var/mob/M in contents)
|
||||
M.loc = loc
|
||||
if(M.client)
|
||||
M.client.eye = M.client.mob
|
||||
M.client.perspective = MOB_PERSPECTIVE
|
||||
M << "\blue The machine turns off, and you fall out."
|
||||
|
||||
return
|
||||
|
||||
//Normal output reaction
|
||||
if(contents.len)
|
||||
for(var/atom/movable/A in contents)
|
||||
var/datum/cargoprofile/p = types[A.type]
|
||||
if(p)
|
||||
p.outlet_reaction(A,output)
|
||||
else
|
||||
A.loc = output // may have been dropped by a mob, etc
|
||||
|
||||
if(types.len > 50)
|
||||
types = list() // good luck mr. garbage collector
|
||||
|
||||
|
||||
var/work = 0
|
||||
for(var/mob/M in input.contents)
|
||||
for(var/datum/cargoprofile/p in overrides + default)
|
||||
if(p.enabled && p.mobcheck && p.contains(M))
|
||||
var/done = p.inlet_reaction(M,input,workmax - work)
|
||||
if(done)
|
||||
work += done
|
||||
if(src.debug)
|
||||
visible_message("[p.name]:[M.name] ([done])")
|
||||
break
|
||||
|
||||
if(sleep)
|
||||
return // something stopped the machine
|
||||
|
||||
for (var/obj/A in input.contents)// I fully expect this to cause unreasonable lag
|
||||
if(!A)
|
||||
break
|
||||
if(work > workmax)
|
||||
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) // Beep if the machine is full - testing only probably
|
||||
break
|
||||
|
||||
var/done = 0 // work done - testing only
|
||||
var/aname // target item name - testing only
|
||||
|
||||
for(var/datum/cargoprofile/p in overrides)
|
||||
if(p.enabled && p.contains(A))
|
||||
aname = A.name // in case of deletion
|
||||
done = p.inlet_reaction(A,input,workmax - work)
|
||||
if(done)
|
||||
work += done
|
||||
if(src.debug)
|
||||
visible_message("[p.name]:[aname] ([done])")
|
||||
|
||||
else
|
||||
break
|
||||
if(sleep)
|
||||
break // Something stopped the machine
|
||||
if(!A || A.loc != input || done)
|
||||
continue // next item
|
||||
|
||||
if(default && default.enabled)
|
||||
if(default.contains(A))
|
||||
aname = A.name
|
||||
done = default.inlet_reaction(A,input,workmax - work)
|
||||
if(done)
|
||||
work += done
|
||||
if(src.debug)
|
||||
visible_message("[default.name]: [aname] ([done])")
|
||||
continue
|
||||
for(var/datum/cargoprofile/p in profiles)
|
||||
if(p.enabled && p.contains(A))
|
||||
aname = A.name
|
||||
done = p.inlet_reaction(A,input,workmax - work)
|
||||
if(done)
|
||||
work += done
|
||||
if(src.debug)
|
||||
visible_message("[p.name]:[aname] ([done])")
|
||||
else
|
||||
break
|
||||
if(work)
|
||||
use_power = 2
|
||||
else
|
||||
use_power = 1
|
||||
//----------------------------------------------------------------------------
|
||||
// Specialty machines
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//Uses the inlet stacking profile. Ejects only full stacks.
|
||||
/obj/machinery/programmable/stacker
|
||||
name = "Stacking & Spooling Machine"
|
||||
default = new/datum/cargoprofile/in_stacker()
|
||||
profiles = list()
|
||||
overrides = list()
|
||||
emag_overrides = list()
|
||||
typename = "Stacking and Spooling Machine"
|
||||
|
||||
|
||||
/obj/machinery/programmable/unloader
|
||||
name = "Cargo Unloader"
|
||||
default = new/datum/cargoprofile/cargo/unload()
|
||||
profiles = list()
|
||||
overrides = list()
|
||||
emag_overrides = list()
|
||||
typename = "Cargo Unloader"
|
||||
|
||||
/obj/machinery/programmable/delivery
|
||||
name = "Finished robot delivery"
|
||||
default = new/datum/cargoprofile/finished()
|
||||
profiles = list()
|
||||
overrides = list()
|
||||
emag_overrides = list()
|
||||
typename = "Robot Delivery"
|
||||
|
||||
/obj/machinery/programmable/crate_handler
|
||||
name = "Crate Handler"
|
||||
default = null
|
||||
profiles = list(new/datum/cargoprofile/cargo/unload(),new/datum/cargoprofile/cargo(),new/datum/cargoprofile/cargo/empty(),new/datum/cargoprofile/cargo/full())
|
||||
overrides = list()
|
||||
emag_overrides = list()
|
||||
typename = "Crate Handler"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Unary machine: Input and output in the same location
|
||||
// Be careful with this, it could easily be running the same
|
||||
// computations every round needlessly
|
||||
//----------------------------------------------------------------------------
|
||||
/obj/machinery/programmable/unary
|
||||
name = "Programmable Processor"
|
||||
default = null
|
||||
profiles = list()
|
||||
overrides = list(new/datum/cargoprofile/unary/stacker(),new/datum/cargoprofile/unary/trainer())
|
||||
emag_overrides = list(new/datum/cargoprofile/unary/shredder())
|
||||
indir = 1
|
||||
outdir = 1
|
||||
typename = "Processor"
|
||||
|
||||
New()
|
||||
..()
|
||||
outdir = indir
|
||||
output = input
|
||||
buildMenu()
|
||||
var/dat
|
||||
dat += "<B>PROGRAMMABLE PROCESSOR</B><BR><TT>"
|
||||
dat += "POWER: <A href='?src=\ref[src];operation=start'>[on ? "ON" : "OFF"]</A><BR>"
|
||||
dat += "INLET: <A href='?src=\ref[src];operation=inlet'>[capitalize(dir2text(indir))]</A><BR>"
|
||||
if(default)
|
||||
dat += "MAIN PROGRAM: "
|
||||
dat += "<TT>[default.name]: <A href='?src=\ref[src];operation=default'>[default.enabled ? "<B>YES</B>" : "NO"]</A><BR>"
|
||||
if(profiles.len)
|
||||
if(!default || !default.enabled)
|
||||
dat += printlist(profiles)
|
||||
dat += "</TT>"
|
||||
if(overrides.len)
|
||||
dat += "<HR>OVERRIDES:<BR><TT>"
|
||||
dat += printlist(overrides)
|
||||
dat += "</TT>"
|
||||
return dat
|
||||
Topic(href, href_list)
|
||||
switch(href_list["operation"])
|
||||
if("inlet")
|
||||
indir *= 2 // N S E W
|
||||
if(indir > 8)
|
||||
indir = 1 // W N
|
||||
outdir = indir
|
||||
input = get_step(src,indir) // todo: check for glasswalls / no path to target?
|
||||
output = input
|
||||
updateUsrDialog()
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/programmable/unary/stacker
|
||||
name = "Stacking Machine"
|
||||
default = new/datum/cargoprofile/unary/stacker()
|
||||
profiles = list()
|
||||
overrides = list()
|
||||
emag_overrides = list()
|
||||
typename = "Stacking Machine"
|
||||
|
||||
/obj/machinery/programmable/unary/shredder
|
||||
name = "Paper Shredder"
|
||||
default = new/datum/cargoprofile/unary/shredder()
|
||||
profiles = list()
|
||||
overrides = list()
|
||||
emag_overrides = list(new/datum/cargoprofile/unary/gibber())
|
||||
typename = "Paper Shredder"
|
||||
|
||||
/obj/machinery/programmable/unary/trainer
|
||||
name = "\improper Boxing Trainer"
|
||||
default = new/datum/cargoprofile/unary/trainer()
|
||||
profiles = list()
|
||||
overrides = list()
|
||||
emag_overrides = list()
|
||||
typename = "Boxing Trainer"
|
||||
|
||||
attack_hand(mob/user as mob) //How did I type this with boxing gloves on?
|
||||
if(!istype(user,/mob/living/carbon/human))
|
||||
return ..()
|
||||
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.gloves && istype(H.gloves, /obj/item/clothing/gloves/boxing))
|
||||
var/newsleep = 0
|
||||
if(H.loc != input)
|
||||
H << "The boxing machine refuses to acknowledge you unless you face it head on!"
|
||||
return
|
||||
var/damage = 0
|
||||
if(H.a_intent != "hurt")
|
||||
damage += rand(0,5)
|
||||
else
|
||||
damage += rand(0,10)
|
||||
if(!damage)
|
||||
playsound(H.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
|
||||
visible_message("[H] tries to punch \the [src], but whiffs")
|
||||
return
|
||||
|
||||
playsound(loc, "punch", 25, 1, -1)
|
||||
if(HULK in H.mutations) damage += 5
|
||||
|
||||
if(damage < 5)
|
||||
visible_message("[H] gives \the [src] a weak punch.")
|
||||
if(prob(10))
|
||||
visible_message("\blue \The [src] feints at [H], as though mocking \him.")
|
||||
else if(damage < 10)
|
||||
visible_message("[H] hits \the [src] with a solid [pick("punch","jab","smack")].")
|
||||
else if(damage < 15)
|
||||
visible_message("[pick("Whoa!","Nice!","Gasp!")] [H] hits [src] with a powerful [pick("punch","jab","uppercut","left hook", "right hook")].")
|
||||
else if(damage < 20)
|
||||
visible_message("[pick("WHOA!","ACK!","Jeez!")] [H] hits [src] so hard, the whole machine rocks band and forth for a moment.")
|
||||
else
|
||||
visible_message("Holy moly! [H] hits \the [src] so hard it stops working.")
|
||||
stat |= BROKEN
|
||||
return
|
||||
while(damage >= 5)
|
||||
if(prob(50))
|
||||
newsleep++
|
||||
damage -= 5
|
||||
if(newsleep)
|
||||
if(emagged)
|
||||
visible_message("\red \The [src]'s lights glow a bloodthirsty red. It refuses to stop!")
|
||||
sleep = 0
|
||||
else
|
||||
sleep += newsleep
|
||||
visible_message("\blue \The [src]'s lights dim for a moment and it beeps, signifying a valid hit.")
|
||||
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
|
||||
return
|
||||
|
||||
else
|
||||
return ..()
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// For construction
|
||||
//----------------------------------------------------------------------------
|
||||
/obj/item/weapon/circuitboard/programmable
|
||||
name = "Circuit board (Programmable Unloader)"
|
||||
build_path = "/obj/machinery/programmable"
|
||||
board_type = "machine"
|
||||
origin_tech = "engineering=3;programming=6"
|
||||
frame_desc = "Requires 2 Manipulators, 1 Scanning Module, 1 Cable."
|
||||
req_components = list(
|
||||
"/obj/item/weapon/stock_parts/scanning_module" = 1,
|
||||
"/obj/item/weapon/stock_parts/manipulator" = 2,
|
||||
"/obj/item/weapon/cable_coil" = 1)
|
||||
|
||||
//Customization of the machine
|
||||
var/datum/cargoprofile/default = new/datum/cargoprofile()
|
||||
var/list/profiles = list()
|
||||
var/list/overrides = list()
|
||||
var/list/emag_overrides = list()
|
||||
|
||||
var/emagged = 0
|
||||
var/hacking = 0
|
||||
|
||||
proc/resetlists()
|
||||
profiles = list(new/datum/cargoprofile/cargo(),new/datum/cargoprofile/boxes(),new/datum/cargoprofile/supplies(),
|
||||
new/datum/cargoprofile/exotics(),new/datum/cargoprofile/tools(),new/datum/cargoprofile/weapons(),new/datum/cargoprofile/finished(),
|
||||
new/datum/cargoprofile/pressure(),new/datum/cargoprofile/pressure/full(),new/datum/cargoprofile/pressure/empty(),
|
||||
new/datum/cargoprofile/chemical(),new/datum/cargoprofile/organics(),new/datum/cargoprofile/food(),
|
||||
new/datum/cargoprofile/clothing(),new/datum/cargoprofile/trash())
|
||||
overrides = list(new/datum/cargoprofile/cargo/unload(),new/datum/cargoprofile/in_stacker(),
|
||||
new/datum/cargoprofile/unary/stacker(),new/datum/cargoprofile/unary/trainer())
|
||||
emag_overrides = list(new/datum/cargoprofile/people(),new/datum/cargoprofile/unary/shredder())
|
||||
|
||||
New()
|
||||
..()
|
||||
resetlists()
|
||||
|
||||
attackby(obj/item/I as obj, mob/user as mob)
|
||||
if(istype(I,/obj/item/device/multitool))
|
||||
hacking = (hacking?0:1)
|
||||
if(hacking)
|
||||
user << "You unlock the data port on the board. You can now use a PDA to alter its data."
|
||||
else
|
||||
user << "You relock the data port."
|
||||
if(istype(I,/obj/item/device/pda))
|
||||
if(!hacking)
|
||||
user << "It looks like you can't access the board's data port. You'll have to open it with a multitool."
|
||||
else
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
if(istype(I,/obj/item/weapon/card/emag) && !emagged)
|
||||
if(!hacking)
|
||||
user << "There seems to be a data port on the card, but it's locked. A multitool could open it."
|
||||
else
|
||||
emagged = 1
|
||||
overrides += emag_overrides
|
||||
user << "You swipe the card in the card's data port. The lights flicker, then flash once."
|
||||
|
||||
proc/format(var/datum/cargoprofile/P,var/level)
|
||||
// PROFILE=0 OVERRIDE=1 MAIN=2
|
||||
if(P == null)
|
||||
return "NONE<BR>"
|
||||
var/dat = "[P.name]"
|
||||
if(level == 0 || (level == 1 && !default))
|
||||
dat += " <A href='?src=\ref[src];operation=promote;id=[P.id];level=[level]'>PROMOTE</A>"
|
||||
if(level > 0)
|
||||
dat += " <A href='?src=\ref[src];operation=demote;id=[P.id];level=[level]'>DEMOTE</A>"
|
||||
dat += " <A href='?src=\ref[src];operation=delete;id=[P.id];level=[level]'>REMOVE</A>"
|
||||
dat += "<BR>"
|
||||
return dat
|
||||
|
||||
interact(mob/user as mob)
|
||||
var/dat
|
||||
dat = "MAIN FUNCTION<BR><TT>"
|
||||
dat += format(default,2)
|
||||
dat += "</TT>- CAUTION -<BR>\[<A href='?src=\ref[src];operation=deleteall'>DELETE NON-MAIN ALGORITHMS</A>\]<BR>"
|
||||
dat += "\[<A href='?src=\ref[src];operation=reset'>MASTER RESET</A>\]<HR>"
|
||||
|
||||
dat += "OVERRIDES:<BR><TT>"
|
||||
for(var/datum/cargoprofile/P in overrides)
|
||||
dat += format(P,1)
|
||||
dat += "</TT><BR>"
|
||||
dat += "- CAUTION -<BR>\[<A href='?src=\ref[src];operation=deleteoverrides'>DELETE ALL OVERRIDES</A>\]<HR>"
|
||||
|
||||
dat += "</TT> TERTIARY PROFILES:<BR><TT>"
|
||||
for(var/datum/cargoprofile/P in profiles)
|
||||
dat += format(P,0)
|
||||
dat += "</TT><BR>"
|
||||
dat += "- CAUTION -<BR>\[<A href='?src=\ref[src];operation=deleteprofiles'>DELETE TERTIARY PROFILES</A>\]"
|
||||
|
||||
user << browse("<HEAD><TITLE>Circuit Reprogramming</TITLE></HEAD>[dat]", "window=progcircuit")
|
||||
onclose(user, "progcircuit")
|
||||
|
||||
Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
var/id = href_list["id"]
|
||||
var/level = text2num(href_list["level"])
|
||||
switch(href_list["operation"])
|
||||
if("promote")
|
||||
if(level == 0)
|
||||
for(var/datum/cargoprofile/T in profiles)
|
||||
if(T.id == id)
|
||||
overrides += T
|
||||
profiles -= T
|
||||
//updateUsrDialog()
|
||||
interact(usr)
|
||||
return
|
||||
|
||||
if(level == 1)
|
||||
if(default) return
|
||||
for(var/datum/cargoprofile/T in overrides)
|
||||
if(T.id == id)
|
||||
default = T
|
||||
overrides -= T
|
||||
|
||||
if(default.dedicated_path)
|
||||
build_path = "[default.dedicated_path]"
|
||||
else
|
||||
if(istype(default,/datum/cargoprofile/unary))
|
||||
build_path = "/obj/machinery/programmable/unary"
|
||||
else
|
||||
build_path = "/obj/machinery/programmable"
|
||||
|
||||
//updateUsrDialog()
|
||||
interact(usr)
|
||||
return
|
||||
|
||||
if("demote")
|
||||
if(level == 2)
|
||||
overrides += default
|
||||
default = null
|
||||
//updateUsrDialog()
|
||||
interact(usr)
|
||||
return
|
||||
if(level == 1)
|
||||
for(var/datum/cargoprofile/T in overrides)
|
||||
if(T.id == id)
|
||||
profiles += T
|
||||
overrides -= T
|
||||
//updateUsrDialog()
|
||||
interact(usr)
|
||||
return
|
||||
if("delete")
|
||||
if(level == 2)
|
||||
default = null
|
||||
//updateUsrDialog()
|
||||
interact(usr)
|
||||
return
|
||||
if(level == 1)
|
||||
for(var/datum/cargoprofile/T in overrides)
|
||||
if(T.id == id)
|
||||
overrides -= T
|
||||
//updateUsrDialog()
|
||||
interact(usr)
|
||||
return
|
||||
if(level == 0)
|
||||
for(var/datum/cargoprofile/T in profiles)
|
||||
if(T.id == id)
|
||||
profiles -= T
|
||||
//updateUsrDialog()
|
||||
interact(usr)
|
||||
return
|
||||
if("deleteall")
|
||||
for(var/datum/cargoprofile/T in profiles)
|
||||
profiles -= T
|
||||
for(var/datum/cargoprofile/T in overrides)
|
||||
overrides -= T
|
||||
//updateUsrDialog()
|
||||
interact(usr)
|
||||
return
|
||||
if("deleteoverrides")
|
||||
for(var/datum/cargoprofile/T in overrides)
|
||||
overrides -= T
|
||||
interact(usr)
|
||||
return
|
||||
if("deleteprofiles")
|
||||
for(var/datum/cargoprofile/T in profiles)
|
||||
profiles -= T
|
||||
interact(usr)
|
||||
return
|
||||
if("reset")
|
||||
resetlists()
|
||||
interact(usr)
|
||||
return
|
||||
|
||||
//End switch
|
||||
|
||||
|
||||
datum/design/programmable
|
||||
name = "Circuit Design (Programmable Unloader)"
|
||||
desc = "Allows for the construction of circuit boards used to build a Programmable Unloader."
|
||||
id = "selunload"
|
||||
req_tech = list("programming" = 5)
|
||||
build_type = IMPRINTER
|
||||
materials = list("$glass" = 2000, "sacid" = 20)
|
||||
build_path = "/obj/item/weapon/circuitboard/programmable"
|
||||
Reference in New Issue
Block a user