diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index 558595930fa..f4836ee6283 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -92,9 +92,14 @@ //check if it doesn't require any access at all if(src.check_access(null)) return 1 + if(istype(M, /mob/living/silicon)) - //AI can do whatever he wants - return 1 + if(ispAI(M)) + var/mob/living/silicon/pai/P = M + if(P.ID && src.check_access(P.ID)) + return 1 + else//AI can do whatever he wants + return 1 else if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M //if they are holding or wearing a card that has access, that works diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 22041ae091f..8e7c952def7 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -105,8 +105,8 @@ playsound(src.loc, hatch_open_sound, 40, 1, -1) hatchclosetime = world.time + 29 - if (istype(mover, /mob/living/silicon)) - var/mob/living/silicon/S = mover + if (istype(mover, /mob/living)) + var/mob/living/S = mover S.under_door() @@ -190,8 +190,14 @@ if(mover.checkpass(PASSGLASS)) return !opacity if(density && hashatch && mover.checkpass(PASSDOORHATCH)) - open_hatch(mover) - return 1//If this door is closed, but it has hatches, and this creature can go through hatches. Then we let it through without opening + if (istype(mover, /mob/living/silicon/pai)) + var/mob/living/silicon/pai/P = mover + if (allowed(P)) + open_hatch(mover) + return 1 + else + open_hatch(mover) + return 1//If this door is closed, but it has hatches, and this creature can go through hatches. Then we let it through without opening return !density diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index 70fa3a409f3..8306c5f06e6 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -10,6 +10,7 @@ var/looking_for_personality = 0 var/mob/living/silicon/pai/pai + /*/obj/item/device/paicard/relaymove(var/mob/user, var/direction) if(src.loc && istype(src.loc.loc, /obj/item/rig_module)) var/obj/item/rig_module/module = src.loc.loc @@ -27,6 +28,45 @@ pai.death(0) ..() +/obj/item/device/paicard/attackby(obj/item/C as obj, mob/user as mob) + if(istype(C, /obj/item/weapon/card/id)) + scan_ID(C, user) + + +//This proc is called when the user scans their ID on the pAI card. +//It registers their ID and copies their access to the pai, allowing it to use airlocks the owner can +//Scanning an ID replaces any previously stored access with the new set. +//Only cards that match the imprinted DNA can be used, it's not a free Agent ID card. +//Possible TODO in future, allow emagging a paicard to let it work like an agent ID, accumulating access from any ID +/obj/item/device/paicard/proc/scan_ID(var/obj/item/weapon/card/id/card, var/mob/user) + if (!pai) + user << "Error: ID Registration failed. No pAI personality installed." + playsound(src.loc, 'sound/machines/buzz-two.ogg', 20, 0) + return 0 + + if (!pai.master_dna) + user << "Error: ID Registration failed. User not registered as owner. Please complete imprinting process first." + playsound(src.loc, 'sound/machines/buzz-two.ogg', 20, 0) + return 0 + + if (pai.master_dna != card.dna_hash) + user << "Error: ID Registration failed. Biometric data on ID card does not match DNA sample of registered owner." + playsound(src.loc, 'sound/machines/buzz-two.ogg', 20, 0) + return 0 + + pai.ID.access.Cut() + pai.ID.access = card.access.Copy() + pai.ID.registered_name = card.registered_name + playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) + user << "ID Registration for [pai.ID.registered_name] is a success. PAI access updated!" + return 1 + +/obj/item/device/paicard/proc/ID_readout() + if (pai.ID.registered_name) + return "Identity of owner: [pai.ID.registered_name] registered." + else + return "No ID card registered! Please scan your ID to share access." + /obj/item/device/paicard/attack_self(mob/user) if (!in_range(src, user)) return @@ -143,6 +183,10 @@ Additional directives: [pai.pai_laws] + + ID: + [ID_readout()] +
"} diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 6c7dcf9d5ba..3bec295e313 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -128,7 +128,7 @@ desc = "A card used to provide ID and determine access across the station." icon_state = "id" item_state = "card-id" - var/access = list() + var/list/access = list() var/registered_name = "Unknown" // The name registered_name on the card slot_flags = SLOT_ID @@ -147,16 +147,29 @@ /obj/item/weapon/card/id/New() ..() spawn(30) - if(istype(loc, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = loc - blood_type = H.dna.b_type - dna_hash = H.dna.unique_enzymes - fingerprint_hash = md5(H.dna.uni_identity) - citizenship = H.citizenship - religion = H.religion - age = H.age + if(istype(loc, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = loc + blood_type = H.dna.b_type + dna_hash = H.dna.unique_enzymes + fingerprint_hash = md5(H.dna.uni_identity) + citizenship = H.citizenship + religion = H.religion + age = H.age /obj/item/weapon/card/id/attack_self(mob/user as mob) + if (dna_hash == "\[UNSET\]" && ishuman(user)) + var/response = alert(user, "This ID card has not been imprinted with biometric data. Would you like to imprint yours now?", "Biometric Imprinting", "Yes", "No") + if (response == "Yes") + var/mob/living/carbon/human/H = user + blood_type = H.dna.b_type + dna_hash = H.dna.unique_enzymes + fingerprint_hash = md5(H.dna.uni_identity) + citizenship = H.citizenship + religion = H.religion + age = H.age + user << "Biometric Imprinting Successful!." + return + for(var/mob/O in viewers(user, null)) O.show_message(text("[] shows you: \icon[] []: assignment: []", user, src, src.name, src.assignment), 1) diff --git a/code/modules/mob/living/carbon/brain/emote.dm b/code/modules/mob/living/carbon/brain/emote.dm index 818af164161..65f6bbe4eb4 100644 --- a/code/modules/mob/living/carbon/brain/emote.dm +++ b/code/modules/mob/living/carbon/brain/emote.dm @@ -28,15 +28,12 @@ if ("custom") return custom_emote(m_type, message) if ("alarm") - src << "You sound an alarm." message = "[src] sounds an alarm." m_type = 2 if ("alert") - src << "You let out a distressed noise." message = "[src] lets out a distressed noise." m_type = 2 if ("notice") - src << "You play a loud tone." message = "[src] plays a loud tone." m_type = 2 if ("flash") @@ -46,15 +43,21 @@ message = "[src] blinks." m_type = 1 if ("whistle") - src << "You whistle." message = "[src] whistles." m_type = 2 - if ("beep") - src << "You beep." + if("beep") message = "[src] beeps." + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) + m_type = 2 + if("ping") + message = "[src] pings." + playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) + m_type = 2 + if("buzz") + message = "[src] buzzes." + playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0) m_type = 2 if ("boop") - src << "You boop." message = "[src] boops." m_type = 2 if ("help") diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 98f4e191691..39195ff1efb 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -676,6 +676,12 @@ default behaviour is: /mob/living/proc/slip(var/slipped_on,stun_duration=8) return 0 +/mob/living/proc/under_door() + //This function puts a silicon on a layer that makes it draw under doors, then periodically checks if its still standing on a door + if (layer > UNDERDOOR)//Don't toggle it if we're hiding + layer = UNDERDOOR + underdoor = 1 + /mob/living/carbon/drop_from_inventory(var/obj/item/W, var/atom/Target = null) if(W in internal_organs) return diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 36119b3e6b4..eddf2f4c2d3 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -45,4 +45,5 @@ var/composition_reagent_quantity var/mouth_size = 2//how large of a creature it can swallow at once, and how big of a bite it can take out of larger things var/eat_types = 0//This is a bitfield which must be initialised in New(). The valid values for it are in devour.dm - var/datum/reagents/metabolism/ingested = null \ No newline at end of file + var/datum/reagents/metabolism/ingested = null + var/underdoor //Used for mobs that can walk through maintenance hatches - drones, pais, and spiderbots \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 336050268b3..5517d5463dc 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -5,8 +5,9 @@ emote_type = 2 // pAIs emotes are heard, not seen, so they can be seen through a container (eg. person) small = 1 - pass_flags = 1 + pass_flags = PASSTABLE | PASSDOORHATCH density = 0 + mob_size = 1//As a holographic projection, a pAI is massless except for its card device mob_size = 1 @@ -14,7 +15,6 @@ var/network = "SS13" var/obj/machinery/camera/current = null - var/ram = 100 // Used as currency to purchase different abilities var/list/software = list() var/userDNA // The DNA string of our assigned user @@ -34,10 +34,12 @@ "Natural" = list("says","yells","asks"), "Beep" = list("beeps","beeps loudly","boops"), "Chirp" = list("chirps","chirrups","cheeps"), - "Feline" = list("purrs","yowls","meows") + "Feline" = list("purrs","yowls","meows"), + "Rodent" = list("squeaks","squeals","squeeks") ) var/obj/item/weapon/pai_cable/cable // The cable we produce and use when door or camera jacking + var/obj/item/weapon/card/id/ID = null //Internal ID used to store copied owner access, and to check access for airlocks var/master // Name of the one who commands us var/master_dna // DNA string for owner verification @@ -106,6 +108,8 @@ //PDA pda = new(src) + ID = new(src) + ID.registered_name = "" spawn(5) pda.ownjob = "Personal Assistant" pda.owner = text("[]", src) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 1e12a07419a..218e633eba3 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -24,7 +24,7 @@ var/next_alarm_notice var/list/datum/alarm/queued_alarms = new() - var/underdoor + #define SEC_HUD 1 //Security HUD mode #define MED_HUD 2 //Medical HUD mode @@ -370,10 +370,4 @@ spawn(3)//A slight delay to let us finish walking out from under the door layer = initial(layer) -/mob/living/silicon/proc/under_door() - //This function puts a silicon on a layer that makes it draw under doors, then periodically checks if its still standing on a door - if (layer > UNDERDOOR)//Don't toggle it if we're hiding - layer = UNDERDOOR - underdoor = 1 -/mob/living/silicon/proc/not_under_door() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm index 14ab5cf7b37..f65d471bcb3 100644 --- a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm +++ b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm @@ -23,7 +23,7 @@ icon_dead = "spiderbot-smashed" wander = 0 - + density = 0 health = 25 maxHealth = 25 hunger_enabled = 0 @@ -39,7 +39,7 @@ var/emagged = 0 var/obj/item/held_item = null //Storage for single item they can hold. speed = -1 //Spiderbots gotta go fast. - pass_flags = PASSTABLE + pass_flags = PASSTABLE | PASSDOORHATCH small = 1 speak_emote = list("beeps","clicks","chirps") @@ -298,3 +298,17 @@ /mob/living/simple_animal/spiderbot/binarycheck() return positronic + +/mob/living/simple_animal/spiderbot/Move(newloc, direct) + ..(newloc,direct) + if (underdoor) + underdoor = 0 + if ((layer == UNDERDOOR))//if this is false, then we must have used hide, or had our layer changed by something else. We wont do anymore checks for this move proc + for (var/obj/machinery/door/D in loc) + if (D.hashatch) + underdoor = 1 + break + + if (!underdoor) + spawn(3)//A slight delay to let us finish walking out from under the door + layer = initial(layer) \ No newline at end of file diff --git a/html/changelogs/Nanako-PAIhatch.yml b/html/changelogs/Nanako-PAIhatch.yml new file mode 100644 index 00000000000..6e777f2b457 --- /dev/null +++ b/html/changelogs/Nanako-PAIhatch.yml @@ -0,0 +1,42 @@ +################################ +# 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: Nanako + +# 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: "Spiderbots no longer block movement." + - tweak: "Spiderbots can now use airlock maintenance hatches." + - rscadd: "PAIs can now have the owner's ID card scanned onto them to share access." + - tweak: "PAIs can now use airlock maintenance hatches, but only on airlocks they have access to. Requires a scanned ID" + - tweak: "Added new rodent speech verbs for PAIs" + - tweak: "Positronic brains and MMIs outside of a chassis can now use ping/beep/buzz audio emotes." + \ No newline at end of file