diff --git a/COPYING b/COPYING
index 5c2d485924d..a4192d74542 100644
--- a/COPYING
+++ b/COPYING
@@ -1,5 +1,5 @@
Paradise
-Copyright (C) 2010-2014 Paradise, Baystation12 and tgstation13.
+Copyright (C) 2010-2016 Paradise, Baystation12, Goonstation and tgstation13.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -13,3 +13,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
Aliens - Kill or infect the crew. Protect the Queen.
Crew - Protect the station. Exterminate all aliens.")
-
-/datum/game_mode/xenos/can_start()
- if(!..())
- return 0
-
- var/list/candidates = get_players_for_role(ROLE_ALIEN)
- var/playersready = 0
- var/xenos_num = required_enemies
- for(var/mob/new_player/player in player_list)
- if((player.client)&&(player.ready))
- playersready += 1
-
- //Check that we have enough alien candidates
- if(candidates.len < required_enemies)
- return 0
-
- //Grab candidates randomly until we have enough.
- while(xenos_num > 0)
- var/datum/mind/new_xenos = pick(candidates)
- xenos += new_xenos
- candidates -= new_xenos
- xenos_num--
-
- for(var/datum/mind/xeno in xenos)
- xeno.assigned_role = "MODE"
- xeno.special_role = SPECIAL_ROLE_XENOMORPH
- set_antag_hud(xeno, "hudalien")//like this is needed...
- return 1
-
-/datum/game_mode/xenos/pre_setup()
- return 1
-
-/datum/game_mode/xenos/post_setup()
-
- var/list/turf/xenos_spawn = list()
-
- for(var/obj/effect/landmark/A in landmarks_list)
- if(A.name == "Xenos-Spawn")
- xenos_spawn += get_turf(A)
- qdel(A)
- continue
-
- var/xenoqueen_selected = 0
- var/spawnpos = 1
-
- for(var/datum/mind/xeno_mind in xenos)
- if(spawnpos > xenos_spawn.len)
- spawnpos = 1
- //XenoQueen Selection
- if(!xenoqueen_selected)
- var/mob/living/carbon/alien/humanoid/queen/O = new(xenos_spawn[spawnpos])
- if(xeno_mind.current)
- xeno_mind.transfer_to(O)
- else
- O.key = xeno_mind.current.key
- xeno_mind.name = O.name
- //qdel(xeno_mind)
- xenoqueen_selected = 1
- spawnpos++
- continue
- //Additional larvas if playercount > 20
- else
- var/mob/living/carbon/alien/larva/O = new(xenos_spawn[spawnpos])
- if(xeno_mind.current)
- xeno_mind.transfer_to(O)
- else
- O.key = xeno_mind.current.key
- xeno_mind.name = O.name
- //qdel(xeno_mind)
- spawnpos++
-
- return ..()
-
-/datum/game_mode/xenos/process()
- checkwin_counter++
- if(checkwin_counter >= 5)
- if(!result)
- ticker.mode.check_win()
- checkwin_counter = 0
- return 0
-
-
-/datum/game_mode/xenos/check_win()
- var/xenosalive = xenos_alive()
- var/playersalive = players_alive()
- var/playeralienratio = 0
- if(playersalive)
- playeralienratio = xenosalive / playersalive
- if(shuttle_master && shuttle_master.emergency.mode >= SHUTTLE_ESCAPE)
- return ..()
- if(!xenosalive)
- result = 1
- return 1
- else if(!playersalive)
- result = 2
- return 1
- else if(station_was_nuked)
- result = 3
- return 1
- else
- if(playeralienratio >= gammaratio && !gammacalled)
- gammacalled = 1
- command_announcement.Announce("The aliens have nearly succeeded in capturing the station and exterminating the crew. Activate the nuclear failsafe to stop the alien threat once and for all. The Nuclear Authentication Code is [get_nuke_code()] ", "Alien Lifeform Alert")
- set_security_level("gamma")
- var/obj/machinery/door/airlock/vault/V = locate(/obj/machinery/door/airlock/vault) in world
- if(V && is_station_level(V.z))
- V.locked = 0
- V.update_icon()
- return ..()
-
-/datum/game_mode/xenos/check_finished()
- return result != 0
-
-/datum/game_mode/xenos/proc/xenos_alive()
- var/list/livingxenos = list()
- for(var/datum/mind/xeno in xenos)
- if((xeno) && (xeno.current) && (xeno.current.stat != 2) && (xeno.current.client))
- if(istype(xeno.current,/mob/living/carbon/alien))
- livingxenos += xeno
- return livingxenos.len
-
-/datum/game_mode/xenos/proc/players_alive()
- var/list/livingplayers = list()
- for(var/mob/M in player_list)
- var/turf/T = get_turf(M)
- if((M) && (M.stat != DEAD) && M.client && T && (is_station_level(T.z) || shuttle_master.emergency.mode >= SHUTTLE_ESCAPE && is_secure_level(T.z)))
- if(ishuman(M))
- livingplayers += 1
- return livingplayers.len
-
-/datum/game_mode/xenos/declare_completion()
- if(station_was_nuked)
- feedback_set_details("round_end_result","win - xenos nuked")
- to_chat(world, "Crew Victory")
- to_chat(world, "The station was destroyed in a nuclear explosion, preventing the aliens from overrunning it!")
- else if(result == 1)
- feedback_set_details("round_end_result","win - xenos killed")
- to_chat(world, "Crew Victory")
- to_chat(world, "The aliens did not succeed and were exterminated by the crew!")
- else if(result == 2)
- feedback_set_details("round_end_result","win - crew killed")
- to_chat(world, "Alien Victory")
- to_chat(world, "The aliens were successful and slaughtered the crew!")
- else
- feedback_set_details("round_end_result","win - crew escaped")
- to_chat(world, "Draw")
- to_chat(world, "The crew has escaped from the aliens but did not exterminate them, allowing them to overrun the station.")
-
- var/text = "
There were [xenos.len] aliens."
- text += "
The aliens were:"
- for(var/datum/mind/xeno in xenos)
- text += "
[xeno.key] was [xeno.name] ("
- if(xeno.current)
- if(xeno.current.stat == DEAD)
- text += "died"
- else if(!xeno.current.client)
- text += "SSD"
- else
- text += "survived"
- else
- text += "body destroyed"
- text += ")"
- to_chat(world, text)
-
- ..()
- return 1
diff --git a/code/game/machinery/biogenerator.dm b/code/game/machinery/biogenerator.dm
index bde30cd92d4..6344dec7bbf 100644
--- a/code/game/machinery/biogenerator.dm
+++ b/code/game/machinery/biogenerator.dm
@@ -97,16 +97,17 @@
else if(processing)
to_chat(user, "The biogenerator is currently processing.")
else if(istype(O, /obj/item/weapon/storage/bag/plants))
+ var/obj/item/weapon/storage/bag/plants/PB = O
var/i = 0
for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in contents)
i++
if(i >= max_items)
to_chat(user, "The biogenerator is already full! Activate it.")
else
- for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in O.contents)
+ for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in PB.contents)
if(i >= max_items)
break
- G.forceMove(src)
+ PB.remove_from_storage(G, src)
i++
if(i < max_items)
to_chat(user, "You empty the plant bag into the biogenerator.")
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 1c77d4b099a..4c52667a106 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -14,7 +14,7 @@
icon = 'icons/obj/cloning.dmi'
icon_state = "pod_0"
req_access = list(access_genetics) //For premature unlocking.
- var/mob/living/occupant
+ var/mob/living/carbon/human/occupant
var/heal_level = 90 //The clone is released once its health reaches this level.
var/locked = 0
var/obj/machinery/computer/cloning/connected = null //So we remember the connected clone machine.
@@ -25,19 +25,34 @@
var/speed_coeff
var/efficiency
+ var/datum/mind/clonemind
+ var/grab_ghost_when = CLONER_MATURE_CLONE
+
+ var/obj/item/device/radio/Radio
+ var/radio_announce = 0
+
+ var/obj/effect/countdown/clonepod/countdown
+
light_color = LIGHT_COLOR_PURE_GREEN
- power_change()
- ..()
- if(!(stat & (BROKEN|NOPOWER)))
- set_light(2)
- else
- set_light(0)
+
+/obj/machinery/clonepod/power_change()
+ ..()
+ if(!(stat & (BROKEN|NOPOWER)))
+ set_light(2)
+ else
+ set_light(0)
/obj/machinery/clonepod/biomass
biomass = CLONE_BIOMASS
/obj/machinery/clonepod/New()
..()
+ countdown = new(src)
+
+ Radio = new /obj/item/device/radio(src)
+ Radio.listening = 0
+ Radio.config(list("Medical" = 0))
+
component_parts = list()
component_parts += new /obj/item/weapon/circuitboard/clonepod(null)
component_parts += new /obj/item/weapon/stock_parts/scanning_module(null)
@@ -67,6 +82,12 @@
/obj/machinery/clonepod/Destroy()
if(connected)
connected.pods -= src
+ if(Radio)
+ qdel(Radio)
+ Radio = null
+ if(countdown)
+ qdel(countdown)
+ countdown = null
return ..()
/obj/machinery/clonepod/RefreshParts()
@@ -97,49 +118,29 @@
name = "data disk - 'God Emperor of Mankind'"
read_only = 1
- New()
- Initialize()
- buf.types=DNA2_BUF_UE|DNA2_BUF_UI
- //data = "066000033000000000AF00330660FF4DB002690"
- //data = "0C80C80C80C80C80C8000000000000161FBDDEF" - Farmer Jeff
- buf.dna.real_name="God Emperor of Mankind"
- buf.dna.unique_enzymes = md5(buf.dna.real_name)
- buf.dna.UI=list(0x066,0x000,0x033,0x000,0x000,0x000,0xAF0,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x033,0x066,0x0FF,0x4DB,0x002,0x690,0x000,0x000)
- //buf.dna.UI=list(0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x000,0x000,0x000,0x000,0x161,0xFBD,0xDEF) // Farmer Jeff
- buf.dna.UpdateUI()
+/obj/item/weapon/disk/data/demo/New()
+ Initialize()
+ buf.types=DNA2_BUF_UE|DNA2_BUF_UI
+ //data = "066000033000000000AF00330660FF4DB002690"
+ //data = "0C80C80C80C80C80C8000000000000161FBDDEF" - Farmer Jeff
+ buf.dna.real_name="God Emperor of Mankind"
+ buf.dna.unique_enzymes = md5(buf.dna.real_name)
+ buf.dna.UI=list(0x066,0x000,0x033,0x000,0x000,0x000,0xAF0,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x033,0x066,0x0FF,0x4DB,0x002,0x690,0x000,0x000)
+ //buf.dna.UI=list(0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x000,0x000,0x000,0x000,0x161,0xFBD,0xDEF) // Farmer Jeff
+ buf.dna.UpdateUI()
/obj/item/weapon/disk/data/monkey
name = "data disk - 'Mr. Muggles'"
read_only = 1
- New()
- Initialize()
- buf.types=DNA2_BUF_SE
- var/list/new_SE=list(0x098,0x3E8,0x403,0x44C,0x39F,0x4B0,0x59D,0x514,0x5FC,0x578,0x5DC,0x640,0x6A4)
- for(var/i=new_SE.len;i<=DNA_SE_LENGTH;i++)
- new_SE += rand(1,1024)
- buf.dna.SE=new_SE
- buf.dna.SetSEValueRange(MONKEYBLOCK,0xDAC, 0xFFF)
-
-
-//Find a dead mob with a brain and client.
-/proc/find_dead_player(var/find_key)
- if(isnull(find_key))
- return
-
- var/mob/selected = null
- for(var/mob/M in player_list)
- //Dead people only thanks!
- if((M.stat != 2) || (!M.client))
- continue
- //They need a brain!
- if(istype(M, /mob/living/carbon/human) && !M.get_int_organ(/obj/item/organ/internal/brain))
- continue
-
- if(M.ckey == find_key)
- selected = M
- break
- return selected
+/obj/item/weapon/disk/data/monkey/New()
+ Initialize()
+ buf.types=DNA2_BUF_SE
+ var/list/new_SE=list(0x098,0x3E8,0x403,0x44C,0x39F,0x4B0,0x59D,0x514,0x5FC,0x578,0x5DC,0x640,0x6A4)
+ for(var/i=new_SE.len;i<=DNA_SE_LENGTH;i++)
+ new_SE += rand(1,1024)
+ buf.dna.SE=new_SE
+ buf.dna.SetSEValueRange(MONKEYBLOCK,0xDAC, 0xFFF)
//Disk stuff.
/obj/item/weapon/disk/data/New()
@@ -173,44 +174,47 @@
healthstring = "ERROR"
return healthstring
-/obj/machinery/clonepod/attack_ai(mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/clonepod/attack_hand(mob/user as mob)
- if((isnull(occupant)) || (stat & NOPOWER))
- if(mess)
- go_out()
- return
- if((!isnull(occupant)) && (occupant.stat != 2))
- var/completion = (100 * ((occupant.health + 100) / (heal_level + 100)))
- to_chat(user, "Current clone cycle is [round(completion)]% complete.")
- return
-
//Clonepod
+/obj/machinery/clonepod/examine(mob/user)
+ ..()
+ if(mess)
+ to_chat(user, "It's filled with blood and viscera. You swear you can see it moving...")
+ if(!occupant || stat & (NOPOWER|BROKEN))
+ return
+ if(occupant && occupant.stat != DEAD)
+ to_chat(user, "Current clone cycle is [round(get_completion())]% complete.")
+
+/obj/machinery/clonepod/proc/get_completion()
+ . = (100 * ((occupant.health + 100) / (heal_level + 100)))
+
+/obj/machinery/clonepod/attack_ai(mob/user)
+ return examine(user)
+
+//Radio Announcement
+
+/obj/machinery/clonepod/proc/announce_radio_message(message)
+ if(radio_announce)
+ Radio.autosay(message, name, "Medical", list(z))
+
+
//Start growing a human clone in the pod!
-/obj/machinery/clonepod/proc/growclone(var/datum/dna2/record/R)
+/obj/machinery/clonepod/proc/growclone(datum/dna2/record/R)
if(mess || attempting || panel_open || stat & (NOPOWER|BROKEN))
return 0
- var/datum/mind/clonemind = locate(R.mind)
+ clonemind = locate(R.mind)
if(!istype(clonemind)) //not a mind
return 0
if( clonemind.current && clonemind.current.stat != DEAD ) //mind is associated with a non-dead body
return 0
if(clonemind.active) //somebody is using that mind
- if( ckey(clonemind.key)!=R.ckey )
+ if(ckey(clonemind.key) != R.ckey)
return 0
else
- for(var/mob/M in player_list)
- if(M.ckey == R.ckey)
- if(istype(M, /mob/dead/observer))
- var/mob/dead/observer/G = M
- if(G.can_reenter_corpse)
- break
- if(istype(M, /mob/living/simple_animal))
- if(M in respawnable_list)
- break
- return 0
+ // get_ghost() will fail if they're unable to reenter their body
+ var/mob/dead/observer/G = clonemind.get_ghost()
+ if(!G)
+ return 0
if(biomass >= CLONE_BIOMASS)
biomass -= CLONE_BIOMASS
@@ -219,6 +223,7 @@
attempting = 1 //One at a time!!
locked = 1
+ countdown.start()
eject_wait = 1
spawn(30)
@@ -239,8 +244,16 @@
//Here let's calculate their health so the pod doesn't immediately eject them!!!
H.updatehealth()
- clonemind.transfer_to(H)
- to_chat(H, "Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?")
+ if(grab_ghost_when == CLONER_FRESH_CLONE)
+ clonemind.transfer_to(H)
+ H.ckey = R.ckey
+ to_chat(H, {"Consciousness slowly creeps over you
+ as your body regenerates.
So this is what cloning
+ feels like?"})
+ else if(grab_ghost_when == CLONER_MATURE_CLONE)
+ to_chat(clonemind.current, {"Your body is
+ beginning to regenerate in a cloning pod. You will
+ become conscious when it is complete."})
// -- Mode/mind specific stuff goes here
callHook("clone", list(H))
@@ -298,20 +311,20 @@
biomass += BIOMASS_MEAT_AMOUNT
show_message = 1
if(show_message)
- visible_message("\The [src] sucks in and processes the nearby biomass.")
+ visible_message("[src] sucks in and processes the nearby biomass.")
if(stat & NOPOWER) //Autoeject if power is lost
if(occupant)
locked = 0
go_out()
- return
+ connected_message("Clone Ejected: Loss of power.")
- if((occupant) && (occupant.loc == src))
- if((occupant.stat == DEAD) || (occupant.suiciding) || !occupant.key) //Autoeject corpses and suiciding dudes.
+ else if((occupant) && (occupant.loc == src))
+ if((occupant.stat == DEAD) || (occupant.suiciding)) //Autoeject corpses and suiciding dudes.
locked = 0
+ announce_radio_message("The cloning of [occupant] has been aborted due to unrecoverable tissue failure.")
go_out()
connected_message("Clone Rejected: Deceased.")
- return
else if(occupant.cloneloss > (100 - heal_level))
occupant.Paralyse(4)
@@ -330,48 +343,40 @@
occupant.adjustOxyLoss(-4)
use_power(7500) //This might need tweaking.
- return
else if((occupant.cloneloss <= (100 - heal_level)) && (!eject_wait))
connected_message("Cloning Process Complete.")
+ announce_radio_message("The cloning cycle of [occupant] is complete.")
locked = 0
go_out()
- return
else if((!occupant) || (occupant.loc != src))
occupant = null
if(locked)
locked = 0
- //use_power(200)
- return
-
- return
+ update_icon()
+ use_power(200)
//Let's unlock this early I guess. Might be too early, needs tweaking.
-/obj/machinery/clonepod/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
- if(istype(W, /obj/item/weapon/screwdriver))
- if(occupant || mess || locked)
- to_chat(user, "The maintenance panel is locked.")
+/obj/machinery/clonepod/attackby(obj/item/weapon/W, mob/user, params)
+ if(!(occupant || mess || locked))
+ if(default_deconstruction_screwdriver(user, "[icon_state]_maintenance", "[initial(icon_state)]", W))
return
- default_deconstruction_screwdriver(user, "[icon_state]_maintenance", "[initial(icon_state)]", W)
- return
if(exchange_parts(user, W))
return
- if(istype(W, /obj/item/weapon/crowbar))
- if(panel_open)
- default_deconstruction_crowbar(W)
+ if(default_deconstruction_crowbar(W))
return
- if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
+ if(W.GetID())
if(!check_access(W))
- to_chat(user, "\red Access Denied.")
+ to_chat(user, "Access Denied.")
return
- if((!locked) || (isnull(occupant)))
+ if (!locked || !occupant)
return
- if((occupant.health < -20) && (occupant.stat != 2))
- to_chat(user, "\red Access Refused.")
+ if(occupant.health < -20 && occupant.stat != DEAD)
+ to_chat(user, "Access Refused. Patient status still unstable.")
return
else
locked = 0
@@ -407,16 +412,15 @@
else
..()
-/obj/machinery/clonepod/emag_act(user as mob)
+/obj/machinery/clonepod/emag_act(user)
if(isnull(occupant))
return
to_chat(user, "You force an emergency ejection.")
locked = 0
go_out()
- return
//Put messages in the connected computer's temp var for display.
-/obj/machinery/clonepod/proc/connected_message(var/message)
+/obj/machinery/clonepod/proc/connected_message(message)
if((isnull(connected)) || (!istype(connected, /obj/machinery/computer/cloning)))
return 0
if(!message)
@@ -433,49 +437,56 @@
if(!usr)
return
- if(usr.stat != 0)
+ if(usr.incapacitated())
return
- go_out(usr)
+ go_out()
add_fingerprint(usr)
- return
-/obj/machinery/clonepod/proc/go_out(user)
+/obj/machinery/clonepod/proc/go_out()
+ if(locked)
+ return
+ countdown.stop()
+
if(mess) //Clean that mess and dump those gibs!
- if(occupant)
- return
mess = 0
gibs(loc)
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
update_icon()
return
- if(!(occupant))
- to_chat(user, "The cloning pod is empty!")
+ if(!occupant)
return
- if(locked)
- to_chat(user, "The cloning pod is locked!")
- return
+ if(grab_ghost_when == CLONER_MATURE_CLONE)
+ clonemind.transfer_to(occupant)
+ occupant.grab_ghost()
+ to_chat(occupant, "There is a bright flash!
\
+ You feel like a new being.")
+ occupant.flash_eyes(visual = 1)
- if(occupant.client)
- occupant.client.eye = occupant.client.mob
- occupant.client.perspective = MOB_PERSPECTIVE
occupant.forceMove(get_turf(src))
eject_wait = 0 //If it's still set somehow.
domutcheck(occupant) //Waiting until they're out before possible notransform.
+ occupant.shock_stage = 0 //Reset Shock
occupant = null
update_icon()
- return
/obj/machinery/clonepod/proc/malfunction()
if(occupant)
connected_message("Critical Error!")
+ announce_radio_message("Critical error! Please contact a Thinktronic Systems technician, as your warranty may be affected.")
mess = 1
- occupant.ghostize()
- qdel(occupant)
- occupant = null
update_icon()
- return
+ if(occupant.mind != clonemind)
+ clonemind.transfer_to(occupant)
+ occupant.grab_ghost() // We really just want to make you suffer.
+ to_chat(occupant, {"Agony blazes across your
+ consciousness as your body is torn apart.
+ Is this what dying is like? Yes it is."})
+ playsound(loc, 'sound/machines/warning-buzzer.ogg', 50, 0)
+ occupant << sound('sound/hallucinations/veryfar_noise.ogg',0,1,50)
+ spawn(40)
+ qdel(occupant)
/obj/machinery/clonepod/update_icon()
..()
@@ -485,11 +496,9 @@
else if(mess && !panel_open)
icon_state = "pod_g"
-/obj/machinery/clonepod/relaymove(mob/user as mob)
- if(user.stat)
- return
- go_out()
- return
+/obj/machinery/clonepod/relaymove(mob/user)
+ if(user.stat == CONSCIOUS)
+ go_out()
/obj/machinery/clonepod/emp_act(severity)
if(prob(100/(severity*efficiency))) malfunction()
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 6f4a373580c..4afe9ba3cff 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -323,19 +323,7 @@
qdel(C)
menu = 1
else
- var/mob/selected = find_dead_player("[C.ckey]")
- if(!selected)
- return
- selected << 'sound/machines/chime.ogg' //probably not the best sound but I think it's reasonable
-
- var/answer = alert(selected,"Do you want to return to life?","Cloning","Yes","No")
- if(answer != "No" && pod.growclone(C))
- temp = "Initiating cloning cycle..."
- records.Remove(C)
- qdel(C)
- menu = 1
- else
- temp = "Initiating cloning cycle...
Error: Post-initialisation failed. Cloning cycle aborted."
+ temp = "[C.name] => Initialisation failure."
else
temp = "Error: Data corruption."
diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm
index 8120bae4216..41952adf355 100644
--- a/code/game/machinery/hologram.dm
+++ b/code/game/machinery/hologram.dm
@@ -90,12 +90,15 @@ var/const/HOLOPAD_MODE = 0
user.eyeobj.setLoc(get_turf(src))
else if(!hologram)//If there is no hologram, possibly make one.
activate_holo(user)
- else if(master==user)//If there is a hologram, remove it. But only if the user is the master. Otherwise do nothing.
+ else if(master == user)//If there is a hologram, remove it. But only if the user is the master. Otherwise do nothing.
clear_holo()
return
/obj/machinery/hologram/holopad/proc/activate_holo(mob/living/silicon/ai/user)
if(!(stat & NOPOWER) && user.eyeobj.loc == src.loc)//If the projector has power and client eye is on it.
+ if(user.holo)
+ var/obj/machinery/hologram/holopad/current = user.holo
+ current.clear_holo()
if(!hologram)//If there is not already a hologram.
create_holo(user)//Create one.
src.visible_message("A holographic image of [user] flicks to life right before your eyes!")
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index b003d9ef1d6..519a7177d7a 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -127,13 +127,15 @@ Class Procs:
/obj/machinery/proc/addAtProcessing()
if(use_power)
myArea = get_area_master(src)
-
- machines += src
if(!speed_process)
machine_processing += src
else
fast_processing += src
+/obj/machinery/New() //new
+ machines += src
+ ..()
+
/obj/machinery/Destroy()
if(myArea)
myArea = null
diff --git a/code/modules/arcade/arcade_base.dm b/code/modules/arcade/arcade_base.dm
index d886fa3f4be..3c68c7142f4 100644
--- a/code/modules/arcade/arcade_base.dm
+++ b/code/modules/arcade/arcade_base.dm
@@ -16,9 +16,10 @@
/obj/machinery/arcade/New()
..()
- var/choice = pick(subtypesof(/obj/machinery/arcade))
- new choice(loc)
- qdel(src)
+ if(type == /obj/machinery/arcade) //if you spawn the base-type, it will replace itself with a random subtype for randomness
+ var/choice = pick(subtypesof(/obj/machinery/arcade))
+ new choice(loc)
+ qdel(src)
/obj/machinery/arcade/examine(mob/user)
..(user)
@@ -76,7 +77,7 @@
if(pay_with_cash(C, user))
tokens += 1
return
- if(panel_open&& component_parts && istype(O, /obj/item/weapon/crowbar))
+ if(panel_open && component_parts && istype(O, /obj/item/weapon/crowbar))
default_deconstruction_crowbar(O)
/obj/machinery/arcade/update_icon()
diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm
index 8094ef82966..82f76a04824 100644
--- a/code/modules/client/preference/preferences.dm
+++ b/code/modules/client/preference/preferences.dm
@@ -1148,7 +1148,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
if("name")
var/raw_name = input(user, "Choose your character's name:", "Character Preference") as text|null
if(!isnull(raw_name)) // Check to ensure that the user entered text (rather than cancel.)
- var/new_name = reject_bad_name(raw_name)
+ var/new_name = reject_bad_name(raw_name, 1)
if(new_name)
real_name = new_name
else
diff --git a/code/modules/countdown/countdown.dm b/code/modules/countdown/countdown.dm
new file mode 100644
index 00000000000..2ef85d6a9d7
--- /dev/null
+++ b/code/modules/countdown/countdown.dm
@@ -0,0 +1,69 @@
+/obj/effect/countdown
+ name = "countdown"
+ desc = "We're leaving together\n\
+ But still it's farewell\n\
+ And maybe we'll come back\n\
+ To earth, who can tell?"
+
+ var/displayed_text
+ var/atom/attached_to
+ color = "#ff0000"
+ var/text_size = 4
+ var/started = 0
+ invisibility = INVISIBILITY_OBSERVER
+ anchored = 1
+ layer = 5
+
+/obj/effect/countdown/New(atom/A)
+ . = ..()
+ attach(A)
+
+/obj/effect/countdown/proc/attach(atom/A)
+ attached_to = A
+ loc = get_turf(A)
+
+/obj/effect/countdown/proc/start()
+ if(!started)
+ fast_processing += src
+ started = 1
+
+/obj/effect/countdown/proc/stop()
+ if(started)
+ maptext = null
+ fast_processing -= src
+ started = 0
+
+/obj/effect/countdown/proc/get_value()
+ // Get the value from our atom
+ return
+
+/obj/effect/countdown/process()
+ if(!attached_to || qdeleted(attached_to))
+ qdel(src)
+ forceMove(get_turf(attached_to))
+ var/new_val = get_value()
+ if(new_val == displayed_text)
+ return
+ displayed_text = new_val
+
+ if(displayed_text)
+ maptext = "[displayed_text]"
+ else
+ maptext = null
+
+/obj/effect/countdown/Destroy()
+ attached_to = null
+ fast_processing -= src
+ return ..()
+
+/obj/effect/countdown/clonepod
+ name = "cloning pod countdown"
+ text_size = 1
+
+/obj/effect/countdown/clonepod/get_value()
+ var/obj/machinery/clonepod/C = attached_to
+ if(!istype(C))
+ return
+ else if(C.occupant)
+ var/completion = round(C.get_completion())
+ return completion
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 3ed49f7f0e7..9954b8e12b2 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -263,9 +263,12 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
A.icon = ui_style2icon(client.prefs.UI_style)
A.desc = message
var/old_layer = source.layer
+ var/old_plane = source.plane
source.layer = FLOAT_LAYER
+ source.plane = FLOAT_PLANE
A.overlays += source
source.layer = old_layer
+ source.plane = old_plane
to_chat(src, "(Click to re-enter)")
if(sound)
src << sound(sound)
diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm
index fbb3c5edfd4..81b54bcc3a6 100644
--- a/code/modules/mob/language.dm
+++ b/code/modules/mob/language.dm
@@ -559,6 +559,17 @@
flags = RESTRICTED | HIVEMIND
drone_only = 1
follow = 1
+
+/datum/language/drone
+ name = "Drone"
+ desc = "An encrypted stream of data converted to speech patterns."
+ speech_verb = "states"
+ ask_verb = "queries"
+ exclaim_verb = "declares"
+ key = "]"
+ flags = RESTRICTED
+ follow = 1
+ syllables = list ("beep", "boop")
/datum/language/swarmer
name = "Swarmer"
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 86232208e2e..ed48c229b89 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -854,12 +854,7 @@
modified = 1
spawn()
- if(istype(usr,/mob/living/carbon/human))
- //var/mob/living/carbon/human/U = usr
- sec_hud_set_security_status()
- if(istype(usr,/mob/living/silicon/robot))
- //var/mob/living/silicon/robot/U = usr
- sec_hud_set_security_status()
+ sec_hud_set_security_status()
if(!modified)
to_chat(usr, "\red Unable to locate a data core entry for this person.")
@@ -984,12 +979,7 @@
PDA_Manifest.Cut()
spawn()
- if(istype(usr,/mob/living/carbon/human))
- //var/mob/living/carbon/human/U = usr
- sec_hud_set_security_status()
- if(istype(usr,/mob/living/silicon/robot))
- //var/mob/living/silicon/robot/U = usr
- sec_hud_set_security_status()
+ sec_hud_set_security_status()
if(!modified)
to_chat(usr, "\red Unable to locate a data core entry for this person.")
diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm
index 96a23acf5c7..8288c2dbd8b 100644
--- a/code/modules/mob/living/carbon/human/human_organs.dm
+++ b/code/modules/mob/living/carbon/human/human_organs.dm
@@ -108,11 +108,13 @@
if((E.body_part == HAND_LEFT) || (E.body_part == ARM_LEFT))
if(!l_hand)
continue
- unEquip(l_hand)
+ if(!unEquip(l_hand))
+ continue
else
if(!r_hand)
continue
- unEquip(r_hand)
+ if(!unEquip(r_hand))
+ continue
var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ")
custom_emote(1, "[(species.flags & NO_PAIN) ? "" : emote_scream ]drops what they were holding in their [E.name]!")
@@ -122,11 +124,13 @@
if((E.body_part == HAND_LEFT) || (E.body_part == ARM_LEFT))
if(!l_hand)
continue
- unEquip(l_hand)
+ if(!unEquip(l_hand))
+ continue
else
if(!r_hand)
continue
- unEquip(r_hand)
+ if(!unEquip(r_hand))
+ continue
custom_emote(1, "drops what they were holding, their [E.name] malfunctioning!")
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index c0800a2413d..95f9362684b 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -97,12 +97,7 @@ var/list/ai_verbs_default = list(
var/obj/machinery/camera/portable/builtInCamera
- //var/obj/item/borg/sight/hud/sec/sechud = null
- //var/obj/item/borg/sight/hud/med/healthhud = null
-
var/arrivalmsg = "$name, $rank, has arrived on the station."
- med_hud = DATA_HUD_MEDICAL_BASIC
- sec_hud = DATA_HUD_SECURITY_BASIC
/mob/living/silicon/ai/proc/add_ai_verbs()
src.verbs |= ai_verbs_default
diff --git a/code/modules/mob/living/silicon/login.dm b/code/modules/mob/living/silicon/login.dm
index cc2cb3e8435..fa71b48232e 100644
--- a/code/modules/mob/living/silicon/login.dm
+++ b/code/modules/mob/living/silicon/login.dm
@@ -1,8 +1,15 @@
/mob/living/silicon/Login()
sleeping = 0
if(mind && ticker && ticker.mode)
- ticker.mode.remove_cultist(mind, 1)
+ ticker.mode.remove_traitor(mind)
+ ticker.mode.remove_traitor_mind(mind)
ticker.mode.remove_revolutionary(mind, 1)
- ticker.mode.remove_thrall(mind,0)
+ ticker.mode.remove_cultist(mind, 1)
+ ticker.mode.remove_wizard(mind)
+ ticker.mode.remove_changeling(mind)
+ ticker.mode.remove_vampire(mind)
+ ticker.mode.remove_thrall(mind, 0)
+ ticker.mode.remove_operative(mind)
ticker.mode.remove_shadowling(mind)
+ ticker.mode.remove_abductor(mind)
..()
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index 1089e05862a..0e354b4c4a6 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -13,9 +13,10 @@
lawupdate = 0
density = 0
req_access = list(access_engine, access_robotics)
- local_transmit = 1
ventcrawler = 2
magpulse = 1
+
+ default_language = "Drone"
// We need to keep track of a few module items so we don't need to do list operations
// every time we need them. These get set in New() after the module is chosen.
@@ -39,7 +40,13 @@
..()
remove_language("Robot Talk")
+ remove_language("Galactic Common")
add_language("Drone Talk", 1)
+ add_language("Drone", 1)
+
+ // Disable the microphone wire on Drones
+ if(radio)
+ radio.wires.CutWireIndex(WIRE_TRANSMIT)
if(camera && "Robots" in camera.network)
camera.network.Add("Engineering")
@@ -284,7 +291,7 @@
full_law_reset()
to_chat(src, "
You are a maintenance drone, a tiny-brained robotic repair machine.")
to_chat(src, "You have no individual will, no personality, and no drives or urges other than your laws.")
- to_chat(src, "Use ; to talk to other drones, and say to speak silently to your nearby fellows.")
+ to_chat(src, "Use :d to talk to other drones, and say to speak silently in a language only your fellows understand.")
to_chat(src, "Remember, you are lawed against interference with the crew. Also remember, you DO NOT take orders from the AI.")
to_chat(src, "Don't invade their worksites, don't steal their resources, don't tell them about the changeling in the toilets.")
to_chat(src, "Make sure crew members do not notice you..")
diff --git a/code/modules/mob/living/silicon/robot/drone/drone_say.dm b/code/modules/mob/living/silicon/robot/drone/drone_say.dm
index 5d00d45f97c..0a98e276c43 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_say.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_say.dm
@@ -1,43 +1,11 @@
-/mob/living/silicon/robot/drone/say(var/message)
- if(local_transmit)
- if(src.client)
- if(client.prefs.muted & MUTE_IC)
- to_chat(src, "You cannot send IC messages (muted).")
- return 0
- if(src.client.handle_spam_prevention(message,MUTE_IC))
- return 0
-
- message = sanitize(message)
-
- if(stat == 2)
- return say_dead(message)
-
- if(copytext(message,1,2) == "*")
- return emote(copytext(message,2))
-
- if(copytext(message,1,2) == ";")
- var/datum/language/L = all_languages["Drone Talk"]
- if(istype(L))
- return L.broadcast(src,trim(copytext(message,2)))
-
- //Must be concious to speak
- if(stat)
- return 0
-
- var/list/listeners = hearers(5,src)
- listeners |= src
-
- for(var/mob/living/silicon/D in listeners)
- if(D.client && D.local_transmit)
- to_chat(D, "[src] transmits, \"[message]\"")
-
- for(var/mob/M in player_list)
- if(istype(M, /mob/new_player))
- continue
- else if(M.stat == 2 && M.client && M.client.prefs.toggles & CHAT_GHOSTEARS)
- to_chat(M, "[src] transmits, \"[message]\"")
- return 1
- return ..(message, 0)
+/mob/living/silicon/robot/drone/say(var/message, var/datum/language/speaking = null)
+ if(!speaking)
+ speaking = parse_language(message)
+ if(!speaking)
+ speaking = istype(get_default_language(), /datum/language) ? get_default_language() : all_languages[get_default_language()]
+ message = speaking.key + " " + message; // Prepend key to prevent the message from getting trimmed
+ if(speaking)
+ return ..()
/mob/living/silicon/robot/drone/whisper_say(var/message, var/datum/language/speaking = null, var/alt_name="", var/verb="whispers")
say(message) //drones do not get to whisper, only speak normally
diff --git a/code/modules/mob/living/silicon/robot/login.dm b/code/modules/mob/living/silicon/robot/login.dm
index 84fcd64f849..2dd61d9a2ce 100644
--- a/code/modules/mob/living/silicon/robot/login.dm
+++ b/code/modules/mob/living/silicon/robot/login.dm
@@ -4,9 +4,3 @@
client.hotkeytype = "Cyborg"
regenerate_icons()
show_laws(0)
- if(mind) ticker.mode.remove_cultist(mind)
- if(mind) ticker.mode.remove_revolutionary(mind)
- if(mind) ticker.mode.remove_thrall(mind,0)
- if(mind) ticker.mode.remove_shadowling(mind)
- if(mind) ticker.mode.remove_changeling(mind)
- return
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index afae06678d2..7e771b2f372 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -78,16 +78,13 @@ var/list/robot_verbs_default = list(
var/updating = 0 //portable camera camerachunk update
- hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD,NATIONS_HUD)
+ hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD, NATIONS_HUD)
var/magpulse = 0
var/ionpulse = 0 // Jetpack-like effect.
var/ionpulse_on = 0 // Jetpack-like effect.
var/datum/effect/system/ion_trail_follow/ion_trail // Ionpulse effect.
-
- var/obj/item/borg/sight/hud/sec/sechud = null
- var/obj/item/borg/sight/hud/med/healthhud = null
-
+
var/datum/action/item_action/toggle_research_scanner/scanner = null
/mob/living/silicon/robot/New(loc,var/syndie = 0,var/unfinished = 0, var/alien = 0)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index fcc5c5dcbdd..75bbec89a1b 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -32,7 +32,6 @@
var/sec_hud = DATA_HUD_SECURITY_ADVANCED //Determines the sec hud to use
var/d_hud = DATA_HUD_DIAGNOSTIC //There is only one kind of diag hud
- var/local_transmit //If set, can only speak to others of the same type within a short range.
var/obj/item/device/radio/common_radio
/mob/living/silicon/New()
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 9201d660ae8..c55fa301e10 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -456,11 +456,15 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HARM)
A.jump_target = source
if(!alert_overlay)
var/old_layer = source.layer
+ var/old_plane = source.plane
source.layer = FLOAT_LAYER
+ source.plane = FLOAT_PLANE
A.overlays += source
source.layer = old_layer
+ source.plane = old_plane
else
alert_overlay.layer = FLOAT_LAYER
+ alert_overlay.plane = FLOAT_PLANE
A.overlays += alert_overlay
/mob/proc/switch_to_camera(var/obj/machinery/camera/C)
@@ -510,10 +514,9 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HARM)
search_pda = 0
//Fixes renames not being reflected in objective text
- var/list/O = subtypesof(/datum/objective)
var/length
var/pos
- for(var/datum/objective/objective in O)
+ for(var/datum/objective/objective in all_objectives)
if(objective.target != mind) continue
length = lentext(oldname)
pos = findtextEx(objective.explanation_text, oldname)
diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm
index a5eafacba51..0f587c54bf4 100644
--- a/code/modules/projectiles/ammunition/magazines.dm
+++ b/code/modules/projectiles/ammunition/magazines.dm
@@ -269,7 +269,7 @@
/obj/item/ammo_box/magazine/smgm9mm/update_icon()
..()
- icon_state = "[initial(icon_state)]-[round(ammo_count(),6)]"
+ icon_state = "[initial(icon_state)]-[round(ammo_count()+1,4)]"
/obj/item/ammo_box/magazine/pistolm9mm
name = "pistol magazine (9mm)"
@@ -373,12 +373,12 @@
/obj/item/ammo_box/magazine/toy/smg
name = "foam force SMG magazine"
- icon_state = "smg9mm-30"
+ icon_state = "smg9mm-20"
max_ammo = 20
/obj/item/ammo_box/magazine/toy/smg/update_icon()
..()
- icon_state = "smg9mm-[round(ammo_count(),5)]"
+ icon_state = "smg9mm-[round(ammo_count()+1,4)]"
/obj/item/ammo_box/magazine/toy/smg/riot
ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot
diff --git a/code/modules/projectiles/guns/projectile/toy.dm b/code/modules/projectiles/guns/projectile/toy.dm
index 4efeb570e0f..809647e4186 100644
--- a/code/modules/projectiles/guns/projectile/toy.dm
+++ b/code/modules/projectiles/guns/projectile/toy.dm
@@ -92,8 +92,8 @@
/obj/item/weapon/gun/projectile/shotgun/toy/tommygun
name = "tommy gun"
desc = "Looks almost like the real thing! Great for practicing Drive-bys. Ages 8 and up."
- icon = 'icons/obj/guns/projectile.dmi'
- icon_state = "tommy"
+ icon = 'icons/obj/guns/toy.dmi'
+ icon_state = "tommygun"
item_state = "shotgun"
mag_type = /obj/item/ammo_box/magazine/internal/shot/toy/tommygun
w_class = 2
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 88d5946742a..0ae9b10752e 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -9,6 +9,7 @@
hitsound_wall = "ricochet"
/obj/item/projectile/bullet/weakbullet //beanbag, heavy stamina damage
+ name = "beanbag slug"
damage = 5
stamina = 80
@@ -37,6 +38,7 @@
A.volume += 5 //Because we can
/obj/item/projectile/bullet/weakbullet2 //detective revolver instastuns, but multiple shots are better for keeping punks down
+ name = "rubber bullet"
damage = 5
weaken = 3
stamina = 60
@@ -130,6 +132,7 @@
damage = 35
/obj/item/projectile/bullet/rpellet
+ name = "rubber pellet"
damage = 3
stamina = 25
diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm
index bf107eebd16..ddd53d98fdf 100644
--- a/code/modules/reagents/Chemistry-Machinery.dm
+++ b/code/modules/reagents/Chemistry-Machinery.dm
@@ -829,7 +829,6 @@
//All types that you can put into the grinder to transfer the reagents to the beaker. !Put all recipes above this.!
- /obj/item/weapon/reagent_containers/food/pill = list(),
/obj/item/weapon/reagent_containers/food = list(),
/obj/item/weapon/reagent_containers/honeycomb = list()
)
@@ -895,19 +894,18 @@
to_chat(usr, "The machine cannot hold anymore items.")
return 1
- //Fill machine with the plantbag!
+ //Fill machine with a plantbag!
if(istype(O, /obj/item/weapon/storage/bag/plants))
-
- for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in O.contents)
- O.contents -= G
- G.forceMove(src)
+ var/obj/item/weapon/storage/bag/plants/PB = O
+ for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in PB.contents)
+ PB.remove_from_storage(G, src)
holdingitems += G
if(holdingitems && holdingitems.len >= limit) //Sanity checking so the blender doesn't overfill
to_chat(user, "You empty the plant bag into the All-In-One grinder.")
+ if(!PB.contents.len)
+ to_chat(user, "You empty [PB] into the All-In-One grinder.")
updateUsrDialog()
return 0
diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm
index 6ff39d21b0d..2a36ba585df 100644
--- a/code/modules/recycling/conveyor2.dm
+++ b/code/modules/recycling/conveyor2.dm
@@ -23,12 +23,12 @@
id = "round_end_belt"
-// Auto conveyour is always on unless unpowered
+// Auto conveyor is always on unless unpowered
/obj/machinery/conveyor/auto/New(loc, newdir)
..(loc, newdir)
operating = 1
- setmove()
+ update_move_direction()
/obj/machinery/conveyor/auto/update()
if(stat & BROKEN)
@@ -48,6 +48,10 @@
..(loc)
if(newdir)
dir = newdir
+ update_move_direction()
+
+
+/obj/machinery/conveyor/proc/update_move_direction()
switch(dir)
if(NORTH)
forwards = NORTH
@@ -77,14 +81,13 @@
var/temp = forwards
forwards = backwards
backwards = temp
-
-/obj/machinery/conveyor/proc/setmove()
if(operating == 1)
movedir = forwards
else
movedir = backwards
update()
+
/obj/machinery/conveyor/proc/update()
if(stat & BROKEN)
icon_state = "conveyor-broken"
@@ -113,12 +116,31 @@
step(A,movedir)
CHECK_TICK
+
+
// attack with item, place item on conveyor
-/obj/machinery/conveyor/attackby(var/obj/item/I, mob/user, params)
- if(isrobot(user)) return //Carn: fix for borgs dropping their modules on conveyor belts
- user.drop_item()
- if(I && I.loc) I.loc = src.loc
- return
+/obj/machinery/conveyor/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/weapon/crowbar))
+ if(!(stat & BROKEN))
+ var/obj/item/conveyor_construct/C = new/obj/item/conveyor_construct(src.loc)
+ C.id = id
+ transfer_fingerprints_to(C)
+ to_chat(usr,"You remove the conveyor belt.")
+ qdel(src)
+
+ else if(istype(I, /obj/item/weapon/wrench))
+ if(!(stat & BROKEN))
+ playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
+ dir = turn(dir,-45)
+ update_move_direction()
+ to_chat(user, "You rotate [src].")
+
+ else if(user.a_intent != "harm")
+ if(user.drop_item())
+ I.forceMove(loc)
+ else
+ return ..()
+
// attack with hand, move pulled object onto conveyor
/obj/machinery/conveyor/attack_hand(mob/user as mob)
@@ -176,6 +198,7 @@
var/position = 0 // 0 off, -1 reverse, 1 forward
var/last_pos = -1 // last direction setting
var/operated = 1 // true if just operated
+ var/convdir = 0 // 0 is two way switch, 1 and -1 means one way
var/id = "" // must match conveyor IDs to control them
@@ -184,16 +207,19 @@
speed_process = 1
-/obj/machinery/conveyor_switch/New()
- ..()
+/obj/machinery/conveyor_switch/New(newloc, newid)
+ ..(newloc)
+ if(!id)
+ id = newid
update()
- spawn(5) // allow map load
+ spawn(5)
conveyors = list()
- for(var/obj/machinery/conveyor/C in world)
+ for(var/obj/machinery/conveyor/C in machines)
if(C.id == id)
conveyors += C
+
// update the icon depending on the position
/obj/machinery/conveyor_switch/proc/update()
@@ -215,23 +241,28 @@
for(var/obj/machinery/conveyor/C in conveyors)
C.operating = position
- C.setmove()
+ C.update_move_direction()
CHECK_TICK
+/obj/machinery/conveyor_switch/oneway
+ convdir = 1 //Set to 1 or -1 depending on which way you want the convayor to go. (In other words keep at 1 and set the proper dir on the belts.) - Cargo uses a reverse belt.
+
// attack with hand, switch position
/obj/machinery/conveyor_switch/attack_hand(mob/user)
- if(!allowed(user))
+ if(!allowed(user)) //this is in Para but not TG. I don't think there's any which are set anyway.
to_chat(user, "Access denied.")
return
-
-
+ add_fingerprint(user)
if(position == 0)
- if(last_pos < 0)
- position = 1
- last_pos = 0
+ if(convdir) //is it a oneway switch
+ position = convdir
else
- position = -1
- last_pos = 0
+ if(last_pos < 0)
+ position = 1
+ last_pos = 0
+ else
+ position = -1
+ last_pos = 0
else
last_pos = position
position = 0
@@ -246,22 +277,92 @@
S.update()
CHECK_TICK
-/obj/machinery/conveyor_switch/oneway
- var/convdir = 1 //Set to 1 or -1 depending on which way you want the convayor to go. (In other words keep at 1 and set the proper dir on the belts.)
- desc = "A conveyor control switch. It appears to only go in one direction."
-// attack with hand, switch position
-/obj/machinery/conveyor_switch/oneway/attack_hand(mob/user)
- if(position == 0)
- position = convdir
- else
- position = 0
+/obj/machinery/conveyor_switch/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/weapon/crowbar))
+ var/obj/item/conveyor_switch_construct/C = new/obj/item/conveyor_switch_construct(src.loc)
+ C.id = id
+ transfer_fingerprints_to(C)
+ to_chat(user,"You deattach the conveyor switch.")
+ qdel(src)
- operated = 1
- update()
+ else if(istype(I, /obj/item/device/multitool))
+ update_multitool_menu(user)
+ return 1
- // find any switches with same id as this one, and set their positions to match us
- for(var/obj/machinery/conveyor_switch/S in world)
- if(S.id == src.id)
- S.position = position
- S.update()
+
+/obj/machinery/conveyor_switch/multitool_topic(var/mob/user,var/list/href_list,var/obj/O)
+ ..()
+ if("toggle_logic" in href_list)
+ convdir = !convdir //reverses?
+
+
+/obj/machinery/conveyor_switch/multitool_menu(var/mob/user, var/obj/item/device/multitool/P)
+ return {"
+
+
"}
+
+
+
+//
+// CONVEYOR CONSTRUCTION STARTS HERE
+//
+
+/obj/item/conveyor_construct
+ icon = 'icons/obj/recycling.dmi'
+ icon_state = "conveyor0"
+ name = "conveyor belt assembly"
+ desc = "A conveyor belt assembly."
+ w_class = 4
+ var/id = "" //inherited by the belt
+
+/obj/item/conveyor_construct/attackby(obj/item/I, mob/user, params)
+ ..()
+ if(istype(I, /obj/item/conveyor_switch_construct))
+ to_chat(user, "You link the switch to the conveyor belt assembly.")
+ var/obj/item/conveyor_switch_construct/C = I
+ id = C.id
+
+/obj/item/conveyor_construct/afterattack(atom/A, mob/user, proximity)
+ if(!proximity || user.stat || !istype(A, /turf/simulated/floor) || istype(A, /area/shuttle))
+ return
+ var/cdir = get_dir(A, user)
+ if(A == user.loc)
+ to_chat(user, "You cannot place a conveyor belt under yourself.")
+ return
+ var/obj/machinery/conveyor/C = new/obj/machinery/conveyor(A,cdir)
+ C.id = id
+ transfer_fingerprints_to(C)
+ qdel(src)
+
+/obj/item/conveyor_switch_construct
+ name = "conveyor switch assembly"
+ desc = "A conveyor control switch assembly."
+ icon = 'icons/obj/recycling.dmi'
+ icon_state = "switch-off"
+ w_class = 4
+ var/id = "" //inherited by the switch
+
+/obj/item/conveyor_switch_construct/New()
+ ..()
+ id = rand() //this couldn't possibly go wrong
+
+/obj/item/conveyor_switch_construct/afterattack(atom/A, mob/user, proximity)
+ if(!proximity || user.stat || !istype(A, /turf/simulated/floor) || istype(A, /area/shuttle))
+ return
+ var/found = 0
+ for(var/obj/machinery/conveyor/C in view())
+ if(C.id == src.id)
+ found = 1
+ break
+ if(!found)
+ to_chat(usr, "\icon[src]The conveyor switch did not detect any linked conveyor belts in range.")
+ return
+ var/obj/machinery/conveyor_switch/NC = new/obj/machinery/conveyor_switch(A, id)
+ transfer_fingerprints_to(NC)
+ qdel(src)
+
+/obj/item/weapon/paper/conveyor
+ name = "paper- 'Nano-it-up U-build series, #9: Build your very own conveyor belt, in SPACE'"
+ info = "Congratulations!
You are now the proud owner of the best conveyor set available for space mail order! We at Nano-it-up know you love to prepare your own structures without wasting time, so we have devised a special streamlined assembly procedure that puts all other mail-order products to shame!
Firstly, you need to link the conveyor switch assembly to each of the conveyor belt assemblies. After doing so, you simply need to install the belt assemblies onto the floor, et voila, belt built. Our special Nano-it-up smart switch will detected any linked assemblies as far as the eye can see!
Set single directional switches by using your multitool on the switch after you've installed the switch assembly.
This convenience, you can only have it when you Nano-it-up. Stay nano!
" diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index 8337e0ffaf7..f34d9797124 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -713,3 +713,19 @@ materials = list(MAT_GLASS = 750, MAT_METAL = 250) build_path = /obj/item/weapon/circuitboard/vendor category = list("initial", "Electronics") + +/datum/design/conveyor_belt + name = "Conveyor belt" + id = "conveyor_belt" + build_type = AUTOLATHE + materials = list(MAT_METAL = 5000) + build_path = /obj/item/conveyor_construct + category = list("initial", "Construction") + +/datum/design/conveyor_switch + name = "Conveyor belt switch" + id = "conveyor_switch" + build_type = AUTOLATHE + materials = list(MAT_METAL = 450, MAT_GLASS = 190) + build_path = /obj/item/conveyor_switch_construct + category = list("initial", "Construction") \ No newline at end of file diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index cc6d48dc269..84fc3573bae 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -31,6 +31,18 @@ won't update every console in existence) but it's more of a hassle to do. Also, */ +// Who likes #defines? +// I don't! +// but I gotta add 'em anyways because we have a bias against /const statements for some reason +#define TECH_UPDATE_DELAY 50 +#define DESIGN_UPDATE_DELAY 50 +#define PROTOLATHE_CONSTRUCT_DELAY 32 +#define SYNC_RESEARCH_DELAY 30 +#define DECONSTRUCT_DELAY 24 +#define SYNC_DEVICE_DELAY 20 +#define RESET_RESEARCH_DELAY 20 +#define IMPRINTER_DELAY 16 + /obj/machinery/computer/rdconsole name = "\improper R&D console" icon_screen = "rdcomp" @@ -50,6 +62,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, var/menu = 0 // Current menu. var/submenu = 0 var/wait_message = 0 + var/wait_message_timer = 0 var/id = 0 //ID of the computer (for server restrictions). var/sync = 1 //If sync = 0, it doesn't show up on Server Control Console @@ -139,6 +152,17 @@ won't update every console in existence) but it's more of a hassle to do. Also, ..() SyncRDevices() +/obj/machinery/computer/rdconsole/Destroy() + if(wait_message_timer) + deltimer(wait_message_timer) + wait_message_timer = 0 + return ..() + +/* Instead of calling this every tick, it is only being called when needed +/obj/machinery/computer/rdconsole/process() + griefProtection() +*/ + /obj/machinery/computer/rdconsole/attackby(var/obj/item/weapon/D as obj, var/mob/user as mob, params) //Loading a disk into it. @@ -206,9 +230,9 @@ won't update every console in existence) but it's more of a hassle to do. Also, selected_category = "Viewing Category [href_list["category"]]" else if(href_list["updt_tech"]) //Update the research holder with information from the technology disk. - wait_message = "Updating Database...." - spawn(50) - wait_message = 0 + add_wait_message("Updating Database...", TECH_UPDATE_DELAY) + spawn(TECH_UPDATE_DELAY) + clear_wait_message() files.AddTech2Known(t_disk.stored) nanomanager.update_uis(src) griefProtection() //Update centcom too @@ -231,9 +255,9 @@ won't update every console in existence) but it's more of a hassle to do. Also, submenu = 0 else if(href_list["updt_design"]) //Updates the research holder with design data from the design disk. - wait_message = "Updating Database...." - spawn(50) - wait_message = 0 + add_wait_message("Updating Database...", DESIGN_UPDATE_DELAY) + spawn(DESIGN_UPDATE_DELAY) + clear_wait_message() files.AddDesign2Known(d_disk.blueprint) nanomanager.update_uis(src) griefProtection() //Update centcom too @@ -252,7 +276,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, else if(href_list["copy_design"]) //Copy design data from the research holder to the design disk. // This href ALSO makes me very nervous var/datum/design/D = files.known_designs[href_list["copy_design_ID"]] - if(D) + if(D) // eeeeeep design datums are global be careful! var/autolathe_friendly = 1 for(var/x in D.materials) @@ -299,16 +323,16 @@ won't update every console in existence) but it's more of a hassle to do. Also, var/choice = input("Proceeding will destroy loaded item.") in list("Proceed", "Cancel") if(choice == "Cancel" || !linked_destroy) return linked_destroy.busy = 1 - wait_message = "Processing and Updating Database..." + add_wait_message("Processing and Updating Database...", DECONSTRUCT_DELAY) nanomanager.update_uis(src) flick("d_analyzer_process", linked_destroy) - spawn(24) + spawn(DECONSTRUCT_DELAY) + clear_wait_message() if(linked_destroy) linked_destroy.busy = 0 if(!linked_destroy.hacked) if(!linked_destroy.loaded_item) to_chat(usr, "The destructive analyzer appears to be empty.") - wait_message = 0 menu = 0 submenu = 0 return @@ -318,19 +342,16 @@ won't update every console in existence) but it's more of a hassle to do. Also, if(prob(linked_destroy.loaded_item.reliability)) //If deconstructed item is not reliable enough its just being wasted, else it is pocessed files.UpdateTech(T, temp_tech[T]) //Check if deconstructed item has research levels higher/same/one less than current ones files.UpdateDesigns(linked_destroy.loaded_item, temp_tech, src) //If if such reseach type found all the known designs are checked for having this research type in them - wait_message = 0 //If design have it it gains some reliability - menu = 0 + menu = 0 //If design have it it gains some reliability submenu = 0 else //Same design always gain quality - wait_message = 0 //Crit fail gives the same design a lot of reliability, like really a lot - menu = 2 + menu = 2 //Crit fail gives the same design a lot of reliability, like really a lot submenu = 0 if(linked_lathe) //Also sends salvaged materials to a linked protolathe, if any. for(var/material in linked_destroy.loaded_item.materials) linked_lathe.materials.insert_amount(min((linked_lathe.materials.max_amount - linked_lathe.materials.total_amount), (linked_destroy.loaded_item.materials[material]*(linked_destroy.decon_mod/10))), material) linked_destroy.loaded_item = null else - wait_message = 0 menu = 0 submenu = 0 for(var/obj/I in linked_destroy.contents) @@ -352,26 +373,26 @@ won't update every console in existence) but it's more of a hassle to do. Also, nanomanager.update_uis(src) else if(href_list["sync"]) //Sync the research holder with all the R&D consoles in the game that aren't sync protected. - wait_message = "Updating Database...." if(!sync) to_chat(usr, "You must connect to the network first!") else + add_wait_message("Updating Database...", SYNC_RESEARCH_DELAY) griefProtection() //Putting this here because I dont trust the sync process - spawn(30) + spawn(SYNC_RESEARCH_DELAY) + clear_wait_message() if(src) for(var/obj/machinery/r_n_d/server/S in world) var/server_processed = 0 if(S.disabled) continue - if((id in S.id_with_upload) || istype(S, /obj/machinery/r_n_d/server/centcom)) + if((id in S.id_with_upload) || istype(S, /obj/machinery/r_n_d/server/centcom)) files.push_data(S.files) server_processed = 1 - if(((id in S.id_with_download) && !istype(S, /obj/machinery/r_n_d/server/centcom)) || S.hacked) + if(((id in S.id_with_download) && !istype(S, /obj/machinery/r_n_d/server/centcom)) || S.hacked) S.files.push_data(files) server_processed = 1 if(!istype(S, /obj/machinery/r_n_d/server/centcom) && server_processed) S.produce_heat(100) - wait_message = 0 nanomanager.update_uis(src) else if(href_list["togglesync"]) //Prevents the console from being synced by other consoles. Can still send data. @@ -393,7 +414,6 @@ won't update every console in existence) but it's more of a hassle to do. Also, for(var/M in being_built.materials) power += round(being_built.materials[M] * amount / 5) power = max(2000, power) - wait_message = "Constructing Prototype. Please Wait..." if(linked_lathe.busy) g2g = 0 var/key = usr.key //so we don't lose the info during the spawn delay @@ -404,7 +424,11 @@ won't update every console in existence) but it's more of a hassle to do. Also, if(g2g) //If input is incorrect, nothing happens + var/time_to_construct = PROTOLATHE_CONSTRUCT_DELAY * amount / coeff var/enough_materials = 1 + + time_to_construct /= being_built.lathe_time_factor + add_wait_message("Constructing Prototype. Please Wait...", time_to_construct) linked_lathe.busy = 1 flick("protolathe_n",linked_lathe) use_power(power) @@ -432,9 +456,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, var/P = being_built.build_path //lets save these values before the spawn() just in case. Nobody likes runtimes. var/O = being_built.locked - coeff *= being_built.lathe_time_factor - - spawn(32*amount/coeff) + spawn(time_to_construct) if(g2g) //And if we only fail the material requirements, we still spend time and power for(var/i = 0, i