From 034cf8ef69cbc610914863b9dd014f3c9012c5a3 Mon Sep 17 00:00:00 2001 From: Markolie Date: Sun, 9 Aug 2015 23:42:55 +0200 Subject: [PATCH 1/8] ID card/agent ID rework --- _maps/map_files/cyberiad/z2.dmm | 2 +- code/__HELPERS/text.dm | 2 +- code/game/jobs/access.dm | 8 +- code/game/jobs/job/engineering.dm | 5 +- code/game/jobs/job/medical.dm | 8 +- code/game/jobs/job/science.dm | 3 + code/game/jobs/job/security.dm | 8 +- code/game/jobs/job/supervisor.dm | 6 +- code/game/jobs/job/support.dm | 5 + code/game/machinery/guestpass.dm | 8 - code/game/objects/items/weapons/cards_ids.dm | 432 ++++++++++++------ code/game/response_team.dm | 8 +- code/modules/admin/verbs/debug.dm | 21 +- code/modules/admin/verbs/striketeam.dm | 2 +- .../admin/verbs/striketeam_syndicate.dm | 2 +- icons/obj/card.dmi | Bin 9661 -> 18896 bytes 16 files changed, 348 insertions(+), 172 deletions(-) diff --git a/_maps/map_files/cyberiad/z2.dmm b/_maps/map_files/cyberiad/z2.dmm index abe72f0c374..65eb347f54b 100644 --- a/_maps/map_files/cyberiad/z2.dmm +++ b/_maps/map_files/cyberiad/z2.dmm @@ -1654,7 +1654,7 @@ "FP" = (/obj/machinery/computer/rdservercontrol{badmin = 1; name = "Master R&D Server Controller"},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) "FQ" = (/obj/machinery/r_n_d/server/centcom,/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) "FR" = (/obj/structure/table,/obj/item/weapon/card/id/silver{pixel_x = -3; pixel_y = -3},/obj/item/weapon/card/id/captains_spare,/obj/item/weapon/card/id/fluff/lifetime{pixel_x = 3; pixel_y = 3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) -"FS" = (/obj/structure/table,/obj/item/weapon/card/id/centcom,/obj/item/weapon/card/id{pixel_x = 3; pixel_y = 3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) +"FS" = (/obj/structure/table,/obj/item/weapon/card/id/centcom{pixel_x = -3; pixel_y = -3},/obj/item/weapon/card/id{pixel_x = 0; pixel_y = 0},/obj/item/weapon/card/id/admin{pixel_x = 3; pixel_y = 3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) "FT" = (/turf/unsimulated/floor{dir = 8; icon_state = "wood"},/turf/unsimulated/wall{dir = 2; icon = 'icons/turf/shuttle.dmi'; icon_state = "window5"; name = "window"; opacity = 0; tag = "icon-window5"},/area/admin) "FU" = (/obj/structure/stool/bed/chair/comfy/black,/turf/unsimulated/floor{dir = 8; icon_state = "wood"},/area/admin) "FV" = (/obj/machinery/computer/card,/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index c6cd633398b..2b840e6759c 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -140,7 +140,7 @@ if(last_char_group == 1) t_out = copytext(t_out,1,length(t_out)) //removes the last character (in this case a space) - for(var/bad_name in list("space","floor","wall","r-wall","monkey","unknown","inactive ai")) //prevents these common metagamey names + for(var/bad_name in list("space","floor","wall","r-wall","monkey","unknown","inactive ai","plating")) //prevents these common metagamey names if(cmptext(t_out,bad_name)) return //(not case sensitive) return t_out diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index 22edeb3702c..168212d725c 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -252,7 +252,13 @@ /proc/get_all_syndicate_access() return list(access_syndicate, access_syndicate_leader, access_vox) - + +/proc/get_all_misc_access() + return list(access_salvage_captain) + +/proc/get_absolutely_all_accesses() + return (get_all_accesses() | get_all_centcom_access() | get_all_syndicate_access() | get_all_misc_access()) + /proc/get_region_accesses(var/code) switch(code) if(0) diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm index 2d8f789e2c9..de8ae87ae53 100644 --- a/code/game/jobs/job/engineering.dm +++ b/code/game/jobs/job/engineering.dm @@ -6,7 +6,7 @@ spawn_positions = 1 supervisors = "the captain" selection_color = "#ffeeaa" - idtype = /obj/item/weapon/card/id/silver + idtype = /obj/item/weapon/card/id/ce req_admin_notify = 1 access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva, @@ -49,6 +49,7 @@ spawn_positions = 5 supervisors = "the chief engineer" selection_color = "#fff5cc" + idtype = /obj/item/weapon/card/id/engineering access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics) minimal_access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction) alt_titles = list("Maintenance Technician","Engine Technician","Electrician") @@ -83,6 +84,7 @@ spawn_positions = 2 supervisors = "the chief engineer" selection_color = "#fff5cc" + idtype = /obj/item/weapon/card/id/engineering access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics) minimal_access = list(access_eva, access_atmospherics, access_maint_tunnels, access_external_airlocks, access_emergency_storage, access_construction) alt_titles = list("Atmospheric Technician") @@ -113,6 +115,7 @@ spawn_positions = 1 supervisors = "the chief engineer" selection_color = "#fff5cc" + idtype = /obj/item/weapon/card/id/engineering access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_mechanic, access_external_airlocks) minimal_access = list(access_maint_tunnels, access_emergency_storage, access_mechanic, access_external_airlocks) diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm index 0945ba7cad0..3c38eb19042 100644 --- a/code/game/jobs/job/medical.dm +++ b/code/game/jobs/job/medical.dm @@ -6,7 +6,7 @@ spawn_positions = 1 supervisors = "the captain" selection_color = "#ffddf0" - idtype = /obj/item/weapon/card/id/silver + idtype = /obj/item/weapon/card/id/cmo req_admin_notify = 1 access = list(access_medical, access_morgue, access_genetics, access_heads, access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce, @@ -46,6 +46,7 @@ spawn_positions = 3 supervisors = "the chief medical officer" selection_color = "#ffeef0" + idtype = /obj/item/weapon/card/id/medical access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_mineral_storeroom) minimal_access = list(access_medical, access_morgue, access_surgery, access_maint_tunnels) alt_titles = list("Surgeon","Nurse","Coroner") @@ -108,6 +109,7 @@ spawn_positions = 2 supervisors = "the chief medical officer" selection_color = "#ffeef0" + idtype = /obj/item/weapon/card/id/medical access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_mineral_storeroom) minimal_access = list(access_medical, access_chemistry, access_maint_tunnels, access_mineral_storeroom) alt_titles = list("Pharmacist","Pharmacologist") @@ -139,6 +141,7 @@ spawn_positions = 2 supervisors = "the chief medical officer and the research director" selection_color = "#ffeef0" + idtype = /obj/item/weapon/card/id/medical access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_research, access_mineral_storeroom) minimal_access = list(access_medical, access_morgue, access_genetics, access_research, access_maint_tunnels) minimal_player_age = 3 @@ -167,6 +170,7 @@ spawn_positions = 1 supervisors = "the chief medical officer" selection_color = "#ffeef0" + idtype = /obj/item/weapon/card/id/medical access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics) minimal_access = list(access_medical, access_virology, access_maint_tunnels) alt_titles = list("Pathologist","Microbiologist") @@ -199,6 +203,7 @@ spawn_positions = 1 supervisors = "the chief medical officer" selection_color = "#ffeef0" + idtype = /obj/item/weapon/card/id/medical access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_psychiatrist) minimal_access = list(access_medical, access_psychiatrist, access_maint_tunnels) alt_titles = list("Psychologist","Therapist") @@ -238,6 +243,7 @@ spawn_positions = 1 supervisors = "the chief medical officer" selection_color = "#ffeef0" + idtype = /obj/item/weapon/card/id/medical access = list(access_paramedic, access_medical, access_sec_doors, access_maint_tunnels, access_external_airlocks, access_morgue) minimal_access=list(access_paramedic, access_medical, access_sec_doors, access_maint_tunnels, access_external_airlocks, access_morgue) minimal_player_age = 3 diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm index f51ad1c838d..6c720ef04a3 100644 --- a/code/game/jobs/job/science.dm +++ b/code/game/jobs/job/science.dm @@ -8,6 +8,7 @@ selection_color = "#ffddff" idtype = /obj/item/weapon/card/id/silver req_admin_notify = 1 + idtype = /obj/item/weapon/card/id/rd access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue, access_tox_storage, access_tech_storage, access_teleporter, access_sec_doors, access_research, access_robotics, access_xenobiology, access_ai_upload, @@ -50,6 +51,7 @@ spawn_positions = 6 supervisors = "the research director" selection_color = "#ffeeff" + idtype = /obj/item/weapon/card/id/research access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_xenoarch, access_mineral_storeroom) minimal_access = list(access_tox, access_tox_storage, access_research, access_xenobiology, access_xenoarch, access_maint_tunnels, access_mineral_storeroom) alt_titles = list("Xenoarcheologist", "Anomalist", "Plasma Researcher", "Xenobiologist", "Chemical Researcher") @@ -85,6 +87,7 @@ spawn_positions = 2 supervisors = "the research director" selection_color = "#ffeeff" + idtype = /obj/item/weapon/card/id/research access = list(access_robotics, access_tox, access_tox_storage, access_tech_storage, access_morgue, access_research, access_mineral_storeroom) //As a job that handles so many corpses, it makes sense for them to have morgue access. minimal_access = list(access_robotics, access_tech_storage, access_morgue, access_research, access_maint_tunnels, access_mineral_storeroom) //As a job that handles so many corpses, it makes sense for them to have morgue access. alt_titles = list("Biomechanical Engineer","Mechatronic Engineer") diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm index d741bcb234b..2bf5b7d156c 100644 --- a/code/game/jobs/job/security.dm +++ b/code/game/jobs/job/security.dm @@ -6,7 +6,7 @@ spawn_positions = 1 supervisors = "the captain" selection_color = "#ffdddd" - idtype = /obj/item/weapon/card/id/silver + idtype = /obj/item/weapon/card/id/hos req_admin_notify = 1 access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_forensics_lockers, access_pilot, access_morgue, access_maint_tunnels, access_all_personal_lockers, @@ -58,6 +58,7 @@ spawn_positions = 1 supervisors = "the head of security" selection_color = "#ffeeee" + idtype = /obj/item/weapon/card/id/security access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_morgue, access_weapons) minimal_access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_weapons) minimal_player_age = 21 @@ -104,7 +105,7 @@ supervisors = "the head of security" selection_color = "#ffeeee" alt_titles = list("Forensic Technician") - + idtype = /obj/item/weapon/card/id/security access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court, access_weapons) minimal_access = list(access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court, access_weapons) alt_titles = list("Forensic Technician") @@ -162,6 +163,7 @@ spawn_positions = 5 supervisors = "the head of security" selection_color = "#ffeeee" + idtype = /obj/item/weapon/card/id/security access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_morgue, access_weapons) minimal_access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_weapons) minimal_player_age = 14 @@ -202,6 +204,7 @@ spawn_positions = 1 supervisors = "the head of security" selection_color = "#ffeeee" + idtype = /obj/item/weapon/card/id/security access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics) minimal_access = list(access_medical, access_morgue, access_surgery, access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels) @@ -239,6 +242,7 @@ spawn_positions = 1 supervisors = "the head of security" selection_color = "#ffeeee" + idtype = /obj/item/weapon/card/id/security access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_morgue, access_weapons, access_pilot, access_external_airlocks) minimal_access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_weapons, access_pilot, access_external_airlocks) minimal_player_age = 7 diff --git a/code/game/jobs/job/supervisor.dm b/code/game/jobs/job/supervisor.dm index 1f1c4735a31..645b4171405 100644 --- a/code/game/jobs/job/supervisor.dm +++ b/code/game/jobs/job/supervisor.dm @@ -102,7 +102,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) spawn_positions = 1 supervisors = "the command staff" selection_color = "#ddddff" - idtype = /obj/item/weapon/card/id + idtype = /obj/item/weapon/card/id/silver req_admin_notify = 1 minimal_player_age = 21 access = list(access_security, access_sec_doors, access_brig, access_court, access_forensics_lockers, @@ -148,7 +148,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) spawn_positions = 1 supervisors = "the nanotrasen representative" selection_color = "#ddddff" - idtype = /obj/item/weapon/card/id + idtype = /obj/item/weapon/card/id/silver req_admin_notify = 1 minimal_player_age = 21 access = list(access_security, access_sec_doors, access_brig, access_court, access_forensics_lockers, @@ -195,7 +195,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) spawn_positions = 1 supervisors = "the Nanotrasen Supreme Court" selection_color = "#ddddff" - idtype = /obj/item/weapon/card/id + idtype = /obj/item/weapon/card/id/silver req_admin_notify = 1 minimal_player_age = 30 access = list(access_security, access_sec_doors, access_brig, access_court, access_forensics_lockers, diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm index 3e55831efe3..87f83439980 100644 --- a/code/game/jobs/job/support.dm +++ b/code/game/jobs/job/support.dm @@ -112,6 +112,7 @@ spawn_positions = 1 supervisors = "the head of personnel" selection_color = "#dddddd" + idtype = /obj/item/weapon/card/id/supply access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mint, access_mining, access_mining_station, access_mineral_storeroom) minimal_access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mint, access_mining, access_mining_station, access_mineral_storeroom) @@ -144,6 +145,7 @@ spawn_positions = 2 supervisors = "the quartermaster" selection_color = "#dddddd" + idtype = /obj/item/weapon/card/id/supply access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mint, access_mining, access_mining_station, access_mineral_storeroom) minimal_access = list(access_maint_tunnels, access_cargo, access_cargo_bot, access_mailsorting, access_mineral_storeroom) @@ -174,6 +176,7 @@ spawn_positions = 3 supervisors = "the quartermaster" selection_color = "#dddddd" + idtype = /obj/item/weapon/card/id/supply access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mint, access_mining, access_mining_station, access_mineral_storeroom) minimal_access = list(access_mining, access_mint, access_mining_station, access_mailsorting, access_maint_tunnels, access_mineral_storeroom) alt_titles = list("Spelunker") @@ -214,6 +217,7 @@ spawn_positions = 1 supervisors = "the head of personnel" selection_color = "#dddddd" + idtype = /obj/item/weapon/card/id/clown access = list(access_clown, access_theatre, access_maint_tunnels) minimal_access = list(access_clown, access_theatre, access_maint_tunnels) @@ -253,6 +257,7 @@ spawn_positions = 1 supervisors = "the head of personnel" selection_color = "#dddddd" + idtype = /obj/item/weapon/card/id/mime access = list(access_mime, access_theatre, access_maint_tunnels) minimal_access = list(access_mime, access_theatre, access_maint_tunnels) diff --git a/code/game/machinery/guestpass.dm b/code/game/machinery/guestpass.dm index 623336050aa..3be065b3d02 100644 --- a/code/game/machinery/guestpass.dm +++ b/code/game/machinery/guestpass.dm @@ -22,18 +22,10 @@ usr << "This pass expires at [worldtime2text(expiration_time)]." else usr << "It expired at [worldtime2text(expiration_time)]." - -/obj/item/weapon/card/id/guest/read() - if (world.time > expiration_time) - usr << "This pass expired at [worldtime2text(expiration_time)]." - else - usr << "This pass expires at [worldtime2text(expiration_time)]." - usr << "It grants access to following areas:" for (var/A in temp_access) usr << "[get_access_desc(A)]." usr << "Issuing reason: [reason]." - return ///////////////////////////////////////////// //Guest pass terminal//////////////////////// diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index db8945d9063..ce340a26aa5 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -96,7 +96,7 @@ //alt titles are handled a bit weirdly in order to unobtrusively integrate into existing ID system var/assignment = null //can be alt title or the actual job var/rank = null //actual job - var/dorm = 0 // determines if this ID has claimed a dorm already + var/dorm = 0 // determines if this ID has claimed a dorm already var/datum/data/record/active1 = null var/sex @@ -105,58 +105,61 @@ var/icon/front var/icon/side var/dat - var/stamped=0 + var/stamped = 0 /obj/item/weapon/card/id/New() ..() spawn(30) - updatedat() + if(ishuman(loc)) + var/mob/living/carbon/human/H = loc + SetOwnerInfo(H) -/obj/item/weapon/card/id/proc/updatedat() - if(istype(loc, /mob/living/carbon/human)) - blood_type = loc:dna:b_type - dna_hash = loc:dna:unique_enzymes - fingerprint_hash = md5(loc:dna:uni_identity) - dat = ("
") - dat +=text("Name: []
", registered_name) - dat +=text("Sex: []
\n", sex) - dat +=text("Age: []
\n", age) - dat +=text("Rank: []
\n", assignment) - dat +=text("Fingerprint: []
\n", fingerprint_hash) - dat +=text("Blood Type: []
\n", blood_type) - dat +=text("DNA Hash: []

\n", dna_hash) - dat +="
Photo:
\ -
" - -/obj/item/weapon/card/id/examine() +/obj/item/weapon/card/id/examine(mob/user) set src in oview(1) if(in_range(usr, src)) show(usr) usr << desc else - usr << "It is too far away." + usr << "It is too far away." /obj/item/weapon/card/id/proc/show(mob/user as mob) - if(!front) - front = new(photo, dir = SOUTH) - if(!side) - side = new(photo, dir = WEST) - user << browse_rsc(front, "front.png") - user << browse_rsc(side, "side.png") var/datum/browser/popup = new(user, "idcard", name, 600, 400) popup.set_content(dat) - popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) popup.open() return /obj/item/weapon/card/id/attack_self(mob/user as mob) for(var/mob/O in viewers(user, null)) - O.show_message(text("[] shows you: \icon[] []. The assignment on the card: []", user, src, src.name, src.assignment), 1) + user.visible_message("[user] shows you: \icon[src] [src.name]. The assignment on the card: [src.assignment]",\ + "You flash your ID card: \icon[src] [src.name]. The assignment on the card: [src.assignment]") if(mining_points) user << "There's [mining_points] mining equipment redemption points loaded onto this card." src.add_fingerprint(user) return + +/obj/item/weapon/card/id/proc/UpdateName() + name = "[src.registered_name]'s ID Card ([src.assignment])" + +/obj/item/weapon/card/id/proc/SetOwnerInfo(var/mob/living/carbon/human/H) + if(!H || !H.dna) + return + + sex = capitalize(H.gender) + age = H.age + blood_type = H.dna.b_type + dna_hash = H.dna.unique_enzymes + fingerprint_hash = md5(H.dna.uni_identity) + + dat = ("
") + dat += text("Name: []
", registered_name) + dat += text("Sex: []
\n", sex) + dat += text("Age: []
\n", age) + dat += text("Rank: []
\n", assignment) + dat += text("Fingerprint: []
\n", fingerprint_hash) + dat += text("Blood Type: []
\n", blood_type) + dat += text("DNA Hash: []

\n", dna_hash) + dat += "
" /obj/item/weapon/card/id/GetAccess() return access @@ -187,19 +190,6 @@ else usr << "This ID has already been stamped!" - -/obj/item/weapon/card/id/verb/read() - set name = "Read ID Card" - set category = "Object" - set src in usr - - usr << text("\icon[] []: The current assignment on the card is [].", src, src.name, src.assignment) - usr << "The blood type on the card is [blood_type]." - usr << "The DNA hash on the card is [dna_hash]." - usr << "The fingerprint hash on the card is [fingerprint_hash]." - return - - /obj/item/weapon/card/id/silver name = "identification card" desc = "A silver card which shows honour and dedication." @@ -214,122 +204,181 @@ /obj/item/weapon/card/id/syndicate name = "agent card" - access = list(access_maint_tunnels, access_syndicate) + access = list(access_maint_tunnels, access_syndicate, access_external_airlocks) origin_tech = "syndicate=3" - var/registered_user=null - -/obj/item/weapon/card/id/syndicate/New(mob/user as mob) -// ..() - Intentionally does not call parent, doesn't need to - if(!isnull(user) && iscarbon(user)) // Runtime prevention on laggy starts or where users log out because of lag at round start. Also stops the ID from inheriting anything but a mob name - registered_name = ishuman(user) ? user.real_name : user.name - else - registered_name = "Agent Card" - assignment = "Agent" - name = "[registered_name]'s ID Card ([assignment])" + var/registered_user= n ull /obj/item/weapon/card/id/syndicate/afterattack(var/obj/item/weapon/O as obj, mob/user as mob, proximity) - if(!proximity) return + if(!proximity) + return if(istype(O, /obj/item/weapon/card/id)) var/obj/item/weapon/card/id/I = O - src.access |= I.access if(istype(user, /mob/living) && user.mind) if(user.mind.special_role) - usr << "\blue The card's microscanners activate as you pass it over the ID, copying its access." + usr << "The card's microscanners activate as you pass it over \the [I], copying its access." + src.access |= I.access //Don't copy access if user isn't an antag -- to prevent metagaming /obj/item/weapon/card/id/syndicate/attack_self(mob/user as mob) if(!src.registered_name) - //Stop giving the players unsanitized unputs! You are giving ways for players to intentionally crash clients! -Nodrak - var t = reject_bad_name(input(user, "What name would you like to put on this card?", "Agent card name", ishuman(user) ? user.real_name : user.name)) - if(!t) //Same as mob/new_player/prefrences.dm - alert("Invalid name.") + var t = reject_bad_name(input(user, "What name would you like to use on this card?", "Agent Card name", ishuman(user) ? user.real_name : user.name)) + if(!t) + user << "Invalid name." return src.registered_name = t - var u = sanitize(copytext(input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", "Civilian"),1,MAX_MESSAGE_LEN)) + var u = sanitize(stripped_input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than maintenance.", "Agent Card Job Assignment", "Agent", MAX_MESSAGE_LEN)) if(!u) - alert("Invalid assignment.") + user << "Invalid assignment." src.registered_name = "" return src.assignment = u src.name = "[src.registered_name]'s ID Card ([src.assignment])" + user << "You successfully forge the ID card." registered_user = user - var/s = input(user, "Would you like to update this card's details with your own?\nNote: This will take a picture of how you currently look, so put any items in your hand down first (other than this ID), and it will assume your age, and gender.", "Agent card update choice", "No") in list("Yes","No") - if(s == "Yes") - src.setupdat() - spawn(0) - src.updatedat() - user << "\blue You successfully forge the ID card." - else if(!registered_user || registered_user == user) + if(!registered_user) + registered_user = user - if(!registered_user) registered_user = user // - - switch(alert("Would you like to display the ID, or retitle it?","Choose.","Rename","Show")) - if("Rename") - var t = sanitize(copytext(input(user, "What name would you like to put on this card?", "Agent card name", ishuman(user) ? user.real_name : user.name),1,26)) - if(!t || t == "Unknown" || t == "floor" || t == "wall" || t == "r-wall") //Same as mob/new_player/prefrences.dm - alert("Invalid name.") - return - src.registered_name = t - - var u = sanitize(copytext(input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", "Civilian"),1,MAX_MESSAGE_LEN)) - if(!u) - alert("Invalid assignment.") - src.registered_name = "" - return - src.assignment = u - src.name = "[src.registered_name]'s ID Card ([src.assignment])" - var/s = input(user, "Would you like to update this card's details with your own?\nNote: This will take a picture of how you currently look, so put any items in your hand down first (other than this ID), and it will assume your age, and gender.", "Agent card update choice", "No") in list("Yes","No") - if(s == "Yes") - src.setupdat() - spawn(0) - src.updatedat() - user << "\blue You successfully forge the ID card." - return + switch(alert(user,"Would you like to display \the [src] or edit it?","Choose","Show","Edit")) if("Show") - ..() + return ..() + if("Edit") + switch(input(user,"What would you like to edit on \the [src]?") in list("Name","Appearance","Sex","Age","Occupation","Money Account","Blood Type","DNA Hash","Fingerprint Hash","Reset Card")) + if("Name") + var/new_name = reject_bad_name(input(user,"What name would you like to put on this card?","Agent Card Name", ishuman(user) ? user.real_name : user.name)) + if(!Adjacent(user)) + return + src.registered_name = new_name + UpdateName() + user << "Name changed to [new_name]." + + if("Appearance") + var/list/appearances = list( + "data", + "id", + "gold", + "silver", + "centcom", + "centcom_old", + "security", + "medical", + "HoS", + "research", + "engineering", + "CMO", + "RD", + "CE", + "clown", + "mime", + "prisoner", + "syndie", + "deathsquad", + "commander", + "ERT_leader", + "ERT_security", + "ERT_engineering", + "ERT_medical", + "ERT_janitorial", + ) + var/choice = input(user, "Select the appearance for this card.", "Agent Card Appearance") in appearances + if(!Adjacent(user)) + return + if(!choice) + return + src.icon_state = choice + usr << "Appearance changed to [choice]." + + if("Sex") + var/new_sex = sanitize(stripped_input(user,"What sex would you like to put on this card?","Agent Card Sex", ishuman(user) ? capitalize(user.gender) : "Male", MAX_MESSAGE_LEN)) + if(!Adjacent(user)) + return + src.sex = new_sex + user << "Sex changed to [new_sex]." + + if("Age") + var/new_age = sanitize(stripped_input(user,"What age would you like to put on this card?","Agent Card Age","21", MAX_MESSAGE_LEN)) + if(!Adjacent(user)) + return + src.age = new_age + user << "Age changed to [new_age]." + + if("Occupation") + var/new_job = sanitize(stripped_input(user,"What job would you like to put on this card?\nChanging occupation will not grant or remove any access levels.","Agent Card Occupation", "Assistant", MAX_MESSAGE_LEN)) + if(!Adjacent(user)) + return + src.assignment = new_job + user << "Occupation changed to [new_job]." + UpdateName() + + if("Money Account") + var/new_account = input(user,"What money account would you like to link to this card?","Agent Card Account",12345) as num + if(!Adjacent(user)) + return + associated_account_number = new_account + user << "Linked money account changed to [new_account]." + + if("Blood Type") + var/default = "\[UNSET\]" + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.dna) + default = H.dna.b_type + + var/new_blood_type = sanitize(input(user,"What blood type would you like to be written on this card?","Agent Card Blood Type",default) as text) + if(!Adjacent(user)) + return + src.blood_type = new_blood_type + user << "Blood type changed to [new_blood_type]." + + if("DNA Hash") + var/default = "\[UNSET\]" + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.dna) + default = H.dna.unique_enzymes + + var/new_dna_hash = sanitize(input(user,"What DNA hash would you like to be written on this card?","Agent Card DNA Hash",default) as text) + if(!Adjacent(user)) + return + src.dna_hash = new_dna_hash + user << "DNA hash changed to [new_dna_hash]." + + if("Fingerprint Hash") + var/default = "\[UNSET\]" + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.dna) + default = md5(H.dna.uni_identity) + + var/new_fingerprint_hash = sanitize(input(user,"What fingerprint hash would you like to be written on this card?","Agent Card Fingerprint Hash",default) as text) + if(!Adjacent(user)) + return + src.fingerprint_hash = new_fingerprint_hash + user << "Fingerprint hash changed to [new_fingerprint_hash]." + + if("Reset Card") + name = initial(name) + registered_name = initial(registered_name) + icon_state = initial(icon_state) + sex = initial(sex) + age = initial(age) + assignment = initial(assignment) + associated_account_number = initial(associated_account_number) + blood_type = initial(blood_type) + dna_hash = initial(dna_hash) + fingerprint_hash = initial(fingerprint_hash) + access = initial(access) + registered_user = null + + user << "All information has been deleted from \the [src]." else ..() -/obj/item/weapon/card/id/syndicate/proc/setupdat() //fake initilization, taken mostly from job_controller.dm - if(istype(src.loc, /mob/living/carbon/human)) //just adopt the syndie stuff, it would be annoying to ask them to set all of this, and the use would be limited - var/mob/living/carbon/human/H = loc - src.sex = capitalize(H.gender) - src.rank = src.assignment - src.age = H.age - src.photo = fake_id_photo(H) - var/icon/photoside = fake_id_photo(H,1) - front = new(photo) - side = new(photoside) - -/obj/item/weapon/card/id/syndicate/proc/fake_id_photo(var/mob/living/carbon/human/H, var/side=0)//get_id_photo wouldn't work correctly - if(!istype(H)) - return - var/storedDir = H.dir //don't want to lose track of this - - var/icon/faked - if(!side) - if(!H.equip_to_slot_if_possible(src, slot_l_store, 0, 1)) - H << "You need to empty your pockets before taking the ID picture." - return - - if(side) - H.dir = WEST //ensure the icon is actually the proper direction before copying it - faked = getFlatIcon(H) - H.dir = storedDir //reset the user back to their original direction, not even noticable they changed - H.equip_to_slot_if_possible(src, slot_l_hand, 0, 1) - - else - H.dir = SOUTH - faked = getFlatIcon(H) - H.dir = storedDir - - return faked - /obj/item/weapon/card/id/syndicate_command name = "syndicate ID card" desc = "An ID straight from the Syndicate." registered_name = "Syndicate" + icon_state = "syndie" assignment = "Syndicate Overlord" access = list(access_syndicate, access_external_airlocks) @@ -340,10 +389,22 @@ item_state = "gold_id" registered_name = "Captain" assignment = "Captain" - New() - var/datum/job/captain/J = new/datum/job/captain - access = J.get_access() - ..() + +/obj/item/weapon/card/id/captains_spare/New() + var/datum/job/captain/J = new/datum/job/captain + access = J.get_access() + ..() + +/obj/item/weapon/card/id/admin + name = "admin ID card" + icon_state = "admin" + item_state = "gold_id" + registered_name = "Admin" + assignment = "Testing Shit" + +/obj/item/weapon/card/id/admin/New() + access = get_absolutely_all_accesses() + ..() /obj/item/weapon/card/id/centcom name = "central command ID card" @@ -351,14 +412,15 @@ icon_state = "centcom" registered_name = "Central Command" assignment = "General" - New() - access = get_all_centcom_access() - ..() + +/obj/item/weapon/card/id/centcom/New() + access = get_all_centcom_access() + ..() /obj/item/weapon/card/id/prisoner name = "prisoner ID card" desc = "You are a number, you are not a free man." - icon_state = "orange" + icon_state = "prisoner" item_state = "orange-id" assignment = "Prisoner" registered_name = "Scum" @@ -403,6 +465,100 @@ desc = "Finders, keepers." access = list(access_salvage_captain) +/obj/item/weapon/card/id/medical + name = "Medical ID" + registered_name = "Medic" + icon_state = "medical" + access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics, access_mineral_storeroom) + +/obj/item/weapon/card/id/security + name = "Security ID" + registered_name = "Officer" + icon_state = "security" + access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_morgue, access_weapons) + +/obj/item/weapon/card/id/research + name = "Research ID" + registered_name = "Scientist" + icon_state = "research" + access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_xenoarch, access_mineral_storeroom) + +/obj/item/weapon/card/id/supply + name = "Supply ID" + registered_name = "Cargonian" + icon_state = "cargo" + access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mint, access_mining, access_mining_station, access_mineral_storeroom) + +/obj/item/weapon/card/id/engineering + name = "Engineering ID" + registered_name = "Engineer" + icon_state = "engineering" + access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics) + +/obj/item/weapon/card/id/hos + name = "Head of Security ID" + registered_name = "HoS" + icon_state = "HoS" + access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, + access_forensics_lockers, access_pilot, access_morgue, access_maint_tunnels, access_all_personal_lockers, + access_research, access_engine, access_mining, access_medical, access_construction, access_mailsorting, + access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_weapons) + +/obj/item/weapon/card/id/cmo + name = "Chief Medical Officer ID" + registered_name = "CMO" + icon_state = "CMO" + access = list(access_medical, access_morgue, access_genetics, access_heads, + access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce, + access_keycard_auth, access_sec_doors, access_psychiatrist, access_paramedic, access_mineral_storeroom) + +/obj/item/weapon/card/id/rd + name = "Research Director ID" + registered_name = "RD" + icon_state = "RD" + access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue, + access_tox_storage, access_tech_storage, access_teleporter, access_sec_doors, + access_research, access_robotics, access_xenobiology, access_ai_upload, + access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_minisat, access_mineral_storeroom) + +/obj/item/weapon/card/id/ce + name = "Chief Engineer ID" + registered_name = "CE" + icon_state = "CE" + access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, + access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva, + access_heads, access_construction, access_sec_doors, + access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_minisat, access_mechanic, access_mineral_storeroom) + +/obj/item/weapon/card/id/clown + name = "Pink ID" + registered_name = "HONK!" + icon_state = "clown" + desc = "Even looking at the card strikes you with deep fear." + access = list(access_clown, access_theatre, access_maint_tunnels) + +/obj/item/weapon/card/id/mime + name = "Black and White ID" + registered_name = "..." + icon_state = "mime" + desc = "..." + access = list(access_mime, access_theatre, access_maint_tunnels) + +/obj/item/weapon/card/id/thunderdome/red + name = "Thunderdome Red ID" + registered_name = "Red Team Fighter" + assignment = "Red Team Fighter" + icon_state = "TDred" + desc = "This ID card is given to those who fought inside the thunderdome for the Red Team. Not many have lived to see one of those, even fewer lived to keep it." + +/obj/item/weapon/card/id/thunderdome/green + name = "Thunderdome Green ID" + registered_name = "Green Team Fighter" + assignment = "Green Team Fighter" + icon_state = "TDgreen" + desc = "This ID card is given to those who fought inside the thunderdome for the Green Team. Not many have lived to see one of those, even fewer lived to keep it." + +// Decals /obj/item/weapon/id_decal name = "identification card decal" desc = "A modification kit to make your ID cards look snazzy.." @@ -429,7 +585,7 @@ /obj/item/weapon/id_decal/prisoner name = "prisoner ID card decal" decal_desc = "You are a number, you are not a free man." - decal_icon_state = "orange" + decal_icon_state = "prisoner" decal_item_state = "orange-id" /obj/item/weapon/id_decal/centcom diff --git a/code/game/response_team.dm b/code/game/response_team.dm index 39e5e672553..03efff51ffe 100644 --- a/code/game/response_team.dm +++ b/code/game/response_team.dm @@ -260,7 +260,7 @@ var/send_emergency_team W.assignment = "Emergency Response Team Member" W.registered_name = M.real_name W.name = "[M.real_name]'s ID Card (Emergency Response Team Engineer)" - W.icon_state = "centcom" + W.icon_state = "ERT_engineering" W.access = get_centcom_access(W.assignment) M.equip_to_slot_or_del(W, slot_wear_id) @@ -284,7 +284,7 @@ var/send_emergency_team W.assignment = "Emergency Response Team Member" W.registered_name = M.real_name W.name = "[M.real_name]'s ID Card (Emergency Response Team Officer)" - W.icon_state = "centcom" + W.icon_state = "ERT_security" W.access = get_centcom_access(W.assignment) M.equip_to_slot_or_del(W, slot_wear_id) @@ -306,7 +306,7 @@ var/send_emergency_team W.assignment = "Emergency Response Team Member" W.registered_name = M.real_name W.name = "[M.real_name]'s ID Card (Emergency Response Team Medic)" - W.icon_state = "centcom" + W.icon_state = "ERT_medical" W.access = get_centcom_access(W.assignment) M.equip_to_slot_or_del(W, slot_wear_id) @@ -328,7 +328,7 @@ var/send_emergency_team W.assignment = "Emergency Response Team Leader" W.registered_name = M.real_name W.name = "[M.real_name]'s ID Card (Emergency Response Team Leader)" - W.icon_state = "centcom" + W.icon_state = "ERT_leader" W.access = get_centcom_access(W.assignment) M.equip_to_slot_or_del(W, slot_wear_id) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 096eb0128b0..18729e36a79 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -605,11 +605,11 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that "blue wizard", "red wizard", "marisa wizard", - "emergency response team", + "emergency response team member", + "emergency response team leader", "nanotrasen officer", "nanotrasen captain", "singuloth knight" - ) var/dostrip = input("Do you want to strip [M] before equipping them? (0=no, 1=yes)", "STRIPTEASE") as null|anything in list(0,1) if(isnull(dostrip)) @@ -820,6 +820,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that var/obj/item/weapon/card/id/syndicate/W = new(M) W.name = "[M.real_name]'s ID Card (Dark Lord)" + W.icon_state = "syndie" W.access = get_all_accesses() W.assignment = "Dark Lord" W.registered_name = M.real_name @@ -837,7 +838,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that var/obj/item/weapon/storage/secure/briefcase/sec_briefcase = new(M) for(var/obj/item/briefcase_item in sec_briefcase) - del(briefcase_item) + qdel(briefcase_item) for(var/i=3, i>0, i--) sec_briefcase.contents += new /obj/item/weapon/spacecash/c1000 sec_briefcase.contents += new /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow @@ -855,6 +856,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that var/obj/item/weapon/card/id/syndicate/W = new(M) W.name = "[M.real_name]'s ID Card (Reaper)" + W.icon_state = "syndie" W.access = get_all_accesses() W.assignment = "Reaper" W.registered_name = M.real_name @@ -889,7 +891,6 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that W.registered_name = M.real_name M.equip_if_possible(W, slot_wear_id) - if("nanotrasen captain") M.equip_if_possible(new /obj/item/clothing/under/rank/centcom/captain(M), slot_w_uniform) M.equip_if_possible(new /obj/item/clothing/shoes/centcom(M), slot_shoes) @@ -925,7 +926,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that var/obj/item/weapon/card/id/W = new(M) W.name = "[M.real_name]'s ID Card (Emergency Response Team - Member)" - W.icon_state = "centcom" + W.icon_state = "ERT_empty" W.assignment = "Emergency Response Team Member" W.access = get_centcom_access(W.assignment) W.registered_name = M.real_name @@ -947,7 +948,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that var/obj/item/weapon/card/id/W = new(M) W.name = "[M.real_name]'s ID Card (Emergency Response Team - Leader)" - W.icon_state = "centcom" + W.icon_state = "ERT_leader" W.assignment = "Emergency Response Team Leader" W.access = get_centcom_access(W.assignment) W.registered_name = M.real_name @@ -982,7 +983,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that var/obj/item/weapon/card/id/W = new(M) W.name = "[M.real_name]'s ID Card" - W.icon_state = "centcom" + W.icon_state = "commander" W.assignment = "Special Operations Officer" W.access = get_centcom_access(W.assignment) W.registered_name = M.real_name @@ -1015,7 +1016,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that var/obj/item/weapon/card/id/W = new(M) W.name = "[M.real_name]'s ID Card (Special Operations Officer)" - W.icon_state = "centcom" + W.icon_state = "commander" W.assignment = "Special Operations Officer" W.access = get_centcom_access(W.assignment) W.registered_name = M.real_name @@ -1037,7 +1038,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that var/obj/item/weapon/card/id/W = new(M) W.name = "[M.real_name]'s ID Card (Singuloth Knight)" - W.icon_state = "centcom" + W.icon_state = "syndie" W.access = get_all_accesses() W.access += get_all_centcom_access() W.assignment = "Singuloth Knight" @@ -1092,7 +1093,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that M.equip_to_slot_or_del(new /obj/item/clothing/under/soviet(M), slot_w_uniform) var/obj/item/weapon/card/id/W = new(M) W.name = "[M.real_name]'s ID Card (Admiral)" - W.icon_state = "centcom" + W.icon_state = "commander" W.access = get_all_accesses() W.access += get_all_centcom_access() W.assignment = "Admiral" diff --git a/code/modules/admin/verbs/striketeam.dm b/code/modules/admin/verbs/striketeam.dm index 92a883faf1c..347f461dca8 100644 --- a/code/modules/admin/verbs/striketeam.dm +++ b/code/modules/admin/verbs/striketeam.dm @@ -167,7 +167,7 @@ var/global/sent_strike_team = 0 var/obj/item/weapon/card/id/W = new(src) W.name = "[real_name]'s ID Card" - W.icon_state = "centcom" + W.icon_state = "deathsquad" W.assignment = "Death Commando" W.access = get_centcom_access(W.assignment) W.registered_name = real_name diff --git a/code/modules/admin/verbs/striketeam_syndicate.dm b/code/modules/admin/verbs/striketeam_syndicate.dm index 270c3d8c4f1..f9ea83e4ba9 100644 --- a/code/modules/admin/verbs/striketeam_syndicate.dm +++ b/code/modules/admin/verbs/striketeam_syndicate.dm @@ -169,7 +169,7 @@ var/global/sent_syndicate_strike_team = 0 var/obj/item/weapon/card/id/syndicate/W = new(src) //Untrackable by AI W.name = "[real_name]'s ID Card" - W.icon_state = "id" + W.icon_state = "syndie" W.access = get_all_accesses()//They get full station access because obviously the syndicate has HAAAX, and can make special IDs for their most elite members. W.assignment = "Syndicate Commando" W.access = get_syndicate_access(W.assignment) diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi index d304ba2e27706d5af1e710c38abf16a508c54e21..54dd291702e0e59b7806cb15869b5dceb1147e7d 100644 GIT binary patch literal 18896 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 literal 9661 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 From c9ed5fe5bc1d04a695506a0876b8052f23fb1e0a Mon Sep 17 00:00:00 2001 From: Markolie Date: Sun, 9 Aug 2015 23:46:40 +0200 Subject: [PATCH 2/8] Fix typo --- code/game/objects/items/weapons/cards_ids.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index ce340a26aa5..2ba58c8adb9 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -206,7 +206,7 @@ name = "agent card" access = list(access_maint_tunnels, access_syndicate, access_external_airlocks) origin_tech = "syndicate=3" - var/registered_user= n ull + var/registered_user = null /obj/item/weapon/card/id/syndicate/afterattack(var/obj/item/weapon/O as obj, mob/user as mob, proximity) if(!proximity) From fbbc0a1ac8701284e07833b8a1ed21392a8cbc29 Mon Sep 17 00:00:00 2001 From: Markolie Date: Mon, 10 Aug 2015 01:24:02 +0200 Subject: [PATCH 3/8] Make card skins changeable by centcom/regular card computers --- code/game/machinery/computer/card.dm | 66 +++++++++++++++++++-- nano/templates/identification_computer.tmpl | 12 ++++ 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 3ddb72d13ab..6d046a9df80 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -11,6 +11,37 @@ var/obj/item/weapon/card/id/modify = null var/mode = 0.0 var/printing = null + var/list/card_skins = list( + "data", + "id", + "gold", + "silver", + "security", + "medical", + "research", + "engineering", + "HoS", + "CMO", + "RD", + "CE", + "clown", + "mime" + ) + var/list/centcom_card_skins = list( + "centcom", + "centcom_old", + "ERT_leader", + "ERT_empty", + "ERT_security", + "ERT_engineering", + "ERT_medical", + "ERT_janitorial", + "deathsquad", + "commander", + "syndie", + "TDred", + "TDgreen" + ) light_color = LIGHT_COLOR_LIGHTBLUE @@ -27,11 +58,20 @@ var/list/formatted = list() for(var/job in jobs) formatted.Add(list(list( - "display_name" = replacetext(job, " ", " "), + "display_name" = replacetext(job, " ", " "), "target_rank" = get_target_rank(), "job" = job))) return formatted + + proc/format_card_skins(list/card_skins) + var/list/formatted = list() + for(var/skin in card_skins) + formatted.Add(list(list( + "display_name" = replacetext(skin, " ", " "), + "skin" = skin))) + + return formatted /obj/machinery/computer/card/verb/eject_id() set category = null @@ -112,16 +152,29 @@ data["civilian_jobs"] = format_jobs(civilian_positions) data["special_jobs"] = format_jobs(whitelisted_positions) data["centcom_jobs"] = format_jobs(get_all_centcom_jobs()) + data["card_skins"] = format_card_skins(card_skins) + + if(modify) + data["current_skin"] = modify.icon_state if (modify && is_centcom()) var/list/all_centcom_access = list() for(var/access in get_all_centcom_access()) all_centcom_access.Add(list(list( - "desc" = replacetext(get_centcom_access_desc(access), " ", " "), + "desc" = replacetext(get_centcom_access_desc(access), " ", " "), "ref" = access, "allowed" = (access in modify.access) ? 1 : 0))) data["all_centcom_access"] = all_centcom_access + + var/list/all_centcom_skins = list() + for(var/skin in centcom_card_skins) + all_centcom_skins.Add(list(list( + "display_name" = replacetext(skin, " ", " "), + "skin" = skin))) + + data["all_centcom_skins"] = all_centcom_skins + else if (modify) var/list/regions = list() for(var/i = 1; i <= 7; i++) @@ -129,7 +182,7 @@ for(var/access in get_region_accesses(i)) if (get_access_desc(access)) accesses.Add(list(list( - "desc" = replacetext(get_access_desc(access), " ", " "), + "desc" = replacetext(get_access_desc(access), " ", " "), "ref" = access, "allowed" = (access in modify.access) ? 1 : 0))) @@ -141,7 +194,7 @@ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "identification_computer.tmpl", src.name, 600, 700) + ui = new(user, src, ui_key, "identification_computer.tmpl", src.name, 775, 700) ui.set_initial_data(data) ui.open() @@ -195,6 +248,11 @@ modify.access -= access_type if(!access_allowed) modify.access += access_type + + if("skin") + var/skin = href_list["skin_target"] + if(is_authenticated() && modify && ((skin in card_skins) || ((skin in centcom_card_skins) && is_centcom()))) + modify.icon_state = href_list["skin_target"] if ("assign") if (is_authenticated() && modify) diff --git a/nano/templates/identification_computer.tmpl b/nano/templates/identification_computer.tmpl index b12f3ab444e..4330515b832 100644 --- a/nano/templates/identification_computer.tmpl +++ b/nano/templates/identification_computer.tmpl @@ -210,6 +210,12 @@ {{:helper.link(value.desc, '', {'choice' : 'access', 'access_target' : value.ref, 'allowed' : value.allowed}, null, value.allowed ? 'selected' : null)}} {{/for}} +
+
Card Skin
+ {{for data.all_centcom_skins}} + {{:helper.link(value.display_name, '', {'choice' : 'skin', 'skin_target' : value.skin}, null,(data.current_skin == value.skin) ? 'selected' : null )}} + {{/for}} +
{{else}}
@@ -226,6 +232,12 @@ {{/for}}
{{/for}} +
+
Card Skin
+ {{for data.card_skins}} + {{:helper.link(value.display_name, '', {'choice' : 'skin', 'skin_target' : value.skin}, null,(data.current_skin == value.skin) ? 'selected' : null )}} + {{/for}} +
{{/if}} {{/if}} From 958ea8c8ee290d6ee91db260d127d79a067c987e Mon Sep 17 00:00:00 2001 From: Markolie Date: Mon, 10 Aug 2015 01:27:35 +0200 Subject: [PATCH 4/8] Minor card computer styling change --- nano/templates/identification_computer.tmpl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/nano/templates/identification_computer.tmpl b/nano/templates/identification_computer.tmpl index 4330515b832..fa778bc1abc 100644 --- a/nano/templates/identification_computer.tmpl +++ b/nano/templates/identification_computer.tmpl @@ -204,13 +204,11 @@

Central Command

-
+
{{for data.all_centcom_access}} -
{{:helper.link(value.desc, '', {'choice' : 'access', 'access_target' : value.ref, 'allowed' : value.allowed}, null, value.allowed ? 'selected' : null)}} -
{{/for}} -
+
Card Skin
{{for data.all_centcom_skins}} {{:helper.link(value.display_name, '', {'choice' : 'skin', 'skin_target' : value.skin}, null,(data.current_skin == value.skin) ? 'selected' : null )}} @@ -221,7 +219,7 @@

{{:data.station_name}}

-
+
{{for data.regions}}
{{:value.name}}
From fe512b37769b8adbf89a6ca8ec4a5cac29859e8f Mon Sep 17 00:00:00 2001 From: Markolie Date: Mon, 10 Aug 2015 02:58:00 +0200 Subject: [PATCH 5/8] Add slot removal/additions on identification computers --- code/game/machinery/computer/card.dm | 172 ++++++++++++++++--- code/game/objects/items/weapons/cards_ids.dm | 2 +- nano/templates/identification_computer.tmpl | 66 +++++-- 3 files changed, 195 insertions(+), 45 deletions(-) diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 6d046a9df80..e01706b3bb5 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -1,4 +1,6 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 +//Keeps track of the time for the ID console. Having it as a global variable prevents people from dismantling/reassembling it to +//increase the slots of many jobs. +var/time_last_changed_position = 0 /obj/machinery/computer/card name = "Identification Computer" @@ -6,11 +8,45 @@ icon_keyboard = "id_key" icon_screen = "id" req_access = list(access_change_ids) - circuit = "/obj/item/weapon/circuitboard/card" + circuit = /obj/item/weapon/circuitboard/card + light_color = LIGHT_COLOR_LIGHTBLUE var/obj/item/weapon/card/id/scan = null var/obj/item/weapon/card/id/modify = null var/mode = 0.0 var/printing = null + + //Cooldown for closing positions in seconds + //if set to -1: No cooldown... probably a bad idea + //if set to 0: Not able to close "original" positions. You can only close positions that you have opened before + var/change_position_cooldown = 60 + //Jobs you cannot open new positions for + var/list/blacklisted = list( + "AI", + "Cyborg", + "Captain", + "Head of Personnel", + "Head of Security", + "Chief Engineer", + "Research Director", + "Chief Medical Officer", + "Magistrate", + "Blueshield", + "Nanotrasen Representative", + "Security Pod Pilot", + "Brig Physician", + "Mechanic", + "Barber", + "Civilian", + "Chaplain" + ) + + //The scaling factor of max total positions in relation to the total amount of people on board the station in % + var/max_relative_positions = 30 //30%: Seems reasonable, limit of 6 @ 20 players + + //This is used to keep track of opened positions for jobs to allow instant closing + //Assoc array: "JobName" = (int) + var/list/opened_positions = list(); + var/list/card_skins = list( "data", "id", @@ -25,7 +61,8 @@ "RD", "CE", "clown", - "mime" + "mime", + "prisoner" ) var/list/centcom_card_skins = list( "centcom", @@ -43,35 +80,47 @@ "TDgreen" ) - light_color = LIGHT_COLOR_LIGHTBLUE +/obj/machinery/computer/card/proc/is_centcom() + return istype(src, /obj/machinery/computer/card/centcom) - proc/is_centcom() - return istype(src, /obj/machinery/computer/card/centcom) +/obj/machinery/computer/card/proc/is_authenticated() + return scan ? check_access(scan) : 0 - proc/is_authenticated() - return scan ? check_access(scan) : 0 +/obj/machinery/computer/card/proc/get_target_rank() + return modify && modify.assignment ? modify.assignment : "Unassigned" - proc/get_target_rank() - return modify && modify.assignment ? modify.assignment : "Unassigned" +/obj/machinery/computer/card/proc/format_jobs(list/jobs) + var/list/formatted = list() + for(var/job in jobs) + formatted.Add(list(list( + "display_name" = replacetext(job, " ", " "), + "target_rank" = get_target_rank(), + "job" = job))) - proc/format_jobs(list/jobs) - var/list/formatted = list() - for(var/job in jobs) - formatted.Add(list(list( - "display_name" = replacetext(job, " ", " "), - "target_rank" = get_target_rank(), - "job" = job))) + return formatted + +/obj/machinery/computer/card/proc/format_job_slots() + var/list/formatted = list() + for(var/datum/job/job in job_master.occupations) + if(job.title in blacklisted) + continue + formatted.Add(list(list( + "title" = job.title, + "current_positions" = job.current_positions, + "total_positions" = job.total_positions, + "can_open" = can_open_job(job), + "can_close" = can_close_job(job)))) - return formatted + return formatted - proc/format_card_skins(list/card_skins) - var/list/formatted = list() - for(var/skin in card_skins) - formatted.Add(list(list( - "display_name" = replacetext(skin, " ", " "), - "skin" = skin))) +/obj/machinery/computer/card/proc/format_card_skins(list/card_skins) + var/list/formatted = list() + for(var/skin in card_skins) + formatted.Add(list(list( + "display_name" = replacetext(skin, " ", " "), + "skin" = skin))) - return formatted + return formatted /obj/machinery/computer/card/verb/eject_id() set category = null @@ -111,11 +160,39 @@ nanomanager.update_uis(src) attack_hand(user) + +//Check if you can't open a new position for a certain job +/obj/machinery/computer/card/proc/job_blacklisted(jobtitle) + return (jobtitle in blacklisted) + + +//Logic check for Topic() if you can open the job +/obj/machinery/computer/card/proc/can_open_job(datum/job/job) + if(job) + if(!job_blacklisted(job.title)) + if((job.total_positions <= player_list.len * (max_relative_positions / 100))) + var/delta = (world.time / 10) - time_last_changed_position + if((change_position_cooldown < delta) || (opened_positions[job.title] < 0)) + return 1 + return -2 + return -1 + return 0 + +//Logic check for Topic() if you can close the job +/obj/machinery/computer/card/proc/can_close_job(datum/job/job) + if(job) + if(!job_blacklisted(job.title)) + if(job.total_positions > job.current_positions) + var/delta = (world.time / 10) - time_last_changed_position + if((change_position_cooldown < delta) || (opened_positions[job.title] > 0)) + return 1 + return -2 + return -1 + return 0 /obj/machinery/computer/card/attack_ai(var/mob/user as mob) return attack_hand(user) - /obj/machinery/computer/card/attack_hand(mob/user as mob) if(..()) return @@ -154,6 +231,14 @@ data["centcom_jobs"] = format_jobs(get_all_centcom_jobs()) data["card_skins"] = format_card_skins(card_skins) + data["job_slots"] = format_job_slots() + + var/time_to_wait = round(change_position_cooldown - ((world.time / 10) - time_last_changed_position), 1) + var/mins = round(time_to_wait / 60) + var/seconds = time_to_wait - (60*mins) + data["cooldown_mins"] = mins + data["cooldown_secs"] = (seconds < 10) ? "0[seconds]" : seconds + if(modify) data["current_skin"] = modify.icon_state @@ -315,13 +400,13 @@ nanomanager.update_uis(src) var/obj/item/weapon/paper/P = new(loc) - if (mode) + if (mode == 2) P.name = text("crew manifest ([])", worldtime2text()) P.info = {"

Crew Manifest


[data_core ? data_core.get_manifest(0) : ""] "} - else if (modify) + else if (modify && !mode) P.name = "access report" P.info = {"

Access Report

Prepared By: [scan.registered_name ? scan.registered_name : "Unknown"]
@@ -342,6 +427,37 @@ modify.access = list() callHook("terminate_employee", list(modify)) + + if("make_job_available") + // MAKE ANOTHER JOB POSITION AVAILABLE FOR LATE JOINERS + if(is_authenticated()) + var/edit_job_target = href_list["job"] + var/datum/job/j = job_master.GetJob(edit_job_target) + if(!j) + return 0 + if(can_open_job(j) != 1) + return 0 + if(opened_positions[edit_job_target] >= 0) + time_last_changed_position = world.time / 10 + j.total_positions++ + opened_positions[edit_job_target]++ + nanomanager.update_uis(src) + + if("make_job_unavailable") + // MAKE JOB POSITION UNAVAILABLE FOR LATE JOINERS + if(is_authenticated()) + var/edit_job_target = href_list["job"] + var/datum/job/j = job_master.GetJob(edit_job_target) + if(!j) + return 0 + if(can_close_job(j) != 1) + return 0 + //Allow instant closing without cooldown if a position has been opened before + if(opened_positions[edit_job_target] <= 0) + time_last_changed_position = world.time / 10 + j.total_positions-- + opened_positions[edit_job_target]-- + nanomanager.update_uis(src) if (modify) modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])") diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 2ba58c8adb9..0633ae94dc7 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -303,7 +303,7 @@ user << "Age changed to [new_age]." if("Occupation") - var/new_job = sanitize(stripped_input(user,"What job would you like to put on this card?\nChanging occupation will not grant or remove any access levels.","Agent Card Occupation", "Assistant", MAX_MESSAGE_LEN)) + var/new_job = sanitize(stripped_input(user,"What job would you like to put on this card?\nChanging occupation will not grant or remove any access levels.","Agent Card Occupation", "Civilian", MAX_MESSAGE_LEN)) if(!Adjacent(user)) return src.assignment = new_job diff --git a/nano/templates/identification_computer.tmpl b/nano/templates/identification_computer.tmpl index fa778bc1abc..a1d1e971dfa 100644 --- a/nano/templates/identification_computer.tmpl +++ b/nano/templates/identification_computer.tmpl @@ -1,24 +1,58 @@ {{if data.printing}} -
The computer is currently busy.
-
-
Printing...
-
-

- Thank you for your patience! -

+
The computer is currently busy.
+
+
Printing...
+
+

+ Thank you for your patience! +

{{else}} - {{:helper.link('Access Modification', 'home', {'choice' : 'mode', 'mode_target' : 0}, !data.mode ? 'disabled' : null)}} - {{:helper.link('Crew Manifest', 'folder-open', {'choice' : 'mode', 'mode_target' : 1}, data.mode ? 'disabled' : null)}} - {{:helper.link('Print', 'print', {'choice' : 'print'}, (data.mode || data.has_modify) ? null : 'disabled')}} + {{:helper.link('Access Modification', 'home', {'choice' : 'mode', 'mode_target' : 0}, !data.mode ? 'disabled' : null)}} + {{:helper.link('Job Management', 'gear', {'choice' : 'mode', 'mode_target' : 1}, data.mode == 1 ? 'disabled' : null)}} + {{:helper.link('Crew Manifest', 'folder-open', {'choice' : 'mode', 'mode_target' : 2}, data.mode == 2 ? 'disabled' : null)}} + {{:helper.link('Print', 'print', {'choice' : 'print'}, (data.mode == 2 || data.has_modify && !data.mode) ? null : 'disabled')}} - {{if data.mode}} + {{if data.mode == 1}} +
+

Job Management

+

Cooldown: {{:data.cooldown}}

+
-

Crew Manifest

+
+ Authorized Identity: +
+
+ {{:helper.link(data.scan_name, 'eject', {'choice' : 'scan'})}} +
+
+ Cooldown: +
+
+ {{if data.cooldown_mins || data.cooldown_secs}} + Next change in: {{:data.cooldown_mins}}:{{:data.cooldown_secs}} + {{else}} + Ready! + {{/if}} +
-
- {{:data.manifest}} -
- {{else}} +
+
+ {{for data.job_slots}} +
+ {{:value.title}}: {{:value.current_positions}}/{{:value.total_positions}} + {{:helper.link('', 'minus', {'choice' : 'make_job_unavailable', 'job' : value.title}, value.can_close != 1 && data.authenticated ? null : 'disabled')}} + {{:helper.link('', 'plus', {'choice' : 'make_job_available', 'job' : value.title}, value.can_open != 1 && data.authenticated ? null : 'disabled')}} +
+ {{/for}} +
+ {{else data.mode == 2}} +
+

Crew Manifest

+
+
+ {{:data.manifest}} +
+ {{else}}

Access Modification

From f65db354cf2494a159468002032059533b41269f Mon Sep 17 00:00:00 2001 From: Markolie Date: Mon, 10 Aug 2015 02:59:16 +0200 Subject: [PATCH 6/8] Include updated NanoUI template --- nano/templates/identification_computer.tmpl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/nano/templates/identification_computer.tmpl b/nano/templates/identification_computer.tmpl index a1d1e971dfa..7344e740efd 100644 --- a/nano/templates/identification_computer.tmpl +++ b/nano/templates/identification_computer.tmpl @@ -15,7 +15,6 @@ {{if data.mode == 1}}

Job Management

-

Cooldown: {{:data.cooldown}}

@@ -28,7 +27,7 @@ Cooldown:
- {{if data.cooldown_mins || data.cooldown_secs}} + {{if data.cooldown_mins > 0 || data.cooldown_mins == 0 && data.cooldown_secs > 0}} Next change in: {{:data.cooldown_mins}}:{{:data.cooldown_secs}} {{else}} Ready! @@ -38,10 +37,10 @@
{{for data.job_slots}} -
+
{{:value.title}}: {{:value.current_positions}}/{{:value.total_positions}} - {{:helper.link('', 'minus', {'choice' : 'make_job_unavailable', 'job' : value.title}, value.can_close != 1 && data.authenticated ? null : 'disabled')}} - {{:helper.link('', 'plus', {'choice' : 'make_job_available', 'job' : value.title}, value.can_open != 1 && data.authenticated ? null : 'disabled')}} + {{:helper.link('', 'minus', {'choice' : 'make_job_unavailable', 'job' : value.title}, value.can_close == 1 && data.authenticated ? null : 'disabled')}} + {{:helper.link('', 'plus', {'choice' : 'make_job_available', 'job' : value.title}, value.can_open == 1 && data.authenticated ? null : 'disabled')}}
{{/for}}
From 63bff3e31d1f04394db2d51755cb8f3ad1e47412 Mon Sep 17 00:00:00 2001 From: Markolie Date: Mon, 10 Aug 2015 04:29:17 +0200 Subject: [PATCH 7/8] Fix double attack_self message --- code/game/objects/items/weapons/cards_ids.dm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 0633ae94dc7..296ca45debb 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -130,9 +130,8 @@ return /obj/item/weapon/card/id/attack_self(mob/user as mob) - for(var/mob/O in viewers(user, null)) - user.visible_message("[user] shows you: \icon[src] [src.name]. The assignment on the card: [src.assignment]",\ - "You flash your ID card: \icon[src] [src.name]. The assignment on the card: [src.assignment]") + user.visible_message("[user] shows you: \icon[src] [src.name]. The assignment on the card: [src.assignment]",\ + "You flash your ID card: \icon[src] [src.name]. The assignment on the card: [src.assignment]") if(mining_points) user << "There's [mining_points] mining equipment redemption points loaded onto this card." src.add_fingerprint(user) From 99c7bbed55a6eb0c62a95bf4d6dfe967c72b4b1a Mon Sep 17 00:00:00 2001 From: Markolie Date: Mon, 10 Aug 2015 16:00:58 +0200 Subject: [PATCH 8/8] Add card skin descriptions, let agent ID's change photo, re-add photos and job blacklist update --- code/game/machinery/computer/card.dm | 93 ++++++-------------- code/game/objects/items/weapons/cards_ids.dm | 91 ++++++++++++++++++- nano/templates/identification_computer.tmpl | 4 +- 3 files changed, 116 insertions(+), 72 deletions(-) diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index e01706b3bb5..62629ca59ec 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -21,23 +21,23 @@ var/time_last_changed_position = 0 var/change_position_cooldown = 60 //Jobs you cannot open new positions for var/list/blacklisted = list( - "AI", - "Cyborg", - "Captain", - "Head of Personnel", - "Head of Security", - "Chief Engineer", - "Research Director", - "Chief Medical Officer", - "Magistrate", - "Blueshield", - "Nanotrasen Representative", - "Security Pod Pilot", - "Brig Physician", - "Mechanic", - "Barber", - "Civilian", - "Chaplain" + /datum/job/ai, + /datum/job/cyborg, + /datum/job/captain, + /datum/job/hop, + /datum/job/hos, + /datum/job/chief_engineer, + /datum/job/rd, + /datum/job/cmo, + /datum/job/judge, + /datum/job/blueshield, + /datum/job/nanotrasenrep, + /datum/job/pilot, + /datum/job/brigdoc, + /datum/job/mechanic, + /datum/job/barber, + /datum/job/chaplain, + /datum/job/civilian ) //The scaling factor of max total positions in relation to the total amount of people on board the station in % @@ -47,39 +47,6 @@ var/time_last_changed_position = 0 //Assoc array: "JobName" = (int) var/list/opened_positions = list(); - var/list/card_skins = list( - "data", - "id", - "gold", - "silver", - "security", - "medical", - "research", - "engineering", - "HoS", - "CMO", - "RD", - "CE", - "clown", - "mime", - "prisoner" - ) - var/list/centcom_card_skins = list( - "centcom", - "centcom_old", - "ERT_leader", - "ERT_empty", - "ERT_security", - "ERT_engineering", - "ERT_medical", - "ERT_janitorial", - "deathsquad", - "commander", - "syndie", - "TDred", - "TDgreen" - ) - /obj/machinery/computer/card/proc/is_centcom() return istype(src, /obj/machinery/computer/card/centcom) @@ -102,7 +69,7 @@ var/time_last_changed_position = 0 /obj/machinery/computer/card/proc/format_job_slots() var/list/formatted = list() for(var/datum/job/job in job_master.occupations) - if(job.title in blacklisted) + if(job_blacklisted(job)) continue formatted.Add(list(list( "title" = job.title, @@ -117,7 +84,7 @@ var/time_last_changed_position = 0 var/list/formatted = list() for(var/skin in card_skins) formatted.Add(list(list( - "display_name" = replacetext(skin, " ", " "), + "display_name" = get_skin_desc(skin), "skin" = skin))) return formatted @@ -162,14 +129,13 @@ var/time_last_changed_position = 0 attack_hand(user) //Check if you can't open a new position for a certain job -/obj/machinery/computer/card/proc/job_blacklisted(jobtitle) - return (jobtitle in blacklisted) - +/obj/machinery/computer/card/proc/job_blacklisted(datum/job/job) + return (job.type in blacklisted) //Logic check for Topic() if you can open the job /obj/machinery/computer/card/proc/can_open_job(datum/job/job) if(job) - if(!job_blacklisted(job.title)) + if(!job_blacklisted(job)) if((job.total_positions <= player_list.len * (max_relative_positions / 100))) var/delta = (world.time / 10) - time_last_changed_position if((change_position_cooldown < delta) || (opened_positions[job.title] < 0)) @@ -181,7 +147,7 @@ var/time_last_changed_position = 0 //Logic check for Topic() if you can close the job /obj/machinery/computer/card/proc/can_close_job(datum/job/job) if(job) - if(!job_blacklisted(job.title)) + if(!job_blacklisted(job)) if(job.total_positions > job.current_positions) var/delta = (world.time / 10) - time_last_changed_position if((change_position_cooldown < delta) || (opened_positions[job.title] > 0)) @@ -229,7 +195,7 @@ var/time_last_changed_position = 0 data["civilian_jobs"] = format_jobs(civilian_positions) data["special_jobs"] = format_jobs(whitelisted_positions) data["centcom_jobs"] = format_jobs(get_all_centcom_jobs()) - data["card_skins"] = format_card_skins(card_skins) + data["card_skins"] = format_card_skins(get_station_card_skins()) data["job_slots"] = format_job_slots() @@ -251,14 +217,7 @@ var/time_last_changed_position = 0 "allowed" = (access in modify.access) ? 1 : 0))) data["all_centcom_access"] = all_centcom_access - - var/list/all_centcom_skins = list() - for(var/skin in centcom_card_skins) - all_centcom_skins.Add(list(list( - "display_name" = replacetext(skin, " ", " "), - "skin" = skin))) - - data["all_centcom_skins"] = all_centcom_skins + data["all_centcom_skins"] = format_card_skins(get_centcom_card_skins()) else if (modify) var/list/regions = list() @@ -336,7 +295,7 @@ var/time_last_changed_position = 0 if("skin") var/skin = href_list["skin_target"] - if(is_authenticated() && modify && ((skin in card_skins) || ((skin in centcom_card_skins) && is_centcom()))) + if(is_authenticated() && modify && ((skin in get_station_card_skins()) || ((skin in get_centcom_card_skins()) && is_centcom()))) modify.icon_state = href_list["skin_target"] if ("assign") diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 296ca45debb..6322947feae 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -123,10 +123,16 @@ usr << "It is too far away." /obj/item/weapon/card/id/proc/show(mob/user as mob) + if(!front) + front = new(photo, dir = SOUTH) + if(!side) + side = new(photo, dir = WEST) + user << browse_rsc(front, "front.png") + user << browse_rsc(side, "side.png") var/datum/browser/popup = new(user, "idcard", name, 600, 400) popup.set_content(dat) + popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) popup.open() - return /obj/item/weapon/card/id/attack_self(mob/user as mob) @@ -158,7 +164,8 @@ dat += text("Fingerprint: []
\n", fingerprint_hash) dat += text("Blood Type: []
\n", blood_type) dat += text("DNA Hash: []

\n", dna_hash) - dat += "" + dat +="Photo:
\ + " /obj/item/weapon/card/id/GetAccess() return access @@ -217,6 +224,30 @@ usr << "The card's microscanners activate as you pass it over \the [I], copying its access." src.access |= I.access //Don't copy access if user isn't an antag -- to prevent metagaming +/obj/item/weapon/card/id/syndicate/proc/fake_id_photo(var/mob/living/carbon/human/H, var/side=0)//get_id_photo wouldn't work correctly + if(!istype(H)) + return + var/storedDir = H.dir //don't want to lose track of this + + var/icon/faked + if(!side) + if(!H.equip_to_slot_if_possible(src, slot_l_store, 0, 1)) + H << "You need to empty your pockets before taking the ID picture." + return + + if(side) + H.dir = WEST //ensure the icon is actually the proper direction before copying it + faked = getFlatIcon(H) + H.dir = storedDir //reset the user back to their original direction, not even noticable they changed + H.equip_to_slot_if_possible(src, slot_l_hand, 0, 1) + + else + H.dir = SOUTH + faked = getFlatIcon(H) + H.dir = storedDir + + return faked + /obj/item/weapon/card/id/syndicate/attack_self(mob/user as mob) if(!src.registered_name) var t = reject_bad_name(input(user, "What name would you like to use on this card?", "Agent Card name", ishuman(user) ? user.real_name : user.name)) @@ -242,7 +273,7 @@ if("Show") return ..() if("Edit") - switch(input(user,"What would you like to edit on \the [src]?") in list("Name","Appearance","Sex","Age","Occupation","Money Account","Blood Type","DNA Hash","Fingerprint Hash","Reset Card")) + switch(input(user,"What would you like to edit on \the [src]?") in list("Name","Photo","Appearance","Sex","Age","Occupation","Money Account","Blood Type","DNA Hash","Fingerprint Hash","Reset Card")) if("Name") var/new_name = reject_bad_name(input(user,"What name would you like to put on this card?","Agent Card Name", ishuman(user) ? user.real_name : user.name)) if(!Adjacent(user)) @@ -251,6 +282,16 @@ UpdateName() user << "Name changed to [new_name]." + if("Photo") + if(!Adjacent(user)) + return + photo = fake_id_photo(user) + var/icon/photoside = fake_id_photo(user,1) + front = new(photo) + side = new(photoside) + if(photo && photoside) + user << "Photo changed." + if("Appearance") var/list/appearances = list( "data", @@ -598,3 +639,47 @@ decal_desc = "It's a card with a magnetic strip attached to some circuitry." decal_icon_state = "emag" override_name = 1 + +/proc/get_station_card_skins() + return list("data","id","gold","silver","security","medical","research","engineering","HoS","CMO","RD","CE","clown","mime","prisoner") + +/proc/get_centcom_card_skins() + return list("centcom","centcom_old","ERT_leader","ERT_empty","ERT_security","ERT_engineering","ERT_medical","ERT_janitorial","deathsquad","commander","syndie","TDred","TDgreen") + +/proc/get_all_card_skins() + return get_station_card_skins() + get_centcom_card_skins() + +/proc/get_skin_desc(skin) + switch(skin) + if("id") + return "Standard" + if("HoS") + return "Head of Security" + if("CMO") + return "Chief Medical Officer" + if("RD") + return "Research Director" + if("CE") + return "Chief Engineer" + if("centcom_old") + return "Centcom Old" + if("ERT_leader") + return "ERT Leader" + if("ERT_empty") + return "ERT Default" + if("ERT_security") + return "ERT Security" + if("ERT_engineering") + return "ERT Engineering" + if("ERT_medical") + return "ERT Medical" + if("ERT_janitorial") + return "ERT Janitorial" + if("syndie") + return "Syndicate" + if("TDred") + return "Thunderdome Red" + if("TDgreen") + return "Thunderdome Green" + else + return capitalize(skin) \ No newline at end of file diff --git a/nano/templates/identification_computer.tmpl b/nano/templates/identification_computer.tmpl index 7344e740efd..f6739383633 100644 --- a/nano/templates/identification_computer.tmpl +++ b/nano/templates/identification_computer.tmpl @@ -39,8 +39,8 @@ {{for data.job_slots}}
{{:value.title}}: {{:value.current_positions}}/{{:value.total_positions}} - {{:helper.link('', 'minus', {'choice' : 'make_job_unavailable', 'job' : value.title}, value.can_close == 1 && data.authenticated ? null : 'disabled')}} - {{:helper.link('', 'plus', {'choice' : 'make_job_available', 'job' : value.title}, value.can_open == 1 && data.authenticated ? null : 'disabled')}} + {{:helper.link('-', null, {'choice' : 'make_job_unavailable', 'job' : value.title}, value.can_close == 1 && data.authenticated ? null : 'disabled')}} + {{:helper.link('+', null, {'choice' : 'make_job_available', 'job' : value.title}, value.can_open == 1 && data.authenticated ? null : 'disabled')}}
{{/for}}