diff --git a/code/modules/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm
new file mode 100644
index 0000000000..9431c4685f
--- /dev/null
+++ b/code/modules/holodeck/HolodeckControl.dm
@@ -0,0 +1,385 @@
+var/global/list/holodeck_programs = list(
+ "emptycourt" = /area/holodeck/source_emptycourt, \
+ "boxingcourt" = /area/holodeck/source_boxingcourt, \
+ "basketball" = /area/holodeck/source_basketball, \
+ "thunderdomecourt" = /area/holodeck/source_thunderdomecourt, \
+ "beach" = /area/holodeck/source_beach, \
+ "desert" = /area/holodeck/source_desert, \
+ "space" = /area/holodeck/source_space, \
+ "picnicarea" = /area/holodeck/source_picnicarea, \
+ "snowfield" = /area/holodeck/source_snowfield, \
+ "theatre" = /area/holodeck/source_theatre, \
+ "meetinghall" = /area/holodeck/source_meetinghall, \
+ "courtroom" = /area/holodeck/source_courtroom, \
+ "burntest" = /area/holodeck/source_burntest, \
+ "wildlifecarp" = /area/holodeck/source_wildlife, \
+ "turnoff" = /area/holodeck/source_plating \
+ )
+
+/obj/machinery/computer/HolodeckControl
+ name = "holodeck control console"
+ desc = "A computer used to control a nearby holodeck."
+ icon_state = "holocontrol"
+
+ use_power = 1
+ active_power_usage = 8000 //8kW for the scenery + 500W per holoitem
+ var/item_power_usage = 500
+
+ var/area/linkedholodeck = null
+ var/area/target = null
+ var/active = 0
+ var/list/holographic_items = list()
+ var/list/holographic_mobs = list()
+ var/damaged = 0
+ var/safety_disabled = 0
+ var/mob/last_to_emag = null
+ var/last_change = 0
+ var/last_gravity_change = 0
+ var/list/supported_programs = list( \
+ "Empty Court" = "emptycourt", \
+ "Basketball Court" = "basketball", \
+ "Thunderdome Court" = "thunderdomecourt", \
+ "Boxing Ring"="boxingcourt", \
+ "Beach" = "beach", \
+ "Desert" = "desert", \
+ "Space" = "space", \
+ "Picnic Area" = "picnicarea", \
+ "Snow Field" = "snowfield", \
+ "Theatre" = "theatre", \
+ "Meeting Hall" = "meetinghall", \
+ "Courtroom" = "courtroom" \
+ )
+ var/list/restricted_programs = list("Atmospheric Burn Simulation" = "burntest", "Wildlife Simulation" = "wildlifecarp")
+
+/obj/machinery/computer/HolodeckControl/attack_ai(var/mob/user as mob)
+ return src.attack_hand(user)
+
+/obj/machinery/computer/HolodeckControl/attack_hand(var/mob/user as mob)
+
+ if(..())
+ return
+ user.set_machine(src)
+ var/dat
+
+ dat += "Holodeck Control System
"
+ dat += "
Current Loaded Programs:
"
+ for(var/prog in supported_programs)
+ dat += "([prog])
"
+
+ dat += "
"
+ dat += "(Turn Off)
"
+
+ dat += "
"
+ dat += "Please ensure that only holographic weapons are used in the holodeck if a combat simulation has been loaded.
"
+
+ if(issilicon(user))
+ dat += "
"
+ if(safety_disabled)
+ if (emagged)
+ dat += "ERROR: Cannot re-enable Safety Protocols.
"
+ else
+ dat += "(Re-Enable Safety Protocols?)
"
+ else
+ dat += "(Override Safety Protocols?)
"
+
+ dat += "
"
+
+ if(safety_disabled)
+ for(var/prog in restricted_programs)
+ dat += "(Begin [prog])
"
+ dat += "Ensure the holodeck is empty before testing.
"
+ dat += "
"
+ dat += "Safety Protocols are DISABLED
"
+ else
+ dat += "Safety Protocols are ENABLED
"
+
+ if(linkedholodeck.has_gravity)
+ dat += "Gravity is (ON)
"
+ else
+ dat += "Gravity is (OFF)
"
+
+ user << browse(dat, "window=computer;size=400x500")
+ onclose(user, "computer")
+
+ return
+
+
+/obj/machinery/computer/HolodeckControl/Topic(href, href_list)
+ if(..())
+ return
+ if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
+ usr.set_machine(src)
+
+ if(href_list["program"])
+ var/prog = href_list["program"]
+ if(prog in holodeck_programs)
+ target = locate(holodeck_programs[prog])
+ if(target)
+ loadProgram(target)
+
+ else if(href_list["AIoverride"])
+ if(!issilicon(usr))
+ return
+
+ if(safety_disabled && emagged)
+ return //if a traitor has gone through the trouble to emag the thing, let them keep it.
+
+ safety_disabled = !safety_disabled
+ update_projections()
+ if(safety_disabled)
+ message_admins("[key_name_admin(usr)] overrode the holodeck's safeties")
+ log_game("[key_name(usr)] overrided the holodeck's safeties")
+ else
+ message_admins("[key_name_admin(usr)] restored the holodeck's safeties")
+ log_game("[key_name(usr)] restored the holodeck's safeties")
+
+ else if(href_list["gravity"])
+ toggleGravity(linkedholodeck)
+
+ src.add_fingerprint(usr)
+ src.updateUsrDialog()
+ return
+
+/obj/machinery/computer/HolodeckControl/attackby(var/obj/item/weapon/D as obj, var/mob/user as mob)
+ if(istype(D, /obj/item/weapon/card/emag))
+ playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1)
+ last_to_emag = user //emag again to change the owner
+ if (!emagged)
+ emagged = 1
+ safety_disabled = 1
+ update_projections()
+ user << "You vastly increase projector power and override the safety and security protocols."
+ user << "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call Nanotrasen maintenance and do not use the simulator."
+ log_game("[key_name(usr)] emagged the Holodeck Control Computer")
+ src.updateUsrDialog()
+ return
+
+/obj/machinery/computer/HolodeckControl/proc/update_projections()
+ if (safety_disabled)
+ item_power_usage = 2500
+ for(var/obj/item/weapon/holo/esword/H in linkedholodeck)
+ H.damtype = BRUTE
+ else
+ item_power_usage = initial(item_power_usage)
+ for(var/obj/item/weapon/holo/esword/H in linkedholodeck)
+ H.damtype = initial(H.damtype)
+
+ for(var/mob/living/simple_animal/hostile/carp/holodeck/C in holographic_mobs)
+ C.set_safety(!safety_disabled)
+ if (last_to_emag)
+ C.friends = list(last_to_emag)
+
+/obj/machinery/computer/HolodeckControl/New()
+ ..()
+ linkedholodeck = locate(/area/holodeck/alphadeck)
+ //if(linkedholodeck)
+ // target = locate(/area/holodeck/source_emptycourt)
+ // if(target)
+ // loadProgram(target)
+
+//This could all be done better, but it works for now.
+/obj/machinery/computer/HolodeckControl/Del()
+ emergencyShutdown()
+ ..()
+
+/obj/machinery/computer/HolodeckControl/meteorhit(var/obj/O as obj)
+ emergencyShutdown()
+ ..()
+
+
+/obj/machinery/computer/HolodeckControl/emp_act(severity)
+ emergencyShutdown()
+ ..()
+
+
+/obj/machinery/computer/HolodeckControl/ex_act(severity)
+ emergencyShutdown()
+ ..()
+
+
+/obj/machinery/computer/HolodeckControl/blob_act()
+ emergencyShutdown()
+ ..()
+
+/obj/machinery/computer/HolodeckControl/power_change()
+ var/oldstat
+ ..()
+ if (stat != oldstat && active && (stat & NOPOWER))
+ emergencyShutdown()
+
+/obj/machinery/computer/HolodeckControl/process()
+ for(var/item in holographic_items) // do this first, to make sure people don't take items out when power is down.
+ if(!(get_turf(item) in linkedholodeck))
+ derez(item, 0)
+
+ if (!safety_disabled)
+ for(var/mob/living/simple_animal/hostile/carp/holodeck/C in holographic_mobs)
+ if (get_area(C.loc) != linkedholodeck)
+ holographic_mobs -= C
+ C.derez()
+
+ if(!..())
+ return
+ if(active)
+ use_power(item_power_usage * (holographic_items.len + holographic_mobs.len))
+
+ if(!checkInteg(linkedholodeck))
+ damaged = 1
+ target = locate(/area/holodeck/source_plating)
+ if(target)
+ loadProgram(target)
+ active = 0
+ use_power = 1
+ for(var/mob/M in range(10,src))
+ M.show_message("The holodeck overloads!")
+
+
+ for(var/turf/T in linkedholodeck)
+ if(prob(30))
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(2, 1, T)
+ s.start()
+ T.ex_act(3)
+ T.hotspot_expose(1000,500,1)
+
+/obj/machinery/computer/HolodeckControl/proc/derez(var/obj/obj , var/silent = 1)
+ holographic_items.Remove(obj)
+
+ if(obj == null)
+ return
+
+ if(isobj(obj))
+ var/mob/M = obj.loc
+ if(ismob(M))
+ M.u_equip(obj)
+ M.update_icons() //so their overlays update
+
+ if(!silent)
+ var/obj/oldobj = obj
+ visible_message("The [oldobj.name] fades away!")
+ del(obj)
+
+/obj/machinery/computer/HolodeckControl/proc/checkInteg(var/area/A)
+ for(var/turf/T in A)
+ if(istype(T, /turf/space))
+ return 0
+
+ return 1
+
+//Why is it called toggle if it doesn't toggle?
+/obj/machinery/computer/HolodeckControl/proc/togglePower(var/toggleOn = 0)
+
+ if(toggleOn)
+ var/area/targetsource = locate(/area/holodeck/source_emptycourt)
+ holographic_items = targetsource.copy_contents_to(linkedholodeck)
+
+ spawn(30)
+ for(var/obj/effect/landmark/L in linkedholodeck)
+ if(L.name=="Atmospheric Test Start")
+ spawn(20)
+ var/turf/T = get_turf(L)
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(2, 1, T)
+ s.start()
+ if(T)
+ T.temperature = 5000
+ T.hotspot_expose(50000,50000,1)
+
+ active = 1
+ use_power = 2
+ else
+ for(var/item in holographic_items)
+ derez(item)
+ if(!linkedholodeck.has_gravity)
+ linkedholodeck.gravitychange(1,linkedholodeck)
+
+ var/area/targetsource = locate(/area/holodeck/source_plating)
+ targetsource.copy_contents_to(linkedholodeck , 1)
+ active = 0
+ use_power = 1
+
+
+/obj/machinery/computer/HolodeckControl/proc/loadProgram(var/area/A)
+
+ if(world.time < (last_change + 25))
+ if(world.time < (last_change + 15))//To prevent super-spam clicking, reduced process size and annoyance -Sieve
+ return
+ for(var/mob/M in range(3,src))
+ M.show_message("\b ERROR. Recalibrating projection apparatus.")
+ last_change = world.time
+ return
+
+ last_change = world.time
+ active = 1
+ use_power = 2
+
+ for(var/item in holographic_items)
+ derez(item)
+
+ for(var/mob/living/simple_animal/hostile/carp/holodeck/C in holographic_mobs)
+ holographic_mobs -= C
+ C.derez()
+
+ for(var/obj/effect/decal/cleanable/blood/B in linkedholodeck)
+ del(B)
+
+ holographic_items = A.copy_contents_to(linkedholodeck , 1)
+
+ spawn(30)
+ for(var/obj/effect/landmark/L in linkedholodeck)
+ if(L.name=="Atmospheric Test Start")
+ spawn(20)
+ var/turf/T = get_turf(L)
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(2, 1, T)
+ s.start()
+ if(T)
+ T.temperature = 5000
+ T.hotspot_expose(50000,50000,1)
+ if(L.name=="Holocarp Spawn")
+ holographic_mobs += new /mob/living/simple_animal/hostile/carp/holodeck(L.loc)
+
+ if(L.name=="Holocarp Spawn Random")
+ if (prob(4)) //With 4 spawn points, carp should only appear 15% of the time.
+ holographic_mobs += new /mob/living/simple_animal/hostile/carp/holodeck(L.loc)
+
+ update_projections()
+
+
+/obj/machinery/computer/HolodeckControl/proc/toggleGravity(var/area/A)
+ if(world.time < (last_gravity_change + 25))
+ if(world.time < (last_gravity_change + 15))//To prevent super-spam clicking
+ return
+ for(var/mob/M in range(3,src))
+ M.show_message("\b ERROR. Recalibrating gravity field.")
+ last_change = world.time
+ return
+
+ last_gravity_change = world.time
+ active = 1
+ use_power = 1
+
+ if(A.has_gravity)
+ A.gravitychange(0,A)
+ else
+ A.gravitychange(1,A)
+
+/obj/machinery/computer/HolodeckControl/proc/emergencyShutdown()
+ //Get rid of any items
+ for(var/item in holographic_items)
+ derez(item)
+ for(var/mob/living/simple_animal/hostile/carp/holodeck/C in holographic_mobs)
+ holographic_mobs -= C
+ C.derez()
+ //Turn it back to the regular non-holographic room
+ target = locate(/area/holodeck/source_plating)
+ if(target)
+ loadProgram(target)
+
+ if(!linkedholodeck.has_gravity)
+ linkedholodeck.gravitychange(1,linkedholodeck)
+
+ var/area/targetsource = locate(/area/holodeck/source_plating)
+ targetsource.copy_contents_to(linkedholodeck , 1)
+ active = 0
+ use_power = 1
\ No newline at end of file
diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm
new file mode 100644
index 0000000000..fda07a2ddb
--- /dev/null
+++ b/code/modules/holodeck/HolodeckObjects.dm
@@ -0,0 +1,422 @@
+// Holographic Items!
+
+/turf/simulated/floor/holofloor/
+ thermal_conductivity = 0
+
+/turf/simulated/floor/holofloor/grass
+ name = "Lush Grass"
+ icon_state = "grass1"
+ floor_type = /obj/item/stack/tile/grass
+
+ New()
+ icon_state = "grass[pick("1","2","3","4")]"
+ ..()
+ spawn(4)
+ update_icon()
+ for(var/direction in cardinal)
+ if(istype(get_step(src,direction),/turf/simulated/floor))
+ var/turf/simulated/floor/FF = get_step(src,direction)
+ FF.update_icon() //so siding get updated properly
+
+/turf/simulated/floor/holofloor/space
+ icon = 'icons/turf/space.dmi'
+ name = "\proper space"
+ icon_state = "0"
+
+/turf/simulated/floor/holofloor/space/New()
+ icon_state = "[((x + y) ^ ~(x * y) + z) % 25]"
+
+/turf/simulated/floor/holofloor/desert
+ name = "desert sand"
+ desc = "Uncomfortably gritty for a hologram."
+ icon_state = "asteroid"
+
+/turf/simulated/floor/holofloor/desert/New()
+ ..()
+ if(prob(10))
+ overlays += "asteroid[rand(0,9)]"
+
+/turf/simulated/floor/holofloor/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ return
+ // HOLOFLOOR DOES NOT GIVE A FUCK
+
+/obj/structure/table/holotable
+ name = "table"
+ desc = "A square piece of metal standing on four metal legs. It can not move."
+ icon = 'icons/obj/structures.dmi'
+ icon_state = "table"
+ density = 1
+ anchored = 1.0
+ layer = 2.8
+ throwpass = 1 //You can throw objects over this, despite it's density.
+
+/obj/structure/table/holotable/attack_hand(mob/user as mob)
+ return // HOLOTABLE DOES NOT GIVE A FUCK
+
+
+/obj/structure/table/holotable/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if (istype(W, /obj/item/weapon/wrench))
+ user << "It's a holotable! There are no bolts!"
+ return
+
+ if(isrobot(user))
+ return
+
+ ..()
+
+/obj/structure/table/woodentable/holotable
+ name = "table"
+ desc = "A square piece of wood standing on four wooden legs. It can not move."
+ icon = 'icons/obj/structures.dmi'
+ icon_state = "wood_table"
+
+/obj/structure/holostool
+ name = "stool"
+ desc = "Apply butt."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "stool"
+ anchored = 1.0
+ pressure_resistance = 15
+
+
+/obj/item/clothing/gloves/boxing/hologlove
+ name = "boxing gloves"
+ desc = "Because you really needed another excuse to punch your crewmates."
+ icon_state = "boxing"
+ item_state = "boxing"
+
+/obj/structure/window/reinforced/holowindow/Del()
+ ..()
+
+/obj/structure/window/reinforced/holowindow/attackby(obj/item/W as obj, mob/user as mob)
+ if(!istype(W)) return//I really wish I did not need this
+ if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2)
+ var/obj/item/weapon/grab/G = W
+ if(istype(G.affecting,/mob/living))
+ var/mob/living/M = G.affecting
+ var/state = G.state
+ del(W) //gotta delete it here because if window breaks, it won't get deleted
+ switch (state)
+ if(1)
+ M.visible_message("[user] slams [M] against \the [src]!")
+ M.apply_damage(7)
+ hit(10)
+ if(2)
+ M.visible_message("[user] bashes [M] against \the [src]!")
+ if (prob(50))
+ M.Weaken(1)
+ M.apply_damage(10)
+ hit(25)
+ if(3)
+ M.visible_message("[user] crushes [M] against \the [src]!")
+ M.Weaken(5)
+ M.apply_damage(20)
+ hit(50)
+ return
+
+ if(W.flags & NOBLUDGEON) return
+
+ if(istype(W, /obj/item/weapon/screwdriver))
+ user << ("It's a holowindow, you can't unfasten it!")
+ else if(istype(W, /obj/item/weapon/crowbar) && reinf && state <= 1)
+ user << ("It's a holowindow, you can't pry it!")
+ else if(istype(W, /obj/item/weapon/wrench) && !anchored && (!state || !reinf))
+ user << ("It's a holowindow, you can't dismantle it!")
+ else
+ if(W.damtype == BRUTE || W.damtype == BURN)
+ hit(W.force)
+ if(health <= 7)
+ anchored = 0
+ update_nearby_icons()
+ step(src, get_dir(user, src))
+ else
+ playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1)
+ ..()
+ return
+
+/obj/structure/window/reinforced/holowindow/shatter(var/display_message = 1)
+ playsound(src, "shatter", 70, 1)
+ if(display_message)
+ visible_message("[src] fades away as it shatters!")
+ del(src)
+ return
+
+/obj/structure/window/reinforced/holowindow/disappearing/Del()
+ ..()
+
+/obj/machinery/door/window/holowindoor/Del()
+ ..()
+
+/obj/machinery/door/window/holowindoor/attackby(obj/item/weapon/I as obj, mob/user as mob)
+
+ if (src.operating == 1)
+ return
+
+ if(src.density && istype(I, /obj/item/weapon) && !istype(I, /obj/item/weapon/card))
+ var/aforce = I.force
+ playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
+ visible_message("\red [src] was hit by [I].")
+ if(I.damtype == BRUTE || I.damtype == BURN)
+ take_damage(aforce)
+ return
+
+ src.add_fingerprint(user)
+ if (!src.requiresID())
+ user = null
+
+ if (src.allowed(user))
+ if (src.density)
+ open()
+ else
+ close()
+
+ else if (src.density)
+ flick(text("[]deny", src.base_state), src)
+
+ return
+
+/obj/machinery/door/window/holowindoor/shatter(var/display_message = 1)
+ src.density = 0
+ playsound(src, "shatter", 70, 1)
+ if(display_message)
+ visible_message("[src] fades away as it shatters!")
+ del(src)
+
+/obj/structure/stool/bed/chair/holochair/Del()
+ ..()
+
+/obj/structure/stool/bed/chair/holochair/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/weapon/wrench))
+ user << ("It's a holochair, you can't dismantle it!")
+ return
+
+/obj/item/weapon/holo
+ damtype = HALLOSS
+
+/obj/item/weapon/holo/esword
+ desc = "May the force be within you. Sorta."
+ icon_state = "sword0"
+ force = 3.0
+ throw_speed = 1
+ throw_range = 5
+ throwforce = 0
+ w_class = 2.0
+ flags = NOSHIELD | NOBLOODY
+ var/active = 0
+
+/obj/item/weapon/holo/esword/green
+ New()
+ item_color = "green"
+
+/obj/item/weapon/holo/esword/red
+ New()
+ item_color = "red"
+
+/obj/item/weapon/holo/esword/IsShield()
+ if(active)
+ return 1
+ return 0
+
+/obj/item/weapon/holo/esword/attack(target as mob, mob/user as mob)
+ ..()
+
+/obj/item/weapon/holo/esword/New()
+ item_color = pick("red","blue","green","purple")
+
+/obj/item/weapon/holo/esword/attack_self(mob/living/user as mob)
+ active = !active
+ if (active)
+ force = 30
+ icon_state = "sword[item_color]"
+ w_class = 4
+ playsound(user, 'sound/weapons/saberon.ogg', 50, 1)
+ user << "[src] is now active."
+ else
+ force = 3
+ icon_state = "sword0"
+ w_class = 2
+ playsound(user, 'sound/weapons/saberoff.ogg', 50, 1)
+ user << "[src] can now be concealed."
+
+ if(istype(user,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = user
+ H.update_inv_l_hand()
+ H.update_inv_r_hand()
+
+ add_fingerprint(user)
+ return
+
+//BASKETBALL OBJECTS
+
+/obj/item/weapon/beach_ball/holoball
+ icon = 'icons/obj/basketball.dmi'
+ icon_state = "basketball"
+ name = "basketball"
+ item_state = "basketball"
+ desc = "Here's your chance, do your dance at the Space Jam."
+ w_class = 4 //Stops people from hiding it in their bags/pockets
+
+/obj/structure/holohoop
+ name = "basketball hoop"
+ desc = "Boom, Shakalaka!"
+ icon = 'icons/obj/basketball.dmi'
+ icon_state = "hoop"
+ anchored = 1
+ density = 1
+ throwpass = 1
+
+/obj/structure/holohoop/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2)
+ var/obj/item/weapon/grab/G = W
+ if(G.state<2)
+ user << "You need a better grip to do that!"
+ return
+ G.affecting.loc = src.loc
+ G.affecting.Weaken(5)
+ visible_message("[G.assailant] dunks [G.affecting] into the [src]!", 3)
+ del(W)
+ return
+ else if (istype(W, /obj/item) && get_dist(src,user)<2)
+ user.drop_item(src)
+ visible_message("[user] dunks [W] into the [src]!", 3)
+ return
+
+/obj/structure/holohoop/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
+ if (istype(mover,/obj/item) && mover.throwing)
+ var/obj/item/I = mover
+ if(istype(I, /obj/item/projectile))
+ return
+ if(prob(50))
+ I.loc = src.loc
+ visible_message("Swish! \the [I] lands in \the [src].", 3)
+ else
+ visible_message("\The [I] bounces off of \the [src]'s rim!", 3)
+ return 0
+ else
+ return ..(mover, target, height, air_group)
+
+
+/obj/machinery/readybutton
+ name = "Ready Declaration Device"
+ desc = "This device is used to declare ready. If all devices in an area are ready, the event will begin!"
+ icon = 'icons/obj/monitors.dmi'
+ icon_state = "auth_off"
+ var/ready = 0
+ var/area/currentarea = null
+ var/eventstarted = 0
+
+ anchored = 1.0
+ use_power = 1
+ idle_power_usage = 2
+ active_power_usage = 6
+ power_channel = ENVIRON
+
+/obj/machinery/readybutton/attack_ai(mob/user as mob)
+ user << "The station AI is not to interact with these devices!"
+ return
+
+/obj/machinery/readybutton/New()
+ ..()
+
+
+/obj/machinery/readybutton/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ user << "The device is a solid button, there's nothing you can do with it!"
+
+/obj/machinery/readybutton/attack_hand(mob/user as mob)
+
+ if(user.stat || stat & (NOPOWER|BROKEN))
+ user << "This device is not powered."
+ return
+
+ if(!user.IsAdvancedToolUser())
+ return 0
+
+ currentarea = get_area(src.loc)
+ if(!currentarea)
+ del(src)
+
+ if(eventstarted)
+ usr << "The event has already begun!"
+ return
+
+ ready = !ready
+
+ update_icon()
+
+ var/numbuttons = 0
+ var/numready = 0
+ for(var/obj/machinery/readybutton/button in currentarea)
+ numbuttons++
+ if (button.ready)
+ numready++
+
+ if(numbuttons == numready)
+ begin_event()
+
+/obj/machinery/readybutton/update_icon()
+ if(ready)
+ icon_state = "auth_on"
+ else
+ icon_state = "auth_off"
+
+/obj/machinery/readybutton/proc/begin_event()
+
+ eventstarted = 1
+
+ for(var/obj/structure/window/reinforced/holowindow/disappearing/W in currentarea)
+ del(W)
+
+ for(var/mob/M in currentarea)
+ M << "FIGHT!"
+
+//Holorack
+
+/obj/structure/table/rack/holorack
+ name = "rack"
+ desc = "Different from the Middle Ages version."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "rack"
+
+/obj/structure/table/rack/holorack/attack_hand(mob/user as mob)
+ return
+
+/obj/structure/table/rack/holorack/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if (istype(W, /obj/item/weapon/wrench))
+ user << "It's a holorack! You can't unwrench it!"
+ return
+
+//Holocarp
+
+/mob/living/simple_animal/hostile/carp/holodeck
+ icon = 'icons/mob/AI.dmi'
+ icon_state = "holo4"
+ icon_living = "holo4"
+ icon_dead = "holo4"
+ icon_gib = null
+ meat_amount = 0
+ meat_type = null
+
+/mob/living/simple_animal/hostile/carp/holodeck/proc/set_safety(var/safe)
+ if (safe)
+ faction = "neutral"
+ melee_damage_lower = 0
+ melee_damage_upper = 0
+ wall_smash = 0
+ destroy_surroundings = 0
+ else
+ faction = "carp"
+ melee_damage_lower = initial(melee_damage_lower)
+ melee_damage_upper = initial(melee_damage_upper)
+ wall_smash = initial(wall_smash)
+ destroy_surroundings = initial(destroy_surroundings)
+
+/mob/living/simple_animal/hostile/carp/holodeck/gib()
+ derez() //holograms can't gib
+
+/mob/living/simple_animal/hostile/carp/holodeck/death()
+ ..()
+ derez()
+
+/mob/living/simple_animal/hostile/carp/holodeck/proc/derez()
+ visible_message("\The [src] fades away!")
+ del(src)