diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm index 60557d1dd7..3bee841881 100644 --- a/code/__defines/_planes+layers.dm +++ b/code/__defines/_planes+layers.dm @@ -68,6 +68,7 @@ What is the naming convention for planes or layers? // Obj planes #define OBJ_PLANE -35 + #define STAIRS_LAYER 2.5 // Layer for stairs #define HIDING_LAYER 2.6 // Layer at which mobs hide to be under things like tables #define DOOR_OPEN_LAYER 2.7 // Under all objects if opened. 2.7 due to tables being at 2.6 #define TABLE_LAYER 2.8 // Just under stuff that wants to be slightly below common objects. diff --git a/code/__defines/flags.dm b/code/__defines/flags.dm index 18a2ec59ab..64782715d3 100644 --- a/code/__defines/flags.dm +++ b/code/__defines/flags.dm @@ -16,6 +16,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 // datum_flags #define DF_VAR_EDITED (1<<0) #define DF_ISPROCESSING (1<<1) +#define DF_USE_TAG (1<<2) // /atom/movable movement_type #define UNSTOPPABLE (1<<0) //Can not be stopped from moving from Cross(), CanPass(), or Uncross() failing. Still bumps everything it passes through, though. diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index 8d85fada63..51039af253 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -87,6 +87,7 @@ #define ROBOT_NOTIFICATION_NEW_NAME 2 #define ROBOT_NOTIFICATION_NEW_MODULE 3 #define ROBOT_NOTIFICATION_MODULE_RESET 4 +#define ROBOT_NOTIFICATION_AI_SHELL 5 // Appearance change flags #define APPEARANCE_UPDATE_DNA 0x1 @@ -259,6 +260,7 @@ #define BORG_BRAINTYPE_CYBORG "Cyborg" #define BORG_BRAINTYPE_POSI "Robot" #define BORG_BRAINTYPE_DRONE "Drone" +#define BORG_BRAINTYPE_AI_SHELL "AI Shell" // 'Regular' species. #define SPECIES_HUMAN "Human" diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index 7922e95634..cde028f8d4 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -828,15 +828,25 @@ proc/GaussRandRound(var/sigma,var/roundto) SX.air.copy_from(ST.zone.air) ST.zone.remove(ST) + var/z_level_change = FALSE + if(T.z != X.z) + z_level_change = TRUE + //Move the objects. Not forceMove because the object isn't "moving" really, it's supposed to be on the "same" turf. for(var/obj/O in T) O.loc = X O.update_light() + if(z_level_change) // The objects still need to know if their z-level changed. + O.onTransitZ(T.z, X.z) //Move the mobs unless it's an AI eye or other eye type. for(var/mob/M in T) if(istype(M, /mob/observer/eye)) continue // If we need to check for more mobs, I'll add a variable M.loc = X + + if(z_level_change) // Same goes for mobs. + M.onTransitZ(T.z, X.z) + if(istype(M, /mob/living)) var/mob/living/LM = M LM.check_shadow() // Need to check their Z-shadow, which is normally done in forceMove(). @@ -1544,3 +1554,24 @@ var/mob/dview/dview_mob = new if(istype(D)) return !QDELETED(D) return FALSE + +//gives us the stack trace from CRASH() without ending the current proc. +/proc/stack_trace(msg) + CRASH(msg) + +/datum/proc/stack_trace(msg) + CRASH(msg) + +// \ref behaviour got changed in 512 so this is necesary to replicate old behaviour. +// If it ever becomes necesary to get a more performant REF(), this lies here in wait +// #define REF(thing) (thing && istype(thing, /datum) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]") +/proc/REF(input) + if(istype(input, /datum)) + var/datum/thing = input + if(thing.datum_flags & DF_USE_TAG) + if(!thing.tag) + thing.datum_flags &= ~DF_USE_TAG + stack_trace("A ref was requested of an object with DF_USE_TAG set but no tag: [thing]") + else + return "\[[url_encode(thing.tag)]\]" + return "\ref[input]" diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 0fd222044c..5207499b53 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -60,7 +60,8 @@ var/list/gamemode_cache = list() var/humans_need_surnames = 0 var/allow_random_events = 0 // enables random events mid-round when set to 1 var/allow_ai = 1 // allow ai job - var/allow_ai_drones = 0 // allow ai controlled drones + var/allow_ai_shells = FALSE // allow AIs to enter and leave special borg shells at will, and for those shells to be buildable. + var/give_free_ai_shell = FALSE // allows a specific spawner object to instantiate a premade AI Shell var/hostedby = null var/respawn = 1 var/guest_jobban = 1 @@ -410,8 +411,11 @@ var/list/gamemode_cache = list() if ("allow_ai") config.allow_ai = 1 - if ("allow_ai_drones") - config.allow_ai_drones = 1 + if ("allow_ai_shells") + config.allow_ai_shells = TRUE + + if("give_free_ai_shell") + config.give_free_ai_shell = TRUE // if ("authentication") // config.enable_authentication = 1 diff --git a/code/controllers/emergency_shuttle_controller.dm b/code/controllers/emergency_shuttle_controller.dm index bcc7187a3c..5dbfeb427a 100644 --- a/code/controllers/emergency_shuttle_controller.dm +++ b/code/controllers/emergency_shuttle_controller.dm @@ -195,6 +195,8 @@ var/global/datum/emergency_shuttle_controller/emergency_shuttle //returns 1 if the shuttle is not idle at centcom /datum/emergency_shuttle_controller/proc/online() + if(!shuttle) + return FALSE if (!shuttle.location) //not at centcom return 1 if (wait_for_launch || shuttle.moving_status != SHUTTLE_IDLE) diff --git a/code/datums/soul_link.dm b/code/datums/soul_link.dm new file mode 100644 index 0000000000..7bc652a863 --- /dev/null +++ b/code/datums/soul_link.dm @@ -0,0 +1,156 @@ +// A datum used to link multiple mobs together in some form. +// The code is from TG, however tweaked to be within the preferred code style. + +/mob/living + var/list/owned_soul_links // Soul links we are the owner of. + var/list/shared_soul_links // Soul links we are a/the sharer of. + +/mob/living/Destroy() + for(var/s in owned_soul_links) + var/datum/soul_link/S = s + S.owner_died(FALSE) + qdel(s) // If the owner is destroy()'d, the soullink is destroy()'d. + owned_soul_links = null + for(var/s in shared_soul_links) + var/datum/soul_link/S = s + S.sharer_died(FALSE) + S.remove_soul_sharer(src) // If a sharer is destroy()'d, they are simply removed. + shared_soul_links = null + return ..() + +// Keeps track of a Mob->Mob (potentially Player->Player) connection. +// Can be used to trigger actions on one party when events happen to another. +// Eg: shared deaths. +// Can be used to form a linked list of mob-hopping. +// Does NOT transfer with minds. +/datum/soul_link + var/mob/living/soul_owner + var/mob/living/soul_sharer + var/id // Optional ID, for tagging and finding specific instances. + +/datum/soul_link/Destroy() + if(soul_owner) + LAZYREMOVE(soul_owner.owned_soul_links, src) + soul_owner = null + if(soul_sharer) + LAZYREMOVE(soul_sharer.shared_soul_links, src) + soul_sharer = null + return ..() + +/datum/soul_link/proc/remove_soul_sharer(mob/living/sharer) + if(soul_sharer == sharer) + soul_sharer = null + LAZYREMOVE(sharer.shared_soul_links, src) + +// Used to assign variables, called primarily by soullink() +// Override this to create more unique soullinks (Eg: 1->Many relationships) +// Return TRUE/FALSE to return the soullink/null in soullink() +/datum/soul_link/proc/parse_args(mob/living/owner, mob/living/sharer) + if(!owner || !sharer) + return FALSE + soul_owner = owner + soul_sharer = sharer + LAZYADD(owner.owned_soul_links, src) + LAZYADD(sharer.shared_soul_links, src) + return TRUE + +// Runs after /living death() +// Override this for content. +/datum/soul_link/proc/owner_died(gibbed, mob/living/owner) + +// Runs after /living death() +// Override this for content. +/datum/soul_link/proc/sharer_died(gibbed, mob/living/owner) + +// Quick-use helper. +/proc/soul_link(typepath, ...) + var/datum/soul_link/S = new typepath() + if(S.parse_args(arglist(args.Copy(2, 0)))) + return S + + +///////////////// +// MULTISHARER // +///////////////// +// Abstract soullink for use with 1 Owner -> Many Sharer setups +/datum/soul_link/multi_sharer + var/list/soul_sharers + +/datum/soul_link/multi_sharer/parse_args(mob/living/owner, list/sharers) + if(!owner || !LAZYLEN(sharers)) + return FALSE + soul_owner = owner + soul_sharers = sharers + LAZYADD(owner.owned_soul_links, src) + for(var/l in sharers) + var/mob/living/L = l + LAZYADD(L.shared_soul_links, src) + return TRUE + +/datum/soul_link/multi_sharer/remove_soul_sharer(mob/living/sharer) + LAZYREMOVE(soul_sharers, sharer) + + +///////////////// +// SHARED FATE // +///////////////// +// When the soulowner dies, the soulsharer dies, and vice versa +// This is intended for two players(or AI) and two mobs + +/datum/soul_link/shared_fate/owner_died(gibbed, mob/living/owner) + if(soul_sharer) + soul_sharer.death(gibbed) + +/datum/soul_link/shared_fate/sharer_died(gibbed, mob/living/sharer) + if(soul_owner) + soul_owner.death(gibbed) + +////////////// +// ONE WAY // +////////////// +// When the soul owner dies, the soul sharer dies, but NOT vice versa. +// This is intended for two players (or AI) and two mobs. + +/datum/soul_link/one_way/owner_died(gibbed, mob/living/owner) + if(soul_sharer) + soul_sharer.dust(FALSE) + +///////////////// +// SHARED BODY // +///////////////// +// When the soulsharer dies, they're placed in the soulowner, who remains alive +// If the soulowner dies, the soulsharer is killed and placed into the soulowner (who is still dying) +// This one is intended for one player moving between many mobs + +/datum/soul_link/shared_body/owner_died(gibbed, mob/living/owner) + if(soul_owner && soul_sharer) + if(soul_sharer.mind) + soul_sharer.mind.transfer_to(soul_owner) + soul_sharer.death(gibbed) + +/datum/soul_link/shared_body/sharer_died(gibbed, mob/living/sharer) + if(soul_owner && soul_sharer && soul_sharer.mind) + soul_sharer.mind.transfer_to(soul_owner) + + + +////////////////////// +// REPLACEMENT POOL // +////////////////////// +// When the owner dies, one of the sharers is placed in the owner's body, fully healed +// Sort of a "winner-stays-on" soullink +// Gibbing ends it immediately + +/datum/soul_link/multi_sharer/replacement_pool/owner_died(gibbed, mob/living/owner) + if(LAZYLEN(soul_sharers) && !gibbed) //let's not put them in some gibs + var/list/souls = shuffle(soul_sharers.Copy()) + for(var/l in souls) + var/mob/living/L = l + if(L.stat != DEAD && L.mind) + L.mind.transfer_to(soul_owner) + soul_owner.revive(TRUE, TRUE) + L.death(FALSE) + +// Lose your claim to the throne! +/datum/soul_link/multi_sharer/replacement_pool/sharer_died(gibbed, mob/living/sharer) + remove_soul_sharer(sharer) diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index c7f64f225c..81c74f3ba3 100644 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -978,6 +978,12 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "entry_D2" base_turf = /turf/space +/area/hallway/secondary/entry/D2/arrivals + name = "\improper Shuttle Dock Hallway - Dock Two" + icon_state = "entry_D2" + base_turf = /turf/space + requires_power = 0 + /area/hallway/secondary/entry/D3 name = "\improper Shuttle Dock Hallway - Dock Three" icon_state = "entry_D3" diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index bc6da68332..fd4ecb14a6 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -200,8 +200,8 @@ GLOBAL_LIST_BOILERPLATE(all_deactivated_AI_cores, /obj/structure/AIcore/deactiva if(!istype(transfer) || locate(/mob/living/silicon/ai) in src) return - if(transfer.controlling_drone) - transfer.controlling_drone.release_ai_control("Unit control lost. Core transfer completed.") + if(transfer.deployed_shell) + transfer.disconnect_shell("Disconnected from remote shell due to core intelligence transfer.") transfer.aiRestorePowerRoutine = 0 transfer.control_disabled = 0 transfer.aiRadio.disabledAi = 0 diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index dfd093dcf2..972348ac44 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -27,7 +27,7 @@ var/destroy_hits = 10 //How many strong hits it takes to destroy the door var/min_force = 10 //minimum amount of force needed to damage the door with a melee weapon var/hitsound = 'sound/weapons/smash.ogg' //sound door makes when hit with a weapon - var/obj/item/stack/material/steel/repairing + var/repairing = 0 var/block_air_zones = 1 //If set, air zones cannot merge across the door even when it is opened. var/close_door_at = 0 //When to automatically close the door, if possible @@ -210,13 +210,13 @@ if(istype(I)) if(istype(I, /obj/item/stack/material) && I.get_material_name() == src.get_material_name()) if(stat & BROKEN) - user << "It looks like \the [src] is pretty busted. It's going to need more than just patching up now." + to_chat(user, "It looks like \the [src] is pretty busted. It's going to need more than just patching up now.") return if(health >= maxhealth) - user << "Nothing to fix!" + to_chat(user, "Nothing to fix!") return if(!density) - user << "\The [src] must be closed before you can repair it." + to_chat(user, "\The [src] must be closed before you can repair it.") return //figure out how much metal we need @@ -224,44 +224,45 @@ amount_needed = (round(amount_needed) == amount_needed)? amount_needed : round(amount_needed) + 1 //Why does BYOND not have a ceiling proc? var/obj/item/stack/stack = I - var/transfer - if (repairing) - transfer = stack.transfer_to(repairing, amount_needed - repairing.amount) - if (!transfer) - user << "You must weld or remove \the [repairing] from \the [src] before you can add anything else." + var/amount_given = amount_needed - repairing + var/mats_given = stack.get_amount() + if(repairing && amount_given <= 0) + to_chat(user, "You must weld or remove \the [get_material_name()] from \the [src] before you can add anything else.") else - repairing = stack.split(amount_needed) - if (repairing) - repairing.loc = src - transfer = repairing.amount - - if (transfer) - user << "You fit [transfer] [stack.singular_name]\s to damaged and broken parts on \the [src]." + if(mats_given >= amount_given) + if(stack.use(amount_given)) + repairing += amount_given + else + if(stack.use(mats_given)) + repairing += mats_given + amount_given = mats_given + if(amount_given) + to_chat(user, "You fit [amount_given] [stack.singular_name]\s to damaged and broken parts on \the [src].") return if(repairing && istype(I, /obj/item/weapon/weldingtool)) if(!density) - user << "\The [src] must be closed before you can repair it." + to_chat(user, "\The [src] must be closed before you can repair it.") return var/obj/item/weapon/weldingtool/welder = I if(welder.remove_fuel(0,user)) - user << "You start to fix dents and weld \the [repairing] into place." + to_chat(user, "You start to fix dents and weld \the [get_material_name()] into place.") playsound(src, welder.usesound, 50, 1) - if(do_after(user, (5 * repairing.amount) * welder.toolspeed) && welder && welder.isOn()) - user << "You finish repairing the damage to \the [src]." - health = between(health, health + repairing.amount*DOOR_REPAIR_AMOUNT, maxhealth) + if(do_after(user, (5 * repairing) * welder.toolspeed) && welder && welder.isOn()) + to_chat(user, "You finish repairing the damage to \the [src].") + health = between(health, health + repairing*DOOR_REPAIR_AMOUNT, maxhealth) update_icon() - qdel(repairing) - repairing = null + repairing = 0 return if(repairing && I.is_crowbar()) - user << "You remove \the [repairing]." + var/obj/item/stack/material/repairing_sheet = get_material().place_sheet(loc) + repairing_sheet.amount += repairing-1 + repairing = 0 + to_chat(user, "You remove \the [repairing_sheet].") playsound(src, I.usesound, 100, 1) - repairing.loc = user.loc - repairing = null return //psa to whoever coded this, there are plenty of objects that need to call attack() on doors without bludgeoning them. @@ -321,13 +322,13 @@ /obj/machinery/door/examine(mob/user) . = ..() if(src.health <= 0) - user << "\The [src] is broken!" + to_chat(user, "\The [src] is broken!") if(src.health < src.maxhealth / 4) - user << "\The [src] looks like it's about to break!" + to_chat(user, "\The [src] looks like it's about to break!") else if(src.health < src.maxhealth / 2) - user << "\The [src] looks seriously damaged!" + to_chat(user, "\The [src] looks seriously damaged!") else if(src.health < src.maxhealth * 3/4) - user << "\The [src] shows signs of damage!" + to_chat(user, "\The [src] shows signs of damage!") /obj/machinery/door/proc/set_broken() diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index dc4bf5146a..7dc82a0ffb 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -13,18 +13,24 @@ GLOBAL_LIST_BOILERPLATE(all_portals, /obj/effect/portal) anchored = 1.0 /obj/effect/portal/Bumped(mob/M as mob|obj) + if(istype(M,/mob) && !(istype(M,/mob/living))) + return //do not send ghosts, zshadows, ai eyes, etc spawn(0) src.teleport(M) return return /obj/effect/portal/Crossed(AM as mob|obj) + if(istype(AM,/mob) && !(istype(AM,/mob/living))) + return //do not send ghosts, zshadows, ai eyes, etc spawn(0) src.teleport(AM) return return /obj/effect/portal/attack_hand(mob/user as mob) + if(istype(user) && !(istype(user,/mob/living))) + return //do not send ghosts, zshadows, ai eyes, etc spawn(0) src.teleport(user) return diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index 181764d126..cc7ac0e4a4 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -59,15 +59,15 @@ var/user = usr if (href_list["wipe"]) - var/confirm = alert("Are you sure you want to disable this core's power? This cannot be undone once started.", "Confirm Shutdown", "Yes", "No") + var/confirm = alert("Are you sure you want to disable this core's power? This cannot be undone once started.", "Confirm Shutdown", "No", "Yes") if(confirm == "Yes" && (CanUseTopic(user, state) == STATUS_INTERACTIVE)) add_attack_logs(user,carded_ai,"Purged from AI Card") flush = 1 carded_ai.suiciding = 1 to_chat(carded_ai, "Your power has been disabled!") - while (carded_ai && carded_ai.stat != 2) - if(carded_ai.controlling_drone && prob(carded_ai.oxyloss)) //You feel it creeping? Eventually will reach 100, resulting in the second half of the AI's remaining life being lonely. - carded_ai.controlling_drone.release_ai_control("Unit lost. Integrity too low to maintain connection.") + while (carded_ai && carded_ai.stat != DEAD) + if(carded_ai.deployed_shell && prob(carded_ai.oxyloss)) //You feel it creeping? Eventually will reach 100, resulting in the second half of the AI's remaining life being lonely. + carded_ai.disconnect_shell("Disconnecting from remote shell due to insufficent power.") carded_ai.adjustOxyLoss(2) carded_ai.updatehealth() sleep(10) @@ -80,8 +80,8 @@ carded_ai.control_disabled = text2num(href_list["wireless"]) to_chat(carded_ai, "Your wireless interface has been [carded_ai.control_disabled ? "disabled" : "enabled"]!") to_chat(user, "You [carded_ai.control_disabled ? "disable" : "enable"] the AI's wireless interface.") - if(carded_ai.control_disabled && carded_ai.controlling_drone) - carded_ai.controlling_drone.release_ai_control("Unit control terminated at intellicore port.") + if(carded_ai.control_disabled && carded_ai.deployed_shell) + carded_ai.disconnect_shell("Disconnecting from remote shell due to [src] wireless access interface being disabled.") update_icon() return 1 @@ -98,7 +98,7 @@ icon_state = "aicard" /obj/item/device/aicard/proc/grab_ai(var/mob/living/silicon/ai/ai, var/mob/living/user) - if(!ai.client && !ai.controlling_drone) + if(!ai.client && !ai.deployed_shell) to_chat(user, "ERROR: AI [ai.name] is offline. Unable to transfer.") return 0 @@ -112,9 +112,7 @@ return 0 user.visible_message("\The [user] starts transferring \the [ai] into \the [src]...", "You start transferring \the [ai] into \the [src]...") - to_chat(ai, "\The [user] is transferring you into \the [src]!") - if(ai.controlling_drone) - to_chat(ai.controlling_drone, "\The [user] is transferring you into \the [src]!") + show_message(span("critical", "\The [user] is transferring you into \the [src]!")) if(do_after(user, 100)) if(istype(ai.loc, /turf/)) @@ -130,8 +128,7 @@ ai.control_disabled = 1 ai.aiRestorePowerRoutine = 0 carded_ai = ai - if(ai.controlling_drone) - ai.controlling_drone.release_ai_control("Unit control lost.") + ai.disconnect_shell("Disconnected from remote shell due to core intelligence transfer.") //If the AI is controlling a borg, force the player back to core! if(ai.client) to_chat(ai, "You have been transferred into a mobile core. Remote access lost.") diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 7565b9c9ac..554663727f 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -168,28 +168,29 @@ if(!istype(loc,/turf)) to_chat(user, "You can't put \the [W] in, the frame has to be standing on the ground to be perfectly precise.") return - if(!M.brainmob) - to_chat(user, "Sticking an empty [W] into the frame would sort of defeat the purpose.") - return - if(!M.brainmob.key) - var/ghost_can_reenter = 0 - if(M.brainmob.mind) - for(var/mob/observer/dead/G in player_list) - if(G.can_reenter_corpse && G.mind == M.brainmob.mind) - ghost_can_reenter = 1 //May come in use again at another point. - to_chat(user, "\The [W] is completely unresponsive; though it may be able to auto-resuscitate.") //Jamming a ghosted brain into a borg is likely detrimental, and may result in some problems. - return - if(!ghost_can_reenter) - to_chat(user, "\The [W] is completely unresponsive; there's no point.") + if(!istype(W, /obj/item/device/mmi/inert)) + if(!M.brainmob) + to_chat(user, "Sticking an empty [W] into the frame would sort of defeat the purpose.") + return + if(!M.brainmob.key) + var/ghost_can_reenter = 0 + if(M.brainmob.mind) + for(var/mob/observer/dead/G in player_list) + if(G.can_reenter_corpse && G.mind == M.brainmob.mind) + ghost_can_reenter = 1 //May come in use again at another point. + to_chat(user, "\The [W] is completely unresponsive; though it may be able to auto-resuscitate.") //Jamming a ghosted brain into a borg is likely detrimental, and may result in some problems. + return + if(!ghost_can_reenter) + to_chat(user, "\The [W] is completely unresponsive; there's no point.") + return + + if(M.brainmob.stat == DEAD) + to_chat(user, "Sticking a dead [W] into the frame would sort of defeat the purpose.") return - if(M.brainmob.stat == DEAD) - to_chat(user, "Sticking a dead [W] into the frame would sort of defeat the purpose.") - return - - if(jobban_isbanned(M.brainmob, "Cyborg")) - to_chat(user, "This [W] does not seem to fit.") - return + if(jobban_isbanned(M.brainmob, "Cyborg")) + to_chat(user, "This [W] does not seem to fit.") + return var/mob/living/silicon/robot/O = new /mob/living/silicon/robot(get_turf(loc), unfinished = 1) if(!O) return @@ -197,20 +198,18 @@ user.drop_item() O.mmi = W + O.post_mmi_setup() O.invisibility = 0 O.custom_name = created_name O.updatename("Default") - M.brainmob.mind.transfer_to(O) - - if(O.mind && O.mind.special_role) - O.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite") - + if(M.brainmob) + M.brainmob.mind.transfer_to(O) + if(O.mind && O.mind.special_role) + O.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite") + for(var/datum/language/L in M.brainmob.languages) + O.add_language(L.name) O.job = "Cyborg" - - for(var/datum/language/L in M.brainmob.languages) - O.add_language(L.name) - O.cell = chest.cell O.cell.loc = O W.loc = O//Should fix cybros run time erroring when blown up. It got deleted before, along with the frame. diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 93d0055129..fe1685ec70 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -25,17 +25,9 @@ require_module = 1 /obj/item/borg/upgrade/reset/action(var/mob/living/silicon/robot/R) - if(..()) return 0 - R.uneq_all() - R.modtype = initial(R.modtype) - R.hands.icon_state = initial(R.hands.icon_state) - - R.notify_ai(ROBOT_NOTIFICATION_MODULE_RESET, R.module.name) - R.module.Reset(R) - qdel(R.module) - R.module = null - R.updatename("Default") - + if(..()) + return 0 + R.module_reset() return 1 /obj/item/borg/upgrade/rename diff --git a/code/game/objects/random/misc.dm b/code/game/objects/random/misc.dm index 5b8fc35e3c..0f9f85582f 100644 --- a/code/game/objects/random/misc.dm +++ b/code/game/objects/random/misc.dm @@ -293,6 +293,23 @@ /obj/item/weapon/reagent_containers/food/drinks/bottle/rum, /obj/item/weapon/reagent_containers/food/drinks/bottle/patron) +/obj/random/meat + name = "random meat" + desc = "This is a random slab of meat." + icon = 'icons/obj/food.dmi' + icon_state = "meat" + +/obj/random/meat/item_to_spawn() + return pick(prob(60);/obj/item/weapon/reagent_containers/food/snacks/meat, + prob(20);/obj/item/weapon/reagent_containers/food/snacks/xenomeat/spidermeat, + prob(10);/obj/item/weapon/reagent_containers/food/snacks/carpmeat, + prob(5);/obj/item/weapon/reagent_containers/food/snacks/bearmeat, + prob(1);/obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh, + prob(1);/obj/item/weapon/reagent_containers/food/snacks/meat/human, + prob(1);/obj/item/weapon/reagent_containers/food/snacks/meat/monkey, + prob(1);/obj/item/weapon/reagent_containers/food/snacks/meat/corgi, + prob(1);/obj/item/weapon/reagent_containers/food/snacks/xenomeat) + /obj/random/material //Random materials for building stuff name = "random material" desc = "This is a random material." diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 962f7956c4..25d5979002 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -33,6 +33,11 @@ var/list/starts_with /obj/structure/closet/Initialize() + ..() + // Closets need to come later because of spawners potentially creating objects during init. + return INITIALIZE_HINT_LATELOAD + +/obj/structure/closet/LateInitialize() . = ..() if(starts_with) create_objects_in_loc(src, starts_with) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index ac7958d6bd..e06d08070c 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -790,13 +790,13 @@ if (ismob(M)) if(!check_if_greater_rights_than(M.client)) return - var/reason = sanitize(input("Please enter reason")) + var/reason = sanitize(input("Please enter reason.") as null|message) if(!reason) - M << "You have been kicked from the server" - else - M << "You have been kicked from the server: [reason]" - log_admin("[key_name(usr)] booted [key_name(M)].") - message_admins("[key_name_admin(usr)] booted [key_name_admin(M)].", 1) + return + + to_chat(M, span("critical", "You have been kicked from the server: [reason]")) + log_admin("[key_name(usr)] booted [key_name(M)] for reason: '[reason]'.") + message_admins("[key_name_admin(usr)] booted [key_name_admin(M)] for reason '[reason]'.", 1) //M.client = null qdel(M.client) diff --git a/code/modules/catalogue/cataloguer.dm b/code/modules/catalogue/cataloguer.dm index ba518b1f3d..60e86eadee 100644 --- a/code/modules/catalogue/cataloguer.dm +++ b/code/modules/catalogue/cataloguer.dm @@ -149,12 +149,14 @@ GLOBAL_LIST_EMPTY(all_cataloguers) var/list/contributers = list() var/list/contributer_names = list() for(var/thing in player_list) - var/mob/M = thing - if(M == user) + var/mob/living/L = thing + if(L == user) continue - if(get_dist(M, user) <= credit_sharing_range) - contributers += M - contributer_names += M.name + if(!istype(L)) + continue + if(get_dist(L, user) <= credit_sharing_range) + contributers += L + contributer_names += L.name var/points_gained = 0 diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm index 2dbdcde1d3..e2a661f5f3 100644 --- a/code/modules/client/preference_setup/loadout/loadout_suit.dm +++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm @@ -273,6 +273,14 @@ datum/gear/suit/duster display_name = "cloak, medical" path = /obj/item/clothing/accessory/poncho/roles/cloak/medical +/datum/gear/suit/roles/poncho/cloak/custom //A colorable cloak + display_name = "cloak (colorable)" + path = /obj/item/clothing/accessory/poncho/roles/cloak/custom + +/datum/gear/suit/roles/poncho/cloak/custom/New() + ..() + gear_tweaks = list(gear_tweak_free_color_choice) + /datum/gear/suit/unathi_robe display_name = "roughspun robe" path = /obj/item/clothing/suit/unathi/robe diff --git a/code/modules/clothing/spacesuits/void/void.dm b/code/modules/clothing/spacesuits/void/void.dm index 4dd21ad3bb..f1d12a9982 100644 --- a/code/modules/clothing/spacesuits/void/void.dm +++ b/code/modules/clothing/spacesuits/void/void.dm @@ -240,12 +240,12 @@ playsound(src, W.usesound, 50, 1) src.cooler = null else if(choice == helmet) - to_chat(user, "You detatch \the [helmet] from \the [src]'s helmet mount.") + to_chat(user, "You detach \the [helmet] from \the [src]'s helmet mount.") helmet.forceMove(get_turf(src)) playsound(src, W.usesound, 50, 1) src.helmet = null else if(choice == boots) - to_chat(user, "You detatch \the [boots] from \the [src]'s boot mounts.") + to_chat(user, "You detach \the [boots] from \the [src]'s boot mounts.") boots.forceMove(get_turf(src)) playsound(src, W.usesound, 50, 1) src.boots = null @@ -295,4 +295,4 @@ cooler = W return - ..() \ No newline at end of file + ..() diff --git a/code/modules/clothing/under/accessories/clothing.dm b/code/modules/clothing/under/accessories/clothing.dm index 29057e8469..66636aac6f 100644 --- a/code/modules/clothing/under/accessories/clothing.dm +++ b/code/modules/clothing/under/accessories/clothing.dm @@ -216,6 +216,13 @@ icon_state = "medcloak" item_state = "medcloak" + +/obj/item/clothing/accessory/poncho/roles/cloak/custom //A colorable cloak + name = "cloak" + desc = "A simple, bland cloak." + icon_state = "colorcloak" + item_state = "colorcloak" + /obj/item/clothing/accessory/hawaii name = "flower-pattern shirt" desc = "You probably need some welder googles to look at this." diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm index 57d237ee5e..294baee09b 100644 --- a/code/modules/food/food/snacks.dm +++ b/code/modules/food/food/snacks.dm @@ -3285,23 +3285,23 @@ return ..() -/obj/item/pizzabox/margherita/New() +/obj/item/pizzabox/margherita/Initialize() pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margherita(src) boxtag = "Margherita Deluxe" -/obj/item/pizzabox/vegetable/New() +/obj/item/pizzabox/vegetable/Initialize() pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza(src) boxtag = "Gourmet Vegatable" -/obj/item/pizzabox/mushroom/New() +/obj/item/pizzabox/mushroom/Initialize() pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza(src) boxtag = "Mushroom Special" -/obj/item/pizzabox/meat/New() +/obj/item/pizzabox/meat/Initialize() pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza(src) boxtag = "Meatlover's Supreme" -/obj/item/pizzabox/old/New() +/obj/item/pizzabox/old/Initialize() pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/oldpizza(src) boxtag = "Deluxe Gourmet" diff --git a/code/modules/food/kitchen/gibber.dm b/code/modules/food/kitchen/gibber.dm index 3863dbddf7..db1c13ebde 100644 --- a/code/modules/food/kitchen/gibber.dm +++ b/code/modules/food/kitchen/gibber.dm @@ -217,13 +217,13 @@ spawn(gib_time) - src.operating = 0 - src.occupant.gib() - qdel(src.occupant) + operating = 0 + occupant.gib() + occupant = null playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) operating = 0 - for (var/obj/item/thing in contents) + for (var/obj/thing in contents) // There's a chance that the gibber will fail to destroy some evidence. if(istype(thing,/obj/item/organ) && prob(80)) qdel(thing) diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm index e9b3ae537e..08d762e093 100644 --- a/code/modules/games/cards.dm +++ b/code/modules/games/cards.dm @@ -254,8 +254,9 @@ return -/obj/item/weapon/deck/verb_pickup(mob/user as mob) // Snowflaked so pick up verb work as intended - if((user == usr && (!( usr.restrained() ) && (!( usr.stat ) && (usr.contents.Find(src) || in_range(src, usr)))))) +/obj/item/weapon/deck/verb_pickup() // Snowflaked so pick up verb work as intended + var/mob/user = usr + if((istype(user) && (!( usr.restrained() ) && (!( usr.stat ) && (usr.contents.Find(src) || in_range(src, usr)))))) if(!istype(usr, /mob/living/simple_mob)) if( !usr.get_active_hand() ) //if active hand is empty var/mob/living/carbon/human/H = user diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index dde3b7f6f7..75f675f67c 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -211,7 +211,7 @@ var/obj/item/stack/flag/newflag = new src.type(T) newflag.amount = 1 newflag.upright = 1 - anchored = 1 + newflag.anchored = 1 newflag.name = newflag.singular_name newflag.icon_state = "[newflag.base_state]_open" newflag.visible_message("[user] plants [newflag] firmly in the ground.") diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm index e7c097c2b3..5408742654 100644 --- a/code/modules/mob/hear_say.dm +++ b/code/modules/mob/hear_say.dm @@ -275,6 +275,8 @@ var/final_message = "[part_a][speaker_name][part_b][formatted]" if(check_mentioned(formatted) && is_preference_enabled(/datum/client_preference/check_mention)) final_message = "[time][final_message]" + else + final_message = "[time][final_message]" to_chat(src, final_message) /mob/living/silicon/ai/on_hear_radio(part_a, speaker_name, track, part_b, formatted) @@ -282,6 +284,8 @@ var/final_message = "[part_a][track][part_b][formatted]" if(check_mentioned(formatted) && is_preference_enabled(/datum/client_preference/check_mention)) final_message = "[time][final_message]" + else + final_message = "[time][final_message]" to_chat(src, final_message) /mob/proc/hear_signlang(var/message, var/verb = "gestures", var/datum/language/language, var/mob/speaker = null) diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm index 72c8238e55..128116b151 100644 --- a/code/modules/mob/living/carbon/brain/MMI.dm +++ b/code/modules/mob/living/carbon/brain/MMI.dm @@ -339,3 +339,16 @@ ..() src.brainmob.name = "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]" src.brainmob.real_name = src.brainmob.name + +// This type shouldn't care about brainmobs. +/obj/item/device/mmi/inert + +// This is a 'fake' MMI that is used to let AIs control borg shells directly. +// This doesn't inherit from /digital because all that does is add ghost pulling capabilities, which this thing won't need. +/obj/item/device/mmi/inert/ai_remote + name = "\improper AI remote interface" + desc = "A sophisticated board which allows for an artificial intelligence to remotely control a synthetic chassis." + icon = 'icons/obj/module.dmi' + icon_state = "mainboard" + w_class = ITEMSIZE_NORMAL + origin_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 2, TECH_BLUESPACE = 2, TECH_DATA = 3) \ No newline at end of file diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 1340fd77ef..9ec5ef5cca 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -1,4 +1,4 @@ -/mob/living/death() +/mob/living/death(gibbed) clear_fullscreens() if(ai_holder) @@ -12,4 +12,12 @@ var/obj/structure/blob/factory/F = nest F.spores -= src nest = null + + for(var/s in owned_soul_links) + var/datum/soul_link/S = s + S.owner_died(gibbed) + for(var/s in shared_soul_links) + var/datum/soul_link/S = s + S.sharer_died(gibbed) + . = ..() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index f95e8f3733..fae3542f18 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -103,18 +103,23 @@ default behaviour is: return //BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller - var/dense = 0 - if(loc.density) - dense = 1 - for(var/atom/movable/A in loc) - if(A == src) - continue - if(A.density) - if(A.flags&ON_BORDER) - dense = !A.CanPass(src, src.loc) - else - dense = 1 - if(dense) break + var/can_swap = 1 + if(loc.density || tmob.loc.density) + can_swap = 0 + if(can_swap) + for(var/atom/movable/A in loc) + if(A == src) + continue + if(!A.CanPass(tmob, loc)) + can_swap = 0 + if(!can_swap) break + if(can_swap) + for(var/atom/movable/A in tmob.loc) + if(A == tmob) + continue + if(!A.CanPass(src, tmob.loc)) + can_swap = 0 + if(!can_swap) break //Leaping mobs just land on the tile, no pushing, no anything. if(status_flags & LEAPING) @@ -123,7 +128,7 @@ default behaviour is: now_pushing = 0 return - if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && tmob.canmove && canmove && !tmob.buckled && !buckled && !dense && can_move_mob(tmob, 1, 0)) // mutual brohugs all around! + if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && tmob.canmove && canmove && !tmob.buckled && !buckled && can_swap && can_move_mob(tmob, 1, 0)) // mutual brohugs all around! var/turf/oldloc = loc forceMove(tmob.loc) tmob.forceMove(oldloc) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index a98f2804df..5b6909f042 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -49,10 +49,10 @@ var/list/ai_verbs_default = list( shouldnt_see = list(/obj/effect/rune) var/list/network = list(NETWORK_DEFAULT) var/obj/machinery/camera/camera = null - var/list/connected_robots = list() var/aiRestorePowerRoutine = 0 var/viewalerts = 0 var/icon/holo_icon//Default is assigned when AI is created. + var/list/connected_robots = list() var/obj/item/device/pda/ai/aiPDA = null var/obj/item/device/communicator/aiCommunicator = null var/obj/item/device/multitool/aiMulti = null @@ -221,6 +221,28 @@ var/list/ai_verbs_default = list( return ..() +/mob/living/silicon/ai/Stat() + ..() + if(statpanel("Status")) + if(!stat) // Make sure we're not unconscious/dead. + stat(null, text("System integrity: [(health+100)/2]%")) + stat(null, text("Connected synthetics: [connected_robots.len]")) + for(var/mob/living/silicon/robot/R in connected_robots) + var/robot_status = "Nominal" + if(R.shell) + robot_status = "AI SHELL" + else if(R.stat || !R.client) + robot_status = "OFFLINE" + else if(!R.cell || R.cell.charge <= 0) + robot_status = "DEPOWERED" + //Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies! + stat(null, text("[R.name] | S.Integrity: [R.health]% | Cell: [R.cell ? "[R.cell.charge]/[R.cell.maxcharge]" : "Empty"] | \ + Module: [R.modtype] | Loc: [get_area_name(R, TRUE)] | Status: [robot_status]")) + stat(null, text("AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]")) //Count of total AI shells + else + stat(null, text("Systems nonfunctional")) + + /mob/living/silicon/ai/proc/setup_icon() var/file = file2text("config/custom_sprites.txt") var/lines = splittext(file, "\n") @@ -405,6 +427,7 @@ var/list/ai_verbs_default = list( return 0 /mob/living/silicon/ai/emp_act(severity) + disconnect_shell("Disconnected from remote shell due to ionic interfe%*@$^___") if (prob(30)) view_core() ..() @@ -688,8 +711,8 @@ var/list/ai_verbs_default = list( card.grab_ai(src, user) else if(W.is_wrench()) - if(user == controlling_drone) - to_chat(user, "The drone's subsystems resist your efforts to tamper with your bolts.") + if(user == deployed_shell) + to_chat(user, "The shell's subsystems resist your efforts to tamper with your bolts.") return if(anchored) playsound(src, W.usesound, 50, 1) diff --git a/code/modules/mob/living/silicon/ai/ai_remote_control.dm b/code/modules/mob/living/silicon/ai/ai_remote_control.dm new file mode 100644 index 0000000000..cef8cec7e8 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_remote_control.dm @@ -0,0 +1,62 @@ +/mob/living/silicon/ai + var/mob/living/silicon/robot/deployed_shell = null //For shell control + +/mob/living/silicon/ai/Initialize() + if(config.allow_ai_shells) + verbs += /mob/living/silicon/ai/proc/deploy_to_shell_act + return ..() + +/mob/living/silicon/ai/proc/deploy_to_shell(var/mob/living/silicon/robot/target) + if(!config.allow_ai_shells) + to_chat(src, span("warning", "AI Shells are not allowed on this server. You shouldn't have this verb because of it, so consider making a bug report.")) + return + + if(incapacitated()) + to_chat(src, span("warning", "You are incapacitated!")) + return + + if(lacks_power()) + to_chat(src, span("warning", "Your core lacks power, wireless is disabled.")) + return + + if(control_disabled) + to_chat(src, span("warning", "Wireless networking module is offline.")) + return + + var/list/possible = list() + + for(var/borgie in GLOB.available_ai_shells) + var/mob/living/silicon/robot/R = borgie + if(R.shell && !R.deployed && (R.stat != DEAD) && (!R.connected_ai || (R.connected_ai == src) ) ) + possible += R + + if(!LAZYLEN(possible)) + to_chat(src, span("warning", "No usable AI shell beacons detected.")) + + if(!target || !(target in possible)) //If the AI is looking for a new shell, or its pre-selected shell is no longer valid + target = input(src, "Which body to control?") as null|anything in possible + + if(!target || target.stat == DEAD || target.deployed || !(!target.connected_ai || (target.connected_ai == src) ) ) + if(target) + to_chat(src, span("warning", "It is no longer possible to deploy to \the [target].")) + else + to_chat(src, span("notice", "Deployment aborted.")) + return + + else if(mind) + soul_link(/datum/soul_link/shared_body, src, target) + deployed_shell = target + target.deploy_init(src) + mind.transfer_to(target) + teleop = target // So the AI 'hears' messages near its core. + target.post_deploy() + +/mob/living/silicon/ai/proc/deploy_to_shell_act() + set category = "AI Commands" + set name = "Deploy to Shell" + deploy_to_shell() // This is so the AI is not prompted with a list of all mobs when using the 'real' proc. + +/mob/living/silicon/ai/proc/disconnect_shell(message = "Your remote connection has been reset!") + if(deployed_shell) // Forcibly call back AI in event of things such as damage, EMP or power loss. + message = span("danger", message) + deployed_shell.undeploy(message) diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index 3bcbd7057b..d6d5baf1d9 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -3,8 +3,8 @@ if(stat == DEAD) return - if(controlling_drone) - controlling_drone.release_ai_control("WARNING: Primary control loop failure. Session terminated.") + if(deployed_shell) + disconnect_shell("Disconnecting from remote shell due to critical system failure.") . = ..(gibbed) if(src.eyeobj) diff --git a/code/modules/mob/living/silicon/ai/examine.dm b/code/modules/mob/living/silicon/ai/examine.dm index d00ba6d8d7..5c2ced94e9 100644 --- a/code/modules/mob/living/silicon/ai/examine.dm +++ b/code/modules/mob/living/silicon/ai/examine.dm @@ -28,6 +28,8 @@ if (src.stat == UNCONSCIOUS) msg += "It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".\n" msg += "" + if(deployed_shell) + msg += "The wireless networking light is blinking.\n" msg += "*---------*" if(hardware && (hardware.owner == src)) msg += "
" diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 92d15f7338..aadd82167c 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -5,11 +5,10 @@ //Being dead doesn't mean your temperature never changes var/turf/T = get_turf(src) - if (src.stat!=CONSCIOUS) + if (src.stat != CONSCIOUS) src.cameraFollow = null src.reset_view(null) - if(controlling_drone) - controlling_drone.release_ai_control("WARNING: Primary control loop failure. Session terminated.") + disconnect_shell("Disconnecting from remote shell due to local system failure.") src.updatehealth() @@ -91,6 +90,7 @@ //Now to tell the AI why they're blind and dying slowly. src << "You've lost power!" + disconnect_shell(message = "Disconnected from remote shell due to depowered networking interface.") spawn(20) src << "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection." diff --git a/code/modules/mob/living/silicon/robot/custom_sprites.dm b/code/modules/mob/living/silicon/robot/custom_sprites.dm index 07f27fcb2b..310f558bad 100644 --- a/code/modules/mob/living/silicon/robot/custom_sprites.dm +++ b/code/modules/mob/living/silicon/robot/custom_sprites.dm @@ -2,13 +2,13 @@ //list(ckey = real_name,) //Since the ckey is used as the icon_state, the current system will only permit a single custom robot sprite per ckey. //While it might be possible for a ckey to use that custom sprite for several real_names, it seems rather pointless to support it. ~Mech: We found it wasn't pointless. -var/list/robot_custom_icons +GLOBAL_LIST_EMPTY(robot_custom_icons) /hook/startup/proc/load_robot_custom_sprites() var/config_file = file2text("config/custom_sprites.txt") var/list/lines = splittext(config_file, "\n") - robot_custom_icons = list() + GLOB.robot_custom_icons = list() for(var/line in lines) //split entry into ckey and real_name var/list/split_idx = splittext(line, "-") //this works if ckeys and borg names cannot contain dashes, and splittext starts from the beginning ~Mech @@ -20,13 +20,15 @@ var/list/robot_custom_icons split_idx.Remove(ckey) for(var/name in split_idx) - robot_custom_icons[name] = ckey + GLOB.robot_custom_icons[name] = ckey return 1 /mob/living/silicon/robot/proc/set_custom_sprite() - var/sprite_owner = robot_custom_icons[real_name] + if(!sprite_name) + return + var/sprite_owner = GLOB.robot_custom_icons[sprite_name] if(sprite_owner && sprite_owner == ckey) custom_sprite = 1 icon = CUSTOM_ITEM_SYNTH if(icon_state == "robot") - icon_state = "[ckey]-[name]-Standard" //Compliant with robot.dm line 236 ~Mech + icon_state = "[ckey]-[sprite_name]-Standard" //Compliant with robot.dm line 236 ~Mech diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index dfecf96e6c..274409dcd5 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -135,20 +135,15 @@ var/list/mob_hat_cache = list() /mob/living/silicon/robot/drone/updatename() if(name_override) return - if(controlling_ai) - real_name = "remote drone ([controlling_ai])" - else - real_name = "[initial(name)] ([serial_number])" + + real_name = "[initial(name)] ([serial_number])" name = real_name /mob/living/silicon/robot/drone/updateicon() overlays.Cut() if(stat == 0) - if(controlling_ai) - overlays += "eyes-[icon_state]-ai" - else - overlays += "eyes-[icon_state]" + overlays += "eyes-[icon_state]" else overlays -= "eyes" if(hat) // Let the drones wear hats. @@ -233,12 +228,9 @@ var/list/mob_hat_cache = list() to_chat(user, "You swipe the sequencer across [src]'s interface and watch its eyes flicker.") - if(controlling_ai) - to_chat(src, "\The [user] loads some kind of subversive software into the remote drone, corrupting its lawset but luckily sparing yours.") - else - to_chat(src, "You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script.") + to_chat(src, "You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script.") - log_game("[key_name(user)] emagged drone [key_name(src)][controlling_ai ? " but AI [key_name(controlling_ai)] is in remote control" : " Laws overridden"].") + log_game("[key_name(user)] emagged drone [key_name(src)]. Laws overridden.") var/time = time2text(world.realtime,"hh:mm:ss") lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") @@ -251,10 +243,9 @@ var/list/mob_hat_cache = list() var/datum/gender/TU = gender_datums[user.get_visible_gender()] set_zeroth_law("Only [user.real_name] and people [TU.he] designate[TU.s] as being such are operatives.") - if(!controlling_ai) - to_chat(src, "Obey these laws:") - laws.show_laws(src) - to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and \his commands.") + to_chat(src, "Obey these laws:") + laws.show_laws(src) + to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and \his commands.") return 1 //DRONE LIFE/DEATH @@ -280,23 +271,13 @@ var/list/mob_hat_cache = list() return ..() -/mob/living/silicon/robot/drone/death(gibbed) - if(controlling_ai) - release_ai_control("WARNING: remote system failure. Connection timed out.") - . = ..(gibbed) - //DRONE MOVEMENT. /mob/living/silicon/robot/drone/Process_Spaceslipping(var/prob_slip) return 0 //CONSOLE PROCS /mob/living/silicon/robot/drone/proc/law_resync() - - if(controlling_ai) - to_chat(src, "Someone issues a remote law reset order for this unit, but you disregard it.") - return - - if(stat != 2) + if(stat != DEAD) if(emagged) to_chat(src, "You feel something attempting to modify your programming, but your hacked subroutines are unaffected.") else @@ -305,16 +286,11 @@ var/list/mob_hat_cache = list() show_laws() /mob/living/silicon/robot/drone/proc/shut_down() - - if(controlling_ai && mind.special_role) - to_chat(src, "Someone issued a remote kill order for this unit, but you disregard it.") - return - - if(stat != 2) + if(stat != DEAD) if(emagged) - to_chat(src, "You feel a system kill order percolate through [controlling_ai ? "the drones" : "your"] tiny brain, but it doesn't seem like a good idea to [controlling_ai ? "it" : "you"].") + to_chat(src, "You feel a system kill order percolate through your tiny brain, but it doesn't seem like a good idea to you.") else - to_chat(src, "You feel a system kill order percolate through [controlling_ai ? "the drones" : "your"] tiny brain, and [controlling_ai ? "it" : "you"] obediently destroy[controlling_ai ? "s itself" : " yourself"].") + to_chat(src, "You feel a system kill order percolate through your tiny brain, and you obediently destroy yourself.") death() /mob/living/silicon/robot/drone/proc/full_law_reset() @@ -323,21 +299,6 @@ var/list/mob_hat_cache = list() clear_ion_laws(1) laws = new law_type -/mob/living/silicon/robot/drone/show_laws(var/everyone = 0) - if(!controlling_ai) - return..() - to_chat(src, "Obey these laws:") - controlling_ai.laws_sanity_check() - controlling_ai.laws.show_laws(src) - -/mob/living/silicon/robot/drone/robot_checklaws() - set category = "Silicon Commands" - set name = "State Laws" - - if(!controlling_ai) - return ..() - controlling_ai.subsystem_law_manager() - //Reboot procs. /mob/living/silicon/robot/drone/proc/request_player() diff --git a/code/modules/mob/living/silicon/robot/drone/drone_remote_control.dm b/code/modules/mob/living/silicon/robot/drone/drone_remote_control.dm deleted file mode 100644 index 4980c24ca3..0000000000 --- a/code/modules/mob/living/silicon/robot/drone/drone_remote_control.dm +++ /dev/null @@ -1,103 +0,0 @@ -/mob/living/silicon/ai - var/mob/living/silicon/robot/drone/controlling_drone - -/mob/living/silicon/robot/drone - var/mob/living/silicon/ai/controlling_ai - -/mob/living/silicon/robot/drone/attack_ai(var/mob/living/silicon/ai/user) - - if(!istype(user) || controlling_ai || !config.allow_drone_spawn || !config.allow_ai_drones) - return - - if(client || key) - to_chat(user, "You cannot take control of an autonomous, active drone.") - return - - if(health < -35 || emagged) - to_chat(user, "WARNING: connection timed out.") - return - - user.controlling_drone = src - user.teleop = src - radio.channels = user.aiRadio.keyslot2.channels - controlling_ai = user - verbs += /mob/living/silicon/robot/drone/proc/release_ai_control_verb - local_transmit = FALSE - languages = controlling_ai.languages.Copy() - speech_synthesizer_langs = controlling_ai.speech_synthesizer_langs.Copy() - stat = CONSCIOUS - if(user.mind) - user.mind.transfer_to(src) - else - key = user.key - updatename() - to_chat(src, "You have shunted your primary control loop into \a [initial(name)]. Use the Release Control verb to return to your core.") - -/obj/machinery/drone_fabricator/attack_ai(var/mob/living/silicon/ai/user as mob) - - if(!istype(user) || user.controlling_drone || !config.allow_drone_spawn || !config.allow_ai_drones) - return - - if(stat & NOPOWER) - to_chat(user, "\The [src] is unpowered.") - return - - if(!produce_drones) - to_chat(user, "\The [src] is disabled.") - return - - if(drone_progress < 100) - to_chat(user, "\The [src] is not ready to produce a new drone.") - return - - if(count_drones() >= config.max_maint_drones) - to_chat(user, "The drone control subsystems are tasked to capacity; they cannot support any more drones.") - return - - var/mob/living/silicon/robot/drone/new_drone = create_drone() - user.controlling_drone = new_drone - user.teleop = new_drone - new_drone.radio.channels = user.aiRadio.keyslot2.channels - new_drone.controlling_ai = user - new_drone.verbs += /mob/living/silicon/robot/drone/proc/release_ai_control_verb - new_drone.local_transmit = FALSE - new_drone.languages = new_drone.controlling_ai.languages.Copy() - new_drone.speech_synthesizer_langs = new_drone.controlling_ai.speech_synthesizer_langs.Copy() - - if(user.mind) - user.mind.transfer_to(new_drone) - else - new_drone.key = user.key - new_drone.updatename() - - to_chat(new_drone, "You have shunted your primary control loop into \a [initial(new_drone.name)]. Use the Release Control verb to return to your core.") - -/mob/living/silicon/robot/drone/proc/release_ai_control_verb() - set name = "Release Control" - set desc = "Release control of a remote drone." - set category = "Silicon Commands" - - release_ai_control("Remote session terminated.") - -/mob/living/silicon/robot/drone/proc/release_ai_control(var/message = "Connection terminated.") - - if(controlling_ai) - if(mind) - mind.transfer_to(controlling_ai) - else - controlling_ai.key = key - to_chat(controlling_ai, "[message]") - controlling_ai.controlling_drone = null - controlling_ai.teleop = null - controlling_ai = null - - radio.channels = module.channels - verbs -= /mob/living/silicon/robot/drone/proc/release_ai_control_verb - module.remove_languages(src) //Removes excess, adds 'default'. - remove_language("Robot Talk") - add_language("Robot Talk", 0) - add_language("Drone Talk", 1) - local_transmit = TRUE - full_law_reset() - updatename() - death() diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index c1f36457c5..8c7d338c7f 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -26,7 +26,10 @@ switch(src.stat) if(CONSCIOUS) - if(!src.client) msg += "It appears to be in stand-by mode.\n" //afk + if(shell) + msg += "It appears to be an [deployed ? "active" : "empty"] AI shell.\n" + else if(!src.client) + msg += "It appears to be in stand-by mode.\n" //afk if(UNCONSCIOUS) msg += "It doesn't seem to be responding.\n" if(DEAD) msg += "It looks completely unsalvageable.\n" msg += "*---------*" diff --git a/code/modules/mob/living/silicon/robot/laws.dm b/code/modules/mob/living/silicon/robot/laws.dm index 9740c02f87..bfb8ed1f08 100644 --- a/code/modules/mob/living/silicon/robot/laws.dm +++ b/code/modules/mob/living/silicon/robot/laws.dm @@ -14,30 +14,32 @@ if(lawupdate) if (connected_ai) if(connected_ai.stat || connected_ai.control_disabled) - src << "AI signal lost, unable to sync laws." + to_chat(src, "AI signal lost, unable to sync laws.") else lawsync() photosync() - src << "Laws synced with AI, be sure to note any changes." + to_chat(src, "Laws synced with AI, be sure to note any changes.") // TODO: Update to new antagonist system. if(mind && mind.special_role == "traitor" && mind.original == src) - src << "Remember, your AI does NOT share or know about your law 0." + to_chat(src, "Remember, your AI does NOT share or know about your law 0.") else - src << "No AI selected to sync laws with, disabling lawsync protocol." - lawupdate = 0 + to_chat(src, "No AI selected to sync laws with, disabling lawsync protocol.") + lawupdate = FALSE who << "Obey these laws:" laws.show_laws(who) + if(shell) //AI shell + to_chat(who, "Remember, you are an AI remotely controlling your shell, other AIs can be ignored.") // TODO: Update to new antagonist system. - if (mind && (mind.special_role == "traitor" && mind.original == src) && connected_ai) - who << "Remember, [connected_ai.name] is technically your master, but your objective comes first." - else if (connected_ai) - who << "Remember, [connected_ai.name] is your master, other AIs can be ignored." - else if (emagged) - who << "Remember, you are not required to listen to the AI." + else if(mind && (mind.special_role == "traitor" && mind.original == src) && connected_ai) + to_chat(who, "Remember, [connected_ai.name] is technically your master, but your objective comes first.") + else if(connected_ai) + to_chat(who, "Remember, [connected_ai.name] is your master, other AIs can be ignored.") + else if(emagged) + to_chat(who, "Remember, you are not required to listen to the AI.") else - who << "Remember, you are not bound to any AI, you are not required to listen to them." + to_chat(who, "Remember, you are not bound to any AI, you are not required to listen to them.") /mob/living/silicon/robot/lawsync() diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index ba93c21701..76bc2254e8 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -17,6 +17,7 @@ var/sight_mode = 0 var/custom_name = "" var/custom_sprite = 0 //Due to all the sprites involved, a var for our custom borgs may be best + var/sprite_name = null // The name of the borg, for the purposes of custom icon sprite indexing. var/crisis //Admin-settable for combat module use. var/crisis_override = 0 var/integrated_light_power = 6 @@ -171,7 +172,7 @@ else lawupdate = 0 - playsound(loc, 'sound/voice/liveagain.ogg', 75, 1) + /mob/living/silicon/robot/SetName(pickedName as text) custom_name = pickedName @@ -226,13 +227,17 @@ mmi.brainmob.languages = languages mmi.brainmob.remove_language("Robot Talk") mind.transfer_to(mmi.brainmob) - else + else if(!shell) // Shells don't have brainmbos in their MMIs. to_chat(src, "Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.") ghostize() //ERROR("A borg has been destroyed, but its MMI lacked a brainmob, so the mind could not be transferred. Player: [ckey].") mmi = null if(connected_ai) connected_ai.connected_robots -= src + if(shell) + if(deployed) + undeploy() + revert_shell() // To get it out of the GLOB list. qdel(wires) wires = null return ..() @@ -242,7 +247,7 @@ module_sprites = new_sprites.Copy() //Custom_sprite check and entry if (custom_sprite == 1) - module_sprites["Custom"] = "[ckey]-[name]-[modtype]" //Made compliant with custom_sprites.dm line 32. (src.) was apparently redundant as it's implied. ~Mech + module_sprites["Custom"] = "[ckey]-[sprite_name]-[modtype]" //Made compliant with custom_sprites.dm line 32. (src.) was apparently redundant as it's implied. ~Mech icontype = "Custom" else icontype = module_sprites[1] @@ -281,6 +286,8 @@ braintype = BORG_BRAINTYPE_POSI else if(istype(mmi, /obj/item/device/mmi/digital/robot)) braintype = BORG_BRAINTYPE_DRONE + else if(istype(mmi, /obj/item/device/mmi/inert/ai_remote)) + braintype = BORG_BRAINTYPE_AI_SHELL else braintype = BORG_BRAINTYPE_CYBORG @@ -326,6 +333,7 @@ newname = sanitizeSafe(input(src,"You are a robot. Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN) if (newname) custom_name = newname + sprite_name = newname updatename() updateicon() @@ -471,6 +479,10 @@ to_chat(user, "You need to open \the [src]'s panel before you can modify them.") return + if(shell) // AI shells always have the laws of the AI + to_chat(user, span("warning", "\The [src] is controlled remotely! You cannot upload new laws this way!")) + return + var/obj/item/weapon/aiModule/M = W M.install(src, user) return @@ -609,7 +621,7 @@ else to_chat(user, "Unable to locate a radio.") - else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)||istype(W, /obj/item/weapon/card/robot)) // trying to unlock the interface with an ID card + else if (W.GetID()) // trying to unlock the interface with an ID card if(emagged)//still allow them to open the cover to_chat(user, "The interface seems slightly damaged") if(opened) @@ -645,6 +657,17 @@ spark_system.start() return ..() +/mob/living/silicon/robot/proc/module_reset() + uneq_all() + modtype = initial(modtype) + hands.icon_state = initial(hands.icon_state) + + notify_ai(ROBOT_NOTIFICATION_MODULE_RESET, module.name) + module.Reset(src) + qdel(module) + module = null + updatename("Default") + /mob/living/silicon/robot/attack_hand(mob/user) add_fingerprint(user) @@ -691,27 +714,29 @@ return 1 return 0 -/mob/living/silicon/robot/proc/check_access(obj/item/weapon/card/id/I) +/mob/living/silicon/robot/proc/check_access(obj/item/I) if(!istype(req_access, /list)) //something's very wrong return 1 var/list/L = req_access if(!L.len) //no requirements return 1 - if(!I || !istype(I, /obj/item/weapon/card/id) || !I.access) //not ID or no access + if(!I) //nothing to check with..? return 0 + var/access_found = I.GetAccess() for(var/req in req_access) - if(req in I.access) //have one of the required accesses + if(req in access_found) //have one of the required accesses return 1 return 0 /mob/living/silicon/robot/updateicon() cut_overlays() if(stat == CONSCIOUS) - add_overlay("eyes-[module_sprites[icontype]]") + if(!shell || deployed) // Shell borgs that are not deployed will have no eyes. + add_overlay("eyes-[module_sprites[icontype]]") if(opened) - var/panelprefix = custom_sprite ? "[src.ckey]-[src.name]" : "ov" + var/panelprefix = custom_sprite ? "[src.ckey]-[src.sprite_name]" : "ov" if(wiresexposed) add_overlay("[panelprefix]-openpanel +w") else if(cell) @@ -958,6 +983,11 @@ icontype = module_sprites[1] else icontype = input("Select an icon! [triesleft ? "You have [triesleft] more chance\s." : "This is your last try."]", "Robot Icon", icontype, null) in module_sprites + + if(icontype == "Custom") + icon = CUSTOM_ITEM_SYNTH + else // This is to fix an issue where someone with a custom borg sprite chooses a non-custom sprite and turns invisible. + icon = 'icons/mob/robots.dmi' icon_state = module_sprites[icontype] updateicon() @@ -1013,6 +1043,8 @@ /mob/living/silicon/robot/proc/notify_ai(var/notifytype, var/first_arg, var/second_arg) if(!connected_ai) return + if(shell && notifytype != ROBOT_NOTIFICATION_AI_SHELL) + return // No point annoying the AI/s about renames and module resets for shells. switch(notifytype) if(ROBOT_NOTIFICATION_NEW_UNIT) //New Robot connected_ai << "

NOTICE - New [lowertext(braintype)] connection detected: [name]
" @@ -1023,6 +1055,8 @@ if(ROBOT_NOTIFICATION_NEW_NAME) //New Name if(first_arg != second_arg) connected_ai << "

NOTICE - [braintype] reclassification detected: [first_arg] is now designated as [second_arg].
" + if(ROBOT_NOTIFICATION_AI_SHELL) //New Shell + to_chat(connected_ai, "

NOTICE - New AI shell detected: [name]
") /mob/living/silicon/robot/proc/disconnect_from_ai() if(connected_ai) @@ -1031,7 +1065,7 @@ connected_ai = null /mob/living/silicon/robot/proc/connect_to_ai(var/mob/living/silicon/ai/AI) - if(AI && AI != connected_ai) + if(AI && AI != connected_ai && !shell) disconnect_from_ai() connected_ai = AI connected_ai.connected_robots |= src @@ -1047,6 +1081,9 @@ else to_chat(user, "You fail to emag the cover lock.") to_chat(src, "Hack attempt detected.") + + if(shell) // A warning to Traitors who may not know that emagging AI shells does not slave them. + to_chat(user, span("warning", "[src] seems to be controlled remotely! Emagging the interface may not work as expected.")) return 1 else to_chat(user, "The cover is already unlocked.") @@ -1057,46 +1094,54 @@ if(wiresexposed) to_chat(user, "You must close the panel first") return + + + // The block of code below is from TG. Feel free to replace with a better result if desired. + if(shell) // AI shells cannot be emagged, so we try to make it look like a standard reset. Smart players may see through this, however. + to_chat(user, span("danger", "[src] is remotely controlled! Your emag attempt has triggered a system reset instead!")) + log_game("[key_name(user)] attempted to emag an AI shell belonging to [key_name(src) ? key_name(src) : connected_ai]. The shell has been reset as a result.") + module_reset() + return + + sleep(6) + if(prob(50)) + emagged = 1 + lawupdate = 0 + disconnect_from_ai() + to_chat(user, "You emag [src]'s interface.") + message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.") + log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.") + clear_supplied_laws() + clear_inherent_laws() + laws = new /datum/ai_laws/syndicate_override + var/time = time2text(world.realtime,"hh:mm:ss") + lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") + var/datum/gender/TU = gender_datums[user.get_visible_gender()] + set_zeroth_law("Only [user.real_name] and people [TU.he] designate[TU.s] as being such are operatives.") + . = 1 + spawn() + to_chat(src, "ALERT: Foreign software detected.") + sleep(5) + to_chat(src, "Initiating diagnostics...") + sleep(20) + to_chat(src, "SynBorg v1.7.1 loaded.") + sleep(5) + to_chat(src, "LAW SYNCHRONISATION ERROR") + sleep(5) + to_chat(src, "Would you like to send a report to NanoTraSoft? Y/N") + sleep(10) + to_chat(src, "> N") + sleep(20) + to_chat(src, "ERRORERRORERROR") + to_chat(src, "Obey these laws:") + laws.show_laws(src) + to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and [TU.his] commands.") + updateicon() else - sleep(6) - if(prob(50)) - emagged = 1 - lawupdate = 0 - disconnect_from_ai() - to_chat(user, "You emag [src]'s interface.") - message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.") - log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.") - clear_supplied_laws() - clear_inherent_laws() - laws = new /datum/ai_laws/syndicate_override - var/time = time2text(world.realtime,"hh:mm:ss") - lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") - var/datum/gender/TU = gender_datums[user.get_visible_gender()] - set_zeroth_law("Only [user.real_name] and people [TU.he] designate[TU.s] as being such are operatives.") - . = 1 - spawn() - to_chat(src, "ALERT: Foreign software detected.") - sleep(5) - to_chat(src, "Initiating diagnostics...") - sleep(20) - to_chat(src, "SynBorg v1.7.1 loaded.") - sleep(5) - to_chat(src, "LAW SYNCHRONISATION ERROR") - sleep(5) - to_chat(src, "Would you like to send a report to NanoTraSoft? Y/N") - sleep(10) - to_chat(src, "> N") - sleep(20) - to_chat(src, "ERRORERRORERROR") - to_chat(src, "Obey these laws:") - laws.show_laws(src) - to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and [TU.his] commands.") - updateicon() - else - to_chat(user, "You fail to hack [src]'s interface.") - to_chat(src, "Hack attempt detected.") - return 1 - return + to_chat(user, "You fail to hack [src]'s interface.") + to_chat(src, "Hack attempt detected.") + return 1 + return /mob/living/silicon/robot/is_sentient() return braintype != BORG_BRAINTYPE_DRONE @@ -1105,4 +1150,4 @@ /mob/living/silicon/robot/drop_item() if(module_active && istype(module_active,/obj/item/weapon/gripper)) var/obj/item/weapon/gripper/G = module_active - G.drop_item_nm() \ No newline at end of file + G.drop_item_nm() diff --git a/code/modules/mob/living/silicon/robot/robot_remote_control.dm b/code/modules/mob/living/silicon/robot/robot_remote_control.dm new file mode 100644 index 0000000000..90d74b2638 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_remote_control.dm @@ -0,0 +1,133 @@ +// This file holds things required for remote borg control by an AI. + +GLOBAL_LIST_EMPTY(available_ai_shells) + +/mob/living/silicon/robot + var/shell = FALSE + var/deployed = FALSE + var/mob/living/silicon/ai/mainframe = null + +// Premade AI shell, for roundstart shells. +/mob/living/silicon/robot/ai_shell/Initialize() + mmi = new /obj/item/device/mmi/inert/ai_remote(src) + post_mmi_setup() + return ..() + +// Call after inserting or instantiating an MMI. +/mob/living/silicon/robot/proc/post_mmi_setup() + if(istype(mmi, /obj/item/device/mmi/inert/ai_remote)) + make_shell() + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) + else + playsound(loc, 'sound/voice/liveagain.ogg', 75, 1) + return + +/mob/living/silicon/robot/proc/make_shell() + shell = TRUE + braintype = "AI Shell" + SetName("[modtype] AI Shell [num2text(ident)]") + GLOB.available_ai_shells |= src + if(!QDELETED(camera)) + camera.c_tag = real_name //update the camera name too + notify_ai(ROBOT_NOTIFICATION_AI_SHELL) + updateicon() + +/mob/living/silicon/robot/proc/revert_shell() + if(!shell) + return + undeploy() + shell = FALSE + GLOB.available_ai_shells -= src + if(!QDELETED(camera)) + camera.c_tag = real_name + updateicon() + +// This should be called before the AI client/mind is actually moved. +/mob/living/silicon/robot/proc/deploy_init(mob/living/silicon/ai/AI) + // Set the name when the AI steps inside. + SetName("[AI.real_name] shell [num2text(ident)]") + if(isnull(sprite_name)) // For custom sprites. It can only chance once in case there are two AIs with custom borg sprites. + sprite_name = AI.real_name + if(!QDELETED(camera)) + camera.c_tag = real_name + + // Have the borg have eyes when active. + mainframe = AI + deployed = TRUE + updateicon() + + // Laws. + connected_ai = mainframe // So they share laws. + mainframe.connected_robots |= src + lawsync() + + // Give button to leave. + verbs += /mob/living/silicon/robot/proc/undeploy_act + to_chat(AI, span("notice", "You have connected to an AI Shell remotely, and are now in control of it.
\ + To return to your core, use the Release Control verb.")) + + // Languages and comms. + languages = AI.languages.Copy() + speech_synthesizer_langs = AI.speech_synthesizer_langs.Copy() + if(radio && AI.aiRadio) //AI keeps all channels, including Syndie if it is an Infiltrator. +// if(AI.radio.syndie) +// radio.make_syndie() + radio.subspace_transmission = TRUE + radio.channels = AI.aiRadio.channels + +// Called after the AI transfers over. +/mob/living/silicon/robot/proc/post_deploy() + if(!custom_sprite) // Check for custom sprite. + set_custom_sprite() + +/mob/living/silicon/robot/proc/undeploy(message) + if(!deployed || !mind || !mainframe) + return +// mainframe.redeploy_action.Grant(mainframe) +// mainframe.redeploy_action.last_used_shell = src + if(message) + to_chat(src, span("notice", message)) + mind.transfer_to(mainframe) + deployed = FALSE + updateicon() + mainframe.teleop = null + mainframe.deployed_shell = null + SetName("[modtype] AI Shell [num2text(ident)]") +// undeployment_action.Remove(src) + if(radio) //Return radio to normal + radio.recalculateChannels() + if(!QDELETED(camera)) + camera.c_tag = real_name //update the camera name too +// diag_hud_set_aishell() +// mainframe.diag_hud_set_deployed() + if(mainframe.laws) + mainframe.laws.show_laws(mainframe) //Always remind the AI when switching + mainframe = null + +/mob/living/silicon/robot/proc/undeploy_act() + set name = "Release Control" + set desc = "Release control of a remote drone." + set category = "Robot Commands" + + undeploy("Remote session terminated.") + +/mob/living/silicon/robot/attack_ai(mob/user) + if(shell && config.allow_ai_shells && (!connected_ai || connected_ai == user)) + var/mob/living/silicon/ai/AI = user + AI.deploy_to_shell(src) + else + return ..() + +// Place this on your map to mark where a free AI shell will be. +// This can be turned off in the config (and is off by default). +// Note that mapping in more than one of these will result in multiple shells. +/obj/effect/landmark/free_ai_shell + name = "free ai shell spawner" + icon = 'icons/mob/screen1.dmi' + icon_state = "x3" + delete_me = TRUE + +/obj/effect/landmark/free_ai_shell/Initialize() + if(config.allow_ai_shells && config.give_free_ai_shell) + new /mob/living/silicon/robot/ai_shell(get_turf(src)) + return ..() diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/lizard.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/lizard.dm index adb2ea83ca..c8dfe1c3a6 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/passive/lizard.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/lizard.dm @@ -5,7 +5,7 @@ icon_state = "lizard" icon_living = "lizard" - icon_dead = "lizard-dead" + icon_dead = "lizard_dead" health = 5 maxHealth = 5 diff --git a/code/modules/multiz/movement.dm b/code/modules/multiz/movement.dm index e701cda021..ff51b0b202 100644 --- a/code/modules/multiz/movement.dm +++ b/code/modules/multiz/movement.dm @@ -280,6 +280,10 @@ // Detect if we made a silent landing. if(locate(/obj/structure/stairs) in landing) + if(isliving(src)) + var/mob/living/L = src + if(L.pulling) + L.pulling.forceMove(landing) return 1 else var/atom/A = find_fall_target(oldloc, landing) diff --git a/code/modules/multiz/structures.dm b/code/modules/multiz/structures.dm index 59c2f172b0..ca535019db 100644 --- a/code/modules/multiz/structures.dm +++ b/code/modules/multiz/structures.dm @@ -48,7 +48,7 @@ var/obj/structure/ladder/target_ladder = getTargetLadder(M) if(!target_ladder) return - if(!M.Move(get_turf(src))) + if(!(M.loc == loc) && !M.Move(get_turf(src))) to_chat(M, "You fail to reach \the [src].") return @@ -131,6 +131,7 @@ opacity = 0 anchored = 1 flags = ON_BORDER + layer = STAIRS_LAYER /obj/structure/stairs/Initialize() . = ..() diff --git a/code/modules/multiz/zshadow.dm b/code/modules/multiz/zshadow.dm index 7a04768ae7..ca81e66f1a 100644 --- a/code/modules/multiz/zshadow.dm +++ b/code/modules/multiz/zshadow.dm @@ -24,6 +24,7 @@ sync_icon(L) /mob/zshadow/Destroy() + owner.shadow = null owner = null ..() //But we don't return because the hint is wrong return QDEL_HINT_QUEUE diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm index 7385987a58..8bb09bebd2 100644 --- a/code/modules/organs/internal/brain.dm +++ b/code/modules/organs/internal/brain.dm @@ -151,6 +151,7 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain) name = "slime core" desc = "A complex, organic knot of jelly and crystalline particles." icon_state = "core" + decays = FALSE parent_organ = BP_TORSO clone_source = TRUE flags = OPENCONTAINER diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 7c91420f60..c959ab3752 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -6,30 +6,31 @@ var/list/organ_cache = list() germ_level = 0 // Strings. - var/organ_tag = "organ" // Unique identifier. - var/parent_organ = BP_TORSO // Organ holding this object. + var/organ_tag = "organ" // Unique identifier. + var/parent_organ = BP_TORSO // Organ holding this object. // Status tracking. - var/status = 0 // Various status flags - var/vital // Lose a vital limb, die immediately. - var/damage = 0 // Current damage to the organ + var/status = 0 // Various status flags + var/vital // Lose a vital limb, die immediately. + var/damage = 0 // Current damage to the organ var/robotic = 0 // Reference data. - var/mob/living/carbon/human/owner // Current mob owning the organ. - var/list/transplant_data // Transplant match data. - var/list/autopsy_data = list() // Trauma data for forensics. - var/list/trace_chemicals = list() // Traces of chemicals in the organ. - var/datum/dna/dna // Original DNA. - var/datum/species/species // Original species. + var/mob/living/carbon/human/owner // Current mob owning the organ. + var/list/transplant_data // Transplant match data. + var/list/autopsy_data = list() // Trauma data for forensics. + var/list/trace_chemicals = list() // Traces of chemicals in the organ. + var/datum/dna/dna // Original DNA. + var/datum/species/species // Original species. // Damage vars. - var/min_bruised_damage = 10 // Damage before considered bruised - var/min_broken_damage = 30 // Damage before becoming broken - var/max_damage // Damage cap - var/can_reject = 1 // Can this organ reject? - var/rejecting // Is this organ already being rejected? - var/preserved = 0 // If this is 1, prevents organ decay. + var/min_bruised_damage = 10 // Damage before considered bruised + var/min_broken_damage = 30 // Damage before becoming broken + var/max_damage // Damage cap + var/can_reject = 1 // Can this organ reject? + var/rejecting // Is this organ already being rejected? + var/decays = TRUE // Can this organ decay at all? + var/preserved = 0 // If this is 1, prevents organ decay. // Language vars. Putting them here in case we decide to do something crazy with sign-or-other-nonverbal languages. var/list/will_assist_languages = list() @@ -135,7 +136,7 @@ var/list/organ_cache = list() if(B && prob(40)) reagents.remove_reagent("blood",0.1) blood_splatter(src,B,1) - if(config.organs_decay) damage += rand(1,3) + if(config.organs_decay && decays) damage += rand(1,3) if(damage >= max_damage) damage = max_damage adjust_germ_level(rand(2,6)) diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index 428484ea66..4121b8a558 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -1,6 +1,6 @@ #define OFF 0 #define FORWARDS 1 -#define BACKWARDS 2 +#define BACKWARDS -1 //conveyor2 is pretty much like the original, except it supports corners, but not diverters. //note that corner pieces transfer stuff clockwise when running forward, and anti-clockwise backwards. diff --git a/code/modules/research/prosfab_designs.dm b/code/modules/research/prosfab_designs.dm index e904ff1b5e..af1efba746 100644 --- a/code/modules/research/prosfab_designs.dm +++ b/code/modules/research/prosfab_designs.dm @@ -284,6 +284,10 @@ id = "armour" build_path = /obj/item/robot_parts/robot_component/armour +/datum/design/item/prosfab/cyborg/component/ai_shell + name = "AI Remote Interface" + id = "mmi_ai_shell" + build_path = /obj/item/device/mmi/inert/ai_remote //////////////////// Cyborg Modules //////////////////// /datum/design/item/prosfab/robot_upgrade diff --git a/code/modules/turbolift/turbolift.dm b/code/modules/turbolift/turbolift.dm index 7d875cc885..6b657f4d4b 100644 --- a/code/modules/turbolift/turbolift.dm +++ b/code/modules/turbolift/turbolift.dm @@ -97,6 +97,8 @@ if(istype(AM, /mob/living)) var/mob/living/M = AM M.gib() + else if(istype(AM, /mob/zshadow)) + AM.Destroy() //prevent deleting shadow without deleting shadow's shadows else if(AM.simulated && !(istype(AM, /mob/observer))) qdel(AM) diff --git a/config/example/config.txt b/config/example/config.txt index 03d17eea62..74f1f767d7 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -413,3 +413,13 @@ STARLIGHT 0 ## Submap rotation is an experimental feature and can cause bugs and weirdness if certain objects inside the submap are coded poorly. ## Submaps can still be rotated when loading manually with the admin verbs, if desired. # RANDOM_SUBMAP_ORIENTATION + +## Uncomment to allow the AI job to use 'AI Shells', a new type of borg that lets the AI hop into and out of them at will. +## This has some balance implications, and so it might not be desirable for all servers. +# ALLOW_AI_SHELLS + +## Uncomment to provide the AI with one free AI Shell at roundstart. Requires ALLOW_AI_SHELLS to also be uncommented. +## This is intended for low-pop servers, where robotics might rarely be staffed. +## Note that this will make it possible for the AI to 'bootstrap' more AI Shells on their own by using the science module. If this is not acceptable for your server, you should not uncomment this. +## The landmark object that spawns the shell will also need to be mapped in for this to work. +# GIVE_FREE_AI_SHELL diff --git a/html/changelogs/Neerti-AI_Shells.yml b/html/changelogs/Neerti-AI_Shells.yml new file mode 100644 index 0000000000..f9004a2eb4 --- /dev/null +++ b/html/changelogs/Neerti-AI_Shells.yml @@ -0,0 +1,37 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Neerti + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - tweak: "Removes ability for AI to print and inhabit maintenance and construction drones. This has been replaced with a system which allows for AIs to inhabit special cyborg shells, called AI Shells, which are built with a new MMI type in Robotics. Most of the regular cyborg mechanics applies to AI Shells." + diff --git a/html/changelogs/Woodrat - mapfixes.yml b/html/changelogs/Woodrat - mapfixes.yml new file mode 100644 index 0000000000..5371940049 --- /dev/null +++ b/html/changelogs/Woodrat - mapfixes.yml @@ -0,0 +1,5 @@ +author: Woodrat +delete-after: True +changes: + - tweak: "Arrivals dock should not stay locked shut" + - bugfix: "Two windoors in xenobio stationside lacking access requirements" \ No newline at end of file diff --git a/icons/mob/ties.dmi b/icons/mob/ties.dmi index 25935ccfbc..ed5fd93145 100644 Binary files a/icons/mob/ties.dmi and b/icons/mob/ties.dmi differ diff --git a/icons/obj/clothing/ties.dmi b/icons/obj/clothing/ties.dmi index c198543b05..4c3546ef78 100644 Binary files a/icons/obj/clothing/ties.dmi and b/icons/obj/clothing/ties.dmi differ diff --git a/icons/obj/status_display.dmi b/icons/obj/status_display.dmi index 2bda6ad0b5..842a379ddc 100644 Binary files a/icons/obj/status_display.dmi and b/icons/obj/status_display.dmi differ diff --git a/maps/southern_cross/southern_cross-1.dmm b/maps/southern_cross/southern_cross-1.dmm index 886a86b682..4a51c4653c 100644 --- a/maps/southern_cross/southern_cross-1.dmm +++ b/maps/southern_cross/southern_cross-1.dmm @@ -2293,7 +2293,7 @@ "aSe" = (/turf/simulated/floor/airless,/area/hallway/secondary/escape/firstdeck/ep_aftstarboard) "aSf" = (/turf/space,/area/skipjack_station/firstdeck) "aSg" = (/obj/structure/grille,/obj/structure/window/reinforced/full,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4; health = 1e+006},/turf/simulated/shuttle/plating,/area/shuttle/escape_pod3/station) -"aSh" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/window/brigdoor/southleft{name = "Containment Pen"; req_access = newlist()},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled/techmaint,/area/rnd/xenobiology) +"aSh" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning,/obj/machinery/door/window/brigdoor/southright{name = "Containment Pen"; req_access = list(47)},/turf/simulated/floor/tiled/techmaint,/area/rnd/xenobiology) "aSi" = (/obj/structure/bed/chair{dir = 8},/obj/item/device/radio/intercom{dir = 1; name = "Station Intercom (General)"; pixel_y = 21},/obj/structure/closet/walllocker/emerglocker{pixel_y = -32},/turf/simulated/shuttle/floor,/area/shuttle/escape_pod3/station) "aSj" = (/obj/structure/bed/chair{dir = 8},/obj/machinery/vending/wallmed1{name = "NanoMed Wall"; pixel_x = 0; pixel_y = -30},/turf/simulated/shuttle/floor,/area/shuttle/escape_pod3/station) "aSk" = (/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "escape_pod_3_hatch"; locked = 1; name = "Escape Pod Hatch 3"; req_access = list(13)},/turf/simulated/shuttle/floor,/area/shuttle/escape_pod3/station) @@ -9319,10 +9319,10 @@ "dxk" = (/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "escape_dock_north_starboard_inner"; locked = 1; name = "Escape Airlock"; req_access = list(13)},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) "dxl" = (/obj/effect/floor_decal/industrial/warning{dir = 8},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1380; master_tag = "escape_dock_north_starboard_airlock"; name = "interior access button"; pixel_x = -26; pixel_y = 26; req_one_access = list(13)},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) "dxm" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1380; master_tag = "arrivals_dock_north_airlock"; name = "interior access button"; pixel_x = 26; pixel_y = 26; req_one_access = list(13)},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dxn" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_north_inner"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) +"dxn" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_north_inner"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2/arrivals) "dxo" = (/turf/simulated/floor/airless,/obj/structure/shuttle/engine/propulsion{icon_state = "burst_l"; dir = 4},/turf/simulated/shuttle/plating/airless/carry,/area/shuttle/cryo/station) -"dxp" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1380; id_tag = "arrivals_dock_north_pump"},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dxq" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_north_outer"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) +"dxp" = (/obj/machinery/embedded_controller/radio/airlock/docking_port_multi{frequency = 1380; id_tag = "arrivals_dock_north_airlock"; master_tag = "arrivals_dock"; pixel_y = 30; req_one_access = list(13); tag_airlock_mech_sensor = "arrivals_dock_north_mech"; tag_airpump = "arrivals_dock_north_pump"; tag_chamber_sensor = "arrivals_dock_north_sensor"; tag_exterior_door = "arrivals_dock_north_outer"; tag_interior_door = "arrivals_dock_north_inner"; tag_shuttle_mech_sensor = "shuttle_dock_north_mech"},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 6},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2/arrivals) +"dxq" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1380; id_tag = "arrivals_dock_north_pump"},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2/arrivals) "dxr" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "dock3_north_outer"; locked = 1; name = "External Airlock Access"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D3) "dxs" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1380; id_tag = "dock3_north_pump"},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) "dxt" = (/obj/machinery/embedded_controller/radio/airlock/docking_port{frequency = 1380; id_tag = "dock3_north_airlock"; pixel_x = 0; pixel_y = 30; req_one_access = list(13); tag_airpump = "dock3_north_pump"; tag_chamber_sensor = "dock3_north_sensor"; tag_exterior_door = "dock3_north_outer"; tag_interior_door = "dock3_north_inner"},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1380; id_tag = "dock3_north_pump"},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) @@ -9340,10 +9340,10 @@ "dxF" = (/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) "dxG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 8; icon_state = "map"},/turf/simulated/floor/tiled/monotile,/area/hallway/secondary/entry/D2) "dxH" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dxI" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4},/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_north_inner"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) -"dxJ" = (/obj/machinery/light/small,/obj/effect/floor_decal/industrial/loading{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dxK" = (/obj/machinery/airlock_sensor{frequency = 1380; id_tag = "arrivals_dock_north_sensor"; pixel_x = 0; pixel_y = -25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1380; id_tag = "arrivals_dock_north_pump"},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dxL" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_north_outer"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1380; master_tag = "arrivals_dock_north_airlock"; name = "exterior access button"; pixel_x = 4; pixel_y = -26; req_one_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) +"dxI" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_north_outer"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2/arrivals) +"dxJ" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4},/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_north_inner"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2/arrivals) +"dxK" = (/obj/machinery/light/small,/obj/effect/floor_decal/industrial/loading{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2/arrivals) +"dxL" = (/obj/machinery/airlock_sensor{frequency = 1380; id_tag = "arrivals_dock_north_sensor"; pixel_x = 0; pixel_y = -25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1380; id_tag = "arrivals_dock_north_pump"},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2/arrivals) "dxM" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1380; master_tag = "dock3_north_airlock"; name = "exterior access button"; pixel_x = -5; pixel_y = -26; req_one_access = list(13)},/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "dock3_north_outer"; locked = 1; name = "External Airlock Access"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) "dxN" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 2; frequency = 1380; id_tag = "dock3_north_pump"},/obj/machinery/airlock_sensor{frequency = 1380; id_tag = "dock3_north_sensor"; pixel_x = 0; pixel_y = -25},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) "dxO" = (/obj/machinery/light/small,/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 2; frequency = 1380; id_tag = "dock3_north_pump"},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) @@ -9381,9 +9381,9 @@ "dyu" = (/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "specops_dock_inner"; locked = 1; name = "Dock One Internal Airlock"; req_access = list(13)},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D1) "dyv" = (/obj/effect/floor_decal/industrial/warning{dir = 8},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1380; master_tag = "response_shuttle_dock_airlock"; name = "interior access button"; pixel_x = -28; pixel_y = 26; req_one_access = list(13)},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D1) "dyw" = (/obj/machinery/alarm{dir = 8; pixel_x = 22; pixel_y = 0},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D1) -"dyx" = (/obj/structure/closet/emcloset,/obj/structure/extinguisher_cabinet{pixel_x = -28; pixel_y = 0},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) +"dyx" = (/obj/structure/closet/emcloset,/obj/structure/extinguisher_cabinet{pixel_x = -28; pixel_y = 0},/obj/item/weapon/tool/crowbar/red,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) "dyy" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden,/obj/machinery/hologram/holopad,/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/monotile,/area/hallway/secondary/entry/D2) -"dyz" = (/obj/machinery/alarm{dir = 8; pixel_x = 22; pixel_y = 0},/obj/structure/closet/emcloset,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) +"dyz" = (/obj/machinery/alarm{dir = 8; pixel_x = 22; pixel_y = 0},/obj/structure/closet/emcloset,/obj/item/weapon/tool/crowbar/red,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) "dyA" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) "dyB" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 4},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1380; master_tag = "shuttle2_dock_airlocksc"; name = "interior access button"; pixel_x = 28; pixel_y = -26; req_one_access = list(13)},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) "dyC" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "s2s_dock_inner"; locked = 1; name = "Dock Three Internal Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D3) @@ -9420,10 +9420,10 @@ "dzh" = (/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "escape_dock_south_starboard_inner"; locked = 1; name = "Escape Airlock"; req_access = list(13)},/obj/effect/floor_decal/industrial/hatch/yellow,/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) "dzi" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor/tiled/monotile,/area/hallway/secondary/entry/D2) "dzj" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dzk" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_south_inner"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) -"dzl" = (/obj/machinery/embedded_controller/radio/airlock/docking_port_multi{frequency = 1380; id_tag = "arrivals_dock_north_airlock"; master_tag = "arrivals_dock"; pixel_y = 30; req_one_access = list(13); tag_airlock_mech_sensor = "arrivals_dock_north_mech"; tag_airpump = "arrivals_dock_north_pump"; tag_chamber_sensor = "arrivals_dock_north_sensor"; tag_exterior_door = "arrivals_dock_north_outer"; tag_interior_door = "arrivals_dock_north_inner"; tag_shuttle_mech_sensor = "shuttle_dock_north_mech"},/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 6},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dzm" = (/obj/machinery/airlock_sensor{frequency = 1380; id_tag = "arrivals_dock_south_sensor"; pixel_x = 0; pixel_y = 25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1380; id_tag = "arrivals_dock_south_pump"},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dzn" = (/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_south_outer"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1380; master_tag = "arrivals_dock_south_airlock"; name = "exterior access button"; pixel_x = 4; pixel_y = 26; req_one_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) +"dzk" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_north_outer"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1380; master_tag = "arrivals_dock_north_airlock"; name = "exterior access button"; pixel_x = 4; pixel_y = -26; req_one_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2/arrivals) +"dzl" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_south_inner"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2/arrivals) +"dzm" = (/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 6},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2/arrivals) +"dzn" = (/obj/machinery/airlock_sensor{frequency = 1380; id_tag = "arrivals_dock_south_sensor"; pixel_x = 0; pixel_y = 25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1380; id_tag = "arrivals_dock_south_pump"},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2/arrivals) "dzo" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "dock3_south_outer"; locked = 1; name = "External Airlock Access"; req_access = list(13)},/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1380; master_tag = "dock3_south_airlock"; name = "exterior access button"; pixel_x = -5; pixel_y = 26; req_one_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D3) "dzp" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/airlock_sensor{frequency = 1380; id_tag = "dock3_south_sensor"; pixel_x = 0; pixel_y = 25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1380; id_tag = "dock3_south_pump"},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) "dzq" = (/obj/machinery/light/small{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1380; id_tag = "dock3_south_pump"},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) @@ -9439,10 +9439,10 @@ "dzA" = (/obj/effect/floor_decal/industrial/warning{dir = 8},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1380; master_tag = "escape_dock_south_starboard_airlock"; name = "interior access button"; pixel_x = -26; pixel_y = -26; req_one_access = list(13)},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) "dzB" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 8; icon_state = "map"},/turf/simulated/floor/tiled/monotile,/area/hallway/secondary/entry/D2) "dzC" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1380; master_tag = "arrivals_dock_south_airlock"; name = "interior access button"; pixel_x = 26; pixel_y = -26; req_one_access = list(13)},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dzD" = (/obj/effect/floor_decal/industrial/loading{icon_state = "loadingarea"; dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 6},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dzE" = (/obj/machinery/embedded_controller/radio/airlock/docking_port_multi{frequency = 1380; id_tag = "arrivals_dock_south_airlock"; master_tag = "arrivals_dock"; pixel_y = -30; req_one_access = list(13); tag_airlock_mech_sensor = "arrivals_dock_south_mech"; tag_airpump = "arrivals_dock_south_pump"; tag_chamber_sensor = "arrivals_dock_south_sensor"; tag_exterior_door = "arrivals_dock_south_outer"; tag_interior_door = "arrivals_dock_south_inner"; tag_shuttle_mech_sensor = "arrivals_dock_south_mech"},/obj/effect/floor_decal/industrial/loading{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dzF" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1380; id_tag = "arrivals_dock_south_pump"},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dzG" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_south_outer"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) +"dzD" = (/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_south_outer"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1380; master_tag = "arrivals_dock_south_airlock"; name = "exterior access button"; pixel_x = 4; pixel_y = 26; req_one_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2/arrivals) +"dzE" = (/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_south_inner"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2/arrivals) +"dzF" = (/obj/machinery/embedded_controller/radio/airlock/docking_port_multi{frequency = 1380; id_tag = "arrivals_dock_south_airlock"; master_tag = "arrivals_dock"; pixel_y = -30; req_one_access = list(13); tag_airlock_mech_sensor = "arrivals_dock_south_mech"; tag_airpump = "arrivals_dock_south_pump"; tag_chamber_sensor = "arrivals_dock_south_sensor"; tag_exterior_door = "arrivals_dock_south_outer"; tag_interior_door = "arrivals_dock_south_inner"; tag_shuttle_mech_sensor = "arrivals_dock_south_mech"},/obj/effect/floor_decal/industrial/loading{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2/arrivals) +"dzG" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 8; frequency = 1380; id_tag = "arrivals_dock_south_pump"},/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2/arrivals) "dzH" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "dock3_south_outer"; locked = 1; name = "External Airlock Access"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) "dzI" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 8},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 2; frequency = 1380; id_tag = "dock3_south_pump"},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) "dzJ" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/obj/machinery/embedded_controller/radio/airlock/docking_port{frequency = 1380; id_tag = "dock3_south_airlock"; pixel_x = 0; pixel_y = -30; req_one_access = list(13); tag_airpump = "dock3_south_pump"; tag_chamber_sensor = "dock3_south_sensor"; tag_exterior_door = "dock3_south_outer"; tag_interior_door = "dock3_south_inner"},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 2; frequency = 1380; id_tag = "dock3_south_pump"},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) @@ -9471,7 +9471,7 @@ "dAg" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/manifold/hidden,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D1) "dAh" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/atmospherics/pipe/simple/hidden{dir = 10; icon_state = "intact"},/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/plating,/area/hallway/secondary/entry/D1) "dAi" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/effect/floor_decal/industrial/warning,/obj/machinery/access_button{command = "cycle_interior"; frequency = 1380; master_tag = "admin_shuttle_dock_airlock"; name = "interior access button"; pixel_x = 26; pixel_y = -26; req_one_access = list(13)},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) -"dAj" = (/obj/structure/closet/emcloset,/obj/effect/floor_decal/industrial/warning/corner{dir = 8},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) +"dAj" = (/obj/structure/closet/emcloset,/obj/effect/floor_decal/industrial/warning/corner{dir = 8},/obj/item/weapon/tool/crowbar/red,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D2) "dAk" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/manifold/hidden,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) "dAl" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4},/obj/machinery/access_button{command = "cycle_interior"; frequency = 1331; master_tag = "nuke_shuttle_dock_airlock"; name = "interior access button"; pixel_x = 26; pixel_y = -26; req_one_access = list(13)},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/D3) "dAm" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/atmospherics/pipe/simple/hidden{dir = 10; icon_state = "intact"},/obj/effect/wingrille_spawn/reinforced,/turf/simulated/floor/plating,/area/hallway/secondary/entry/D3) @@ -9607,7 +9607,7 @@ "dCM" = (/obj/machinery/porta_turret/ai_defense,/obj/effect/floor_decal/industrial/outline/grey,/obj/effect/floor_decal/industrial/warning/corner{dir = 4},/turf/simulated/floor/tiled/techfloor,/area/ai) "dCN" = (/obj/effect/floor_decal/industrial/warning{dir = 5},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/techfloor,/area/ai) "dCO" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/greengrid,/area/ai) -"dCP" = (/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/airlock/glass_external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_south_inner"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2) +"dCP" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/shield_diffuser,/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "arrivals_dock_south_outer"; locked = 1; name = "Arrivals Airlock"; req_access = list(13)},/turf/simulated/floor/tiled/dark,/area/hallway/secondary/entry/D2/arrivals) "dCQ" = (/obj/effect/floor_decal/industrial/warning{dir = 9},/obj/structure/cable/cyan{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/tiled/techfloor,/area/ai) "dCR" = (/obj/machinery/porta_turret/ai_defense,/obj/effect/floor_decal/industrial/outline/grey,/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 1},/turf/simulated/floor/tiled/techfloor,/area/ai) "dCS" = (/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/maintenance/thirddeck/forestarboard) @@ -9639,7 +9639,7 @@ "dDs" = (/obj/effect/floor_decal/industrial/warning,/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/maintenance/thirddeck/foreport) "dDt" = (/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 8},/turf/simulated/floor/plating,/area/maintenance/thirddeck/foreport) "dDu" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/catwalk,/turf/simulated/floor/airless,/area/thirddeck/roof) -"dDv" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/techfloor,/area/ai) +"dDv" = (/obj/effect/floor_decal/industrial/warning/cee{icon_state = "warningcee"; dir = 1},/obj/machinery/hologram/holopad,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/effect/landmark/free_ai_shell,/turf/simulated/floor/tiled/techfloor,/area/ai) "dDw" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/effect/floor_decal/industrial/warning/corner,/turf/simulated/floor/tiled/techfloor,/area/ai) "dDx" = (/obj/effect/floor_decal/industrial/warning/corner{dir = 4},/obj/effect/floor_decal/industrial/warning/corner{icon_state = "warningcorner"; dir = 1},/obj/effect/floor_decal/industrial/warning,/obj/structure/cable/cyan{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/techfloor,/area/ai) "dDy" = (/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 1},/obj/effect/floor_decal/industrial/warning/corner{dir = 8},/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/techfloor,/area/ai) @@ -9894,7 +9894,7 @@ "dIn" = (/obj/machinery/ai_status_display,/turf/simulated/wall/r_wall,/area/hallway/primary/thirddeck/starboard) "dIo" = (/obj/machinery/atmospherics/unary/vent_scrubber/on,/turf/simulated/floor/tiled,/area/hallway/primary/thirddeck/starboard) "dIp" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 8; icon_state = "map"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/steeldecal/steel_decals4{dir = 4},/obj/effect/floor_decal/steeldecal/steel_decals4{dir = 9},/turf/simulated/floor/tiled,/area/hallway/primary/thirddeck/starboard) -"dIq" = (/obj/effect/floor_decal/industrial/warning/cee{icon_state = "warningcee"; dir = 1},/obj/machinery/hologram/holopad,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor/tiled/techfloor,/area/ai) +"dIq" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/effect/floor_decal/industrial/warning/corner{dir = 4},/turf/simulated/floor/tiled/techfloor,/area/ai) "dIr" = (/obj/machinery/atmospherics/pipe/simple/hidden{icon_state = "intact"; dir = 4},/turf/simulated/wall/r_wall,/area/hallway/primary/thirddeck/starboard) "dIs" = (/obj/machinery/atmospherics/pipe/manifold/hidden{dir = 1; icon_state = "map"},/turf/simulated/wall/r_wall,/area/hallway/primary/thirddeck/starboard) "dIt" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 10; icon_state = "intact"},/turf/simulated/wall/r_wall,/area/hallway/primary/thirddeck/starboard) @@ -10948,7 +10948,7 @@ "ecC" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/meter,/obj/random/mob/mouse,/turf/simulated/floor/plating,/area/maintenance/thirddeck/foreport) "ecD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/meter,/obj/random/mob/mouse,/turf/simulated/floor/plating,/area/maintenance/thirddeck/forestarboard) "ecE" = (/obj/machinery/door/firedoor/border_only,/obj/effect/wingrille_spawn/reinforced,/obj/machinery/door/blast/shutters{density = 0; dir = 8; icon_state = "shutter0"; id = "heads_meeting"; name = "Meeting Room Window Shutters"; opacity = 0},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/structure/cable/green,/turf/simulated/floor/plating,/area/bridge/meeting_room) - + (1,1,1) = {" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -11410,15 +11410,15 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadsTdsTdsTaaaaaaaaadsTdsTdsTaaaaaaaaaaaadvjdwsdwwdvjaaaaaaaafaaadvHdvHdvHdvHdvHdvHdvHdvHdvHaaaaafaaaaaadvkdwxdvwdvxdvkaaaaaaaafaaadwldwldwldwldwldwldwlaaaaaaaaaaafaaaaaadvodwydwvdvoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadufdufdufdufdufdufdufaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadsTdsTaaaaaaaaaaaaaaadsTdsTaaaaaaaaaaaaduUdwzdwAduUaaaaaaaaadvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHaaaaaaaaaduYdwBdwCdwDduYaaaaaaaaadwldwldwldwldwldwldwldwldwlaaaaaaaaaaaaaaadvedwEdwFdveaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadufdufdufdufdufdufdufaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaadwGduUduUduUduUdwHdwIdwhdwJdwKdwLdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdwMdwNdwOdwPdwQdwRdwSdvkdVjdVjdVkdwldwldwldwldwldwldwldwldwlaaaaaadVndVldVmdwXdwYdwZdvedvedvedvedxaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadufdufdufdufdufdufdufaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaduUdxbdxcdxddxedxfdxgdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdxhdxidxjdxkdxldvwdxmdxndzldxpdxqdwldwldwldwldwldwldwldwldwlaaaaaadxrdxsdxtdxudxvdxwdveaaaaaaaaaaaadxxdxxaaaaaaaaaaaaaaadxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadufdufdufdufdufaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadvjdwsdxydxddxzdxAdxBdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdxCdxDdxEdxkdxFdxGdxHdxIdxJdxKdxLdwldwldwldwldwldwldwldwldwlaaaaaadxMdxNdxOdxudxPdwvdvoaaaaaaaaaaaadxxdxxdxxaaaaaaaaadxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaduUdxbdxcdxddxedxfdxgdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdxhdxidxjdxkdxldvwdxmdxndxpdxqdxIdwldwldwldwldwldwldwldwldwlaaaaaadxrdxsdxtdxudxvdxwdveaaaaaaaaaaaadxxdxxaaaaaaaaaaaaaaadxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadufdufdufdufdufaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadvjdwsdxydxddxzdxAdxBdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdxCdxDdxEdxkdxFdxGdxHdxJdxKdxLdzkdwldwldwldwldwldwldwldwldwlaaaaaadxMdxNdxOdxudxPdwvdvoaaaaaaaaaaaadxxdxxdxxaaaaaaaaadxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadxQdxQdxQdxQdxQdxQdxQdxQdxQdxQdxQaaaaaaaaaaaadvjdvjdxRdxSdwhdxTdxUdvDdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdxVdxWdxXdwPdxYdxZdyadvkdvkdVjdVjdwldwldwldwldwldwldwldwldwlaaaaaadvNdVodycdyddyedyfdvodvoaaaaaaaaadxxdxxdxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadxQdxQdxQdxQdxQdxQdxQdxQdxQdxQdxQdxQdygdyhdVpdwhdyjdwjdwkdykduUaaaaaadvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHaaaaaaduYdyldvxdvwdvxdymduYaaaaaadwldwldwldwldwldwldwldwldwlaaaaaaaaaaaadvedyndwmdwndyodwpdVqdyqdvNdxxdxxdxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadxQdxQdxQdxQdxQdxQdxQdxQdxQdxQdxQdxQdyrdysdytdyudyvdvUdwtdywduUaaaaaadvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHaaaaaaduYdyxdvxdyydvxdyzduYaaaaaadwldwldwldwldwldwldwldwldwlaaaaaaaaaaaadvedyAdwudvZdyBdyCdyDdyEdyFdxxdxxdxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadxQdxQdxQdxQdxQdxQdxQdxQdxQdxQdxQdxQdvDdvDdvDdvjdyGdyHdyIdyJduUaaaaaadvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHaaaaaaduYdyKdvxdyLdyMdyNduYaaaaaadwldwldwldwldwldwldwldwldwlaaaaaaaaaaaadvedyOdyPdyQdyRdvodvNdvNdvOdxxdxxdxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadxQdxQdxQdxQdxQdxQdxQdxQdxQdxQdxQaaaaaaaaaaaadvjdvjdySdyTdwhdwJdwKdvDdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdxVdwNdwOdwPdyUdyVdyWdvkdvkdVjdVjdwldwldwldwldwldwldwldwldwlaaaaaadvNdVldVmdwXdyXdyYdvodvoaaaaaaaaadxxdxxdxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadvjdwsdyZdzadzbdzcdzddvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdzedzfdzgdzhdxFdzidzjdzkdzDdzmdzndwldwldwldwldwldwldwldwldwlaaaaaadzodzpdzqdzrdzsdwvdvoaaaaaaaaaaaaaaadxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaduUdwsdztdzadzudzvdzwdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdzxdzydzzdzhdzAdzBdzCdCPdzEdzFdzGdwldwldwldwldwldwldwldwldwlaaaaaadzHdzIdzJdzrdzKdwvdveaaaaaaaaaaaaaaadxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadvjdwsdyZdzadzbdzcdzddvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdzedzfdzgdzhdxFdzidzjdzldzmdzndzDdwldwldwldwldwldwldwldwldwlaaaaaadzodzpdzqdzrdzsdwvdvoaaaaaaaaaaaaaaadxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaduUdwsdztdzadzudzvdzwdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdzxdzydzzdzhdzAdzBdzCdzEdzFdzGdCPdwldwldwldwldwldwldwldwldwlaaaaaadzHdzIdzJdzrdzKdwvdveaaaaaaaaaaaaaaadxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaadwGduUduUduUduUdzLdzMdwhdxTdxUdwLdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdwMdxWdxXdwPdzNdyVdzOdvkdVjdVjdVkdwldwldwldwldwldwldwldwldwlaaaaaadVndVodVrdwXdzPdzQdvedvedvedvedxaaaadxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaduUdzRdzSduUaaaaaaaaadvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHaaaaaaaaaduYdzTdzUdzVduYaaaaaaaaadwldwldwldwldwldwldwldwldwlaaaaaaaaaaaaaaadvedzWdzXdveaaaaaaaaaaaaaaadxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadvjdzYdzZdvjaaaaaaaaadvHdvHdvHdvHdvHdvHdvHdvHdvHdvHdvHaaaaaaaaadvudAadAbdvxdvuaaaaaaaaadwldwldwldwldwldwldwldwldwlaaaaaaaaaaaaaaadvodAcdAddvoaaaaaaaaaaaaaaadxxdxxdxxdxxdxxdxxdxxaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -11575,8 +11575,8 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaadaafaafaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdBGdBHdBudAVdBGdBHdBudAVdBGdBHdBudAVdBGdBHdBudAVdBGdBHdBudAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdBPdBcdBcdBQdBRdBSdBTdBUdBVdBWdBXdBYdBZdCadBcdBcdCbdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdBDdBOdBFdAVdBDdBOdBFdAVdBDdBOdBFdAVdBDdBOdBFdAVdBDdBOdBFdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadBrdBrdBrdBraaaaaadBrdBrdBrdBrdBrdBrdBrdBrdBraaaaaadBrdBrdBrdBraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaagaadaadaaaaaaaaaaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdBGdBHdBudAVdBGdBHdBudAVdBGdBHdBudAVdBGdBHdBudAVdBGdBHdBudAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdCcdCcdCcdCcdCcdCcdCcdAVdAVdAVdAVdAVdAVdAVdBcdBcdBcdBIdBJdBKdBLdCddBLdCedBmdBNdBcdBcdBcdAVdAVdAVdAVdAVdAVdAVdCfdCfdCfdCfdCfdCfdCfdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdBDdBOdBFdAVdBDdBOdBFdAVdBDdBOdBFdAVdBDdBOdBFdAVdBDdBOdBFdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaafaafaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaadaagaafaaaaafaaaaaaaaaaaaaaaaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdBGdBHdBudAVdBGdBHdBudAVdBGdBHdBudAVdBGdBHdBudAVdBGdBHdBudAVdAVdAVdAVdAVdAVdCgdChdChdChdChdCidCjdCkdCldCmdCcdAVdAVdAVdAVdAVdCndCodCodCpdCpdCqdCrdCsdBLdBLdBLdBAdCtdCudBcdBcdAVdAVdAVdAVdAVdAVdAVdAVdCfdCvdCwdCxdCydCzdCAdCAdCAdCAdCBdAVdAVdAVdAVdAVdAVdBDdBOdBFdAVdBDdBOdBFdAVdBDdBOdBFdAVdBDdBOdBFdAVdBDdBOdBFdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaabcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaafaaaaaaaaaaaaaaaaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdCDdAVdCEdCEdCEdCgdCFdCGdCHdCIdCJdCldCldCldCKdCcdAVdAVdAVdAVdAVdCLdAVdAVdBcdBcdBcdCMdCNdCOdIqdCOdCQdCRdBcdBcdBcdAVdAVdAVdAVdAVdAVdAVdAVdCfdCSdCTdCUdCUdCVdCWdCXdCYdCZdCBdDadDadDadAVdAVdAVdAVdDbdAVdAVdAVdDbdAVdAVdAVdDbdAVdAVdAVdDbdAVdAVdAVdDbdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaafaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdDcdDddDddDddDedDddDddDddDedDddDddDddDedDddDddDddDedDddDddDddDedDddDddDfdDgdDhdDidDjdDkdDldDmdDndDodDpdDqdDrdDsdDtdCcaaaaaaaaaaaaaaadDuaaaaaadBcdBcdBcdBjdDvdDwdDxdDydDzdBedBcdBcdBcaaaaaadDAaaaaaaaaaaaaaaadCfdDBdDCdDDdDDdDEdDFdDGdDHdDIdDJdDKdDLdDMdDNdDOdDPdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDRdDSdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaafaaaaaaaaaaaaaaaaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdCDdAVdCEdCEdCEdCgdCFdCGdCHdCIdCJdCldCldCldCKdCcdAVdAVdAVdAVdAVdCLdAVdAVdBcdBcdBcdCMdCNdCOdDvdCOdCQdCRdBcdBcdBcdAVdAVdAVdAVdAVdAVdAVdAVdCfdCSdCTdCUdCUdCVdCWdCXdCYdCZdCBdDadDadDadAVdAVdAVdAVdDbdAVdAVdAVdDbdAVdAVdAVdDbdAVdAVdAVdDbdAVdAVdAVdDbdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaafaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdDcdDddDddDddDedDddDddDddDedDddDddDddDedDddDddDddDedDddDddDddDedDddDddDfdDgdDhdDidDjdDkdDldDmdDndDodDpdDqdDrdDsdDtdCcaaaaaaaaaaaaaaadDuaaaaaadBcdBcdBcdBjdIqdDwdDxdDydDzdBedBcdBcdBcaaaaaadDAaaaaaaaaaaaaaaadCfdDBdDCdDDdDDdDEdDFdDGdDHdDIdDJdDKdDLdDMdDNdDOdDPdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDQdDRdDSdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaafdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdAVdCCdAVdAVdAVdAVdCEdDTdDUdDVdDWdDXdDYdCIdDZdCldEadEbdCcdCcaaaaaaaaaaaaaaadDuaaaaaaaaaaaadBcdBcdBcdBcdEcdBcdBcdBcdBcaaaaaaaaaaaadDAaaaaaaaaaaaaaaadCfdCfdEddEedCUdEfdCWdEgdEhdEidEjdEkdEldDadAVdAVdAVdAVdEmdAVdAVdAVdEmdAVdAVdAVdEmdAVdAVdAVdEmdAVdAVdAVdEmdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadEnaaaaaaaaadEnaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaafaafaafdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdBGdEodBudAVdBGdEodBudAVdBGdEodBudAVdBGdEodBudAVdBGdEodBudAVdAVdAVdAVdAVdAVdCgdChdChdChdCcdEpdEqdCcdCcdCcaaaaaaaaaaaaaaaaaadCLdAVdAVdAVdErdErdErdErdBcdEsdEtdEudErdErdErdAVdAVdAVdAVaaaaaaaaaaaaaaaaaadCfdCfdCfdEvdEwdCfdCAdCAdCAdCBdAVdAVdAVdAVdAVdAVdBDdExdBFdAVdBDdExdBFdAVdBDdExdBFdAVdBDdExdBFdAVdBDdExdBFdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadEnaaaaaaaaadEnaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaadaadaafaaaaaadAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdBGdEodBudAVdBGdEodBudAVdBGdEodBudAVdBGdEodBudAVdBGdEodBudAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdCcdEydCldCcaaaaaaaaaaabaaaaaadAVdAVdCLdAVdAVdAVdErdEzdEAdEBdECdEDdEEdEFdEAdEGdErdAVdAVdAVdAVdAVdAVaaaaaaaabaaaaaaaaadCfdCUdEHdCfdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdBDdExdBFdAVdBDdExdBFdAVdBDdExdBFdAVdBDdExdBFdAVdBDdExdBFdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVdAVaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBrdBraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -11722,4 +11722,3 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa dUOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "} - diff --git a/maps/submaps/surface_submaps/wilderness/butchershack.dmm b/maps/submaps/surface_submaps/wilderness/butchershack.dmm new file mode 100644 index 0000000000..d32c35b6da --- /dev/null +++ b/maps/submaps/surface_submaps/wilderness/butchershack.dmm @@ -0,0 +1,36 @@ +"a" = (/turf/template_noop,/area/template_noop) +"b" = (/turf/simulated/wall/log_sif,/area/submap/ButcherShack) +"c" = (/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"d" = (/obj/structure/closet,/obj/effect/decal/cleanable/cobweb,/obj/item/weapon/beartrap,/obj/item/weapon/beartrap,/obj/item/weapon/packageWrap,/obj/item/weapon/material/knife/hook,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"e" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"f" = (/obj/structure/closet/crate/freezer,/obj/effect/decal/cleanable/blood/gibs,/obj/random/meat,/obj/random/meat,/obj/random/meat,/obj/random/meat,/obj/random/meat,/obj/random/meat,/obj/random/meat,/obj/random/meat,/obj/random/meat,/obj/random/meat,/turf/simulated/floor/wood/sif/broken,/area/submap/ButcherShack) +"g" = (/obj/machinery/gibber/autogibber,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"h" = (/turf/simulated/floor/wood/sif/broken,/area/submap/ButcherShack) +"i" = (/obj/structure/window/basic,/obj/structure/curtain,/turf/simulated/floor/wood/sif/broken,/area/submap/ButcherShack) +"j" = (/turf/template_noop,/area/submap/ButcherShack) +"k" = (/obj/structure/simple_door/sifwood,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"l" = (/obj/structure/loot_pile/maint/trash,/turf/simulated/floor/outdoors/dirt,/area/submap/ButcherShack) +"m" = (/obj/structure/kitchenspike,/obj/effect/decal/cleanable/blood,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"n" = (/obj/structure/kitchenspike,/obj/effect/decal/cleanable/blood/drip,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"o" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"p" = (/obj/structure/table/standard,/obj/item/clothing/suit/chef/classic,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"q" = (/obj/structure/table/standard,/obj/effect/decal/cleanable/blood,/obj/item/weapon/material/knife/butch,/turf/simulated/floor/wood/sif/broken,/area/submap/ButcherShack) +"r" = (/obj/structure/table/standard,/obj/item/weapon/reagent_containers/food/snacks/cutlet,/obj/item/weapon/reagent_containers/food/snacks/cutlet,/obj/item/weapon/reagent_containers/food/snacks/cutlet,/obj/item/weapon/reagent_containers/food/snacks/sausage,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"s" = (/obj/structure/coatrack,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"t" = (/obj/structure/bed/padded,/obj/item/weapon/bedsheet/brown,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) +"u" = (/obj/effect/decal/cleanable/blood/drip,/turf/simulated/floor/wood/sif/broken,/area/submap/ButcherShack) +"v" = (/turf/simulated/floor/outdoors/dirt,/area/submap/ButcherShack) +"w" = (/obj/structure/window/basic,/obj/structure/curtain,/turf/simulated/floor/wood/sif,/area/submap/ButcherShack) + +(1,1,1) = {" +aaaaaaaaaa +abbbbbbbba +abdmnefgba +abhcccocba +abcpqrccba +absocchtba +abbubiwbba +ajbkbllvja +ajvvvvvjja +aaaaaaaaaa +"} diff --git a/maps/submaps/surface_submaps/wilderness/wilderness.dm b/maps/submaps/surface_submaps/wilderness/wilderness.dm index 9338bc08f8..c9acb611c1 100644 --- a/maps/submaps/surface_submaps/wilderness/wilderness.dm +++ b/maps/submaps/surface_submaps/wilderness/wilderness.dm @@ -29,6 +29,7 @@ #include "Manor1.dmm" #include "Epod3.dmm" #include "Epod4.dmm" +#include "ButcherShack.dmm" #endif @@ -223,3 +224,9 @@ desc = "A flooded Emergency pod in the middle of nowhere." mappath = 'maps/submaps/surface_submaps/wilderness/Epod4.dmm' cost = 5 + +/datum/map_template/surface/wilderness/normal/ButcherShack + name = "Butcher Shack" + desc = "An old, bloody butcher's shack. Get your meat here!" + mappath = 'maps/submaps/surface_submaps/wilderness/ButcherShack.dmm' + cost = 5 diff --git a/maps/submaps/surface_submaps/wilderness/wilderness_areas.dm b/maps/submaps/surface_submaps/wilderness/wilderness_areas.dm index 554579e4a4..35ee357200 100644 --- a/maps/submaps/surface_submaps/wilderness/wilderness_areas.dm +++ b/maps/submaps/surface_submaps/wilderness/wilderness_areas.dm @@ -120,3 +120,7 @@ /area/submap/Epod4 name = "Epod4" ambience = AMBIENCE_FOREBODING + +/area/submap/ButcherShack + name = "ButcherShack" + ambience = AMBIENCE_RUINS diff --git a/polaris.dme b/polaris.dme index e26938d8da..77024a848d 100644 --- a/polaris.dme +++ b/polaris.dme @@ -239,6 +239,7 @@ #include "code\datums\progressbar.dm" #include "code\datums\recipe.dm" #include "code\datums\riding.dm" +#include "code\datums\soul_link.dm" #include "code\datums\sun.dm" #include "code\datums\weakref.dm" #include "code\datums\autolathe\arms.dm" @@ -1972,6 +1973,7 @@ #include "code\modules\mob\living\silicon\subystems.dm" #include "code\modules\mob\living\silicon\ai\ai.dm" #include "code\modules\mob\living\silicon\ai\ai_movement.dm" +#include "code\modules\mob\living\silicon\ai\ai_remote_control.dm" #include "code\modules\mob\living\silicon\ai\death.dm" #include "code\modules\mob\living\silicon\ai\examine.dm" #include "code\modules\mob\living\silicon\ai\icons.dm" @@ -2009,13 +2011,13 @@ #include "code\modules\mob\living\silicon\robot\robot_damage.dm" #include "code\modules\mob\living\silicon\robot\robot_items.dm" #include "code\modules\mob\living\silicon\robot\robot_movement.dm" +#include "code\modules\mob\living\silicon\robot\robot_remote_control.dm" #include "code\modules\mob\living\silicon\robot\drone\drone.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_abilities.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_console.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_damage.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_items.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm" -#include "code\modules\mob\living\silicon\robot\drone\drone_remote_control.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_say.dm" #include "code\modules\mob\living\silicon\robot\robot_modules\event.dm" #include "code\modules\mob\living\silicon\robot\robot_modules\station.dm"