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