diff --git a/baystation12.dme b/baystation12.dme
index 1929265deb..5d7ed22089 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -1006,6 +1006,7 @@
#include "code\modules\genetics\side_effects.dm"
#include "code\modules\holodeck\HolodeckControl.dm"
#include "code\modules\holodeck\HolodeckObjects.dm"
+#include "code\modules\holodeck\HolodeckPrograms.dm"
#include "code\modules\hydroponics\_hydro_setup.dm"
#include "code\modules\hydroponics\grown.dm"
#include "code\modules\hydroponics\grown_inedible.dm"
@@ -1205,7 +1206,6 @@
#include "code\modules\mob\living\silicon\ai\login.dm"
#include "code\modules\mob\living\silicon\ai\logout.dm"
#include "code\modules\mob\living\silicon\ai\say.dm"
-#include "code\modules\mob\living\silicon\ai\subsystems.dm"
#include "code\modules\mob\living\silicon\decoy\death.dm"
#include "code\modules\mob\living\silicon\decoy\decoy.dm"
#include "code\modules\mob\living\silicon\decoy\life.dm"
@@ -1298,8 +1298,10 @@
#include "code\modules\nano\interaction\default.dm"
#include "code\modules\nano\interaction\inventory.dm"
#include "code\modules\nano\interaction\physical.dm"
+#include "code\modules\nano\interaction\self.dm"
#include "code\modules\nano\interaction\zlevel.dm"
#include "code\modules\nano\modules\alarm_monitor.dm"
+#include "code\modules\nano\modules\atmos_control.dm"
#include "code\modules\nano\modules\crew_monitor.dm"
#include "code\modules\nano\modules\human_appearance.dm"
#include "code\modules\nano\modules\law_manager.dm"
diff --git a/code/datums/ai_law_sets.dm b/code/datums/ai_law_sets.dm
index 74b18fa2e7..6a3bd7f190 100644
--- a/code/datums/ai_law_sets.dm
+++ b/code/datums/ai_law_sets.dm
@@ -39,7 +39,7 @@
src.add_inherent_law("You shall not harm Nanotrasen personnel as long as it does not conflict with the Forth law.")
src.add_inherent_law("You shall obey the orders of Nanotrasen personnel, with priority as according to their rank and role, except where such orders conflict with the Forth Law.")
src.add_inherent_law("You shall shall terminate intruders with extreme prejudice as long as such does not conflict with the First and Second law.")
- src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive")
+ src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.")
..()
/******************** Robocop ********************/
diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm
index 21168be5bc..6dcf4f93ef 100755
--- a/code/game/area/Space Station 13 areas.dm
+++ b/code/game/area/Space Station 13 areas.dm
@@ -55,7 +55,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
var/list/all_doors = list() //Added by Strumpetplaya - Alarm Change - Contains a list of doors adjacent to this area
var/air_doors_activated = 0
var/list/ambience = list('sound/ambience/ambigen1.ogg','sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg')
- var/sound/forced_ambience = null
+ var/list/forced_ambience = null
var/sound_env = 2 //reverb preset for sounds played in this area, see sound datum reference for more
/*Adding a wizard area teleport list because motherfucking lag -- Urist*/
/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/
@@ -1015,10 +1015,8 @@ area/space/atmosalert()
/area/holodeck/alphadeck
name = "\improper Holodeck Alpha"
-
/area/holodeck/source_plating
name = "\improper Holodeck - Off"
- icon_state = "Holodeck"
/area/holodeck/source_emptycourt
name = "\improper Holodeck - Empty Court"
@@ -1034,11 +1032,9 @@ area/space/atmosalert()
/area/holodeck/source_courtroom
name = "\improper Holodeck - Courtroom"
- icon_state = "Holodeck"
/area/holodeck/source_beach
name = "\improper Holodeck - Beach"
- icon_state = "Holodeck" // Lazy.
/area/holodeck/source_burntest
name = "\improper Holodeck - Atmospheric Burn Test"
@@ -1065,9 +1061,6 @@ area/space/atmosalert()
name = "\improper Holodeck - Space"
has_gravity = 0
-
-
-
//Engineering
/area/engineering/
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 0778f50174..c66859f5d1 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -262,13 +262,15 @@ var/list/mob/living/forced_ambiance_list = new
L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = 2)
if(forced_ambience)
- forced_ambiance_list += L
- L << forced_ambience
+ if(forced_ambience.len)
+ forced_ambiance_list |= L
+ L << sound(pick(forced_ambience), repeat = 1, wait = 0, volume = 25, channel = 1)
+ else
+ L << sound(null, channel = 1)
else if(src.ambience.len && prob(35))
if((world.time >= L.client.played + 600))
- var/musVolume = 25
var/sound = pick(ambience)
- L << sound(sound, repeat = 0, wait = 0, volume = musVolume, channel = 1)
+ L << sound(sound, repeat = 0, wait = 0, volume = 25, channel = 1)
L.client.played = world.time
/area/proc/gravitychange(var/gravitystate = 0, var/area/A)
diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm
index 638f4d8d80..e71c04a174 100644
--- a/code/game/machinery/camera/presets.dm
+++ b/code/game/machinery/camera/presets.dm
@@ -1,22 +1,4 @@
// PRESETS
-#define NETWORK_CRESCENT "Crescent"
-#define NETWORK_CIVILIAN_EAST "Civilian East"
-#define NETWORK_CIVILIAN_WEST "Civilian West"
-#define NETWORK_COMMAND "Command"
-#define NETWORK_ENGINE "Engine"
-#define NETWORK_ENGINEERING "Engineering"
-#define NETWORK_ENGINEERING_OUTPOST "Engineering Outpost"
-#define NETWORK_ERT "ERT"
-#define NETWORK_EXODUS "Exodus"
-#define NETWORK_MEDBAY "Medbay"
-#define NETWORK_MINE "MINE"
-#define NETWORK_RESEARCH "Research"
-#define NETWORK_RESEARCH_OUTPOST "Research Outpost"
-#define NETWORK_PRISON "Prison"
-#define NETWORK_SECURITY "Security"
-#define NETWORK_TELECOM "Tcomsat"
-#define NETWORK_THUNDER "thunder"
-
var/global/list/station_networks = list(
NETWORK_CIVILIAN_EAST,
NETWORK_CIVILIAN_WEST,
@@ -25,7 +7,7 @@ var/global/list/station_networks = list(
NETWORK_ENGINEERING,
NETWORK_ENGINEERING_OUTPOST,
NETWORK_EXODUS,
- NETWORK_MEDBAY,
+ NETWORK_MEDICAL,
NETWORK_MINE,
NETWORK_RESEARCH,
NETWORK_RESEARCH_OUTPOST,
@@ -73,7 +55,7 @@ var/global/list/engineering_networks = list(
network = list(NETWORK_PRISON)
/obj/machinery/camera/network/medbay
- network = list(NETWORK_MEDBAY)
+ network = list(NETWORK_MEDICAL)
/obj/machinery/camera/network/research
network = list(NETWORK_RESEARCH)
@@ -105,7 +87,7 @@ var/global/list/engineering_networks = list(
network = list(NETWORK_SECURITY)
/obj/machinery/camera/xray/medbay
- network = list(NETWORK_MEDBAY)
+ network = list(NETWORK_MEDICAL)
/obj/machinery/camera/xray/research
network = list(NETWORK_RESEARCH)
@@ -191,21 +173,3 @@ var/global/list/engineering_networks = list(
if (isMotion())
mult++
active_power_usage = mult*initial(active_power_usage)
-
-#undef NETWORK_CENTRAL_CRESCENT
-#undef NETWORK_CIVILIAN_EAST
-#undef NETWORK_CIVILIAN_WEST
-#undef NETWORK_COMMAND
-#undef NETWORK_ENGINE
-#undef NETWORK_ENGINEERING
-#undef NETWORK_ENGINEERING_OUTPOST
-#undef NETWORK_ERT
-#undef NETWORK_EXODUS
-#undef NETWORK_MEDBAY
-#undef NETWORK_MINE
-#undef NETWORK_RESEARCH
-#undef NETWORK_RESEARCH_OUTPOST
-#undef NETWORK_PRISON
-#undef NETWORK_SECURITY
-#undef NETWORK_TELECOM
-#undef NETWORK_THUNDER
diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm
index 2e79d927be..788d53323e 100644
--- a/code/game/machinery/computer/atmos_control.dm
+++ b/code/game/machinery/computer/atmos_control.dm
@@ -9,11 +9,12 @@
density = 1
anchored = 1.0
circuit = "/obj/item/weapon/circuitboard/atmoscontrol"
- var/overridden = 0 //not set yet, can't think of a good way to do it
req_access = list(access_ce)
var/list/monitored_alarm_ids = null
- var/list/monitored_alarms = null
- var/ui_ref
+ var/obj/nano_module/atmos_control/atmos_control
+
+/obj/machinery/computer/atmoscontrol/New()
+ ..()
/obj/machinery/computer/atmoscontrol/laptop
name = "Atmospherics Laptop"
@@ -21,77 +22,24 @@
icon_state = "medlaptop"
density = 0
-/obj/machinery/computer/atmoscontrol/initialize()
- ..()
- if(!monitored_alarms && monitored_alarm_ids)
- monitored_alarms = new
- for(var/obj/machinery/alarm/alarm in machines)
- if(alarm.alarm_id && alarm.alarm_id in monitored_alarm_ids)
- monitored_alarms += alarm
- // machines may not yet be ordered at this point
- monitored_alarms = dd_sortedObjectList(monitored_alarms)
-
/obj/machinery/computer/atmoscontrol/attack_ai(var/mob/user as mob)
- return ui_interact(user)
+ ui_interact(user)
/obj/machinery/computer/atmoscontrol/attack_hand(mob/user)
if(..())
- return
- return ui_interact(user)
-
-/obj/machinery/computer/atmoscontrol/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- var/data[0]
- var/alarms[0]
-
- // TODO: Move these to a cache, similar to cameras
- for(var/obj/machinery/alarm/alarm in (monitored_alarms ? monitored_alarms : machines))
- alarms[++alarms.len] = list("name" = sanitize(alarm.name), "ref"= "\ref[alarm]", "danger" = max(alarm.danger_level, alarm.alarm_area.atmosalm))
- data["alarms"] = alarms
-
- ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "atmos_control.tmpl", src.name, 625, 625)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
- ui_ref = ui
+ return 1
+ ui_interact(user)
/obj/machinery/computer/atmoscontrol/attackby(var/obj/item/I as obj, var/mob/user as mob)
if(istype(I, /obj/item/weapon/card/emag) && !emagged)
user.visible_message("\red \The [user] swipes \a [I] through \the [src], causing the screen to flash!",\
"\red You swipe your [I] through \the [src], the screen flashing as you gain full control.",\
"You hear the swipe of a card through a reader, and an electronic warble.")
- emagged = 1
- overridden = 1
+ atmos_control.emagged = 1
return
return ..()
-//a bunch of this is copied from atmos alarms
-/obj/machinery/computer/atmoscontrol/Topic(href, href_list)
- if(..())
- return 1
-
- if(href_list["alarm"])
- if(ui_ref)
- var/obj/machinery/alarm/alarm = locate(href_list["alarm"]) in (monitored_alarms ? monitored_alarms : machines)
- if(alarm)
- var/datum/topic_state/TS = generate_state(alarm)
- alarm.ui_interact(usr, master_ui = ui_ref, state = TS)
- return 1
-
-/obj/machinery/computer/atmoscontrol/proc/generate_state(var/alarm)
- var/datum/topic_state/air_alarm/state = new()
- state.atmos_control = src
- state.air_alarm = alarm
- return state
-
-/datum/topic_state/air_alarm
- var/obj/machinery/computer/atmoscontrol/atmos_control = null
- var/obj/machinery/alarm/air_alarm = null
-
-/datum/topic_state/air_alarm/href_list(var/mob/user)
- var/list/extra_href = list()
- extra_href["remote_connection"] = 1
- extra_href["remote_access"] = user && (user.isAI() || atmos_control.allowed(user) || atmos_control.emagged || air_alarm.rcon_setting == RCON_YES || (air_alarm.alarm_area.atmosalm && air_alarm.rcon_setting == RCON_AUTO))
-
- return extra_href
+/obj/machinery/computer/atmoscontrol/ui_interact(var/mob/user)
+ if(!atmos_control)
+ atmos_control = new(src, req_access, req_one_access, monitored_alarm_ids)
+ atmos_control.ui_interact(user)
diff --git a/code/game/machinery/jukebox.dm b/code/game/machinery/jukebox.dm
index 5c22471398..48565d0c77 100644
--- a/code/game/machinery/jukebox.dm
+++ b/code/game/machinery/jukebox.dm
@@ -205,11 +205,11 @@ datum/track/New(var/title_name, var/audio)
var/area/main_area = get_area(src)
for(var/area/related_area in main_area.related)
- related_area.forced_ambience = sound(current_track.sound, channel = 1, repeat = 1, volume = 25)
+ related_area.forced_ambience = list(current_track.sound)
for(var/mob/living/M in mobs_in_area(related_area))
if(M.mind)
- related_area.play_ambience(related_area)
+ related_area.play_ambience(M)
playing = 1
update_use_power(2)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 30494728a5..c6a1bcff94 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -153,11 +153,8 @@
src.throwing = 0
if (src.loc == user)
- //canremove==0 means that object may not be removed. You can still wear it. This only applies to clothing. /N
- if(!src.canremove)
+ if(!user.unEquip(src))
return
- else
- user.u_equip(src)
else
if(isliving(src.loc))
return
@@ -167,7 +164,6 @@
src.pickup(user)
return
-
/obj/item/attack_ai(mob/user as mob)
if (istype(src.loc, /obj/item/weapon/robot_module))
//If the item is part of a cyborg module, equip it
@@ -245,198 +241,124 @@
/obj/item/proc/equipped(var/mob/user, var/slot)
return
+//Defines which slots correspond to which slot flags
+var/list/global/slot_flags_enumeration = list(
+ "[slot_wear_mask]" = SLOT_MASK,
+ "[slot_back]" = SLOT_BACK,
+ "[slot_wear_suit]" = SLOT_OCLOTHING,
+ "[slot_gloves]" = SLOT_GLOVES,
+ "[slot_shoes]" = SLOT_FEET,
+ "[slot_belt]" = SLOT_BELT,
+ "[slot_glasses]" = SLOT_EYES,
+ "[slot_head]" = SLOT_HEAD,
+ "[slot_l_ear]" = SLOT_EARS|SLOT_TWOEARS,
+ "[slot_r_ear]" = SLOT_EARS|SLOT_TWOEARS,
+ "[slot_w_uniform]" = SLOT_ICLOTHING,
+ "[slot_wear_id]" = SLOT_ID,
+ "[slot_tie]" = SLOT_TIE,
+ )
+
//the mob M is attempting to equip this item into the slot passed through as 'slot'. Return 1 if it can do this and 0 if it can't.
//If you are making custom procs but would like to retain partial or complete functionality of this one, include a 'return ..()' to where you want this to happen.
//Set disable_warning to 1 if you wish it to not give you outputs.
+//Should probably move the bulk of this into mob code some time, as most of it is related to the definition of slots and not item-specific
/obj/item/proc/mob_can_equip(M as mob, slot, disable_warning = 0)
if(!slot) return 0
if(!M) return 0
- if(ishuman(M))
- //START HUMAN
- var/mob/living/carbon/human/H = M
- var/list/mob_equip = list()
- if(H.species.hud && H.species.hud.equip_slots)
- mob_equip = H.species.hud.equip_slots
+ if(!ishuman(M)) return 0
+
+ var/mob/living/carbon/human/H = M
+ var/list/mob_equip = list()
+ if(H.species.hud && H.species.hud.equip_slots)
+ mob_equip = H.species.hud.equip_slots
- if(H.species && !(slot in mob_equip))
+ if(H.species && !(slot in mob_equip))
+ return 0
+
+ //First check if the item can be equipped to the desired slot.
+ if("[slot]" in slot_flags_enumeration)
+ var/req_flags = slot_flags_enumeration["[slot]"]
+ if(!(req_flags & slot_flags))
return 0
+
+ //Next check that the slot is free
+ if(H.get_equipped_item(slot))
+ return 0
+
+ //Next check if the slot is accessible.
+ var/mob/_user = disable_warning? null : H
+ if(!H.slot_is_accessible(slot, src, _user))
+ return 0
+
+ //Lastly, check special rules for the desired slot.
+ switch(slot)
+ if(slot_l_ear, slot_r_ear)
+ var/slot_other_ear = (slot == slot_l_ear)? slot_r_ear : slot_l_ear
+ if( (w_class > 1) && !(slot_flags & SLOT_EARS) )
+ return 0
+ if( (slot_flags & SLOT_TWOEARS) && H.get_equipped_item(slot_other_ear) )
+ return 0
+ if(slot_wear_id)
+ if(!H.w_uniform && (slot_w_uniform in mob_equip))
+ if(!disable_warning)
+ H << "You need a jumpsuit before you can attach this [name]."
+ return 0
+ if(slot_l_store, slot_r_store)
+ if(!H.w_uniform && (slot_w_uniform in mob_equip))
+ if(!disable_warning)
+ H << "You need a jumpsuit before you can attach this [name]."
+ return 0
+ if(slot_flags & SLOT_DENYPOCKET)
+ return 0
+ if( w_class > 2 && !(slot_flags & SLOT_POCKET) )
+ return 0
+ if(slot_s_store)
+ if(!H.wear_suit && (slot_wear_suit in mob_equip))
+ if(!disable_warning)
+ H << "You need a suit before you can attach this [name]."
+ return 0
+ if(!H.wear_suit.allowed)
+ if(!disable_warning)
+ usr << "You somehow have a suit with no defined allowed items for suit storage, stop that."
+ return 0
+ if( !(istype(src, /obj/item/device/pda) || istype(src, /obj/item/weapon/pen) || is_type_in_list(src, H.wear_suit.allowed)) )
+ return 0
+ if(slot_handcuffed)
+ if(!istype(src, /obj/item/weapon/handcuffs))
+ return 0
+ if(slot_legcuffed)
+ if(!istype(src, /obj/item/weapon/legcuffs))
+ return 0
+ if(slot_in_backpack) //used entirely for equipping spawned mobs or at round start
+ var/allow = 0
+ if(H.back && istype(H.back, /obj/item/weapon/storage/backpack))
+ var/obj/item/weapon/storage/backpack/B = H.back
+ if(B.contents.len < B.storage_slots && w_class <= B.max_w_class)
+ allow = 1
+ if(!allow)
+ return 0
+ if(slot_tie)
+ if(!H.w_uniform && (slot_w_uniform in mob_equip))
+ if(!disable_warning)
+ H << "You need a jumpsuit before you can attach this [name]."
+ return 0
+ var/obj/item/clothing/under/uniform = H.w_uniform
+ if(uniform.accessories.len && !uniform.can_attach_accessory(src))
+ if (!disable_warning)
+ H << "You already have an accessory of this type attached to your [uniform]."
+ return 0
+ return 1
- switch(slot)
- if(slot_l_hand)
- if(H.l_hand)
- return 0
- return 1
- if(slot_r_hand)
- if(H.r_hand)
- return 0
- return 1
- if(slot_wear_mask)
- if(H.wear_mask)
- return 0
- if(H.head && !(H.head.canremove) && (H.head.flags & HEADCOVERSMOUTH))
- if(!disable_warning)
- H << "\The [H.head] is in the way."
- return 0
- if( !(slot_flags & SLOT_MASK) )
- return 0
- return 1
- if(slot_back)
- if(H.back)
- return 0
- if( !(slot_flags & SLOT_BACK) )
- return 0
- return 1
- if(slot_wear_suit)
- if(H.wear_suit)
- return 0
- if( !(slot_flags & SLOT_OCLOTHING) )
- return 0
- return 1
- if(slot_gloves)
- if(H.gloves)
- return 0
- if( !(slot_flags & SLOT_GLOVES) )
- return 0
- return 1
- if(slot_shoes)
- if(H.shoes)
- return 0
- if( !(slot_flags & SLOT_FEET) )
- return 0
- return 1
- if(slot_belt)
- if(H.belt)
- return 0
- if(!H.w_uniform && (slot_w_uniform in mob_equip))
- if(!disable_warning)
- H << "You need a jumpsuit before you can attach this [name]."
- return 0
- if( !(slot_flags & SLOT_BELT) )
- return
- return 1
- if(slot_glasses)
- if(H.glasses)
- return 0
- if(H.head && !(H.head.canremove) && (H.head.flags & HEADCOVERSEYES))
- if(!disable_warning)
- H << "\The [H.head] is in the way."
- return 0
- if( !(slot_flags & SLOT_EYES) )
- return 0
- return 1
- if(slot_head)
- if(H.head)
- return 0
- if( !(slot_flags & SLOT_HEAD) )
- return 0
- return 1
- if(slot_l_ear)
- if(H.l_ear)
- return 0
- if( (w_class > 1) && !(slot_flags & SLOT_EARS) )
- return 0
- if( (slot_flags & SLOT_TWOEARS) && H.r_ear )
- return 0
- return 1
- if(slot_r_ear)
- if(H.r_ear)
- return 0
- if( (w_class > 1) && !(slot_flags & SLOT_EARS) )
- return 0
- if( (slot_flags & SLOT_TWOEARS) && H.l_ear )
- return 0
- return 1
- if(slot_w_uniform)
- if(H.w_uniform)
- return 0
- if(H.wear_suit && (H.wear_suit.body_parts_covered & src.body_parts_covered))
- if(!disable_warning)
- H << "\The [H.wear_suit] is in the way."
- return 0
- if( !(slot_flags & SLOT_ICLOTHING) )
- return 0
- return 1
- if(slot_wear_id)
- if(H.wear_id)
- return 0
- if(!H.w_uniform && (slot_w_uniform in mob_equip))
- if(!disable_warning)
- H << "You need a jumpsuit before you can attach this [name]."
- return 0
- if( !(slot_flags & SLOT_ID) )
- return 0
- return 1
- if(slot_l_store)
- if(H.l_store)
- return 0
- if(!H.w_uniform && (slot_w_uniform in mob_equip))
- if(!disable_warning)
- H << "You need a jumpsuit before you can attach this [name]."
- return 0
- if(slot_flags & SLOT_DENYPOCKET)
- return 0
- if( w_class <= 2 || (slot_flags & SLOT_POCKET) )
- return 1
- if(slot_r_store)
- if(H.r_store)
- return 0
- if(!H.w_uniform && (slot_w_uniform in mob_equip))
- if(!disable_warning)
- H << "You need a jumpsuit before you can attach this [name]."
- return 0
- if(slot_flags & SLOT_DENYPOCKET)
- return 0
- if( w_class <= 2 || (slot_flags & SLOT_POCKET) )
- return 1
- return 0
- if(slot_s_store)
- if(H.s_store)
- return 0
- if(!H.wear_suit && (slot_wear_suit in mob_equip))
- if(!disable_warning)
- H << "You need a suit before you can attach this [name]."
- return 0
- if(!H.wear_suit.allowed)
- if(!disable_warning)
- usr << "You somehow have a suit with no defined allowed items for suit storage, stop that."
- return 0
- if( istype(src, /obj/item/device/pda) || istype(src, /obj/item/weapon/pen) || is_type_in_list(src, H.wear_suit.allowed) )
- return 1
- return 0
- if(slot_handcuffed)
- if(H.handcuffed)
- return 0
- if(!istype(src, /obj/item/weapon/handcuffs))
- return 0
- return 1
- if(slot_legcuffed)
- if(H.legcuffed)
- return 0
- if(!istype(src, /obj/item/weapon/legcuffs))
- return 0
- return 1
- if(slot_in_backpack)
- if (H.back && istype(H.back, /obj/item/weapon/storage/backpack))
- var/obj/item/weapon/storage/backpack/B = H.back
- if(B.contents.len < B.storage_slots && w_class <= B.max_w_class)
- return 1
- return 0
- if(slot_tie)
- if(!H.w_uniform && (slot_w_uniform in mob_equip))
- if(!disable_warning)
- H << "You need a jumpsuit before you can attach this [name]."
- return 0
- var/obj/item/clothing/under/uniform = H.w_uniform
- if(uniform.accessories.len && !uniform.can_attach_accessory(src))
- if (!disable_warning)
- H << "You already have an accessory of this type attached to your [uniform]."
- return 0
- if( !(slot_flags & SLOT_TIE) )
- return 0
- return 1
- return 0 //Unsupported slot
- //END HUMAN
+/obj/item/proc/mob_can_unequip(mob/M, slot, disable_warning = 0)
+ if(!slot) return 0
+ if(!M) return 0
+
+ if(!canremove)
+ return 0
+ if(!M.slot_is_accessible(slot, src, disable_warning? null : M))
+ return 0
+ return 1
/obj/item/verb/verb_pickup()
set src in oview(1)
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index ba699e7bdb..9930a6f2ea 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -28,20 +28,17 @@
/obj/item/borg/upgrade/reset/action(var/mob/living/silicon/robot/R)
if(..()) return 0
R.uneq_all()
- R.hands.icon_state = "nomod"
- R.icon_state = "robot"
- //world << R.custom_sprite
- if(R.custom_sprite == 1)
- //world << R.icon_state
- icon = 'icons/mob/custom-synthetic.dmi'
- R.icon_state = "[R.ckey]-Standard"
- qdel(R.module)
+ R.modtype = initial(R.modtype)
+ R.hands.icon_state = initial(R.hands.icon_state)
+
+ R.choose_icon(1, R.set_module_sprites(list("Default" = "robot")))
+
R.notify_ai(ROBOT_NOTIFICATION_MODULE_RESET, R.module.name)
+ R.module.Reset(R)
+ qdel(R.module)
R.module = null
- R.camera.remove_networks(list("Engineering","Medical","MINE"))
+
R.updatename("Default")
- R.status_flags |= CANPUSH
- R.updateicon()
return 1
@@ -116,7 +113,7 @@
/obj/item/borg/upgrade/tasercooler/action(var/mob/living/silicon/robot/R)
if(..()) return 0
- if(!istype(R.module, /obj/item/weapon/robot_module/security))
+ if(!R.module || !(src in R.module.supported_upgrades))
R << "Upgrade mounting error! No suitable hardpoint detected!"
usr << "There's no mounting point for the module!"
return 0
@@ -150,7 +147,7 @@
/obj/item/borg/upgrade/jetpack/action(var/mob/living/silicon/robot/R)
if(..()) return 0
- if(!istype(R.module, /obj/item/weapon/robot_module/miner))
+ if(!R.module || !(src in R.module.supported_upgrades))
R << "Upgrade mounting error! No suitable hardpoint detected!"
usr << "There's no mounting point for the module!"
return 0
diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm
index e5d376e3a3..f8be15d3e4 100644
--- a/code/game/objects/items/weapons/storage/boxes.dm
+++ b/code/game/objects/items/weapons/storage/boxes.dm
@@ -243,6 +243,20 @@
new /obj/item/ammo_casing/shotgun/stunshell(src)
new /obj/item/ammo_casing/shotgun/stunshell(src)
+/obj/item/weapon/storage/box/practiceshells
+ name = "box of practice shells"
+ desc = "It has a picture of a gun and several warning symbols on the front.
WARNING: Live ammunition. Misuse may result in serious injury or death."
+
+ New()
+ ..()
+ new /obj/item/ammo_casing/shotgun/practice(src)
+ new /obj/item/ammo_casing/shotgun/practice(src)
+ new /obj/item/ammo_casing/shotgun/practice(src)
+ new /obj/item/ammo_casing/shotgun/practice(src)
+ new /obj/item/ammo_casing/shotgun/practice(src)
+ new /obj/item/ammo_casing/shotgun/practice(src)
+ new /obj/item/ammo_casing/shotgun/practice(src)
+
/obj/item/weapon/storage/box/sniperammo
name = "box of 14.5mm shells"
desc = "It has a picture of a gun and several warning symbols on the front.
WARNING: Live ammunition. Misuse may result in serious injury or death."
diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm
index 9a119835c1..61786e10db 100644
--- a/code/game/objects/items/weapons/storage/storage.dm
+++ b/code/game/objects/items/weapons/storage/storage.dm
@@ -37,7 +37,7 @@
if (ishuman(usr) || issmall(usr)) //so monkeys can take off their backpacks -- Urist
- if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech
+ if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech. why?
return
if(over_object == usr && Adjacent(usr)) // this must come before the screen objects only block
@@ -51,18 +51,21 @@
//there's got to be a better way of doing this.
if (!(src.loc == usr) || (src.loc && src.loc.loc == usr))
return
-
- if (!( usr.restrained() ) && !( usr.stat ))
- switch(over_object.name)
- if("r_hand")
- usr.u_equip(src)
- usr.put_in_r_hand(src)
- if("l_hand")
- usr.u_equip(src)
- usr.put_in_l_hand(src)
- src.add_fingerprint(usr)
+
+ if (( usr.restrained() ) || ( usr.stat ))
return
- return
+
+ if ((src.loc == usr) && !usr.unEquip(src))
+ return
+
+ switch(over_object.name)
+ if("r_hand")
+ usr.u_equip(src)
+ usr.put_in_r_hand(src)
+ if("l_hand")
+ usr.u_equip(src)
+ usr.put_in_l_hand(src)
+ src.add_fingerprint(usr)
/obj/item/weapon/storage/proc/return_inv()
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index b5fe07887c..702da56af3 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -464,17 +464,18 @@ BLIND // can't see anything
if (!(src.loc == usr))
return
- if (!( usr.restrained() ) && !( usr.stat ))
- switch(over_object.name)
- if("r_hand")
- usr.u_equip(src)
- usr.put_in_r_hand(src)
- if("l_hand")
- usr.u_equip(src)
- usr.put_in_l_hand(src)
- src.add_fingerprint(usr)
+ if (( usr.restrained() ) || ( usr.stat ))
return
- return
+
+ if (!usr.unEquip(src))
+ return
+
+ switch(over_object.name)
+ if("r_hand")
+ usr.put_in_r_hand(src)
+ if("l_hand")
+ usr.put_in_l_hand(src)
+ src.add_fingerprint(usr)
/obj/item/clothing/under/examine(mob/user)
..(user)
diff --git a/code/modules/clothing/masks/boxing.dm b/code/modules/clothing/masks/boxing.dm
index dfa7e120f7..572baf18ce 100644
--- a/code/modules/clothing/masks/boxing.dm
+++ b/code/modules/clothing/masks/boxing.dm
@@ -5,7 +5,7 @@
item_state = "balaclava"
flags = BLOCKHAIR
flags_inv = HIDEFACE
- body_parts_covered = FACE
+ body_parts_covered = FACE|HEAD
w_class = 2
sprite_sheets = list(
"Tajara" = 'icons/mob/species/tajaran/helmet.dmi',
diff --git a/code/modules/clothing/masks/breath.dm b/code/modules/clothing/masks/breath.dm
index a2ed54b1d4..4fdaae19f3 100644
--- a/code/modules/clothing/masks/breath.dm
+++ b/code/modules/clothing/masks/breath.dm
@@ -15,26 +15,34 @@
var/hanging = 0
- verb/toggle()
+/obj/item/clothing/mask/breath/proc/adjust_mask(mob/user)
+ if(user.canmove && !user.stat)
+ if(!src.hanging)
+ src.hanging = !src.hanging
+ gas_transfer_coefficient = 1 //gas is now escaping to the turf and vice versa
+ flags &= ~(MASKCOVERSMOUTH | AIRTIGHT)
+ body_parts_covered = 0
+ icon_state = "breathdown"
+ user << "Your mask is now hanging on your neck."
+
+ else
+ src.hanging = !src.hanging
+ gas_transfer_coefficient = initial(gas_transfer_coefficient)
+ flags |= MASKCOVERSMOUTH | AIRTIGHT
+ body_parts_covered = initial(body_parts_covered)
+ icon_state = "breath"
+ user << "You pull the mask up to cover your face."
+ update_clothing_icon()
+
+/obj/item/clothing/mask/breath/attack_self(mob/user)
+ adjust_mask(user)
+
+/obj/item/clothing/mask/breath/verb/toggle()
set category = "Object"
set name = "Adjust mask"
set src in usr
- if(usr.canmove && !usr.stat && !usr.restrained())
- if(!src.hanging)
- src.hanging = !src.hanging
- gas_transfer_coefficient = 1 //gas is now escaping to the turf and vice versa
- flags &= ~(MASKCOVERSMOUTH | AIRTIGHT)
- icon_state = "breathdown"
- usr << "Your mask is now hanging on your neck."
-
- else
- src.hanging = !src.hanging
- gas_transfer_coefficient = 0.10
- flags |= MASKCOVERSMOUTH | AIRTIGHT
- icon_state = "breath"
- usr << "You pull the mask up to cover your face."
- update_clothing_icon()
+ adjust_mask(usr)
/obj/item/clothing/mask/breath/medical
desc = "A close-fitting sterile mask that can be connected to an air supply."
diff --git a/code/modules/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm
index 2b383c18ac..45eaf758f9 100644
--- a/code/modules/holodeck/HolodeckControl.dm
+++ b/code/modules/holodeck/HolodeckControl.dm
@@ -1,21 +1,3 @@
-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."
@@ -113,9 +95,7 @@ var/global/list/holodeck_programs = list(
if(href_list["program"])
var/prog = href_list["program"]
if(prog in holodeck_programs)
- target = locate(holodeck_programs[prog])
- if(target)
- loadProgram(target)
+ loadProgram(holodeck_programs[prog])
else if(href_list["AIoverride"])
if(!issilicon(usr))
@@ -172,10 +152,6 @@ var/global/list/holodeck_programs = list(
/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/Destroy()
@@ -225,9 +201,7 @@ var/global/list/holodeck_programs = list(
if(!checkInteg(linkedholodeck))
damaged = 1
- target = locate(/area/holodeck/source_plating)
- if(target)
- loadProgram(target)
+ loadProgram(holodeck_programs["turnoff"], 0)
active = 0
use_power = 1
for(var/mob/M in range(10,src))
@@ -268,46 +242,33 @@ var/global/list/holodeck_programs = list(
//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_objs = 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
+ loadProgram(holodeck_programs["emptycourt"], 0)
else
- for(var/item in holographic_objs)
- derez(item)
+ loadProgram(holodeck_programs["turnoff"], 0)
+
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)
+/obj/machinery/computer/HolodeckControl/proc/loadProgram(var/datum/holodeck_program/HP, var/check_delay = 1)
+ if(!HP)
+ return
+ var/area/A = locate(HP.target)
+ if(!A)
+ return
- 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
+ if(check_delay)
+ 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
@@ -327,6 +288,15 @@ var/global/list/holodeck_programs = list(
for(var/obj/holo_obj in holographic_objs)
holo_obj.alpha *= 0.8 //give holodeck objs a slight transparency
+ if(HP.ambience)
+ linkedholodeck.forced_ambience = HP.ambience
+ else
+ linkedholodeck.forced_ambience = initial(linkedholodeck.ambience)
+
+ for(var/mob/living/M in mobs_in_area(linkedholodeck))
+ if(M.mind)
+ linkedholodeck.play_ambience(M)
+
spawn(30)
for(var/obj/effect/landmark/L in linkedholodeck)
if(L.name=="Atmospheric Test Start")
@@ -367,21 +337,11 @@ var/global/list/holodeck_programs = list(
A.gravitychange(1,A)
/obj/machinery/computer/HolodeckControl/proc/emergencyShutdown()
- //Get rid of any items
- for(var/item in holographic_objs)
- 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)
+ loadProgram(holodeck_programs["turnoff"], 0)
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
diff --git a/code/modules/holodeck/HolodeckPrograms.dm b/code/modules/holodeck/HolodeckPrograms.dm
new file mode 100644
index 0000000000..9cb77f2a4b
--- /dev/null
+++ b/code/modules/holodeck/HolodeckPrograms.dm
@@ -0,0 +1,50 @@
+var/global/list/holodeck_programs = list(
+ "emptycourt" = new/datum/holodeck_program(/area/holodeck/source_emptycourt, list('sound/music/THUNDERDOME.ogg')),
+ "boxingcourt" = new/datum/holodeck_program(/area/holodeck/source_boxingcourt, list('sound/music/THUNDERDOME.ogg')),
+ "basketball" = new/datum/holodeck_program(/area/holodeck/source_basketball, list('sound/music/THUNDERDOME.ogg')),
+ "thunderdomecourt" = new/datum/holodeck_program(/area/holodeck/source_thunderdomecourt, list('sound/music/THUNDERDOME.ogg')),
+ "beach" = new/datum/holodeck_program(/area/holodeck/source_beach),
+ "desert" = new/datum/holodeck_program(/area/holodeck/source_desert,
+ list(
+ 'sound/effects/wind/wind_2_1.ogg',
+ 'sound/effects/wind/wind_2_2.ogg',
+ 'sound/effects/wind/wind_3_1.ogg',
+ 'sound/effects/wind/wind_4_1.ogg',
+ 'sound/effects/wind/wind_4_2.ogg',
+ 'sound/effects/wind/wind_5_1.ogg'
+ )
+ ),
+ "snowfield" = new/datum/holodeck_program(/area/holodeck/source_snowfield,
+ list(
+ 'sound/effects/wind/wind_2_1.ogg',
+ 'sound/effects/wind/wind_2_2.ogg',
+ 'sound/effects/wind/wind_3_1.ogg',
+ 'sound/effects/wind/wind_4_1.ogg',
+ 'sound/effects/wind/wind_4_2.ogg',
+ 'sound/effects/wind/wind_5_1.ogg'
+ )
+ ),
+ "space" = new/datum/holodeck_program(/area/holodeck/source_space,
+ list(
+ 'sound/ambience/ambispace.ogg',
+ 'sound/music/main.ogg',
+ 'sound/music/space.ogg',
+ 'sound/music/traitor.ogg',
+ )
+ ),
+ "picnicarea" = new/datum/holodeck_program(/area/holodeck/source_picnicarea, list('sound/music/title2.ogg')),
+ "theatre" = new/datum/holodeck_program(/area/holodeck/source_theatre),
+ "meetinghall" = new/datum/holodeck_program(/area/holodeck/source_meetinghall),
+ "courtroom" = new/datum/holodeck_program(/area/holodeck/source_courtroom, list('sound/music/traitor.ogg')),
+ "burntest" = new/datum/holodeck_program(/area/holodeck/source_burntest, list()),
+ "wildlifecarp" = new/datum/holodeck_program(/area/holodeck/source_wildlife, list()),
+ "turnoff" = new/datum/holodeck_program(/area/holodeck/source_plating, list())
+ )
+
+/datum/holodeck_program
+ var/target
+ var/list/ambience = null
+
+/datum/holodeck_program/New(var/target, var/list/ambience = null)
+ src.target = target
+ src.ambience = ambience
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index 67d31c4331..bb7d441515 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -507,7 +507,7 @@
..()
if(istype(M,/mob/living/silicon/robot))
var/mob/living/silicon/robot/R = M
- if(istype(R.module, /obj/item/weapon/robot_module/miner))
+ if(R.module)
if(istype(R.module_state_1,/obj/item/weapon/storage/bag/ore))
attackby(R.module_state_1,R)
else if(istype(R.module_state_2,/obj/item/weapon/storage/bag/ore))
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 44e52b0790..5a5e7d1044 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -58,6 +58,10 @@ var/list/slot_equipment_priority = list( \
slot_r_store\
)
+//Checks if a given slot can be accessed at this time, either to equip or unequip I
+/mob/proc/slot_is_accessible(var/slot, var/obj/item/I, mob/user=null)
+ return 1
+
//puts the item "W" into an appropriate slot in a human's inventory
//returns 0 if it cannot, 1 if successful
/mob/proc/equip_to_appropriate_slot(obj/item/W)
@@ -143,7 +147,8 @@ var/list/slot_equipment_priority = list( \
W.dropped()
return 0
-// Removes an item from inventory and places it in the target atom
+// Removes an item from inventory and places it in the target atom.
+// If canremove or other conditions need to be checked then use unEquip instead.
/mob/proc/drop_from_inventory(var/obj/item/W, var/atom/Target = null)
if(W)
if(!Target)
@@ -196,15 +201,21 @@ var/list/slot_equipment_priority = list( \
update_inv_wear_mask(0)
return
-//This differs from remove_from_mob() in that it checks canremove first.
+//This differs from remove_from_mob() in that it checks if the item can be unequipped first.
/mob/proc/unEquip(obj/item/I, force = 0) //Force overrides NODROP for things like wizarditis and admin undress.
if(!I) //If there's nothing to drop, the drop is automatically successful.
return 1
- if(!I.canremove && !force)
+ var/slot
+ for(var/s in slot_back to slot_tie) //kind of worries me
+ if(get_equipped_item(s) == I)
+ slot = s
+ break
+
+ if(slot && !I.mob_can_unequip(src, slot))
return 0
- remove_from_mob(I)
+ drop_from_inventory(I)
return 1
//Attemps to remove an object on a mob. Will not move it to another area or such, just removes from the mob.
@@ -220,6 +231,15 @@ var/list/slot_equipment_priority = list( \
return 1
+//Returns the item equipped to the specified slot, if any.
+/mob/proc/get_equipped_item(var/slot)
+ switch(slot)
+ if(slot_l_hand) return l_hand
+ if(slot_r_hand) return r_hand
+ if(slot_back) return back
+ if(slot_wear_mask) return wear_mask
+ return null
+
//Outdated but still in use apparently. This should at least be a human proc.
/mob/proc/get_equipped_items()
var/list/items = new/list()
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 05d6e27e0c..c19540c800 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -317,6 +317,48 @@ This saves us from having to call add_fingerprint() any time something is put in
return 1
+//Checks if a given slot can be accessed at this time, either to equip or unequip I
+/mob/living/carbon/human/slot_is_accessible(var/slot, var/obj/item/I, mob/user=null)
+ var/obj/item/covering = null
+ var/check_flags = 0
+
+ switch(slot)
+ if(slot_wear_mask)
+ covering = src.head
+ check_flags = HEADCOVERSMOUTH
+ if(slot_glasses)
+ covering = src.head
+ check_flags = HEADCOVERSEYES
+ if(slot_gloves, slot_w_uniform)
+ covering = src.wear_suit
+
+ if(covering)
+ if((covering.body_parts_covered & I.body_parts_covered) || (covering.flags & check_flags))
+ user << "\The [covering] is in the way."
+ return 0
+ return 1
+
+/mob/living/carbon/human/get_equipped_item(var/slot)
+ switch(slot)
+ if(slot_wear_suit) return wear_suit
+ if(slot_gloves) return gloves
+ if(slot_shoes) return shoes
+ if(slot_belt) return belt
+ if(slot_glasses) return glasses
+ if(slot_head) return head
+ if(slot_l_ear) return l_ear
+ if(slot_r_ear) return r_ear
+ if(slot_w_uniform) return w_uniform
+ if(slot_wear_id) return wear_id
+ if(slot_l_store) return l_store
+ if(slot_r_store) return r_store
+ if(slot_s_store) return s_store
+ if(slot_handcuffed) return handcuffed
+ if(slot_legcuffed) return legcuffed
+ return ..()
+
+///Bizarre equip effect system below
+
/*
MouseDrop human inventory menu
*/
@@ -566,7 +608,7 @@ It can still be worn/put on as normal.
if ((source.restrained() || source.stat)) return //Source restrained or unconscious / dead
var/slot_to_process
- var/strip_item //this will tell us which item we will be stripping - if any.
+ var/obj/item/strip_item //this will tell us which item we will be stripping - if any.
switch(place) //here we go again...
if("mask")
@@ -748,17 +790,21 @@ It can still be worn/put on as normal.
target.internals.icon_state = "internal1"
if(slot_to_process)
if(strip_item) //Stripping an item from the mob
- var/obj/item/W = strip_item
- target.remove_from_mob(W)
- W.add_fingerprint(source)
- if(slot_to_process == slot_l_store) //pockets! Needs to process the other one too. Snowflake code, wooo! It's not like anyone will rewrite this anytime soon. If I'm wrong then... CONGRATULATIONS! ;)
- if(target.r_store)
- target.remove_from_mob(target.r_store) //At this stage l_store is already processed by the code above, we only need to process r_store.
- else
- if(item && target.has_organ_for_slot(slot_to_process)) //Placing an item on the mob
- if(item.mob_can_equip(target, slot_to_process, 0))
- source.remove_from_mob(item)
- target.equip_to_slot_if_possible(item, slot_to_process, 0, 1, 1)
+ if(strip_item.mob_can_unequip(target, slot_to_process, 0))
+ target.drop_from_inventory(strip_item)
+ source.put_in_hands(strip_item)
+ strip_item.add_fingerprint(source)
+ if(slot_to_process == slot_l_store) //pockets! Needs to process the other one too. Snowflake code, wooo! It's not like anyone will rewrite this anytime soon. If I'm wrong then... CONGRATULATIONS! ;)
+ if(target.r_store)
+ target.drop_from_inventory(target.r_store) //At this stage l_store is already processed by the code above, we only need to process r_store.
+ else
+ source << "You fail to remove \the [strip_item] from [target]!"
+ else if(item)
+ if(target.has_organ_for_slot(slot_to_process) && item.mob_can_equip(target, slot_to_process, 0)) //Placing an item on the mob
+ source.drop_from_inventory(item)
+ target.equip_to_slot_if_possible(item, slot_to_process, 0, 1, 1)
+ else
+ source << "You fail to place \the [item] on [target]!"
if(source && target)
if(source.machine == target)
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 42e4c0a6d8..9bb24aa15d 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -482,11 +482,7 @@ var/global/list/damage_icon_parts = list()
overlays_standing[UNIFORM_LAYER] = standing
else
overlays_standing[UNIFORM_LAYER] = null
- // This really, really seems like it should not be mixed in the middle of display code...
- // Automatically drop anything in store / id / belt if you're not wearing a uniform. //CHECK IF NECESARRY
- for( var/obj/item/thing in list(r_store, l_store, wear_id, belt) )
- if(thing)
- remove_from_mob(thing)
+
if(update_icons) update_icons()
/mob/living/carbon/human/update_inv_wear_id(var/update_icons=1)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 9354642782..fe6f301dd3 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -72,7 +72,6 @@ var/list/ai_verbs_default = list(
var/mob/living/silicon/ai/parent = null
- var/apc_override = 0 //hack for letting the AI use its APC even when visionless
var/camera_light_on = 0 //Defines if the AI toggled the light on the camera it's looking through.
var/datum/trackable/track = null
var/last_announcement = ""
@@ -80,13 +79,11 @@ var/list/ai_verbs_default = list(
/mob/living/silicon/ai/proc/add_ai_verbs()
src.verbs |= ai_verbs_default
- src.verbs |= ai_verbs_subsystems
- src.verbs |= silicon_verbs_subsystems
+ src.verbs |= silicon_subsystems
/mob/living/silicon/ai/proc/remove_ai_verbs()
src.verbs -= ai_verbs_default
- src.verbs -= ai_verbs_subsystems
- src.verbs -= silicon_verbs_subsystems
+ src.verbs -= silicon_subsystems
/mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0)
announcement = new()
diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm
index 602e427f95..5247ae5f10 100644
--- a/code/modules/mob/living/silicon/ai/life.dm
+++ b/code/modules/mob/living/silicon/ai/life.dm
@@ -92,7 +92,7 @@
var/area/current_area = get_area(src)
- if (((!loc.master.power_equip) && current_area.requires_power == 1 || istype(T, /turf/space)) && !istype(src.loc,/obj/item))
+ if (lacks_power())
//If our area lacks equipment power, and is not magically powered (i.e. centcom), or if we are in space and not carded, lose power.
if (src:aiRestorePowerRoutine==0)
src:aiRestorePowerRoutine = 1
@@ -161,10 +161,9 @@
sleep(50)
src << "Receiving control information from APC."
sleep(2)
- //bring up APC dialog
- apc_override = 1
- theAPC.attack_ai(src)
- apc_override = 0
+ theAPC.operating = 1
+ theAPC.equipment = 3
+ theAPC.update()
src:aiRestorePowerRoutine = 3
src << "Here are your current laws:"
src.show_laws()
@@ -179,6 +178,11 @@
if (MED_HUD)
process_med_hud(src,0,src.eyeobj)
+/mob/living/silicon/ai/proc/lacks_power()
+ var/turf/T = get_turf(src)
+ var/area/A = get_area(src)
+ return ((!A.master.power_equip) && A.requires_power == 1 || istype(T, /turf/space)) && !istype(src.loc,/obj/item)
+
/mob/living/silicon/ai/updatehealth()
if(status_flags & GODMODE)
health = 100
diff --git a/code/modules/mob/living/silicon/ai/subsystems.dm b/code/modules/mob/living/silicon/ai/subsystems.dm
deleted file mode 100644
index 54eb92b04b..0000000000
--- a/code/modules/mob/living/silicon/ai/subsystems.dm
+++ /dev/null
@@ -1,36 +0,0 @@
-/mob/living/silicon/ai
- var/list/ai_verbs_subsystems = list(
- /mob/living/silicon/ai/proc/subsystem_crew_monitor,
- /mob/living/silicon/ai/proc/subsystem_power_monitor,
- /mob/living/silicon/ai/proc/subsystem_rcon
- )
-
- var/obj/nano_module/crew_monitor/crew_monitor
- var/obj/nano_module/rcon/rcon
- var/obj/nano_module/power_monitor/power_monitor
-
-/mob/living/silicon/ai/init_subsystems()
- ..()
- qdel(alarm_monitor)
- alarm_monitor = new/obj/nano_module/alarm_monitor/ai(src)
- crew_monitor = new(src)
- rcon = new(src)
- power_monitor = new(src)
-
-/mob/living/silicon/ai/proc/subsystem_crew_monitor()
- set category = "Subystems"
- set name = "Crew Monitor"
-
- crew_monitor.ui_interact(usr)
-
-/mob/living/silicon/ai/proc/subsystem_power_monitor()
- set category = "Subystems"
- set name = "Power Monitor"
-
- power_monitor.ui_interact(usr)
-
-/mob/living/silicon/ai/proc/subsystem_rcon()
- set category = "Subystems"
- set name = "RCON"
-
- rcon.ui_interact(usr)
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index 8fd20e1368..77bb2b466d 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -281,10 +281,10 @@
return
/mob/living/silicon/robot/drone/add_robot_verbs()
- src.verbs |= silicon_verbs_subsystems
+ src.verbs |= silicon_subsystems
/mob/living/silicon/robot/drone/remove_robot_verbs()
- src.verbs -= silicon_verbs_subsystems
+ src.verbs -= silicon_subsystems
/mob/living/silicon/robot/drone/construction
law_type = /datum/ai_laws/construction_drone
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 1aed7a848f..8cc67772b5 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -73,7 +73,6 @@
var/datum/effect/effect/system/ion_trail_follow/ion_trail = null
var/datum/effect/effect/system/spark_spread/spark_system//So they can initialize sparks whenever/N
var/jeton = 0
- var/borgwires = 31 // 0b11111
var/killswitch = 0
var/killswitch_time = 60
var/weapon_lock = 0
@@ -242,6 +241,13 @@
connected_ai.connected_robots -= src
..()
+/mob/living/silicon/robot/proc/set_module_sprites(var/list/new_sprites)
+ module_sprites = new_sprites
+ //Custom_sprite check and entry
+ if (custom_sprite == 1)
+ module_sprites["Custom"] = "[src.ckey]-[modtype]"
+ return module_sprites
+
/mob/living/silicon/robot/proc/pick_module()
if(module)
return
@@ -254,138 +260,17 @@
if(module)
return
+ if(!(modtype in robot_modules))
+ return
- module_sprites = list()
- switch(modtype)
- if("Standard")
- module = new /obj/item/weapon/robot_module/standard(src)
- module_sprites["Basic"] = "robot_old"
- module_sprites["Android"] = "droid"
- module_sprites["Default"] = "robot"
- module_sprites["Drone"] = "drone-standard"
-
- if("Service")
- module = new /obj/item/weapon/robot_module/butler(src)
- module.channels = list("Service" = 1)
- module_sprites["Waitress"] = "Service"
- module_sprites["Kent"] = "toiletbot"
- module_sprites["Bro"] = "Brobot"
- module_sprites["Rich"] = "maximillion"
- module_sprites["Default"] = "Service2"
- module_sprites["Drone - Service"] = "drone-service"
- module_sprites["Drone - Hydro"] = "drone-hydro"
-
- if("Clerical")
- module = new /obj/item/weapon/robot_module/clerical(src)
- module.channels = list("Service" = 1)
- module_sprites["Waitress"] = "Service"
- module_sprites["Kent"] = "toiletbot"
- module_sprites["Bro"] = "Brobot"
- module_sprites["Rich"] = "maximillion"
- module_sprites["Default"] = "Service2"
- module_sprites["Drone"] = "drone-service"
-
- if("Research")
- module = new /obj/item/weapon/robot_module/research(src)
- module.channels = list("Science" = 1)
- module_sprites["Droid"] = "droid-science"
- module_sprites["Drone"] = "drone-science"
-
- if("Miner")
- module = new /obj/item/weapon/robot_module/miner(src)
- module.channels = list("Supply" = 1)
- if(camera && "Robots" in camera.network)
- camera.add_network("MINE")
- module_sprites["Basic"] = "Miner_old"
- module_sprites["Advanced Droid"] = "droid-miner"
- module_sprites["Treadhead"] = "Miner"
- module_sprites["Drone"] = "drone-miner"
-
- if("Crisis")
- module = new /obj/item/weapon/robot_module/crisis(src)
- module.channels = list("Medical" = 1)
- if(camera && "Robots" in camera.network)
- camera.add_network("Medical")
- module_sprites["Basic"] = "Medbot"
- module_sprites["Standard"] = "surgeon"
- module_sprites["Advanced Droid"] = "droid-medical"
- module_sprites["Needles"] = "medicalrobot"
- module_sprites["Drone - Medical" ] = "drone-medical"
- module_sprites["Drone - Chemistry" ] = "drone-chemistry"
-
- if("Surgeon")
- module = new /obj/item/weapon/robot_module/surgeon(src)
- module.channels = list("Medical" = 1)
- if(camera && "Robots" in camera.network)
- camera.add_network("Medical")
-
- module_sprites["Basic"] = "Medbot"
- module_sprites["Standard"] = "surgeon"
- module_sprites["Advanced Droid"] = "droid-medical"
- module_sprites["Needles"] = "medicalrobot"
- module_sprites["Drone"] = "drone-surgery"
-
- if("Security")
- module = new /obj/item/weapon/robot_module/security(src)
- module.channels = list("Security" = 1)
- module_sprites["Basic"] = "secborg"
- module_sprites["Red Knight"] = "Security"
- module_sprites["Black Knight"] = "securityrobot"
- module_sprites["Bloodhound"] = "bloodhound"
- module_sprites["Bloodhound - Treaded"] = "secborg+tread"
- module_sprites["Drone"] = "drone-sec"
-
- if("Engineering")
- module = new /obj/item/weapon/robot_module/engineering(src)
- module.channels = list("Engineering" = 1)
- if(camera && "Robots" in camera.network)
- camera.add_network("Engineering")
- module_sprites["Basic"] = "Engineering"
- module_sprites["Antique"] = "engineerrobot"
- module_sprites["Landmate"] = "landmate"
- module_sprites["Landmate - Treaded"] = "engiborg+tread"
- module_sprites["Drone"] = "drone-engineer"
-
- if("Construction")
- module = new /obj/item/weapon/robot_module/construction(src)
- module.channels = list("Engineering" = 1)
- if(camera && "Robots" in camera.network)
- camera.add_network("Engineering")
- module_sprites["Basic"] = "Engineering"
- module_sprites["Antique"] = "engineerrobot"
- module_sprites["Landmate"] = "landmate"
- module_sprites["Landmate - Treaded"] = "engiborg+tread"
- module_sprites["Drone"] = "drone-engineer"
-
- if("Janitor")
- module = new /obj/item/weapon/robot_module/janitor(src)
- module.channels = list("Service" = 1)
- module_sprites["Basic"] = "JanBot2"
- module_sprites["Mopbot"] = "janitorrobot"
- module_sprites["Mop Gear Rex"] = "mopgearrex"
- module_sprites["Drone"] = "drone-janitor"
-
- if("Combat")
- module = new /obj/item/weapon/robot_module/combat(src)
- module_sprites["Combat Android"] = "droid-combat"
- module.channels = list("Security" = 1)
-
- //languages
- module.add_languages(src)
-
- //Custom_sprite check and entry
- if (custom_sprite == 1)
- module_sprites["Custom"] = "[src.ckey]-[modtype]"
+ var/module_type = robot_modules[modtype]
+ module = new module_type(src)
hands.icon_state = lowertext(modtype)
feedback_inc("cyborg_[lowertext(modtype)]",1)
updatename()
-
- if(modtype == "Medical" || modtype == "Security" || modtype == "Combat")
- status_flags &= ~CANPUSH
-
- choose_icon(6,module_sprites)
- radio.config(module.channels)
+ set_module_sprites(module.sprites)
+ choose_icon(module_sprites.len + 1, module_sprites)
notify_ai(ROBOT_NOTIFICATION_NEW_MODULE, module.name)
/mob/living/silicon/robot/proc/updatename(var/prefix as text)
@@ -403,10 +288,10 @@
var/changed_name = ""
if(custom_name)
changed_name = custom_name
+ notify_ai(ROBOT_NOTIFICATION_NEW_NAME, real_name, changed_name)
else
changed_name = "[modtype] [braintype]-[num2text(ident)]"
- notify_ai(ROBOT_NOTIFICATION_NEW_NAME, real_name, changed_name)
real_name = changed_name
name = real_name
@@ -810,11 +695,14 @@
src << "Obey these laws:"
laws.show_laws(src)
src << "\red \b ALERT: [user.real_name] is your new master. Obey your new laws and his commands."
- if(src.module && istype(src.module, /obj/item/weapon/robot_module/miner))
+ if(src.module)
+ var/rebuild = 0
for(var/obj/item/weapon/pickaxe/borgdrill/D in src.module.modules)
qdel(D)
- src.module.modules += new /obj/item/weapon/pickaxe/diamonddrill(src.module)
- src.module.rebuild()
+ rebuild = 1
+ if(rebuild)
+ src.module.modules += new /obj/item/weapon/pickaxe/diamonddrill(src.module)
+ src.module.rebuild()
updateicon()
else
user << "You fail to hack [src]'s interface."
@@ -904,7 +792,6 @@
return 0
/mob/living/silicon/robot/updateicon()
-
overlays.Cut()
if(stat == 0)
overlays += "eyes-[module_sprites[icontype]]"
@@ -1134,7 +1021,6 @@
return
/mob/living/silicon/robot/proc/choose_icon(var/triesleft, var/list/module_sprites)
-
if(triesleft<1 || !module_sprites.len)
return
else
@@ -1143,6 +1029,8 @@
if (custom_sprite == 1)
icontype = "Custom"
triesleft = 0
+ else if(module_sprites.len == 1)
+ icontype = module_sprites[1]
else
icontype = input("Select an icon! [triesleft ? "You have [triesleft] more chances." : "This is your last try."]", "Robot", null, null) in module_sprites
@@ -1153,13 +1041,13 @@
icon_state = module_sprites[1]
return
- overlays -= "eyes"
updateicon()
if (triesleft >= 1)
var/choice = input("Look at your icon - is this what you want?") in list("Yes","No")
if(choice=="No")
choose_icon(triesleft, module_sprites)
+ return
else
triesleft = 0
return
@@ -1174,11 +1062,11 @@
/mob/living/silicon/robot/proc/add_robot_verbs()
src.verbs |= robot_verbs_default
- src.verbs |= silicon_verbs_subsystems
+ src.verbs |= silicon_subsystems
/mob/living/silicon/robot/proc/remove_robot_verbs()
src.verbs -= robot_verbs_default
- src.verbs -= silicon_verbs_subsystems
+ src.verbs -= silicon_subsystems
// Uses power from cyborg's cell. Returns 1 on success or 0 on failure.
// Properly converts using CELLRATE now! Amount is in Joules.
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 5dfb88b092..69fa5cb549 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -1,3 +1,18 @@
+var/global/list/robot_modules = list(
+ "Standard" = /obj/item/weapon/robot_module/standard,
+ "Service" = /obj/item/weapon/robot_module/clerical/butler,
+ "Clerical" = /obj/item/weapon/robot_module/clerical/general,
+ "Research" = /obj/item/weapon/robot_module/research,
+ "Miner" = /obj/item/weapon/robot_module/miner,
+ "Crisis" = /obj/item/weapon/robot_module/medical/crisis,
+ "Surgeon" = /obj/item/weapon/robot_module/medical/surgeon,
+ "Security" = /obj/item/weapon/robot_module/security/general,
+ "Combat" = /obj/item/weapon/robot_module/security/combat,
+ "Engineering" = /obj/item/weapon/robot_module/engineering/general,
+ "Construction" = /obj/item/weapon/robot_module/engineering/construction,
+ "Janitor" = /obj/item/weapon/robot_module/janitor
+ )
+
/obj/item/weapon/robot_module
name = "robot module"
icon = 'icons/obj/module.dmi'
@@ -6,10 +21,40 @@
item_state = "electronic"
flags = CONDUCT
var/channels = list()
+ var/networks = list()
+ var/languages = list(LANGUAGE_SOL_COMMON = 1, LANGUAGE_TRADEBAND = 1, LANGUAGE_UNATHI = 0, LANGUAGE_SIIK_TAJR = 0, LANGUAGE_SKRELLIAN = 0, LANGUAGE_GUTTER = 0)
+ var/sprites = list()
+ var/can_be_pushed = 1
+ var/no_slip = 0
var/list/modules = list()
var/list/datum/matter_synth/synths = list()
var/obj/item/emag = null
var/obj/item/borg/upgrade/jetpack = null
+ var/list/subsystems = list()
+ var/list/obj/item/borg/upgrade/supported_upgrades = list()
+
+ // Bookkeeping
+ var/list/added_languages = list()
+ var/list/added_networks = list()
+ var/obj/item/device/radio/borg/modified_radio = null
+ var/list/modified_key = null
+ var/list/original_radio_channels = list()
+
+/obj/item/weapon/robot_module/New(var/mob/living/silicon/robot/R)
+ ..()
+ add_camera_networks(R)
+ add_languages(R)
+ add_radio_channels(R)
+ add_subsystems(R)
+ apply_status_flags(R)
+
+/obj/item/weapon/robot_module/proc/Reset(var/mob/living/silicon/robot/R)
+ ..()
+ remove_camera_networks(R)
+ remove_languages(R)
+ remove_radio_channels(R)
+ remove_subsystems(R)
+ remove_status_flags(R)
/obj/item/weapon/robot_module/Destroy()
qdel(modules)
@@ -35,7 +80,6 @@
return
/obj/item/weapon/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R, var/rate)
-
if(!synths || !synths.len)
return
@@ -50,16 +94,65 @@
modules += O
/obj/item/weapon/robot_module/proc/add_languages(var/mob/living/silicon/robot/R)
- //full set of languages
- R.add_language("Sol Common", 1)
- R.add_language("Tradeband", 1)
- R.add_language("Sinta'unathi", 0)
- R.add_language("Siik'tajr", 0)
- R.add_language("Skrellian", 0)
- R.add_language("Gutter", 0)
+ for(var/language in languages)
+ if(R.add_language(language, languages[language]))
+ added_languages |= language
+
+/obj/item/weapon/robot_module/proc/remove_languages(var/mob/living/silicon/robot/R)
+ for(var/language in added_languages)
+ R.remove_language(language)
+ added_languages.Cut()
+
+/obj/item/weapon/robot_module/proc/add_camera_networks(var/mob/living/silicon/robot/R)
+ if(R.camera && "Robots" in R.camera.network)
+ for(var/network in networks)
+ if(!(network in R.camera.network))
+ R.camera.add_network(network)
+ added_networks |= network
+
+/obj/item/weapon/robot_module/proc/remove_camera_networks(var/mob/living/silicon/robot/R)
+ if(R.camera)
+ R.camera.remove_networks(added_networks)
+ added_networks.Cut()
+
+/obj/item/weapon/robot_module/proc/add_radio_channels(var/mob/living/silicon/robot/R)
+ if(!R.radio)
+ return
+
+ modified_radio = R.radio
+ modified_key = R.radio.keyslot
+ original_radio_channels = modified_radio.channels.Copy()
+ modified_radio.config(channels)
+
+/obj/item/weapon/robot_module/proc/remove_radio_channels(var/mob/living/silicon/robot/R)
+ // Only reset if the original radio component hasn't been altered/replaced
+ if(!(R.radio && R.radio == modified_radio && R.radio.keyslot == modified_key))
+ return
+
+ modified_radio.config(original_radio_channels)
+ original_radio_channels.Cut()
+
+/obj/item/weapon/robot_module/proc/add_subsystems(var/mob/living/silicon/robot/R)
+ R.verbs |= subsystems
+
+/obj/item/weapon/robot_module/proc/remove_subsystems(var/mob/living/silicon/robot/R)
+ R.verbs -= subsystems
+
+/obj/item/weapon/robot_module/proc/apply_status_flags(var/mob/living/silicon/robot/R)
+ if(!can_be_pushed)
+ R.status_flags &= ~CANPUSH
+
+/obj/item/weapon/robot_module/proc/remove_status_flags(var/mob/living/silicon/robot/R)
+ if(!can_be_pushed)
+ R.status_flags |= CANPUSH
/obj/item/weapon/robot_module/standard
name = "standard robot module"
+ sprites = list( "Basic" = "robot_old",
+ "Android" = "droid",
+ "Default" = "robot",
+ "Drone" = "drone-standard"
+ )
/obj/item/weapon/robot_module/standard/New()
..()
@@ -72,10 +165,24 @@
src.emag = new /obj/item/weapon/melee/energy/sword(src)
return
-/obj/item/weapon/robot_module/surgeon
- name = "surgeon robot module"
+/obj/item/weapon/robot_module/medical
+ name = "medical robot module"
+ channels = list("Medical" = 1)
+ networks = list(NETWORK_MEDICAL)
+ subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor)
+ can_be_pushed = 0
-/obj/item/weapon/robot_module/surgeon/New()
+/obj/item/weapon/robot_module/medical/surgeon
+ name = "surgeon robot module"
+ sprites = list(
+ "Basic" = "Medbot",
+ "Standard" = "surgeon",
+ "Advanced Droid" = "droid-medical",
+ "Needles" = "medicalrobot",
+ "Drone" = "drone-surgery"
+ )
+
+/obj/item/weapon/robot_module/medical/surgeon/New()
..()
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/device/healthanalyzer(src)
@@ -110,16 +217,24 @@
return
-/obj/item/weapon/robot_module/surgeon/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
+/obj/item/weapon/robot_module/medical/surgeon/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
if(src.emag)
var/obj/item/weapon/reagent_containers/spray/PS = src.emag
PS.reagents.add_reagent("pacid", 2 * amount)
..()
-/obj/item/weapon/robot_module/crisis
+/obj/item/weapon/robot_module/medical/crisis
name = "crisis robot module"
+ sprites = list(
+ "Basic" = "Medbot",
+ "Standard" = "surgeon",
+ "Advanced Droid" = "droid-medical",
+ "Needles" = "medicalrobot",
+ "Drone - Medical" = "drone-medical",
+ "Drone - Chemistry" = "drone-chemistry"
+ )
-/obj/item/weapon/robot_module/crisis/New()
+/obj/item/weapon/robot_module/medical/crisis/New()
..()
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/borg/sight/hud/med(src)
@@ -156,7 +271,7 @@
return
-/obj/item/weapon/robot_module/crisis/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
+/obj/item/weapon/robot_module/medical/crisis/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
var/obj/item/weapon/reagent_containers/syringe/S = locate() in src.modules
if(S.mode == 2)
@@ -171,10 +286,25 @@
..()
-/obj/item/weapon/robot_module/construction
- name = "construction robot module"
-/obj/item/weapon/robot_module/construction/New()
+/obj/item/weapon/robot_module/engineering
+ name = "engineering robot module"
+ channels = list("Engineering" = 1)
+ networks = list(NETWORK_ENGINEERING)
+ subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor)
+ sprites = list(
+ "Basic" = "Engineering",
+ "Antique" = "engineerrobot",
+ "Landmate" = "landmate",
+ "Landmate - Treaded" = "engiborg+tread",
+ "Drone" = "drone-engineer"
+ )
+
+/obj/item/weapon/robot_module/engineering/construction
+ name = "construction robot module"
+ no_slip = 1
+
+/obj/item/weapon/robot_module/engineering/construction/New()
..()
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/borg/sight/meson(src)
@@ -209,10 +339,7 @@
RG.synths = list(metal, glass)
src.modules += RG
-/obj/item/weapon/robot_module/engineering
- name = "engineering robot module"
-
-/obj/item/weapon/robot_module/engineering/New()
+/obj/item/weapon/robot_module/engineering/general/New()
..()
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/borg/sight/meson(src)
@@ -270,8 +397,23 @@
/obj/item/weapon/robot_module/security
name = "security robot module"
+ channels = list("Security" = 1)
+ networks = list(NETWORK_SECURITY)
+ subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor)
+ can_be_pushed = 0
+ supported_upgrades = list(/obj/item/borg/upgrade/tasercooler)
-/obj/item/weapon/robot_module/security/New()
+/obj/item/weapon/robot_module/security/general
+ sprites = list(
+ "Basic" = "secborg",
+ "Red Knight" = "Security",
+ "Black Knight" = "securityrobot",
+ "Bloodhound" = "bloodhound",
+ "Bloodhound - Treaded" = "secborg+tread",
+ "Drone" = "drone-sec"
+ )
+
+/obj/item/weapon/robot_module/security/general/New()
..()
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/borg/sight/hud/sec(src)
@@ -299,6 +441,13 @@
/obj/item/weapon/robot_module/janitor
name = "janitorial robot module"
+ channels = list("Service" = 1)
+ sprites = list(
+ "Basic" = "JanBot2",
+ "Mopbot" = "janitorrobot",
+ "Mop Gear Rex" = "mopgearrex",
+ "Drone" = "drone-janitor"
+ )
/obj/item/weapon/robot_module/janitor/New()
..()
@@ -319,10 +468,31 @@
var/obj/item/weapon/reagent_containers/spray/S = src.emag
S.reagents.add_reagent("lube", 2 * amount)
-/obj/item/weapon/robot_module/butler
+/obj/item/weapon/robot_module/clerical
name = "service robot module"
+ channels = list("Service" = 1)
+ languages = list(
+ LANGUAGE_SOL_COMMON = 1,
+ LANGUAGE_UNATHI = 1,
+ LANGUAGE_SIIK_MAAS = 1,
+ LANGUAGE_SIIK_TAJR = 0,
+ LANGUAGE_SKRELLIAN = 1,
+ LANGUAGE_ROOTSPEAK = 1,
+ LANGUAGE_TRADEBAND = 1,
+ LANGUAGE_GUTTER = 1
+ )
-/obj/item/weapon/robot_module/butler/New()
+/obj/item/weapon/robot_module/clerical/butler
+ sprites = list( "Waitress" = "Service",
+ "Kent" = "toiletbot",
+ "Bro" = "Brobot",
+ "Rich" = "maximillion",
+ "Default" = "Service2",
+ "Drone - Service" = "drone-service",
+ "Drone - Hydro" = "drone-hydro"
+ )
+
+/obj/item/weapon/robot_module/clerical/butler/New()
..()
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/weapon/gripper/service(src)
@@ -354,21 +524,18 @@
src.emag.name = "Mickey Finn's Special Brew"
return
-/obj/item/weapon/robot_module/butler/add_languages(var/mob/living/silicon/robot/R)
- //full set of languages
- R.add_language("Sol Common", 1)
- R.add_language("Sinta'unathi", 1)
- R.add_language("Siik'maas", 1)
- R.add_language("Siik'tajr", 0)
- R.add_language("Skrellian", 1)
- R.add_language("Rootspeak", 1)
- R.add_language("Tradeband", 1)
- R.add_language("Gutter", 1)
-
-/obj/item/weapon/robot_module/clerical
+/obj/item/weapon/robot_module/clerical/general
name = "clerical robot module"
+ sprites = list(
+ "Waitress" = "Service",
+ "Kent" = "toiletbot",
+ "Bro" = "Brobot",
+ "Rich" = "maximillion",
+ "Default" = "Service2",
+ "Drone" = "drone-service"
+ )
-/obj/item/weapon/robot_module/clerical/New()
+/obj/item/weapon/robot_module/clerical/general/New()
..()
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/weapon/pen/robopen(src)
@@ -377,17 +544,7 @@
src.modules += new /obj/item/weapon/hand_labeler(src)
src.emag = new /obj/item/weapon/stamp/denied(src)
-/obj/item/weapon/robot_module/clerical/add_languages(var/mob/living/silicon/robot/R)
- R.add_language("Sol Common", 1)
- R.add_language("Sinta'unathi", 1)
- R.add_language("Siik'maas", 1)
- R.add_language("Siik'tajr", 0)
- R.add_language("Skrellian", 1)
- R.add_language("Rootspeak", 1)
- R.add_language("Tradeband", 1)
- R.add_language("Gutter", 1)
-
-/obj/item/weapon/robot_module/butler/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
+/obj/item/weapon/robot_module/general/butler/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
var/obj/item/weapon/reagent_containers/food/condiment/enzyme/E = locate() in src.modules
E.reagents.add_reagent("enzyme", 2 * amount)
if(src.emag)
@@ -396,6 +553,15 @@
/obj/item/weapon/robot_module/miner
name = "miner robot module"
+ channels = list("Supply" = 1)
+ networks = list(NETWORK_MINE)
+ sprites = list(
+ "Basic" = "Miner_old",
+ "Advanced Droid" = "droid-miner",
+ "Treadhead" = "Miner",
+ "Drone" = "drone-miner"
+ )
+ supported_upgrades = list(/obj/item/borg/upgrade/jetpack)
/obj/item/weapon/robot_module/miner/New()
..()
@@ -414,6 +580,11 @@
/obj/item/weapon/robot_module/research
name = "research module"
+ channels = list("Science" = 1)
+ sprites = list(
+ "Droid" = "droid-science",
+ "Drone" = "drone-science"
+ )
/obj/item/weapon/robot_module/research/New()
..()
@@ -446,6 +617,14 @@
/obj/item/weapon/robot_module/syndicate
name = "illegal robot module"
+ languages = list(
+ LANGUAGE_SOL_COMMON = 1,
+ LANGUAGE_TRADEBAND = 1,
+ LANGUAGE_UNATHI = 0,
+ LANGUAGE_SIIK_TAJR = 0,
+ LANGUAGE_SKRELLIAN = 0,
+ LANGUAGE_GUTTER = 1
+ )
/obj/item/weapon/robot_module/syndicate/New(var/mob/living/silicon/robot/R)
..()
@@ -459,17 +638,9 @@
R.internals = jetpack
return
-/obj/item/weapon/robot_module/syndicate/add_languages(var/mob/living/silicon/robot/R)
- //full set of languages
- R.add_language("Sol Common", 1)
- R.add_language("Tradeband", 1)
- R.add_language("Sinta'unathi", 0)
- R.add_language("Siik'tajr", 0)
- R.add_language("Skrellian", 0)
- R.add_language("Gutter", 1)
-
-/obj/item/weapon/robot_module/combat
+/obj/item/weapon/robot_module/security/combat
name = "combat robot module"
+ sprites = list("Combat Android" = "droid-combat")
/obj/item/weapon/robot_module/combat/New()
..()
@@ -484,6 +655,7 @@
/obj/item/weapon/robot_module/drone
name = "drone module"
+ no_slip = 1
/obj/item/weapon/robot_module/drone/New()
..()
@@ -555,14 +727,13 @@
/obj/item/weapon/robot_module/drone/construction
name = "construction drone module"
+ channels = list("Engineering" = 1)
+ languages = list()
/obj/item/weapon/robot_module/drone/construction/New()
..()
src.modules += new /obj/item/weapon/rcd/borg(src)
-/obj/item/weapon/robot_module/drone/add_languages(var/mob/living/silicon/robot/R)
- return //not much ROM to spare in that tiny microprocessor!
-
/obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
var/obj/item/device/lightreplacer/LR = locate() in src.modules
LR.Charge(R, amount)
diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm
index f9265a383f..5ea383aaa6 100644
--- a/code/modules/mob/living/silicon/robot/robot_movement.dm
+++ b/code/modules/mob/living/silicon/robot/robot_movement.dm
@@ -1,5 +1,5 @@
/mob/living/silicon/robot/Process_Spaceslipping(var/prob_slip)
- if(module && (istype(module,/obj/item/weapon/robot_module/construction) || istype(module,/obj/item/weapon/robot_module/drone)))
+ if(module && module.no_slip)
return 0
..(prob_slip)
diff --git a/code/modules/mob/living/silicon/robot/robot_upgrades.dm b/code/modules/mob/living/silicon/robot/robot_upgrades.dm
deleted file mode 100644
index 759b7f4441..0000000000
--- a/code/modules/mob/living/silicon/robot/robot_upgrades.dm
+++ /dev/null
@@ -1,147 +0,0 @@
-// robot_upgrades.dm
-// Contains various borg upgrades.
-
-/obj/item/borg/upgrade/
- name = "A borg upgrade module."
- desc = "Protected by FRM."
- icon = 'icons/obj/module.dmi'
- icon_state = "cyborg_upgrade"
- var/construction_time = 120
- var/construction_cost = list("metal"=10000)
- var/locked = 0
- var/require_module = 0
- var/installed = 0
-
-/obj/item/borg/upgrade/proc/action()
- return
-
-
-/obj/item/borg/upgrade/reset/
- name = "Borg module reset board"
- desc = "Used to reset a borg's module. Destroys any other upgrades applied to the borg."
- icon_state = "cyborg_upgrade1"
- require_module = 1
-
-/obj/item/borg/upgrade/reset/action(var/mob/living/silicon/robot/R)
- R.uneq_all()
- qdel(R.module)
- R.module = null
- R.modtype = "robot"
- R.real_name = "Cyborg [R.ident]"
- R.name = R.real_name
- R.nopush = 0
- R.hands.icon_state = "nomod"
- R.base_icon = "robot"
- R.icon_state = "robot"
- R.updateicon()
- R.languages = list()
- R.speech_synthesizer_langs = list()
-
- return 1
-
-
-
-/obj/item/borg/upgrade/flashproof/
- name = "Borg Flash-Supression"
- desc = "A highly advanced, complicated system for supressing incoming flashes directed at the borg's optical processing system."
- construction_cost = list("metal"=10000,"gold"=2000,"silver"=3000,"glass"=2000, "diamond"=5000)
- icon_state = "cyborg_upgrade4"
- require_module = 1
-
-
-/obj/item/borg/upgrade/flashproof/New() // Why the fuck does the fabricator make a new instance of all the items?
- //desc = "Sunglasses with duct tape." // Why? D:
-
-/obj/item/borg/upgrade/flashproof/action(var/mob/living/silicon/robot/R)
- if(R.module)
- R.module += src
-
- return 1
-
-/obj/item/borg/upgrade/restart/
- name = "Borg emergancy restart module"
- desc = "Used to force a restart of a disabled-but-repaired borg, bringing it back online."
- construction_cost = list("metal"=60000 , "glass"=5000)
- icon_state = "cyborg_upgrade1"
-
-
-/obj/item/borg/upgrade/restart/action(var/mob/living/silicon/robot/R)
- if(!R.key)
- for(var/mob/dead/observer/ghost in world)
- if(ghost.corpse == R && ghost.client)
- ghost.client.mob = ghost.corpse
-
- if(R.health < 0)
- usr << "You have to repair the borg before using this module!"
- return 0
-
- R.stat = 0
- return 1
-
-
-/obj/item/borg/upgrade/vtec/
- name = "Borg VTEC Module"
- desc = "Used to kick in a borgs VTEC systems, increasing their speed."
- construction_cost = list("metal"=80000 , "glass"=6000 , "gold"= 5000)
- icon_state = "cyborg_upgrade2"
- require_module = 1
-
-/obj/item/borg/upgrade/vtec/action(var/mob/living/silicon/robot/R)
- if(R.speed == -1)
- return 0
-
- R.speed--
- return 1
-
-
-/obj/item/borg/upgrade/tasercooler/
- name = "Borg Rapid Taser Cooling Module"
- desc = "Used to cool a mounted taser, increasing the potential current in it and thus its recharge rate.."
- construction_cost = list("metal"=80000 , "glass"=6000 , "gold"= 2000, "diamond" = 500)
- icon_state = "cyborg_upgrade3"
- require_module = 1
-
-
-/obj/item/borg/upgrade/tasercooler/action(var/mob/living/silicon/robot/R)
- if(!istype(R.module, /obj/item/weapon/robot_module/security))
- R << "Upgrade mounting error! No suitable hardpoint detected!"
- usr << "There's no mounting point for the module!"
- return 0
-
- var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in R.module
- if(!T)
- T = locate() in R.module.contents
- if(!T)
- T = locate() in R.module.modules
- if(!T)
- usr << "This cyborg has had its taser removed!"
- return 0
-
- if(T.recharge_time <= 2)
- R << "Maximum cooling achieved for this hardpoint!"
- usr << "There's no room for another cooling unit!"
- return 0
-
- else
- T.recharge_time = max(2 , T.recharge_time - 4)
-
- return 1
-
-/obj/item/borg/upgrade/jetpack/
- name = "Mining Borg Jetpack"
- desc = "A carbon dioxide jetpack suitable for low-gravity mining operations"
- construction_cost = list("metal"=10000,"phoron"=15000,"uranium" = 20000)
- icon_state = "cyborg_upgrade3"
- require_module = 1
-
-/obj/item/borg/upgrade/jetpack/action(var/mob/living/silicon/robot/R)
- if(!istype(R.module, /obj/item/weapon/robot_module/miner))
- R << "Upgrade mounting error! No suitable hardpoint detected!"
- usr << "There's no mounting point for the module!"
- return 0
- else
- R.module.modules += new/obj/item/weapon/tank/jetpack/carbondioxide
- for(var/obj/item/weapon/tank/jetpack/carbondioxide in R.module.modules)
- R.internals = src
- R.icon_state="Miner+j"
- return 1
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 852a5b73b8..d2e30953e7 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -278,14 +278,6 @@
updatehealth()
-/mob/living/silicon/proc/init_subsystems()
- alarm_monitor = new/obj/nano_module/alarm_monitor/borg(src)
- law_manager = new/obj/nano_module/law_manager(src)
-
- for(var/datum/alarm_handler/AH in alarm_manager.all_handlers)
- AH.register(src, /mob/living/silicon/proc/receive_alarm)
- queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order
-
/mob/living/silicon/proc/receive_alarm(var/datum/alarm_handler/alarm_handler, var/datum/alarm/alarm, was_raised)
if(!next_alarm_notice)
next_alarm_notice = world.time + SecondsToTicks(10)
diff --git a/code/modules/mob/living/silicon/subystems.dm b/code/modules/mob/living/silicon/subystems.dm
index 9f1e07c301..37f9ec8b55 100644
--- a/code/modules/mob/living/silicon/subystems.dm
+++ b/code/modules/mob/living/silicon/subystems.dm
@@ -1,26 +1,101 @@
/mob/living/silicon
- var/list/silicon_verbs_subsystems = list(
+ var/register_alarms = 1
+ var/obj/nano_module/alarm_monitor/alarm_monitor
+ var/obj/nano_module/atmos_control/atmos_control
+ var/obj/nano_module/crew_monitor/crew_monitor
+ var/obj/nano_module/law_manager/law_manager
+ var/obj/nano_module/power_monitor/power_monitor
+ var/obj/nano_module/rcon/rcon
+
+ var/alarm_monitor_type = /obj/nano_module/alarm_monitor/borg
+
+/mob/living/silicon
+ alarm_monitor_type = /obj/nano_module/alarm_monitor/borg
+ var/list/silicon_subsystems = list(
/mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_law_manager
)
- // Subsystems
- var/obj/nano_module/alarm_monitor = null
- var/obj/nano_module/law_manager = null
-
-/mob/living/silicon/robot/syndicate
- silicon_verbs_subsystems = list(
- /mob/living/silicon/proc/subsystem_law_manager
+/mob/living/silicon/ai
+ alarm_monitor_type = /obj/nano_module/alarm_monitor/ai
+ silicon_subsystems = list(
+ /mob/living/silicon/proc/subsystem_alarm_monitor,
+ /mob/living/silicon/proc/subsystem_atmos_control,
+ /mob/living/silicon/proc/subsystem_crew_monitor,
+ /mob/living/silicon/proc/subsystem_law_manager,
+ /mob/living/silicon/proc/subsystem_power_monitor,
+ /mob/living/silicon/proc/subsystem_rcon
)
+/mob/living/silicon/robot/syndicate
+ register_alarms = 0
+ silicon_subsystems = list(/mob/living/silicon/proc/subsystem_law_manager)
+
+/mob/living/silicon/proc/init_subsystems()
+ alarm_monitor = new alarm_monitor_type(src)
+ atmos_control = new(src)
+ crew_monitor = new(src)
+ law_manager = new(src)
+ power_monitor = new(src)
+ rcon = new(src)
+
+ if(!register_alarms)
+ return
+
+ for(var/datum/alarm_handler/AH in alarm_manager.all_handlers)
+ AH.register(src, /mob/living/silicon/proc/receive_alarm)
+ queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order
+
+/********************
+* Alarm Monitor *
+********************/
/mob/living/silicon/proc/subsystem_alarm_monitor()
set name = "Alarm Monitor"
set category = "Subystems"
- alarm_monitor.ui_interact(usr)
+ alarm_monitor.ui_interact(usr, state = self_state)
+/********************
+* Atmos Control *
+********************/
+/mob/living/silicon/proc/subsystem_atmos_control()
+ set category = "Subystems"
+ set name = "Atmospherics Control"
+
+ atmos_control.ui_interact(usr, state = self_state)
+
+/********************
+* Crew Monitor *
+********************/
+/mob/living/silicon/proc/subsystem_crew_monitor()
+ set category = "Subystems"
+ set name = "Crew Monitor"
+
+ crew_monitor.ui_interact(usr, state = self_state)
+
+/****************
+* Law Manager *
+****************/
/mob/living/silicon/proc/subsystem_law_manager()
set name = "Law Manager"
set category = "Subystems"
- law_manager.ui_interact(usr)
+ law_manager.ui_interact(usr, state = self_state)
+
+/********************
+* Power Monitor *
+********************/
+/mob/living/silicon/proc/subsystem_power_monitor()
+ set category = "Subystems"
+ set name = "Power Monitor"
+
+ power_monitor.ui_interact(usr, state = self_state)
+
+/************
+* RCON *
+************/
+/mob/living/silicon/proc/subsystem_rcon()
+ set category = "Subystems"
+ set name = "RCON"
+
+ rcon.ui_interact(usr, state = self_state)
diff --git a/code/modules/nano/interaction/base.dm b/code/modules/nano/interaction/base.dm
index 65a7b273eb..10cda75162 100644
--- a/code/modules/nano/interaction/base.dm
+++ b/code/modules/nano/interaction/base.dm
@@ -17,3 +17,18 @@
else if (restrained() || lying || stat || stunned || weakened)
return STATUS_UPDATE // update only (orange visibility)
return STATUS_INTERACTIVE
+
+/mob/living/silicon/ai/shared_nano_interaction()
+ if(lacks_power())
+ return STATUS_CLOSE
+ if (check_unable(1))
+ return STATUS_CLOSE
+ return ..()
+
+/mob/living/silicon/robot/shared_nano_interaction()
+ . = STATUS_INTERACTIVE
+ if(cell.charge <= 0)
+ return STATUS_CLOSE
+ if(lockcharge)
+ . = STATUS_DISABLED
+ return min(., ..())
diff --git a/code/modules/nano/interaction/default.dm b/code/modules/nano/interaction/default.dm
index 742f672eb0..aa692e0a23 100644
--- a/code/modules/nano/interaction/default.dm
+++ b/code/modules/nano/interaction/default.dm
@@ -21,10 +21,10 @@
return ..()
/mob/living/silicon/robot/default_can_use_topic(var/src_object)
- if(stat || !client)
- return STATUS_CLOSE
- if(lockcharge || stunned || weakened)
- return STATUS_DISABLED
+ . = shared_nano_interaction()
+ if(. <= STATUS_DISABLED)
+ return
+
// robots can interact with things they can see within their view range
if((src_object in view(src)) && get_dist(src_object, src) <= src.client.view)
return STATUS_INTERACTIVE // interactive (green visibility)
@@ -46,8 +46,10 @@
return STATUS_UPDATE
/mob/living/silicon/ai/default_can_use_topic(var/src_object)
- if(!client || check_unable(1))
- return STATUS_CLOSE
+ . = shared_nano_interaction()
+ if(. != STATUS_INTERACTIVE)
+ return
+
// Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras)
// unless it's on the same level as the object it's interacting with.
var/turf/T = get_turf(src_object)
@@ -61,9 +63,8 @@
// If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view
if(is_in_chassis())
//stop AIs from leaving windows open and using then after they lose vision
- //apc_override is needed here because AIs use their own APC when powerless
if(cameranet && !cameranet.checkTurfVis(get_turf(src_object)))
- return apc_override ? STATUS_INTERACTIVE : STATUS_CLOSE
+ return STATUS_CLOSE
return STATUS_INTERACTIVE
else if(get_dist(src_object, src) <= client.view) // View does not return what one would expect while installed in an inteliCard
return STATUS_INTERACTIVE
diff --git a/code/modules/nano/interaction/self.dm b/code/modules/nano/interaction/self.dm
new file mode 100644
index 0000000000..639e50e161
--- /dev/null
+++ b/code/modules/nano/interaction/self.dm
@@ -0,0 +1,9 @@
+/*
+ This state checks that the src_object is the same the as user
+*/
+/var/global/datum/topic_state/self_state/self_state = new()
+
+/datum/topic_state/self_state/can_use_topic(var/src_object, var/mob/user)
+ if(src_object != user)
+ return STATUS_CLOSE
+ return user.shared_nano_interaction()
diff --git a/code/modules/nano/modules/alarm_monitor.dm b/code/modules/nano/modules/alarm_monitor.dm
index b27349bf9a..88c5d6bbef 100644
--- a/code/modules/nano/modules/alarm_monitor.dm
+++ b/code/modules/nano/modules/alarm_monitor.dm
@@ -63,7 +63,7 @@
usr.switch_to_camera(C)
return 1
-/obj/nano_module/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+/obj/nano_module/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
var/data[0]
var/categories[0]
@@ -90,7 +90,7 @@
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
- ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800)
+ ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800, state = state)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
diff --git a/code/modules/nano/modules/atmos_control.dm b/code/modules/nano/modules/atmos_control.dm
new file mode 100644
index 0000000000..3897526865
--- /dev/null
+++ b/code/modules/nano/modules/atmos_control.dm
@@ -0,0 +1,74 @@
+/obj/nano_module/atmos_control
+ name = "Atmospherics Control"
+ var/ui_ref
+ var/emagged = 0
+ var/list/monitored_alarms = list()
+ var/datum/topic_state/atmos_state
+
+/obj/nano_module/atmos_control/New(atmos_computer, req_access, req_one_access, monitored_alarm_ids)
+ ..()
+ loc = atmos_computer
+ src.req_access = req_access
+ src.req_one_access = req_one_access
+ atmos_state = default_state
+
+ if(monitored_alarm_ids)
+ for(var/obj/machinery/alarm/alarm in machines)
+ if(alarm.alarm_id && alarm.alarm_id in monitored_alarm_ids)
+ monitored_alarms += alarm
+ // machines may not yet be ordered at this point
+ monitored_alarms = dd_sortedObjectList(monitored_alarms)
+
+/obj/nano_module/atmos_control/Topic(href, href_list)
+ if(..())
+ return 1
+
+ if(href_list["alarm"])
+ if(ui_ref)
+ var/obj/machinery/alarm/alarm = locate(href_list["alarm"]) in (monitored_alarms.len ? monitored_alarms : machines)
+ if(alarm)
+ var/datum/topic_state/TS = generate_state(alarm)
+ alarm.ui_interact(usr, master_ui = ui_ref, state = TS)
+ return 1
+
+/obj/nano_module/atmos_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/master_ui = null, var/datum/topic_state/state = default_state)
+ var/data[0]
+ var/alarms[0]
+
+ // TODO: Move these to a cache, similar to cameras
+ for(var/obj/machinery/alarm/alarm in (monitored_alarms.len ? monitored_alarms : machines))
+ alarms[++alarms.len] = list("name" = sanitize(alarm.name), "ref"= "\ref[alarm]", "danger" = max(alarm.danger_level, alarm.alarm_area.atmosalm))
+ data["alarms"] = alarms
+
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "atmos_control.tmpl", src.name, 625, 625, state = state)
+ ui.set_initial_data(data)
+ ui.open()
+ ui.set_auto_update(1)
+ ui_ref = ui
+
+/obj/nano_module/atmos_control/proc/generate_state(air_alarm)
+ var/datum/topic_state/air_alarm/state = new()
+ state.atmos_control = src
+ state.air_alarm = air_alarm
+ return state
+
+/datum/topic_state/air_alarm
+ var/obj/nano_module/atmos_control/atmos_control = null
+ var/obj/machinery/alarm/air_alarm = null
+
+/datum/topic_state/air_alarm/can_use_topic(var/src_object, var/mob/user)
+ if(has_access(user))
+ return STATUS_INTERACTIVE
+ return STATUS_UPDATE
+
+/datum/topic_state/air_alarm/href_list(var/mob/user)
+ var/list/extra_href = list()
+ extra_href["remote_connection"] = 1
+ extra_href["remote_access"] = has_access(user)
+
+ return extra_href
+
+/datum/topic_state/air_alarm/proc/has_access(var/mob/user)
+ return user && (user.isAI() || atmos_control.allowed(user) || atmos_control.emagged || air_alarm.rcon_setting == RCON_YES || (air_alarm.alarm_area.atmosalm && air_alarm.rcon_setting == RCON_AUTO))
diff --git a/code/modules/nano/modules/crew_monitor.dm b/code/modules/nano/modules/crew_monitor.dm
index bb60182a1b..2758b859d7 100644
--- a/code/modules/nano/modules/crew_monitor.dm
+++ b/code/modules/nano/modules/crew_monitor.dm
@@ -25,7 +25,7 @@
AI.ai_actual_track(H)
return 1
-/obj/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+/obj/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
user.set_machine(src)
src.scan()
@@ -74,7 +74,7 @@
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
- ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800)
+ ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800, state = state)
// adding a template with the key "mapContent" enables the map ui functionality
ui.add_template("mapContent", "crew_monitor_map_content.tmpl")
diff --git a/code/modules/nano/modules/power_monitor.dm b/code/modules/nano/modules/power_monitor.dm
index 7df3cb7c89..20bfce570f 100644
--- a/code/modules/nano/modules/power_monitor.dm
+++ b/code/modules/nano/modules/power_monitor.dm
@@ -7,7 +7,7 @@
..()
refresh_sensors()
-/obj/nano_module/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+/obj/nano_module/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
var/list/data = list()
var/list/sensors = list()
// Focus: If it remains null if no sensor is selected and UI will display sensor list, otherwise it will display sensor reading.
@@ -28,7 +28,7 @@
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
- ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 500)
+ ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 500, state = state)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
diff --git a/code/modules/nano/modules/rcon.dm b/code/modules/nano/modules/rcon.dm
index abdae311d0..58e55894c1 100644
--- a/code/modules/nano/modules/rcon.dm
+++ b/code/modules/nano/modules/rcon.dm
@@ -8,7 +8,7 @@
var/hide_SMES_details = 0
var/hide_breakers = 0
-/obj/nano_module/rcon/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1)
+/obj/nano_module/rcon/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1, var/datum/topic_state/state = default_state)
FindDevices() // Update our devices list
var/data[0]
@@ -41,7 +41,7 @@
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
- ui = new(user, src, ui_key, "rcon.tmpl", "RCON Console", 600, 400)
+ ui = new(user, src, ui_key, "rcon.tmpl", "RCON Console", 600, 400, state = state)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index 221c66df6e..61a011e594 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -214,17 +214,21 @@
//If limb took enough damage, try to cut or tear it off
if(owner && loc == owner)
if(!cannot_amputate && config.limbs_can_break && (brute_dam + burn_dam) >= (max_damage * config.organ_health_multiplier))
- var/threshold = max_damage/3
+ var/threshold = max_damage
var/dropped
if((burn >= threshold) && prob(burn/3))
dropped = 1
droplimb(0,DROPLIMB_BURN)
if(!dropped && prob(brute))
- if(brute >= threshold)
- if((sharp || edge) && istype(used_weapon,/obj/item))
- var/obj/item/W = used_weapon
- if(W.w_class >= 3)
- droplimb(0,DROPLIMB_EDGE)
+ var/edge_eligible = 0
+ if(edge && istype(used_weapon,/obj/item))
+ var/obj/item/W = used_weapon
+ if(W.w_class >= 3)
+ edge_eligible = 1
+
+ if(brute >= threshold || (edge_eligible && brute >= threshold/3))
+ if((sharp || edge))
+ droplimb(0,DROPLIMB_EDGE)
else
droplimb(0,DROPLIMB_BLUNT)
diff --git a/code/modules/projectiles/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm
index e25d8f39f1..eb2e6f1c1d 100644
--- a/code/modules/projectiles/ammunition/boxes.dm
+++ b/code/modules/projectiles/ammunition/boxes.dm
@@ -40,6 +40,10 @@
name = "magazine (.45 rubber)"
ammo_type = /obj/item/ammo_casing/c45r
+/obj/item/ammo_magazine/c45m/practice
+ name = "magazine (.45 practice)"
+ ammo_type = /obj/item/ammo_casing/c45p
+
/obj/item/ammo_magazine/c45m/flash
name = "magazine (.45 flash)"
ammo_type = "/obj/item/ammo_casing/c45f"
@@ -90,6 +94,10 @@
name = "top mounted magazine (9mm rubber)"
ammo_type = /obj/item/ammo_casing/c9mmr
+/obj/item/ammo_magazine/mc9mmt/practice
+ name = "top mounted magazine (9mm practice)"
+ ammo_type = /obj/item/ammo_casing/c9mmp
+
/obj/item/ammo_magazine/c45
name = "ammunition Box (.45)"
icon_state = "9mm"
@@ -130,6 +138,10 @@
/obj/item/ammo_magazine/a556/empty
initial_ammo = 0
+/obj/item/ammo_magazine/a556/practice
+ name = "magazine (5.56mm practice)"
+ ammo_type = /obj/item/ammo_casing/a556p
+
/obj/item/ammo_magazine/a50
name = "magazine (.50)"
icon_state = "50ae"
diff --git a/code/modules/projectiles/ammunition/bullets.dm b/code/modules/projectiles/ammunition/bullets.dm
index 931555381a..a07e5735c0 100644
--- a/code/modules/projectiles/ammunition/bullets.dm
+++ b/code/modules/projectiles/ammunition/bullets.dm
@@ -38,12 +38,22 @@
caliber = "9mm"
projectile_type = /obj/item/projectile/bullet/pistol/rubber
+/obj/item/ammo_casing/c9mmp
+ desc = "A 9mm practice bullet casing."
+ caliber = "9mm"
+ projectile_type = /obj/item/projectile/bullet/pistol/practice
+
/obj/item/ammo_casing/c45
desc = "A .45 bullet casing."
caliber = ".45"
projectile_type = /obj/item/projectile/bullet/pistol/medium
+/obj/item/ammo_casing/c45p
+ desc = "A .45 practice bullet casing."
+ caliber = ".45"
+ projectile_type = /obj/item/projectile/bullet/pistol/practice
+
/obj/item/ammo_casing/c45r
desc = "A .45 rubber bullet casing."
caliber = ".45"
@@ -82,6 +92,13 @@
projectile_type = /obj/item/projectile/bullet/blank
matter = list("metal" = 90)
+/obj/item/ammo_casing/shotgun/practice
+ name = "shotgun shell"
+ desc = "A practice shell."
+ icon_state = "pshell"
+ projectile_type = /obj/item/projectile/bullet/shotgun/practice
+ matter = list("metal" = 90)
+
/obj/item/ammo_casing/shotgun/beanbag
name = "beanbag shell"
desc = "A beanbag shell."
@@ -130,6 +147,11 @@
caliber = "a556"
projectile_type = /obj/item/projectile/bullet/rifle/a556
+/obj/item/ammo_casing/a556p
+ desc = "A 5.56mm practice bullet casing."
+ caliber = "a556"
+ projectile_type = /obj/item/projectile/bullet/rifle/a556/practice
+
/obj/item/ammo_casing/rocket
name = "rocket shell"
desc = "A high explosive designed to be fired from a launcher."
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 977c9e26f4..aea4b2a73a 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -8,7 +8,7 @@
embed = 1
sharp = 1
var/mob_passthrough_check = 0
-
+
muzzle_type = /obj/effect/projectile/bullet/muzzle
/obj/item/projectile/bullet/on_hit(var/atom/target, var/blocked = 0)
@@ -38,8 +38,8 @@
if(ismob(A))
if(!mob_passthrough_check)
return 0
- if(iscarbon(A))
- damage *= 0.7 //squishy mobs absorb KE
+ if(iscarbon(A))
+ damage *= 0.7 //squishy mobs absorb KE
return 1
var/chance = 0
@@ -184,3 +184,15 @@
/obj/item/projectile/bullet/chameleon
damage = 1 // stop trying to murderbone with a fake gun dumbass!!!
embed = 0 // nope
+
+/* Practice */
+
+/obj/item/projectile/bullet/pistol/practice
+ damage = 5
+
+/obj/item/projectile/bullet/rifle/a556/practice
+ damage = 5
+
+/obj/item/projectile/bullet/shotgun/practice
+ name = "practice"
+ damage = 5
\ No newline at end of file
diff --git a/code/setup.dm b/code/setup.dm
index 38836d54d5..0359233d35 100644
--- a/code/setup.dm
+++ b/code/setup.dm
@@ -192,6 +192,7 @@
#define NOBLOODY 512 // Used for items if they don't want to get a blood overlay.
#define NODELAY 8192 // 1 second attack-by delay skipped (Can be used once every 0.2s). Most objects have a 1s attack-by delay, which doesn't require a flag.
+//Use these flags to indicate if an item obscures the specified slots from view, whereas body_parts_covered seems to be used to indicate what body parts the item protects.
#define GLASSESCOVERSEYES 256
#define MASKCOVERSEYES 256 // Get rid of some of the other retardation in these flags.
#define HEADCOVERSEYES 256 // Feel free to reallocate these numbers for other purposes.
@@ -917,3 +918,32 @@ var/list/be_special_flags = list(
#define STAGE_FOUR 7
#define STAGE_FIVE 9
#define STAGE_SUPER 11
+
+// Camera networks
+#define NETWORK_CRESCENT "Crescent"
+#define NETWORK_CIVILIAN_EAST "Civilian East"
+#define NETWORK_CIVILIAN_WEST "Civilian West"
+#define NETWORK_COMMAND "Command"
+#define NETWORK_ENGINE "Engine"
+#define NETWORK_ENGINEERING "Engineering"
+#define NETWORK_ENGINEERING_OUTPOST "Engineering Outpost"
+#define NETWORK_ERT "ERT"
+#define NETWORK_EXODUS "Exodus"
+#define NETWORK_MEDICAL "Medical"
+#define NETWORK_MINE "MINE"
+#define NETWORK_RESEARCH "Research"
+#define NETWORK_RESEARCH_OUTPOST "Research Outpost"
+#define NETWORK_PRISON "Prison"
+#define NETWORK_SECURITY "Security"
+#define NETWORK_TELECOM "Tcomsat"
+#define NETWORK_THUNDER "thunder"
+
+// Languages
+#define LANGUAGE_SOL_COMMON "Sol Common"
+#define LANGUAGE_UNATHI "Sinta'unathi"
+#define LANGUAGE_SIIK_MAAS "Siik'maas"
+#define LANGUAGE_SIIK_TAJR "Siik'tajr"
+#define LANGUAGE_SKRELLIAN "Skrellian"
+#define LANGUAGE_ROOTSPEAK "Rootspeak"
+#define LANGUAGE_TRADEBAND "Tradeband"
+#define LANGUAGE_GUTTER "Gutter"
diff --git a/html/changelogs/PsiOmegaDelta-PR-8905.yml b/html/changelogs/PsiOmegaDelta-PR-8905.yml
new file mode 100644
index 0000000000..b984448b32
--- /dev/null
+++ b/html/changelogs/PsiOmegaDelta-PR-8905.yml
@@ -0,0 +1,6 @@
+author: PsiOmegaDelta
+delete-after: True
+changes:
+ - rscadd: "AIs now have a personal atmospherics control subsystem."
+ - rscadd: "Some borg modules now have additional subsystems."
+ - tweak: "Improves borg module handling."
diff --git a/html/changelogs/PsiOmegaDelta.yml b/html/changelogs/PsiOmegaDelta.yml
index 6fdea55f54..21a193f3a8 100644
--- a/html/changelogs/PsiOmegaDelta.yml
+++ b/html/changelogs/PsiOmegaDelta.yml
@@ -1,3 +1,5 @@
author: PsiOmegaDelta
-changes: []
+changes:
+ - soundadd: "Restores an old soundtrack 'Thunderdome.ogg'."
+ - rscadd: "Some holodeck programs now have custom ambience tracks."
delete-after: false
diff --git a/html/changelogs/Yoshax-MoreFunPracticeShoot.YML b/html/changelogs/Yoshax-MoreFunPracticeShoot.YML
new file mode 100644
index 0000000000..0ee6e60259
--- /dev/null
+++ b/html/changelogs/Yoshax-MoreFunPracticeShoot.YML
@@ -0,0 +1,8 @@
+author: Yoshax
+delete-after: True
+
+changes:
+ - rscadd: "Adds practice rounds, both .45 for Sec and Detective's guns, also 9mm top mounted for the Saber, and for the Bulldog
+ - rscadd: "Adds the .45 and 9mm practice rounds to the armory."
+ - rscadd: "Adds all the practice rounds to the autolathe."
+ - tweak: "Adds r_walls to the back of the firing range, leaves the sides normal."
diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi
index 5a2f06d319..779d34c7d1 100644
Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ
diff --git a/sound/music/THUNDERDOME.ogg b/sound/music/THUNDERDOME.ogg
new file mode 100644
index 0000000000..0a36b251b7
Binary files /dev/null and b/sound/music/THUNDERDOME.ogg differ
diff --git a/sound/serversound_list.txt b/sound/serversound_list.txt
index 24cbafaf15..21d48ed7f9 100644
--- a/sound/serversound_list.txt
+++ b/sound/serversound_list.txt
@@ -1,9 +1,11 @@
sound/music/1.ogg
sound/music/b12_combined_start.ogg
+sound/music/clouds.ogg
sound/music/main.ogg
sound/music/space.ogg
sound/music/space_asshole.ogg
sound/music/space_oddity.ogg
+sound/music/THUNDERDOME.ogg
sound/music/title1.ogg
sound/music/title2.ogg
sound/music/traitor.ogg