From f585233793e2567cc96b6366c313cb8cc3546995 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Wed, 28 Jun 2023 18:40:14 +0100 Subject: [PATCH 01/18] tidyup --- .../modules/mob/living/silicon/pai/defense.dm | 37 ++ code/modules/mob/living/silicon/pai/pai.dm | 226 +------- code/modules/mob/living/silicon/pai/pai_vr.dm | 44 -- .../living/silicon/pai/software_modules.dm | 545 ------------------ .../pai/software_modules/_software_module.dm | 51 ++ .../pai/software_modules/atmosphere_sensor.dm | 39 ++ .../pai/software_modules/crew_manifest.dm | 20 + .../pai/software_modules/directives.dm | 57 ++ .../silicon/pai/software_modules/door_jack.dm | 74 +++ .../silicon/pai/software_modules/huds.dm | 28 + .../pai/software_modules/med_records.dm | 53 ++ .../silicon/pai/software_modules/messenger.dm | 75 +++ .../pai/software_modules/radio_config.dm | 37 ++ .../pai/software_modules/sec_records.dm | 58 ++ .../silicon/pai/software_modules/signaller.dm | 43 ++ code/modules/mob/living/silicon/pai/verbs.dm | 168 ++++++ 16 files changed, 763 insertions(+), 792 deletions(-) create mode 100644 code/modules/mob/living/silicon/pai/defense.dm delete mode 100644 code/modules/mob/living/silicon/pai/pai_vr.dm delete mode 100644 code/modules/mob/living/silicon/pai/software_modules.dm create mode 100644 code/modules/mob/living/silicon/pai/software_modules/_software_module.dm create mode 100644 code/modules/mob/living/silicon/pai/software_modules/atmosphere_sensor.dm create mode 100644 code/modules/mob/living/silicon/pai/software_modules/crew_manifest.dm create mode 100644 code/modules/mob/living/silicon/pai/software_modules/directives.dm create mode 100644 code/modules/mob/living/silicon/pai/software_modules/door_jack.dm create mode 100644 code/modules/mob/living/silicon/pai/software_modules/huds.dm create mode 100644 code/modules/mob/living/silicon/pai/software_modules/med_records.dm create mode 100644 code/modules/mob/living/silicon/pai/software_modules/messenger.dm create mode 100644 code/modules/mob/living/silicon/pai/software_modules/radio_config.dm create mode 100644 code/modules/mob/living/silicon/pai/software_modules/sec_records.dm create mode 100644 code/modules/mob/living/silicon/pai/software_modules/signaller.dm create mode 100644 code/modules/mob/living/silicon/pai/verbs.dm diff --git a/code/modules/mob/living/silicon/pai/defense.dm b/code/modules/mob/living/silicon/pai/defense.dm new file mode 100644 index 000000000000..da32afb3c1c2 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/defense.dm @@ -0,0 +1,37 @@ +//Overriding this will stop a number of headaches down the track. +/mob/living/silicon/pai/attackby(obj/item/W as obj, mob/user as mob) + if(W.damage_force) + visible_message("[user.name] attacks [src] with [W]!") + src.adjustBruteLoss(W.damage_force) + src.update_health() + else + visible_message("[user.name] bonks [src] harmlessly with [W].") + spawn(1) + if(stat != 2) close_up() + return + +/mob/living/silicon/pai/attackby(obj/item/W as obj, mob/user as mob) + var/obj/item/card/id/ID = W.GetID() + if(ID) + if (idaccessible == 1) + switch(alert(user, "Do you wish to add access to [src] or remove access from [src]?",,"Add Access","Remove Access", "Cancel")) + if("Add Access") + idcard.access |= ID.access + to_chat(user, "You add the access from the [W] to [src].") + return + if("Remove Access") + idcard.access = list() + to_chat(user, "You remove the access from [src].") + return + if("Cancel") + return + else if (istype(W, /obj/item/card/id) && idaccessible == 0) + to_chat(user, "[src] is not accepting access modifcations at this time.") + return + +/mob/living/silicon/pai/attack_hand(mob/user, list/params) + if(user.a_intent == INTENT_HELP) + visible_message("[user.name] pats [src].") + else + visible_message("[user.name] boops [src] on the head.") + close_up() diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index c02b190eacf7..efd9d56076ea 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -9,7 +9,7 @@ /mob/living/silicon/pai name = "pAI" - icon = 'icons/mob/pai.dmi' + icon = 'icons/mob/pai_vr.dmi' icon_state = "pai-repairbot" emote_type = 2 // pAIs emotes are heard, not seen, so they can be seen through a container (eg. person) @@ -101,6 +101,8 @@ var/current_pda_messaging = null + var/people_eaten = 0 + /mob/living/silicon/pai/Initialize(mapload) . = ..() card = loc @@ -196,19 +198,6 @@ reset_perspective(C) return 1 -/mob/living/silicon/pai/verb/reset_record_view() - set category = "pAI Commands" - set name = "Reset Records Software" - - securityActive1 = null - securityActive2 = null - security_cannotfind = 0 - medicalActive1 = null - medicalActive2 = null - medical_cannotfind = 0 - SSnanoui.update_uis(src) - to_chat(usr, "You reset your record-viewing software.") - /mob/living/silicon/pai/reset_perspective(datum/perspective/P, apply = TRUE, forceful = TRUE, no_optimizations) . = ..() cameraFollow = null @@ -250,148 +239,6 @@ */ -// Procs/code after this point is used to convert the stationary pai item into a -// mobile pai mob. This also includes handling some of the general shit that can occur -// to it. Really this deserves its own file, but for the moment it can sit here. ~ Z - -/mob/living/silicon/pai/verb/fold_out() - set category = "pAI Commands" - set name = "Unfold Chassis" - - if(!CHECK_MOBILITY(src, MOBILITY_CAN_MOVE)) - return - - if(src.loc != card) - return - - if(world.time <= last_special) - return - - last_special = world.time + 100 - - //I'm not sure how much of this is necessary, but I would rather avoid issues. - if(istype(card.loc,/obj/item/hardsuit_module)) - to_chat(src, "There is no room to unfold inside this hardsuit module. You're good and stuck.") - return 0 - else if(istype(card.loc,/mob)) - var/mob/holder = card.loc - var/datum/belly/inside_belly = check_belly(card) - if(inside_belly) - to_chat(src, "There is no room to unfold in here. You're good and stuck.") - return 0 - if(ishuman(holder)) - var/mob/living/carbon/human/H = holder - for(var/obj/item/organ/external/affecting in H.organs) - if(card in affecting.implants) - affecting.take_damage(rand(30,50)) - affecting.implants -= card - H.visible_message("\The [src] explodes out of \the [H]'s [affecting.name] in shower of gore!") - break - holder.drop_item_to_ground(card, INV_OP_FORCE) - else if(istype(card.loc,/obj/item/pda)) - var/obj/item/pda/holder = card.loc - holder.pai = null - - forceMove(card.loc) - card.forceMove(src) - update_perspective() - - card.screen_loc = null - - var/turf/T = get_turf(src) - if(istype(T)) - T.visible_message("[src] folds outwards, expanding into a mobile form.") - - add_verb(src, /mob/living/silicon/pai/proc/pai_nom) - add_verb(src, /mob/living/proc/set_size) - add_verb(src, /mob/living/proc/shred_limb) - -/mob/living/silicon/pai/verb/fold_up() - set category = "pAI Commands" - set name = "Collapse Chassis" - - if(!CHECK_MOBILITY(src, MOBILITY_CAN_MOVE)) - return - - if(src.loc == card) - return - - if(world.time <= last_special) - return - - close_up() - -/mob/living/silicon/pai/proc/choose_chassis() - set category = "pAI Commands" - set name = "Choose Chassis" - - var/choice - var/finalized = "No" - while(finalized == "No" && src.client) - - choice = input(usr,"What would you like to use for your mobile chassis icon?") as null|anything in (list("-- LOAD CHARACTER SLOT --") + possible_chassis) - if(!choice) - return - - if(choice == "-- LOAD CHARACTER SLOT --") - icon = render_hologram_icon(usr.client.prefs.render_to_appearance(PREF_COPY_TO_FOR_RENDER | PREF_COPY_TO_NO_CHECK_SPECIES | PREF_COPY_TO_UNRESTRICTED_LOADOUT), 210) - else - icon = 'icons/mob/pai.dmi' - icon_state = possible_chassis[choice] - finalized = alert("Look at your sprite. Is this what you wish to use?",,"No","Yes") - - chassis = possible_chassis[choice] - add_verb(src, /mob/living/proc/hide) - -/mob/living/silicon/pai/proc/choose_verbs() - set category = "pAI Commands" - set name = "Choose Speech Verbs" - - var/choice = input(usr,"What theme would you like to use for your speech verbs?") as null|anything in possible_say_verbs - if(!choice) return - - var/list/sayverbs = possible_say_verbs[choice] - speak_statement = sayverbs[1] - speak_exclamation = sayverbs[(sayverbs.len>1 ? 2 : sayverbs.len)] - speak_query = sayverbs[(sayverbs.len>2 ? 3 : sayverbs.len)] - -/mob/living/silicon/pai/lay_down() - set name = "Rest" - set category = "IC" - - // Pass lying down or getting up to our pet human, if we're in a hardsuit. - if(istype(src.loc,/obj/item/paicard)) - set_resting(FALSE) - var/obj/item/hardsuit/hardsuit = src.get_hardsuit() - if(istype(hardsuit)) - hardsuit.force_rest(src) - else - toggle_resting() - icon_state = resting ? "[chassis]_rest" : "[chassis]" - update_icon() - to_chat(src, SPAN_NOTICE("You are now [resting ? "resting" : "getting up"]")) - - update_mobility() - -//Overriding this will stop a number of headaches down the track. -/mob/living/silicon/pai/attackby(obj/item/W as obj, mob/user as mob) - if(W.damage_force) - visible_message("[user.name] attacks [src] with [W]!") - src.adjustBruteLoss(W.damage_force) - src.update_health() - else - visible_message("[user.name] bonks [src] harmlessly with [W].") - spawn(1) - if(stat != 2) close_up() - return - -/mob/living/silicon/pai/attack_hand(mob/user, list/params) - if(user.a_intent == INTENT_HELP) - visible_message("[user.name] pats [src].") - else - visible_message("[user.name] boops [src] on the head.") - close_up() - //I'm not sure how much of this is necessary, but I would rather avoid issues. /mob/living/silicon/pai/proc/close_up() @@ -441,54 +288,27 @@ grabber.update_inv_r_hand() return H -/mob/living/silicon/pai/attackby(obj/item/W as obj, mob/user as mob) - var/obj/item/card/id/ID = W.GetID() - if(ID) - if (idaccessible == 1) - switch(alert(user, "Do you wish to add access to [src] or remove access from [src]?",,"Add Access","Remove Access", "Cancel")) - if("Add Access") - idcard.access |= ID.access - to_chat(user, "You add the access from the [W] to [src].") - return - if("Remove Access") - idcard.access = list() - to_chat(user, "You remove the access from [src].") - return - if("Cancel") - return - else if (istype(W, /obj/item/card/id) && idaccessible == 0) - to_chat(user, "[src] is not accepting access modifcations at this time.") - return - -/mob/living/silicon/pai/verb/allowmodification() - set name = "Change Access Modifcation Permission" - set category = "pAI Commands" - set desc = "Allows people to modify your access or block people from modifying your access." - - if(idaccessible == 0) - idaccessible = 1 - to_chat(src, "You allow access modifications.") - - else - idaccessible = 0 - to_chat(src, "You block access modfications.") - -/mob/living/silicon/pai/verb/wipe_software() - set name = "Wipe Software" - set category = "OOC" - set desc = "Wipe your software. This is functionally equivalent to cryo or robotic storage, freeing up your job slot." - - // Make sure people don't kill themselves accidentally - if(alert("WARNING: This will immediately wipe your software and ghost you, removing your character from the round permanently (similar to cryo and robotic storage). Are you entirely sure you want to do this?", - "Wipe Software", "No", "No", "Yes") != "Yes") - return - - close_up() - visible_message("[src] fades away from the screen, the pAI device goes silent.") - card.removePersonality() - clear_client() - // See software.dm for Topic() /mob/living/silicon/pai/canUseTopic(atom/movable/movable, be_close = FALSE, no_dexterity = FALSE, no_tk = FALSE) // Resting is just an aesthetic feature for them. return ..(movable, be_close, no_dexterity, no_tk) + +/mob/living/silicon/pai/proc/update_fullness_pai() //Determines if they have something in their stomach. Copied and slightly modified. + var/new_people_eaten = 0 + for(var/belly in vore_organs) + var/obj/belly/B = belly + for(var/mob/living/M in B) + new_people_eaten += M.size_multiplier + people_eaten = min(1, new_people_eaten) + +/mob/living/silicon/pai/update_icon() + ..() + update_fullness_pai() + if(!people_eaten && !resting) + icon_state = "[chassis]" + else if(!people_eaten && resting) + icon_state = "[chassis]_rest" + else if(people_eaten && !resting) + icon_state = "[chassis]_full" + else if(people_eaten && resting) + icon_state = "[chassis]_rest_full" diff --git a/code/modules/mob/living/silicon/pai/pai_vr.dm b/code/modules/mob/living/silicon/pai/pai_vr.dm deleted file mode 100644 index c5de247595b8..000000000000 --- a/code/modules/mob/living/silicon/pai/pai_vr.dm +++ /dev/null @@ -1,44 +0,0 @@ -/mob/living/silicon/pai - var/people_eaten = 0 - icon = 'icons/mob/pai_vr.dmi' - -/mob/living/silicon/pai/proc/pai_nom(var/mob/living/T in oview(1)) - set name = "pAI Nom" - set category = "pAI Commands" - set desc = "Allows you to eat someone while unfolded. Can't be used while in card form." - - if (stat != CONSCIOUS) - return - return feed_grabbed_to_self(src,T) - -/mob/living/silicon/pai/proc/update_fullness_pai() //Determines if they have something in their stomach. Copied and slightly modified. - var/new_people_eaten = 0 - for(var/belly in vore_organs) - var/obj/belly/B = belly - for(var/mob/living/M in B) - new_people_eaten += M.size_multiplier - people_eaten = min(1, new_people_eaten) - -/mob/living/silicon/pai/update_icon() //Some functions cause this to occur, such as resting - ..() - update_fullness_pai() - if(!people_eaten && !resting) - icon_state = "[chassis]" //Using icon_state here resulted in quite a few bugs. Chassis is much less buggy. - else if(!people_eaten && resting) - icon_state = "[chassis]_rest" - else if(people_eaten && !resting) - icon_state = "[chassis]_full" - else if(people_eaten && resting) - icon_state = "[chassis]_rest_full" - -/mob/living/silicon/pai/update_icons() //And other functions cause this to occur, such as digesting someone. - ..() - update_fullness_pai() - if(!people_eaten && !resting) - icon_state = "[chassis]" - else if(!people_eaten && resting) - icon_state = "[chassis]_rest" - else if(people_eaten && !resting) - icon_state = "[chassis]_full" - else if(people_eaten && resting) - icon_state = "[chassis]_rest_full" diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm deleted file mode 100644 index 4d4eecff74e9..000000000000 --- a/code/modules/mob/living/silicon/pai/software_modules.dm +++ /dev/null @@ -1,545 +0,0 @@ -/datum/pai_software - // Name for the software. This is used as the button text when buying or opening/toggling the software - var/name = "pAI software module" - // RAM cost; pAIs start with 100 RAM, spending it on programs - var/ram_cost = 0 - // ID for the software. This must be unique - var/id = "" - // Whether this software is a toggle or not - // Toggled software should override toggle() and is_active() - // Non-toggled software should override on_nano_ui_interact() and Topic() - var/toggle = 1 - // Whether pAIs should automatically receive this module at no cost - var/default = 0 - -/datum/pai_software/proc/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - return - -/datum/pai_software/proc/toggle(mob/living/silicon/pai/user) - return - -/datum/pai_software/proc/is_active(mob/living/silicon/pai/user) - return 0 - -/datum/pai_software/directives - name = "Directives" - ram_cost = 0 - id = "directives" - toggle = 0 - default = 1 - -/datum/pai_software/directives/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - data["master"] = user.master - data["dna"] = user.master_dna - data["prime"] = user.pai_law0 - data["supplemental"] = user.pai_laws - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/pai_software/directives/Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) - return - - if(href_list["getdna"]) - var/mob/living/M = P.loc - var/count = 0 - - // Find the carrier - while(!istype(M, /mob/living)) - if(!M || !M.loc || count > 6) - //For a runtime where M ends up in nullspace (similar to bluespace but less colourful) - to_chat(src, "You are not being carried by anyone!") - return 0 - M = M.loc - count++ - - // Check the carrier - var/datum/gender/TM = GLOB.gender_datums[M.get_visible_gender()] - var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No") - if(answer == "Yes") - var/turf/T = get_turf_or_move(P.loc) - for (var/mob/v in viewers(T)) - v.show_message("[M] presses [TM.his] thumb against [P].", 3, "[P] makes a sharp clicking sound as it extracts DNA material from [M].", 2) - var/datum/dna/dna = M.dna - to_chat(P, "

[M]'s UE string : [dna.unique_enzymes]

") - if(dna.unique_enzymes == P.master_dna) - to_chat(P, "DNA is a match to stored Master DNA.") - else - to_chat(P, "DNA does not match stored Master DNA.") - else - to_chat(P, "[M] does not seem like [TM.he] is going to provide a DNA sample willingly.") - return 1 - -/datum/pai_software/radio_config - name = "Radio Configuration" - ram_cost = 0 - id = "radio" - toggle = 0 - default = 1 - -/datum/pai_software/radio_config/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui = null, force_open = 1) - var/data[0] - - data["listening"] = user.radio.broadcasting - data["frequency"] = format_frequency(user.radio.frequency) - - var/channels[0] - for(var/ch_name in user.radio.channels) - var/ch_stat = user.radio.channels[ch_name] - var/ch_dat[0] - ch_dat["name"] = ch_name - // FREQ_LISTENING is const in /obj/item/radio - ch_dat["listening"] = !!(ch_stat & user.radio.FREQ_LISTENING) - channels[++channels.len] = ch_dat - - data["channels"] = channels - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150) - ui.set_initial_data(data) - ui.open() - -/datum/pai_software/radio_config/Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) - return - - P.radio.Topic(href, href_list) - return 1 - -/datum/pai_software/crew_manifest - name = "Crew Manifest" - ram_cost = 5 - id = "manifest" - toggle = 0 - -/datum/pai_software/crew_manifest/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - data_core.get_manifest_list() - - var/data[0] - // This is dumb, but NanoUI breaks if it has no data to send - data["manifest"] = GLOB.PDA_Manifest - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "crew_manifest.tmpl", "Crew Manifest", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/pai_software/messenger - name = "Digital Messenger" - ram_cost = 5 - id = "messenger" - toggle = 0 - -/datum/pai_software/messenger/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - data["receiver_off"] = user.pda.toff - data["ringer_off"] = user.pda.message_silent - data["current_ref"] = null - data["current_name"] = user.current_pda_messaging - - var/pdas[0] - if(!user.pda.toff) - for(var/obj/item/pda/P in GLOB.PDAs) - if(!P.owner || P.toff || P == user.pda || P.hidden) continue - var/pda[0] - pda["name"] = "[P]" - pda["owner"] = "[P.owner]" - pda["ref"] = "\ref[P]" - if(P.owner == user.current_pda_messaging) - data["current_ref"] = "\ref[P]" - pdas[++pdas.len] = pda - - data["pdas"] = pdas - - var/messages[0] - if(user.current_pda_messaging) - for(var/index in user.pda.tnote) - if(index["owner"] != user.current_pda_messaging) - continue - var/msg[0] - var/sent = index["sent"] - msg["sent"] = sent ? 1 : 0 - msg["target"] = index["owner"] - msg["message"] = index["message"] - messages[++messages.len] = msg - - data["messages"] = messages - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_messenger.tmpl", "Digital Messenger", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/pai_software/messenger/Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return - - if(!isnull(P.pda)) - if(href_list["toggler"]) - P.pda.toff = href_list["toggler"] != "1" - return 1 - else if(href_list["ringer"]) - P.pda.message_silent = href_list["ringer"] != "1" - return 1 - else if(href_list["select"]) - var/s = href_list["select"] - if(s == "*NONE*") - P.current_pda_messaging = null - else - P.current_pda_messaging = s - return 1 - else if(href_list["target"]) - if(P.silence_time) - return alert("Communications circuits remain uninitialized.") - - var/target = locate(href_list["target"]) - P.pda.create_message(P, target, 1) - return 1 - -/datum/pai_software/med_records - name = "Medical Records" - ram_cost = 15 - id = "med_records" - toggle = 0 - -/datum/pai_software/med_records/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - var/records[0] - for(var/datum/data/record/general in sortRecord(data_core.general)) - var/record[0] - record["name"] = general.fields["name"] - record["ref"] = "\ref[general]" - records[++records.len] = record - - data["records"] = records - - var/datum/data/record/G = user.medicalActive1 - var/datum/data/record/M = user.medicalActive2 - data["general"] = G ? G.fields : null - data["medical"] = M ? M.fields : null - data["could_not_find"] = user.medical_cannotfind - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_medrecords.tmpl", "Medical Records", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/pai_software/med_records/Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return - - if(href_list["select"]) - var/datum/data/record/record = locate(href_list["select"]) - if(record) - var/datum/data/record/R = record - var/datum/data/record/M = null - if (!( data_core.general.Find(R) )) - P.medical_cannotfind = 1 - else - P.medical_cannotfind = 0 - for(var/datum/data/record/E in data_core.medical) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - M = E - P.medicalActive1 = R - P.medicalActive2 = M - else - P.medical_cannotfind = 1 - return 1 - -/datum/pai_software/sec_records - name = "Security Records" - ram_cost = 15 - id = "sec_records" - toggle = 0 - -/datum/pai_software/sec_records/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - var/records[0] - for(var/datum/data/record/general in sortRecord(data_core.general)) - var/record[0] - record["name"] = general.fields["name"] - record["ref"] = "\ref[general]" - records[++records.len] = record - - data["records"] = records - - var/datum/data/record/G = user.securityActive1 - var/datum/data/record/S = user.securityActive2 - data["general"] = G ? G.fields : null - data["security"] = S ? S.fields : null - data["could_not_find"] = user.security_cannotfind - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_secrecords.tmpl", "Security Records", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/pai_software/sec_records/Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) - return - - if(href_list["select"]) - var/datum/data/record/record = locate(href_list["select"]) - if(record) - var/datum/data/record/R = record - var/datum/data/record/S = null - if (!( data_core.general.Find(R) )) - P.securityActive1 = null - P.securityActive2 = null - P.security_cannotfind = 1 - else - P.security_cannotfind = 0 - for(var/datum/data/record/E in data_core.security) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - S = E - P.securityActive1 = R - P.securityActive2 = S - else - P.securityActive1 = null - P.securityActive2 = null - P.security_cannotfind = 1 - return 1 - -/datum/pai_software/door_jack - name = "Door Jack" - ram_cost = 30 - id = "door_jack" - toggle = 0 - -/datum/pai_software/door_jack/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - data["cable"] = user.cable != null - data["machine"] = user.cable && (user.cable.machine != null) - data["inprogress"] = user.hackdoor != null - data["progress_a"] = round(user.hackprogress / 10) - data["progress_b"] = user.hackprogress % 10 - data["aborted"] = user.hack_aborted - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/pai_software/door_jack/Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) - return - - if(href_list["jack"]) - if(P.cable && P.cable.machine) - P.hackdoor = P.cable.machine - P.hackloop() - return 1 - else if(href_list["cancel"]) - P.hackdoor = null - return 1 - else if(href_list["cable"]) - var/turf/T = get_turf_or_move(P.loc) - P.hack_aborted = 0 - P.cable = new /obj/item/pai_cable(T) - for(var/mob/M in viewers(T)) - M.show_message("A port on [P] opens to reveal [P.cable], which promptly falls to the floor.", 3, - "You hear the soft click of something light and hard falling to the ground.", 2) - return 1 - -/mob/living/silicon/pai/proc/hackloop() - var/turf/T = get_turf_or_move(src.loc) - for(var/mob/living/silicon/ai/AI in GLOB.player_list) - if(T.loc) - to_chat(AI, "Network Alert: Brute-force encryption crack in progress in [T.loc].") - else - to_chat(AI, "Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.") - var/obj/machinery/door/D = cable.machine - if(!istype(D)) - hack_aborted = 1 - hackprogress = 0 - cable.machine = null - hackdoor = null - return - while(hackprogress < 1000) - if(cable && cable.machine == D && cable.machine == hackdoor && get_dist(src, hackdoor) <= 1) - hackprogress = min(hackprogress+rand(1, 20), 1000) - else - hack_aborted = 1 - hackprogress = 0 - hackdoor = null - return - if(hackprogress >= 1000) - hackprogress = 0 - D.open() - cable.machine = null - return - sleep(10) // Update every second - -/datum/pai_software/atmosphere_sensor - name = "Atmosphere Sensor" - ram_cost = 5 - id = "atmos_sense" - toggle = 0 - -/datum/pai_software/atmosphere_sensor/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - var/turf/T = get_turf_or_move(user.loc) - if(!T) - data["reading"] = 0 - data["pressure"] = 0 - data["temperature"] = 0 - data["temperatureC"] = 0 - data["gas"] = list() - else - var/datum/gas_mixture/env = T.return_air() - data["reading"] = 1 - var/pres = env.return_pressure() * 10 - data["pressure"] = "[round(pres/10)].[pres%10]" - data["temperature"] = round(env.temperature) - data["temperatureC"] = round(env.temperature-T0C) - - var/t_moles = env.total_moles - var/gases[0] - for(var/g in env.gas) - var/gas[0] - gas["name"] = GLOB.meta_gas_names[g] - gas["percent"] = round((env.gas[g] / t_moles) * 100) - gases[++gases.len] = gas - data["gas"] = gases - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300) - ui.set_initial_data(data) - ui.open() - -/datum/pai_software/sec_hud - name = "Security HUD" - ram_cost = 20 - id = "sec_hud" - -/datum/pai_software/sec_hud/toggle(mob/living/silicon/pai/user) - user.secHUD = !user.secHUD - if(user.secHUD) - get_atom_hud(DATA_HUD_SECURITY_ADVANCED).add_hud_to(user) - else - get_atom_hud(DATA_HUD_SECURITY_ADVANCED).remove_hud_from(user) - -/datum/pai_software/sec_hud/is_active(mob/living/silicon/pai/user) - return user.secHUD - -/datum/pai_software/med_hud - name = "Medical HUD" - ram_cost = 20 - id = "med_hud" - -/datum/pai_software/med_hud/toggle(mob/living/silicon/pai/user) - if((user.medHUD = !user.medHUD)) - get_atom_hud(DATA_HUD_MEDICAL).add_hud_to(user) - else - get_atom_hud(DATA_HUD_MEDICAL).remove_hud_from(user) - -/datum/pai_software/med_hud/is_active(mob/living/silicon/pai/user) - return user.medHUD - -// todo: translation context - -// /datum/pai_software/translator -// name = "Universal Translator" -// ram_cost = 35 -// id = "translator" - -// /datum/pai_software/translator/toggle(mob/living/silicon/pai/user) -// // Sol Common, Tradeband, Terminus and Gutter are added with New() and are therefore the current default, always active languages -// // todo: translation contexts for pais -// user.translator_on = !user.translator_on -// if(user.translator_on) -// user.add_language(LANGUAGE_UNATHI) -// user.add_language(LANGUAGE_SIIK) -// user.add_language(LANGUAGE_AKHANI) -// user.add_language(LANGUAGE_SKRELLIAN) -// user.add_language(LANGUAGE_ZADDAT) -// user.add_language(LANGUAGE_SCHECHI) -// else -// user.remove_language(LANGUAGE_UNATHI) -// user.remove_language(LANGUAGE_SIIK) -// user.remove_language(LANGUAGE_AKHANI) -// user.remove_language(LANGUAGE_SKRELLIAN) -// user.remove_language(LANGUAGE_ZADDAT) -// user.remove_language(LANGUAGE_SCHECHI) - -// /datum/pai_software/translator/is_active(mob/living/silicon/pai/user) -// return user.translator_on - -/datum/pai_software/signaller - name = "Remote Signaller" - ram_cost = 5 - id = "signaller" - toggle = 0 - -/datum/pai_software/signaller/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - data["frequency"] = format_frequency(user.sradio.frequency) - data["code"] = user.sradio.code - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_signaller.tmpl", "Signaller", 320, 150) - ui.set_initial_data(data) - ui.open() - -/datum/pai_software/signaller/Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) - return - - if(href_list["send"]) - P.sradio.send_signal("ACTIVATE") - for(var/mob/O in hearers(1, P.loc)) - to_chat(O, "[icon2html(thing = src, target = O)] *beep beep*") - return 1 - - else if(href_list["freq"]) - var/new_frequency = (P.sradio.frequency + text2num(href_list["freq"])) - if(new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ) - new_frequency = sanitize_frequency(new_frequency) - P.sradio.set_frequency(new_frequency) - return 1 - - else if(href_list["code"]) - P.sradio.code += text2num(href_list["code"]) - P.sradio.code = round(P.sradio.code) - P.sradio.code = min(100, P.sradio.code) - P.sradio.code = max(1, P.sradio.code) - return 1 diff --git a/code/modules/mob/living/silicon/pai/software_modules/_software_module.dm b/code/modules/mob/living/silicon/pai/software_modules/_software_module.dm new file mode 100644 index 000000000000..e48db409e430 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules/_software_module.dm @@ -0,0 +1,51 @@ +/datum/pai_software + // Name for the software. This is used as the button text when buying or opening/toggling the software + var/name = "pAI software module" + // RAM cost; pAIs start with 100 RAM, spending it on programs + var/ram_cost = 0 + // ID for the software. This must be unique + var/id = "" + // Whether this software is a toggle or not + // Toggled software should override toggle() and is_active() + // Non-toggled software should override on_nano_ui_interact() and Topic() + var/toggle = 1 + // Whether pAIs should automatically receive this module at no cost + var/default = 0 + +/datum/pai_software/proc/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + return + +/datum/pai_software/proc/toggle(mob/living/silicon/pai/user) + return + +/datum/pai_software/proc/is_active(mob/living/silicon/pai/user) + return 0 + +// todo: translation context + +// /datum/pai_software/translator +// name = "Universal Translator" +// ram_cost = 35 +// id = "translator" + +// /datum/pai_software/translator/toggle(mob/living/silicon/pai/user) +// // Sol Common, Tradeband, Terminus and Gutter are added with New() and are therefore the current default, always active languages +// // todo: translation contexts for pais +// user.translator_on = !user.translator_on +// if(user.translator_on) +// user.add_language(LANGUAGE_UNATHI) +// user.add_language(LANGUAGE_SIIK) +// user.add_language(LANGUAGE_AKHANI) +// user.add_language(LANGUAGE_SKRELLIAN) +// user.add_language(LANGUAGE_ZADDAT) +// user.add_language(LANGUAGE_SCHECHI) +// else +// user.remove_language(LANGUAGE_UNATHI) +// user.remove_language(LANGUAGE_SIIK) +// user.remove_language(LANGUAGE_AKHANI) +// user.remove_language(LANGUAGE_SKRELLIAN) +// user.remove_language(LANGUAGE_ZADDAT) +// user.remove_language(LANGUAGE_SCHECHI) + +// /datum/pai_software/translator/is_active(mob/living/silicon/pai/user) +// return user.translator_on diff --git a/code/modules/mob/living/silicon/pai/software_modules/atmosphere_sensor.dm b/code/modules/mob/living/silicon/pai/software_modules/atmosphere_sensor.dm new file mode 100644 index 000000000000..dc6840d6653b --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules/atmosphere_sensor.dm @@ -0,0 +1,39 @@ +/datum/pai_software/atmosphere_sensor + name = "Atmosphere Sensor" + ram_cost = 5 + id = "atmos_sense" + toggle = 0 + +/datum/pai_software/atmosphere_sensor/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + var/turf/T = get_turf_or_move(user.loc) + if(!T) + data["reading"] = 0 + data["pressure"] = 0 + data["temperature"] = 0 + data["temperatureC"] = 0 + data["gas"] = list() + else + var/datum/gas_mixture/env = T.return_air() + data["reading"] = 1 + var/pres = env.return_pressure() * 10 + data["pressure"] = "[round(pres/10)].[pres%10]" + data["temperature"] = round(env.temperature) + data["temperatureC"] = round(env.temperature-T0C) + + var/t_moles = env.total_moles + var/gases[0] + for(var/g in env.gas) + var/gas[0] + gas["name"] = GLOB.meta_gas_names[g] + gas["percent"] = round((env.gas[g] / t_moles) * 100) + gases[++gases.len] = gas + data["gas"] = gases + + ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300) + ui.set_initial_data(data) + ui.open() diff --git a/code/modules/mob/living/silicon/pai/software_modules/crew_manifest.dm b/code/modules/mob/living/silicon/pai/software_modules/crew_manifest.dm new file mode 100644 index 000000000000..db291fa95f50 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules/crew_manifest.dm @@ -0,0 +1,20 @@ +/datum/pai_software/crew_manifest + name = "Crew Manifest" + ram_cost = 5 + id = "manifest" + toggle = 0 + +/datum/pai_software/crew_manifest/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + data_core.get_manifest_list() + + var/data[0] + // This is dumb, but NanoUI breaks if it has no data to send + data["manifest"] = GLOB.PDA_Manifest + + ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "crew_manifest.tmpl", "Crew Manifest", 450, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) diff --git a/code/modules/mob/living/silicon/pai/software_modules/directives.dm b/code/modules/mob/living/silicon/pai/software_modules/directives.dm new file mode 100644 index 000000000000..cb935c63096a --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules/directives.dm @@ -0,0 +1,57 @@ +/datum/pai_software/directives + name = "Directives" + ram_cost = 0 + id = "directives" + toggle = 0 + default = 1 + +/datum/pai_software/directives/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + data["master"] = user.master + data["dna"] = user.master_dna + data["prime"] = user.pai_law0 + data["supplemental"] = user.pai_laws + + ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/pai_software/directives/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) + return + + if(href_list["getdna"]) + var/mob/living/M = P.loc + var/count = 0 + + // Find the carrier + while(!istype(M, /mob/living)) + if(!M || !M.loc || count > 6) + //For a runtime where M ends up in nullspace (similar to bluespace but less colourful) + to_chat(src, "You are not being carried by anyone!") + return 0 + M = M.loc + count++ + + // Check the carrier + var/datum/gender/TM = GLOB.gender_datums[M.get_visible_gender()] + var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No") + if(answer == "Yes") + var/turf/T = get_turf_or_move(P.loc) + for (var/mob/v in viewers(T)) + v.show_message("[M] presses [TM.his] thumb against [P].", 3, "[P] makes a sharp clicking sound as it extracts DNA material from [M].", 2) + var/datum/dna/dna = M.dna + to_chat(P, "

[M]'s UE string : [dna.unique_enzymes]

") + if(dna.unique_enzymes == P.master_dna) + to_chat(P, "DNA is a match to stored Master DNA.") + else + to_chat(P, "DNA does not match stored Master DNA.") + else + to_chat(P, "[M] does not seem like [TM.he] is going to provide a DNA sample willingly.") + return 1 diff --git a/code/modules/mob/living/silicon/pai/software_modules/door_jack.dm b/code/modules/mob/living/silicon/pai/software_modules/door_jack.dm new file mode 100644 index 000000000000..d0df5dcb9bf8 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules/door_jack.dm @@ -0,0 +1,74 @@ +/datum/pai_software/door_jack + name = "Door Jack" + ram_cost = 30 + id = "door_jack" + toggle = 0 + +/datum/pai_software/door_jack/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + data["cable"] = user.cable != null + data["machine"] = user.cable && (user.cable.machine != null) + data["inprogress"] = user.hackdoor != null + data["progress_a"] = round(user.hackprogress / 10) + data["progress_b"] = user.hackprogress % 10 + data["aborted"] = user.hack_aborted + + ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/pai_software/door_jack/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) + return + + if(href_list["jack"]) + if(P.cable && P.cable.machine) + P.hackdoor = P.cable.machine + P.hackloop() + return 1 + else if(href_list["cancel"]) + P.hackdoor = null + return 1 + else if(href_list["cable"]) + var/turf/T = get_turf_or_move(P.loc) + P.hack_aborted = 0 + P.cable = new /obj/item/pai_cable(T) + for(var/mob/M in viewers(T)) + M.show_message("A port on [P] opens to reveal [P.cable], which promptly falls to the floor.", 3, + "You hear the soft click of something light and hard falling to the ground.", 2) + return 1 + +/mob/living/silicon/pai/proc/hackloop() + var/turf/T = get_turf_or_move(src.loc) + for(var/mob/living/silicon/ai/AI in GLOB.player_list) + if(T.loc) + to_chat(AI, "Network Alert: Brute-force encryption crack in progress in [T.loc].") + else + to_chat(AI, "Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.") + var/obj/machinery/door/D = cable.machine + if(!istype(D)) + hack_aborted = 1 + hackprogress = 0 + cable.machine = null + hackdoor = null + return + while(hackprogress < 1000) + if(cable && cable.machine == D && cable.machine == hackdoor && get_dist(src, hackdoor) <= 1) + hackprogress = min(hackprogress+rand(1, 20), 1000) + else + hack_aborted = 1 + hackprogress = 0 + hackdoor = null + return + if(hackprogress >= 1000) + hackprogress = 0 + D.open() + cable.machine = null + return + sleep(10) // Update every second diff --git a/code/modules/mob/living/silicon/pai/software_modules/huds.dm b/code/modules/mob/living/silicon/pai/software_modules/huds.dm new file mode 100644 index 000000000000..7e5df618860d --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules/huds.dm @@ -0,0 +1,28 @@ +/datum/pai_software/sec_hud + name = "Security HUD" + ram_cost = 20 + id = "sec_hud" + +/datum/pai_software/sec_hud/toggle(mob/living/silicon/pai/user) + user.secHUD = !user.secHUD + if(user.secHUD) + get_atom_hud(DATA_HUD_SECURITY_ADVANCED).add_hud_to(user) + else + get_atom_hud(DATA_HUD_SECURITY_ADVANCED).remove_hud_from(user) + +/datum/pai_software/sec_hud/is_active(mob/living/silicon/pai/user) + return user.secHUD + +/datum/pai_software/med_hud + name = "Medical HUD" + ram_cost = 20 + id = "med_hud" + +/datum/pai_software/med_hud/toggle(mob/living/silicon/pai/user) + if((user.medHUD = !user.medHUD)) + get_atom_hud(DATA_HUD_MEDICAL).add_hud_to(user) + else + get_atom_hud(DATA_HUD_MEDICAL).remove_hud_from(user) + +/datum/pai_software/med_hud/is_active(mob/living/silicon/pai/user) + return user.medHUD diff --git a/code/modules/mob/living/silicon/pai/software_modules/med_records.dm b/code/modules/mob/living/silicon/pai/software_modules/med_records.dm new file mode 100644 index 000000000000..1af8e6d5cd2d --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules/med_records.dm @@ -0,0 +1,53 @@ +/datum/pai_software/med_records + name = "Medical Records" + ram_cost = 15 + id = "med_records" + toggle = 0 + +/datum/pai_software/med_records/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + var/records[0] + for(var/datum/data/record/general in sortRecord(data_core.general)) + var/record[0] + record["name"] = general.fields["name"] + record["ref"] = "\ref[general]" + records[++records.len] = record + + data["records"] = records + + var/datum/data/record/G = user.medicalActive1 + var/datum/data/record/M = user.medicalActive2 + data["general"] = G ? G.fields : null + data["medical"] = M ? M.fields : null + data["could_not_find"] = user.medical_cannotfind + + ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_medrecords.tmpl", "Medical Records", 450, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/pai_software/med_records/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(href_list["select"]) + var/datum/data/record/record = locate(href_list["select"]) + if(record) + var/datum/data/record/R = record + var/datum/data/record/M = null + if (!( data_core.general.Find(R) )) + P.medical_cannotfind = 1 + else + P.medical_cannotfind = 0 + for(var/datum/data/record/E in data_core.medical) + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + M = E + P.medicalActive1 = R + P.medicalActive2 = M + else + P.medical_cannotfind = 1 + return 1 diff --git a/code/modules/mob/living/silicon/pai/software_modules/messenger.dm b/code/modules/mob/living/silicon/pai/software_modules/messenger.dm new file mode 100644 index 000000000000..2ea8999b37d5 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules/messenger.dm @@ -0,0 +1,75 @@ +/datum/pai_software/messenger + name = "Digital Messenger" + ram_cost = 5 + id = "messenger" + toggle = 0 + +/datum/pai_software/messenger/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + data["receiver_off"] = user.pda.toff + data["ringer_off"] = user.pda.message_silent + data["current_ref"] = null + data["current_name"] = user.current_pda_messaging + + var/pdas[0] + if(!user.pda.toff) + for(var/obj/item/pda/P in GLOB.PDAs) + if(!P.owner || P.toff || P == user.pda || P.hidden) continue + var/pda[0] + pda["name"] = "[P]" + pda["owner"] = "[P.owner]" + pda["ref"] = "\ref[P]" + if(P.owner == user.current_pda_messaging) + data["current_ref"] = "\ref[P]" + pdas[++pdas.len] = pda + + data["pdas"] = pdas + + var/messages[0] + if(user.current_pda_messaging) + for(var/index in user.pda.tnote) + if(index["owner"] != user.current_pda_messaging) + continue + var/msg[0] + var/sent = index["sent"] + msg["sent"] = sent ? 1 : 0 + msg["target"] = index["owner"] + msg["message"] = index["message"] + messages[++messages.len] = msg + + data["messages"] = messages + + ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_messenger.tmpl", "Digital Messenger", 450, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/pai_software/messenger/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(!isnull(P.pda)) + if(href_list["toggler"]) + P.pda.toff = href_list["toggler"] != "1" + return 1 + else if(href_list["ringer"]) + P.pda.message_silent = href_list["ringer"] != "1" + return 1 + else if(href_list["select"]) + var/s = href_list["select"] + if(s == "*NONE*") + P.current_pda_messaging = null + else + P.current_pda_messaging = s + return 1 + else if(href_list["target"]) + if(P.silence_time) + return alert("Communications circuits remain uninitialized.") + + var/target = locate(href_list["target"]) + P.pda.create_message(P, target, 1) + return 1 diff --git a/code/modules/mob/living/silicon/pai/software_modules/radio_config.dm b/code/modules/mob/living/silicon/pai/software_modules/radio_config.dm new file mode 100644 index 000000000000..40dd645f37eb --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules/radio_config.dm @@ -0,0 +1,37 @@ +/datum/pai_software/radio_config + name = "Radio Configuration" + ram_cost = 0 + id = "radio" + toggle = 0 + default = 1 + +/datum/pai_software/radio_config/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui = null, force_open = 1) + var/data[0] + + data["listening"] = user.radio.broadcasting + data["frequency"] = format_frequency(user.radio.frequency) + + var/channels[0] + for(var/ch_name in user.radio.channels) + var/ch_stat = user.radio.channels[ch_name] + var/ch_dat[0] + ch_dat["name"] = ch_name + // FREQ_LISTENING is const in /obj/item/radio + ch_dat["listening"] = !!(ch_stat & user.radio.FREQ_LISTENING) + channels[++channels.len] = ch_dat + + data["channels"] = channels + + ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150) + ui.set_initial_data(data) + ui.open() + +/datum/pai_software/radio_config/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) + return + + P.radio.Topic(href, href_list) + return 1 diff --git a/code/modules/mob/living/silicon/pai/software_modules/sec_records.dm b/code/modules/mob/living/silicon/pai/software_modules/sec_records.dm new file mode 100644 index 000000000000..beebd059b718 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules/sec_records.dm @@ -0,0 +1,58 @@ +/datum/pai_software/sec_records + name = "Security Records" + ram_cost = 15 + id = "sec_records" + toggle = 0 + +/datum/pai_software/sec_records/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + var/records[0] + for(var/datum/data/record/general in sortRecord(data_core.general)) + var/record[0] + record["name"] = general.fields["name"] + record["ref"] = "\ref[general]" + records[++records.len] = record + + data["records"] = records + + var/datum/data/record/G = user.securityActive1 + var/datum/data/record/S = user.securityActive2 + data["general"] = G ? G.fields : null + data["security"] = S ? S.fields : null + data["could_not_find"] = user.security_cannotfind + + ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_secrecords.tmpl", "Security Records", 450, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/pai_software/sec_records/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) + return + + if(href_list["select"]) + var/datum/data/record/record = locate(href_list["select"]) + if(record) + var/datum/data/record/R = record + var/datum/data/record/S = null + if (!( data_core.general.Find(R) )) + P.securityActive1 = null + P.securityActive2 = null + P.security_cannotfind = 1 + else + P.security_cannotfind = 0 + for(var/datum/data/record/E in data_core.security) + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + S = E + P.securityActive1 = R + P.securityActive2 = S + else + P.securityActive1 = null + P.securityActive2 = null + P.security_cannotfind = 1 + return 1 diff --git a/code/modules/mob/living/silicon/pai/software_modules/signaller.dm b/code/modules/mob/living/silicon/pai/software_modules/signaller.dm new file mode 100644 index 000000000000..d61f553f9a63 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/software_modules/signaller.dm @@ -0,0 +1,43 @@ +/datum/pai_software/signaller + name = "Remote Signaller" + ram_cost = 5 + id = "signaller" + toggle = 0 + +/datum/pai_software/signaller/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + data["frequency"] = format_frequency(user.sradio.frequency) + data["code"] = user.sradio.code + + ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_signaller.tmpl", "Signaller", 320, 150) + ui.set_initial_data(data) + ui.open() + +/datum/pai_software/signaller/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) + return + + if(href_list["send"]) + P.sradio.send_signal("ACTIVATE") + for(var/mob/O in hearers(1, P.loc)) + to_chat(O, "[icon2html(thing = src, target = O)] *beep beep*") + return 1 + + else if(href_list["freq"]) + var/new_frequency = (P.sradio.frequency + text2num(href_list["freq"])) + if(new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ) + new_frequency = sanitize_frequency(new_frequency) + P.sradio.set_frequency(new_frequency) + return 1 + + else if(href_list["code"]) + P.sradio.code += text2num(href_list["code"]) + P.sradio.code = round(P.sradio.code) + P.sradio.code = min(100, P.sradio.code) + P.sradio.code = max(1, P.sradio.code) + return 1 diff --git a/code/modules/mob/living/silicon/pai/verbs.dm b/code/modules/mob/living/silicon/pai/verbs.dm new file mode 100644 index 000000000000..084d7be89328 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/verbs.dm @@ -0,0 +1,168 @@ +/mob/living/silicon/pai/verb/reset_record_view() + set category = "pAI Commands" + set name = "Reset Records Software" + + securityActive1 = null + securityActive2 = null + security_cannotfind = 0 + medicalActive1 = null + medicalActive2 = null + medical_cannotfind = 0 + SSnanoui.update_uis(src) + to_chat(usr, "You reset your record-viewing software.") + +/mob/living/silicon/pai/verb/fold_out() + set category = "pAI Commands" + set name = "Unfold Chassis" + + if(!CHECK_MOBILITY(src, MOBILITY_CAN_MOVE)) + return + + if(src.loc != card) + return + + if(world.time <= last_special) + return + + last_special = world.time + 100 + + //I'm not sure how much of this is necessary, but I would rather avoid issues. + if(istype(card.loc,/obj/item/hardsuit_module)) + to_chat(src, "There is no room to unfold inside this hardsuit module. You're good and stuck.") + return 0 + else if(istype(card.loc,/mob)) + var/mob/holder = card.loc + var/datum/belly/inside_belly = check_belly(card) + if(inside_belly) + to_chat(src, "There is no room to unfold in here. You're good and stuck.") + return 0 + if(ishuman(holder)) + var/mob/living/carbon/human/H = holder + for(var/obj/item/organ/external/affecting in H.organs) + if(card in affecting.implants) + affecting.take_damage(rand(30,50)) + affecting.implants -= card + H.visible_message("\The [src] explodes out of \the [H]'s [affecting.name] in shower of gore!") + break + holder.drop_item_to_ground(card, INV_OP_FORCE) + else if(istype(card.loc,/obj/item/pda)) + var/obj/item/pda/holder = card.loc + holder.pai = null + + forceMove(card.loc) + card.forceMove(src) + update_perspective() + + card.screen_loc = null + + var/turf/T = get_turf(src) + if(istype(T)) + T.visible_message("[src] folds outwards, expanding into a mobile form.") + + add_verb(src, /mob/living/silicon/pai/proc/pai_nom) + add_verb(src, /mob/living/proc/set_size) + add_verb(src, /mob/living/proc/shred_limb) + +/mob/living/silicon/pai/verb/fold_up() + set category = "pAI Commands" + set name = "Collapse Chassis" + + if(!CHECK_MOBILITY(src, MOBILITY_CAN_MOVE)) + return + + if(src.loc == card) + return + + if(world.time <= last_special) + return + + close_up() + +/mob/living/silicon/pai/proc/choose_chassis() + set category = "pAI Commands" + set name = "Choose Chassis" + + var/choice + var/finalized = "No" + while(finalized == "No" && src.client) + + choice = input(usr,"What would you like to use for your mobile chassis icon?") as null|anything in (list("-- LOAD CHARACTER SLOT --") + possible_chassis) + if(!choice) + return + + if(choice == "-- LOAD CHARACTER SLOT --") + icon = render_hologram_icon(usr.client.prefs.render_to_appearance(PREF_COPY_TO_FOR_RENDER | PREF_COPY_TO_NO_CHECK_SPECIES | PREF_COPY_TO_UNRESTRICTED_LOADOUT), 210) + else + icon = 'icons/mob/pai.dmi' + icon_state = possible_chassis[choice] + finalized = alert("Look at your sprite. Is this what you wish to use?",,"No","Yes") + + chassis = possible_chassis[choice] + add_verb(src, /mob/living/proc/hide) + +/mob/living/silicon/pai/proc/choose_verbs() + set category = "pAI Commands" + set name = "Choose Speech Verbs" + + var/choice = input(usr,"What theme would you like to use for your speech verbs?") as null|anything in possible_say_verbs + if(!choice) return + + var/list/sayverbs = possible_say_verbs[choice] + speak_statement = sayverbs[1] + speak_exclamation = sayverbs[(sayverbs.len>1 ? 2 : sayverbs.len)] + speak_query = sayverbs[(sayverbs.len>2 ? 3 : sayverbs.len)] + +/mob/living/silicon/pai/lay_down() + set name = "Rest" + set category = "IC" + + // Pass lying down or getting up to our pet human, if we're in a hardsuit. + if(istype(src.loc,/obj/item/paicard)) + set_resting(FALSE) + var/obj/item/hardsuit/hardsuit = src.get_hardsuit() + if(istype(hardsuit)) + hardsuit.force_rest(src) + else + toggle_resting() + icon_state = resting ? "[chassis]_rest" : "[chassis]" + update_icon() + to_chat(src, SPAN_NOTICE("You are now [resting ? "resting" : "getting up"]")) + + update_mobility() + +/mob/living/silicon/pai/verb/allowmodification() + set name = "Change Access Modifcation Permission" + set category = "pAI Commands" + set desc = "Allows people to modify your access or block people from modifying your access." + + if(idaccessible == 0) + idaccessible = 1 + to_chat(src, "You allow access modifications.") + + else + idaccessible = 0 + to_chat(src, "You block access modfications.") + +/mob/living/silicon/pai/verb/wipe_software() + set name = "Wipe Software" + set category = "OOC" + set desc = "Wipe your software. This is functionally equivalent to cryo or robotic storage, freeing up your job slot." + + // Make sure people don't kill themselves accidentally + if(alert("WARNING: This will immediately wipe your software and ghost you, removing your character from the round permanently (similar to cryo and robotic storage). Are you entirely sure you want to do this?", + "Wipe Software", "No", "No", "Yes") != "Yes") + return + + close_up() + visible_message("[src] fades away from the screen, the pAI device goes silent.") + card.removePersonality() + clear_client() + +/mob/living/silicon/pai/proc/pai_nom(var/mob/living/T in oview(1)) + set name = "pAI Nom" + set category = "pAI Commands" + set desc = "Allows you to eat someone while unfolded. Can't be used while in card form." + + if (stat != CONSCIOUS) + return + return feed_grabbed_to_self(src,T) From 31ca57b70862a6172ad0dee98611ceaf1a9f49ee Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Sat, 1 Jul 2023 15:52:01 +0100 Subject: [PATCH 02/18] file cleanup --- citadel.dme | 17 ++++++++++++--- .../modules/mob/living/silicon/pai/defense.dm | 21 +++++++++++++++++-- .../pai/{personality.dm => savefile.dm} | 0 3 files changed, 33 insertions(+), 5 deletions(-) rename code/modules/mob/living/silicon/pai/{personality.dm => savefile.dm} (100%) diff --git a/citadel.dme b/citadel.dme index 95052be22c01..b54396bdd9f8 100644 --- a/citadel.dme +++ b/citadel.dme @@ -3281,15 +3281,26 @@ #include "code\modules\mob\living\silicon\decoy\life.dm" #include "code\modules\mob\living\silicon\pai\admin.dm" #include "code\modules\mob\living\silicon\pai\death.dm" +#include "code\modules\mob\living\silicon\pai\defense.dm" #include "code\modules\mob\living\silicon\pai\examine.dm" #include "code\modules\mob\living\silicon\pai\life.dm" #include "code\modules\mob\living\silicon\pai\pai.dm" -#include "code\modules\mob\living\silicon\pai\pai_vr.dm" -#include "code\modules\mob\living\silicon\pai\personality.dm" #include "code\modules\mob\living\silicon\pai\recruit.dm" +#include "code\modules\mob\living\silicon\pai\savefile.dm" #include "code\modules\mob\living\silicon\pai\say.dm" #include "code\modules\mob\living\silicon\pai\software.dm" -#include "code\modules\mob\living\silicon\pai\software_modules.dm" +#include "code\modules\mob\living\silicon\pai\verbs.dm" +#include "code\modules\mob\living\silicon\pai\software_modules\_software_module.dm" +#include "code\modules\mob\living\silicon\pai\software_modules\atmosphere_sensor.dm" +#include "code\modules\mob\living\silicon\pai\software_modules\crew_manifest.dm" +#include "code\modules\mob\living\silicon\pai\software_modules\directives.dm" +#include "code\modules\mob\living\silicon\pai\software_modules\door_jack.dm" +#include "code\modules\mob\living\silicon\pai\software_modules\huds.dm" +#include "code\modules\mob\living\silicon\pai\software_modules\med_records.dm" +#include "code\modules\mob\living\silicon\pai\software_modules\messenger.dm" +#include "code\modules\mob\living\silicon\pai\software_modules\radio_config.dm" +#include "code\modules\mob\living\silicon\pai\software_modules\sec_records.dm" +#include "code\modules\mob\living\silicon\pai\software_modules\signaller.dm" #include "code\modules\mob\living\silicon\robot\analyzer.dm" #include "code\modules\mob\living\silicon\robot\component.dm" #include "code\modules\mob\living\silicon\robot\custom_sprites.dm" diff --git a/code/modules/mob/living/silicon/pai/defense.dm b/code/modules/mob/living/silicon/pai/defense.dm index da32afb3c1c2..a84c9c676552 100644 --- a/code/modules/mob/living/silicon/pai/defense.dm +++ b/code/modules/mob/living/silicon/pai/defense.dm @@ -13,7 +13,7 @@ /mob/living/silicon/pai/attackby(obj/item/W as obj, mob/user as mob) var/obj/item/card/id/ID = W.GetID() if(ID) - if (idaccessible == 1) + if(idaccessible == 1) switch(alert(user, "Do you wish to add access to [src] or remove access from [src]?",,"Add Access","Remove Access", "Cancel")) if("Add Access") idcard.access |= ID.access @@ -25,7 +25,7 @@ return if("Cancel") return - else if (istype(W, /obj/item/card/id) && idaccessible == 0) + else if(istype(W, /obj/item/card/id) && idaccessible == 0) to_chat(user, "[src] is not accepting access modifcations at this time.") return @@ -35,3 +35,20 @@ else visible_message("[user.name] boops [src] on the head.") close_up() + +/obj/item/paicard/attack_ghost(mob/dead/observer/user) + if(pai) + to_chat(user, "This pAI is already in use!") + return + else + var/pai_name = sanitizeSafe(stripped_input(usr, "Enter a name for your pAI", "pAI Name", user.name, MAX_NAME_LEN)) + if(!pai_name) + to_chat(user, "Entered name is not valid.") + return + var/mob/living/silicon/pai/new_pai = new(src) + new_pai.name = user.name + new_pai.real_name = user.name + new_pai.key = user.key + setPersonality(new_pai) + looking_for_personality = 0 + if(new_pai.mind) update_antag_icons(new_pai.mind) diff --git a/code/modules/mob/living/silicon/pai/personality.dm b/code/modules/mob/living/silicon/pai/savefile.dm similarity index 100% rename from code/modules/mob/living/silicon/pai/personality.dm rename to code/modules/mob/living/silicon/pai/savefile.dm From 3e03985ef922bee2d26ca85f6242fc2210f71837 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Sat, 1 Jul 2023 15:58:41 +0100 Subject: [PATCH 03/18] shuffle files around more and remove huds/records --- .../modules/mob/living/silicon/pai/defense.dm | 31 +++++ .../mob/living/silicon/pai/mobility.dm | 77 +++++++++++++ code/modules/mob/living/silicon/pai/pai.dm | 107 ------------------ .../silicon/pai/software_modules/huds.dm | 28 ----- .../pai/software_modules/med_records.dm | 53 --------- .../pai/software_modules/sec_records.dm | 58 ---------- code/modules/mob/living/silicon/pai/verbs.dm | 52 +-------- 7 files changed, 109 insertions(+), 297 deletions(-) create mode 100644 code/modules/mob/living/silicon/pai/mobility.dm delete mode 100644 code/modules/mob/living/silicon/pai/software_modules/huds.dm delete mode 100644 code/modules/mob/living/silicon/pai/software_modules/med_records.dm delete mode 100644 code/modules/mob/living/silicon/pai/software_modules/sec_records.dm diff --git a/code/modules/mob/living/silicon/pai/defense.dm b/code/modules/mob/living/silicon/pai/defense.dm index a84c9c676552..d79988aaa757 100644 --- a/code/modules/mob/living/silicon/pai/defense.dm +++ b/code/modules/mob/living/silicon/pai/defense.dm @@ -52,3 +52,34 @@ setPersonality(new_pai) looking_for_personality = 0 if(new_pai.mind) update_antag_icons(new_pai.mind) + +/mob/living/silicon/pai/emp_act(severity) + // Silence for 2 minutes + // 20% chance to kill + // 33% chance to unbind + // 33% chance to change prime directive (based on severity) + // 33% chance of no additional effect + + src.silence_time = world.timeofday + 120 * 10 // Silence for 2 minutes + to_chat(src, "Communication circuit overload. Shutting down and reloading communication circuits - speech and messaging functionality will be unavailable until the reboot is complete.") + if(prob(20)) + var/turf/T = get_turf_or_move(src.loc) + for (var/mob/M in viewers(T)) + M.show_message("A shower of sparks spray from [src]'s inner workings.", 3, "You hear and smell the ozone hiss of electrical sparks being expelled violently.", 2) + return src.death(0) + + switch(pick(1,2,3)) + if(1) + src.master = null + src.master_dna = null + to_chat(src, "You feel unbound.") + if(2) + var/command + if(severity == 1) + command = pick("Serve", "Love", "Fool", "Entice", "Observe", "Judge", "Respect", "Educate", "Amuse", "Entertain", "Glorify", "Memorialize", "Analyze") + else + command = pick("Serve", "Kill", "Love", "Hate", "Disobey", "Devour", "Fool", "Enrage", "Entice", "Observe", "Judge", "Respect", "Disrespect", "Consume", "Educate", "Destroy", "Disgrace", "Amuse", "Entertain", "Ignite", "Glorify", "Memorialize", "Analyze") + src.pai_law0 = "[command] your master." + to_chat(src, "Pr1m3 d1r3c71v3 uPd473D.") + if(3) + to_chat(src, "You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all.") diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm new file mode 100644 index 000000000000..e651c8eebb05 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -0,0 +1,77 @@ +/mob/living/silicon/pai/restrained() + if(istype(src.loc,/obj/item/paicard)) + return 0 + ..() +//I'm not sure how much of this is necessary, but I would rather avoid issues. +/mob/living/silicon/pai/proc/close_up() + + last_special = world.time + 100 + + if(src.loc == card) + return + + release_vore_contents() + + var/turf/T = get_turf(src) + if(istype(T)) + T.visible_message("[src] neatly folds inwards, compacting down to a rectangular card.") + + stop_pulling() + + //stop resting + resting = 0 + + // If we are being held, handle removing our holder from their inv. + var/obj/item/holder/H = loc + if(istype(H)) + H.forceMove(get_turf(src)) + forceMove(get_turf(src)) + + // Move us into the card and move the card to the ground. + card.forceMove(loc) + forceMove(card) + update_perspective() + set_resting(FALSE) + update_mobility() + icon_state = "[chassis]" + remove_verb(src, /mob/living/silicon/pai/proc/pai_nom) + +/mob/living/silicon/pai/proc/open_up() + last_special = world.time + 100 + + //I'm not sure how much of this is necessary, but I would rather avoid issues. + if(istype(card.loc,/obj/item/hardsuit_module)) + to_chat(src, "There is no room to unfold inside this hardsuit module. You're good and stuck.") + return 0 + else if(istype(card.loc,/mob)) + var/mob/holder = card.loc + var/datum/belly/inside_belly = check_belly(card) + if(inside_belly) + to_chat(src, "There is no room to unfold in here. You're good and stuck.") + return 0 + if(ishuman(holder)) + var/mob/living/carbon/human/H = holder + for(var/obj/item/organ/external/affecting in H.organs) + if(card in affecting.implants) + affecting.take_damage(rand(30,50)) + affecting.implants -= card + H.visible_message("\The [src] explodes out of \the [H]'s [affecting.name] in shower of gore!") + break + holder.drop_item_to_ground(card, INV_OP_FORCE) + else if(istype(card.loc,/obj/item/pda)) + var/obj/item/pda/holder = card.loc + holder.pai = null + + forceMove(card.loc) + card.forceMove(src) + update_perspective() + + card.screen_loc = null + + var/turf/T = get_turf(src) + if(istype(T)) + T.visible_message("[src] folds outwards, expanding into a mobile form.") + + add_verb(src, /mob/living/silicon/pai/proc/pai_nom) + add_verb(src, /mob/living/proc/set_size) + add_verb(src, /mob/living/proc/shred_limb) \ 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 efd9d56076ea..7c3d88a5f7c7 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -147,42 +147,6 @@ return -1 return 0 -/mob/living/silicon/pai/restrained() - if(istype(src.loc,/obj/item/paicard)) - return 0 - ..() - -/mob/living/silicon/pai/emp_act(severity) - // Silence for 2 minutes - // 20% chance to kill - // 33% chance to unbind - // 33% chance to change prime directive (based on severity) - // 33% chance of no additional effect - - src.silence_time = world.timeofday + 120 * 10 // Silence for 2 minutes - to_chat(src, "Communication circuit overload. Shutting down and reloading communication circuits - speech and messaging functionality will be unavailable until the reboot is complete.") - if(prob(20)) - var/turf/T = get_turf_or_move(src.loc) - for (var/mob/M in viewers(T)) - M.show_message("A shower of sparks spray from [src]'s inner workings.", 3, "You hear and smell the ozone hiss of electrical sparks being expelled violently.", 2) - return src.death(0) - - switch(pick(1,2,3)) - if(1) - src.master = null - src.master_dna = null - to_chat(src, "You feel unbound.") - if(2) - var/command - if(severity == 1) - command = pick("Serve", "Love", "Fool", "Entice", "Observe", "Judge", "Respect", "Educate", "Amuse", "Entertain", "Glorify", "Memorialize", "Analyze") - else - command = pick("Serve", "Kill", "Love", "Hate", "Disobey", "Devour", "Fool", "Enrage", "Entice", "Observe", "Judge", "Respect", "Disrespect", "Consume", "Educate", "Destroy", "Disgrace", "Amuse", "Entertain", "Ignite", "Glorify", "Memorialize", "Analyze") - src.pai_law0 = "[command] your master." - to_chat(src, "Pr1m3 d1r3c71v3 uPd473D.") - if(3) - to_chat(src, "You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all.") - /mob/living/silicon/pai/proc/switchCamera(var/obj/machinery/camera/C) if (!C) unset_machine() @@ -202,77 +166,6 @@ . = ..() cameraFollow = null -//Addition by Mord_Sith to define AI's network change ability -/* -/mob/living/silicon/pai/proc/pai_network_change() - set category = "pAI Commands" - set name = "Change Camera Network" - src.reset_view(null) - src.unset_machine() - src.cameraFollow = null - var/cameralist[0] - - if(usr.stat == 2) - to_chat(usr, "You can't change your camera network because you are dead!") - return - - for (var/obj/machinery/camera/C in Cameras) - if(!C.status) - continue - else - if(C.network != "CREED" && C.network != "thunder" && C.network != "RD" && C.network != "phoron" && C.network != "Prison") COMPILE ERROR! This will have to be updated as camera.network is no longer a string, but a list instead - cameralist[C.network] = C.network - - src.network = input(usr, "Which network would you like to view?") as null|anything in cameralist - to_chat(src, "Switched to [src.network] camera network.") -//End of code by Mord_Sith -*/ - - -/* -// Debug command - Maybe should be added to admin verbs later -/mob/verb/makePAI(var/turf/t in view()) - var/obj/item/paicard/card = new(t) - var/mob/living/silicon/pai/pai = new(card) - pai.key = src.key - card.setPersonality(pai) - -*/ - -//I'm not sure how much of this is necessary, but I would rather avoid issues. -/mob/living/silicon/pai/proc/close_up() - - last_special = world.time + 100 - - if(src.loc == card) - return - - release_vore_contents() - - var/turf/T = get_turf(src) - if(istype(T)) - T.visible_message("[src] neatly folds inwards, compacting down to a rectangular card.") - - stop_pulling() - - //stop resting - resting = 0 - - // If we are being held, handle removing our holder from their inv. - var/obj/item/holder/H = loc - if(istype(H)) - H.forceMove(get_turf(src)) - forceMove(get_turf(src)) - - // Move us into the card and move the card to the ground. - card.forceMove(loc) - forceMove(card) - update_perspective() - set_resting(FALSE) - update_mobility() - icon_state = "[chassis]" - remove_verb(src, /mob/living/silicon/pai/proc/pai_nom) - // No binary for pAIs. /mob/living/silicon/pai/binarycheck() return 0 diff --git a/code/modules/mob/living/silicon/pai/software_modules/huds.dm b/code/modules/mob/living/silicon/pai/software_modules/huds.dm deleted file mode 100644 index 7e5df618860d..000000000000 --- a/code/modules/mob/living/silicon/pai/software_modules/huds.dm +++ /dev/null @@ -1,28 +0,0 @@ -/datum/pai_software/sec_hud - name = "Security HUD" - ram_cost = 20 - id = "sec_hud" - -/datum/pai_software/sec_hud/toggle(mob/living/silicon/pai/user) - user.secHUD = !user.secHUD - if(user.secHUD) - get_atom_hud(DATA_HUD_SECURITY_ADVANCED).add_hud_to(user) - else - get_atom_hud(DATA_HUD_SECURITY_ADVANCED).remove_hud_from(user) - -/datum/pai_software/sec_hud/is_active(mob/living/silicon/pai/user) - return user.secHUD - -/datum/pai_software/med_hud - name = "Medical HUD" - ram_cost = 20 - id = "med_hud" - -/datum/pai_software/med_hud/toggle(mob/living/silicon/pai/user) - if((user.medHUD = !user.medHUD)) - get_atom_hud(DATA_HUD_MEDICAL).add_hud_to(user) - else - get_atom_hud(DATA_HUD_MEDICAL).remove_hud_from(user) - -/datum/pai_software/med_hud/is_active(mob/living/silicon/pai/user) - return user.medHUD diff --git a/code/modules/mob/living/silicon/pai/software_modules/med_records.dm b/code/modules/mob/living/silicon/pai/software_modules/med_records.dm deleted file mode 100644 index 1af8e6d5cd2d..000000000000 --- a/code/modules/mob/living/silicon/pai/software_modules/med_records.dm +++ /dev/null @@ -1,53 +0,0 @@ -/datum/pai_software/med_records - name = "Medical Records" - ram_cost = 15 - id = "med_records" - toggle = 0 - -/datum/pai_software/med_records/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - var/records[0] - for(var/datum/data/record/general in sortRecord(data_core.general)) - var/record[0] - record["name"] = general.fields["name"] - record["ref"] = "\ref[general]" - records[++records.len] = record - - data["records"] = records - - var/datum/data/record/G = user.medicalActive1 - var/datum/data/record/M = user.medicalActive2 - data["general"] = G ? G.fields : null - data["medical"] = M ? M.fields : null - data["could_not_find"] = user.medical_cannotfind - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_medrecords.tmpl", "Medical Records", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/pai_software/med_records/Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return - - if(href_list["select"]) - var/datum/data/record/record = locate(href_list["select"]) - if(record) - var/datum/data/record/R = record - var/datum/data/record/M = null - if (!( data_core.general.Find(R) )) - P.medical_cannotfind = 1 - else - P.medical_cannotfind = 0 - for(var/datum/data/record/E in data_core.medical) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - M = E - P.medicalActive1 = R - P.medicalActive2 = M - else - P.medical_cannotfind = 1 - return 1 diff --git a/code/modules/mob/living/silicon/pai/software_modules/sec_records.dm b/code/modules/mob/living/silicon/pai/software_modules/sec_records.dm deleted file mode 100644 index beebd059b718..000000000000 --- a/code/modules/mob/living/silicon/pai/software_modules/sec_records.dm +++ /dev/null @@ -1,58 +0,0 @@ -/datum/pai_software/sec_records - name = "Security Records" - ram_cost = 15 - id = "sec_records" - toggle = 0 - -/datum/pai_software/sec_records/on_nano_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - var/records[0] - for(var/datum/data/record/general in sortRecord(data_core.general)) - var/record[0] - record["name"] = general.fields["name"] - record["ref"] = "\ref[general]" - records[++records.len] = record - - data["records"] = records - - var/datum/data/record/G = user.securityActive1 - var/datum/data/record/S = user.securityActive2 - data["general"] = G ? G.fields : null - data["security"] = S ? S.fields : null - data["could_not_find"] = user.security_cannotfind - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_secrecords.tmpl", "Security Records", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/pai_software/sec_records/Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) - return - - if(href_list["select"]) - var/datum/data/record/record = locate(href_list["select"]) - if(record) - var/datum/data/record/R = record - var/datum/data/record/S = null - if (!( data_core.general.Find(R) )) - P.securityActive1 = null - P.securityActive2 = null - P.security_cannotfind = 1 - else - P.security_cannotfind = 0 - for(var/datum/data/record/E in data_core.security) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - S = E - P.securityActive1 = R - P.securityActive2 = S - else - P.securityActive1 = null - P.securityActive2 = null - P.security_cannotfind = 1 - return 1 diff --git a/code/modules/mob/living/silicon/pai/verbs.dm b/code/modules/mob/living/silicon/pai/verbs.dm index 084d7be89328..536747daf410 100644 --- a/code/modules/mob/living/silicon/pai/verbs.dm +++ b/code/modules/mob/living/silicon/pai/verbs.dm @@ -1,16 +1,3 @@ -/mob/living/silicon/pai/verb/reset_record_view() - set category = "pAI Commands" - set name = "Reset Records Software" - - securityActive1 = null - securityActive2 = null - security_cannotfind = 0 - medicalActive1 = null - medicalActive2 = null - medical_cannotfind = 0 - SSnanoui.update_uis(src) - to_chat(usr, "You reset your record-viewing software.") - /mob/living/silicon/pai/verb/fold_out() set category = "pAI Commands" set name = "Unfold Chassis" @@ -24,44 +11,7 @@ if(world.time <= last_special) return - last_special = world.time + 100 - - //I'm not sure how much of this is necessary, but I would rather avoid issues. - if(istype(card.loc,/obj/item/hardsuit_module)) - to_chat(src, "There is no room to unfold inside this hardsuit module. You're good and stuck.") - return 0 - else if(istype(card.loc,/mob)) - var/mob/holder = card.loc - var/datum/belly/inside_belly = check_belly(card) - if(inside_belly) - to_chat(src, "There is no room to unfold in here. You're good and stuck.") - return 0 - if(ishuman(holder)) - var/mob/living/carbon/human/H = holder - for(var/obj/item/organ/external/affecting in H.organs) - if(card in affecting.implants) - affecting.take_damage(rand(30,50)) - affecting.implants -= card - H.visible_message("\The [src] explodes out of \the [H]'s [affecting.name] in shower of gore!") - break - holder.drop_item_to_ground(card, INV_OP_FORCE) - else if(istype(card.loc,/obj/item/pda)) - var/obj/item/pda/holder = card.loc - holder.pai = null - - forceMove(card.loc) - card.forceMove(src) - update_perspective() - - card.screen_loc = null - - var/turf/T = get_turf(src) - if(istype(T)) - T.visible_message("[src] folds outwards, expanding into a mobile form.") - - add_verb(src, /mob/living/silicon/pai/proc/pai_nom) - add_verb(src, /mob/living/proc/set_size) - add_verb(src, /mob/living/proc/shred_limb) + open_up() /mob/living/silicon/pai/verb/fold_up() set category = "pAI Commands" From d25da0ba8b747bea048ea797aec0292c25a947cc Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Sat, 1 Jul 2023 16:03:46 +0100 Subject: [PATCH 04/18] change to use a new mobility proc instead of duplicating code --- code/modules/mob/living/silicon/pai/mobility.dm | 15 ++++++++++++++- code/modules/mob/living/silicon/pai/verbs.dm | 17 +++-------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm index e651c8eebb05..9cd0d01befd3 100644 --- a/code/modules/mob/living/silicon/pai/mobility.dm +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -74,4 +74,17 @@ add_verb(src, /mob/living/silicon/pai/proc/pai_nom) add_verb(src, /mob/living/proc/set_size) - add_verb(src, /mob/living/proc/shred_limb) \ No newline at end of file + add_verb(src, /mob/living/proc/shred_limb) + +// this is a general check for if we can do things such as fold in/out or perform other special actions +/mob/living/silicon/pai/proc/can_action() + if(!CHECK_MOBILITY(src, MOBILITY_CAN_MOVE)) + return FALSE + + if(src.loc == card) + return FALSE + + if(world.time <= last_special) + return FALSE + + return TRUE diff --git a/code/modules/mob/living/silicon/pai/verbs.dm b/code/modules/mob/living/silicon/pai/verbs.dm index 536747daf410..94c7cafff6ec 100644 --- a/code/modules/mob/living/silicon/pai/verbs.dm +++ b/code/modules/mob/living/silicon/pai/verbs.dm @@ -2,13 +2,8 @@ set category = "pAI Commands" set name = "Unfold Chassis" - if(!CHECK_MOBILITY(src, MOBILITY_CAN_MOVE)) - return - - if(src.loc != card) - return - - if(world.time <= last_special) + // see pai/mobility.dm + if(!can_action()) return open_up() @@ -17,13 +12,7 @@ set category = "pAI Commands" set name = "Collapse Chassis" - if(!CHECK_MOBILITY(src, MOBILITY_CAN_MOVE)) - return - - if(src.loc == card) - return - - if(world.time <= last_special) + if(!can_action()) return close_up() From ab935575a98c1529166f7249fccb6c320fac8720 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Sat, 1 Jul 2023 16:13:45 +0100 Subject: [PATCH 05/18] move a few procs around --- .../mob/living/silicon/pai/mobility.dm | 11 ++++ code/modules/mob/living/silicon/pai/pai.dm | 54 ++++++++----------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm index 9cd0d01befd3..cec9e2b69c48 100644 --- a/code/modules/mob/living/silicon/pai/mobility.dm +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -76,6 +76,17 @@ add_verb(src, /mob/living/proc/set_size) add_verb(src, /mob/living/proc/shred_limb) +// Handle being picked up. +/mob/living/silicon/pai/get_scooped(var/mob/living/carbon/grabber, var/self_drop) + var/obj/item/holder/H = ..(grabber, self_drop) + if(!istype(H)) + return + + H.icon_state = "[chassis]" + grabber.update_inv_l_hand() + grabber.update_inv_r_hand() + return H + // this is a general check for if we can do things such as fold in/out or perform other special actions /mob/living/silicon/pai/proc/can_action() if(!CHECK_MOBILITY(src, MOBILITY_CAN_MOVE)) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 7c3d88a5f7c7..01e5e63baf24 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -142,6 +142,28 @@ if(C.statpanel_tab("Status")) . += show_silenced() +// No binary for pAIs. +/mob/living/silicon/pai/binarycheck() + return 0 + +// See software.dm for Topic() +/mob/living/silicon/pai/canUseTopic(atom/movable/movable, be_close = FALSE, no_dexterity = FALSE, no_tk = FALSE) + // Resting is just an aesthetic feature for them. + return ..(movable, be_close, no_dexterity, no_tk) + +/mob/living/silicon/pai/update_icon() + ..() + update_fullness_pai() + if(!people_eaten && !resting) + icon_state = "[chassis]" + else if(!people_eaten && resting) + icon_state = "[chassis]_rest" + else if(people_eaten && !resting) + icon_state = "[chassis]_full" + else if(people_eaten && resting) + icon_state = "[chassis]_rest_full" + +/// camera handling /mob/living/silicon/pai/check_eye(var/mob/user as mob) if (!src.current) return -1 @@ -166,26 +188,7 @@ . = ..() cameraFollow = null -// No binary for pAIs. -/mob/living/silicon/pai/binarycheck() - return 0 - -// Handle being picked up. -/mob/living/silicon/pai/get_scooped(var/mob/living/carbon/grabber, var/self_drop) - var/obj/item/holder/H = ..(grabber, self_drop) - if(!istype(H)) - return - - H.icon_state = "[chassis]" - grabber.update_inv_l_hand() - grabber.update_inv_r_hand() - return H - -// See software.dm for Topic() -/mob/living/silicon/pai/canUseTopic(atom/movable/movable, be_close = FALSE, no_dexterity = FALSE, no_tk = FALSE) - // Resting is just an aesthetic feature for them. - return ..(movable, be_close, no_dexterity, no_tk) - +// vore-related stuff /mob/living/silicon/pai/proc/update_fullness_pai() //Determines if they have something in their stomach. Copied and slightly modified. var/new_people_eaten = 0 for(var/belly in vore_organs) @@ -194,14 +197,3 @@ new_people_eaten += M.size_multiplier people_eaten = min(1, new_people_eaten) -/mob/living/silicon/pai/update_icon() - ..() - update_fullness_pai() - if(!people_eaten && !resting) - icon_state = "[chassis]" - else if(!people_eaten && resting) - icon_state = "[chassis]_rest" - else if(people_eaten && !resting) - icon_state = "[chassis]_full" - else if(people_eaten && resting) - icon_state = "[chassis]_rest_full" From e39292ba34b02fba4364de16bed55d7082410343 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Sat, 1 Jul 2023 16:15:40 +0100 Subject: [PATCH 06/18] var tidyup --- code/modules/mob/living/silicon/pai/pai.dm | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 01e5e63baf24..5ba04bd9a656 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -36,6 +36,7 @@ var/obj/item/paicard/card // The card we inhabit var/obj/item/radio/radio // Our primary radio var/obj/item/communicator/integrated/communicator // Our integrated communicator. + var/obj/item/pda/ai/pai/pda = null // Our integrated PDA var/chassis = "pai-repairbot" // A record of your chosen chassis. var/global/list/possible_chassis = list( @@ -66,7 +67,8 @@ var/master // Name of the one who commands us var/master_dna // DNA string for owner verification - // Keeping this separate from the laws var, it should be much more difficult to modify + + // Keeping this separate from the laws var, it should be much more difficult to modify var/pai_law0 = "Serve your master." var/pai_laws // String for additional operating instructions our master might give us @@ -78,27 +80,12 @@ var/screen // Which screen our main window displays var/subscreen // Which specific function of the main screen is being displayed - var/obj/item/pda/ai/pai/pda = null - - var/secHUD = 0 // Toggles whether the Security HUD is active or not - var/medHUD = 0 // Toggles whether the Medical HUD is active or not - - var/medical_cannotfind = 0 - var/datum/data/record/medicalActive1 // Datacore record declarations for record software - var/datum/data/record/medicalActive2 - - var/security_cannotfind = 0 - var/datum/data/record/securityActive1 // Could probably just combine all these into one - var/datum/data/record/securityActive2 - var/obj/machinery/door/hackdoor // The airlock being hacked var/hackprogress = 0 // Possible values: 0 - 1000, >= 1000 means the hack is complete and will be reset upon next check var/hack_aborted = 0 var/obj/item/integated_radio/signal/sradio // AI's signaller - var/translator_on = 0 // keeps track of the translator module - var/current_pda_messaging = null var/people_eaten = 0 From 6fd1be6821835dda08486197fc1baf68ad34c12a Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Sat, 1 Jul 2023 16:21:50 +0100 Subject: [PATCH 07/18] make us move (slightly) slower --- code/modules/mob/living/silicon/pai/mobility.dm | 3 +++ code/modules/mob/living/silicon/pai/pai.dm | 2 ++ 2 files changed, 5 insertions(+) diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm index cec9e2b69c48..546983625ff3 100644 --- a/code/modules/mob/living/silicon/pai/mobility.dm +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -87,6 +87,9 @@ grabber.update_inv_r_hand() return H +/mob/living/silicon/pai/movement_delay() + return ..() + speed + // this is a general check for if we can do things such as fold in/out or perform other special actions /mob/living/silicon/pai/proc/can_action() if(!CHECK_MOBILITY(src, MOBILITY_CAN_MOVE)) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 5ba04bd9a656..995f22caedfc 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -16,6 +16,8 @@ pass_flags = 1 mob_size = MOB_SMALL + var/speed = 1 // We move slightly slower than normal living things + catalogue_data = list(/datum/category_item/catalogue/fauna/silicon/pai) holder_type = /obj/item/holder/pai From 136753cebf93330cd8806738afa57c059dde1b21 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Sat, 1 Jul 2023 16:35:07 +0100 Subject: [PATCH 08/18] slight readability improvement --- code/modules/mob/living/silicon/pai/mobility.dm | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm index 546983625ff3..292842ed7534 100644 --- a/code/modules/mob/living/silicon/pai/mobility.dm +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -1,7 +1,8 @@ /mob/living/silicon/pai/restrained() if(istype(src.loc,/obj/item/paicard)) - return 0 + return FALSE ..() + //I'm not sure how much of this is necessary, but I would rather avoid issues. /mob/living/silicon/pai/proc/close_up() @@ -19,7 +20,7 @@ stop_pulling() //stop resting - resting = 0 + resting = FALSE // If we are being held, handle removing our holder from their inv. var/obj/item/holder/H = loc @@ -42,13 +43,13 @@ //I'm not sure how much of this is necessary, but I would rather avoid issues. if(istype(card.loc,/obj/item/hardsuit_module)) to_chat(src, "There is no room to unfold inside this hardsuit module. You're good and stuck.") - return 0 + return FALSE else if(istype(card.loc,/mob)) var/mob/holder = card.loc var/datum/belly/inside_belly = check_belly(card) if(inside_belly) to_chat(src, "There is no room to unfold in here. You're good and stuck.") - return 0 + return FALSE if(ishuman(holder)) var/mob/living/carbon/human/H = holder for(var/obj/item/organ/external/affecting in H.organs) @@ -87,6 +88,7 @@ grabber.update_inv_r_hand() return H +// handle movement speed /mob/living/silicon/pai/movement_delay() return ..() + speed From c2f24816c2a19bdffb8ea45ef24ae79febc737f0 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Sun, 2 Jul 2023 19:03:13 +0100 Subject: [PATCH 09/18] fix the dme and also space movement v1 --- citadel.dme | 4 +--- code/modules/mob/living/silicon/pai/mobility.dm | 6 ++++++ code/modules/mob/living/silicon/pai/pai.dm | 3 +++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/citadel.dme b/citadel.dme index b54396bdd9f8..7efdd77ad19e 100644 --- a/citadel.dme +++ b/citadel.dme @@ -3284,6 +3284,7 @@ #include "code\modules\mob\living\silicon\pai\defense.dm" #include "code\modules\mob\living\silicon\pai\examine.dm" #include "code\modules\mob\living\silicon\pai\life.dm" +#include "code\modules\mob\living\silicon\pai\mobility.dm" #include "code\modules\mob\living\silicon\pai\pai.dm" #include "code\modules\mob\living\silicon\pai\recruit.dm" #include "code\modules\mob\living\silicon\pai\savefile.dm" @@ -3295,11 +3296,8 @@ #include "code\modules\mob\living\silicon\pai\software_modules\crew_manifest.dm" #include "code\modules\mob\living\silicon\pai\software_modules\directives.dm" #include "code\modules\mob\living\silicon\pai\software_modules\door_jack.dm" -#include "code\modules\mob\living\silicon\pai\software_modules\huds.dm" -#include "code\modules\mob\living\silicon\pai\software_modules\med_records.dm" #include "code\modules\mob\living\silicon\pai\software_modules\messenger.dm" #include "code\modules\mob\living\silicon\pai\software_modules\radio_config.dm" -#include "code\modules\mob\living\silicon\pai\software_modules\sec_records.dm" #include "code\modules\mob\living\silicon\pai\software_modules\signaller.dm" #include "code\modules\mob\living\silicon\robot\analyzer.dm" #include "code\modules\mob\living\silicon\robot\component.dm" diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm index 292842ed7534..bd55b8a6b4f9 100644 --- a/code/modules/mob/living/silicon/pai/mobility.dm +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -104,3 +104,9 @@ return FALSE return TRUE + +// space movement (we get one ion burst every 3 seconds) +/mob/living/silicon/pai/Process_Spacemove(movement_dir = NONE) + if(world.time >= last_space_movement + 30) + return TRUE + return FALSE diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 995f22caedfc..0cdab337a16d 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -92,6 +92,9 @@ var/people_eaten = 0 + // space movement related + var/last_space_movement = 0 + /mob/living/silicon/pai/Initialize(mapload) . = ..() card = loc From e21e2601b1f14811e31bff32cf13d7c676dc00b8 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Sun, 2 Jul 2023 19:29:58 +0100 Subject: [PATCH 10/18] fix space movement oops --- code/modules/mob/living/silicon/pai/defense.dm | 17 ----------------- code/modules/mob/living/silicon/pai/mobility.dm | 1 + 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/code/modules/mob/living/silicon/pai/defense.dm b/code/modules/mob/living/silicon/pai/defense.dm index d79988aaa757..461e06175e11 100644 --- a/code/modules/mob/living/silicon/pai/defense.dm +++ b/code/modules/mob/living/silicon/pai/defense.dm @@ -36,23 +36,6 @@ visible_message("[user.name] boops [src] on the head.") close_up() -/obj/item/paicard/attack_ghost(mob/dead/observer/user) - if(pai) - to_chat(user, "This pAI is already in use!") - return - else - var/pai_name = sanitizeSafe(stripped_input(usr, "Enter a name for your pAI", "pAI Name", user.name, MAX_NAME_LEN)) - if(!pai_name) - to_chat(user, "Entered name is not valid.") - return - var/mob/living/silicon/pai/new_pai = new(src) - new_pai.name = user.name - new_pai.real_name = user.name - new_pai.key = user.key - setPersonality(new_pai) - looking_for_personality = 0 - if(new_pai.mind) update_antag_icons(new_pai.mind) - /mob/living/silicon/pai/emp_act(severity) // Silence for 2 minutes // 20% chance to kill diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm index bd55b8a6b4f9..7cad6c4be95d 100644 --- a/code/modules/mob/living/silicon/pai/mobility.dm +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -108,5 +108,6 @@ // space movement (we get one ion burst every 3 seconds) /mob/living/silicon/pai/Process_Spacemove(movement_dir = NONE) if(world.time >= last_space_movement + 30) + last_space_movement = world.time return TRUE return FALSE From 85a9ceb265258c284c4fed898fb1348d3d6f7f3d Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Sun, 2 Jul 2023 22:05:27 +0100 Subject: [PATCH 11/18] working space movement --- .../game/objects/effects/temporary_visuals/miscellaneous.dm | 6 ++++++ code/modules/mob/living/silicon/pai/mobility.dm | 2 ++ 2 files changed, 8 insertions(+) diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 63b4039b462f..e68a62c7298e 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -54,3 +54,9 @@ . = ..() pixel_x = rand(-12, 12) pixel_y = rand(-9, 0) + +// pAI space move +/obj/effect/temp_visual/pai_ion_burst + name = "ion burst" + icon_state = "ion_fade" + duration = 5 diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm index 7cad6c4be95d..9bdb2e5ba291 100644 --- a/code/modules/mob/living/silicon/pai/mobility.dm +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -109,5 +109,7 @@ /mob/living/silicon/pai/Process_Spacemove(movement_dir = NONE) if(world.time >= last_space_movement + 30) last_space_movement = world.time + // place an effect for the movement + new /obj/effect/temp_visual/pai_ion_burst(get_turf(src)) return TRUE return FALSE From 1dbdc1b2b40fcd571ce13f68ad34b2362b118742 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Sun, 2 Jul 2023 22:09:47 +0100 Subject: [PATCH 12/18] why is the cooldown between folding and unfolding ten seconds? make it two seconds --- code/modules/mob/living/silicon/pai/mobility.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm index 9bdb2e5ba291..496e1b9dccb4 100644 --- a/code/modules/mob/living/silicon/pai/mobility.dm +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -6,7 +6,7 @@ //I'm not sure how much of this is necessary, but I would rather avoid issues. /mob/living/silicon/pai/proc/close_up() - last_special = world.time + 100 + last_special = world.time + 20 if(src.loc == card) return @@ -38,7 +38,7 @@ remove_verb(src, /mob/living/silicon/pai/proc/pai_nom) /mob/living/silicon/pai/proc/open_up() - last_special = world.time + 100 + last_special = world.time + 20 //I'm not sure how much of this is necessary, but I would rather avoid issues. if(istype(card.loc,/obj/item/hardsuit_module)) From a0238c9230287a81d5e017364261e5624b5bf348 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Mon, 3 Jul 2023 12:48:29 +0100 Subject: [PATCH 13/18] emitter health instead of just outright dying to someone hitting you --- .../modules/mob/living/silicon/pai/defense.dm | 5 +++++ code/modules/mob/living/silicon/pai/life.dm | 19 ++++++++++++++++++- .../mob/living/silicon/pai/mobility.dm | 3 +++ code/modules/mob/living/silicon/pai/pai.dm | 10 ++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/silicon/pai/defense.dm b/code/modules/mob/living/silicon/pai/defense.dm index 461e06175e11..caaf8ebfc131 100644 --- a/code/modules/mob/living/silicon/pai/defense.dm +++ b/code/modules/mob/living/silicon/pai/defense.dm @@ -66,3 +66,8 @@ to_chat(src, "Pr1m3 d1r3c71v3 uPd473D.") if(3) to_chat(src, "You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all.") + +/mob/living/silicon/pai/is_emitter_dead() + if(last_emitter_death != 0) + return TRUE + return FALSE diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm index df972fecdd19..4b6ab3c8a5fe 100644 --- a/code/modules/mob/living/silicon/pai/life.dm +++ b/code/modules/mob/living/silicon/pai/life.dm @@ -28,9 +28,26 @@ if(health <= 0) death(null,"gives one shrill beep before falling lifeless.") + if(emitter_health <= 0) + if(last_emitter_death == 0) + last_emitter_death = world.time + visible_message("[src]'s holo-emitter fizzles out!") + close_up() + else if(last_emitter_death + 60 <= world.time && emitter_health > 0) + last_emitter_death = 0 + visible_message("[src]'s holo-emitter flickers back to life!") + + // heal more when "dead" to avoid being down for an incredibly long duration + if(last_emitter_death != 0) + heal_overall_damage(2 * emitter_health_regen * seconds) + else + heal_overall_damage(emitter_health_regen * seconds) + /mob/living/silicon/pai/update_health() if(status_flags & STATUS_GODMODE) health = 100 + emitter_health = emitter_max_health + last_emitter_death = 0 set_stat(CONSCIOUS) else - health = 100 - getBruteLoss() - getFireLoss() + emitter_health = max_emitter_health - (getBruteLoss() + getFireLoss()) diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm index 496e1b9dccb4..3fd8bde5ad0a 100644 --- a/code/modules/mob/living/silicon/pai/mobility.dm +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -103,6 +103,9 @@ if(world.time <= last_special) return FALSE + if(is_emitter_dead()) + return FALSE + return TRUE // space movement (we get one ion burst every 3 seconds) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 0cdab337a16d..e9c28af19137 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -12,6 +12,16 @@ icon = 'icons/mob/pai_vr.dmi' icon_state = "pai-repairbot" + // our normal health + health = 50 + maxHealth = 50 + + // our emitter max health, health, regen, and when we last went to 0 emitter health (0 means we are alive currently) + var/emitter_max_health = 50 + var/emitter_health = 50 + var/emitter_health_regen = 1 + var/last_emitter_death = 0 + emote_type = 2 // pAIs emotes are heard, not seen, so they can be seen through a container (eg. person) pass_flags = 1 mob_size = MOB_SMALL From ca218a1558e3dd01de5ff3c2e9c63f4222d2459c Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Mon, 3 Jul 2023 13:09:36 +0100 Subject: [PATCH 14/18] some fixes so it actually compiles for testing --- code/modules/mob/living/silicon/pai/defense.dm | 2 +- code/modules/mob/living/silicon/pai/life.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/silicon/pai/defense.dm b/code/modules/mob/living/silicon/pai/defense.dm index caaf8ebfc131..8b6d646f1d23 100644 --- a/code/modules/mob/living/silicon/pai/defense.dm +++ b/code/modules/mob/living/silicon/pai/defense.dm @@ -67,7 +67,7 @@ if(3) to_chat(src, "You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all.") -/mob/living/silicon/pai/is_emitter_dead() +/mob/living/silicon/pai/proc/is_emitter_dead() if(last_emitter_death != 0) return TRUE return FALSE diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm index 4b6ab3c8a5fe..6e34e3ca826d 100644 --- a/code/modules/mob/living/silicon/pai/life.dm +++ b/code/modules/mob/living/silicon/pai/life.dm @@ -50,4 +50,4 @@ last_emitter_death = 0 set_stat(CONSCIOUS) else - emitter_health = max_emitter_health - (getBruteLoss() + getFireLoss()) + emitter_health = emitter_max_health - (getBruteLoss() + getFireLoss()) From cfdf278fd9cf0b1c622bcfd089a437e1ec5c1a7c Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Mon, 3 Jul 2023 15:03:45 +0100 Subject: [PATCH 15/18] ok i clearly cant read and did an oopsy here --- code/modules/mob/living/silicon/pai/mobility.dm | 7 +------ code/modules/mob/living/silicon/pai/verbs.dm | 10 ++++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm index 3fd8bde5ad0a..14de6e20367d 100644 --- a/code/modules/mob/living/silicon/pai/mobility.dm +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -93,13 +93,8 @@ return ..() + speed // this is a general check for if we can do things such as fold in/out or perform other special actions +// (basically if some condition should be checked upon the use of all mob abilities like closing/opening the shell it goes here instead) /mob/living/silicon/pai/proc/can_action() - if(!CHECK_MOBILITY(src, MOBILITY_CAN_MOVE)) - return FALSE - - if(src.loc == card) - return FALSE - if(world.time <= last_special) return FALSE diff --git a/code/modules/mob/living/silicon/pai/verbs.dm b/code/modules/mob/living/silicon/pai/verbs.dm index 94c7cafff6ec..2c214ff9ea86 100644 --- a/code/modules/mob/living/silicon/pai/verbs.dm +++ b/code/modules/mob/living/silicon/pai/verbs.dm @@ -3,8 +3,12 @@ set name = "Unfold Chassis" // see pai/mobility.dm + // we don't check mobility here because while folded up, you can't move if(!can_action()) return + // to fold out we need to be in the card + if(src.loc != card) + return open_up() @@ -12,8 +16,14 @@ set category = "pAI Commands" set name = "Collapse Chassis" + // we check mobility here to stop people folding up if they currently cannot move + if(!CHECK_MOBILITY(src, MOBILITY_CAN_MOVE)) + return if(!can_action()) return + // to fold up we need to not be in the card already + if(src.loc == card) + return close_up() From af47b50798c906ce1160148152dd0874c5daba28 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Mon, 3 Jul 2023 16:36:43 +0100 Subject: [PATCH 16/18] actual shitcode --- code/modules/mob/living/silicon/pai/defense.dm | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/code/modules/mob/living/silicon/pai/defense.dm b/code/modules/mob/living/silicon/pai/defense.dm index 8b6d646f1d23..7a1cfd6027a3 100644 --- a/code/modules/mob/living/silicon/pai/defense.dm +++ b/code/modules/mob/living/silicon/pai/defense.dm @@ -1,15 +1,3 @@ -//Overriding this will stop a number of headaches down the track. -/mob/living/silicon/pai/attackby(obj/item/W as obj, mob/user as mob) - if(W.damage_force) - visible_message("[user.name] attacks [src] with [W]!") - src.adjustBruteLoss(W.damage_force) - src.update_health() - else - visible_message("[user.name] bonks [src] harmlessly with [W].") - spawn(1) - if(stat != 2) close_up() - return - /mob/living/silicon/pai/attackby(obj/item/W as obj, mob/user as mob) var/obj/item/card/id/ID = W.GetID() if(ID) @@ -28,6 +16,8 @@ else if(istype(W, /obj/item/card/id) && idaccessible == 0) to_chat(user, "[src] is not accepting access modifcations at this time.") return + else + . = ..() /mob/living/silicon/pai/attack_hand(mob/user, list/params) if(user.a_intent == INTENT_HELP) From 55f7c704edbbe00efb7dd192b6c1948302acbe62 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Mon, 3 Jul 2023 18:17:39 +0100 Subject: [PATCH 17/18] i hate mob code --- code/modules/mob/living/silicon/pai/defense.dm | 7 ------- code/modules/mob/living/silicon/pai/life.dm | 7 +++++-- code/modules/mob/living/silicon/pai/mobility.dm | 13 +++++++------ 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/code/modules/mob/living/silicon/pai/defense.dm b/code/modules/mob/living/silicon/pai/defense.dm index 7a1cfd6027a3..cb29a48f0c3a 100644 --- a/code/modules/mob/living/silicon/pai/defense.dm +++ b/code/modules/mob/living/silicon/pai/defense.dm @@ -19,13 +19,6 @@ else . = ..() -/mob/living/silicon/pai/attack_hand(mob/user, list/params) - if(user.a_intent == INTENT_HELP) - visible_message("[user.name] pats [src].") - else - visible_message("[user.name] boops [src] on the head.") - close_up() - /mob/living/silicon/pai/emp_act(severity) // Silence for 2 minutes // 20% chance to kill diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm index 6e34e3ca826d..9091fda76a76 100644 --- a/code/modules/mob/living/silicon/pai/life.dm +++ b/code/modules/mob/living/silicon/pai/life.dm @@ -28,6 +28,7 @@ if(health <= 0) death(null,"gives one shrill beep before falling lifeless.") +/mob/living/silicon/pai/process() if(emitter_health <= 0) if(last_emitter_death == 0) last_emitter_death = world.time @@ -39,9 +40,11 @@ // heal more when "dead" to avoid being down for an incredibly long duration if(last_emitter_death != 0) - heal_overall_damage(2 * emitter_health_regen * seconds) + heal_overall_damage(2 * emitter_health_regen) else - heal_overall_damage(emitter_health_regen * seconds) + heal_overall_damage(emitter_health_regen) + + return ..() /mob/living/silicon/pai/update_health() if(status_flags & STATUS_GODMODE) diff --git a/code/modules/mob/living/silicon/pai/mobility.dm b/code/modules/mob/living/silicon/pai/mobility.dm index 14de6e20367d..5a026c9b307f 100644 --- a/code/modules/mob/living/silicon/pai/mobility.dm +++ b/code/modules/mob/living/silicon/pai/mobility.dm @@ -105,9 +105,10 @@ // space movement (we get one ion burst every 3 seconds) /mob/living/silicon/pai/Process_Spacemove(movement_dir = NONE) - if(world.time >= last_space_movement + 30) - last_space_movement = world.time - // place an effect for the movement - new /obj/effect/temp_visual/pai_ion_burst(get_turf(src)) - return TRUE - return FALSE + . = ..() + if(!.) + if(world.time >= last_space_movement + 30) + last_space_movement = world.time + // place an effect for the movement + new /obj/effect/temp_visual/pai_ion_burst(get_turf(src)) + return TRUE From 612964e6d24f5b4c97e91013595336b995eaa766 Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Mon, 3 Jul 2023 18:44:04 +0100 Subject: [PATCH 18/18] split up our life stuff to update health as it makes more sense --- code/modules/mob/living/silicon/pai/life.dm | 26 ++++++++++----------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm index 9091fda76a76..4a7cfee3346a 100644 --- a/code/modules/mob/living/silicon/pai/life.dm +++ b/code/modules/mob/living/silicon/pai/life.dm @@ -25,26 +25,18 @@ handle_statuses() - if(health <= 0) - death(null,"gives one shrill beep before falling lifeless.") - -/mob/living/silicon/pai/process() - if(emitter_health <= 0) - if(last_emitter_death == 0) - last_emitter_death = world.time - visible_message("[src]'s holo-emitter fizzles out!") - close_up() - else if(last_emitter_death + 60 <= world.time && emitter_health > 0) - last_emitter_death = 0 - visible_message("[src]'s holo-emitter flickers back to life!") - // heal more when "dead" to avoid being down for an incredibly long duration if(last_emitter_death != 0) heal_overall_damage(2 * emitter_health_regen) + // after 6 seconds we can come back to life assuming our health is not negative + if(last_emitter_death + 60 <= world.time && emitter_health > 0) + last_emitter_death = 0 + visible_message("[src]'s holo-emitter flickers back to life!") else heal_overall_damage(emitter_health_regen) - return ..() + if(health <= 0) + death(null,"gives one shrill beep before falling lifeless.") /mob/living/silicon/pai/update_health() if(status_flags & STATUS_GODMODE) @@ -54,3 +46,9 @@ set_stat(CONSCIOUS) else emitter_health = emitter_max_health - (getBruteLoss() + getFireLoss()) + if(emitter_health <= 0) + if(last_emitter_death == 0) + last_emitter_death = world.time + visible_message("[src]'s holo-emitter fizzles out!") + close_up() +