diff --git a/baystation12.dme b/baystation12.dme
index 2e0db0b4a2..e7b2e62c4e 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -1506,6 +1506,7 @@
#include "code\modules\random_map\noise\tundra.dm"
#include "code\modules\reagents\Chemistry-Colours.dm"
#include "code\modules\reagents\Chemistry-Holder.dm"
+#include "code\modules\reagents\Chemistry-Logging.dm"
#include "code\modules\reagents\Chemistry-Machinery.dm"
#include "code\modules\reagents\Chemistry-Metabolism.dm"
#include "code\modules\reagents\Chemistry-Readme.dm"
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index ecca29bfd1..8936151992 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -117,8 +117,8 @@
#define DOOR_OPEN_LAYER 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6
#define DOOR_CLOSED_LAYER 3.1 //Above most items if closed
#define LIGHTING_LAYER 11
-#define OBFUSCATION_LAYER 14 //Where images covering the view for eyes are put
-#define SCREEN_LAYER 17 //Mob HUD/effects layer
+#define OBFUSCATION_LAYER 21 //Where images covering the view for eyes are put
+#define SCREEN_LAYER 22 //Mob HUD/effects layer
// Convoluted setup so defines can be supplied by Bay12 main server compile script.
// Should still work fine for people jamming the icons into their repo.
@@ -154,3 +154,7 @@
#define BOMBCAP_HEAVY_RADIUS (max_explosion_range/2)
#define BOMBCAP_LIGHT_RADIUS max_explosion_range
#define BOMBCAP_FLASH_RADIUS (max_explosion_range*1.5)
+
+// Special return values from bullet_act(). Positive return values are already used to indicate the blocked level of the projectile.
+#define PROJECTILE_CONTINUE -1 //if the projectile should continue flying after calling bullet_act()
+#define PROJECTILE_FORCE_MISS -2 //if the projectile should treat the attack as a miss (suppresses attack and admin logs) - only applies to mobs.
diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm
index 7e1ba6d368..03680c8ff3 100644
--- a/code/game/gamemodes/heist/heist.dm
+++ b/code/game/gamemodes/heist/heist.dm
@@ -20,12 +20,3 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind'
if (skipjack && skipjack.returned_home)
return 1
return 0
-
-/datum/game_mode/heist/cleanup()
- //the skipjack and everything in it have left and aren't coming back, so get rid of them.
- var/area/skipjack = locate(/area/shuttle/skipjack/station)
- for (var/mob/living/M in skipjack.contents)
- //maybe send the player a message that they've gone home/been kidnapped? Someone responsible for vox lore should write that.
- qdel(M)
- for (var/obj/O in skipjack.contents)
- qdel(O) //no hiding in lockers or anything
\ No newline at end of file
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index 95e043db28..834f3f3749 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -919,7 +919,7 @@ FIRE ALARM
/obj/machinery/firealarm/attack_ai(mob/user as mob)
return src.attack_hand(user)
-/obj/machinery/firealarm/bullet_act(BLAH)
+/obj/machinery/firealarm/bullet_act()
return src.alarm()
/obj/machinery/firealarm/emp_act(severity)
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index 0e26be38a8..d6a09e3b93 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -624,6 +624,14 @@ var/list/turret_icons
// Emagged turrets again use twice as much power due to higher firing rates
use_power(reqpower * (2 * (emagged || lethal)) * (2 * emagged))
+ //Turrets aim for the center of mass by default.
+ //If the target is grabbing someone then the turret smartly aims for extremities
+ var/obj/item/weapon/grab/G = locate() in target
+ if(G && G.state >= GRAB_NECK) //works because mobs are currently not allowed to upgrade to NECK if they are grabbing two people.
+ A.def_zone = pick("head", "l_hand", "r_hand", "l_foot", "r_foot", "l_arm", "r_arm", "l_leg", "r_leg")
+ else
+ A.def_zone = pick("chest", "groin")
+
//Shooting Code:
A.current = T
A.starting = T
diff --git a/code/game/machinery/turrets.dm b/code/game/machinery/turrets.dm
index a3ac073a90..db548443ca 100644
--- a/code/game/machinery/turrets.dm
+++ b/code/game/machinery/turrets.dm
@@ -266,6 +266,15 @@
else
A = new /obj/item/projectile/energy/electrode( loc )
use_power(200)
+
+ //Turrets aim for the center of mass by default.
+ //If the target is grabbing someone then the turret smartly aims for extremities
+ var/obj/item/weapon/grab/G = locate() in target
+ if(G && G.state >= GRAB_NECK) //works because mobs are currently not allowed to upgrade to NECK if they are grabbing two people.
+ A.def_zone = pick("head", "l_hand", "r_hand", "l_foot", "r_foot", "l_arm", "r_arm", "l_leg", "r_leg")
+ else
+ A.def_zone = pick("chest", "groin")
+
A.current = T
A.starting = T
A.yo = U.y - T.y
diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm
index 5f14980373..f1c9aa2d14 100644
--- a/code/game/objects/items/shooting_range.dm
+++ b/code/game/objects/items/shooting_range.dm
@@ -146,7 +146,7 @@
return
- return -1 // the bullet/projectile goes through the target! Ie, you missed
+ return PROJECTILE_CONTINUE // the bullet/projectile goes through the target!
// Small memory holder entity for transparent bullet holes
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index d217b10197..0b634b192e 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -25,7 +25,7 @@
/obj/structure/girder/bullet_act(var/obj/item/projectile/Proj)
//Girders only provide partial cover. There's a chance that the projectiles will just pass through. (unless you are trying to shoot the girder)
if(Proj.original != src && !prob(cover))
- return -1 //pass through
+ return PROJECTILE_CONTINUE //pass through
//Tasers and the like should not damage girders.
if(!(Proj.damage_type == BRUTE || Proj.damage_type == BURN))
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 331529b87d..149d6bf394 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -91,7 +91,7 @@
passthrough = 1
if(passthrough)
- . = -1
+ . = PROJECTILE_CONTINUE
damage = between(0, (damage - Proj.damage)*(Proj.damage_type == BRUTE? 0.4 : 1), 10) //if the bullet passes through then the grille avoids most of the damage
src.health -= damage*0.2
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index b415a317fc..c3b3fb54ee 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -83,10 +83,12 @@ var/list/admin_verbs_admin = list(
/client/proc/allow_character_respawn, /* Allows a ghost to respawn */
/client/proc/event_manager_panel,
/client/proc/empty_ai_core_toggle_latejoin,
+ /client/proc/empty_ai_core_toggle_latejoin,
/client/proc/aooc,
/client/proc/change_human_appearance_admin, /* Allows an admin to change the basic appearance of human-based mobs */
/client/proc/change_human_appearance_self, /* Allows the human-based mob itself change its basic appearance */
- /client/proc/change_security_level
+ /client/proc/change_security_level,
+ /client/proc/view_chemical_reaction_logs
)
var/list/admin_verbs_ban = list(
/client/proc/unban_panel,
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index 9552a0f17d..f3eb8a8183 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -46,6 +46,8 @@
/obj/item/clothing/mask/gas/swat/vox
name = "\improper alien mask"
desc = "Clearly not designed for a human face."
+ body_parts_covered = 0 //Hack to allow vox to eat while wearing this mask.
+ species_restricted = list("Vox")
/obj/item/clothing/mask/gas/syndicate
name = "tactical mask"
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index ed71989e50..3542f87ed7 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -566,7 +566,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
toggle_visibility(1)
else
user.visible_message ( \
- "[user] just tried to smash his book into that ghost! It's not very effective.", \
+ "[user] just tried to smash \his book into that ghost! It's not very effective.", \
"You get the feeling that the ghost can't become any more visible." \
)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 1faf2f7e7a..cdaad1c42f 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -10,9 +10,11 @@ emp_act
/mob/living/carbon/human/bullet_act(var/obj/item/projectile/P, var/def_zone)
- var/obj/item/organ/external/organ = get_organ(check_zone(def_zone))
- if(!organ)
- return
+ def_zone = check_zone(def_zone)
+ if(!has_organ(def_zone))
+ return PROJECTILE_FORCE_MISS //if they don't have the organ in question then the projectile just passes by.
+
+ var/obj/item/organ/external/organ = get_organ()
//Shields
if(check_shields(P.damage, "the [P.name]"))
@@ -37,7 +39,7 @@ emp_act
// redirect the projectile
P.redirect(new_x, new_y, curloc, src)
- return -1 // complete projectile permutation
+ return PROJECTILE_CONTINUE // complete projectile permutation
//Shrapnel
if(P.can_embed())
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index b496a554b4..c9998888f5 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -268,11 +268,11 @@ var/list/global/organ_rel_size = list(
/proc/get_zone_with_miss_chance(zone, var/mob/target, var/miss_chance_mod = 0, var/ranged_attack=0)
zone = check_zone(zone)
- // you cannot miss if your target is prone or restrained
- if(target.buckled || target.lying)
- return zone
- // if your target is being grabbed aggressively by someone you cannot miss either
if(!ranged_attack)
+ // you cannot miss if your target is prone or restrained
+ if(target.buckled || target.lying)
+ return zone
+ // if your target is being grabbed aggressively by someone you cannot miss either
for(var/obj/item/weapon/grab/G in target.grabbed_by)
if(G.state >= GRAB_AGGRESSIVE)
return zone
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index f13ad24287..6d8c40c16c 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -165,14 +165,17 @@
//roll to-hit
miss_modifier = max(15*(distance-2) - round(15*accuracy) + miss_modifier, 0)
- var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1))
- if(!hit_zone)
+ var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1 || original != target_mob)) //if the projectile hits a target we weren't originally aiming at then retain the chance to miss
+
+ var/result = PROJECTILE_FORCE_MISS
+ if(hit_zone)
+ def_zone = hit_zone //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part
+ result = target_mob.bullet_act(src, def_zone)
+
+ if(result == PROJECTILE_FORCE_MISS)
visible_message("\The [src] misses [target_mob] narrowly!")
return 0
- //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part
- def_zone = hit_zone
-
//hit messages
if(silenced)
target_mob << "You've been hit in the [parse_zone(def_zone)] by \the [src]!"
@@ -193,7 +196,7 @@
msg_admin_attack("UNKNOWN shot [target_mob] ([target_mob.ckey]) with \a [src] (JMP)")
//sometimes bullet_act() will want the projectile to continue flying
- if (target_mob.bullet_act(src, def_zone) == -1)
+ if (result == PROJECTILE_CONTINUE)
return 0
return 1
@@ -227,7 +230,7 @@
else
passthrough = 1 //so ghosts don't stop bullets
else
- passthrough = (A.bullet_act(src, def_zone) == -1) //backwards compatibility
+ passthrough = (A.bullet_act(src, def_zone) == PROJECTILE_CONTINUE) //backwards compatibility
if(isturf(A))
for(var/obj/O in A)
O.bullet_act(src)
diff --git a/code/modules/reagents/Chemistry-Logging.dm b/code/modules/reagents/Chemistry-Logging.dm
new file mode 100644
index 0000000000..1432b18a2e
--- /dev/null
+++ b/code/modules/reagents/Chemistry-Logging.dm
@@ -0,0 +1,28 @@
+
+/var/list/chemical_reaction_logs = list()
+
+/proc/log_chemical_reaction(atom/A, datum/chemical_reaction/R, multiplier)
+ if(!A || !R)
+ return
+
+ var/turf/T = get_turf(A)
+ var/logstr = "[usr ? key_name(usr) : "EVENT"] mixed [R.name] ([R.result]) (x[multiplier]) in \the [A] at [T ? "[T.x],[T.y],[T.z]" : "*null*"]"
+
+ chemical_reaction_logs += "\[[time_stamp()]\] [logstr]"
+
+ if(R.log_is_important)
+ message_admins(logstr)
+ log_admin(logstr)
+
+/client/proc/view_chemical_reaction_logs()
+ set name = "Show Chemical Reactions"
+ set category = "Admin"
+
+ if(!check_rights(R_ADMIN))
+ return
+
+ var/html = ""
+ for(var/entry in chemical_reaction_logs)
+ html += "[entry]
"
+
+ usr << browse(html, "window=chemlogs")
diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm
index ece76b00d0..878724a727 100644
--- a/code/modules/reagents/Chemistry-Recipes.dm
+++ b/code/modules/reagents/Chemistry-Recipes.dm
@@ -52,6 +52,7 @@
var/mix_message = "The solution begins to bubble."
var/reaction_sound = 'sound/effects/bubbles.ogg'
+ var/log_is_important = 0 // If this reaction should be considered important for logging. Important recipes message admins when mixed, non-important ones just log to file.
/datum/chemical_reaction/proc/can_happen(var/datum/reagents/holder)
//check that all the required reagents are present
if(!holder.has_all_reagents(required_reagents))
@@ -264,6 +265,7 @@
result = "kelotane"
required_reagents = list("silicon" = 1, "carbon" = 1)
result_amount = 2
+ log_is_important = 1
/datum/chemical_reaction/peridaxon
name = "Peridaxon"
@@ -503,6 +505,7 @@
result = "coolant"
required_reagents = list("tungsten" = 1, "acetone" = 1, "water" = 1)
result_amount = 3
+ log_is_important = 1
/datum/chemical_reaction/rezadone
name = "Rezadone"
@@ -638,6 +641,7 @@
result = "nitroglycerin"
required_reagents = list("glycerol" = 1, "pacid" = 1, "sacid" = 1)
result_amount = 2
+ log_is_important = 1
/datum/chemical_reaction/nitroglycerin/on_reaction(var/datum/reagents/holder, var/created_volume)
var/datum/effect/effect/system/reagents_explosion/e = new()
diff --git a/code/world.dm b/code/world.dm
index 79b6c059c8..9a5508ffe9 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -127,7 +127,8 @@ var/world_topic_spam_protect_time = world.timeofday
n++
return n
- else if (T == "status")
+ else if (copytext(T,1,7) == "status")
+ var/input[] = params2list(T)
var/list/s = list()
s["version"] = game_version
s["mode"] = master_mode
@@ -136,21 +137,37 @@ var/world_topic_spam_protect_time = world.timeofday
s["vote"] = config.allow_vote_mode
s["ai"] = config.allow_ai
s["host"] = host ? host : null
- s["players"] = list()
s["stationtime"] = worldtime2text()
- var/n = 0
- var/admins = 0
- for(var/client/C in clients)
- if(C.holder)
- if(C.holder.fakekey)
- continue //so stealthmins aren't revealed by the hub
- admins++
- s["player[n]"] = C.key
- n++
- s["players"] = n
+ if(input["status"] == "2")
+ var/list/players = list()
+ var/list/admins = list()
- s["admins"] = admins
+ for(var/client/C in clients)
+ if(C.holder)
+ if(C.holder.fakekey)
+ continue
+ admins[C.key] = C.holder.rank
+ players += C.key
+
+ s["players"] = players.len
+ s["playerlist"] = list2params(players)
+ s["admins"] = admins.len
+ s["adminlist"] = list2params(admins)
+ else
+ var/n = 0
+ var/admins = 0
+
+ for(var/client/C in clients)
+ if(C.holder)
+ if(C.holder.fakekey)
+ continue //so stealthmins aren't revealed by the hub
+ admins++
+ s["player[n]"] = C.key
+ n++
+
+ s["players"] = n
+ s["admins"] = admins
return list2params(s)
diff --git a/html/changelogs/HarpyEagle-dev-freeze.yml b/html/changelogs/HarpyEagle-dev-freeze.yml
index a999f1236d..d7bf101a08 100644
--- a/html/changelogs/HarpyEagle-dev-freeze.yml
+++ b/html/changelogs/HarpyEagle-dev-freeze.yml
@@ -1,3 +1,4 @@
author: HarpyEagle
-changes: []
delete-after: false
+changes:
+ - bugfix: "Fixed projectiles being able to hit people in body parts that they don't have. This will also mean that the less limbs someone has the less effective they will be as a body shield."
\ No newline at end of file