diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index 0bce785f6d..3f894ebccc 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -194,6 +194,9 @@ #define O_LIVER "liver" #define O_KIDNEYS "kidneys" #define O_APPENDIX "appendix" +#define O_VOICE "voicebox" + +// Non-Standard organs #define O_PLASMA "plasma vessel" #define O_HIVE "hive node" #define O_NUTRIENT "nutrient vessel" diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm index f3f3e8d088..f12b630979 100644 --- a/code/__defines/species_languages.dm +++ b/code/__defines/species_languages.dm @@ -50,7 +50,7 @@ #define LANGUAGE_MINBUS "Minbus" #define LANGUAGE_EVENT1 "Occursus" #define LANGUAGE_AKHANI "Akhani" -#define LANGUAGE_SIIK_ALAI "Siik'alai" +#define LANGUAGE_ALAI "Alai" // Language flags. #define WHITELISTED 1 // Language is available if the speaker is whitelisted. diff --git a/code/controllers/subsystems/planets.dm b/code/controllers/subsystems/planets.dm index 2bb09050f4..a163a3b1e7 100644 --- a/code/controllers/subsystems/planets.dm +++ b/code/controllers/subsystems/planets.dm @@ -56,13 +56,14 @@ SUBSYSTEM_DEF(planets) P.planet_floors -= T else P.planet_walls -= T + T.vis_contents -= P.weather_holder.visuals /datum/controller/subsystem/planets/proc/allocateTurfs(var/initial = FALSE) var/list/currentlist = new_outdoor_turfs while(currentlist.len) var/turf/simulated/OT = currentlist[currentlist.len] currentlist.len-- - if(istype(OT) && z_to_planet[OT.z]) + if(istype(OT) && OT.outdoors && z_to_planet.len >= OT.z && z_to_planet[OT.z]) var/datum/planet/P = z_to_planet[OT.z] P.planet_floors |= OT OT.vis_contents |= P.weather_holder.visuals @@ -73,7 +74,7 @@ SUBSYSTEM_DEF(planets) while(currentlist.len) var/turf/unsimulated/wall/planetary/PW = currentlist[currentlist.len] currentlist.len-- - if(istype(PW) && z_to_planet[PW.z]) + if(istype(PW) && z_to_planet.len >= PW.z && z_to_planet[PW.z]) var/datum/planet/P = z_to_planet[PW.z] P.planet_walls |= PW if(!initial && MC_TICK_CHECK) @@ -113,9 +114,9 @@ SUBSYSTEM_DEF(planets) while(currentrun.len) var/datum/planet/P = currentrun[currentrun.len] currentrun.len-- - + P.process(last_fire) - + //Sun light needs changing if(P.needs_work & PLANET_PROCESS_SUN) P.needs_work &= ~PLANET_PROCESS_SUN diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index b665465084..765e1ee9e9 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -84,10 +84,8 @@ for(var/mob/living/silicon/robot/robot in mob_list) // No combat/syndicate cyborgs, no drones. - if(robot.module && robot.module.hide_on_manifest) - continue - - bot[robot.name] = "[robot.modtype] [robot.braintype]" + if(!robot.scrambledcodes && !(robot.module && robot.module.hide_on_manifest)) + bot[robot.name] = "[robot.modtype] [robot.braintype]" if(heads.len > 0) diff --git a/code/defines/obj.dm b/code/defines/obj.dm index ba809cb977..f2cec96aab 100644 --- a/code/defines/obj.dm +++ b/code/defines/obj.dm @@ -144,7 +144,7 @@ var/global/list/PDA_Manifest = list() for(var/mob/living/silicon/robot/robot in mob_list) // No combat/syndicate cyborgs, no drones. - if(robot.module && robot.module.hide_on_manifest) + if(!robot.scrambledcodes && !(robot.module && robot.module.hide_on_manifest)) continue bot[++bot.len] = list("name" = robot.real_name, "rank" = "[robot.modtype] [robot.braintype]", "active" = "Active") diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm index 484ff8ea33..7496551c25 100644 --- a/code/game/antagonist/antagonist.dm +++ b/code/game/antagonist/antagonist.dm @@ -79,7 +79,9 @@ Think through your actions and make the roleplay immersive! Please remember all \ rules aside from those without explicit exceptions apply to antagonists." - var/can_use_aooc = TRUE // If true, will be given the AOOC verb, along with the ability to use it. +// var/can_use_aooc = TRUE // If true, will be given the AOOC verb, along with the ability to use it. + var/can_hear_aooc = TRUE // If FALSE, the antag can neither speak nor hear AOOC. If TRUE, they can at least hear it. + var/can_speak_aooc = TRUE // If TRUE, the antag can freely spean in AOOC. /datum/antagonist/New() ..() diff --git a/code/game/antagonist/antagonist_add.dm b/code/game/antagonist/antagonist_add.dm index 67eb7e2e72..d5fa2c1fe6 100644 --- a/code/game/antagonist/antagonist_add.dm +++ b/code/game/antagonist/antagonist_add.dm @@ -36,7 +36,7 @@ and it otherwise has no bearing on your round." player.current.verbs |= /mob/living/proc/write_ambition - if(can_use_aooc) + if(can_speak_aooc) player.current.client.verbs += /client/proc/aooc // Handle only adding a mind and not bothering with gear etc. diff --git a/code/game/antagonist/outsider/ert.dm b/code/game/antagonist/outsider/ert.dm index c1aec2bcf8..245296084c 100644 --- a/code/game/antagonist/outsider/ert.dm +++ b/code/game/antagonist/outsider/ert.dm @@ -25,7 +25,8 @@ var/datum/antagonist/ert/ert initial_spawn_req = 5 initial_spawn_target = 7 - can_use_aooc = FALSE // They're the good guys. + can_hear_aooc = FALSE // They're the good guys. + can_speak_aooc = FALSE // Just in case the above var bugs, or gets touched. /datum/antagonist/ert/create_default(var/mob/source) var/mob/living/carbon/human/M = ..() diff --git a/code/game/antagonist/outsider/trader.dm b/code/game/antagonist/outsider/trader.dm index 9603b49523..69af3883b9 100644 --- a/code/game/antagonist/outsider/trader.dm +++ b/code/game/antagonist/outsider/trader.dm @@ -24,7 +24,7 @@ var/datum/antagonist/trader/traders initial_spawn_req = 5 initial_spawn_target = 7 - can_use_aooc = FALSE // They're not real antags. + can_speak_aooc = FALSE // They're not real antags. /datum/antagonist/trader/create_default(var/mob/source) var/mob/living/carbon/human/M = ..() diff --git a/code/game/antagonist/station/renegade.dm b/code/game/antagonist/station/renegade.dm index 6f7ec89322..3e8afae32d 100644 --- a/code/game/antagonist/station/renegade.dm +++ b/code/game/antagonist/station/renegade.dm @@ -17,7 +17,7 @@ var/datum/antagonist/renegade/renegades Think through your actions and make the roleplay immersive! Please remember all \ rules aside from those without explicit exceptions apply to antagonists." flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE - can_use_aooc = FALSE + can_speak_aooc = FALSE // They aren't 'true' antags, but they still need to hear blanket antag instructions hard_cap = 8 hard_cap_round = 12 @@ -61,8 +61,6 @@ var/datum/antagonist/renegade/renegades list(/obj/item/weapon/gun/projectile/luger,/obj/item/weapon/gun/projectile/luger/brown) ) - can_use_aooc = FALSE // They aren't 'true' antags. - /datum/antagonist/renegade/New() ..() renegades = src diff --git a/code/game/antagonist/station/thug.dm b/code/game/antagonist/station/thug.dm index 8810fca7d0..61d92e1646 100644 --- a/code/game/antagonist/station/thug.dm +++ b/code/game/antagonist/station/thug.dm @@ -15,4 +15,4 @@ var/datum/antagonist/thug/thugs Think through your actions and make the roleplay immersive! Please remember all \ rules aside from those with explicit exceptions apply to antagonists." flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE - can_use_aooc = FALSE + can_speak_aooc = FALSE diff --git a/code/game/antagonist/station/traitor.dm b/code/game/antagonist/station/traitor.dm index d0a1f54ed2..3681cf236d 100644 --- a/code/game/antagonist/station/traitor.dm +++ b/code/game/antagonist/station/traitor.dm @@ -5,7 +5,7 @@ var/datum/antagonist/traitor/traitors id = MODE_TRAITOR protected_jobs = list("Security Officer", "Warden", "Detective", "Internal Affairs Agent", "Head of Security", "Colony Director") flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE - can_use_aooc = FALSE + can_speak_aooc = FALSE // If they want to plot and plan as this sort of traitor, they'll need to do it ICly. /datum/antagonist/traitor/auto id = MODE_AUTOTRAITOR diff --git a/code/game/gamemodes/changeling/absorbed_dna.dm b/code/game/gamemodes/changeling/absorbed_dna.dm index 3c23f0270c..26d433cd8c 100644 --- a/code/game/gamemodes/changeling/absorbed_dna.dm +++ b/code/game/gamemodes/changeling/absorbed_dna.dm @@ -5,12 +5,14 @@ var/list/languages var/identifying_gender var/list/flavour_texts + var/list/genMods -/datum/absorbed_dna/New(var/newName, var/newDNA, var/newSpecies, var/newLanguages, var/newIdentifying_Gender, var/list/newFlavour) +/datum/absorbed_dna/New(var/newName, var/newDNA, var/newSpecies, var/newLanguages, var/newIdentifying_Gender, var/list/newFlavour, var/list/newGenMods) ..() name = newName dna = newDNA speciesName = newSpecies languages = newLanguages identifying_gender = newIdentifying_Gender - flavour_texts = newFlavour ? newFlavour.Copy() : null \ No newline at end of file + flavour_texts = newFlavour ? newFlavour.Copy() : null + genMods = newGenMods ? newGenMods.Copy() : null \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm index f76fd5ca47..45b230b00c 100644 --- a/code/game/gamemodes/changeling/powers/absorb.dm +++ b/code/game/gamemodes/changeling/powers/absorb.dm @@ -78,7 +78,7 @@ src << "We can now re-adapt, reverting our evolution so that we may start anew, if needed." - var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages, T.identifying_gender, T.flavor_texts) + var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages, T.identifying_gender, T.flavor_texts, T.modifiers) absorbDNA(newDNA) if(T.mind && T.mind.changeling) diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm index 9225792575..6dd16061a1 100644 --- a/code/game/gamemodes/changeling/powers/transform.dm +++ b/code/game/gamemodes/changeling/powers/transform.dm @@ -48,6 +48,13 @@ src.UpdateAppearance() domutcheck(src, null) changeling_update_languages(changeling.absorbed_languages) + if(chosen_dna.genMods) + var/mob/living/carbon/human/self = src + for(var/datum/modifier/mod in self.modifiers) + self.modifiers.Remove(mod.type) + + for(var/datum/modifier/mod in chosen_dna.genMods) + self.modifiers.Add(mod.type) src.verbs -= /mob/proc/changeling_transform spawn(10) diff --git a/code/game/jobs/job/civilian_chaplain.dm b/code/game/jobs/job/civilian_chaplain.dm index 2eece781ec..e24e462fdf 100644 --- a/code/game/jobs/job/civilian_chaplain.dm +++ b/code/game/jobs/job/civilian_chaplain.dm @@ -149,5 +149,7 @@ feedback_set_details("religion_book","[new_book_style]") return 1 +/* If you uncomment this, every time the mob preview updates it makes a new PDA. It seems to work just fine and display without it, so why this exists, haven't a clue. -Hawk /datum/job/chaplain/equip_preview(var/mob/living/carbon/human/H, var/alt_title) return equip(H, alt_title, FALSE) +*/ diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index 04dbaffb53..bfc964f7f2 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -378,7 +378,8 @@ var/global/datum/controller/occupations/job_master H.amend_exploitable(G.path) if(G.slot == "implant") - H.implant_loadout(G) + var/obj/item/weapon/implant/I = G.spawn_item(H) + I.implant_loadout(H) continue if(G.slot && !(G.slot in custom_equip_slots)) diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index 08f369d735..dc4bf5146a 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -31,6 +31,7 @@ GLOBAL_LIST_BOILERPLATE(all_portals, /obj/effect/portal) return /obj/effect/portal/New() + ..() // Necessary for the list boilerplate to work spawn(300) qdel(src) return diff --git a/code/game/objects/items/poi_items.dm b/code/game/objects/items/poi_items.dm index 85a8b27854..394212e4c4 100644 --- a/code/game/objects/items/poi_items.dm +++ b/code/game/objects/items/poi_items.dm @@ -52,8 +52,9 @@ /obj/structure/largecrate/animal/crashedshuttle name = "SCP" + /obj/structure/largecrate/animal/crashedshuttle/initialize() - starts_with = pick(/mob/living/simple_animal/hostile/statue, /obj/item/cursed_marble) + starts_with = pick(/mob/living/simple_animal/hostile/statue, /obj/item/cursed_marble, /obj/item/weapon/deadringer) name = pick("Spicy Crust Pizzeria", "Soap and Care Products", "Sally's Computer Parts", "Steve's Chocolate Pastries", "Smith & Christian's Plastics","Standard Containers & Packaging Co.", "Sanitary Chemical Purgation (LTD)") name += " delivery crate" return ..() diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 5c17634ae2..18b13a8034 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -199,3 +199,9 @@ throw_range = 20 flags = 0 no_variants = FALSE + +/obj/item/stack/tile/roofing + name = "roofing" + singular_name = "roofing" + desc = "A section of roofing material. You can use it to repair the ceiling, or expand it." + icon_state = "techtile_grid" \ No newline at end of file diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index 58aa30547d..d9543fed20 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -153,7 +153,7 @@ return 0 if(build_turf) - T.ChangeTurf(build_turf) + T.ChangeTurf(build_turf, preserve_outdoors = TRUE) else if(build_other) new build_other(T) else diff --git a/code/game/objects/items/weapons/autopsy.dm b/code/game/objects/items/weapons/autopsy.dm index d9606d28d2..7cddfd1efc 100644 --- a/code/game/objects/items/weapons/autopsy.dm +++ b/code/game/objects/items/weapons/autopsy.dm @@ -167,21 +167,24 @@ if(!istype(M)) return 0 + if (user.a_intent == I_HELP) + return ..() + if(target_name != M.name) target_name = M.name src.wdata = list() src.chemtraces = list() src.timeofdeath = null - user << "A new patient has been registered. Purging data for previous patient." + to_chat(user, "A new patient has been registered. Purging data for previous patient.") src.timeofdeath = M.timeofdeath var/obj/item/organ/external/S = M.get_organ(user.zone_sel.selecting) if(!S) - usr << "You can't scan this body part." + to_chat(user, "You can't scan this body part.") return if(!S.open) - usr << "You have to cut [S] open first!" + to_chat(user, "You have to cut [S] open first!") return M.visible_message("\The [user] scans the wounds on [M]'s [S.name] with [src]") diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index 02e4cd48c4..f5bd38dcc1 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -21,12 +21,26 @@ /obj/item/weapon/implant/proc/activate() return - // What does the implant do upon injection? - // return 0 if the implant fails (ex. Revhead and loyalty implant.) - // return 1 if the implant succeeds (ex. Nonrevhead and loyalty implant.) -/obj/item/weapon/implant/proc/implanted(var/mob/source) +// Moves the implant where it needs to go, and tells it if there's more to be done in post_implant +/obj/item/weapon/implant/proc/handle_implant(var/mob/source, var/target_zone = BP_TORSO) + . = TRUE + imp_in = source + implanted = TRUE + if(ishuman(source)) + var/mob/living/carbon/human/H = source + var/obj/item/organ/external/affected = H.get_organ(target_zone) + if(affected) + affected.implants += src + part = affected + if(part) + forceMove(part) + else + forceMove(source) + listening_objects |= src - return 1 + +// Takes place after handle_implant, if that returns TRUE +/obj/item/weapon/implant/proc/post_implant(var/mob/source) /obj/item/weapon/implant/proc/get_data() return "No information available" @@ -49,6 +63,12 @@ icon_state = "implant_melted" malfunction = MALFUNCTION_PERMANENT +/obj/item/weapon/implant/proc/implant_loadout(var/mob/living/carbon/human/H) + if(H) + var/obj/item/organ/external/affected = H.organs_by_name[BP_HEAD] + if(handle_implant(H, affected)) + post_implant(H) + /obj/item/weapon/implant/Destroy() if(part) part.implants.Remove(src) @@ -69,6 +89,11 @@ else ..() + + +////////////////////////////// +// Tracking Implant +////////////////////////////// GLOBAL_LIST_BOILERPLATE(all_tracking_implants, /obj/item/weapon/implant/tracking) /obj/item/weapon/implant/tracking @@ -84,9 +109,8 @@ GLOBAL_LIST_BOILERPLATE(all_tracking_implants, /obj/item/weapon/implant/tracking id = rand(1, 1000) ..() -/obj/item/weapon/implant/tracking/implanted(var/mob/source) +/obj/item/weapon/implant/tracking/post_implant(var/mob/source) processing_objects.Add(src) - return 1 /obj/item/weapon/implant/tracking/Destroy() processing_objects.Remove(src) @@ -142,7 +166,9 @@ Implant Specifics:
"} spawn(delay) malfunction-- - +////////////////////////////// +// Death Explosive Implant +////////////////////////////// /obj/item/weapon/implant/dexplosive name = "explosive" desc = "And boom goes the weasel." @@ -177,7 +203,9 @@ Implant Specifics:
"} /obj/item/weapon/implant/dexplosive/islegal() return 0 -//BS12 Explosive +////////////////////////////// +// Explosive Implant +////////////////////////////// /obj/item/weapon/implant/explosive name = "explosive implant" desc = "A military grade micro bio-explosive. Highly dangerous." @@ -249,15 +277,13 @@ Implant Specifics:
"} if(t) t.hotspot_expose(3500,125) -/obj/item/weapon/implant/explosive/implanted(mob/source as mob) +/obj/item/weapon/implant/explosive/post_implant(mob/source as mob) elevel = alert("What sort of explosion would you prefer?", "Implant Intent", "Localized Limb", "Destroy Body", "Full Explosion") phrase = input("Choose activation phrase:") as text var/list/replacechars = list("'" = "","\"" = "",">" = "","<" = "","(" = "",")" = "") phrase = replace_characters(phrase, replacechars) usr.mind.store_memory("Explosive implant in [source] can be activated by saying something containing the phrase ''[src.phrase]'', say [src.phrase] to attempt to activate.", 0, 0) usr << "The implanted explosive implant in [source] can be activated by saying something containing the phrase ''[src.phrase]'', say [src.phrase] to attempt to activate." - listening_objects |= src - return 1 /obj/item/weapon/implant/explosive/emp_act(severity) if (malfunction) @@ -311,6 +337,9 @@ Implant Specifics:
"} explosion(get_turf(imp_in), -1, -1, 1, 3) qdel(src) +////////////////////////////// +// Chemical Implant +////////////////////////////// GLOBAL_LIST_BOILERPLATE(all_chem_implants, /obj/item/weapon/implant/chem) /obj/item/weapon/implant/chem @@ -336,20 +365,17 @@ Can only be loaded while still in its original case.
the implant may become unstable and either pre-maturely inject the subject or simply break."} return dat - /obj/item/weapon/implant/chem/New() ..() var/datum/reagents/R = new/datum/reagents(50) reagents = R R.my_atom = src - /obj/item/weapon/implant/chem/trigger(emote, source as mob) if(emote == "deathgasp") src.activate(src.reagents.total_volume) return - /obj/item/weapon/implant/chem/activate(var/cause) if((!cause) || (!src.imp_in)) return 0 var/mob/living/carbon/R = src.imp_in @@ -384,6 +410,9 @@ the implant may become unstable and either pre-maturely inject the subject or si spawn(20) malfunction-- +////////////////////////////// +// Loyalty Implant +////////////////////////////// /obj/item/weapon/implant/loyalty name = "loyalty implant" desc = "Makes you loyal or such." @@ -401,20 +430,24 @@ the implant may become unstable and either pre-maturely inject the subject or si Integrity: Implant will last so long as the nanobots are inside the bloodstream."} return dat - -/obj/item/weapon/implant/loyalty/implanted(mob/M) - if(!istype(M, /mob/living/carbon/human)) return 0 +/obj/item/weapon/implant/loyalty/handle_implant(mob/M, target_zone = BP_TORSO) + . = ..(M, target_zone) + if(!istype(M, /mob/living/carbon/human)) + . = FALSE var/mob/living/carbon/human/H = M var/datum/antagonist/antag_data = get_antag_data(H.mind.special_role) if(antag_data && (antag_data.flags & ANTAG_IMPLANT_IMMUNE)) H.visible_message("[H] seems to resist the implant!", "You feel the corporate tendrils of [using_map.company_name] try to invade your mind!") - return 0 - else - clear_antag_roles(H.mind, 1) - H << "You feel a surge of loyalty towards [using_map.company_name]." - return 1 + . = FALSE +/obj/item/weapon/implant/loyalty/post_implant(mob/M) + var/mob/living/carbon/human/H = M + clear_antag_roles(H.mind, 1) + to_chat(H, "You feel a surge of loyalty towards [using_map.company_name].") +////////////////////////////// +// Adrenaline Implant +////////////////////////////// /obj/item/weapon/implant/adrenalin name = "adrenalin" desc = "Removes all stuns and knockdowns." @@ -445,14 +478,13 @@ the implant may become unstable and either pre-maturely inject the subject or si return - -/obj/item/weapon/implant/adrenalin/implanted(mob/source) +/obj/item/weapon/implant/adrenalin/post_implant(mob/source) source.mind.store_memory("A implant can be activated by using the pale emote, say *pale to attempt to activate.", 0, 0) source << "The implanted freedom implant can be activated by using the pale emote, say *pale to attempt to activate." - listening_objects |= src - return 1 - +////////////////////////////// +// Death Alarm Implant +////////////////////////////// /obj/item/weapon/implant/death_alarm name = "death alarm implant" desc = "An alarm which monitors host vital signs and transmits a radio message upon death." @@ -529,11 +561,13 @@ the implant may become unstable and either pre-maturely inject the subject or si spawn(20) malfunction-- -/obj/item/weapon/implant/death_alarm/implanted(mob/source as mob) +/obj/item/weapon/implant/death_alarm/post_implant(mob/source as mob) mobname = source.real_name processing_objects.Add(src) - return 1 +////////////////////////////// +// Compressed Matter Implant +////////////////////////////// /obj/item/weapon/implant/compressed name = "compressed matter implant" desc = "Based on compressed matter technology, can store a single item." @@ -571,13 +605,12 @@ the implant may become unstable and either pre-maturely inject the subject or si scanned.loc = t qdel(src) -/obj/item/weapon/implant/compressed/implanted(mob/source as mob) +/obj/item/weapon/implant/compressed/post_implant(mob/source) src.activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") if (source.mind) source.mind.store_memory("Compressed matter implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", 0, 0) source << "The implanted compressed matter implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate." - listening_objects |= src - return 1 + /obj/item/weapon/implant/compressed/islegal() return 0 diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm index 44b33721cf..c05d52442c 100644 --- a/code/game/objects/items/weapons/implants/implantchair.dm +++ b/code/game/objects/items/weapons/implants/implantchair.dm @@ -135,10 +135,9 @@ for (var/mob/O in viewers(M, null)) O.show_message("\The [M] has been implanted by \the [src].", 1) - if(imp.implanted(M)) - imp.loc = M - imp.imp_in = M - imp.implanted = 1 + if(imp.handle_implant(M, BP_TORSO)) + imp.post_implant(M) + implant_list -= imp break return diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm index 8052b19de6..fcfd67bb6a 100644 --- a/code/game/objects/items/weapons/implants/implanter.dm +++ b/code/game/objects/items/weapons/implants/implanter.dm @@ -56,16 +56,11 @@ add_attack_logs(user,M,"Implanted with [imp.name] using [name]") - if(src.imp.implanted(M)) - src.imp.loc = M - src.imp.imp_in = M - src.imp.implanted = 1 - if (ishuman(M)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting) - affected.implants += src.imp - imp.part = affected + if(imp.handle_implant(M)) + imp.post_implant(M) + if(ishuman(M)) + var/mob/living/carbon/human/H = M BITSET(H.hud_updateflag, IMPLOYAL_HUD) src.imp = null diff --git a/code/game/objects/items/weapons/implants/implantfreedom.dm b/code/game/objects/items/weapons/implants/implantfreedom.dm index 92021a46a2..fab692775d 100644 --- a/code/game/objects/items/weapons/implants/implantfreedom.dm +++ b/code/game/objects/items/weapons/implants/implantfreedom.dm @@ -16,7 +16,9 @@ /obj/item/weapon/implant/freedom/trigger(emote, mob/living/carbon/source as mob) - if (src.uses < 1) return 0 + if (src.uses < 1) + return 0 + if (emote == src.activation_emote) src.uses-- source << "You feel a faint click." @@ -46,13 +48,9 @@ W.layer = initial(W.layer) return - -/obj/item/weapon/implant/freedom/implanted(mob/living/carbon/source) +/obj/item/weapon/implant/freedom/post_implant(mob/source) source.mind.store_memory("Freedom implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", 0, 0) source << "The implanted freedom implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate." - listening_objects |= src - return 1 - /obj/item/weapon/implant/freedom/get_data() var/dat = {" diff --git a/code/game/objects/items/weapons/implants/implantlanguage.dm b/code/game/objects/items/weapons/implants/implantlanguage.dm index d813a8d388..7c6e33508b 100644 --- a/code/game/objects/items/weapons/implants/implantlanguage.dm +++ b/code/game/objects/items/weapons/implants/implantlanguage.dm @@ -4,7 +4,26 @@ /obj/item/weapon/implant/language name = "GalCom language implant" - desc = "An implant allowing someone to speak and hear the range of frequencies used in Galactic Common, as well as produce any phonemes that they usually cannot. Only helps with hearing and producing sounds, not understanding them." + desc = "An implant allowing someone to speak the range of frequencies used in Galactic Common, as well as produce any phonemes that they usually cannot. Only helps with producing sounds, not understanding them." + var/list/languages = list(LANGUAGE_GALCOM) // List of languages that this assists with + +/obj/item/weapon/implant/language/post_implant(mob/M) // Amends the mob's voice organ, then deletes itself + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/voicebox/V = locate() in H.internal_organs + if(V) + var/list/need_amend = list() // If they've already got all the languages they need, then they don't need this implant to do anything + for(var/L in languages) + if(L in V.will_assist_languages) + continue + else + need_amend |= L + if(LAZYLEN(need_amend)) + if(V.robotic < ORGAN_ASSISTED) + V.mechassist() + for(var/L in need_amend) + V.add_assistable_langs(L) + qdel_null(src) /obj/item/weapon/implant/language/get_data() var/dat = {" @@ -14,16 +33,19 @@ Important Notes: Affects hearing and speech.

Implant Details:
-Function: Allows a being otherwise incapable to both hear the frequencies Galactic Common is generally spoken at, as well as to produce the phonemes of the language.
+Function: Allows a being otherwise incapable of speaking Galactic Common to produce the phonemes of the language.
Special Features: None.
Integrity: Implant will function for expected life, barring physical damage."} return dat + +// EAL Implant /obj/item/weapon/implant/language/eal name = "EAL language implant" - desc = "An implant allowing an organic to both hear and speak Encoded Audio Language accurately. Only helps with hearing and producing sounds, not understanding them." + desc = "An implant allowing an organic to speak Encoded Audio Language passably. Only helps with producing sounds, not understanding them." + languages = list(LANGUAGE_EAL) -/obj/item/weapon/implant/language/get_data() +/obj/item/weapon/implant/language/eal/get_data() var/dat = {" Implant Specifications:
Name: Vey-Med L-2 Encoded Audio Language Implant
@@ -31,7 +53,25 @@ Important Notes: Affects hearing and speech.

Implant Details:
-Function: Allows an organic to accurately process and speak Encoded Audio Language.
+Function: Allows an organic to accurately speak Encoded Audio Language.
+Special Features: None.
+Integrity: Implant will function for expected life, barring physical damage."} + return dat + +/obj/item/weapon/implant/language/skrellian + name = "Skrellian language implant" + desc = "An implant allowing someone to speak the range of frequencies used in Skrellian, as well as produce any phonemes that they usually cannot. Only helps with hearing and producing sounds, not understanding them." + languages = list(LANGUAGE_SKRELLIAN) + +/obj/item/weapon/implant/language/skrellian/get_data() + var/dat = {" +Implant Specifications:
+Name: Vey-Med L-1 Galactic Common Implant
+Life: 5 years
+Important Notes: Affects hearing and speech.
+
+Implant Details:
+Function: Allows a being otherwise incapable of speaking Skrellian to produce the phonemes of the language.
Special Features: None.
Integrity: Implant will function for expected life, barring physical damage."} return dat \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implantuplink.dm b/code/game/objects/items/weapons/implants/implantuplink.dm index 644ebf1bb7..82809cfe61 100644 --- a/code/game/objects/items/weapons/implants/implantuplink.dm +++ b/code/game/objects/items/weapons/implants/implantuplink.dm @@ -11,15 +11,13 @@ ..() return -/obj/item/weapon/implant/uplink/implanted(mob/source) +/obj/item/weapon/implant/uplink/post_implant(mob/source) + listening_objects |= src activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") source.mind.store_memory("Uplink implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", 0, 0) source << "The implanted uplink implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate." - listening_objects |= src - return 1 - /obj/item/weapon/implant/uplink/trigger(emote, mob/source as mob) if(hidden_uplink && usr == source) // Let's not have another people activate our uplink hidden_uplink.check_trigger(source, emote, activation_emote) - return + return \ No newline at end of file diff --git a/code/game/objects/items/weapons/mop.dm b/code/game/objects/items/weapons/mop.dm index 54f344eae1..0cfdd4792d 100644 --- a/code/game/objects/items/weapons/mop.dm +++ b/code/game/objects/items/weapons/mop.dm @@ -16,6 +16,7 @@ GLOBAL_LIST_BOILERPLATE(all_mops, /obj/item/weapon/mop) /obj/item/weapon/mop/New() create_reagents(30) + ..() /obj/item/weapon/mop/afterattack(atom/A, mob/user, proximity) if(!proximity) return diff --git a/code/game/objects/items/weapons/policetape.dm b/code/game/objects/items/weapons/policetape.dm index 43183d45f4..aec6a790b2 100644 --- a/code/game/objects/items/weapons/policetape.dm +++ b/code/game/objects/items/weapons/policetape.dm @@ -4,6 +4,9 @@ icon = 'icons/policetape.dmi' icon_state = "tape" w_class = ITEMSIZE_SMALL + + toolspeed = 3 //You can use it in surgery. It's stupid, but you can. + var/turf/start var/turf/end var/tape_type = /obj/item/tape diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index e4482932b1..51b1c50274 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -86,7 +86,6 @@ /obj/item/weapon/weldingtool, /obj/item/weapon/crowbar, /obj/item/weapon/wirecutters, - /obj/item/device/t_scanner ) /obj/item/weapon/storage/belt/utility/chief diff --git a/code/game/objects/items/weapons/tape.dm b/code/game/objects/items/weapons/tape.dm index 5a57515588..e3afddba4c 100644 --- a/code/game/objects/items/weapons/tape.dm +++ b/code/game/objects/items/weapons/tape.dm @@ -5,8 +5,12 @@ icon_state = "taperoll" w_class = ITEMSIZE_TINY + toolspeed = 2 //It is now used in surgery as a not awful, but probably dangerous option, due to speed. + /obj/item/weapon/tape_roll/attack(var/mob/living/carbon/human/H, var/mob/user) if(istype(H)) + if(user.a_intent == I_HELP) + return var/can_place = 0 if(istype(user, /mob/living/silicon/robot)) can_place = 1 diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm index 6923728564..4c1bc63618 100644 --- a/code/game/objects/structures/janicart.dm +++ b/code/game/objects/structures/janicart.dm @@ -20,6 +20,7 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart) /obj/structure/janitorialcart/New() create_reagents(300) + ..() /obj/structure/janitorialcart/examine(mob/user) diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index e156588937..1c74b467e2 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -12,6 +12,7 @@ nitrogen = MOLES_N2STANDARD var/to_be_destroyed = 0 //Used for fire, if a melting temperature was reached, it will be destroyed var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to + var/can_dirty = TRUE // If false, tile never gets dirty var/dirt = 0 // This is not great. @@ -65,12 +66,13 @@ tracks.AddTracks(bloodDNA,comingdir,goingdir,bloodcolor) /turf/simulated/proc/update_dirt() - dirt = min(dirt+1, 101) - var/obj/effect/decal/cleanable/dirt/dirtoverlay = locate(/obj/effect/decal/cleanable/dirt, src) - if (dirt > 50) - if (!dirtoverlay) - dirtoverlay = new/obj/effect/decal/cleanable/dirt(src) - dirtoverlay.alpha = min((dirt - 50) * 5, 255) + if(can_dirty) + dirt = min(dirt+1, 101) + var/obj/effect/decal/cleanable/dirt/dirtoverlay = locate(/obj/effect/decal/cleanable/dirt, src) + if (dirt > 50) + if (!dirtoverlay) + dirtoverlay = new/obj/effect/decal/cleanable/dirt(src) + dirtoverlay.alpha = min((dirt - 50) * 5, 255) /turf/simulated/Entered(atom/A, atom/OL) if(movement_disabled && usr.ckey != movement_disabled_exception) @@ -82,8 +84,9 @@ if(M.lying) return ..() - // Dirt overlays. - update_dirt() + if(M.dirties_floor()) + // Dirt overlays. + update_dirt() if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M diff --git a/code/game/turfs/simulated/floor_attackby.dm b/code/game/turfs/simulated/floor_attackby.dm index 91371e7beb..57d51dbaea 100644 --- a/code/game/turfs/simulated/floor_attackby.dm +++ b/code/game/turfs/simulated/floor_attackby.dm @@ -9,6 +9,50 @@ attack_tile(C, L) // Be on help intent if you want to decon something. return + if(istype(C, /obj/item/stack/tile/roofing)) + var/expended_tile = FALSE // To track the case. If a ceiling is built in a multiz zlevel, it also necessarily roofs it against weather + var/turf/T = GetAbove(src) + var/obj/item/stack/tile/roofing/R = C + + // Patch holes in the ceiling + if(T) + if(istype(T, /turf/simulated/open) || istype(T, /turf/space)) + // Must be build adjacent to an existing floor/wall, no floating floors + var/list/cardinalTurfs = list() // Up a Z level + for(var/dir in cardinal) + var/turf/B = get_step(T, dir) + if(B) + cardinalTurfs += B + + var/turf/simulated/A = locate(/turf/simulated/floor) in cardinalTurfs + if(!A) + A = locate(/turf/simulated/wall) in cardinalTurfs + if(!A) + to_chat(user, "There's nothing to attach the ceiling to!") + return + + if(R.use(1)) // Cost of roofing tiles is 1:1 with cost to place lattice and plating + T.ReplaceWithLattice() + T.ChangeTurf(/turf/simulated/floor, preserve_outdoors = TRUE) + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + user.visible_message("[user] patches a hole in the ceiling.", "You patch a hole in the ceiling.") + expended_tile = TRUE + else + to_chat(user, "There aren't any holes in the ceiling to patch here.") + return + + // Create a ceiling to shield from the weather + if(src.outdoors) + for(var/dir in cardinal) + var/turf/A = get_step(src, dir) + if(A && !A.outdoors) + if(expended_tile || R.use(1)) + make_indoors() + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + user.visible_message("[user] roofs a tile, shielding it from the elements.", "You roof this tile, shielding it from the elements.") + break + return + if(flooring) if(istype(C, /obj/item/weapon)) try_deconstruct_tile(C, user) diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm index 1eaca16e76..73a56e8949 100644 --- a/code/game/turfs/simulated/wall_attacks.dm +++ b/code/game/turfs/simulated/wall_attacks.dm @@ -84,16 +84,16 @@ if(rotting) if(reinf_material) - user << "\The [reinf_material.display_name] feels porous and crumbly." + to_chat(user, "\The [reinf_material.display_name] feels porous and crumbly.") else - user << "\The [material.display_name] crumbles under your touch!" + to_chat(user, "\The [material.display_name] crumbles under your touch!") dismantle_wall() return 1 if(..()) return 1 if(!can_open) - user << "You push the wall, but nothing happens." + to_chat(user, "You push the wall, but nothing happens.") playsound(src, 'sound/weapons/Genhit.ogg', 25, 1) else toggle_open(user) @@ -138,28 +138,57 @@ user.setClickCooldown(user.get_attack_speed(W)) if (!user.) - user << "You don't have the dexterity to do this!" + to_chat(user, "You don't have the dexterity to do this!") return //get the user's location - if(!istype(user.loc, /turf)) return //can't do this stuff whilst inside objects and such + if(!istype(user.loc, /turf)) + return //can't do this stuff whilst inside objects and such if(W) radiate() if(is_hot(W)) burn(is_hot(W)) + if(istype(W, /obj/item/stack/tile/roofing)) + var/expended_tile = FALSE // To track the case. If a ceiling is built in a multiz zlevel, it also necessarily roofs it against weather + var/turf/T = GetAbove(src) + var/obj/item/stack/tile/roofing/R = W + + // Place plating over a wall + if(T) + if(istype(T, /turf/simulated/open) || istype(T, /turf/space)) + if(R.use(1)) // Cost of roofing tiles is 1:1 with cost to place lattice and plating + T.ReplaceWithLattice() + T.ChangeTurf(/turf/simulated/floor, preserve_outdoors = TRUE) + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + user.visible_message("[user] patches a hole in the ceiling.", "You patch a hole in the ceiling.") + expended_tile = TRUE + else + to_chat(user, "There aren't any holes in the ceiling to patch here.") + return + + // Create a ceiling to shield from the weather + if(outdoors) + if(expended_tile || R.use(1)) // Don't need to check adjacent turfs for a wall, we're building on one + make_indoors() + if(!expended_tile) // Would've already played a sound + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + user.visible_message("[user] roofs \the [src], shielding it from the elements.", "You roof \the [src] tile, shielding it from the elements.") + return + + if(locate(/obj/effect/overlay/wallrot) in src) if(istype(W, /obj/item/weapon/weldingtool) ) var/obj/item/weapon/weldingtool/WT = W if( WT.remove_fuel(0,user) ) - user << "You burn away the fungi with \the [WT]." + to_chat(user, "You burn away the fungi with \the [WT].") playsound(src, WT.usesound, 10, 1) for(var/obj/effect/overlay/wallrot/WR in src) qdel(WR) return else if(!is_sharp(W) && W.force >= 10 || W.force >= 20) - user << "\The [src] crumbles away under the force of your [W.name]." + to_chat(user, "\The [src] crumbles away under the force of your [W.name].") src.dismantle_wall(1) return @@ -179,7 +208,7 @@ var/obj/item/weapon/melee/energy/blade/EB = W EB.spark_system.start() - user << "You slash \the [src] with \the [EB]; the thermite ignites!" + to_chat(user, "You slash \the [src] with \the [EB]; the thermite ignites!") playsound(src, "sparks", 50, 1) playsound(src, 'sound/weapons/blade1.ogg', 50, 1) @@ -196,13 +225,13 @@ return if(WT.remove_fuel(0,user)) - user << "You start repairing the damage to [src]." + to_chat(user, "You start repairing the damage to [src].") playsound(src.loc, WT.usesound, 100, 1) if(do_after(user, max(5, damage / 5) * WT.toolspeed) && WT && WT.isOn()) - user << "You finish repairing the damage to [src]." + to_chat(user, "You finish repairing the damage to [src].") take_damage(-damage) else - user << "You need more welding fuel to complete this task." + to_chat(user, "You need more welding fuel to complete this task.") return user.update_examine_panel(src) return @@ -219,7 +248,7 @@ if(!WT.isOn()) return if(!WT.remove_fuel(0,user)) - user << "You need more welding fuel to complete this task." + to_chat(user, "You need more welding fuel to complete this task.") return dismantle_verb = "cutting" dismantle_sound = W.usesound @@ -236,7 +265,7 @@ if(dismantle_verb) - user << "You begin [dismantle_verb] through the outer plating." + to_chat(user, "You begin [dismantle_verb] through the outer plating.") if(dismantle_sound) playsound(src, dismantle_sound, 100, 1) @@ -246,7 +275,7 @@ if(!do_after(user,cut_delay * W.toolspeed)) return - user << "You remove the outer plating." + to_chat(user, "You remove the outer plating.") dismantle_wall() user.visible_message("The wall was torn open by [user]!") return @@ -259,24 +288,24 @@ playsound(src, W.usesound, 100, 1) construction_stage = 5 user.update_examine_panel(src) - user << "You cut through the outer grille." + to_chat(user, "You cut through the outer grille.") update_icon() return if(5) if (istype(W, /obj/item/weapon/screwdriver)) - user << "You begin removing the support lines." + to_chat(user, "You begin removing the support lines.") playsound(src, W.usesound, 100, 1) if(!do_after(user,40 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 5) return construction_stage = 4 user.update_examine_panel(src) update_icon() - user << "You unscrew the support lines." + to_chat(user, "You unscrew the support lines.") return else if (istype(W, /obj/item/weapon/wirecutters)) construction_stage = 6 user.update_examine_panel(src) - user << "You mend the outer grille." + to_chat(user, "You mend the outer grille.") playsound(src, W.usesound, 100, 1) update_icon() return @@ -289,51 +318,51 @@ if(WT.remove_fuel(0,user)) cut_cover=1 else - user << "You need more welding fuel to complete this task." + to_chat(user, "You need more welding fuel to complete this task.") return else if (istype(W, /obj/item/weapon/pickaxe/plasmacutter)) cut_cover = 1 if(cut_cover) - user << "You begin slicing through the metal cover." + to_chat(user, "You begin slicing through the metal cover.") playsound(src, W.usesound, 100, 1) if(!do_after(user, 60 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 4) return construction_stage = 3 user.update_examine_panel(src) update_icon() - user << "You press firmly on the cover, dislodging it." + to_chat(user, "You press firmly on the cover, dislodging it.") return else if (istype(W, /obj/item/weapon/screwdriver)) - user << "You begin screwing down the support lines." + to_chat(user, "You begin screwing down the support lines.") playsound(src, W.usesound, 100, 1) if(!do_after(user,40 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 4) return construction_stage = 5 user.update_examine_panel(src) update_icon() - user << "You screw down the support lines." + to_chat(user, "You screw down the support lines.") return if(3) if (istype(W, /obj/item/weapon/crowbar)) - user << "You struggle to pry off the cover." + to_chat(user, "You struggle to pry off the cover.") playsound(src, W.usesound, 100, 1) if(!do_after(user,100 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 3) return construction_stage = 2 user.update_examine_panel(src) update_icon() - user << "You pry off the cover." + to_chat(user, "You pry off the cover.") return if(2) if (istype(W, /obj/item/weapon/wrench)) - user << "You start loosening the anchoring bolts which secure the support rods to their frame." + to_chat(user, "You start loosening the anchoring bolts which secure the support rods to their frame.") playsound(src, W.usesound, 100, 1) if(!do_after(user,40 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 2) return construction_stage = 1 user.update_examine_panel(src) update_icon() - user << "You remove the bolts anchoring the support rods." + to_chat(user, "You remove the bolts anchoring the support rods.") return if(1) var/cut_cover @@ -342,28 +371,28 @@ if( WT.remove_fuel(0,user) ) cut_cover=1 else - user << "You need more welding fuel to complete this task." + to_chat(user, "You need more welding fuel to complete this task.") return else if(istype(W, /obj/item/weapon/pickaxe/plasmacutter)) cut_cover = 1 if(cut_cover) - user << "You begin slicing through the support rods." + to_chat(user, "You begin slicing through the support rods.") playsound(src, W.usesound, 100, 1) if(!do_after(user,70 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 1) return construction_stage = 0 user.update_examine_panel(src) update_icon() - user << "The slice through the support rods." + to_chat(user, "The slice through the support rods.") return if(0) if(istype(W, /obj/item/weapon/crowbar)) - user << "You struggle to pry off the outer sheath." + to_chat(user, "You struggle to pry off the outer sheath.") playsound(src, W.usesound, 100, 1) if(!do_after(user,100 * W.toolspeed) || !istype(src, /turf/simulated/wall) || !user || !W || !T ) return if(user.loc == T && user.get_active_hand() == W ) - user << "You pry off the outer sheath." + to_chat(user, "You pry off the outer sheath.") dismantle_wall() return diff --git a/code/game/turfs/simulated/water.dm b/code/game/turfs/simulated/water.dm index cf06303740..7486f6cb68 100644 --- a/code/game/turfs/simulated/water.dm +++ b/code/game/turfs/simulated/water.dm @@ -19,6 +19,7 @@ ..() // To get the edges. icon_state = water_state var/image/floorbed_sprite = image(icon = 'icons/turf/outdoors.dmi', icon_state = under_state) + underlays.Cut() // To clear the old underlay, so the list doesn't expand infinitely underlays.Add(floorbed_sprite) update_icon_edge() diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 13368bb7ed..1c700eec85 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -33,18 +33,18 @@ /turf/space/attackby(obj/item/C as obj, mob/user as mob) - if (istype(C, /obj/item/stack/rods)) + if(istype(C, /obj/item/stack/rods)) var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) if(L) return var/obj/item/stack/rods/R = C if (R.use(1)) - user << "Constructing support lattice ..." + to_chat(user, "Constructing support lattice ...") playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) ReplaceWithLattice() return - if (istype(C, /obj/item/stack/tile/floor)) + if(istype(C, /obj/item/stack/tile/floor)) var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) if(L) var/obj/item/stack/tile/floor/S = C @@ -56,7 +56,33 @@ ChangeTurf(/turf/simulated/floor/airless) return else - user << "The plating is going to need some support." + to_chat(user, "The plating is going to need some support.") + + if(istype(C, /obj/item/stack/tile/roofing)) + var/turf/T = GetAbove(src) + var/obj/item/stack/tile/roofing/R = C + + // Patch holes in the ceiling + if(T) + if(istype(T, /turf/simulated/open) || istype(T, /turf/space)) + // Must be build adjacent to an existing floor/wall, no floating floors + var/turf/simulated/A = locate(/turf/simulated/floor) in T.CardinalTurfs() + if(!A) + A = locate(/turf/simulated/wall) in T.CardinalTurfs() + if(!A) + to_chat(user, "There's nothing to attach the ceiling to!") + return + + if(R.use(1)) // Cost of roofing tiles is 1:1 with cost to place lattice and plating + T.ReplaceWithLattice() + T.ChangeTurf(/turf/simulated/floor) + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + user.visible_message("[user] expands the ceiling.", "You expand the ceiling.") + else + to_chat(user, "There aren't any holes in the ceiling to patch here.") + return + // Space shouldn't have weather of the sort planets with atmospheres do. + // If that's changed, then you'll want to swipe the rest of the roofing code from code/game/turfs/simulated/floor_attackby.dm return @@ -64,7 +90,7 @@ /turf/space/Entered(atom/movable/A as mob|obj) if(movement_disabled) - usr << "Movement is admin-disabled." //This is to identify lag problems + to_chat(usr, "Movement is admin-disabled.") //This is to identify lag problems return ..() if ((!(A) || src != A.loc)) return diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm index 115a789987..3b5a797c0a 100644 --- a/code/game/turfs/turf_changing.dm +++ b/code/game/turfs/turf_changing.dm @@ -22,7 +22,7 @@ below.update_icon() // To add or remove the 'ceiling-less' overlay. //Creates a new turf -/turf/proc/ChangeTurf(var/turf/N, var/tell_universe=1, var/force_lighting_update = 0) +/turf/proc/ChangeTurf(var/turf/N, var/tell_universe=1, var/force_lighting_update = 0, var/preserve_outdoors = FALSE) if (!N) return @@ -38,6 +38,7 @@ var/old_affecting_lights = affecting_lights var/old_lighting_overlay = lighting_overlay var/old_corners = corners + var/old_outdoors = outdoors //world << "Replacing [src.type] with [N]" @@ -106,3 +107,6 @@ lighting_build_overlay() else lighting_clear_overlay() + + if(preserve_outdoors) + outdoors = old_outdoors \ No newline at end of file diff --git a/code/modules/admin/verbs/antag-ooc.dm b/code/modules/admin/verbs/antag-ooc.dm index 22689f1718..13c6e6a767 100644 --- a/code/modules/admin/verbs/antag-ooc.dm +++ b/code/modules/admin/verbs/antag-ooc.dm @@ -12,7 +12,7 @@ else if(is_antag && !is_admin) // Is an antag, and not an admin, meaning we need to check if their antag type allows AOOC. var/datum/antagonist/A = get_antag_data(usr.mind.special_role) - if(!A || !A.can_use_aooc) + if(!A || !A.can_speak_aooc || !A.can_hear_aooc) to_chat(usr, "Sorry, but your antagonist type is not allowed to speak in AOOC.") return @@ -36,7 +36,7 @@ var/datum/antagonist/A = null if(M.mind) // Observers don't have minds, but they should still see AOOC. A = get_antag_data(M.mind.special_role) - if((M.mind && M.mind.special_role && A && A.can_use_aooc) || isobserver(M)) // Antags must have their type be allowed to AOOC to see AOOC. This prevents, say, ERT from seeing AOOC. + if((M.mind && M.mind.special_role && A && A.can_hear_aooc) || isobserver(M)) // Antags must have their type be allowed to AOOC to see AOOC. This prevents, say, ERT from seeing AOOC. to_chat(M, "[create_text_tag("aooc", "Antag-OOC:", M.client)] [player_display]: [msg]") log_aooc(msg,src) \ No newline at end of file diff --git a/code/modules/artifice/deadringer.dm b/code/modules/artifice/deadringer.dm new file mode 100644 index 0000000000..99061b6624 --- /dev/null +++ b/code/modules/artifice/deadringer.dm @@ -0,0 +1,184 @@ +/obj/item/weapon/deadringer + name = "silver pocket watch" + desc = "A fancy silver-plated digital pocket watch. Looks expensive." + icon = 'icons/obj/deadringer.dmi' + icon_state = "deadringer" + w_class = ITEMSIZE_SMALL + slot_flags = SLOT_ID | SLOT_BELT | SLOT_TIE + origin_tech = list(TECH_ILLEGAL = 3) + var/activated = 0 + var/timer = 0 + var/bruteloss_prev = 999999 + var/fireloss_prev = 999999 + var/mob/living/carbon/human/corpse = null + var/mob/living/carbon/human/watchowner = null + + +/obj/item/weapon/deadringer/New() + ..() + processing_objects |= src + +/obj/item/weapon/deadringer/Destroy() //just in case some smartass tries to stay invisible by destroying the watch + uncloak() + processing_objects -= src + ..() + + +/obj/item/weapon/deadringer/dropped() + if(timer > 20) + uncloak() + watchowner = null + return + +/obj/item/weapon/deadringer/attack_self(var/mob/living/user as mob) + var/mob/living/H = src.loc + if (!istype(H, /mob/living/carbon/human)) + to_chat(H,"You have no clue what to do with this thing.") + return + if(!activated) + if(timer == 0) + to_chat(H, "You press a small button on [src]'s side. It starts to hum quietly.") + bruteloss_prev = H.getBruteLoss() + fireloss_prev = H.getFireLoss() + activated = 1 + return + else + to_chat(H,"You press a small button on [src]'s side. It buzzes a little.") + return + if(activated) + to_chat(H,"You press a small button on [src]'s side. It stops humming.") + activated = 0 + return + + +/obj/item/weapon/deadringer/process() + if(activated) + if (ismob(src.loc)) + var/mob/living/carbon/human/H = src.loc + watchowner = H + if(H.getBruteLoss() > bruteloss_prev || H.getFireLoss() > fireloss_prev) + deathprevent() + activated = 0 + if(watchowner.isSynthetic()) + to_chat(watchowner, "You fade into nothingness! [src]'s screen blinks, being unable to copy your synthetic body!") + else + to_chat(watchowner, "You fade into nothingness, leaving behind a fake body!") + icon_state = "deadringer_cd" + timer = 50 + return + if(timer > 0) + timer-- + if(timer == 20) + uncloak() + if(corpse) + new /obj/effect/effect/smoke/chem(corpse.loc) + qdel(corpse) + if(timer == 0) + icon_state = "deadringer" + return + + +/obj/item/weapon/deadringer/proc/deathprevent() + for(var/mob/living/simple_animal/D in oviewers(7, src)) + D.LoseTarget() + watchowner.emote("deathgasp") + watchowner.invisibility = 85 + watchowner.alpha = 127 + makeacorpse(watchowner) + for(var/mob/living/simple_animal/D in oviewers(7, src)) + D.LoseTarget() + return + +/obj/item/weapon/deadringer/proc/uncloak() + if(watchowner) + watchowner.invisibility = 0 + watchowner.alpha = 255 + playsound(get_turf(src), 'sound/effects/uncloak.ogg', 35, 1, -1) + return + +/obj/item/weapon/deadringer/proc/makeacorpse(var/mob/living/carbon/human/H) + if(H.isSynthetic()) + return + corpse = new /mob/living/carbon/human(H.loc) + corpse.setDNA(H.dna.Clone()) + corpse.death(1) //Kills the new mob + var/obj/item/clothing/temp = null + if(H.get_equipped_item(slot_w_uniform)) + corpse.equip_to_slot_or_del(new /obj/item/clothing/under/chameleon/changeling(corpse), slot_w_uniform) + temp = corpse.get_equipped_item(slot_w_uniform) + var/obj/item/clothing/c_type = H.get_equipped_item(slot_w_uniform) + temp.disguise(c_type.type) + temp.canremove = 0 + if(H.get_equipped_item(slot_wear_suit)) + corpse.equip_to_slot_or_del(new /obj/item/clothing/suit/chameleon/changeling(corpse), slot_wear_suit) + temp = corpse.get_equipped_item(slot_wear_suit) + var/obj/item/clothing/c_type = H.get_equipped_item(slot_wear_suit) + temp.disguise(c_type.type) + temp.canremove = 0 + if(H.get_equipped_item(slot_shoes)) + corpse.equip_to_slot_or_del(new /obj/item/clothing/shoes/chameleon/changeling(corpse), slot_shoes) + temp = corpse.get_equipped_item(slot_shoes) + var/obj/item/clothing/c_type = H.get_equipped_item(slot_shoes) + temp.disguise(c_type.type) + temp.canremove = 0 + if(H.get_equipped_item(slot_gloves)) + corpse.equip_to_slot_or_del(new /obj/item/clothing/gloves/chameleon/changeling(corpse), slot_gloves) + temp = corpse.get_equipped_item(slot_gloves) + var/obj/item/clothing/c_type = H.get_equipped_item(slot_gloves) + temp.disguise(c_type.type) + temp.canremove = 0 + if(H.get_equipped_item(slot_l_ear)) + temp = H.get_equipped_item(slot_l_ear) + corpse.equip_to_slot_or_del(new temp.type(corpse), slot_l_ear) + temp = corpse.get_equipped_item(slot_l_ear) + temp.canremove = 0 + if(H.get_equipped_item(slot_glasses)) + corpse.equip_to_slot_or_del(new /obj/item/clothing/glasses/chameleon/changeling(corpse), slot_glasses) + temp = corpse.get_equipped_item(slot_glasses) + var/obj/item/clothing/c_type = H.get_equipped_item(slot_glasses) + temp.disguise(c_type.type) + temp.canremove = 0 + if(H.get_equipped_item(slot_wear_mask)) + corpse.equip_to_slot_or_del(new /obj/item/clothing/mask/chameleon/changeling(corpse), slot_wear_mask) + temp = corpse.get_equipped_item(slot_wear_mask) + var/obj/item/clothing/c_type = H.get_equipped_item(slot_wear_mask) + temp.disguise(c_type.type) + temp.canremove = 0 + if(H.get_equipped_item(slot_head)) + corpse.equip_to_slot_or_del(new /obj/item/clothing/head/chameleon/changeling(corpse), slot_head) + temp = corpse.get_equipped_item(slot_head) + var/obj/item/clothing/c_type = H.get_equipped_item(slot_head) + temp.disguise(c_type.type) + temp.canremove = 0 + if(H.get_equipped_item(slot_belt)) + corpse.equip_to_slot_or_del(new /obj/item/weapon/storage/belt/chameleon/changeling(corpse), slot_belt) + temp = corpse.get_equipped_item(slot_belt) + var/obj/item/clothing/c_type = H.get_equipped_item(slot_belt) + temp.disguise(c_type.type) + temp.canremove = 0 + if(H.get_equipped_item(slot_back)) + corpse.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/chameleon/changeling(corpse), slot_back) + temp = corpse.get_equipped_item(slot_back) + var/obj/item/clothing/c_type = H.get_equipped_item(slot_back) + temp.disguise(c_type.type) + temp.canremove = 0 + corpse.identifying_gender = H.identifying_gender + corpse.flavor_texts = H.flavor_texts.Copy() + corpse.real_name = H.real_name + corpse.name = H.name + corpse.set_species(corpse.dna.species) + corpse.change_hair(H.h_style) + corpse.change_facial_hair(H.f_style) + corpse.change_hair_color(H.r_hair, H.g_hair, H.b_hair) + corpse.change_facial_hair_color(H.r_facial, H.g_facial, H.b_facial) + corpse.change_skin_color(H.r_skin, H.g_skin, H.b_skin) + corpse.adjustFireLoss(H.getFireLoss()) + corpse.adjustBruteLoss(H.getBruteLoss()) + corpse.UpdateAppearance() + corpse.regenerate_icons() + for(var/obj/item/organ/internal/I in corpse.internal_organs) + var/obj/item/organ/internal/G = I + G.Destroy() + return + + diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index 63c781452c..9e9eaeb868 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -250,9 +250,8 @@ return /obj/effect/beam/i_beam/Destroy() + . = ..() if(master.first == src) master.first = null - if(next) - qdel(next) - next = null - ..() + if(next && !next.gc_destroyed) + qdel_null(next) diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm index f0bccd731e..f044322cab 100644 --- a/code/modules/client/preference_setup/general/01_basic.dm +++ b/code/modules/client/preference_setup/general/01_basic.dm @@ -71,8 +71,8 @@ datum/preferences/proc/set_biological_gender(var/gender) . += "Nickname: " . += "[pref.nickname]" . += "
" - . += "Biological Gender: [gender2text(pref.biological_gender)]
" - . += "Gender Identity: [gender2text(pref.identifying_gender)]
" + . += "Biological Sex: [gender2text(pref.biological_gender)]
" + . += "Pronouns: [gender2text(pref.identifying_gender)]
" . += "Age: [pref.age]
" . += "Spawn Point: [pref.spawnpoint]
" if(config.allow_Metadata) @@ -111,13 +111,13 @@ datum/preferences/proc/set_biological_gender(var/gender) return TOPIC_NOACTION else if(href_list["bio_gender"]) - var/new_gender = input(user, "Choose your character's biological gender:", "Character Preference", pref.biological_gender) as null|anything in get_genders() + var/new_gender = input(user, "Choose your character's biological sex:", "Character Preference", pref.biological_gender) as null|anything in get_genders() if(new_gender && CanUseTopic(user)) pref.set_biological_gender(new_gender) return TOPIC_REFRESH_UPDATE_PREVIEW else if(href_list["id_gender"]) - var/new_gender = input(user, "Choose your character's identifying gender:", "Character Preference", pref.identifying_gender) as null|anything in all_genders_define_list + var/new_gender = input(user, "Choose your character's pronouns:", "Character Preference", pref.identifying_gender) as null|anything in all_genders_define_list if(new_gender && CanUseTopic(user)) pref.identifying_gender = new_gender return TOPIC_REFRESH @@ -158,4 +158,4 @@ datum/preferences/proc/set_biological_gender(var/gender) return possible_genders possible_genders = possible_genders.Copy() possible_genders |= NEUTER - return possible_genders \ No newline at end of file + return possible_genders diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 1fc3b1d8ba..c3d607d490 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -36,6 +36,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O S["synth_red"] >> pref.r_synth S["synth_green"] >> pref.g_synth S["synth_blue"] >> pref.b_synth + S["synth_markings"] >> pref.synth_markings pref.preview_icon = null S["bgstate"] >> pref.bgstate @@ -65,6 +66,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O S["synth_red"] << pref.r_synth S["synth_green"] << pref.g_synth S["synth_blue"] << pref.b_synth + S["synth_markings"] << pref.synth_markings S["bgstate"] << pref.bgstate /datum/category_item/player_setup_item/general/body/sanitize_character(var/savefile/S) @@ -120,6 +122,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O character.r_synth = pref.r_synth character.g_synth = pref.g_synth character.b_synth = pref.b_synth + character.synth_markings = pref.synth_markings // Destroy/cyborgize organs and limbs. for(var/name in list(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM, BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG, BP_GROIN, BP_TORSO)) @@ -305,6 +308,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O . += "
" . += "
" + . += "Allow Synth markings: [pref.synth_markings ? "Yes" : "No"]
" . += "Allow Synth color: [pref.synth_color ? "Yes" : "No"]
" if(pref.synth_color) . += "Change Color
__
" @@ -702,6 +706,10 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.b_synth = hex2num(copytext(new_color, 6, 8)) return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["synth_markings"]) + pref.synth_markings = !pref.synth_markings + return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["cycle_bg"]) pref.bgstate = next_in_list(pref.bgstate, pref.bgstate_options) return TOPIC_REFRESH_UPDATE_PREVIEW diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm index 9161f65517..1c9ec29880 100644 --- a/code/modules/client/preference_setup/loadout/loadout_suit.dm +++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm @@ -241,6 +241,46 @@ datum/gear/suit/duster path = /obj/item/clothing/accessory/poncho/roles/cloak/hop allowed_roles = list("Head of Personnel") +/datum/gear/suit/roles/poncho/cloak/cargo + display_name = "cloak, cargo" + path = /obj/item/clothing/accessory/poncho/roles/cloak/cargo + allowed_roles = list("Cargo Technician","Quartermaster") + +/datum/gear/suit/roles/poncho/cloak/mining + display_name = "cloak, cargo" + path = /obj/item/clothing/accessory/poncho/roles/cloak/mining + allowed_roles = list("Quartermaster","Shaft Miner") + +/datum/gear/suit/roles/poncho/cloak/security + display_name = "cloak, security" + path = /obj/item/clothing/accessory/poncho/roles/cloak/security + allowed_roles = list("Head of Security","Detective","Warden","Security Officer") + +/datum/gear/suit/roles/poncho/cloak/service + display_name = "cloak, service" + path = /obj/item/clothing/accessory/poncho/roles/cloak/service + allowed_roles = list("Head of Personnel","Bartender","Botanist","Janitor","Chef","Librarian") + +/datum/gear/suit/roles/poncho/cloak/engineer + display_name = "cloak, engineer" + path = /obj/item/clothing/accessory/poncho/roles/cloak/engineer + allowed_roles = list("Chief Engineer","Station Engineer") + +/datum/gear/suit/roles/poncho/cloak/atmos + display_name = "cloak, atmos" + path = /obj/item/clothing/accessory/poncho/roles/cloak/atmos + allowed_roles = list("Chief Engineer","Atmospheric Technician") + +/datum/gear/suit/roles/poncho/cloak/research + display_name = "cloak, science" + path = /obj/item/clothing/accessory/poncho/roles/cloak/research + allowed_roles = list("Research Director","Scientist", "Roboticist", "Xenobiologist") + +/datum/gear/suit/roles/poncho/cloak/medical + display_name = "cloak, medical" + path = /obj/item/clothing/accessory/poncho/roles/cloak/medical + allowed_roles = list("Medical Doctor","Chief Medical Officer","Chemist","Paramedic","Geneticist", "Psychiatrist") + /datum/gear/suit/unathi_robe display_name = "roughspun robe" path = /obj/item/clothing/suit/unathi/robe diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm index 3da9a7226c..1f35cc925a 100644 --- a/code/modules/client/preference_setup/loadout/loadout_utility.dm +++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm @@ -114,12 +114,6 @@ path = /obj/item/weapon/cell/device /datum/gear/utility/implant - exploitable = 1 - -/datum/gear/utility/implant/eal //This does nothing if you don't actually know EAL. - display_name = "implant, language, EAL" - path = /obj/item/weapon/implant/language/eal - cost = 2 slot = "implant" exploitable = 1 @@ -127,8 +121,20 @@ display_name = "implant, tracking" path = /obj/item/weapon/implant/tracking/weak cost = 10 - slot = "implant" - exploitable = 1 + +/datum/gear/utility/implant/language + cost = 2 + exploitable = 0 + +/datum/gear/utility/implant/language/eal + display_name = "vocal synthesizer, EAL" + description = "A surgically implanted vocal synthesizer which allows the owner to speak EAL, if they know it." + path = /obj/item/weapon/implant/language/eal + +/datum/gear/utility/implant/language/skrellian + display_name = "vocal synthesizer, Skrellian" + description = "A surgically implanted vocal synthesizer which allows the owner to speak Common Skrellian, if they know it." + path = /obj/item/weapon/implant/language/skrellian /datum/gear/utility/pen display_name = "Fountain Pen" diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index c45567e5a9..dee21ddd5b 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -60,6 +60,7 @@ datum/preferences var/r_synth //Used with synth_color to color synth parts that normaly can't be colored. var/g_synth //Same as above var/b_synth //Same as above + var/synth_markings = 0 //Enable/disable markings on synth parts. //Some faction information. var/home_system = "Unset" //System of birth. diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 9e0c0a0196..6f613e38ab 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -128,6 +128,7 @@ /obj/item/clothing/suit/syndicatefake name = "red space suit replica" + icon = 'icons/obj/clothing/spacesuits.dmi' icon_state = "syndicate" desc = "A plastic replica of the syndicate space suit, you'll look just like a real murderous syndicate agent in this! This is a toy, it is not made for use in space!" w_class = ITEMSIZE_NORMAL diff --git a/code/modules/clothing/under/accessories/clothing.dm b/code/modules/clothing/under/accessories/clothing.dm index eaab8b290a..02fab3e95a 100644 --- a/code/modules/clothing/under/accessories/clothing.dm +++ b/code/modules/clothing/under/accessories/clothing.dm @@ -121,8 +121,8 @@ * Cloak */ /obj/item/clothing/accessory/poncho/roles/cloak - name = "brown cloak" - desc = "An elaborate brown cloak." + name = "quartermaster's cloak" + desc = "An elaborate brown and gold cloak." icon_state = "qmcloak" item_state = "qmcloak" body_parts_covered = null @@ -169,6 +169,54 @@ icon_state = "capcloak" item_state = "capcloak" +/obj/item/clothing/accessory/poncho/roles/cloak/cargo + name = "brown cloak" + desc = "A simple brown and black cloak." + icon_state = "cargocloak" + item_state = "cargocloak" + +/obj/item/clothing/accessory/poncho/roles/cloak/mining + name = "trimmed purple cloak" + desc = "A trimmed purple and brown cloak." + icon_state = "miningcloak" + item_state = "miningcloak" + +/obj/item/clothing/accessory/poncho/roles/cloak/security + name = "red cloak" + desc = "A simple red and black cloak." + icon_state = "seccloak" + item_state = "seccloak" + +/obj/item/clothing/accessory/poncho/roles/cloak/service + name = "green cloak" + desc = "A simple green and blue cloak." + icon_state = "servicecloak" + item_state = "servicecloak" + +/obj/item/clothing/accessory/poncho/roles/cloak/engineer + name = "gold cloak" + desc = "A simple gold and brown cloak." + icon_state = "engicloak" + item_state = "engicloak" + +/obj/item/clothing/accessory/poncho/roles/cloak/atmos + name = "yellow cloak" + desc = "A trimmed yellow and blue cloak." + icon_state = "atmoscloak" + item_state = "atmoscloak" + +/obj/item/clothing/accessory/poncho/roles/cloak/research + name = "purple cloak" + desc = "A simple purple and white cloak." + icon_state = "scicloak" + item_state = "scicloak" + +/obj/item/clothing/accessory/poncho/roles/cloak/medical + name = "blue cloak" + desc = "A simple blue and white cloak." + icon_state = "medcloak" + item_state = "medcloak" + /obj/item/clothing/accessory/hawaii name = "flower-pattern shirt" desc = "You probably need some welder googles to look at this." diff --git a/code/modules/integrated_electronics/core/printer.dm b/code/modules/integrated_electronics/core/printer.dm index 4dfd4e989a..794755b02c 100644 --- a/code/modules/integrated_electronics/core/printer.dm +++ b/code/modules/integrated_electronics/core/printer.dm @@ -162,13 +162,16 @@ return 1 var/cost = 1 + + if(isnull(current_category)) + current_category = recipe_list[1] if(ispath(build_type, /obj/item/device/electronic_assembly)) var/obj/item/device/electronic_assembly/E = build_type cost = round( (initial(E.max_complexity) + initial(E.max_components) ) / 4) - else if(ispath(build_type, /obj/item/integrated_circuit)) - var/obj/item/integrated_circuit/IC = build_type - cost = initial(IC.w_class) else + var/obj/item/I = build_type + cost = initial(I.w_class) + if(!(locate(build_type) in recipe_list[current_category])) return if(metal - cost < 0) @@ -198,4 +201,4 @@ name = "integrated circuit printer upgrade disk - circuit cloner" desc = "Install this into your integrated circuit printer to enhance it. This one allows the printer to duplicate assemblies." icon_state = "upgrade_disk_clone" - origin_tech = list(TECH_ENGINEERING = 5, TECH_DATA = 6) \ No newline at end of file + origin_tech = list(TECH_ENGINEERING = 5, TECH_DATA = 6) diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm index 6e75d97a0d..232ef46e3e 100644 --- a/code/modules/materials/material_recipes.dm +++ b/code/modules/materials/material_recipes.dm @@ -53,6 +53,7 @@ recipes += new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1) recipes += new/datum/stack_recipe("cannon frame", /obj/item/weapon/cannonframe, 10, time = 15, one_per_turf = 0, on_floor = 0) recipes += new/datum/stack_recipe("regular floor tile", /obj/item/stack/tile/floor, 1, 4, 20) + recipes += new/datum/stack_recipe("roofing tile", /obj/item/stack/tile/roofing, 3, 4, 20) recipes += new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60) recipes += new/datum/stack_recipe("frame", /obj/item/frame, 5, time = 25, one_per_turf = 1, on_floor = 1) recipes += new/datum/stack_recipe("mirror frame", /obj/item/frame/mirror, 1, time = 5, one_per_turf = 0, on_floor = 1) diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index 7170b12d32..a056a62bed 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -168,6 +168,12 @@ var/list/mining_overlay_cache = list() if(istype(get_step(src, direction), /turf/space) && !istype(get_step(src, direction), /turf/space/cracked_asteroid)) add_overlay(get_cached_border("asteroid_edge",direction,icon,"asteroid_edges", 0)) + //Or any time + else + var/turf/T = get_step(src, direction) + if(istype(T) && T.density) + add_overlay(get_cached_border("rock_side",direction,'icons/turf/walls.dmi',"rock_side")) + if(overlay_detail) add_overlay('icons/turf/flooring/decals.dmi',overlay_detail) diff --git a/code/modules/mob/language/generic.dm b/code/modules/mob/language/generic.dm index ad55f2b346..7cb7cd08e5 100644 --- a/code/modules/mob/language/generic.dm +++ b/code/modules/mob/language/generic.dm @@ -133,6 +133,6 @@ key = "s" flags = SIGNLANG|NO_STUTTER|NONVERBAL -/datum/language/sign/can_speak_special(var/mob/speaker) +/datum/language/sign/can_speak_special(var/mob/speaker) // TODO: If ever we make external organs assist languages, convert this over to the new format var/obj/item/organ/external/hand/hands = locate() in speaker //you can't sign without hands return (hands || !iscarbon(speaker)) diff --git a/code/modules/mob/language/language.dm b/code/modules/mob/language/language.dm index c6089a8788..66e0e5e0f0 100644 --- a/code/modules/mob/language/language.dm +++ b/code/modules/mob/language/language.dm @@ -133,7 +133,15 @@ return speech_verb /datum/language/proc/can_speak_special(var/mob/speaker) - return 1 + . = TRUE + if(ishuman(speaker)) + var/mob/living/carbon/human/H = speaker + if(src.name in H.species.assisted_langs) + . = FALSE + var/obj/item/organ/internal/voicebox/vox = locate() in H.internal_organs // Only voiceboxes for now. Maybe someday it'll include other organs, but I'm not that clever + if(vox) + if(!vox.is_broken() && (src in vox.assists_languages)) + . = TRUE // Language handling. /mob/proc/add_language(var/language) diff --git a/code/modules/mob/language/station.dm b/code/modules/mob/language/station.dm index b721aa89af..c80f606ae6 100644 --- a/code/modules/mob/language/station.dm +++ b/code/modules/mob/language/station.dm @@ -63,6 +63,14 @@ "ka","aasi","far","wa","baq","ara","qara","zir","saam","mak","hrar","nja","rir","khan","jun","dar","rik","kah", "hal","ket","jurl","mah","tul","cresh","azu","ragh","mro","mra","mrro","mrra") +/datum/language/tajaran/get_random_name(var/gender) + var/new_name = ..(gender,1) + if(prob(50)) + new_name += " [pick(list("Hadii","Kaytam","Nazkiin","Zhan-Khazan","Hharar","Njarir'Akhan","Faaira'Nrezi","Rhezar","Mi'dynh","Rrhazkal","Bayan","Al'Manq","Mi'jri","Chur'eech","Sanu'dra","Ii'rka"))]" + else + new_name += " [..(gender,1)]" + return new_name + /datum/language/tajaranakhani name = LANGUAGE_AKHANI desc = "The language of the sea-faring Njarir'Akhan Tajaran. Borrowing some elements from Siik, the language is distinctly more structured." @@ -78,7 +86,7 @@ "nai","ou","kah","oa","ama","uuk","bel","chi","ayt","kay","kas","akor","tam","yir","enai") /datum/language/tajsign - name = LANGUAGE_SIIK_ALAI + name = LANGUAGE_ALAI desc = "A standardized Tajaran sign language that was developed in Zarraya and gradually adopted by other nations, incorporating \ hand gestures and movements of the ears and tail." signlang_verb = list("gestures with their hands", "gestures with their ears and tail", "gestures with their ears, tail and hands") @@ -86,14 +94,18 @@ key = "l" flags = WHITELISTED | SIGNLANG | NO_STUTTER | NONVERBAL -/datum/language/tajaran/get_random_name(var/gender) +/datum/language/tajsign/can_speak_special(var/mob/speaker) // TODO: If ever we make external organs assist languages, convert this over to the new format + var/list/allowed_species = list(SPECIES_TAJ, SPECIES_TESHARI) // Need a tail and ears and such to use this. + if(iscarbon(speaker)) + var/obj/item/organ/external/hand/hands = locate() in speaker //you can't sign without hands + if(!hands) + return FALSE + if(ishuman(speaker)) + var/mob/living/carbon/human/H = speaker + if(H.species.get_bodytype(H) in allowed_species) + return TRUE - var/new_name = ..(gender,1) - if(prob(50)) - new_name += " [pick(list("Hadii","Kaytam","Nazkiin","Zhan-Khazan","Hharar","Njarir'Akhan","Faaira'Nrezi","Rhezar","Mi'dynh","Rrhazkal","Bayan","Al'Manq","Mi'jri","Chur'eech","Sanu'dra","Ii'rka"))]" - else - new_name += " [..(gender,1)]" - return new_name + return FALSE /datum/language/skrell name = LANGUAGE_SKRELLIAN @@ -161,11 +173,6 @@ syllables = list("beep","beep","beep","beep","beep","boop","boop","boop","bop","bop","dee","dee","doo","doo","hiss","hss","buzz","buzz","bzz","ksssh","keey","wurr","wahh","tzzz","shh","shk") space_chance = 10 -/datum/language/machine/can_speak_special(var/mob/speaker) - var/obj/item/weapon/implant/language/eal/beep = locate() in speaker - return ((beep && beep.implanted) || speaker.isSynthetic() || isvoice(speaker)) - //thank you sweet zuhayr - /datum/language/machine/get_random_name() if(prob(70)) return "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]" diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 72c1f1ed3b..b81f009878 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -14,9 +14,10 @@ var/muzzled = is_muzzled() //var/m_type = 1 - for (var/obj/item/weapon/implant/I in src) - if (I.implanted) - I.trigger(act, src) + for(var/obj/item/organ/O in src.organs) + for (var/obj/item/weapon/implant/I in O) + if (I.implanted) + I.trigger(act, src) if(src.stat == 2.0 && (act != "deathgasp")) return diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index b25973e89a..277604bdfc 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -165,25 +165,12 @@ update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05, used_weapon = weapon_message) if(update) UpdateDamageIcon() -/mob/living/carbon/human/proc/implant_loadout(var/datum/gear/G = new/datum/gear/utility/implant) - var/obj/item/weapon/implant/I = new G.path(src) - I.imp_in = src - I.implanted = 1 - var/obj/item/organ/external/affected = src.organs_by_name[BP_HEAD] - affected.implants += I - I.part = affected - I.implanted(src) - /mob/living/carbon/human/proc/implant_loyalty(override = FALSE) // Won't override by default. if(!config.use_loyalty_implants && !override) return // Nuh-uh. var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(src) - L.imp_in = src - L.implanted = 1 - var/obj/item/organ/external/affected = src.organs_by_name[BP_HEAD] - affected.implants += L - L.part = affected - L.implanted(src) + if(L.handle_implant(src, BP_HEAD)) + L.post_implant(src) /mob/living/carbon/human/proc/is_loyalty_implanted() for(var/L in src.contents) @@ -1120,6 +1107,8 @@ remove_language(species.language) if(species.default_language) remove_language(species.default_language) + for(var/datum/language/L in species.assisted_langs) + remove_language(L) // Clear out their species abilities. species.remove_inherent_verbs(src) holder_type = null diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 5e647cf9a2..6797c570ec 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -167,45 +167,35 @@ emp_act //this proc returns the armour value for a particular external organ. /mob/living/carbon/human/proc/getarmor_organ(var/obj/item/organ/external/def_zone, var/type) - if(!type || !def_zone) return 0 + if(!type || !def_zone) + return 0 var/protection = 0 - var/list/protective_gear = list(head, wear_mask, wear_suit, w_uniform, gloves, shoes) + var/list/protective_gear = def_zone.get_covering_clothing() for(var/obj/item/clothing/gear in protective_gear) - if(gear.body_parts_covered & def_zone.body_part) - protection += gear.armor[type] - if(LAZYLEN(gear.accessories)) - for(var/obj/item/clothing/accessory/bling in gear.accessories) - if(bling.body_parts_covered & def_zone.body_part) - protection += bling.armor[type] + protection += gear.armor[type] return protection /mob/living/carbon/human/proc/getsoak_organ(var/obj/item/organ/external/def_zone, var/type) - if(!type || !def_zone) return 0 + if(!type || !def_zone) + return 0 var/soaked = 0 - var/list/protective_gear = list(head, wear_mask, wear_suit, w_uniform, gloves, shoes) + var/list/protective_gear = def_zone.get_covering_clothing() for(var/obj/item/clothing/gear in protective_gear) - if(gear.body_parts_covered & def_zone.body_part) - soaked += gear.armorsoak[type] - if(LAZYLEN(gear.accessories)) - for(var/obj/item/clothing/accessory/bling in gear.accessories) - if(bling.body_parts_covered & def_zone.body_part) - soaked += bling.armorsoak[type] + soaked += gear.armorsoak[type] return soaked +// Checked in borer code /mob/living/carbon/human/proc/check_head_coverage() - - var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform) - for(var/bp in body_parts) - if(!bp) continue - if(bp && istype(bp ,/obj/item/clothing)) - var/obj/item/clothing/C = bp - if(C.body_parts_covered & HEAD) - return 1 + var/obj/item/organ/external/H = organs_by_name[BP_HEAD] + var/list/body_parts = H.get_covering_clothing() + if(LAZYLEN(body_parts)) + return 1 return 0 //Used to check if they can be fed food/drinks/pills /mob/living/carbon/human/proc/check_mouth_coverage() - var/list/protective_gear = list(head, wear_mask, wear_suit, w_uniform) + var/obj/item/organ/external/H = organs_by_name[BP_HEAD] + var/list/protective_gear = H.get_covering_clothing() for(var/obj/item/gear in protective_gear) if(istype(gear) && (gear.body_parts_covered & FACE) && !(gear.item_flags & FLEXIBLEMATERIAL)) return gear diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 244c22e80b..2cbd93260c 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -30,6 +30,7 @@ var/r_synth //Used with synth_color to color synth parts that normaly can't be colored. var/g_synth //Same as above var/b_synth //Same as above + var/synth_markings = 0 //Enables/disables markings on synth parts. var/damage_multiplier = 1 //multiplies melee combat damage var/icon_update = 1 //whether icon updating shall take place diff --git a/code/modules/mob/living/carbon/human/species/outsider/event.dm b/code/modules/mob/living/carbon/human/species/outsider/event.dm index 3e75acae9c..477b14c0c4 100644 --- a/code/modules/mob/living/carbon/human/species/outsider/event.dm +++ b/code/modules/mob/living/carbon/human/species/outsider/event.dm @@ -70,6 +70,7 @@ Variables you may want to make use of are: num_alternate_languages = 3 species_language = LANGUAGE_GALCOM secondary_langs = list() + assisted_langs = list() name_language = null // Use the first-name last-name generator rather than a language scrambler min_age = 0 diff --git a/code/modules/mob/living/carbon/human/species/outsider/shadow.dm b/code/modules/mob/living/carbon/human/species/outsider/shadow.dm index 5d81bb4c9c..d0f40f693d 100644 --- a/code/modules/mob/living/carbon/human/species/outsider/shadow.dm +++ b/code/modules/mob/living/carbon/human/species/outsider/shadow.dm @@ -25,6 +25,8 @@ genders = list(NEUTER) + assisted_langs = list() + /datum/species/shadow/handle_death(var/mob/living/carbon/human/H) spawn(1) new /obj/effect/decal/cleanable/ash(H.loc) diff --git a/code/modules/mob/living/carbon/human/species/outsider/vox.dm b/code/modules/mob/living/carbon/human/species/outsider/vox.dm index 9fab4751cc..525a611882 100644 --- a/code/modules/mob/living/carbon/human/species/outsider/vox.dm +++ b/code/modules/mob/living/carbon/human/species/outsider/vox.dm @@ -7,6 +7,7 @@ language = LANGUAGE_GALCOM species_language = LANGUAGE_VOX num_alternate_languages = 1 + assisted_langs = list(LANGUAGE_ROOTGLOBAL) unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/strong, /datum/unarmed_attack/bite/strong) rarity_value = 4 blurb = "The Vox are the broken remnants of a once-proud race, now reduced to little more than \ @@ -71,6 +72,7 @@ has_organ = list( O_HEART = /obj/item/organ/internal/heart/vox, O_LUNGS = /obj/item/organ/internal/lungs/vox, + O_VOICE = /obj/item/organ/internal/voicebox, O_LIVER = /obj/item/organ/internal/liver/vox, O_KIDNEYS = /obj/item/organ/internal/kidneys/vox, O_BRAIN = /obj/item/organ/internal/brain/vox, diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 1f2e55b99c..38d566d430 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -52,13 +52,17 @@ // Language/culture vars. var/default_language = LANGUAGE_GALCOM // Default language is used when 'say' is used without modifiers. var/language = LANGUAGE_GALCOM // Default racial language, if any. - var/species_language = LANGUAGE_GALCOM // Used on the Character Setup screen + var/list/species_language = list(LANGUAGE_GALCOM) // Used on the Character Setup screen var/list/secondary_langs = list() // The names of secondary languages that are available to this species. var/list/speech_sounds = list() // A list of sounds to potentially play when speaking. var/list/speech_chance = list() // The likelihood of a speech sound playing. var/num_alternate_languages = 0 // How many secondary languages are available to select at character creation var/name_language = LANGUAGE_GALCOM // The language to use when determining names for this species, or null to use the first name/last name generator + // The languages the species can't speak without an assisted organ. + // This list is a guess at things that no one other than the parent species should be able to speak + var/list/assisted_langs = list(LANGUAGE_EAL, LANGUAGE_TERMINUS, LANGUAGE_SKRELLIAN, LANGUAGE_SKRELLIANFAR, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) + //Soundy emotey things. var/scream_verb = "screams" var/male_scream_sound //= 'sound/goonstation/voice/male_scream.ogg' Removed due to licensing, replace! @@ -183,6 +187,7 @@ var/list/has_organ = list( // which required-organ checks are conducted. O_HEART = /obj/item/organ/internal/heart, O_LUNGS = /obj/item/organ/internal/lungs, + O_VOICE = /obj/item/organ/internal/voicebox, O_LIVER = /obj/item/organ/internal/liver, O_KIDNEYS = /obj/item/organ/internal/kidneys, O_BRAIN = /obj/item/organ/internal/brain, diff --git a/code/modules/mob/living/carbon/human/species/station/golem.dm b/code/modules/mob/living/carbon/human/species/station/golem.dm index 9ec7a2b005..3b09166813 100644 --- a/code/modules/mob/living/carbon/human/species/station/golem.dm +++ b/code/modules/mob/living/carbon/human/species/station/golem.dm @@ -11,6 +11,8 @@ spawn_flags = SPECIES_IS_RESTRICTED siemens_coefficient = 0 + assisted_langs = list() + breath_type = null poison_type = null diff --git a/code/modules/mob/living/carbon/human/species/station/human_subspecies.dm b/code/modules/mob/living/carbon/human/species/station/human_subspecies.dm index 180732b0aa..56b5c36035 100644 --- a/code/modules/mob/living/carbon/human/species/station/human_subspecies.dm +++ b/code/modules/mob/living/carbon/human/species/station/human_subspecies.dm @@ -45,6 +45,7 @@ has_organ = list( O_HEART = /obj/item/organ/internal/heart, O_LUNGS = /obj/item/organ/internal/lungs, + O_VOICE = /obj/item/organ/internal/voicebox, O_LIVER = /obj/item/organ/internal/liver, O_KIDNEYS = /obj/item/organ/internal/kidneys, O_BRAIN = /obj/item/organ/internal/brain, diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm index 213c7c3ae3..0c2fbc0ac3 100644 --- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm +++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm @@ -30,6 +30,7 @@ var/datum/species/shapeshifter/promethean/prometheans health_hud_intensity = 2 num_alternate_languages = 3 species_language = LANGUAGE_SOL_COMMON + assisted_langs = list(LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) // Prometheans are weird, let's just assume they can use basically any language. breath_type = null poison_type = null diff --git a/code/modules/mob/living/carbon/human/species/station/seromi.dm b/code/modules/mob/living/carbon/human/species/station/seromi.dm index 1d1c0036be..81deb462a6 100644 --- a/code/modules/mob/living/carbon/human/species/station/seromi.dm +++ b/code/modules/mob/living/carbon/human/species/station/seromi.dm @@ -104,6 +104,7 @@ has_organ = list( O_HEART = /obj/item/organ/internal/heart, O_LUNGS = /obj/item/organ/internal/lungs, + O_VOICE = /obj/item/organ/internal/voicebox, O_LIVER = /obj/item/organ/internal/liver, O_KIDNEYS = /obj/item/organ/internal/kidneys, O_BRAIN = /obj/item/organ/internal/brain, diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm index 8d8e716076..5d95a63285 100644 --- a/code/modules/mob/living/carbon/human/species/station/station.dm +++ b/code/modules/mob/living/carbon/human/species/station/station.dm @@ -12,6 +12,7 @@ species_language = LANGUAGE_SOL_COMMON secondary_langs = list(LANGUAGE_SOL_COMMON, LANGUAGE_TERMINUS) name_language = null // Use the first-name last-name generator rather than a language scrambler + assisted_langs = list(LANGUAGE_EAL, LANGUAGE_SKRELLIAN, LANGUAGE_SKRELLIANFAR, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) min_age = 17 max_age = 130 @@ -157,7 +158,7 @@ metabolic_rate = 1.1 gluttonous = 1 num_alternate_languages = 3 - secondary_langs = list(LANGUAGE_SIIK, LANGUAGE_AKHANI, LANGUAGE_SIIK_ALAI) + secondary_langs = list(LANGUAGE_SIIK, LANGUAGE_AKHANI, LANGUAGE_ALAI) name_language = LANGUAGE_SIIK species_language = LANGUAGE_SIIK health_hud_intensity = 2.5 @@ -215,6 +216,7 @@ has_organ = list( //No appendix. O_HEART = /obj/item/organ/internal/heart, O_LUNGS = /obj/item/organ/internal/lungs, + O_VOICE = /obj/item/organ/internal/voicebox, O_LIVER = /obj/item/organ/internal/liver, O_KIDNEYS = /obj/item/organ/internal/kidneys, O_BRAIN = /obj/item/organ/internal/brain, @@ -241,6 +243,7 @@ secondary_langs = list(LANGUAGE_SKRELLIAN, LANGUAGE_SCHECHI) name_language = LANGUAGE_SKRELLIAN species_language = LANGUAGE_SKRELLIAN + assisted_langs = list(LANGUAGE_EAL, LANGUAGE_TERMINUS, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) health_hud_intensity = 2 water_movement = -3 @@ -315,13 +318,14 @@ hud_type = /datum/hud_data/diona siemens_coefficient = 0.3 show_ssd = "completely quiescent" - num_alternate_languages = 2 - secondary_langs = list(LANGUAGE_ROOTGLOBAL) - name_language = LANGUAGE_ROOTLOCAL - species_language = LANGUAGE_ROOTLOCAL health_hud_intensity = 2.5 item_slowdown_mod = 0.25 + num_alternate_languages = 2 + name_language = LANGUAGE_ROOTLOCAL + species_language = LANGUAGE_ROOTLOCAL + secondary_langs = list(LANGUAGE_ROOTGLOBAL) + assisted_langs = list(LANGUAGE_VOX) // Diona are weird, let's just assume they can use basically any language. min_age = 1 max_age = 300 diff --git a/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm index 0b9c5490eb..f3115474dc 100644 --- a/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm +++ b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm @@ -16,6 +16,8 @@ speech_bubble_appearance = "cyber" + assisted_langs = list() + male_cough_sounds = list('sound/effects/mob_effects/m_cougha.ogg','sound/effects/mob_effects/m_coughb.ogg', 'sound/effects/mob_effects/m_coughc.ogg') female_cough_sounds = list('sound/effects/mob_effects/f_cougha.ogg','sound/effects/mob_effects/f_coughb.ogg') male_sneeze_sound = 'sound/effects/mob_effects/sneeze.ogg' diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm index d851c40255..1d2ce59307 100644 --- a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm @@ -5,6 +5,7 @@ default_language = "Xenomorph" language = "Hivemind" + assisted_langs = list() unarmed_types = list(/datum/unarmed_attack/claws/strong/xeno, /datum/unarmed_attack/bite/strong/xeno) hud_type = /datum/hud_data/alien rarity_value = 3 diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 6c9a16c355..7ff23130d1 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1239,4 +1239,8 @@ default behaviour is: /mob/living/proc/has_vision() - return !(eye_blind || (disabilities & BLIND) || stat || blinded) \ No newline at end of file + return !(eye_blind || (disabilities & BLIND) || stat || blinded) + + +/mob/living/proc/dirties_floor() // If we ever decide to add fancy conditionals for making dirty floors (floating, etc), here's the proc. + return makes_dirt \ No newline at end of file diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 30c5580d14..d656feb485 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -18,7 +18,6 @@ var/brainloss = 0 //'Retardation' damage caused by someone hitting you in the head with a bible or being infected with brainrot. var/halloss = 0 //Hallucination damage. 'Fake' damage obtained through hallucinating or the holodeck. Sleeping should cause it to wear off. - var/hallucination = 0 //Directly affects how long a mob will hallucinate for var/list/atom/hallucinations = list() //A list of hallucinated people that try to attack the mob. See /obj/effect/fake_attacker in hallucinations.dm @@ -62,3 +61,5 @@ var/list/hud_list //Holder for health hud, status hud, wanted hud, etc (not like inventory slots) var/has_huds = FALSE //Whether or not we should bother initializing the above list + + var/makes_dirt = TRUE //FALSE if the mob shouldn't be making dirt on the ground when it walks \ No newline at end of file diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 60b552013d..b7b0c86b19 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -64,6 +64,7 @@ var/list/ai_verbs_default = list( var/datum/announcement/priority/announcement var/obj/machinery/ai_powersupply/psupply = null // Backwards reference to AI's powersupply object. var/hologram_follow = 1 //This is used for the AI eye, to determine if a holopad's hologram should follow it or not. + var/is_dummy = 0 //Used to prevent dummy AIs from spawning with communicators. //NEWMALF VARIABLES var/malfunctioning = 0 // Master var that determines if AI is malfunctioning. var/datum/malf_hardware/hardware = null // Installed piece of hardware. @@ -111,15 +112,16 @@ var/list/ai_verbs_default = list( possibleNames -= pickedName pickedName = null - aiPDA = new/obj/item/device/pda/ai(src) + if(!is_dummy) + aiPDA = new/obj/item/device/pda/ai(src) SetName(pickedName) anchored = 1 canmove = 0 density = 1 loc = loc - - aiCommunicator = new /obj/item/device/communicator/integrated(src) - + + if(!is_dummy) + aiCommunicator = new /obj/item/device/communicator/integrated(src) holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1")) @@ -792,6 +794,9 @@ var/list/ai_verbs_default = list( return TRUE //Special subtype kept around for global announcements +/mob/living/silicon/ai/announcer/ + is_dummy = 1 + /mob/living/silicon/ai/announcer/initialize() . = ..() mob_list -= src diff --git a/code/modules/mob/living/silicon/ai/icons.dm b/code/modules/mob/living/silicon/ai/icons.dm index 2d8bc0d002..c9891f9ae8 100644 --- a/code/modules/mob/living/silicon/ai/icons.dm +++ b/code/modules/mob/living/silicon/ai/icons.dm @@ -84,6 +84,7 @@ var/list/datum/ai_icon/ai_icons /datum/ai_icon/glitchman name = "Glitchman" alive_icon = "ai-glitchman" + dead_icon = "ai-glitchman-crash" /datum/ai_icon/goon name = "Goon" @@ -110,6 +111,7 @@ var/list/datum/ai_icon/ai_icons name = "Inverted" alive_icon = "ai-u" alive_light = "#81DDFF" + dead_icon = "ai-u-crash" /datum/ai_icon/lonestar name = "Lonestar" @@ -163,14 +165,87 @@ var/list/datum/ai_icon/ai_icons /datum/ai_icon/trapped name = "Trapped" alive_icon = "ai-hades" - dead_icon = "ai-hades_dead" + dead_icon = "ai-hades-crash" -/datum/ai_icon/triumvirate_static +/datum/ai_icon/triumvirate name = "Triumvirate" alive_icon = "ai-triumvirate" alive_light = "#020B2B" /datum/ai_icon/triumvirate_static name = "Triumvirate Static" - alive_icon = "ai-static" + alive_icon = "ai-triumvirate-malf" alive_light = "#020B2B" + +//Eros Research Platform Ports + +/datum/ai_icon/clown2 + name = "Honk" + alive_icon = "ai-clown2" + dead_icon = "ai-clown2-crash" + +/datum/ai_icon/boxfort + name = "Boxfort" + alive_icon = "ai-boxfort" + dead_icon = "ai-boxfort_dead" + +/datum/ai_icon/ravensdale + name = "Integration" + alive_icon = "ai-ravensdale" + dead_icon = "ai-ravensdale-crash" + +/datum/ai_icon/gentoo + name = "Gentoo" + alive_icon = "ai-gentoo" + dead_icon = "ai-gentoo_dead" + +/datum/ai_icon/serithi + name = "Mechanicus" + alive_icon = "ai-serithi" + dead_icon = "ai-serithi-crash" + +/datum/ai_icon/alien + name = "Xenomorph" + alive_icon = "ai-alien" + dead_icon = "ai-alien-crash" + +/datum/ai_icon/syndicat + name = "Syndi-cat" + alive_icon = "ai-syndicatmeow" + +/datum/ai_icon/wasp + name = "Wasp" + alive_icon = "ai-wasp" + +/datum/ai_icon/house + name = "Doctor" + alive_icon = "ai-house" + +/datum/ai_icon/fabulous + name = "Fabulous" + alive_icon = "ai-fabulous" + +/datum/ai_icon/yesman + name = "Yes Man" + alive_icon = "ai-yes-man" + dead_icon = "ai-alien-crash" + +/datum/ai_icon/royal + name = "Royal" + alive_icon = "ai-royal" + +/datum/ai_icon/pirate + name = "Pirate" + alive_icon = "ai-pirate" + +/datum/ai_icon/gygas + name = "Love" + alive_icon = "ai-gygas" + +/datum/ai_icon/xerxes + name = "Xerxes" + alive_icon = "ai-xerxes" + +/datum/ai_icon/godfrey + name = "Godfrey" + alive_icon = "ai-godfrey" \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station.dm b/code/modules/mob/living/silicon/robot/robot_modules/station.dm index e6dbeeac91..19af854d26 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/station.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/station.dm @@ -213,6 +213,7 @@ var/global/list/robot_modules = list( ..() src.modules += new /obj/item/device/healthanalyzer(src) src.modules += new /obj/item/weapon/reagent_containers/borghypo/surgeon(src) + src.modules += new /obj/item/weapon/autopsy_scanner(src) src.modules += new /obj/item/weapon/surgical/scalpel/cyborg(src) src.modules += new /obj/item/weapon/surgical/hemostat/cyborg(src) src.modules += new /obj/item/weapon/surgical/retractor/cyborg(src) diff --git a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm index ac41265fac..63e4f359be 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm @@ -148,6 +148,7 @@ src.modules += new /obj/item/weapon/reagent_containers/borghypo/merc(src) // Surgery things. + src.modules += new /obj/item/weapon/autopsy_scanner(src) src.modules += new /obj/item/weapon/surgical/scalpel/cyborg(src) src.modules += new /obj/item/weapon/surgical/hemostat/cyborg(src) src.modules += new /obj/item/weapon/surgical/retractor/cyborg(src) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index fb5180d99f..1a048b32a5 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -763,6 +763,8 @@ var/mob/living/L = target_mob if(L.stat != DEAD) return 1 + if(L.invisibility < INVISIBILITY_LEVEL_ONE) + return 1 if (istype(target_mob,/obj/mecha)) var/obj/mecha/M = target_mob if (M.occupant) @@ -882,6 +884,8 @@ continue else if(L in friends) continue + else if(L.invisibility >= INVISIBILITY_LEVEL_ONE) + continue else if(!SA_attackable(L)) continue else if(!special_target_check(L)) @@ -1209,7 +1213,7 @@ ai_log("AttackTarget() Bailing because we're disabled",2) LoseTarget() return 0 - if(!target_mob || !SA_attackable(target_mob)) + if(!target_mob || !SA_attackable(target_mob) || (target_mob.invisibility >= INVISIBILITY_LEVEL_ONE)) //if the target went invisible, you can't follow it LoseTarget() return 0 if(!(target_mob in ListTargets(view_range))) diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index 5141eed979..892c185a94 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -1257,6 +1257,24 @@ name = "Tattoo (Campbell, L.Arm)" body_parts = list(BP_L_ARM) + rightleg + name = "Tattoo (Campbell, R.Leg)" + body_parts = list(BP_R_LEG) + + leftleg + name = "Tattoo (Campbell, L.Leg)" + body_parts = list (BP_L_LEG) + + tat_silverburgh + name = "Tattoo (Silverburgh, R.Leg)" + icon_state = "tat_silverburgh" + body_parts = list (BP_R_LEG) + + left + name = "Tattoo (Silverburgh, L.Leg)" + icon_state = "tat_silverburgh" + body_parts = list (BP_L_LEG) + tat_tiger name = "Tattoo (Tiger Stripes, Body)" icon_state = "tat_tiger" diff --git a/code/modules/organs/internal/voicebox.dm b/code/modules/organs/internal/voicebox.dm new file mode 100644 index 0000000000..4de69fe8f2 --- /dev/null +++ b/code/modules/organs/internal/voicebox.dm @@ -0,0 +1,42 @@ +/* + * Voicebox/Vocal Synthesizers + * TL;DR: Assists with speaking languages that a species doesn't normally have, + * such as EAL. Not standard or organic, because at the moment it's undesireable to completely mute characters. + */ + +/obj/item/organ/internal/voicebox + name = "larynx" + icon_state = "larynx" + parent_organ = BP_TORSO // We don't have a neck area + organ_tag = O_VOICE + will_assist_languages = list(LANGUAGE_GALCOM) + +/obj/item/organ/internal/voicebox/New() + ..() + amend_assist_langs() + +/obj/item/organ/internal/voicebox/proc/amend_assist_langs() // Adds the list of language datums assisted by the voicebox to the list used in speaking + for(var/L in will_assist_languages) + assists_languages |= all_languages[L] + +/obj/item/organ/internal/voicebox/proc/add_assistable_langs(var/language) // Adds a new language (by string/define) to the list of things the voicebox can assist + will_assist_languages |= language + amend_assist_langs() // Can't think of a better place to put this, makes the voicebox actually start to assist with the added language + +///////////////////////////////// +// Voicebox Subtypes +///////////////////////////////// + +/obj/item/organ/internal/voicebox/assist // In the off chance we get a species that doesn't speak GalCom by default + +/obj/item/organ/internal/voicebox/assist/New() + ..() + mechassist() + +/obj/item/organ/internal/voicebox/robot + name = "vocal synthesizer" + will_assist_languages = list(LANGUAGE_GALCOM, LANGUAGE_EAL) // Synthetics spawn with this by default + +/obj/item/organ/internal/voicebox/robot/New() + ..() + robotize() diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 5fc5c64ea1..ea31950e3d 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -31,6 +31,10 @@ var/list/organ_cache = list() var/rejecting // Is this organ already being rejected? var/preserved = 0 // If this is 1, prevents organ decay. + // Language vars. Putting them here in case we decide to do something crazy with sign-or-other-nonverbal languages. + var/list/will_assist_languages = list() + var/list/datum/language/assists_languages = list() + /obj/item/organ/Destroy() if(owner) owner = null diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 3655e8b2cb..16250e2c22 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -72,6 +72,8 @@ var/open = 0 var/stage = 0 var/cavity = 0 + var/burn_stage = 0 //Surgical repair stage for burn. + var/brute_stage = 0 //Surgical repair stage for brute. // HUD element variable, see organ_icon.dm get_damage_hud_image() var/image/hud_damage_image @@ -1328,3 +1330,18 @@ Note that amputating the affected organ does in fact remove the infection from t if(6 to INFINITY) flavor_text += "a ton of [wound]\s" return english_list(flavor_text) + +// Returns a list of the clothing (not glasses) that are covering this part +/obj/item/organ/external/proc/get_covering_clothing() + var/list/covering_clothing = list() + if(owner) + var/list/protective_gear = list(owner.head, owner.wear_mask, owner.wear_suit, owner.w_uniform, owner.gloves, owner.shoes) + for(var/obj/item/clothing/gear in protective_gear) + if(gear.body_parts_covered & src.body_part) + covering_clothing |= gear + if(LAZYLEN(gear.accessories)) + for(var/obj/item/clothing/accessory/bling in gear.accessories) + if(bling.body_parts_covered & src.body_part) + covering_clothing |= bling + + return covering_clothing \ No newline at end of file diff --git a/code/modules/organs/organ_icon.dm b/code/modules/organs/organ_icon.dm index 1f5f583324..91b96fea31 100644 --- a/code/modules/organs/organ_icon.dm +++ b/code/modules/organs/organ_icon.dm @@ -179,6 +179,14 @@ var/global/list/limb_icon_cache = list() if(model) icon_cache_key += "_model_[model]" apply_colouration(mob_icon) + if(owner && owner.synth_markings) + for(var/M in markings) + var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"] + var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]") + mark_s.Blend(markings[M]["color"], ICON_ADD) + add_overlay(mark_s) //So when it's not on your body, it has icons + mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons + icon_cache_key += "[M][markings[M]["color"]]" dir = EAST icon = mob_icon diff --git a/code/modules/organs/subtypes/standard.dm b/code/modules/organs/subtypes/standard.dm index a499a437ab..a3ab809523 100644 --- a/code/modules/organs/subtypes/standard.dm +++ b/code/modules/organs/subtypes/standard.dm @@ -25,8 +25,9 @@ /obj/item/organ/external/chest/robotize() if(..()) - // Give them a new cell. - owner.internal_organs_by_name["cell"] = new /obj/item/organ/internal/cell(owner,1) + // Give them fancy new organs. + owner.internal_organs_by_name[O_CELL] = new /obj/item/organ/internal/cell(owner,1) + owner.internal_organs_by_name[O_VOICE] = new /obj/item/organ/internal/voicebox/robot(owner, 1) /obj/item/organ/external/chest/handle_germ_effects() . = ..() //Should return an infection level diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index c0870afda3..c239d1352a 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -134,7 +134,7 @@ var/global/photo_count = 0 var/icon_on = "camera" var/icon_off = "camera_off" var/size = 3 - var/picture_planes = list(PLANE_WORLD) + var/list/picture_planes = list() /obj/item/device/camera/verb/change_size() set name = "Set Photo Focus" @@ -185,7 +185,7 @@ var/global/photo_count = 0 // As well as anything that isn't invisible. for(var/atom/A in the_turf) if(A.invisibility) continue - if(!(A.plane in picture_planes)) continue + if(A.plane > 0 && !(A.plane in picture_planes)) continue atoms.Add(A) // Sort the atoms into their layers @@ -194,7 +194,7 @@ var/global/photo_count = 0 for(var/i; i <= sorted.len; i++) var/atom/A = sorted[i] if(A) - var/icon/img = getFlatIcon(A, picture_planes = picture_planes)//build_composite_icon(A) + var/icon/img = getFlatIcon(A, picture_planes)//build_composite_icon(A) // If what we got back is actually a picture, draw it. if(istype(img, /icon)) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 4085a7c9df..2d057825fa 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -160,6 +160,7 @@ var/list/possible_cable_coil_colours = list( return if(istype(W, /obj/item/weapon/wirecutters)) + var/obj/item/stack/cable_coil/CC if(d1 == UP || d2 == UP) to_chat(user, "You must cut this cable from above.") return @@ -172,9 +173,12 @@ var/list/possible_cable_coil_colours = list( return if(src.d1) // 0-X cables are 1 unit, X-X cables are 2 units long - new/obj/item/stack/cable_coil(T, 2, color) + CC = new/obj/item/stack/cable_coil(T, 2, color) else - new/obj/item/stack/cable_coil(T, 1, color) + CC = new/obj/item/stack/cable_coil(T, 1, color) + + src.add_fingerprint(user) + src.transfer_fingerprints_to(CC) for(var/mob/O in viewers(src, null)) O.show_message("[user] cuts the cable.", 1) diff --git a/code/modules/power/fusion/core/core_control.dm b/code/modules/power/fusion/core/core_control.dm index bb4e04b1e9..54d96883a7 100644 --- a/code/modules/power/fusion/core/core_control.dm +++ b/code/modules/power/fusion/core/core_control.dm @@ -3,21 +3,20 @@ icon = 'icons/obj/machines/power/fusion.dmi' icon_state = "core_control" light_color = COLOR_ORANGE - + circuit = /obj/item/weapon/circuitboard/fusion_core_control var/id_tag var/scan_range = 25 var/list/connected_devices = list() var/obj/machinery/power/fusion_core/cur_viewed_device /obj/machinery/computer/fusion_core_control/attackby(var/obj/item/thing, var/mob/user) + ..() if(ismultitool(thing)) var/new_ident = input("Enter a new ident tag.", "Core Control", id_tag) as null|text if(new_ident && user.Adjacent(src)) id_tag = new_ident cur_viewed_device = null return - else - return ..() /obj/machinery/computer/fusion_core_control/attack_ai(mob/user) attack_hand(user) @@ -28,6 +27,11 @@ /obj/machinery/computer/fusion_core_control/interact(mob/user) + if(stat & (BROKEN|NOPOWER)) + user.unset_machine() + user << browse(null, "window=fusion_control") + return + if(!cur_viewed_device || !check_core_status(cur_viewed_device)) cur_viewed_device = null @@ -174,3 +178,19 @@ if(C.idle_power_usage > C.avail()) return . = 1 + +/obj/machinery/computer/fusion_core_control/update_icon() + if(stat & (BROKEN)) + icon = 'icons/obj/computer.dmi' + icon_state = "broken" + set_light(0) + + if(stat & (NOPOWER)) + icon = 'icons/obj/computer.dmi' + icon_state = "computer" + set_light(0) + + if(!stat & (BROKEN|NOPOWER)) + icon = initial(icon) + icon_state = initial(icon_state) + set_light(light_range_on, light_power_on) diff --git a/code/modules/power/fusion/core/core_field.dm b/code/modules/power/fusion/core/core_field.dm index 1efb09d777..f5d85fb4bf 100644 --- a/code/modules/power/fusion/core/core_field.dm +++ b/code/modules/power/fusion/core/core_field.dm @@ -35,7 +35,7 @@ /obj/structure/cable, /obj/machinery/atmospherics, /obj/machinery/air_sensor, - /mob/observer/dead, + /mob/observer, /obj/machinery/power/hydromagnetic_trap ) @@ -672,4 +672,4 @@ #undef FUSION_HEAT_CAP #undef FUSION_MAX_ENVIRO_HEAT -#undef PLASMA_TEMP_RADIATION_DIVISIOR \ No newline at end of file +#undef PLASMA_TEMP_RADIATION_DIVISIOR diff --git a/code/modules/power/fusion/fuel_assembly/fuel_control.dm b/code/modules/power/fusion/fuel_assembly/fuel_control.dm index 6d95e358d8..e765c4d495 100644 --- a/code/modules/power/fusion/fuel_assembly/fuel_control.dm +++ b/code/modules/power/fusion/fuel_assembly/fuel_control.dm @@ -2,6 +2,7 @@ name = "fuel injection control computer" icon = 'icons/obj/machines/power/fusion.dmi' icon_state = "fuel" + circuit = /obj/item/weapon/circuitboard/fusion_fuel_control var/id_tag var/scan_range = 25 @@ -94,9 +95,25 @@ /obj/machinery/computer/fusion_fuel_control/attackby(var/obj/item/W, var/mob/user) + ..() if(ismultitool(W)) var/new_ident = input("Enter a new ident tag.", "Fuel Control", id_tag) as null|text if(new_ident && user.Adjacent(src)) id_tag = new_ident return - return ..() + +/obj/machinery/computer/fusion_fuel_control/update_icon() + if(stat & (BROKEN)) + icon = 'icons/obj/computer.dmi' + icon_state = "broken" + set_light(0) + + if(stat & (NOPOWER)) + icon = 'icons/obj/computer.dmi' + icon_state = "computer" + set_light(0) + + if(!stat & (BROKEN|NOPOWER)) + icon = initial(icon) + icon_state = initial(icon_state) + set_light(light_range_on, light_power_on) diff --git a/code/modules/power/fusion/gyrotron/gyrotron_control.dm b/code/modules/power/fusion/gyrotron/gyrotron_control.dm index 9f6c59c753..eb735a81f3 100644 --- a/code/modules/power/fusion/gyrotron/gyrotron_control.dm +++ b/code/modules/power/fusion/gyrotron/gyrotron_control.dm @@ -3,6 +3,7 @@ icon = 'icons/obj/machines/power/fusion.dmi' icon_state = "engine" light_color = COLOR_BLUE + circuit = /obj/item/weapon/circuitboard/gyrotron_control var/id_tag var/scan_range = 25 @@ -16,6 +17,11 @@ /obj/machinery/computer/gyrotron_control/interact(var/mob/user) + if(stat & (BROKEN|NOPOWER)) + user.unset_machine() + user << browse(null, "window=gyrotron_controller_[id_tag]") + return + if(!id_tag) to_chat(user, "This console has not been assigned an ident tag. Please contact your system administrator or conduct a manual update with a standard multitool.") return @@ -89,9 +95,25 @@ return 0 /obj/machinery/computer/gyrotron_control/attackby(var/obj/item/W, var/mob/user) + ..() if(ismultitool(W)) var/new_ident = input("Enter a new ident tag.", "Gyrotron Control", id_tag) as null|text if(new_ident && user.Adjacent(src)) id_tag = new_ident return - return ..() + +/obj/machinery/computer/gyrotron_control/update_icon() + if(stat & (BROKEN)) + icon = 'icons/obj/computer.dmi' + icon_state = "broken" + set_light(0) + + if(stat & (NOPOWER)) + icon = 'icons/obj/computer.dmi' + icon_state = "computer" + set_light(0) + + if(!stat & (BROKEN|NOPOWER)) + icon = initial(icon) + icon_state = initial(icon_state) + set_light(light_range_on, light_power_on) diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm index 0c3c76caaf..5ea1c0a2d6 100644 --- a/code/modules/projectiles/ammunition/magazines.dm +++ b/code/modules/projectiles/ammunition/magazines.dm @@ -325,6 +325,31 @@ /obj/item/ammo_magazine/box/c9mm/empty initial_ammo = 0 +/obj/item/ammo_magazine/m9mmR/saber + desc = "A very high capacity double stack magazine made specially for the SABER SMG. Filled with 22 9mm bullets." + icon_state = "S9mm-22" + mag_type = MAGAZINE + ammo_type = /obj/item/ammo_casing/a9mm + matter = list(DEFAULT_WALL_MATERIAL = 1200) + caliber = "9mm" + max_ammo = 22 + origin_tech = list(TECH_COMBAT = 2, TECH_ILLEGAL = 1) + multiple_sprites = 1 + +/obj/item/ammo_magazine/m9mmR/saber/ap + desc = "A high capacity double stack magazine made specially for the SABER SMG. Filled with 22 9mm armor piercing bullets." + icon_state = "S9mm-22" + mag_type = MAGAZINE + ammo_type = /obj/item/ammo_casing/a9mm/ap + matter = list(DEFAULT_WALL_MATERIAL = 2000) + caliber = "9mm" + max_ammo = 22 + origin_tech = list(TECH_COMBAT = 2, TECH_ILLEGAL = 1) + multiple_sprites = 1 + +/obj/item/ammo_magazine/m9mmR/saber/empty + initial_ammo = 0 + ///////// 10mm ///////// /obj/item/ammo_magazine/m10mm diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index 4c7e0e3e88..a1afc075b5 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -1,25 +1,40 @@ -/obj/item/weapon/gun/projectile/automatic //Hopefully someone will find a way to make these fire in bursts or something. --Superxpdude //Except burstfire isn't fit for an rp server --Mark +/obj/item/weapon/gun/projectile/automatic //This should never be spawned in, it is just here because of code necessities. + name = "daka SMG" + desc = "A small SMG. You really shouldn't be able to get this gun. Uses 9mm rounds." + icon_state = "c05r" //Used because it's not used anywhere else + load_method = SPEEDLOADER + ammo_type = /obj/item/ammo_casing/a9mm + projectile_type = /obj/item/projectile/bullet/pistol + +//Burst is the number of bullets fired; Fire delay is the time you have to wait to shoot the gun again, Move delay is the same but for moving after shooting. . +//Burst accuracy is the accuracy of each bullet fired in the burst. Dispersion is how much the bullets will 'spread' away from where you aimed. + + firemodes = list( + list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, burst_accuracy=null, dispersion=null), + list(mode_name="3-round bursts", burst=3, fire_delay=null, move_delay=4, burst_accuracy=list(0,-15,-15), dispersion=list(0.0, 0.6, 1.0))) + +/obj/item/weapon/gun/projectile/automatic/saber //Fixed it name = "prototype SMG" desc = "A protoype lightweight, fast firing gun. Uses 9mm rounds." - icon_state = "saber" //ugly + icon = 'icons/obj/gun.dmi' + icon_state = "saber"//Still ugly w_class = ITEMSIZE_NORMAL - load_method = SPEEDLOADER //yup. until someone sprites a magazine for it. + load_method = MAGAZINE //This should fix it max_shells = 22 caliber = "9mm" origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 2) slot_flags = SLOT_BELT - ammo_type = /obj/item/ammo_casing/a9mm + magazine_type = /obj/item/ammo_magazine/m9mmR/saber + allowed_magazines = list(/obj/item/ammo_magazine/m9mmR/saber, /obj/item/ammo_magazine/m9mmR/saber/ap) projectile_type = /obj/item/projectile/bullet/pistol multi_aim = 1 burst_delay = 2 -// one_handed_penalty = 15 - firemodes = list( list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, burst_accuracy=null, dispersion=null), list(mode_name="3-round bursts", burst=3, fire_delay=null, move_delay=4, burst_accuracy=list(0,-15,-15), dispersion=list(0.0, 0.6, 1.0)) -// list(mode_name="short bursts", burst=5, fire_delay=null, move_delay=4, burst_accuracy=list(0,-15,-15,-30,-30), dispersion=list(0.6, 1.0, 1.0, 1.0, 1.2)), - ) + // list(mode_name="short bursts", burst=5, fire_delay=null, move_delay=4, burst_accuracy=list(0,-15,-15,-30,-30), dispersion=list(0.6, 1.0, 1.0, 1.0, 1.2)), + ) /obj/item/weapon/gun/projectile/automatic/c20r name = "submachine gun" diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm index d315deb111..c98a69aff8 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm @@ -858,7 +858,7 @@ glass_name = "lime tea" glass_desc = "A tasty mixture of lime and tea. It's apparently good for you!" - cup_name = "cup of berry tea" + cup_name = "cup of lime tea" cup_desc = "A tasty mixture of lime and tea. It's apparently good for you!" /datum/reagent/drink/tea/orangetea diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index ef0d4a2100..724cee9a6f 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -49,7 +49,7 @@ if(H.a_intent != I_HELP) to_chat(user, "[H] is resisting your attempt to inject them with \the [src].") to_chat(H, " [user] is trying to inject you with \the [src]!") - if(!do_after(user, 30)) + if(!do_after(user, 30, H)) return user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) diff --git a/code/modules/research/designs/weapons.dm b/code/modules/research/designs/weapons.dm index ddf64473eb..828856aeba 100644 --- a/code/modules/research/designs/weapons.dm +++ b/code/modules/research/designs/weapons.dm @@ -47,9 +47,10 @@ /datum/design/item/weapon/smg id = "smg" + desc = "An compact reliable SMG firing armor piercing ammo." req_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3) materials = list(DEFAULT_WALL_MATERIAL = 8000, "silver" = 2000, "diamond" = 1000) - build_path = /obj/item/weapon/gun/projectile/automatic + build_path = /obj/item/weapon/gun/projectile/automatic/saber sort_string = "TAABA" /datum/design/item/weapon/ammo_9mm diff --git a/code/modules/surgery/external_repair.dm b/code/modules/surgery/external_repair.dm new file mode 100644 index 0000000000..b26d803b34 --- /dev/null +++ b/code/modules/surgery/external_repair.dm @@ -0,0 +1,215 @@ +//Procedures in this file: Organic limb repair +////////////////////////////////////////////////////////////////// +// LIMB REPAIR SURGERY // +////////////////////////////////////////////////////////////////// +/datum/surgery_step/repairflesh/ + priority = 1 + can_infect = 1 + blood_level = 1 + req_open = 1 + +/datum/surgery_step/repairflesh/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (target.stat == DEAD) // Sorry defibs, your subjects need to have pumping fluids for these to work. + return 0 + if (isslime(target)) + return 0 + if (target_zone == O_EYES || target_zone == O_MOUTH) + return 0 + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if (affected == null) + return 0 + if (affected.is_stump()) + return 0 + if (affected.robotic >= ORGAN_ROBOT) + return 0 + return 1 + + +////////////////////////////////////////////////////////////////// +// SCAN STEP // +////////////////////////////////////////////////////////////////// + +/datum/surgery_step/repairflesh/scan_injury + allowed_tools = list( + /obj/item/weapon/autopsy_scanner = 100, + /obj/item/device/healthanalyzer = 80, + /obj/item/device/analyzer = 10 + ) + + priority = 2 + + can_infect = 0 //The only exception here. Sweeping a scanner probably won't transfer many germs. + + min_duration = 20 + max_duration = 40 + +/datum/surgery_step/repairflesh/scan_injury/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(affected.burn_stage || affected.brute_stage) + return 0 + return 1 + return 0 + +/datum/surgery_step/repairflesh/scan_injury/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] begins scanning [target]'s [affected] with \the [tool].", \ + "You begin scanning [target]'s [affected] with \the [tool].") + ..() + +/datum/surgery_step/repairflesh/scan_injury/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] finishes scanning [target]'s [affected].", \ + "You finish scanning [target]'s [affected].") + if(affected.brute_dam) + to_chat(user, "The muscle in [target]'s [affected] is notably bruised.") + if(affected.status & ORGAN_BROKEN) + to_chat(user, "\The [target]'s [affected] is broken!") + affected.brute_stage = max(1, affected.brute_stage) + if(affected.burn_dam) + to_chat(user, "\The muscle in [target]'s [affected] is notably charred.") + affected.burn_stage = max(1, affected.burn_stage) + +/datum/surgery_step/repairflesh/scan_injury/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, dropping \the [tool] onto [target]'s [affected]!" , \ + "Your hand slips, dropping \the [tool] onto [target]'s [affected]!" ) + affected.createwound(BRUISE, 10) + +////////////////////////////////////////////////////////////////// +// BURN STEP // +////////////////////////////////////////////////////////////////// + +/datum/surgery_step/repairflesh/repair_burns + allowed_tools = list( + /obj/item/stack/medical/advanced/ointment = 100, + /obj/item/weapon/surgical/FixOVein = 100, + /obj/item/weapon/surgical/hemostat = 60, + /obj/item/stack/medical/ointment = 50, + /obj/item/weapon/tape_roll = 30, + /obj/item/taperoll = 10 + ) + + priority = 3 + + min_duration = 90 + max_duration = 120 + +/datum/surgery_step/repairflesh/repair_burns/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(affected.burn_stage < 1 || !(affected.burn_dam)) + return 0 + if(affected.burn_dam < affected.brute_dam) + return 0 + return 1 + return 0 + +/datum/surgery_step/repairflesh/repair_burns/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(istype(tool, /obj/item/weapon/tape_roll) || istype(tool, /obj/item/taperoll)) + user.visible_message("[user] begins taping up [target]'s [affected] with \the [tool].", \ + "You begin taping up [target]'s [affected] with \the [tool].") + affected.jostle_bone(10) + else if(istype(tool, /obj/item/weapon/surgical/hemostat) || istype(tool, /obj/item/weapon/surgical/FixOVein)) + user.visible_message("[user] begins mending the charred blood vessels in [target]'s [affected] with \the [tool].", \ + "You begin mending the charred blood vessels in [target]'s [affected] with \the [tool].") + else + user.visible_message("[user] begins coating the charred tissue in [target]'s [affected] with \the [tool].", \ + "You begin coating the charred tissue in [target]'s [affected] with \the [tool].") + ..() + +/datum/surgery_step/repairflesh/repair_burns/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(istype(tool, /obj/item/weapon/tape_roll) || istype(tool, /obj/item/taperoll)) + user.visible_message("[user] finishes taping up [target]'s [affected] with \the [tool].", \ + "You finish taping up [target]'s [affected] with \the [tool].") + affected.createwound(BRUISE, 10) + affected.heal_damage(0, 25, 0, 0) + if(!(affected.burn_dam)) + affected.burn_stage = 0 + if(istype(tool, /obj/item/stack)) + var/obj/item/stack/T = tool + T.use(1) + ..() + +/datum/surgery_step/repairflesh/repair_burns/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, tearing up [target]'s [affected] with \the [tool].", \ + "Your hand slips, tearing up [target]'s [affected] with \the [tool].") + affected.createwound(BRUISE, 10) + affected.createwound(CUT, 5) + if(istype(tool, /obj/item/stack) && prob(30)) + var/obj/item/stack/T = tool + T.use(1) + ..() + +////////////////////////////////////////////////////////////////// +// BRUTE STEP // +////////////////////////////////////////////////////////////////// + +/datum/surgery_step/repairflesh/repair_brute + allowed_tools = list( + /obj/item/stack/medical/advanced/bruise_pack = 100, + /obj/item/weapon/surgical/cautery = 100, + /obj/item/weapon/surgical/bonesetter = 60, + /obj/item/stack/medical/bruise_pack = 50, + /obj/item/weapon/tape_roll = 40, + /obj/item/taperoll = 10 + ) + + priority = 3 + + min_duration = 90 + max_duration = 120 + +/datum/surgery_step/repairflesh/repair_brute/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(..()) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(affected.brute_stage < 1 || !(affected.brute_dam)) + return 0 + if(affected.brute_dam < affected.burn_dam) + return 0 + return 1 + return 0 + +/datum/surgery_step/repairflesh/repair_brute/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(istype(tool, /obj/item/weapon/tape_roll) || istype(tool, /obj/item/taperoll)) + user.visible_message("[user] begins taping up [target]'s [affected] with \the [tool].", \ + "You begin taping up [target]'s [affected] with \the [tool].") + affected.jostle_bone(10) + else if(istype(tool, /obj/item/weapon/surgical/FixOVein) || istype(tool, /obj/item/weapon/surgical/bonesetter)) + user.visible_message("[user] begins mending the torn tissue in [target]'s [affected] with \the [tool].", \ + "You begin mending the torn tissue in [target]'s [affected] with \the [tool].") + else + user.visible_message("[user] begins coating the tissue in [target]'s [affected] with \the [tool].", \ + "You begin coating the tissue in [target]'s [affected] with \the [tool].") + ..() + +/datum/surgery_step/repairflesh/repair_brute/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if(istype(tool, /obj/item/weapon/tape_roll) || istype(tool, /obj/item/taperoll)) + user.visible_message("[user] finishes taping up [target]'s [affected] with \the [tool].", \ + "You finish taping up [target]'s [affected] with \the [tool].") + affected.createwound(BRUISE, 10) + affected.heal_damage(25, 0, 0, 0) + if(!(affected.brute_dam)) + affected.brute_stage = 0 + if(istype(tool, /obj/item/stack)) + var/obj/item/stack/T = tool + T.use(1) + ..() + +/datum/surgery_step/repairflesh/repair_brute/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, tearing up [target]'s [affected] with \the [tool].", \ + "Your hand slips, tearing up [target]'s [affected] with \the [tool].") + affected.createwound(BRUISE, 10) + affected.createwound(CUT, 5) + if(istype(tool, /obj/item/stack) && prob(30)) + var/obj/item/stack/T = tool + T.use(1) + ..() diff --git a/code/modules/xenoarcheaology/tools/equipment.dm b/code/modules/xenoarcheaology/tools/equipment.dm index 186745a277..5bc7694df5 100644 --- a/code/modules/xenoarcheaology/tools/equipment.dm +++ b/code/modules/xenoarcheaology/tools/equipment.dm @@ -4,6 +4,7 @@ icon = 'icons/obj/clothing/spacesuits.dmi' icon_state = "engspace_suit" item_state = "engspace_suit" + update_icon_define = "icons/mob/spacesuit.dmi" armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 100, rad = 100) /obj/item/clothing/head/bio_hood/anomaly diff --git a/html/changelog.html b/html/changelog.html index c61d9998ce..d62a2751dc 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -53,6 +53,33 @@ -->
+

14 July 2018

+

Anewbe updated:

+ +

Atermonera updated:

+ +

Mechoid updated:

+ + +

12 July 2018

+

Anewbe updated:

+ +

21 June 2018

Anewbe updated: