diff --git a/baystation12.dme b/baystation12.dme index 90c6c726d26..b1985b77737 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1357,6 +1357,7 @@ #include "code\modules\mob\living\silicon\robot\robot_items.dm" #include "code\modules\mob\living\silicon\robot\robot_modules.dm" #include "code\modules\mob\living\silicon\robot\robot_movement.dm" +#include "code\modules\mob\living\silicon\robot\syndicate.dm" #include "code\modules\mob\living\silicon\robot\drone\drone.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_abilities.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_console.dm" diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm index 7690e73e09b..9ffc08ca92f 100644 --- a/code/_helpers/global_lists.dm +++ b/code/_helpers/global_lists.dm @@ -64,6 +64,8 @@ var/global/list/rune_list = new() var/global/list/escape_list = list() var/global/list/endgame_exits = list() var/global/list/endgame_safespawns = list() + +var/global/list/syndicate_access = list(access_maint_tunnels, access_syndicate, access_external_airlocks) ////////////////////////// /////Initial Building///// ////////////////////////// diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm index a0f1f9c7f1c..3c247d6c7f9 100644 --- a/code/datums/wires/airlock.dm +++ b/code/datums/wires/airlock.dm @@ -161,7 +161,7 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048 if(A.emagged) return if(!A.requiresID() || A.check_access(null)) if(A.density) A.open() - else A.close() + else A.close() if(AIRLOCK_WIRE_SAFETY) A.safe = !A.safe if(!A.density) diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm index 69b7f8e9d0c..072dd88bee4 100644 --- a/code/game/antagonist/antagonist_create.dm +++ b/code/game/antagonist/antagonist_create.dm @@ -36,7 +36,7 @@ if(!W) return W.access |= default_access W.assignment = "[assignment]" - W.set_owner_info(player) + player.set_id_info(W) if(equip) player.equip_to_slot_or_del(W, slot_wear_id) return W diff --git a/code/game/antagonist/antagonist_update.dm b/code/game/antagonist/antagonist_update.dm index 0fd5fb2a93f..d4999f0183a 100644 --- a/code/game/antagonist/antagonist_update.dm +++ b/code/game/antagonist/antagonist_update.dm @@ -19,8 +19,7 @@ /datum/antagonist/proc/update_access(var/mob/living/player) for(var/obj/item/weapon/card/id/id in player.contents) - id.name = "[player.real_name]'s ID Card" - id.registered_name = player.real_name + player.set_id_info(id) /datum/antagonist/proc/update_all_icons() if(!antag_indicator) diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index fbc92f4bc49..8ace5314300 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -8,14 +8,10 @@ //check if it doesn't require any access at all if(src.check_access(null)) return 1 - if(istype(M, /mob/living/silicon)) - //AI can do whatever he wants - return 1 - else if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - //if they are holding or wearing a card that has access, that works - if(src.check_access(H.get_active_hand()) || src.check_access(H.wear_id)) - return 1 + + var/id = M.GetIdCard() + if(id) + return check_access(id) return 0 /obj/item/proc/GetAccess() @@ -191,18 +187,27 @@ "Emergency Response Team", "Emergency Response Team Leader") -proc/GetIdCard(var/mob/living/carbon/human/H) - if(H.wear_id) - var/id = H.wear_id.GetID() +/mob/proc/GetIdCard() + return null + +/mob/living/bot/GetIdCard() + return botcard + +/mob/living/carbon/human/GetIdCard() + if(wear_id) + var/id = wear_id.GetID() if(id) return id - if(H.get_active_hand()) - var/obj/item/I = H.get_active_hand() + if(get_active_hand()) + var/obj/item/I = get_active_hand() return I.GetID() +/mob/living/silicon/GetIdCard() + return idcard + proc/FindNameFromID(var/mob/living/carbon/human/H) ASSERT(istype(H)) - var/obj/item/weapon/card/id/C = GetIdCard(H) + var/obj/item/weapon/card/id/C = H.GetIdCard() if(C) return C.registered_name diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index ff994e8cd3b..f3757559823 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -528,7 +528,7 @@ var/global/datum/controller/occupations/job_master if(C) C.rank = rank C.assignment = title ? title : rank - C.set_owner_info(H) + H.set_id_info(C) //put the player's account number onto the ID if(H.mind && H.mind.initial_account) diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm index 65324f5555f..739583ede88 100644 --- a/code/game/machinery/camera/tracking.dm +++ b/code/game/machinery/camera/tracking.dm @@ -223,6 +223,9 @@ mob/living/proc/near_camera() /mob/living/proc/tracking_status() // Easy checks first. // Don't detect mobs on Centcom. Since the wizard den is on Centcomm, we only need this. + var/obj/item/weapon/card/id/id = GetIdCard() + if(id && id.prevent_tracking()) + return TRACKING_TERMINATE if(InvalidPlayerTurf(get_turf(src))) return TRACKING_TERMINATE if(invisibility >= INVISIBILITY_LEVEL_ONE) //cloaked @@ -240,14 +243,8 @@ mob/living/proc/near_camera() if(. == TRACKING_NO_COVERAGE) return camera && camera.can_use() ? TRACKING_POSSIBLE : TRACKING_NO_COVERAGE -/mob/living/silicon/robot/syndicate/tracking_status() - return TRACKING_TERMINATE - /mob/living/carbon/human/tracking_status() //Cameras can't track people wearing an agent card or a ninja hood. - var/obj/item/weapon/card/id/id = GetIdCard(src) - if(id && id.prevent_tracking()) - return TRACKING_TERMINATE if(istype(head, /obj/item/clothing/head/helmet/space/rig)) var/obj/item/clothing/head/helmet/space/rig/helmet = head if(helmet.prevent_track()) diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 8d85a63224c..4b8b9a9acf3 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -257,3 +257,7 @@ icon_state = "syndicam" network = list("NUKE") circuit = null + +/obj/machinery/computer/security/nuclear/New() + ..() + req_access = list(150) diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index d8f13f57b77..b949e284b87 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -59,12 +59,10 @@ if(!istype(id_card)) return ..() - if(!scan && access_change_ids in id_card.access) - user.drop_item() + if(!scan && (access_change_ids in id_card.access) && user.unEquip(id_card)) id_card.loc = src scan = id_card else if(!modify) - user.drop_item() id_card.loc = src modify = id_card @@ -157,8 +155,7 @@ modify = null else var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) - usr.drop_item() + if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) I.loc = src modify = I diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm index 7258fc543be..ccbce91b619 100644 --- a/code/game/machinery/computer/guestpass.dm +++ b/code/game/machinery/computer/guestpass.dm @@ -62,13 +62,14 @@ /obj/machinery/computer/guestpass/attackby(obj/O, mob/user) if(istype(O, /obj/item/weapon/card/id)) - if(!giver) - user.drop_item() + if(!giver && user.unEquip(O)) O.loc = src giver = O updateUsrDialog() - else + else if(giver) user << "There is already ID card inside." + return + ..() /obj/machinery/computer/guestpass/attack_ai(var/mob/user as mob) return attack_hand(user) @@ -151,8 +152,7 @@ accesses.Cut() else var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) - usr.drop_item() + if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) I.loc = src giver = I updateUsrDialog() diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 30d7de6d6c0..15c504800a8 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -35,13 +35,13 @@ usr << "There is nothing to remove from the console." return -/obj/machinery/computer/med_data/attackby(obj/item/O as obj, user as mob) - if(istype(O, /obj/item/weapon/card/id) && !scan) - usr.drop_item() +/obj/machinery/computer/med_data/attackby(var/obj/item/O, var/mob/user) + if(istype(O, /obj/item/weapon/card/id) && !scan && user.unEquip(O)) O.loc = src scan = O - user << "You insert [O]." - ..() + user << "You insert \the [O]." + else + ..() /obj/machinery/computer/med_data/attack_ai(user as mob) return src.attack_hand(user) diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 090e02c9080..eba129df262 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -248,8 +248,7 @@ What a mess.*/ scan = null else var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) - usr.drop_item() + if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) I.loc = src scan = I diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm index fb2d4ef0959..fca6cf40242 100644 --- a/code/game/machinery/computer/skills.dm +++ b/code/game/machinery/computer/skills.dm @@ -24,13 +24,13 @@ var/sortBy = "name" var/order = 1 // -1 = Descending - 1 = Ascending -/obj/machinery/computer/skills/attackby(obj/item/O as obj, user as mob) - if(istype(O, /obj/item/weapon/card/id) && !scan) - usr.drop_item() +/obj/machinery/computer/skills/attackby(obj/item/O as obj, var/mob/user) + if(istype(O, /obj/item/weapon/card/id) && !scan && user.unEquip(O)) O.loc = src scan = O user << "You insert [O]." - ..() + else + ..() /obj/machinery/computer/skills/attack_ai(mob/user as mob) return attack_hand(user) @@ -185,8 +185,7 @@ What a mess.*/ scan = null else var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) - usr.drop_item() + if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) I.loc = src scan = I diff --git a/code/game/machinery/computer3/computers/medical.dm b/code/game/machinery/computer3/computers/medical.dm index f39dd54de8d..7cf89a3fce9 100644 --- a/code/game/machinery/computer3/computers/medical.dm +++ b/code/game/machinery/computer3/computers/medical.dm @@ -181,7 +181,7 @@ scan = null else var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) + if (istype(I, /obj/item/weapon/card/id) && usr.drop_item(I)) computer.cardslot.insert(I, 1) scan = I @@ -194,7 +194,7 @@ scan2 = null else var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) + if (istype(I, /obj/item/weapon/card/id) && usr.drop_item(I)) computer.cardslot.insert(I, 2) scan2 = I diff --git a/code/game/machinery/computer3/computers/security.dm b/code/game/machinery/computer3/computers/security.dm index a346c12facc..1ba0c08cf78 100644 --- a/code/game/machinery/computer3/computers/security.dm +++ b/code/game/machinery/computer3/computers/security.dm @@ -254,7 +254,7 @@ What a mess.*/ scan = null else var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) + if (istype(I, /obj/item/weapon/card/id) && usr.drop_item(I)) computer.cardslot.insert(I, 1) scan = I @@ -267,7 +267,7 @@ What a mess.*/ scan2 = null else var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) + if (istype(I, /obj/item/weapon/card/id) && usr.drop_item(I)) computer.cardslot.insert(I, 2) scan2 = I diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index a01dc224c3e..57c5dd95af9 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -1142,21 +1142,22 @@ var/global/list/obj/item/device/pda/PDAs = list() if(choice == 1) if (id) remove_id() + return 1 else var/obj/item/I = user.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) - user.drop_item() + if (istype(I, /obj/item/weapon/card/id) && user.unEquip(I)) I.loc = src id = I + return 1 else var/obj/item/weapon/card/I = user.get_active_hand() - if (istype(I, /obj/item/weapon/card/id) && I:registered_name) + if (istype(I, /obj/item/weapon/card/id) && I:registered_name && user.unEquip(I)) var/obj/old_id = id - user.drop_item() I.loc = src id = I user.put_in_hands(old_id) - return + return 1 + return 0 // access to status display signals /obj/item/device/pda/attackby(obj/item/C as obj, mob/user as mob) @@ -1184,9 +1185,9 @@ var/global/list/obj/item/device/pda/PDAs = list() else //Basic safety check. If either both objects are held by user or PDA is on ground and card is in hand. if(((src in user.contents) && (C in user.contents)) || (istype(loc, /turf) && in_range(src, user) && (C in user.contents)) ) - id_check(user, 2) - user << "You put the ID into \the [src]'s slot." - updateSelfDialog()//Update self dialog on success. + if(id_check(user, 2)) + user << "You put the ID into \the [src]'s slot." + updateSelfDialog()//Update self dialog on success. return //Return in case of failed check or when successful. updateSelfDialog()//For the non-input related code. else if(istype(C, /obj/item/device/paicard) && !src.pai) diff --git a/code/game/objects/items/devices/uplink_items.dm b/code/game/objects/items/devices/uplink_items.dm index f7f49042e58..282d47b6826 100644 --- a/code/game/objects/items/devices/uplink_items.dm +++ b/code/game/objects/items/devices/uplink_items.dm @@ -622,7 +622,7 @@ var/image/default_abstract_uplink_icon if(!user) return 0 - var/obj/item/weapon/card/id/I = GetIdCard(user) + var/obj/item/weapon/card/id/I = user.GetIdCard() var/datum/data/record/random_general_record var/datum/data/record/random_medical_record if(data_core.general.len) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 999303a91dd..1dc489d75eb 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -31,10 +31,10 @@ R.modtype = initial(R.modtype) R.hands.icon_state = initial(R.hands.icon_state) - R.choose_icon(1, R.set_module_sprites(list("Default" = "robot"))) - R.notify_ai(ROBOT_NOTIFICATION_MODULE_RESET, R.module.name) R.module.Reset(R) + qdel(R.module) + R.module = null R.updatename("Default") return 1 diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index ae6bcbdf0ca..dbac808c049 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -122,8 +122,9 @@ return 0 /obj/item/weapon/card/id/proc/show(mob/user as mob) - user << browse_rsc(front, "front.png") - user << browse_rsc(side, "side.png") + if(front && side) + user << browse_rsc(front, "front.png") + user << browse_rsc(side, "side.png") var/datum/browser/popup = new(user, "idcard", name, 600, 250) popup.set_content(dat()) popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) @@ -137,17 +138,21 @@ front = getFlatIcon(M, SOUTH, always_use_defdir = 1) side = getFlatIcon(M, WEST, always_use_defdir = 1) -/obj/item/weapon/card/id/proc/set_owner_info(var/mob/living/carbon/human/H) - if(!H || !H.dna) - return - age = H.age - blood_type = H.dna.b_type - dna_hash = H.dna.unique_enzymes - fingerprint_hash = md5(H.dna.uni_identity) - registered_name = H.real_name - sex = capitalize(H.gender) - set_id_photo(H) - update_name() +/mob/proc/set_id_info(var/obj/item/weapon/card/id/id_card) + id_card.age = 0 + id_card.registered_name = real_name + id_card.sex = capitalize(gender) + id_card.set_id_photo(src) + + if(dna) + id_card.blood_type = dna.b_type + id_card.dna_hash = dna.unique_enzymes + id_card.fingerprint_hash= md5(dna.uni_identity) + id_card.update_name() + +/mob/living/carbon/human/set_id_info(var/obj/item/weapon/card/id/id_card) + ..() + id_card.age = age /obj/item/weapon/card/id/proc/dat() var/dat = ("
| ") @@ -213,9 +218,20 @@ item_state = "gold_id" registered_name = "Captain" assignment = "Captain" - New() - access = get_all_station_access() - ..() +/obj/item/weapon/card/id/captains_spare/New() + access = get_all_station_access() + ..() + +/obj/item/weapon/card/id/synthetic + name = "\improper Synthetic ID" + desc = "Access module for NanoTrasen Synthetics" + icon_state = "id-robot" + item_state = "tdgreen" + assignment = "Synthetic" + +/obj/item/weapon/card/id/synthetic/New() + access = get_all_station_access() + ..() /obj/item/weapon/card/id/centcom name = "\improper CentCom. ID" diff --git a/code/game/objects/items/weapons/cards_ids_syndicate.dm b/code/game/objects/items/weapons/cards_ids_syndicate.dm index 2475c93534b..3496607ffa4 100644 --- a/code/game/objects/items/weapons/cards_ids_syndicate.dm +++ b/code/game/objects/items/weapons/cards_ids_syndicate.dm @@ -6,12 +6,11 @@ var/global/list/syndicate_ids = list() origin_tech = list(TECH_ILLEGAL = 3) var/electronic_warfare = 1 var/registered_user = null - var/list/initial_access = list(access_maint_tunnels, access_syndicate, access_external_airlocks) /obj/item/weapon/card/id/syndicate/New(mob/user as mob) syndicate_ids += src ..() - access = initial_access.Copy() + access = syndicate_access.Copy() /obj/item/weapon/card/id/syndicate/Destroy() syndicate_ids -= src @@ -39,8 +38,8 @@ var/global/list/syndicate_ids = list() /obj/item/weapon/card/id/syndicate/attack_self(mob/user as mob) if(!registered_user) registered_user = user - set_owner_info(user) - user << "The microscanner marks you as its owner, preventing others some accessing its internals." + user.set_id_info(src) + user << "The microscanner marks you as its owner, preventing others from accessing its internals." if(registered_user == user) switch(alert("Would you like edit the ID, or show it?","Show or Edit?", "Edit","Show")) if("Edit") @@ -163,7 +162,7 @@ var/global/list/syndicate_ids = list() if("Factory Reset") if(alert("This will factory reset the card, including access and owner. Continue?", "Factory Reset", "No", "Yes") == "Yes" && CanUseTopic(user, state)) age = initial(age) - access = initial_access.Copy() + access = syndicate_access.Copy() assignment = initial(assignment) blood_type = initial(blood_type) dna_hash = initial(dna_hash) diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index 131347ac29a..c1022c55d0f 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -224,6 +224,9 @@ //Set the stop_messages to stop it from printing messages /obj/item/weapon/storage/proc/can_be_inserted(obj/item/W as obj, stop_messages = 0) if(!istype(W)) return //Not an item + + if(!usr.canUnEquip(W)) + return 0 if(src.loc == W) return 0 //Means the item is already in the storage item diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index d856be051c6..a87342f87f6 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -33,9 +33,20 @@ CouldNotUseTopic(usr) return 1 +/obj/CanUseTopic(var/mob/user, var/datum/topic_state/state) + if(user.CanUseObjTopic(src)) + return ..() + user << "\icon[src]Access Denied!" + return STATUS_CLOSE + +/mob/living/silicon/CanUseObjTopic(var/obj/O) + return O.allowed(src) + +/mob/proc/CanUseObjTopic() + /obj/proc/CouldUseTopic(var/mob/user) var/atom/host = nano_host() - host.add_fingerprint(user) + host.add_hiddenprint(user) /obj/proc/CouldNotUseTopic(var/mob/user) // Nada diff --git a/code/global.dm b/code/global.dm index 044295d8e3d..49484df37d6 100644 --- a/code/global.dm +++ b/code/global.dm @@ -182,4 +182,4 @@ var/max_explosion_range = 14 // Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it. var/global/obj/item/device/radio/intercom/global_announcer = new(null) -var/list/station_departments = list("Command", "Medical", "Engineering", "Science", "Security", "Cargo", "Civilian") \ No newline at end of file +var/list/station_departments = list("Command", "Medical", "Engineering", "Science", "Security", "Cargo", "Civilian") diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index 6cd91f07ef4..09fd236be0d 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -74,7 +74,7 @@ W.access = list() if(corpseidjob) W.assignment = corpseidjob - W.set_owner_info(M) + M.set_id_info(W) M.equip_to_slot_or_del(W, slot_wear_id) qdel(src) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 1115826be80..a23cc18aef6 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -216,11 +216,9 @@ var/list/slot_equipment_priority = list( \ update_inv_wear_mask(0) return -//This differs from remove_from_mob() in that it checks if the item can be unequipped first. -/mob/proc/unEquip(obj/item/I, force = 0) //Force overrides NODROP for things like wizarditis and admin undress. +/mob/proc/canUnEquip(obj/item/I) if(!I) //If there's nothing to drop, the drop is automatically successful. return 1 - var/slot for(var/s in slot_back to slot_tie) //kind of worries me if(get_equipped_item(s) == I) @@ -230,6 +228,12 @@ var/list/slot_equipment_priority = list( \ if(slot && !I.mob_can_unequip(src, slot)) return 0 + return 1 + +//This differs from remove_from_mob() in that it checks if the item can be unequipped first. +/mob/proc/unEquip(obj/item/I, force = 0) //Force overrides NODROP for things like wizarditis and admin undress. + if(!force && canUnEquip(I)) + return drop_from_inventory(I) return 1 diff --git a/code/modules/mob/living/silicon/robot/login.dm b/code/modules/mob/living/silicon/robot/login.dm index eac71acfcdd..9d9117b9330 100644 --- a/code/modules/mob/living/silicon/robot/login.dm +++ b/code/modules/mob/living/silicon/robot/login.dm @@ -5,4 +5,6 @@ winset(src, null, "mainwindow.macro=borgmacro hotkey_toggle.is-checked=false input.focus=true input.background-color=#D3B5B5") - return \ No newline at end of file + // Forces synths to select an icon relevant to their module + if(!icon_selected) + choose_icon(icon_selection_tries, module_sprites) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 493ae9f971f..7ca869ea26a 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -24,8 +24,10 @@ //Icon stuff - var/icontype //Persistent icontype tracking allows for cleaner icon updates - var/module_sprites[0] //Used to store the associations between sprite names and sprite index. + var/icontype //Persistent icontype tracking allows for cleaner icon updates + var/module_sprites[0] //Used to store the associations between sprite names and sprite index. + var/icon_selected = 1 //If icon selection has been completed yet + var/icon_selection_tries = 0//Remaining attempts to select icon before a selection is forced //Hud stuff @@ -89,21 +91,6 @@ /mob/living/silicon/robot/proc/robot_checklaws ) -/mob/living/silicon/robot/syndicate - lawupdate = 0 - scrambledcodes = 1 - icon_state = "securityrobot" - modtype = "Security" - lawchannel = "State" - -/mob/living/silicon/robot/syndicate/New() - if(!cell) - cell = new /obj/item/weapon/cell(src) - cell.maxcharge = 25000 - cell.charge = 25000 - - ..() - /mob/living/silicon/robot/New(loc,var/unfinished = 0) spark_system = new /datum/effect/effect/system/spark_spread() spark_system.set_up(5, 0, src) @@ -178,17 +165,6 @@ playsound(loc, 'sound/voice/liveagain.ogg', 75, 1) -/mob/living/silicon/robot/syndicate/init() - aiCamera = new/obj/item/device/camera/siliconcam/robot_camera(src) - - laws = new /datum/ai_laws/syndicate_override - new /obj/item/weapon/robot_module/syndicate(src) - - radio.keyslot = new /obj/item/device/encryptionkey/syndicate(radio) - radio.recalculateChannels() - - playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0) - /mob/living/silicon/robot/SetName(pickedName as text) custom_name = pickedName updatename() @@ -241,10 +217,15 @@ ..() /mob/living/silicon/robot/proc/set_module_sprites(var/list/new_sprites) - module_sprites = new_sprites + module_sprites = new_sprites.Copy() //Custom_sprite check and entry if (custom_sprite == 1) module_sprites["Custom"] = "[src.ckey]-[modtype]" + icontype = "Custom" + else + icontype = module_sprites[1] + icon_state = module_sprites[icontype] + updateicon() return module_sprites /mob/living/silicon/robot/proc/pick_module() @@ -255,7 +236,7 @@ if((crisis && security_level == SEC_LEVEL_RED) || crisis_override) //Leaving this in until it's balanced appropriately. src << "\red Crisis mode active. Combat module available." modules+="Combat" - modtype = input("Please, select a module!", "Robot", null, null) in modules + modtype = input("Please, select a module!", "Robot", null, null) as null|anything in modules if(module) return @@ -268,8 +249,6 @@ hands.icon_state = lowertext(modtype) feedback_inc("cyborg_[lowertext(modtype)]",1) updatename() - set_module_sprites(module.sprites) - choose_icon(module_sprites.len + 1, module_sprites) notify_ai(ROBOT_NOTIFICATION_NEW_MODULE, module.name) /mob/living/silicon/robot/proc/updatename(var/prefix as text) @@ -688,7 +667,7 @@ /mob/living/silicon/robot/updateicon() overlays.Cut() - if(stat == 0) + if(stat == CONSCIOUS) overlays += "eyes-[module_sprites[icontype]]" if(opened) @@ -916,38 +895,30 @@ return /mob/living/silicon/robot/proc/choose_icon(var/triesleft, var/list/module_sprites) - if(triesleft<1 || !module_sprites.len) - return - else - triesleft-- - - if (custom_sprite == 1) - icontype = "Custom" - triesleft = 0 - else if(module_sprites.len == 1) - icontype = module_sprites[1] - else - icontype = input("Select an icon! [triesleft ? "You have [triesleft] more chances." : "This is your last try."]", "Robot", null, null) in module_sprites - - if(icontype) - icon_state = module_sprites[icontype] - else + if(!module_sprites.len) src << "Something is badly wrong with the sprite selection. Harass a coder." - icon_state = module_sprites[1] return + icon_selected = 0 + src.icon_selection_tries = triesleft + if(module_sprites.len == 1 || !client) + if(!(icontype in module_sprites)) + icontype = module_sprites[1] + else + icontype = input("Select an icon! [triesleft ? "You have [triesleft] more chance\s." : "This is your last try."]", "Robot", icontype, null) in module_sprites + icon_state = module_sprites[icontype] updateicon() - if (triesleft >= 1) + if (module_sprites.len > 1 && triesleft >= 1 && client) + icon_selection_tries-- var/choice = input("Look at your icon - is this what you want?") in list("Yes","No") if(choice=="No") - choose_icon(triesleft, module_sprites) + choose_icon(icon_selection_tries, module_sprites) return - else - triesleft = 0 - return - else - src << "Your icon has been set. You now require a module reset to change it." + + icon_selected = 1 + icon_selection_tries = 0 + src << "Your icon has been set. You now require a module reset to change it." /mob/living/silicon/robot/proc/sensor_mode() //Medical/Security HUD controller for borgs set name = "Set Sensor Augmentation" diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm index ade9bf0f930..2d591f4c36b 100644 --- a/code/modules/mob/living/silicon/robot/robot_items.dm +++ b/code/modules/mob/living/silicon/robot/robot_items.dm @@ -105,13 +105,6 @@ desc = "A circuit grafted onto the bottom of an ID card. It is used to transmit access codes into other robot chassis, \ allowing you to lock and unlock other robots' panels." -/obj/item/weapon/card/id/robot/attack_self() //override so borgs can't flash their IDs. - return - -/obj/item/weapon/card/id/robot/read() - usr << "The ID card does not appear to have any writing on it." - return - //A harvest item for serviceborgs. /obj/item/weapon/robot_harvester name = "auto harvester" diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 6c453256c45..8e6f3207fb2 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -49,9 +49,13 @@ var/global/list/robot_modules = list( if(R.radio) R.radio.recalculateChannels() -/obj/item/weapon/robot_module/proc/Reset(var/mob/living/silicon/robot/R) - R.module = null + R.set_module_sprites(sprites) + R.choose_icon(R.module_sprites.len + 1, R.module_sprites) + for(var/obj/item/I in modules) + I.canremove = 0 + +/obj/item/weapon/robot_module/proc/Reset(var/mob/living/silicon/robot/R) remove_camera_networks(R) remove_languages(R) remove_subsystems(R) @@ -59,16 +63,17 @@ var/global/list/robot_modules = list( if(R.radio) R.radio.recalculateChannels() - - qdel(src) + R.choose_icon(0, R.set_module_sprites(list("Default" = "robot"))) /obj/item/weapon/robot_module/Destroy() - qdel(modules) - qdel(synths) + for(var/module in modules) + qdel(module) + for(var/synth in synths) + qdel(synths) + modules.Cut() + synths.Cut() qdel(emag) qdel(jetpack) - modules = null - synths = null emag = null jetpack = null return ..() @@ -144,7 +149,6 @@ var/global/list/robot_modules = list( ) /obj/item/weapon/robot_module/standard/New() - ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/melee/baton/loaded(src) src.modules += new /obj/item/weapon/extinguisher(src) @@ -152,7 +156,7 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/weapon/crowbar(src) src.modules += new /obj/item/device/healthanalyzer(src) src.emag = new /obj/item/weapon/melee/energy/sword(src) - return + ..() /obj/item/weapon/robot_module/medical name = "medical robot module" @@ -172,7 +176,6 @@ var/global/list/robot_modules = list( ) /obj/item/weapon/robot_module/medical/surgeon/New() - ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/device/healthanalyzer(src) src.modules += new /obj/item/weapon/reagent_containers/borghypo/surgeon(src) @@ -204,7 +207,7 @@ var/global/list/robot_modules = list( src.modules += N src.modules += B - return + ..() /obj/item/weapon/robot_module/medical/surgeon/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) if(src.emag) @@ -224,7 +227,6 @@ var/global/list/robot_modules = list( ) /obj/item/weapon/robot_module/medical/crisis/New() - ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/hud/med(src) src.modules += new /obj/item/device/healthanalyzer(src) @@ -258,7 +260,7 @@ var/global/list/robot_modules = list( src.modules += B src.modules += S - return + ..() /obj/item/weapon/robot_module/medical/crisis/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) @@ -294,7 +296,6 @@ var/global/list/robot_modules = list( no_slip = 1 /obj/item/weapon/robot_module/engineering/construction/New() - ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/meson(src) src.modules += new /obj/item/weapon/extinguisher(src) @@ -328,8 +329,9 @@ var/global/list/robot_modules = list( RG.synths = list(metal, glass) src.modules += RG -/obj/item/weapon/robot_module/engineering/general/New() ..() + +/obj/item/weapon/robot_module/engineering/general/New() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/meson(src) src.modules += new /obj/item/weapon/extinguisher(src) @@ -382,7 +384,7 @@ var/global/list/robot_modules = list( RG.synths = list(metal, glass) src.modules += RG - return + ..() /obj/item/weapon/robot_module/security name = "security robot module" @@ -403,7 +405,6 @@ var/global/list/robot_modules = list( ) /obj/item/weapon/robot_module/security/general/New() - ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/hud/sec(src) src.modules += new /obj/item/weapon/handcuffs/cyborg(src) @@ -411,7 +412,7 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/weapon/gun/energy/taser/mounted/cyborg(src) src.modules += new /obj/item/taperoll/police(src) src.emag = new /obj/item/weapon/gun/energy/laser/mounted(src) - return + ..() /obj/item/weapon/robot_module/security/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) var/obj/item/device/flash/F = locate() in src.modules @@ -442,7 +443,6 @@ var/global/list/robot_modules = list( ) /obj/item/weapon/robot_module/janitor/New() - ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/soap/nanotrasen(src) src.modules += new /obj/item/weapon/storage/bag/trash(src) @@ -451,7 +451,7 @@ var/global/list/robot_modules = list( src.emag = new /obj/item/weapon/reagent_containers/spray(src) src.emag.reagents.add_reagent("lube", 250) src.emag.name = "Lube spray" - return + ..() /obj/item/weapon/robot_module/janitor/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) var/obj/item/device/lightreplacer/LR = locate() in src.modules @@ -485,7 +485,6 @@ var/global/list/robot_modules = list( ) /obj/item/weapon/robot_module/clerical/butler/New() - ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/gripper/service(src) src.modules += new /obj/item/weapon/reagent_containers/glass/bucket(src) @@ -507,14 +506,14 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/weapon/tray/robotray(src) src.modules += new /obj/item/weapon/reagent_containers/borghypo/service(src) - src.emag = new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer(src) + src.emag = new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer(src) var/datum/reagents/R = new/datum/reagents(50) src.emag.reagents = R R.my_atom = src.emag R.add_reagent("beer2", 50) src.emag.name = "Mickey Finn's Special Brew" - return + ..() /obj/item/weapon/robot_module/clerical/general name = "clerical robot module" @@ -528,13 +527,13 @@ var/global/list/robot_modules = list( ) /obj/item/weapon/robot_module/clerical/general/New() - ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/pen/robopen(src) src.modules += new /obj/item/weapon/form_printer(src) src.modules += new /obj/item/weapon/gripper/paperwork(src) src.modules += new /obj/item/weapon/hand_labeler(src) src.emag = new /obj/item/weapon/stamp/denied(src) + ..() /obj/item/weapon/robot_module/general/butler/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) var/obj/item/weapon/reagent_containers/food/condiment/enzyme/E = locate() in src.modules @@ -556,7 +555,6 @@ var/global/list/robot_modules = list( supported_upgrades = list(/obj/item/borg/upgrade/jetpack) /obj/item/weapon/robot_module/miner/New() - ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/meson(src) src.modules += new /obj/item/weapon/wrench(src) @@ -568,7 +566,7 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/weapon/mining_scanner(src) src.modules += new /obj/item/weapon/crowbar(src) src.emag = new /obj/item/weapon/pickaxe/plasmacutter(src) - return + ..() /obj/item/weapon/robot_module/research name = "research module" @@ -579,7 +577,6 @@ var/global/list/robot_modules = list( ) /obj/item/weapon/robot_module/research/New() - ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/portable_destructive_analyzer(src) src.modules += new /obj/item/weapon/gripper/research(src) @@ -605,7 +602,7 @@ var/global/list/robot_modules = list( N.synths = list(nanite) src.modules += N - return + ..() /obj/item/weapon/robot_module/syndicate name = "illegal robot module" @@ -617,9 +614,12 @@ var/global/list/robot_modules = list( LANGUAGE_SKRELLIAN = 0, LANGUAGE_GUTTER = 1 ) + sprites = list( + "Dread" = "securityrobot", + ) + var/id /obj/item/weapon/robot_module/syndicate/New(var/mob/living/silicon/robot/R) - ..() loc = R src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/weapon/melee/energy/sword(src) @@ -628,14 +628,21 @@ var/global/list/robot_modules = list( var/jetpack = new/obj/item/weapon/tank/jetpack/carbondioxide(src) src.modules += jetpack R.internals = jetpack - return + + id = R.idcard + src.modules += id + ..() + +/obj/item/weapon/robot_module/syndicate/Destroy() + src.modules -= id + id = null + return ..() /obj/item/weapon/robot_module/security/combat name = "combat robot module" sprites = list("Combat Android" = "droid-combat") /obj/item/weapon/robot_module/combat/New() - ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/thermal(src) src.modules += new /obj/item/weapon/gun/energy/laser/mounted(src) @@ -643,7 +650,7 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/borg/combat/shield(src) src.modules += new /obj/item/borg/combat/mobility(src) src.emag = new /obj/item/weapon/gun/energy/lasercannon/mounted(src) - return + ..() /obj/item/weapon/robot_module/drone name = "drone module" @@ -651,7 +658,6 @@ var/global/list/robot_modules = list( networks = list(NETWORK_ENGINEERING) /obj/item/weapon/robot_module/drone/New() - ..() src.modules += new /obj/item/weapon/weldingtool(src) src.modules += new /obj/item/weapon/screwdriver(src) src.modules += new /obj/item/weapon/wrench(src) @@ -718,14 +724,16 @@ var/global/list/robot_modules = list( P.synths = list(plastic) src.modules += P + ..() + /obj/item/weapon/robot_module/drone/construction name = "construction drone module" channels = list("Engineering" = 1) languages = list() /obj/item/weapon/robot_module/drone/construction/New() - ..() src.modules += new /obj/item/weapon/rcd/borg(src) + ..() /obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) var/obj/item/device/lightreplacer/LR = locate() in src.modules diff --git a/code/modules/mob/living/silicon/robot/syndicate.dm b/code/modules/mob/living/silicon/robot/syndicate.dm new file mode 100644 index 00000000000..af46cd6fcf5 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/syndicate.dm @@ -0,0 +1,28 @@ +/mob/living/silicon/robot/syndicate + lawupdate = 0 + scrambledcodes = 1 + icon_state = "securityrobot" + modtype = "Security" + lawchannel = "State" + idcard_type = /obj/item/weapon/card/id/syndicate + +/mob/living/silicon/robot/syndicate/New() + if(!cell) + cell = new /obj/item/weapon/cell(src) + cell.maxcharge = 25000 + cell.charge = 25000 + + ..() + +/mob/living/silicon/robot/syndicate/init() + aiCamera = new/obj/item/device/camera/siliconcam/robot_camera(src) + + laws = new /datum/ai_laws/syndicate_override + overlays.Cut() + init_id() + new /obj/item/weapon/robot_module/syndicate(src) + + radio.keyslot = new /obj/item/device/encryptionkey/syndicate(radio) + radio.recalculateChannels() + + playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index c8b0f3d0e05..25b321a9a7e 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -23,6 +23,10 @@ var/next_alarm_notice var/list/datum/alarm/queued_alarms = new() + var/list/access_rights + var/obj/item/weapon/card/id/idcard + var/idcard_type = /obj/item/weapon/card/id/synthetic + #define SEC_HUD 1 //Security HUD mode #define MED_HUD 2 //Medical HUD mode @@ -30,6 +34,7 @@ silicon_mob_list |= src ..() add_language("Galactic Common") + init_id() init_subsystems() /mob/living/silicon/Destroy() @@ -38,6 +43,12 @@ AH.unregister(src) ..() +/mob/living/silicon/proc/init_id() + if(idcard) + return + idcard = new idcard_type(src) + set_id_info(idcard) + /mob/living/silicon/proc/SetName(pickedName as text) real_name = pickedName name = real_name diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index f2e9e958681..e87e486ff37 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -632,7 +632,7 @@ proc/is_blind(A) return SAFE_PERP //Agent cards lower threatlevel. - var/obj/item/weapon/card/id/id = GetIdCard(src) + var/obj/item/weapon/card/id/id = GetIdCard() if(id && istype(id, /obj/item/weapon/card/id/syndicate)) threatcount -= 2 // A proper CentCom id is hard currency. diff --git a/code/modules/nano/interaction/base.dm b/code/modules/nano/interaction/base.dm index cf5424bdc00..ccd9f3740b3 100644 --- a/code/modules/nano/interaction/base.dm +++ b/code/modules/nano/interaction/base.dm @@ -14,7 +14,7 @@ /mob/proc/shared_nano_interaction() if (src.stat || !client) return STATUS_CLOSE // no updates, close the interface - else if (restrained() || lying || stat || stunned || weakened) + else if (incapacitated()) return STATUS_UPDATE // update only (orange visibility) return STATUS_INTERACTIVE diff --git a/code/modules/nano/interaction/default.dm b/code/modules/nano/interaction/default.dm index 79c08227d5a..216f40b9483 100644 --- a/code/modules/nano/interaction/default.dm +++ b/code/modules/nano/interaction/default.dm @@ -30,21 +30,6 @@ return STATUS_INTERACTIVE // interactive (green visibility) return STATUS_DISABLED // no updates, completely disabled (red visibility) -/mob/living/silicon/robot/syndicate/default_can_use_topic(var/src_object) - . = ..() - if(. != STATUS_INTERACTIVE) - return - - if(z in config.admin_levels) // Syndicate borgs can interact with everything on the admin level - return STATUS_INTERACTIVE - if(istype(get_area(src), /area/syndicate_station)) // If elsewhere, they can interact with everything on the syndicate shuttle - return STATUS_INTERACTIVE - if(istype(src_object, /obj/machinery)) // Otherwise they can only interact with emagged machinery - var/obj/machinery/Machine = src_object - if(Machine.emagged) - return STATUS_INTERACTIVE - return STATUS_UPDATE - /mob/living/silicon/ai/default_can_use_topic(var/src_object) . = shared_nano_interaction() if(. != STATUS_INTERACTIVE) diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm index a289d68623e..c0535f48659 100644 --- a/code/modules/paperwork/faxmachine.dm +++ b/code/modules/paperwork/faxmachine.dm @@ -112,8 +112,7 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins scan = null else var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) - usr.drop_item() + if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) I.loc = src scan = I authenticated = 0 diff --git a/html/changelogs/PsiOmegaDelta-SpoonRevolt.yml b/html/changelogs/PsiOmegaDelta-SpoonRevolt.yml index c26ad21ff53..1c47ad71b23 100644 --- a/html/changelogs/PsiOmegaDelta-SpoonRevolt.yml +++ b/html/changelogs/PsiOmegaDelta-SpoonRevolt.yml @@ -1,4 +1,4 @@ author: PsiOmegaDelta delete-after: True changes: - - rscdel: "The Dinnerware vending machine now offer both utensil knives and spoons without first having to hack them." + - rscadd: "The Dinnerware vending machine now offer both utensil knives and spoons without first having to hack them." diff --git a/html/changelogs/PsiOmegaDelta-SynthAccess.yml b/html/changelogs/PsiOmegaDelta-SynthAccess.yml new file mode 100644 index 00000000000..689e8697630 --- /dev/null +++ b/html/changelogs/PsiOmegaDelta-SynthAccess.yml @@ -0,0 +1,7 @@ +author: PsiOmegaDelta +delete-after: True +changes: + - rscadd: "Synths now have id cards with access levels which is checked when operating most station equipment." + - rscadd: "Station synthetics still have full station access but can no longer interact with syndicate equipment, and syndicate borgs now start with only syndicate access." + - rscadd: "Syndicate borgs can copy the access from other cards by utilizing their own id card module, similar to how syndicate ids work." + diff --git a/html/changelogs/PsiOmegaDelta-Uplinkery.yml b/html/changelogs/PsiOmegaDelta-Uplinkery.yml index c8b8f5e31c0..8ee40286e3b 100644 --- a/html/changelogs/PsiOmegaDelta-Uplinkery.yml +++ b/html/changelogs/PsiOmegaDelta-Uplinkery.yml @@ -2,7 +2,8 @@ author: PsiOmegaDelta delete-after: true changes: - rscadd: "When examined up close id cards now offer a more detailed view." - - rscadd: "Agent ids now offer much greater customization, such as being able to toggle termination of AI tracking." + - rscadd: "Agent ids now offer much greater customization, allowing changing name, age, DNA, toggling of AI tracking termination (using the electronic warfware option), and more." + - rscadd: "As AI tracking can now be enabled/disabled at will AI players should not feel the need to hesitate before informing relevant crew members when camera tracking is explicitly terminated." - rscadd: "Uplink menu now more organized and with new categories." - rscadd: "Now possible to cause falsified ion storm announcements." - rscadd: "Now possible to cause falsified radiation storm announcements, with expected maintenance access changes." |