diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 41cd2923af08..33ddd50f5df8 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -788,7 +788,7 @@ Each role inherits the lower role's responsibilities (IE: Headcoders also have c `Headcoders` are the overarching "administrators" of the repository. People included in this role are: * [farie82](https://github.com/farie82) -* [Charliminator](https://github.com/hal9000PR) +* [S34N](https://github.com/S34NW) * [SteelSlayer](https://github.com/SteelSlayer) --- @@ -797,21 +797,21 @@ Each role inherits the lower role's responsibilities (IE: Headcoders also have c * [AffectedArc07](https://github.com/AffectedArc07) +* [Charliminator](https://github.com/hal9000PR) * [lewcc](https://github.com/lewcc) -* [S34N](https://github.com/S34NW) --- `Review Team` members are people who are denoted as having reviews which can affect mergeability status. People included in this role are: -* [lewcc](https://github.com/lewcc) -* [S34N](https://github.com/S34NW) -* [Sirryan2002](https://github.com/Sirryan2002) -* [Contrabang](https://github.com/Contrabang) * [Burzah](https://github.com/Burzah) +* [Charliminator](https://github.com/hal9000PR) +* [Contrabang](https://github.com/Contrabang) * [DGamerL](https://github.com/DGamerL) -* [Warriorstar](https://github.com/warriorstar-orion) * [Henri215](https://github.com/Henri215) +* [lewcc](https://github.com/lewcc) +* [Sirryan2002](https://github.com/Sirryan2002) +* [Warriorstar](https://github.com/warriorstar-orion) --- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a294c4b493c4..c02f49ef71f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,7 @@ jobs: python tools/ci/unticked_files.py ${GITHUB_WORKSPACE} python tools/ci/illegal_dme_files.py ${GITHUB_WORKSPACE} python -m tools.ci.check_icon_conflicts + python -m tools.ci.check_icon_dupenames python -m tools.maplint.source --github DREAMCHECKER_EXIT_CODE=0 ~/dreamchecker > ${GITHUB_WORKSPACE}/output-annotations.txt 2>&1 || DREAMCHECKER_EXIT_CODE=$? diff --git a/code/__DEFINES/power_defines.dm b/code/__DEFINES/power_defines.dm index 0a8694dbb1fb..15d4e1c1baa9 100644 --- a/code/__DEFINES/power_defines.dm +++ b/code/__DEFINES/power_defines.dm @@ -38,3 +38,5 @@ #define APC_IS_CHARGING 1 /// APC battery is at 100% #define APC_FULLY_CHARGED 2 + +#define KW *1000 diff --git a/code/__HELPERS/trait_helpers.dm b/code/__HELPERS/trait_helpers.dm index b19bf436541a..e3feed27c701 100644 --- a/code/__HELPERS/trait_helpers.dm +++ b/code/__HELPERS/trait_helpers.dm @@ -227,6 +227,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai //***** MIND TRAITS *****/ #define TRAIT_HOLY "is_holy" // The mob is holy in regards to religion #define TRAIT_TABLE_LEAP "table_leap" +#define TRAIT_SLEIGHT_OF_HAND "sleight_of_hand" //***** ITEM AND MOB TRAITS *****// /// Show what machine/door wires do when held. diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 159b0cb0baa1..036e141d9ed9 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -92,6 +92,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( /datum/mind = list( "TRAIT_HOLY" = TRAIT_HOLY, + "TRAIT_SLEIGHT_OF_HAND" = TRAIT_SLEIGHT_OF_HAND, "TRAIT_TABLE_LEAP" = TRAIT_TABLE_LEAP ), diff --git a/code/_onclick/click_override.dm b/code/_onclick/click_override.dm index 9bdd7691a1a4..1309e3c9cdc2 100644 --- a/code/_onclick/click_override.dm +++ b/code/_onclick/click_override.dm @@ -71,7 +71,7 @@ var/atom/beam_from = user var/atom/target_atom = A - for(var/i in 0 to 3) + for(var/i in 0 to 2) //3 attempts. Shocks at the clicked source, tries to find a mob in 1 tile, then choses a random tile 1 away to try again. As such, can only hit a mob 2 tiles away from the click beam_from.Beam(target_atom, icon_state = "lightning[rand(1, 12)]", icon = 'icons/effects/effects.dmi', time = 6) if(isliving(target_atom)) var/mob/living/L = target_atom @@ -81,7 +81,12 @@ L.apply_damage(60, STAMINA) L.Jitter(10 SECONDS) var/atom/throw_target = get_edge_target_turf(user, get_dir(user, get_step_away(L, user))) - L.throw_at(throw_target, powergrid / 100000, powergrid / 100000) //100 kW in grid throws 1 tile, 200 throws 2, etc. + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(H.gloves && H.gloves.siemens_coefficient == 0) //No throwing with insulated gloves (you still get stamina however) + break + L.throw_at(throw_target, powergrid / (150 KW), powergrid / (300 KW)) //150 kW in grid throws 1 tile, 300 throws 2, etc. + else add_attack_logs(user, L, "electrocuted with[P.unlimited_power ? " unlimited" : null] power bio-chip") if(P.unlimited_power) @@ -90,13 +95,13 @@ electrocute_mob(L, C.powernet, P) break var/list/next_shocked = list() - for(var/mob/M in range(3, target_atom)) //Try to jump to a mob first + for(var/mob/M in range(1, target_atom)) //Try to jump to a mob first if(M == user || isobserver(M)) continue next_shocked.Add(M) break //Break this so it gets the closest, thank you if(!length(next_shocked)) //No mob? Random bullshit go, try to get closer to a mob with luck - for(var/atom/movable/AM in orange(3, target_atom)) + for(var/atom/movable/AM in orange(1, target_atom)) if(AM == user || iseffect(AM) || isobserver(AM)) continue next_shocked.Add(AM) diff --git a/code/datums/diseases/advance/symptoms/hair.dm b/code/datums/diseases/advance/symptoms/hair.dm new file mode 100644 index 000000000000..60419bd5b25f --- /dev/null +++ b/code/datums/diseases/advance/symptoms/hair.dm @@ -0,0 +1,49 @@ +/* +////////////////////////////////////// +Cranial Hypertrichosis + + Very very Noticeable. + Decreases resistance slightly. + Decreases stage speed. + Reduced transmittability + Intense Level. + +BONUS + Makes the mob grow massive hair, regardless of gender. + +////////////////////////////////////// +*/ + +/datum/symptom/hair + name = "Cranial Hypertrichosis" + stealth = -3 + resistance = -1 + stage_speed = -3 + transmittable = -1 + level = 4 + severity = 1 + +/datum/symptom/hair/Activate(datum/disease/advance/A) + ..() + if(prob(SYMPTOM_ACTIVATION_PROB)) + if(!ishuman(A.affected_mob)) + return + var/mob/living/carbon/human/H = A.affected_mob + if(H.dna.species.bodyflags & BALD) + return + var/obj/item/organ/external/head/head_organ = H.get_organ("head") + if(!istype(head_organ)) + return + switch(A.stage) + if(1, 2, 3) + to_chat(H, "Your scalp itches.") + head_organ.h_style = random_hair_style(H.gender, head_organ.dna.species.name) + else + to_chat(H, "Hair bursts forth from your scalp!") + var/datum/sprite_accessory/tmp_hair_style = GLOB.hair_styles_full_list["Very Long Hair"] + + if(head_organ.dna.species.name in tmp_hair_style.species_allowed) //If 'Very Long Hair' is a style the person's species can have, give it to them. + head_organ.h_style = "Very Long Hair" + else //Otherwise, give them a random hair style. + head_organ.h_style = random_hair_style(H.gender, head_organ.dna.species.name) + H.update_hair() diff --git a/code/datums/uplink_items/uplink_general.dm b/code/datums/uplink_items/uplink_general.dm index ac1040135473..43713e9bdd03 100644 --- a/code/datums/uplink_items/uplink_general.dm +++ b/code/datums/uplink_items/uplink_general.dm @@ -697,6 +697,14 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 5 surplus = 10 +/datum/uplink_item/suits/smoke_grenade + name = "Smoke Grenade Module" + desc = "A module that dispenses primed smoke grenades to disperse crowds." + reference = "SGM" + item = /obj/item/mod/module/dispenser/smoke + cost = 10 + surplus = 10 + /datum/uplink_item/device_tools/binary name = "Binary Translator Key" desc = "A key, that when inserted into a radio headset, allows you to listen to and talk with artificial intelligences and cybernetic organisms in binary. To talk on the binary channel, type :+ before your radio message." diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm index 44be9000c319..d589d34ea973 100644 --- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm +++ b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm @@ -1,4 +1,3 @@ -#define KW *1000 #define PULSEDEMON_REMOTE_DRAIN_MULTIPLIER 5 #define PD_UPGRADE_HIJACK_SPEED "Speed" @@ -484,4 +483,3 @@ return FALSE return TRUE -#undef KW diff --git a/code/game/gamemodes/scoreboard.dm b/code/game/gamemodes/scoreboard.dm index 71106e0ee581..3fd1e5e434ae 100644 --- a/code/game/gamemodes/scoreboard.dm +++ b/code/game/gamemodes/scoreboard.dm @@ -129,7 +129,7 @@ GLOBAL_VAR(scoreboard) // Variable to save the scoreboard string once it's been /datum/scoreboard/proc/check_station_player(mob/M) - if(!is_station_level(M.z) || M.stat < DEAD) + if(!is_station_level(M.z) || M.stat != DEAD) return if(isAI(M)) dead_ai = TRUE diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm index 7608f59fce04..efff255a6398 100644 --- a/code/game/jobs/job/support.dm +++ b/code/game/jobs/job/support.dm @@ -200,10 +200,8 @@ singlemutcheck(H, GLOB.soberblock, MUTCHK_FORCED) H.dna.default_blocks.Add(GLOB.soberblock) H.check_mutations = 1 - var/datum/martial_art/judo/under_siege/bouncer_delight = new - bouncer_delight.teach(H) ADD_TRAIT(H.mind, TRAIT_TABLE_LEAP, ROUNDSTART_TRAIT) - + ADD_TRAIT(H.mind, TRAIT_SLEIGHT_OF_HAND, ROUNDSTART_TRAIT) /datum/job/chef title = "Chef" diff --git a/code/game/objects/items/devices/autopsy.dm b/code/game/objects/items/devices/autopsy.dm index 8877f2a74ea4..141a89738957 100644 --- a/code/game/objects/items/devices/autopsy.dm +++ b/code/game/objects/items/devices/autopsy.dm @@ -12,6 +12,7 @@ var/target_name = null var/target_UID = null var/timeofdeath = null + var/target_rank = null /obj/item/autopsy_scanner/Destroy() QDEL_LIST_ASSOC_VAL(wdata) @@ -66,23 +67,28 @@ if(O.trace_chemicals[V] > 0 && !chemtraces.Find(V)) chemtraces += V +/obj/item/autopsy_scanner/examine(mob/user) + . = ..() + if(Adjacent(user)) + . += "You can use a pen on it to quickly write a coroner's report." + /obj/item/autopsy_scanner/attackby(obj/item/P, mob/user) - if(is_pen(P)) - var/dead_name = input("Insert name of deceased individual") - var/dead_rank = input("Insert rank of deceased individual") - var/dead_tod = input("Insert time of death") - var/dead_cause = input("Insert cause of death") - var/dead_chems = input("Insert any chemical traces") - var/dead_notes = input("Insert any relevant notes") - var/obj/item/paper/R = new(user.loc) - R.name = "Official Coroner's Report - [dead_name]" - R.info = "[SSmapping.map_datum.fluff_name] - Coroner's Report

Name of Deceased: [dead_name]

Rank of Deceased: [dead_rank]

Time of Death: [dead_tod]

Cause of Death: [dead_cause]

Trace Chemicals: [dead_chems]

Additional Coroner's Notes: [dead_notes]

Coroner's Signature: " - playsound(loc, 'sound/goonstation/machines/printer_thermal.ogg', 50, 1) - sleep(10) - user.put_in_hands(R) - else + if(!is_pen(P)) return ..() + var/dead_name = tgui_input_text(user, "Insert name of deceased individual", default = target_name, title = "Coroner's Report", max_length = 60) + var/rank = tgui_input_text(user, "Insert rank of deceased individual", default = target_rank, title = "Coroner's Report", max_length = 60) + var/tod = tgui_input_text(user, "Insert time of death", default = station_time_timestamp("hh:mm", timeofdeath), title = "Coroner's Report", max_length = 60) + var/cause = tgui_input_text(user, "Insert cause of death", title = "Coroner's Report", max_length = 60) + var/chems = tgui_input_text(user, "Insert any chemical traces", multiline = TRUE, title = "Coroner's Report") + var/notes = tgui_input_text(user, "Insert any relevant notes", multiline = TRUE, title = "Coroner's Report") + var/obj/item/paper/R = new(user.loc) + R.name = "Official Coroner's Report - [dead_name]" + R.info = "
[station_name()] - Coroner's Report


Name of Deceased: [dead_name]

Rank of Deceased: [rank]

Time of Death: [tod]

Cause of Death: [cause]

Trace Chemicals: [chems]

Additional Coroner's Notes: [notes]

Coroner's Signature: " + playsound(loc, 'sound/goonstation/machines/printer_thermal.ogg', 50, TRUE) + sleep(1 SECONDS) + user.put_in_hands(R) + /obj/item/autopsy_scanner/attack_self(mob/user) var/scan_data = "" @@ -161,6 +167,7 @@ if(target_UID != M.UID()) target_UID = M.UID() target_name = M.name + target_rank = M.get_assignment(if_no_id = "Unknown", if_no_job = null) wdata.Cut() chemtraces.Cut() timeofdeath = null diff --git a/code/game/objects/items/tools/welder.dm b/code/game/objects/items/tools/welder.dm index 72f286458d94..5fbbf2187e99 100644 --- a/code/game/objects/items/tools/welder.dm +++ b/code/game/objects/items/tools/welder.dm @@ -146,6 +146,20 @@ return remove_fuel(0.5) +/obj/item/weldingtool/attack(mob/living/carbon/M, mob/living/carbon/user) + // For lighting other people's cigarettes. + var/obj/item/clothing/mask/cigarette/cig = M?.wear_mask + if(!istype(cig) || user.zone_selected != "mouth" || !tool_enabled) + return ..() + + if(M == user) + cig.attackby(src, user) + return + + cig.light("[user] holds out [src] out for [M], and casually lights [cig]. What a badass.") + playsound(src, 'sound/items/lighter/light.ogg', 25, TRUE) + M.update_inv_wear_mask() + /obj/item/weldingtool/use_tool(atom/target, user, delay, amount, volume, datum/callback/extra_checks) target.add_overlay(GLOB.welding_sparks) var/did_thing = ..() diff --git a/code/game/objects/items/weapons/grenades/smokebomb.dm b/code/game/objects/items/weapons/grenades/smokebomb.dm index 54074e29ed31..ad386ee55032 100644 --- a/code/game/objects/items/weapons/grenades/smokebomb.dm +++ b/code/game/objects/items/weapons/grenades/smokebomb.dm @@ -28,10 +28,5 @@ src.smoke.start() sleep(10) src.smoke.start() - - for(var/obj/structure/blob/B in view(8,src)) - var/damage = round(30/(get_dist(B,src)+1)) - B.take_damage(damage, BURN, MELEE, 0) sleep(80) qdel(src) - return diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index caf4ce0f190c..7079b62de981 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -588,6 +588,7 @@ ..() if(amount != length(contents)) update_icon() + orient2hud(user) // Update the displayed items and their counts /obj/item/storage/belt/holster name = "shoulder holster" diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index 03cfae8693ef..d94e72c3f573 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -187,6 +187,7 @@ return ..() // Whack them too if in harm intent if(!turned_on) + user.do_attack_animation(L) L.visible_message("[user] has prodded [L] with [src]. Luckily it was off.", "[L == user ? "You prod yourself" : "[user] has prodded you"] with [src]. Luckily it was off.") return diff --git a/code/game/objects/mail.dm b/code/game/objects/mail.dm index 8da165a7be11..6e23945bb58b 100644 --- a/code/game/objects/mail.dm +++ b/code/game/objects/mail.dm @@ -15,6 +15,8 @@ var/list/job_list = list() /// The real name required to open the letter var/recipient + /// The job of the recipient + var/recipient_job var/has_been_scanned = FALSE /obj/item/envelope/suicide_act(mob/user) @@ -49,11 +51,16 @@ if(mail_attracted_people.assigned_role in job_list) recipient = mail_attracted_people.current.real_name name = "letter to [recipient]" + recipient_job = lowertext(mail_attracted_people.assigned_role) return if(!admin_spawned) log_debug("Failed to find a new name to assign to [src]!") qdel(src) +/obj/item/envelope/examine(mob/user) + . = ..() + . += "This letter is addressed to [recipient], the [recipient_job]." + /obj/item/envelope/security icon_state = "mail_sec" possible_contents = list(/obj/item/food/snacks/donut/sprinkles, diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index d633e142fbd5..8421dbf71206 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -302,6 +302,9 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list( spawn(1) // This setting exposes the profiler for people with R_VIEWRUNTIMES. They must still have it set in cfg/admin.txt control_freak = 0 + if(is_connecting_from_localhost()) + verbs += /client/proc/export_current_character + /client/proc/remove_admin_verbs() verbs.Remove( @@ -1055,3 +1058,12 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list( show_blurb(about_to_be_banned, 15, message, null, "center", "center", message_color, null, null, 1) log_admin("[key_name(src)] sent an admin alert to [key_name(about_to_be_banned)] with custom message [message].") message_admins("[key_name(src)] sent an admin alert to [key_name(about_to_be_banned)] with custom message [message].") + + +/client/proc/export_current_character() + set name = "Export Character DMI/JSON" + set category = "Admin" + + if(ishuman(mob)) + var/mob/living/carbon/human/H = mob + H.export_dmi_json() diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 66f5fab88d87..b856869ace8e 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -165,7 +165,7 @@ var/ping_link = check_rights(R_ADMIN, 0, mob) ? "(PING)" : "" var/window_link = "(WINDOW)" var/alert_link = check_rights(R_ADMIN, FALSE, mob) ? " (ALERT)" : "" - to_chat(src, "[send_pm_type][type] to-[holder ? key_name(C, TRUE, type) : key_name_hidden(C, TRUE, type)]: [emoji_msg] [ping_link] [window_link][alert_link]") + to_chat(src, "[send_pm_type][type] to-[holder ? key_name(C, TRUE, type) : key_name_hidden(C, TRUE, type)]: [emoji_msg] [ping_link] [window_link][alert_link]", MESSAGE_TYPE_ADMINPM) /*if(holder && !C.holder) C.last_pm_recieved = world.time diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm index dcec4ba770a8..f6c1d2fb4108 100644 --- a/code/modules/antagonists/changeling/changeling_power.dm +++ b/code/modules/antagonists/changeling/changeling_power.dm @@ -90,6 +90,9 @@ if(HAS_TRAIT(user, TRAIT_FAKEDEATH) && !bypass_fake_death) to_chat(user, "We are incapacitated.") return FALSE + if(!cling.can_use_powers) + to_chat(owner, "Our cells are repairing themselves, we are unable to use our powers!") + return FALSE return TRUE // Transform the target to the chosen dna. Used in transform.dm and tiny_prick.dm (handy for changes since it's the same thing done twice) diff --git a/code/modules/antagonists/changeling/datum_changeling.dm b/code/modules/antagonists/changeling/datum_changeling.dm index f8c39e74fd9b..a507ad5cfa36 100644 --- a/code/modules/antagonists/changeling/datum_changeling.dm +++ b/code/modules/antagonists/changeling/datum_changeling.dm @@ -48,6 +48,10 @@ var/datum/action/changeling/sting/chosen_sting /// If the changeling is in the process of regenerating from their fake death. var/regenerating = FALSE + /// Did changeling use headslug? + var/headslugged = FALSE + /// Can you use abilities due to a recent revival? + var/can_use_powers = TRUE blurb_text_color = COLOR_PURPLE blurb_text_outline_width = 1 diff --git a/code/modules/antagonists/changeling/powers/absorb.dm b/code/modules/antagonists/changeling/powers/absorb.dm index 75b3b4ea4a3f..6e8b98bc5ea3 100644 --- a/code/modules/antagonists/changeling/powers/absorb.dm +++ b/code/modules/antagonists/changeling/powers/absorb.dm @@ -86,6 +86,10 @@ target_cling.absorbed_dna.len = 1 target_cling.absorbed_count = 0 + if(cling.headslugged) + cling.headslugged = FALSE + to_chat(user, "By absorbing [target], we are once again strong enough to turn into a headslug.") + cling.chem_charges = min(cling.chem_charges + 10, cling.chem_storage) cling.is_absorbing = FALSE diff --git a/code/modules/antagonists/changeling/powers/become_headslug.dm b/code/modules/antagonists/changeling/powers/become_headslug.dm index 2ef080c80461..a5c7b712ffc4 100644 --- a/code/modules/antagonists/changeling/powers/become_headslug.dm +++ b/code/modules/antagonists/changeling/powers/become_headslug.dm @@ -1,19 +1,21 @@ /datum/action/changeling/headslug name = "Last Resort" - desc = "We sacrifice our current body in a moment of need, placing us in control of a vessel that can plant our likeness in a new host. Costs 20 chemicals." - helptext = "We will be placed in control of a small, fragile creature. We may attack a corpse like this to plant an egg which will slowly mature into a new form for us." + desc = "We sacrifice our current body in a moment of need, placing us in control of a vessel that can plant our likeness in a new host. Costs 20 chemicals. We will need to absorb someone to use this ability again." + helptext = "We will be placed in control of a small, fragile creature. We may attack a corpse like this to plant an egg which will slowly mature into a new form for us. This ability is available only once per absorption." button_icon_state = "last_resort" chemical_cost = 20 - dna_cost = 2 req_human = TRUE req_stat = DEAD bypass_fake_death = TRUE - power_type = CHANGELING_PURCHASABLE_POWER - category = /datum/changeling_power_category/defence + power_type = CHANGELING_INNATE_POWER /datum/action/changeling/headslug/try_to_sting(mob/user, mob/target) - if(tgui_alert(user, "Are you sure you wish to do this? This action cannot be undone.", "Sting", list("Yes", "No")) == "No") + if(cling.headslugged) + to_chat(user, "We need to absorb a humanoid to headslug again.") return + if(tgui_alert("Are you sure you wish to do this? This action cannot be undone.",,"Yes","No") != "Yes") + return + cling.headslugged = TRUE ..() /datum/action/changeling/headslug/sting_action(mob/user) diff --git a/code/modules/antagonists/changeling/powers/revive.dm b/code/modules/antagonists/changeling/powers/revive.dm index 20e4c7933302..f5fc56bb4959 100644 --- a/code/modules/antagonists/changeling/powers/revive.dm +++ b/code/modules/antagonists/changeling/powers/revive.dm @@ -11,6 +11,10 @@ if(HAS_TRAIT(user, TRAIT_UNREVIVABLE)) to_chat(user, "Something is preventing us from regenerating, we will need to revive at another point.") return FALSE + + cling.can_use_powers = FALSE + addtimer(VARSET_CALLBACK(cling, can_use_powers, TRUE), 10 SECONDS) + REMOVE_TRAIT(user, TRAIT_FAKEDEATH, CHANGELING_TRAIT) for(var/obj/item/grab/G in user.grabbed_by) var/mob/living/carbon/M = G.assailant diff --git a/code/modules/antagonists/vampire/vamp_datum.dm b/code/modules/antagonists/vampire/vamp_datum.dm index 14fae8b6418d..3b5b91c81a0b 100644 --- a/code/modules/antagonists/vampire/vamp_datum.dm +++ b/code/modules/antagonists/vampire/vamp_datum.dm @@ -134,7 +134,6 @@ owner.current.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.current.nutrition + 5)) continue - if(H.stat != DEAD || H.has_status_effect(STATUS_EFFECT_RECENTLY_SUCCUMBED)) if(H.ckey || H.player_ghosted) //Requires ckey regardless if monkey or humanoid, or the body has been ghosted before it died blood = min(20, H.blood_volume) diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index 3331ee4d8fd5..afa07900913f 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -929,6 +929,7 @@ desc = "A black coat with gold trim and an old US Chevron printed on the back. Edgy." icon = 'icons/obj/custom_items.dmi' icon_state = "shodancoat" + item_state = "shodancoat_item" /obj/item/clothing/suit/storage/fluff/k3_webbing name = "vox tactical webbing" diff --git a/code/modules/martial_arts/judo.dm b/code/modules/martial_arts/judo.dm index 7562d2d9d5cd..6fc113321b0d 100644 --- a/code/modules/martial_arts/judo.dm +++ b/code/modules/martial_arts/judo.dm @@ -70,33 +70,3 @@ /datum/martial_art/judo/explaination_footer(user) to_chat(user, "Your unarmed strikes hit about twice as hard as your peers, on average.") - -/datum/martial_art/judo/under_siege - name = "Professional Bodyguarding" - var/static/list/areas_under_siege = typecacheof(list(/area/station/service/kitchen, /area/station/service/bar)) - -/datum/martial_art/judo/under_siege/teach(mob/living/carbon/human/H, make_temporary) - RegisterSignal(H, COMSIG_AREA_ENTERED, PROC_REF(bar_check)) - return ..() - -/datum/martial_art/judo/under_siege/remove(mob/living/carbon/human/H) - UnregisterSignal(H, COMSIG_AREA_ENTERED) - return ..() - -/datum/martial_art/judo/under_siege/proc/bar_check(mob/living/carbon/human/H, area/entered_area) - SIGNAL_HANDLER - if(!is_type_in_typecache(entered_area, areas_under_siege)) - var/list/held_items = list(H.get_active_hand(), H.get_inactive_hand()) - for(var/obj/item/slapper/parry/smacking_hand in held_items) - qdel(smacking_hand) - can_parry = FALSE - weight = 0 - else - can_parry = TRUE - weight = 5 - -/datum/martial_art/judo/under_siege/can_use(mob/living/carbon/human/H) - var/area/A = get_area(H) - if(!(is_type_in_typecache(A, areas_under_siege))) - return FALSE - return ..() diff --git a/code/modules/mining/lavaland/loot/colossus_loot.dm b/code/modules/mining/lavaland/loot/colossus_loot.dm index 1a1bbd268bd3..38d4653f196c 100644 --- a/code/modules/mining/lavaland/loot/colossus_loot.dm +++ b/code/modules/mining/lavaland/loot/colossus_loot.dm @@ -292,7 +292,7 @@ . = ..() if(isliving(target) && target != src) var/mob/living/L = target - if(L.stat < DEAD) + if(L.stat != DEAD) L.heal_overall_damage(heal_power, heal_power) new /obj/effect/temp_visual/heal(get_turf(target), "#80F5FF") diff --git a/code/modules/mob/living/carbon/alien/alien_base.dm b/code/modules/mob/living/carbon/alien/alien_base.dm index 8d2a727019e1..97559889b956 100644 --- a/code/modules/mob/living/carbon/alien/alien_base.dm +++ b/code/modules/mob/living/carbon/alien/alien_base.dm @@ -260,25 +260,6 @@ and carry the owner just to make sure*/ . = ..() ADD_TRAIT(src, TRAIT_IMMOBILIZED, LYING_DOWN_TRAIT) //Xenos can't crawl -/mob/living/carbon/alien/consume_patch_or_pill(obj/item/reagent_containers/medicine, mob/user) - var/apply_method = "swallow" - var/how_many_reagents = medicine.reagents.total_volume - var/reagent_application = REAGENT_INGEST - if(ispatch(medicine)) - apply_method = "apply" - how_many_reagents = clamp(medicine.reagents.total_volume, 0.1, 2) - reagent_application = REAGENT_TOUCH - - visible_message("[user] attempts to force [src] to [apply_method] [medicine].") - if(!do_after(user, 5 SECONDS, TRUE, src)) // You try feeding a xenomorph a pill - return - - visible_message("[user] forces [src] to [apply_method] [medicine].") - var/fraction = min(1 / medicine.reagents.total_volume, 1) - medicine.reagents.reaction(src, reagent_application, fraction) - medicine.reagents.trans_to(src, how_many_reagents) - return TRUE - /mob/living/carbon/alien/update_stat(reason) if(health <= HEALTH_THRESHOLD_CRIT && stat == CONSCIOUS) KnockOut() diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm index b6d3568ca887..fffd5c5e98ec 100644 --- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm +++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm @@ -98,7 +98,7 @@ spawn(6) owner.cut_overlay(overlay) - var/mob/living/carbon/alien/larva/new_xeno = new(owner.drop_location()) + var/mob/living/carbon/alien/larva/new_xeno = new(get_turf(owner)) new_xeno.key = C.key dust_if_respawnable(C) if(SSticker && SSticker.mode) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index f3e4c40a82db..6172ff2d9441 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1164,26 +1164,22 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven return TRUE /mob/living/carbon/proc/eat(obj/item/food/to_eat, mob/user, bitesize_override) - if(ispill(to_eat) || ispatch(to_eat)) // We first have to know if it's either a pill or a patch, only then can we check if it's a food item - return consume_patch_or_pill(to_eat, user) - - if(!isfood(to_eat)) + if(!istype(to_eat)) return FALSE - var/obj/item/food/food = to_eat // It's not a patch or a pill so it must be food var/fullness = nutrition + 10 - if(istype(food, /obj/item/food/snacks)) - for(var/datum/reagent/consumable/C in reagents.reagent_list) //we add the nutrition value of what we're currently digesting + if(istype(to_eat, /obj/item/food/snacks)) + for(var/datum/reagent/consumable/C in reagents.reagent_list) // We add the nutrition value of what we're currently digesting fullness += C.nutriment_factor * C.volume / (C.metabolization_rate * metabolism_efficiency) if(user == src) - if(!selfFeed(food, fullness)) + if(!selfFeed(to_eat, fullness)) return FALSE else - if(!forceFed(food, user, fullness)) + if(!forceFed(to_eat, user, fullness)) return FALSE - consume(food, bitesize_override) + consume(to_eat, bitesize_override) SSticker.score.score_food_eaten++ return TRUE @@ -1208,25 +1204,22 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven return TRUE /mob/living/carbon/proc/selfFeed(obj/item/food/to_eat, fullness) - if(ispill(to_eat)) - to_chat(src, "You swallow [to_eat].") - else if(ispatch(to_eat)) - to_chat(src, "You apply [to_eat].") - else - if(to_eat.junkiness && satiety < -150 && nutrition > NUTRITION_LEVEL_STARVING + 50) - to_chat(src, "You don't feel like eating any more junk food at the moment.") - return FALSE - if(fullness <= 50) - to_chat(src, "You hungrily chew out a piece of [to_eat] and gobble it!") - else if(fullness > 50 && fullness < 150) - to_chat(src, "You hungrily begin to eat [to_eat].") - else if(fullness > 150 && fullness < 500) - to_chat(src, "You take a bite of [to_eat].") - else if(fullness > 500 && fullness < 600) - to_chat(src, "You unwillingly chew a bit of [to_eat].") - else if(fullness > (600 * (1 + overeatduration / 2000))) // The more you eat - the more you can eat - to_chat(src, "You cannot force any more of [to_eat] to go down your throat.") - return FALSE + if(to_eat.junkiness && satiety < -150 && nutrition > NUTRITION_LEVEL_STARVING + 50) + to_chat(src, "You don't feel like eating any more junk food at the moment.") + return FALSE + + if(fullness <= 50) + to_chat(src, "You hungrily chew out a piece of [to_eat] and gobble it!") + else if(fullness > 50 && fullness < 150) + to_chat(src, "You hungrily begin to eat [to_eat].") + else if(fullness > 150 && fullness < 500) + to_chat(src, "You take a bite of [to_eat].") + else if(fullness > 500 && fullness < 600) + to_chat(src, "You unwillingly chew a bit of [to_eat].") + else if(fullness > (600 * (1 + overeatduration / 2000))) // The more you eat - the more you can eat + to_chat(src, "You cannot force any more of [to_eat] to go down your throat.") + return FALSE + return TRUE /mob/living/carbon/proc/selfDrink(obj/item/reagent_containers/drinks/toDrink, mob/user) @@ -1250,7 +1243,7 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven /*TO DO - If/when stomach organs are introduced, override this at the human level sending the item to the stomach so that different stomachs can handle things in different ways VB*/ /mob/living/carbon/proc/consume(obj/item/food/to_eat, bitesize_override) - var/this_bite = bitesize_override ? bitesize_override : to_eat.bitesize + var/this_bite = bitesize_override || to_eat.bitesize if(!to_eat.reagents) return if(satiety > -200) @@ -1263,47 +1256,6 @@ so that different stomachs can handle things in different ways VB*/ to_eat.reagents.reaction(src, REAGENT_INGEST, fraction) to_eat.reagents.trans_to(src, this_bite) -/mob/living/carbon/proc/consume_patch_or_pill(obj/item/reagent_containers/medicine, mob/user) // medicine = patch or pill - // The reason why this is bundled up is to avoid 2 procs that will be practically identical - if(!medicine.reagents.total_volume) - return TRUE // Doesn't have reagents, would be fine to use up - - if(!dna.species.dietflags) // You will not feed the IPC - to_chat(user, "You cannot feed [src] [medicine]!") - return FALSE - - var/apply_method = "swallow" - var/reagent_application = REAGENT_INGEST - var/requires_mouth = TRUE - var/instant = FALSE - var/how_many_reagents = medicine.reagents.total_volume - - if(ispatch(medicine)) - apply_method = "apply" - reagent_application = REAGENT_TOUCH - requires_mouth = FALSE - how_many_reagents = clamp(medicine.reagents.total_volume, 0.1, 2) // Patches aren't that good at transporting reagents into the bloodstream - var/obj/item/reagent_containers/patch/patch = medicine - if(patch.instant_application) - instant = TRUE - - if(user != src && !instant) - if(requires_mouth && !get_organ("head")) - to_chat(user, "You cannot feed [src] [medicine]!") - return FALSE - visible_message("[user] attempts to force [src] to [apply_method] [medicine].") - if(!do_after(user, 3 SECONDS, TRUE, src, TRUE)) - return FALSE - forceFedAttackLog(medicine, user) - visible_message("[user] forces [src] to [apply_method] [medicine].") - else - to_chat(user, "You [apply_method] [medicine].") - - var/fraction = min(1 / medicine.reagents.total_volume, 1) - medicine.reagents.reaction(src, reagent_application, fraction) - medicine.reagents.trans_to(src, how_many_reagents) - return TRUE - /mob/living/carbon/get_access() . = ..() diff --git a/code/modules/mob/living/carbon/human/human_mob.dm b/code/modules/mob/living/carbon/human/human_mob.dm index eb8b65a91631..fb41d6e1bf9a 100644 --- a/code/modules/mob/living/carbon/human/human_mob.dm +++ b/code/modules/mob/living/carbon/human/human_mob.dm @@ -1254,6 +1254,46 @@ sec_hud_set_ID() + +/mob/living/carbon/human/proc/export_dmi_json() + var/filename = clean_input("filename", "filename", "my_character") + + if(filename == "") + return + + var/maxCount = 10 + var/curCount = 0 + var/dmipath = "data/exports/characters/[filename].dmi" + log_world("saving icon to [filename]") + var/icon/allDirs = null + + var/list/directions = list(SOUTH, NORTH, EAST, WEST) + for(var/d in directions) + var/icon/new_icon + for(var/i = 0; i < maxCount; i++) + sleep(5) + curCount = i + new_icon = getFlatIcon(src, defdir=d) + if(new_icon != null) + break + + if(new_icon == null) + log_world("ran [curCount] times and could not find icon") + else + log_world("ran [curCount] times and found icon") + if(allDirs == null) + allDirs = icon(new_icon, "", d) + else + allDirs.Insert(new_icon, "", d) + + fcopy(allDirs, dmipath) + log_world("saved icon to [dmipath]") + + var/jsonpath = "data/exports/characters/[filename].json" + var/json = json_encode(serialize()) + text2file(json, jsonpath) + log_world("saved json to [jsonpath]") + /** * Change a mob's species. * diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 999f80125d5e..9d8e832a937e 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1104,7 +1104,7 @@ if((stat == DEAD) && (var_value < DEAD))//Bringing the dead back to life GLOB.dead_mob_list -= src GLOB.alive_mob_list += src - if((stat < DEAD) && (var_value == DEAD))//Kill he + if((stat != DEAD) && (var_value == DEAD))//Kill he GLOB.alive_mob_list -= src GLOB.dead_mob_list += src . = ..() diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 5baa6c1f92af..ca1b4c9aad76 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -303,7 +303,7 @@ return if(world.time < (last_upgrade + UPGRADE_COOLDOWN)) return - if(!(assailant.mobility_flags & MOBILITY_MOVE) || IS_HORIZONTAL(assailant)) + if(HAS_TRAIT(assailant, TRAIT_HANDS_BLOCKED) || IS_HORIZONTAL(assailant)) qdel(src) return diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index 6927df61279a..6e5a95364955 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -289,3 +289,18 @@ C.reagents.add_reagent("ice", reagent_volume) qdel(src) +/// Smoke Grenade Module, its tacticool. +/obj/item/mod/module/dispenser/smoke + name = "MOD smoke grenade dispenser module" + desc = "A module that dispenses primed smoke grenades to disperse crowds." + icon_state = "smoke_grenade" + cooldown_time = 10 SECONDS + complexity = 1 + overlay_state_inactive = "module_smoke_grenade" + dispense_type = /obj/item/grenade/smokebomb + +/obj/item/mod/module/dispenser/smoke/on_use() + var/obj/item/grenade/smokebomb/grenade = ..() + if(!grenade) + return + grenade.attack_self(mod.wearer) diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index 010bd5d0dbf4..1885adb49ac3 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -47,30 +47,36 @@ txt = copytext(txt, 1, 128) if(loc == user && user.stat == 0) scribble = txt - else if(istype(P, /obj/item/lighter)) + else if(P.get_heat()) burnphoto(P, user) ..() -/obj/item/photo/proc/burnphoto(obj/item/lighter/P, mob/user) - var/class = "" +/obj/item/photo/proc/burnphoto(obj/item/P, mob/user) + if(user.restrained()) + return - if(P.lit && !user.restrained()) - if(istype(P, /obj/item/lighter/zippo)) - class = "" + var/class = "warning" + if(istype(P, /obj/item/lighter/zippo)) + class = "rose" - user.visible_message("[class][user] holds \the [P] up to \the [src], it looks like [user.p_theyre()] trying to burn it!", \ - "[class]You hold [P] up to [src], burning it slowly.") + user.visible_message("[user] holds [P] up to [src], it looks like [user.p_theyre()] trying to burn it!", \ + "You hold [P] up to [src], burning it slowly.") - if(do_after(user, 50, target = src)) - if(user.get_active_hand() == P && P.lit) - user.visible_message("[class][user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ - "[class]You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.
") - if(user.is_in_inactive_hand(src)) - user.unEquip(src) - new /obj/effect/decal/cleanable/ash(get_turf(src)) - qdel(src) - else - to_chat(user, "You must hold \the [P] steady to burn \the [src].") + if(!do_after(user, 5 SECONDS, target = src)) + return + + if(user.get_active_hand() != P || !P.get_heat()) + to_chat(user, "You must hold [P] steady to burn [src].") + return + + user.visible_message("[class][user] burns right through [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ + "[class]You burn right through [src], turning it to ash. It flutters through the air before settling on the floor in a heap.") + + if(user.is_in_inactive_hand(src)) + user.unEquip(src) + + new /obj/effect/decal/cleanable/ash(get_turf(src)) + qdel(src) /obj/item/photo/examine(mob/user) . = ..() diff --git a/code/modules/projectiles/ammunition/ammo_boxes.dm b/code/modules/projectiles/ammunition/ammo_boxes.dm index a2be11cee534..9feb5d0bc375 100644 --- a/code/modules/projectiles/ammunition/ammo_boxes.dm +++ b/code/modules/projectiles/ammunition/ammo_boxes.dm @@ -1,6 +1,6 @@ /obj/item/ammo_box/a357 name = "speed loader (.357)" - desc = "Designed to quickly reload revolvers." + desc = "A small device designed to quickly reload revolvers. Seven round capacity." materials = list() ammo_type = /obj/item/ammo_casing/a357 max_ammo = 7 @@ -9,7 +9,7 @@ /obj/item/ammo_box/b357 name = "ammo box (.357)" - desc = "Contains up to seven .357 bullets, intended to either be inserted into a speed loader or into the gun manually." + desc = "An ammunition box filled with .357 magnum rounds, commonly used in high-caliber revolvers." w_class = WEIGHT_CLASS_NORMAL ammo_type = /obj/item/ammo_casing/a357 max_ammo = 7 @@ -18,6 +18,7 @@ /obj/item/ammo_box/c9mm name = "ammo box (9mm)" + desc = "An ammunition box filled with 9mm pistol cartridges, commonly used in handguns and submachine guns." icon_state = "9mmbox" origin_tech = "combat=2" ammo_type = /obj/item/ammo_casing/c9mm @@ -25,6 +26,7 @@ /obj/item/ammo_box/c10mm name = "ammo box (10mm)" + desc = "An ammunition box filled with 10mm pistol cartridges, commonly used in Syndicate handguns." icon_state = "10mmbox" origin_tech = "combat=2" ammo_type = /obj/item/ammo_casing/c10mm @@ -32,6 +34,7 @@ /obj/item/ammo_box/c45 name = "ammo box (.45)" + desc = "An ammunition box filled with .45 caliber pistol cartridges, commonly used in high-power pistols and submachine guns." icon_state = "45box" origin_tech = "combat=2" ammo_type = /obj/item/ammo_casing/c45 @@ -39,12 +42,14 @@ /obj/item/ammo_box/rubber45 name = "ammo box (.45 rubber)" + desc = "An ammunition box filled with .45 caliber rubber bullets for less-lethal actions." icon_state = "45box-r" ammo_type = /obj/item/ammo_casing/rubber45 max_ammo = 16 /obj/item/ammo_box/a40mm name = "ammo box (40mm grenades)" + desc = "An ammunition box containing four 40mm grenades, for use with a launcher. Dropping them is ill-advised." icon_state = "40mm" ammo_type = /obj/item/ammo_casing/a40mm max_ammo = 4 @@ -52,7 +57,7 @@ /obj/item/ammo_box/a762 name = "stripper clip (7.62mm)" - desc = "A stripper clip." + desc = "A stripper clip for 7.62mm cartridges, used in Mosin-Nagant rifles. Five round capacity." icon_state = "762" ammo_type = /obj/item/ammo_casing/a762 max_ammo = 5 @@ -60,6 +65,7 @@ /obj/item/ammo_box/n762 name = "ammo box (7.62x38mmR)" + desc = "An ammunition box full of 7.62x38mmR pistol cartridges, for use in antique revolvers." icon_state = "riflebox" origin_tech = "combat=2" ammo_type = /obj/item/ammo_casing/n762 @@ -67,6 +73,7 @@ /obj/item/ammo_box/wt550 name = "ammo box (4.6x30mm)" + desc = "An ammunition box containing 4.6x30mm PDW cartridges, for use in submachine guns and low-caliber rifles." icon_state = "riflebox" origin_tech = "combat=2" ammo_type = /obj/item/ammo_casing/c46x30mm @@ -76,21 +83,25 @@ /obj/item/ammo_box/wt550/wtap name = "ammo box (Armor Piercing 4.6x30mm)" + desc = "An ammunition box containing 4.6x30mm PDW cartridges. These are AP rounds, sacrificing damage for armor penetration." icon_state = "wtbox_AP" ammo_type = /obj/item/ammo_casing/c46x30mm/ap /obj/item/ammo_box/wt550/wtic name = "ammo box (Incendiary 4.6x30mm)" + desc = "An ammunition box containing 4.6x30mm PDW ammunition, tipped with an incendiary chemical payload." icon_state = "wtbox_inc" ammo_type = /obj/item/ammo_casing/c46x30mm/inc /obj/item/ammo_box/wt550/wttx name = "ammo box (Toxin Tipped 4.6x30mm)" + desc = "An ammunition box containing 4.6x30mm cartridges, tipped with lethal toxins. Possibly a war crime." icon_state = "wtbox_tox" ammo_type = /obj/item/ammo_casing/c46x30mm/tox /obj/item/ammo_box/laser name = "ammo box (laser)" + desc = "An ammunition box containing caseless laser cartridges, for use in IK-series laser rifles." icon_state = "laserbox" origin_tech = "combat=3" ammo_type = /obj/item/ammo_casing/caseless/laser @@ -99,6 +110,7 @@ /obj/item/ammo_box/shotgun name = "shotgun speedloader (Slug)" + desc = "A specialized speedloader for swiftly reloading shotguns. This one is meant for Slugs." icon_state = "slugloader" origin_tech = "combat=2" ammo_type = /obj/item/ammo_casing/shotgun @@ -108,39 +120,46 @@ /obj/item/ammo_box/shotgun/buck name = "shotgun speedloader (Buckshot)" + desc = "A specialized speedloader for swiftly reloading shotguns. This one is meant for Buckshot." icon_state = "buckloader" ammo_type = /obj/item/ammo_casing/shotgun/buckshot /obj/item/ammo_box/shotgun/confetti name = "shotgun speedloader (Confetti)" + desc = "A specialized speedloader for swiftly reloading shotguns. This one is meant for Confetti shot." icon_state = "partyloader" ammo_type = /obj/item/ammo_casing/shotgun/confetti multi_sprite_step = 1 /obj/item/ammo_box/shotgun/dragonsbreath name = "shotgun speedloader (Dragonsbreath)" + desc = "A specialized speedloader for swiftly reloading shotguns. This one is meant for Dragonsbreath rounds." icon_state = "dragonsbreathloader" ammo_type = /obj/item/ammo_casing/shotgun/incendiary/dragonsbreath /obj/item/ammo_box/shotgun/stun name = "shotgun speedloader (Stun shells)" + desc = "A specialized speedloader for swiftly reloading shotguns. This one is meant for Stun slugs." icon_state = "stunloader" ammo_type = /obj/item/ammo_casing/shotgun/stunslug /obj/item/ammo_box/shotgun/beanbag name = "shotgun speedloader (Beanbag shells)" + desc = "A specialized speedloader for swiftly reloading shotguns. This one is meant for Beanbag slugs." icon_state = "beanbagloader" ammo_type = /obj/item/ammo_casing/shotgun/beanbag materials = list(MAT_METAL=1750) /obj/item/ammo_box/shotgun/rubbershot name = "shotgun speedloader (Rubbershot shells)" + desc = "A specialized speedloader for swiftly reloading shotguns. This one is meant for Rubbershot shells." icon_state = "rubbershotloader" ammo_type = /obj/item/ammo_casing/shotgun/rubbershot materials = list(MAT_METAL=1750) /obj/item/ammo_box/shotgun/tranquilizer name = "shotgun speedloader (Tranquilizer darts)" + desc = "A specialized speedloader for swiftly reloading shotguns. This one is meant for Tranquilizer dart shells." icon_state = "tranqloader" ammo_type = /obj/item/ammo_casing/shotgun/tranquilizer materials = list(MAT_METAL=1750) @@ -149,6 +168,7 @@ //FOAM DARTS /obj/item/ammo_box/foambox name = "ammo box (Foam Darts)" + desc = "An ammunition box, filled with foam darts for use in toy weapons." icon = 'icons/obj/guns/toy.dmi' icon_state = "foambox" ammo_type = /obj/item/ammo_casing/caseless/foam_dart @@ -157,11 +177,13 @@ /obj/item/ammo_box/foambox/riot icon_state = "foambox_riot" + desc = "An ammunition box, filled with riot darts for use in toy weapons. Not safe for children." ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot materials = list(MAT_METAL = 50000) /obj/item/ammo_box/foambox/sniper name = "ammo box (Foam Sniper Darts)" + desc = "An ammunition box full of sniper darts for toy weapons." icon = 'icons/obj/guns/toy.dmi' icon_state = "foambox_sniper" ammo_type = /obj/item/ammo_casing/caseless/foam_dart/sniper @@ -170,12 +192,14 @@ /obj/item/ammo_box/foambox/sniper/riot icon_state = "foambox_sniper_riot" + desc = "An ammunition box full of powerful sniper riot darts." ammo_type = /obj/item/ammo_casing/caseless/foam_dart/sniper/riot materials = list(MAT_METAL = 90000) /obj/item/ammo_box/caps name = "speed loader (caps)" + desc = "A revolver speedloader for a cap gun. Cannot chamber live ammunition." icon_state = "357" ammo_type = /obj/item/ammo_casing/cap max_ammo = 7 diff --git a/code/modules/projectiles/ammunition/ammo_casings.dm b/code/modules/projectiles/ammunition/ammo_casings.dm index 50d5cbb6700d..7d541fcfe80b 100644 --- a/code/modules/projectiles/ammunition/ammo_casings.dm +++ b/code/modules/projectiles/ammunition/ammo_casings.dm @@ -1,18 +1,21 @@ /obj/item/ammo_casing/a357 - desc = "A .357 bullet casing." + name = ".357 magnum round" + desc = "A .357 magnum cartridge, often used in revolvers. Very deadly." caliber = "357" projectile_type = /obj/item/projectile/bullet muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/rubber9mm - desc = "A 9mm rubber bullet casing." + name = "9mm rubber round" + desc = "A 9mm pistol cartridge. This one has a rubber tip for less-lethal takedowns." caliber = "9mm" icon_state = "r-casing" projectile_type = /obj/item/projectile/bullet/weakbullet4 /obj/item/ammo_casing/a762 - desc = "A 7.62mm bullet casing." + name = "7.62mm round" + desc = "A 7.62mm rifle cartridge, often used in Soviet rifles." icon_state = "762-casing" caliber = "a762" projectile_type = /obj/item/projectile/bullet @@ -20,10 +23,13 @@ muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/a762/enchanted + name = "enchanted 7.62 round" + desc = "A 7.62mm rifle cartridge. It sparkles with magic." projectile_type = /obj/item/projectile/bullet/weakbullet3 /obj/item/ammo_casing/a50 - desc = "A .50AE bullet casing." + name = ".50 AE round" + desc = "A .50AE pistol cartridge, used in large caliber handguns." caliber = ".50" projectile_type = /obj/item/projectile/bullet muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL @@ -37,62 +43,86 @@ projectile_type = /obj/item/projectile/bullet/mime/fake /obj/item/ammo_casing/c10mm - desc = "A 10mm bullet casing." + name = "10mm round" + desc = "A 10mm pistol cartridge, commonly used in Syndicate sidearms." caliber = "10mm" projectile_type = /obj/item/projectile/bullet/midbullet3 muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/c10mm/ap + name = "10mm armor piercing round" + desc = "A 10mm pistol cartridge, with a Teflon coating to increase armor penetration, at the cost of damage." projectile_type = /obj/item/projectile/bullet/midbullet3/ap /obj/item/ammo_casing/c10mm/fire + name = "10mm incendiary round" + desc = "A 10mm pistol cartridge, containing a payload of flammable chemicals." projectile_type = /obj/item/projectile/bullet/midbullet3/fire muzzle_flash_color = LIGHT_COLOR_FIRE /obj/item/ammo_casing/c10mm/hp + name = "10mm hollow point round" + desc = "A 10mm pistol cartridge, with an expanding tip that greatly increases stopping power, at the cost of armor penetration." projectile_type = /obj/item/projectile/bullet/midbullet3/hp /obj/item/ammo_casing/overgrown + name = "overgrown round" + desc = "A pistol cartridge... probably. Why does it resemble a pea?" projectile_type = /obj/item/projectile/bullet/midbullet3/overgrown icon_state = "peashooter_bullet" /obj/item/ammo_casing/c9mm - desc = "A 9mm bullet casing." + name = "9mm round" + desc = "A 9mm pistol cartridge, commonly used in handguns and submachine guns." caliber = "9mm" projectile_type = /obj/item/projectile/bullet/weakbullet3 muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_WEAK muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/c9mm/ap + name = "9mm armor piercing round" + desc = "A 9mm pistol cartridge, with a Teflon coating to increase armor penetration, at the cost of stopping power." projectile_type = /obj/item/projectile/bullet/armourpiercing /obj/item/ammo_casing/c9mm/tox + name = "9mm toxic round" + desc = "A 9mm pistol cartridge, tipped with lethal toxins. Likely a war crime." projectile_type = /obj/item/projectile/bullet/toxinbullet /obj/item/ammo_casing/c9mm/inc + name = "9mm incendiary round" + desc = "A 9mm pistol cartridge, tipped with an incendiary chemical payload." projectile_type = /obj/item/projectile/bullet/incendiary/firebullet muzzle_flash_color = LIGHT_COLOR_FIRE /obj/item/ammo_casing/c46x30mm - desc = "A 4.6x30mm bullet casing." + name = "4.6x30mm round" + desc = "A 4.6x30mm PDW cartridge, commonly used in submachine guns and small-caliber rifles." caliber = "4.6x30mm" projectile_type = /obj/item/projectile/bullet/weakbullet3 muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_WEAK muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/c46x30mm/ap + name = "4.6x30mm armor piercing round" + desc = "A 4.6x30mm PDW cartridge, with a tungsten core to increase armor penetration, at the cost of stopping power." projectile_type = /obj/item/projectile/bullet/armourpiercing/wt550 /obj/item/ammo_casing/c46x30mm/tox + name = "4.6x30mm toxic round" + desc = "A 4.6x30mm PDW cartridge, tipped with lethal toxins. Probably a war crime." projectile_type = /obj/item/projectile/bullet/toxinbullet /obj/item/ammo_casing/c46x30mm/inc + name = "4.6x30 incendiary round" + desc = "a 4.6x30mm PDW cartridge, tipped with an incendiary chemical payload." projectile_type = /obj/item/projectile/bullet/incendiary/firebullet muzzle_flash_color = LIGHT_COLOR_FIRE /obj/item/ammo_casing/rubber45 - desc = "A .45 rubber bullet casing." + name = ".45 rubber round" + desc = "A .45 caliber pistol cartridge. Features a rubber bullet for less-lethal takedowns." caliber = ".45" icon_state = "r-casing" projectile_type = /obj/item/projectile/bullet/midbullet_r @@ -100,7 +130,8 @@ muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/c45 - desc = "A .45 bullet casing." + name = ".45 round" + desc = "A .45 caliber pistol cartridge, commonly used in pistols and submachine guns." caliber = ".45" projectile_type = /obj/item/projectile/bullet/midbullet muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL @@ -110,7 +141,8 @@ projectile_type = /obj/item/projectile/bullet/midbullet3 /obj/item/ammo_casing/n762 - desc = "A 7.62x38mmR bullet casing." + name = "7.62x38mmR round" + desc = "A 7.62x38mmR pistol cartridge, commonly used by antique revolvers." caliber = "n762" projectile_type = /obj/item/projectile/bullet muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL @@ -128,7 +160,7 @@ /obj/item/ammo_casing/shotgun name = "shotgun slug" - desc = "A 12 gauge lead slug." + desc = "A 12 gauge lead slug. Fires a single solid projectile." icon_state = "blshell" caliber = "shotgun" casing_drop_sound = 'sound/weapons/gun_interactions/shotgun_fall.ogg' @@ -140,7 +172,7 @@ /obj/item/ammo_casing/shotgun/buckshot name = "buckshot shell" - desc = "A 12 gauge buckshot shell." + desc = "A 12 gauge buckshot shell. Fires a spread of lethal shot." icon_state = "gshell" projectile_type = /obj/item/projectile/bullet/pellet pellets = 6 @@ -148,7 +180,7 @@ /obj/item/ammo_casing/shotgun/rubbershot name = "rubber shot" - desc = "A shotgun casing filled with densely-packed rubber balls, used to incapacitate crowds from a distance." + desc = "A 12 gauge shell filled with densely-packed rubber balls, used to incapacitate crowds from a distance." icon_state = "cshell" projectile_type = /obj/item/projectile/bullet/pellet/rubber pellets = 6 @@ -158,7 +190,7 @@ /obj/item/ammo_casing/shotgun/beanbag name = "beanbag slug" - desc = "A weak beanbag slug for riot control." + desc = "A 12 gauge shell loaded with a beanbag slug for less-lethal takedowns." icon_state = "bshell" projectile_type = /obj/item/projectile/bullet/weakbullet materials = list(MAT_METAL=250) @@ -167,7 +199,7 @@ /obj/item/ammo_casing/shotgun/stunslug name = "taser slug" - desc = "A stunning taser slug." + desc = "A 12 gauge shell loaded with a taser cartridge, somehow." icon_state = "stunshell" projectile_type = /obj/item/projectile/bullet/stunshot materials = list(MAT_METAL=250) @@ -178,35 +210,33 @@ /obj/item/ammo_casing/shotgun/meteorslug name = "meteorslug shell" - desc = "A shotgun shell rigged with CMC technology, which launches a massive slug when fired." + desc = "A 12 gauge shell rigged with CMC technology, which launches a massive slug when fired." icon_state = "mshell" projectile_type = /obj/item/projectile/bullet/meteorshot /obj/item/ammo_casing/shotgun/pulseslug name = "proto pulse slug" - desc = "A delicate device which can be loaded into a shotgun. The primer acts as a button which triggers the gain medium and fires a powerful \ - energy blast. While the heat and power drain limit it to one use, it can still allow an operator to engage targets that ballistic ammunition \ - would have difficulty with." + desc = "A 12 gauge shell loaded with a powerful energy emitter, firing a devastating pulse blast." icon_state = "pshell" projectile_type = /obj/item/projectile/beam/pulse/shot muzzle_flash_color = LIGHT_COLOR_DARKBLUE /obj/item/ammo_casing/shotgun/incendiary name = "incendiary slug" - desc = "An incendiary-coated shotgun slug." + desc = "A 12 gauge slug shell containing an incendiary chemical payload." icon_state = "ishell" projectile_type = /obj/item/projectile/bullet/incendiary/shell muzzle_flash_color = LIGHT_COLOR_FIRE /obj/item/ammo_casing/shotgun/frag12 name = "\improper FRAG-12 slug" - desc = "A high explosive breaching round for a 12 gauge shotgun." + desc = "A 12 gauge shell, loaded with a high-explosive slug." icon_state = "heshell" projectile_type = /obj/item/projectile/bullet/frag12 /obj/item/ammo_casing/shotgun/incendiary/dragonsbreath name = "dragonsbreath shell" - desc = "A shotgun shell which fires a spread of incendiary pellets." + desc = "A 12 gauge shell which fires a spread of incendiary pellets." icon_state = "ishell2" projectile_type = /obj/item/projectile/bullet/incendiary/shell/dragonsbreath pellets = 4 @@ -215,9 +245,7 @@ /obj/item/ammo_casing/shotgun/ion name = "ion shell" - desc = "An advanced shotgun shell which uses a subspace ansible crystal to produce an effect similar to a standard ion rifle. \ - The unique properties of the crystal splot the pulse into a spread of individually weaker bolts." - icon_state = "ionshell" + desc = "An advanced 12 gauge shell that fires a spread of ion bolts." projectile_type = /obj/item/projectile/ion/weak pellets = 4 variance = 35 @@ -227,7 +255,7 @@ /obj/item/ammo_casing/shotgun/lasershot name = "lasershot" - desc = "An advanced shotgun shell that uses a multitude of lenses to split a high-powered laser into eight small pellets." + desc = "An advanced 12 gauge shell that uses a multitude of lenses to split a high-powered laser into eight small beams." icon_state = "lshell" projectile_type = /obj/item/projectile/beam/scatter pellets = 8 @@ -238,13 +266,13 @@ /obj/item/ammo_casing/shotgun/techshell name = "unloaded technological shell" - desc = "A high-tech shotgun shell which can be loaded with materials to produce unique effects." + desc = "An empty 12 gauge shell, ready to be loaded with all manner of projectiles." icon_state = "cshell" projectile_type = null /obj/item/ammo_casing/shotgun/dart name = "shotgun dart" - desc = "A dart for use in shotguns. Can be injected with up to 30 units of any chemical." + desc = "A 12 gauge shell loaded with a hypodermic needle. Can be injected with up to 30 units of any chemical." icon_state = "cshell" container_type = OPENCONTAINER projectile_type = /obj/item/projectile/bullet/dart @@ -271,7 +299,7 @@ /obj/item/ammo_casing/shotgun/tranquilizer name = "tranquilizer darts" - desc = "A tranquilizer round used to subdue individuals utilizing stimulants." + desc = "A 12 gauge dart shell loaded with powerful tranquilizers." icon_state = "nshell" projectile_type = /obj/item/projectile/bullet/dart/syringe/tranquilizer muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL @@ -280,19 +308,21 @@ /obj/item/ammo_casing/shotgun/confetti name = "confettishot" - desc = "It's party time!" + desc = "A 12 gauge shell loaded with... confetti?" icon_state = "partyshell" projectile_type = /obj/item/projectile/bullet/confetti /obj/item/ammo_casing/a556 - desc = "A 5.56mm bullet casing." + name = "5.56mm round" + desc = "A 5.56mm rifle round, produced in incredible quantities by the Trans-Solar Federation." caliber = "a556" projectile_type = /obj/item/projectile/bullet/heavybullet muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/a545 - desc = "A 5.45x39mm bullet casing." + name = "5.45x39mm round" + desc = "A 5.45x39mm rifle round, used by the elite marines of the USSP." caliber = "a545" projectile_type = /obj/item/projectile/bullet/midbullet3 muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL @@ -300,15 +330,15 @@ /obj/item/ammo_casing/shotgun/fakebeanbag name = "beanbag shell" - desc = "A weak beanbag shell." + desc = "A 12 gauge beanbag slug. Smells strongly of alcohol." icon_state = "bshell" projectile_type = /obj/item/projectile/bullet/weakbullet/booze muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/rocket - name = "rocket shell" - desc = "A high explosive designed to be fired from a launcher." + name = "rocket propelled grenade" + desc = "A high explosive rocket meant to be fired from a launcher." icon_state = "rocketshell" projectile_type = /obj/item/projectile/missile caliber = "rocket" @@ -325,15 +355,16 @@ return FALSE /obj/item/ammo_casing/caseless/a75 - desc = "A .75 bullet casing." + name = ".75 gyrojet round" + desc = "A .75 caliber gyrojet cartridge, for use in experimental weaponry. There's a Sunburst Heavy Industries logo on the side." caliber = "75" projectile_type = /obj/item/projectile/bullet/gyro muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_STRONG muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/a40mm - name = "40mm HE shell" - desc = "A cased high explosive grenade that can only be activated once fired out of a grenade launcher." + name = "40mm HE grenade" + desc = "A 40mm high-explosive grenade round, meant to be fired from a grenade launcher." caliber = "40mm" icon_state = "40mmHE" projectile_type = /obj/item/projectile/bullet/a40mm @@ -442,7 +473,7 @@ /obj/item/ammo_casing/shotgun/assassination name = "assassination shell" - desc = "A specialist shrapnel shell that has been laced with a silencing toxin." + desc = "A 12 gauge buckshot shell containing a powerful silencing toxin." projectile_type = /obj/item/projectile/bullet/pellet/assassination muzzle_flash_effect = null icon_state = "gshell" @@ -450,6 +481,7 @@ variance = 25 /obj/item/ammo_casing/cap + name = "cap" desc = "A cap for children toys." caliber = "cap" projectile_type = /obj/item/projectile/bullet/cap @@ -458,6 +490,7 @@ harmful = FALSE /obj/item/ammo_casing/caseless/laser + name = "caseless laser round" desc = "An experimental laser casing, designed to vaporize when fired." caliber = "laser" projectile_type = /obj/item/projectile/beam/laser/ik //Subtype that breaks on firing if emp'd diff --git a/code/modules/projectiles/ammunition/energy_lens.dm b/code/modules/projectiles/ammunition/energy_lens.dm index 5935376b9bb2..322d210681af 100644 --- a/code/modules/projectiles/ammunition/energy_lens.dm +++ b/code/modules/projectiles/ammunition/energy_lens.dm @@ -166,6 +166,15 @@ harmful = FALSE delay = 0.6 SECONDS +/obj/item/ammo_casing/energy/disabler/smg + projectile_type = /obj/item/projectile/beam/disabler/weak + e_cost = 25 + fire_sound = 'sound/weapons/taser3.ogg' + click_cooldown_override = 2 + variance = 15 + randomspread = 1 + delay = 2 + /obj/item/ammo_casing/energy/disabler/cyborg //seperate balancing for cyborg, again e_cost = 250 diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index 53c1120c998b..1b299dd77fc0 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -67,6 +67,18 @@ return ..() +/obj/item/gun/energy/disabler/smg + name = "disabler smg" + desc = "An automatic disabler variant, as opposed to the conventional model. Boasts a higher ammunition capacity at the cost of slightly reduced beam effectiveness." + icon_state = "disabler_smg" + weapon_weight = WEAPON_HEAVY + w_class = WEIGHT_CLASS_BULKY + ammo_type = list(/obj/item/ammo_casing/energy/disabler/smg) + burst_size = 2 + fire_delay = 2.5 + shaded_charge = TRUE + can_holster = FALSE + /obj/item/gun/energy/disabler/cyborg name = "cyborg disabler" desc = "An integrated disabler that draws from a cyborg's power cell. This weapon contains a limiter to prevent the cyborg's power cell from overheating." diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm index 37c26c4569fe..381d1d641d9e 100644 --- a/code/modules/projectiles/guns/projectile/revolver.dm +++ b/code/modules/projectiles/guns/projectile/revolver.dm @@ -374,6 +374,7 @@ /obj/item/gun/projectile/revolver/doublebarrel/attack_self(mob/living/user) var/num_unloaded = 0 + while(get_ammo() > 0) var/obj/item/ammo_casing/CB CB = magazine.get_round(0) @@ -383,11 +384,39 @@ CB.update_icon() playsound(get_turf(CB), 'sound/weapons/gun_interactions/shotgun_fall.ogg', 70, 1) num_unloaded++ + + if(sleight_of_handling(user)) + return + if(num_unloaded) - to_chat(user, "You break open \the [src] and unload [num_unloaded] shell\s.") + to_chat(user, "You break open [src] and unload [num_unloaded] shell\s.") else to_chat(user, "[src] is empty.") +/obj/item/gun/projectile/revolver/doublebarrel/proc/sleight_of_handling(mob/living/carbon/human/user) + if(!istype(get_area(user), /area/station/service/bar)) + return FALSE + if(!istype(user) || !HAS_MIND_TRAIT(user, TRAIT_SLEIGHT_OF_HAND)) + return FALSE + if(!istype(user.belt, /obj/item/storage/belt/bandolier)) + return FALSE + var/obj/item/storage/belt/bandolier/our_bandolier = user.belt + + var/loaded_shells = 0 + for(var/obj/item/ammo_casing/shotgun/shell in our_bandolier) + if(loaded_shells == magazine.max_ammo) + break + + our_bandolier.remove_from_storage(shell) + magazine.give_round(shell) + chamber_round() + + loaded_shells++ + + if(loaded_shells) + to_chat(user, "You quickly load [loaded_shells] shell\s from your bandolier into [src].") + return TRUE + // IMPROVISED SHOTGUN // /obj/item/gun/projectile/revolver/doublebarrel/improvised diff --git a/code/modules/projectiles/guns/projectile/saw.dm b/code/modules/projectiles/guns/projectile/saw.dm index 5d69bbdedec8..9c50158c7b01 100644 --- a/code/modules/projectiles/guns/projectile/saw.dm +++ b/code/modules/projectiles/guns/projectile/saw.dm @@ -129,7 +129,8 @@ //casings// /obj/item/ammo_casing/mm556x45 - desc = "A 556x45mm bullet casing." + name = "5.56x45mm round" + desc = "A 5.56x45mm rifle cartridge, commonly used in light machine guns." icon_state = "762-casing" caliber = "mm55645" projectile_type = /obj/item/projectile/bullet/saw @@ -137,19 +138,23 @@ muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/mm556x45/bleeding - desc = "A 556x45mm bullet casing with specialized inner-casing, that when it makes contact with a target, release tiny shrapnel to induce internal bleeding." + name = "5.56x45mm 'Shredder' round" + desc = "A 5.56x45mm 'Shredder' cartridge, with a heavily serrated tip intended to cause massive bleeding." icon_state = "762-casing" projectile_type = /obj/item/projectile/bullet/saw/bleeding /obj/item/ammo_casing/mm556x45/hollow - desc = "A 556x45mm bullet casing designed to cause more damage to unarmored targets." + name = "5.56x45mm hollow point round" + desc = "A 5.56x45mm rifle cartridge designed to cause more damage to unarmored targets." projectile_type = /obj/item/projectile/bullet/saw/hollow /obj/item/ammo_casing/mm556x45/ap - desc = "A 556x45mm bullet casing designed with a hardened-tipped core to help penetrate armored targets." + name = "5.56x45mm armor piercing round" + desc = "A 5.56x45mm rifle cartridge with a hardened tungsten core to increase armor penetration." projectile_type = /obj/item/projectile/bullet/saw/ap /obj/item/ammo_casing/mm556x45/incen - desc = "A 556x45mm bullet casing designed with a chemical-filled capsule on the tip that when bursted, reacts with the atmosphere to produce a fireball, engulfing the target in flames. " + name = "5.56x45mm incendiary round" + desc = "A 5.56x45mm rifle cartridge with an incendiary chemical payload." projectile_type = /obj/item/projectile/bullet/saw/incen muzzle_flash_color = LIGHT_COLOR_FIRE diff --git a/code/modules/projectiles/guns/projectile/sniper.dm b/code/modules/projectiles/guns/projectile/sniper.dm index 8d1af168a7c5..680b5e6e7e5f 100644 --- a/code/modules/projectiles/guns/projectile/sniper.dm +++ b/code/modules/projectiles/guns/projectile/sniper.dm @@ -56,7 +56,8 @@ icon_state = "[initial(icon_state)]" /obj/item/ammo_casing/point50 - desc = "A .50 bullet casing." + name = ".50 BMG round" + desc = "A .50 BMG rifle cartridge, commonly used in anti-materiel rifles and heavy machine guns." caliber = ".50" projectile_type = /obj/item/projectile/bullet/sniper muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_STRONG @@ -79,7 +80,8 @@ ammo_type = /obj/item/ammo_casing/antimatter /obj/item/ammo_casing/antimatter - desc = "A .50 antimatter bullet casing, designed to cause massive damage to whatever is hit." + name = ".50 BMG anti-matter round" + desc = "A .50 BMG high-explosive cartridge. Does not actually contain antimatter." caliber = ".50" projectile_type = /obj/item/projectile/bullet/sniper/antimatter icon_state = ".50" @@ -105,7 +107,8 @@ max_ammo = 3 /obj/item/ammo_casing/soporific - desc = "A .50 bullet casing, specialised in sending the target to sleep, instead of hell." + name = ".50 BMG soporific round" + desc = "A .50 BMG hypodermic cartridge, loaded with sedatives for instant incapacitation." caliber = ".50" projectile_type = /obj/item/projectile/bullet/sniper/soporific icon_state = ".50" @@ -132,7 +135,8 @@ max_ammo = 5 /obj/item/ammo_casing/haemorrhage - desc = "A .50 bullet casing, specialised in causing massive bloodloss" + name = ".50 BMG shredder round" + desc = "A .50 BMG 'Shredder' cartridge, with a heavily serrated bullet intended to cause massive blood loss." caliber = ".50" projectile_type = /obj/item/projectile/bullet/sniper/haemorrhage icon_state = ".50" @@ -159,7 +163,8 @@ max_ammo = 5 /obj/item/ammo_casing/penetrator - desc = "A .50 caliber penetrator round casing." + name = ".50 BMG sabot round" + desc = "A .50 BMG Sabot Penetrator cartridge, capable of punching through just about anything." caliber = ".50" projectile_type = /obj/item/projectile/bullet/sniper/penetrator icon_state = ".50" diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 3d6211b949d1..d934d34dbe94 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -99,6 +99,12 @@ impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser light_color = LIGHT_COLOR_CYAN +/obj/item/projectile/beam/disabler/weak + name = "weakened disabler beam" + damage = 15 + armour_penetration_flat = -10 + light_color = LIGHT_COLOR_BLUE + /obj/item/projectile/beam/pulse name = "pulse" icon_state = "u_laser" diff --git a/code/modules/projectiles/projectile/magic_projectiles.dm b/code/modules/projectiles/projectile/magic_projectiles.dm index c870715dad83..ff7c643a3e75 100644 --- a/code/modules/projectiles/projectile/magic_projectiles.dm +++ b/code/modules/projectiles/projectile/magic_projectiles.dm @@ -325,8 +325,11 @@ S.icon = change.icon if(H.mind) H.mind.transfer_to(S) - to_chat(S, "You are an animated statue. You cannot move when monitored, but are nearly invincible and deadly when unobserved!") - to_chat(S, "Do not harm [firer.name], your creator.") + var/list/messages = list() + messages.Add("You have been transformed into an animated statue.") + messages.Add("You cannot move when monitored, but are nearly invincible and deadly when unobserved! Hunt down those who shackle you.") + messages.Add("Do not harm [firer.name], your creator.") + to_chat(S, chat_box_red(messages.Join("
"))) H = change H.loc = S qdel(src) diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 6e34d4404cef..567522866765 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -173,7 +173,7 @@ /obj/machinery/chem_master/wrench_act(mob/user, obj/item/I) if(panel_open) return - default_unfasten_wrench(user, I, 4 SECONDS) + return default_unfasten_wrench(user, I, 4 SECONDS) /obj/machinery/chem_master/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) if(..()) diff --git a/code/modules/reagents/reagent_containers/patch.dm b/code/modules/reagents/reagent_containers/patch.dm index a0f33f2ed620..779b8b389883 100644 --- a/code/modules/reagents/reagent_containers/patch.dm +++ b/code/modules/reagents/reagent_containers/patch.dm @@ -12,22 +12,36 @@ var/instant_application = FALSE var/needs_to_apply_reagents = TRUE -/obj/item/reagent_containers/patch/attack(mob/living/carbon/M, mob/user, def_zone) - return apply(M, user) +/obj/item/reagent_containers/patch/attack(mob/living/carbon/C, mob/user) + return apply(C, user) /obj/item/reagent_containers/patch/attack_self(mob/user) return apply(user, user) -/obj/item/reagent_containers/patch/proc/apply(mob/living/carbon/M, mob/user) - if(!istype(M)) +/obj/item/reagent_containers/patch/proc/apply(mob/living/carbon/C, mob/user) + if(!istype(C)) return FALSE - if(M.eat(src, user)) - if(user.get_active_hand() == src) - user.drop_item() // Only drop if they're holding the patch directly - forceMove(M) - LAZYADD(M.processing_patches, src) - return TRUE - return FALSE + + if(ismachineperson(C)) + to_chat(user, "[user == C ? "You" : C] can't use [src]!") + return FALSE + + if(user == C) + to_chat(user, "You apply [src].") + else + if(!instant_application) + C.visible_message("[user] attempts to force [C] to apply [src].") + if(!do_after(user, 3 SECONDS, TRUE, C, TRUE)) + return FALSE + + C.forceFedAttackLog(src, user) + C.visible_message("[user] forces [C] to apply [src].") + + if(user.get_active_hand() == src) + user.drop_item() // Only drop if they're holding the patch directly + forceMove(C) + LAZYADD(C.processing_patches, src) + return TRUE /obj/item/reagent_containers/patch/styptic name = "brute patch" diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index 2c843596059c..20bed7001567 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -18,16 +18,37 @@ if(!icon_state) icon_state = "pill[rand(1, 20)]" -/obj/item/reagent_containers/pill/proc/apply(mob/living/carbon/M, mob/user, def_zone) - if(!istype(M)) +/obj/item/reagent_containers/pill/proc/apply(mob/living/carbon/C, mob/user) + if(!istype(C)) return FALSE - if(M.eat(src, user)) + + if(!reagents.total_volume) qdel(src) return TRUE - return FALSE -/obj/item/reagent_containers/pill/attack(mob/living/carbon/M, mob/user, def_zone) - return apply(M, user) + if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(!H.check_has_mouth()) + to_chat(user, "[user == H ? "You" : H] can't ingest [src]!") + return FALSE + + if(user == C) + to_chat(user, "You swallow [src].") + else + C.visible_message("[user] attempts to force [C] to swallow [src].") + if(!do_after(user, 3 SECONDS, TRUE, C, TRUE)) + return FALSE + + C.forceFedAttackLog(src, user) + C.visible_message("[user] forces [C] to swallow [src].") + + reagents.reaction(C, REAGENT_INGEST) + reagents.trans_to(C, reagents.total_volume) + qdel(src) + return TRUE + +/obj/item/reagent_containers/pill/attack(mob/living/carbon/C, mob/user) + return apply(C, user) /obj/item/reagent_containers/pill/attack_self(mob/user) return apply(user, user) diff --git a/code/modules/research/designs/modsuit_designs.dm b/code/modules/research/designs/modsuit_designs.dm index 5eb37656612c..957774f5902a 100644 --- a/code/modules/research/designs/modsuit_designs.dm +++ b/code/modules/research/designs/modsuit_designs.dm @@ -338,6 +338,13 @@ materials = list(MAT_METAL = 10000, MAT_GLASS = 4000, MAT_SILVER = 2000) build_path = /obj/item/mod/module/plasma_stabilizer +/datum/design/module/smoke_grenade + name = "Smoke Grenade Module" + id = "mod_smokegrenade" + req_tech = list("materials" = 5, "engineering" = 6, "syndicate" = 2) + materials = list(MAT_METAL = 12500, MAT_SILVER = 12050, MAT_GOLD = 2000, MAT_PLASMA = 5000) + build_path = /obj/item/mod/module/dispenser/smoke + /datum/design/module/plate_compression name = "Plate Compression Module" id = "mod_compression" diff --git a/code/modules/supply/supply_packs/pack_security.dm b/code/modules/supply/supply_packs/pack_security.dm index f6e26bb1a441..ed278f83aaf4 100644 --- a/code/modules/supply/supply_packs/pack_security.dm +++ b/code/modules/supply/supply_packs/pack_security.dm @@ -280,6 +280,14 @@ cost = 400 containername = "tranquilizer shell crate" +/datum/supply_packs/security/armory/disablersmg + name = "WT-450 Disabler SMG Crate" + contains = list(/obj/item/gun/energy/disabler/smg, + /obj/item/gun/energy/disabler/smg) + cost = 550 + containertype = /obj/structure/closet/crate/secure/plasma + containername = "disabler smg crate" + /////// Implants & etc /datum/supply_packs/security/armory/mindshield diff --git a/icons/mob/inhands/guns_lefthand.dmi b/icons/mob/inhands/guns_lefthand.dmi index 3e211172c990..7cb890d0548f 100644 Binary files a/icons/mob/inhands/guns_lefthand.dmi and b/icons/mob/inhands/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/guns_righthand.dmi b/icons/mob/inhands/guns_righthand.dmi index deac7d152f0a..bbbda0e17cdd 100644 Binary files a/icons/mob/inhands/guns_righthand.dmi and b/icons/mob/inhands/guns_righthand.dmi differ diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi index f890b05a742e..5692365bace0 100644 Binary files a/icons/mob/robots.dmi and b/icons/mob/robots.dmi differ diff --git a/icons/mob/screen_bot.dmi b/icons/mob/screen_bot.dmi index 7522623f3273..9079dfba15eb 100644 Binary files a/icons/mob/screen_bot.dmi and b/icons/mob/screen_bot.dmi differ diff --git a/icons/mob/screen_robot.dmi b/icons/mob/screen_robot.dmi index d14ac2967aca..2fb11de46abe 100644 Binary files a/icons/mob/screen_robot.dmi and b/icons/mob/screen_robot.dmi differ diff --git a/icons/obj/clothing/modsuit/mod_modules.dmi b/icons/obj/clothing/modsuit/mod_modules.dmi index 598c2b1bf269..ba019b126cc2 100644 Binary files a/icons/obj/clothing/modsuit/mod_modules.dmi and b/icons/obj/clothing/modsuit/mod_modules.dmi differ diff --git a/icons/obj/custom_items.dmi b/icons/obj/custom_items.dmi index 882d60d35a1a..8f2ec75eec3c 100644 Binary files a/icons/obj/custom_items.dmi and b/icons/obj/custom_items.dmi differ diff --git a/icons/obj/flora/snowflora.dmi b/icons/obj/flora/snowflora.dmi index 4a010012fe22..b86a88cc3b5b 100644 Binary files a/icons/obj/flora/snowflora.dmi and b/icons/obj/flora/snowflora.dmi differ diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi index 8494991416e9..60f136f507d0 100644 Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ diff --git a/icons/obj/wizard.dmi b/icons/obj/wizard.dmi index 636e9f6ca2ec..c9722eeed29e 100644 Binary files a/icons/obj/wizard.dmi and b/icons/obj/wizard.dmi differ diff --git a/modular_ss220/aesthetics/skin/icons/screen_clockwork.dmi b/modular_ss220/aesthetics/skin/icons/screen_clockwork.dmi index 6d788556420e..82a95e338117 100644 Binary files a/modular_ss220/aesthetics/skin/icons/screen_clockwork.dmi and b/modular_ss220/aesthetics/skin/icons/screen_clockwork.dmi differ diff --git a/paradise.dme b/paradise.dme index 300e339ded67..72709be4c539 100644 --- a/paradise.dme +++ b/paradise.dme @@ -449,6 +449,7 @@ #include "code\datums\diseases\advance\symptoms\fever.dm" #include "code\datums\diseases\advance\symptoms\fire.dm" #include "code\datums\diseases\advance\symptoms\flesh_eating.dm" +#include "code\datums\diseases\advance\symptoms\hair.dm" #include "code\datums\diseases\advance\symptoms\hallucigen.dm" #include "code\datums\diseases\advance\symptoms\headache.dm" #include "code\datums\diseases\advance\symptoms\heal.dm" diff --git a/sound/weapons/taser3.ogg b/sound/weapons/taser3.ogg new file mode 100644 index 000000000000..bfe904c902a2 Binary files /dev/null and b/sound/weapons/taser3.ogg differ diff --git a/tools/ci/check_grep2.py b/tools/ci/check_grep2.py index 7354b59fa011..f8152ffbf4e0 100644 --- a/tools/ci/check_grep2.py +++ b/tools/ci/check_grep2.py @@ -14,7 +14,7 @@ def print_error(message: str, filename: str, line_number: int): if os.getenv("GITHUB_ACTIONS") == "true": # We're on github, output in a special format. - print(f"::error file={filename},line={line_number},title=Check Grep::{message}") + print(f"::error file={filename},line={line_number},title=Check Grep::{filename}:{line_number}: {RED}{message}{NC}") else: print(f"{filename}:{line_number}: {RED}{message}{NC}") diff --git a/tools/ci/check_icon_dupenames.py b/tools/ci/check_icon_dupenames.py new file mode 100644 index 000000000000..da4f988810ce --- /dev/null +++ b/tools/ci/check_icon_dupenames.py @@ -0,0 +1,40 @@ +from collections import defaultdict +import glob +import sys +import time + +from ..dmi import Dmi + + +if __name__ == "__main__": + print("check_icon_dupenames started") + + count = 0 + exit_code = 0 + start = time.time() + + findings = defaultdict(list) + + for dmi_path in glob.glob("**/*.dmi", recursive=True): + dmi = Dmi.from_file(dmi_path) + states = set() + for state in dmi.states: + # Movement states have the same name as their non-movement counterparts + if (state.name, state.movement) in states: + findings[dmi_path].append(state.name) + states.add((state.name, state.movement)) + count += 1 + + if findings: + exit_code = 1 + + for filename in sorted(findings.keys()): + states = findings[filename] + for state in sorted(states): + print(f"{filename}: duplicate state name `{state}`") + + + end = time.time() + print(f"\ncheck_icon_dupenames checked {count} files in {end - start:.2f}s\n") + + sys.exit(exit_code)