diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm
index 3877ac213c5..65f4da2b50a 100644
--- a/code/__DEFINES/admin.dm
+++ b/code/__DEFINES/admin.dm
@@ -63,4 +63,11 @@
#define AREACOORD(src) "[src ? "[get_area_name(src, TRUE)] [COORD(src)]" : "nonexistent location" ]"
#define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]"
#define ADMIN_VERBOSEJMP(src) "[src ? "[AREACOORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]"
-#define ADMIN_SHOWDETAILS(mask, content) "[mask]"
\ No newline at end of file
+#define ADMIN_SHOWDETAILS(mask, content) "[mask]"
+
+///Max length of a keypress command before it's considered to be a forged packet/bogus command
+#define MAX_KEYPRESS_COMMANDLENGTH 16
+///Max amount of keypress messages per second over two seconds before client is autokicked
+#define MAX_KEYPRESS_AUTOKICK 50
+///Length of held key rolling buffer
+#define HELD_KEY_BUFFER_LENGTH 15
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm
index 59e93e2d513..ad754c496c6 100644
--- a/code/game/gamemodes/changeling/powers/mutations.dm
+++ b/code/game/gamemodes/changeling/powers/mutations.dm
@@ -382,7 +382,7 @@
if(ismob(loc))
loc.visible_message("The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!", "We inflate our hand into a strong shield.", "You hear organic matter ripping and tearing!")
-/obj/item/shield/changeling/hit_reaction()
+/obj/item/shield/changeling/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(remaining_uses < 1)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm
index a1bec7a2a83..7ef5baced97 100644
--- a/code/game/gamemodes/cult/cult_items.dm
+++ b/code/game/gamemodes/cult/cult_items.dm
@@ -160,7 +160,7 @@
user.Dizzy(30)
user.Weaken(5)
-/obj/item/clothing/suit/hooded/cultrobes/cult_shield/hit_reaction(mob/living/carbon/human/owner, attack_text, isinhands)
+/obj/item/clothing/suit/hooded/cultrobes/cult_shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(current_charges)
owner.visible_message("\The [attack_text] is deflected in a burst of blood-red sparks!")
current_charges--
diff --git a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
index f6bed7b539f..232396d951a 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
@@ -80,9 +80,8 @@
M.overlays.Cut()
M.regenerate_icons()
-/obj/item/clothing/suit/armor/abductor/vest/hit_reaction()
+/obj/item/clothing/suit/armor/abductor/vest/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
DeactivateStealth()
- return 0
/obj/item/clothing/suit/armor/abductor/vest/IsReflect()
DeactivateStealth()
@@ -455,7 +454,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
if(ishuman(L))
var/mob/living/carbon/human/H = L
- if(H.check_shields(0, "[user]'s [name]", src, MELEE_ATTACK))
+ if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
return 0
diff --git a/code/game/machinery/computer/HolodeckControl.dm b/code/game/machinery/computer/HolodeckControl.dm
index d3edc588e2d..aeecfa827a2 100644
--- a/code/game/machinery/computer/HolodeckControl.dm
+++ b/code/game/machinery/computer/HolodeckControl.dm
@@ -420,7 +420,7 @@
/obj/item/holo/esword/red/New()
item_color = "red"
-/obj/item/holo/esword/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
+/obj/item/holo/esword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(active)
return ..()
return 0
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 95c00447b92..2116114a305 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -336,7 +336,7 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
else
return ..()
-/obj/item/proc/hit_reaction(mob/living/carbon/human/owner, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, atom/movable/AM)
+/obj/item/proc/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
SEND_SIGNAL(src, COMSIG_ITEM_HIT_REACT, args)
if(prob(final_block_chance))
owner.visible_message("[owner] blocks [attack_text] with [src]!")
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index 6c58b4e1414..94731757895 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -41,160 +41,160 @@
/obj/item/lightreplacer
name = "light replacer"
- desc = "A device to automatically replace lights. Refill with working lightbulbs."
+ desc = "A device to automatically replace lights. Refill with broken or working light bulbs, or sheets of glass."
icon = 'icons/obj/janitor.dmi'
icon_state = "lightreplacer0"
item_state = "electronic"
-
+ w_class = WEIGHT_CLASS_SMALL
flags = CONDUCT
slot_flags = SLOT_BELT
origin_tech = "magnets=3;engineering=4"
+ force = 8
+ var/emagged = FALSE
var/max_uses = 20
- var/uses = 0
- var/shards = 0
- var/recycle = 3
- var/emagged = 0
- var/failmsg = ""
+ var/uses = 10
// How much to increase per each glass?
var/increment = 5
// How much to take from the glass?
var/decrement = 1
var/charge = 1
-/obj/item/lightreplacer/New()
- uses = max_uses / 2
- failmsg = "The [name]'s refill light blinks red."
- ..()
+ // Eating used bulbs gives us bulb shards
+ var/bulb_shards = 0
+ // when we get this many shards, we get a free bulb.
+ var/shards_required = 4
+
/obj/item/lightreplacer/examine(mob/user)
- if(..(user, 2))
- to_chat(user, "It has [uses] lights and [shards] shards remaining.")
+ ..()
+ to_chat(user, status_string())
-/obj/item/lightreplacer/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/stack/sheet/glass))
- var/obj/item/stack/sheet/glass/G = W
- if(G.amount - decrement >= 0 && uses < max_uses)
- var/remaining = max(G.amount - decrement, 0)
- if(!remaining && !(G.amount - decrement) == 0)
- to_chat(user, "There isn't enough glass.")
- return
- G.amount = remaining
- if(!G.amount)
- user.drop_item()
- qdel(G)
- AddUses(increment)
- to_chat(user, "You insert a piece of glass into the [src.name]. You have [uses] lights remaining.")
+/obj/item/lightreplacer/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/stack/sheet/glass))
+ var/obj/item/stack/sheet/glass/G = I
+ if(uses >= max_uses)
+ to_chat(user, "[src] is full.")
return
+ else if(G.use(decrement))
+ AddUses(increment)
+ to_chat(user, "You insert a piece of glass into [src]. You have [uses] light\s remaining.")
+ return
+ else
+ to_chat(user, "You need one sheet of glass to replace lights!")
+ return
- if(istype(W, /obj/item/light))
- var/obj/item/light/L = W
+ if(istype(I, /obj/item/shard))
+ if(uses >= max_uses)
+ to_chat(user, "[src] is full.")
+ return
+ if(!user.unEquip(I))
+ return
+ AddUses(round(increment * 0.75))
+ to_chat(user, "You insert a shard of glass into [src]. You have [uses] light\s remaining.")
+ qdel(I)
+ return
+
+ if(istype(I, /obj/item/light))
+ var/obj/item/light/L = I
if(L.status == 0) // LIGHT OKAY
- if(!user.drop_item())
- to_chat(user, "[L] is stuck to your hand!")
- return
if(uses < max_uses)
+ if(!user.unEquip(L))
+ return
AddUses(1)
- to_chat(user, "You insert the [L.name] into the [src.name]. You have [uses] lights remaining.")
- user.drop_item()
- qdel(L)
- return
- else if(L.status == 2 || L.status == 3)
- if(!user.drop_item())
- to_chat(user, "[L] is stuck to your hand!")
- return
- else
- AddShards(1)
- to_chat(user, "You insert [L] into [src]. You have [shards] shards remaining.")
- user.drop_item()
qdel(L)
+ else
+ if(!user.unEquip(L))
return
+ to_chat(user, "You insert [L] into [src].")
+ AddShards(1, user)
+ qdel(L)
+ return
- if(istype(W, /obj/item/storage))
- var/obj/item/storage/S = W
- var/found_lightbulbs = 0
+ if(istype(I, /obj/item/storage))
+ var/obj/item/storage/S = I
+ var/found_lightbulbs = FALSE
+ var/replaced_something = TRUE
- for(var/obj/item/I in S.contents)
- if(istype(I,/obj/item/light))
- var/obj/item/light/L = I
- found_lightbulbs = 1
+ for(var/obj/item/IT in S.contents)
+ if(istype(IT, /obj/item/light))
+ var/obj/item/light/L = IT
+ found_lightbulbs = TRUE
if(uses >= max_uses)
- to_chat(user, "[src] is full!")
break
- if(L.status == 0)
+ if(L.status == LIGHT_OK)
+ replaced_something = TRUE
AddUses(1)
qdel(L)
- else if(L.status == 2 || L.status == 3)
- AddShards(1)
+
+ else if(L.status == LIGHT_BROKEN || L.status == LIGHT_BURNED)
+ replaced_something = TRUE
+ AddShards(1, user)
qdel(L)
- to_chat(user, "You fill [src] with lights from [S].")
+
if(!found_lightbulbs)
to_chat(user, "[S] contains no bulbs.")
return
+ if(!replaced_something && uses == max_uses)
+ to_chat(user, "[src] is full!")
+ return
+
+ to_chat(user, "You fill [src] with lights from [S]. " + status_string() + "")
+ return
+ return ..()
+
/obj/item/lightreplacer/emag_act(user as mob)
if(!emagged)
Emag()
/obj/item/lightreplacer/attack_self(mob/user)
- /* // This would probably be a bit OP. If you want it though, uncomment the code.
- if(isrobot(user))
- var/mob/living/silicon/robot/R = user
- if(R.emagged)
- src.Emag()
- to_chat(usr, "You shortcircuit the [src].")
- return
- */
- to_chat(usr, "It has [uses] lights remaining.")
+ for(var/obj/machinery/light/target in user.loc)
+ ReplaceLight(target, user)
+ to_chat(user, status_string())
/obj/item/lightreplacer/update_icon()
icon_state = "lightreplacer[emagged]"
+/obj/item/lightreplacer/proc/status_string()
+ return "It has [uses] light\s remaining (plus [bulb_shards] fragment\s)."
-/obj/item/lightreplacer/proc/Use(var/mob/user)
-
- playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
+/obj/item/lightreplacer/proc/Use(mob/user)
+ playsound(loc, 'sound/machines/click.ogg', 50, TRUE)
AddUses(-1)
return 1
// Negative numbers will subtract
-/obj/item/lightreplacer/proc/AddUses(var/amount = 1)
- uses = min(max(uses + amount, 0), max_uses)
+/obj/item/lightreplacer/proc/AddUses(amount = 1)
+ uses = Clamp(uses + amount, 0, max_uses)
-/obj/item/lightreplacer/proc/AddShards(amount = 1)
- shards += amount
- var/recycled_lights = round(shards / recycle)
- if(recycled_lights > 0)
- AddUses(recycled_lights)
- shards = shards % recycle
- return recycled_lights
+/obj/item/lightreplacer/proc/AddShards(amount = 1, user)
+ bulb_shards += amount
+ var/new_bulbs = round(bulb_shards / shards_required)
+ if(new_bulbs > 0)
+ AddUses(new_bulbs)
+ bulb_shards = bulb_shards % shards_required
+ if(new_bulbs != 0)
+ to_chat(user, "[src] has fabricated a new bulb from the broken glass it has stored. It now has [uses] uses.")
+ playsound(loc, 'sound/machines/ding.ogg', 50, TRUE)
+ return new_bulbs
/obj/item/lightreplacer/proc/Charge(var/mob/user)
charge += 1
- if(charge > 7)
+ if(charge > 3)
AddUses(1)
charge = 1
-/obj/item/lightreplacer/proc/ReplaceLight(var/obj/machinery/light/target, var/mob/living/U)
-
+/obj/item/lightreplacer/proc/ReplaceLight(obj/machinery/light/target, mob/living/U)
if(target.status != LIGHT_OK)
if(CanUse(U))
- if(!Use(U)) return
- to_chat(U, "You replace the [target.fitting] with the [src].")
+ if(!Use(U))
+ return
+ to_chat(U, "You replace [target.fitting] with [src].")
if(target.status != LIGHT_EMPTY)
-
- var/obj/item/light/L1 = new target.light_type(target.loc)
- L1.status = target.status
- L1.rigged = target.rigged
- L1.brightness_range = target.brightness_range
- L1.brightness_power = target.brightness_power
- L1.brightness_color = target.brightness_color
- L1.switchcount = target.switchcount
- target.switchcount = 0
- L1.update()
-
+ AddShards(1, U)
target.status = LIGHT_EMPTY
target.update()
@@ -215,37 +215,54 @@
return
else
- to_chat(U, failmsg)
+ to_chat(U, "[src]'s refill light blinks red.")
return
else
- to_chat(U, "There is a working [target.fitting] already inserted.")
+ to_chat(U, "There is a working [target.fitting] already inserted!")
return
/obj/item/lightreplacer/proc/Emag()
emagged = !emagged
- playsound(src.loc, "sparks", 100, 1)
+ playsound(loc, "sparks", 100, TRUE)
if(emagged)
- name = "Shortcircuited [initial(name)]"
+ name = "shortcircuited [initial(name)]"
else
name = initial(name)
update_icon()
-//Can you use it?
+/obj/item/lightreplacer/proc/CanUse(mob/living/user)
+ add_fingerprint(user)
+ if(uses > 0)
+ return 1
+ else
+ return 0
+
+/obj/item/lightreplacer/afterattack(atom/T, mob/U, proximity)
+ if(!proximity)
+ return
+ if(!isturf(T))
+ return
+
+ var/used = FALSE
+ for(var/atom/A in T)
+ if(!CanUse(U))
+ break
+ used = TRUE
+ if(istype(A, /obj/machinery/light))
+ ReplaceLight(A, U)
+
+ if(!used)
+ to_chat(U, "[src]'s refill light blinks red.")
/obj/item/lightreplacer/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J)
J.put_in_cart(src, user)
J.myreplacer = src
J.update_icon()
-/obj/item/lightreplacer/proc/CanUse(var/mob/living/user)
- src.add_fingerprint(user)
- //Not sure what else to check for. Maybe if clumsy?
- if(uses > 0)
- return 1
- else
- return 0
+/obj/item/lightreplacer/cyborg/janicart_insert(mob/user, obj/structure/janitorialcart/J)
+ return
#undef LIGHT_OK
#undef LIGHT_EMPTY
#undef LIGHT_BROKEN
-#undef LIGHT_BURNED
+#undef LIGHT_BURNED
\ No newline at end of file
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index f38398180ee..1b20716783a 100644
--- a/code/game/objects/items/robot/robot_items.dm
+++ b/code/game/objects/items/robot/robot_items.dm
@@ -12,7 +12,7 @@
/obj/item/borg/stun/attack(mob/living/M, mob/living/silicon/robot/user)
if(ishuman(M))
var/mob/living/carbon/human/H = M
- if(H.check_shields(0, "[M]'s [name]", src, MELEE_ATTACK))
+ if(H.check_shields(src, 0, "[M]'s [name]", MELEE_ATTACK))
playsound(M, 'sound/weapons/genhit.ogg', 50, 1)
return 0
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index cc7270e73c8..edc7b855c99 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -210,7 +210,7 @@
brightness_on = 0
sharp_when_wielded = FALSE // It's a toy
-/obj/item/twohanded/dualsaber/toy/hit_reaction()
+/obj/item/twohanded/dualsaber/toy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return 0
/obj/item/twohanded/dualsaber/toy/IsReflect()//Stops Toy Dualsabers from reflecting energy projectiles
diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm
index 7f416679092..d7038fcd752 100644
--- a/code/game/objects/items/weapons/flamethrower.dm
+++ b/code/game/objects/items/weapons/flamethrower.dm
@@ -230,10 +230,12 @@
/obj/item/flamethrower/full/tank
create_with_tank = TRUE
-/obj/item/flamethrower/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type)
- if(ptank && damage && attack_type == PROJECTILE_ATTACK && prob(15))
+/obj/item/flamethrower/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ var/obj/item/projectile/P = hitby
+ if(damage && attack_type == PROJECTILE_ATTACK && P.damage_type != STAMINA && prob(15))
owner.visible_message("[attack_text] hits the fueltank on [owner]'s [src], rupturing it! What a shot!")
- var/target_turf = get_turf(owner)
+ var/turf/target_turf = get_turf(owner)
+ log_game("A projectile ([hitby]) detonated a flamethrower tank held by [key_name(owner)] at [COORD(target_turf)]")
igniter.ignite_turf(src,target_turf, release_amount = 100)
QDEL_NULL(ptank)
return 1 //It hit the flamethrower, not them
diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm
index 3e313bcac33..514c83e89de 100644
--- a/code/game/objects/items/weapons/grenades/chem_grenade.dm
+++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm
@@ -113,9 +113,13 @@
spawn(det_time)
prime()
-/obj/item/grenade/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type)
- if(damage && attack_type == PROJECTILE_ATTACK && prob(15))
+/obj/item/grenade/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ var/obj/item/projectile/P = hitby
+ if(damage && attack_type == PROJECTILE_ATTACK && P.damage_type != STAMINA && prob(15))
owner.visible_message("[attack_text] hits [owner]'s [src], setting it off! What a shot!")
+ var/turf/T = get_turf(src)
+ log_game("A projectile ([hitby]) detonated a grenade held by [key_name(owner)] at [COORD(T)]")
+ message_admins("A projectile ([hitby]) detonated a grenade held by [key_name_admin(owner)] at [ADMIN_COORDJMP(T)]")
prime()
return 1 //It hit the grenade, not them
diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm
index 68e731b8c44..0de138805f1 100644
--- a/code/game/objects/items/weapons/holy_weapons.dm
+++ b/code/game/objects/items/weapons/holy_weapons.dm
@@ -137,7 +137,7 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
-/obj/item/nullrod/claymore/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type)
+/obj/item/nullrod/claymore/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(attack_type == PROJECTILE_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight
return ..()
diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm
index 5e8d170f50b..52e0b24ec4d 100644
--- a/code/game/objects/items/weapons/melee/energy.dm
+++ b/code/game/objects/items/weapons/melee/energy.dm
@@ -119,7 +119,7 @@
if(item_color == null)
item_color = pick("red", "blue", "green", "purple")
-/obj/item/melee/energy/sword/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
+/obj/item/melee/energy/sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(active)
return ..()
return 0
@@ -156,7 +156,7 @@
..()
item_color = null
-/obj/item/melee/energy/sword/cyborg/saw/hit_reaction()
+/obj/item/melee/energy/sword/cyborg/saw/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return 0
/obj/item/melee/energy/sword/saber
diff --git a/code/game/objects/items/weapons/melee/misc.dm b/code/game/objects/items/weapons/melee/misc.dm
index 943d20e9699..b9f1fa679a8 100644
--- a/code/game/objects/items/weapons/melee/misc.dm
+++ b/code/game/objects/items/weapons/melee/misc.dm
@@ -44,7 +44,7 @@
hitsound = 'sound/weapons/rapierhit.ogg'
materials = list(MAT_METAL = 1000)
-/obj/item/melee/rapier/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type)
+/obj/item/melee/rapier/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(attack_type == PROJECTILE_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight
return ..()
diff --git a/code/game/objects/items/weapons/shards.dm b/code/game/objects/items/weapons/shards.dm
index 4c8697da247..e2fc07712bf 100644
--- a/code/game/objects/items/weapons/shards.dm
+++ b/code/game/objects/items/weapons/shards.dm
@@ -1,27 +1,30 @@
// Glass shards
/obj/item/shard
- name = "glass shard"
+ name = "shard"
+ desc = "A nasty looking shard of glass."
icon = 'icons/obj/shards.dmi'
icon_state = "large"
- sharp = TRUE
- desc = "Could probably be used as ... a throwing weapon?"
w_class = WEIGHT_CLASS_TINY
force = 5
throwforce = 10
item_state = "shard-glass"
- materials = list(MAT_GLASS=MINERAL_MATERIAL_AMOUNT)
+ materials = list(MAT_GLASS = MINERAL_MATERIAL_AMOUNT)
attack_verb = list("stabbed", "slashed", "sliced", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
armor = list("melee" = 100, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0)
+ sharp = TRUE
+ var/cooldown = 0
+ var/icon_prefix
+ var/obj/item/stack/sheet/welded_type = /obj/item/stack/sheet/glass
/obj/item/shard/suicide_act(mob/user)
to_chat(viewers(user), pick("[user] is slitting [user.p_their()] wrists with [src]! It looks like [user.p_theyre()] trying to commit suicide.",
"[user] is slitting [user.p_their()] throat with [src]! It looks like [user.p_theyre()] trying to commit suicide."))
return BRUTELOSS
-/obj/item/shard/New()
- ..()
+/obj/item/shard/Initialize(mapload)
+ . = ..()
icon_state = pick("large", "medium", "small")
switch(icon_state)
if("small")
@@ -33,6 +36,8 @@
if("large")
pixel_x = rand(-5, 5)
pixel_y = rand(-5, 5)
+ if(icon_prefix)
+ icon_state = "[icon_prefix][icon_state]"
/obj/item/shard/afterattack(atom/movable/AM, mob/user, proximity)
if(!proximity || !(src in user))
@@ -48,15 +53,17 @@
if(affecting.is_robotic())
return
to_chat(H, "[src] cuts into your hand!")
- if(affecting.receive_damage(force*0.5))
+ if(affecting.receive_damage(force * 0.5))
H.UpdateDamageIcon()
/obj/item/shard/attackby(obj/item/I, mob/user, params)
if(iswelder(I))
var/obj/item/weldingtool/WT = I
if(WT.remove_fuel(0, user))
- var/obj/item/stack/sheet/glass/NG = new (user.loc)
- for(var/obj/item/stack/sheet/glass/G in user.loc)
+ var/obj/item/stack/sheet/NG = new welded_type(user.loc)
+ for(var/obj/item/stack/sheet/G in user.loc)
+ if(!istype(G, welded_type))
+ continue
if(G == NG)
continue
if(G.amount >= G.max_amount)
@@ -64,64 +71,48 @@
G.attackby(NG, user)
to_chat(user, "You add the newly-formed glass to the stack. It now contains [NG.amount] sheet\s.")
qdel(src)
- else
- return ..()
+ return
+ if(istype(I, /obj/item/lightreplacer))
+ I.attackby(src, user)
+ return
+ return ..()
-/obj/item/shard/Crossed(AM as mob|obj, oldloc)
- if(isliving(AM))
- var/mob/living/M = AM
- if(M.incorporeal_move || M.flying || M.throwing)//you are incorporal or flying or being thrown ..no shard stepping!
+/obj/item/shard/Crossed(mob/living/L, oldloc)
+ if(istype(L) && has_gravity(loc))
+ if(L.incorporeal_move || L.flying)
return
- to_chat(M, "You step on \the [src]!")
- playsound(loc, 'sound/effects/glass_step.ogg', 50, 1) // not sure how to handle metal shards with sounds
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
+ playsound(loc, 'sound/effects/glass_step.ogg', 50, TRUE)
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ var/obj/item/organ/external/affecting = H.get_organ(pick("l_foot", "r_foot"))
+ if(!affecting)
+ return
+ if(affecting.is_robotic())
+ return
+ var/feetCover = (H.wear_suit && H.wear_suit.body_parts_covered & FEET) || (H.w_uniform && H.w_uniform.body_parts_covered & FEET)
+ if(H.shoes || feetCover || H.buckled)
+ return
+ if(affecting.receive_damage(force, 0))
+ H.UpdateDamageIcon()
- if( !H.shoes && ( !H.wear_suit || !(H.wear_suit.body_parts_covered & FEET) ) )
- var/obj/item/organ/external/affecting = H.get_organ(pick("l_foot", "r_foot"))
- if(!affecting)
- return
- if(affecting.is_robotic())
- return
- H.Weaken(3)
- if(affecting.receive_damage(5, 0))
- H.UpdateDamageIcon()
- ..()
+ if(cooldown < world.time - 10) //cooldown to avoid message spam.
+ if(!H.incapacitated(ignore_restraints = TRUE))
+ H.visible_message("[H] steps on [src]!", \
+ "You step on [src]!")
+ else
+ H.visible_message("[H] slides on [src]!", \
+ "You slide on [src]!")
+
+ cooldown = world.time
+ H.Weaken(3)
+ return ..()
/obj/item/shard/plasma
name = "plasma shard"
desc = "A shard of plasma glass. Considerably tougher then normal glass shards. Apparently not tough enough to be a window."
- force = 8
- throwforce = 15
+ force = 6
+ throwforce = 11
icon_state = "plasmalarge"
- sharp = TRUE
-
-/obj/item/shard/plasma/New()
- ..()
- icon_state = pick("plasmalarge", "plasmamedium", "plasmasmall")
- switch(icon_state)
- if("plasmasmall")
- pixel_x = rand(-12, 12)
- pixel_y = rand(-12, 12)
- if("plasmamedium")
- pixel_x = rand(-8, 8)
- pixel_y = rand(-8, 8)
- if("plasmalarge")
- pixel_x = rand(-5, 5)
- pixel_y = rand(-5, 5)
-
-/obj/item/shard/plasma/attackby(obj/item/W, mob/user, params)
- if(iswelder(W))
- var/obj/item/weldingtool/WT = W
- if(WT.remove_fuel(0, user))
- var/obj/item/stack/sheet/plasmaglass/NG = new (user.loc)
- for(var/obj/item/stack/sheet/plasmaglass/G in user.loc)
- if(G == NG)
- continue
- if(G.amount >= G.max_amount)
- continue
- G.attackby(NG, user, params)
- to_chat(usr, "You add the newly-formed plasma glass to the stack. It now contains [NG.amount] sheets.")
- qdel(src)
- else
- return ..()
+ materials = list(MAT_PLASMA = MINERAL_MATERIAL_AMOUNT * 0.5, MAT_GLASS = MINERAL_MATERIAL_AMOUNT)
+ icon_prefix = "plasma"
+ welded_type = /obj/item/stack/sheet/plasmaglass
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm
index 61f83fdea25..2cbf80a6388 100644
--- a/code/game/objects/items/weapons/shields.dm
+++ b/code/game/objects/items/weapons/shields.dm
@@ -3,7 +3,7 @@
block_chance = 50
armor = list(melee = 50, bullet = 50, laser = 50, energy = 0, bomb = 30, bio = 0, rad = 0)
-/obj/item/shield/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type)
+/obj/item/shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(attack_type == THROWN_PROJECTILE_ATTACK)
final_block_chance += 30
if(attack_type == LEAP_ATTACK)
@@ -63,7 +63,7 @@
attack_verb = list("shoved", "bashed")
var/active = 0
-/obj/item/shield/energy/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
+/obj/item/shield/energy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return 0
/obj/item/shield/energy/IsReflect()
@@ -110,7 +110,7 @@
w_class = WEIGHT_CLASS_NORMAL
var/active = 0
-/obj/item/shield/riot/tele/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
+/obj/item/shield/riot/tele/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(active)
return ..()
return 0
diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm
index 526340daea5..6d81cdd2dac 100644
--- a/code/game/objects/items/weapons/stunbaton.dm
+++ b/code/game/objects/items/weapons/stunbaton.dm
@@ -175,7 +175,7 @@
if(ishuman(L))
var/mob/living/carbon/human/H = L
- if(H.check_shields(0, "[user]'s [name]", src, MELEE_ATTACK)) //No message; check_shields() handles that
+ if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) //No message; check_shields() handles that
playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
return
diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm
index d0526ebbcb8..409e5575df3 100644
--- a/code/game/objects/items/weapons/swords_axes_etc.dm
+++ b/code/game/objects/items/weapons/swords_axes_etc.dm
@@ -51,7 +51,7 @@
if(cooldown <= 0)
if(ishuman(target))
var/mob/living/carbon/human/H = target
- if(H.check_shields(0, "[user]'s [name]", src, MELEE_ATTACK))
+ if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
return
if(check_martial_counter(H, user))
return
diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm
index 15456386541..16387c8b2cb 100644
--- a/code/game/objects/items/weapons/twohanded.dm
+++ b/code/game/objects/items/weapons/twohanded.dm
@@ -267,7 +267,7 @@
user.SpinAnimation(7, 1)
sleep(1)
-/obj/item/twohanded/dualsaber/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
+/obj/item/twohanded/dualsaber/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(wielded)
return ..()
return FALSE
@@ -337,14 +337,23 @@
sharp = TRUE
no_spin_thrown = TRUE
var/obj/item/grenade/explosive = null
+ var/icon_prefix = "spearglass"
/obj/item/twohanded/spear/update_icon()
- if(explosive)
- icon_state = "spearbomb[wielded]"
- else
- icon_state = "spearglass[wielded]"
+ icon_state = "[icon_prefix][wielded]"
+
+/obj/item/twohanded/spear/CheckParts(list/parts_list)
+ var/obj/item/shard/tip = locate() in parts_list
+ if(istype(tip, /obj/item/shard/plasma))
+ force_wielded = 19
+ force_unwielded = 11
+ throwforce = 21
+ icon_prefix = "spearplasma"
+ update_icon()
+ qdel(tip)
..()
+
/obj/item/twohanded/spear/afterattack(atom/movable/AM, mob/user, proximity)
if(!proximity)
return
@@ -370,9 +379,7 @@
force_wielded = 20 //I have no idea how to balance
throwforce = 22
armour_penetration = 15 //Enhanced armor piercing
-
-/obj/item/twohanded/spear/bonespear/update_icon()
- icon_state = "bone_spear[wielded]"
+ icon_prefix = "bone_spear"
//GREY TIDE
/obj/item/twohanded/spear/grey_tide
@@ -507,7 +514,7 @@
armour_penetration = 100
force_on = 30
-/obj/item/twohanded/required/chainsaw/doomslayer/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type)
+/obj/item/twohanded/required/chainsaw/doomslayer/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(attack_type == PROJECTILE_ATTACK)
owner.visible_message("Ranged attacks just make [owner] angrier!")
playsound(src, pick('sound/weapons/bulletflyby.ogg','sound/weapons/bulletflyby2.ogg','sound/weapons/bulletflyby3.ogg'), 75, 1)
diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm
index 501f1780a0b..de06d78f9a7 100644
--- a/code/game/objects/items/weapons/weaponry.dm
+++ b/code/game/objects/items/weapons/weaponry.dm
@@ -105,7 +105,12 @@
..()
if(istype(I, /obj/item/shard))
var/obj/item/twohanded/spear/S = new /obj/item/twohanded/spear
-
+ if(istype(I, /obj/item/shard/plasma))
+ S.force_wielded = 19
+ S.force_unwielded = 11
+ S.throwforce = 21
+ S.icon_prefix = "spearplasma"
+ S.update_icon()
if(!remove_item_from_storage(user))
user.unEquip(src)
user.unEquip(I)
@@ -171,11 +176,11 @@
desc = "This thing looks dangerous... Dangerously good at baseball, that is."
homerun_able = 1
-/obj/item/melee/baseball_bat/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type, atom/movable/AM)
+/obj/item/melee/baseball_bat/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
. = ..()
- if(!istype(AM, /obj/item) || attack_type != THROWN_PROJECTILE_ATTACK)
+ if(!isitem(hitby) || attack_type != THROWN_PROJECTILE_ATTACK)
return FALSE
- var/obj/item/I = AM
+ var/obj/item/I = hitby
if(I.w_class <= WEIGHT_CLASS_NORMAL || istype(I, /obj/item/beach_ball)) // baseball bat deflecting
if(deflectmode)
if(prob(10))
diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm
index 22325fed75f..0feca103c12 100644
--- a/code/modules/client/client defines.dm
+++ b/code/modules/client/client defines.dm
@@ -95,3 +95,8 @@
// Has the client been varedited by an admin? [Inherits from datum now]
// var/var_edited = FALSE
+
+ var/client_keysend_amount = 0
+ var/next_keysend_reset = 0
+ var/next_keysend_trip_reset = 0
+ var/keysend_tripped = FALSE
\ No newline at end of file
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index b56d2122ee8..f342cf9f04f 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -527,7 +527,7 @@
var/shield_on = "shield-old"
sprite_sheets = null
-/obj/item/clothing/suit/space/hardsuit/shielded/hit_reaction(mob/living/carbon/human/owner, attack_text)
+/obj/item/clothing/suit/space/hardsuit/shielded/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(current_charges > 0)
do_sparks(2, 1, src)
owner.visible_message("[owner]'s shields deflect [attack_text] in a shower of sparks!")
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index c5242d072e0..1ab7fe58c2b 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -301,7 +301,7 @@
desc = "Someone seperated our Research Director from his own head!"
var/tele_range = 6
-/obj/item/clothing/suit/armor/reactive/teleport/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
+/obj/item/clothing/suit/armor/reactive/teleport/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
@@ -332,7 +332,7 @@
/obj/item/clothing/suit/armor/reactive/fire
name = "reactive incendiary armor"
-/obj/item/clothing/suit/armor/reactive/fire/hit_reaction(mob/living/carbon/human/owner, attack_text)
+/obj/item/clothing/suit/armor/reactive/fire/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
@@ -349,7 +349,7 @@
/obj/item/clothing/suit/armor/reactive/stealth
name = "reactive stealth armor"
-/obj/item/clothing/suit/armor/reactive/stealth/hit_reaction(mob/living/carbon/human/owner, attack_text)
+/obj/item/clothing/suit/armor/reactive/stealth/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
@@ -366,7 +366,7 @@
/obj/item/clothing/suit/armor/reactive/tesla
name = "reactive tesla armor"
-/obj/item/clothing/suit/armor/reactive/tesla/hit_reaction(mob/living/carbon/human/owner, attack_text)
+/obj/item/clothing/suit/armor/reactive/tesla/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
diff --git a/code/modules/clothing/under/color.dm b/code/modules/clothing/under/color.dm
index e7f29305929..17db1997174 100644
--- a/code/modules/clothing/under/color.dm
+++ b/code/modules/clothing/under/color.dm
@@ -60,7 +60,7 @@
name = "ancient jumpsuit"
desc = "A terribly ragged and frayed grey jumpsuit. It looks like it hasn't been washed in over a decade."
-/obj/item/clothing/under/color/grey/glorf/hit_reaction(mob/living/carbon/human/owner)
+/obj/item/clothing/under/color/grey/glorf/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
owner.forcesay(GLOB.hit_appends)
return 0
diff --git a/code/modules/clothing/under/jobs/civilian.dm b/code/modules/clothing/under/jobs/civilian.dm
index 81c6d15562a..df04075306d 100644
--- a/code/modules/clothing/under/jobs/civilian.dm
+++ b/code/modules/clothing/under/jobs/civilian.dm
@@ -74,7 +74,7 @@
. = ..()
AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg' = 1), 50)
-/obj/item/clothing/under/rank/clown/hit_reaction()
+/obj/item/clothing/under/rank/clown/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
if(H.mind && H.mind.assigned_role == "Clown")
diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm
index b4aa0a62379..e21d0f80c76 100644
--- a/code/modules/customitems/item_defines.dm
+++ b/code/modules/customitems/item_defines.dm
@@ -135,7 +135,7 @@
force = 5
sharp = 0
-/obj/item/claymore/fluff/hit_reaction()
+/obj/item/claymore/fluff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return 0
/obj/item/fluff/rsik_katana //Xydonus: Rsik Ugsharki Atan
diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm
index e3925aa5283..d59e3da4e8e 100644
--- a/code/modules/keybindings/bindings_client.dm
+++ b/code/modules/keybindings/bindings_client.dm
@@ -3,7 +3,46 @@
/client/verb/keyDown(_key as text)
set instant = TRUE
set hidden = TRUE
+
+ client_keysend_amount += 1
+
+ var/cache = client_keysend_amount
+
+ if(keysend_tripped && next_keysend_trip_reset <= world.time)
+ keysend_tripped = FALSE
+
+ if(next_keysend_reset <= world.time)
+ client_keysend_amount = 0
+ next_keysend_reset = world.time + (1 SECONDS)
+
+ //The "tripped" system is to confirm that flooding is still happening after one spike
+ //not entirely sure how byond commands interact in relation to lag
+ //don't want to kick people if a lag spike results in a huge flood of commands being sent
+ if(cache >= MAX_KEYPRESS_AUTOKICK)
+ if(!keysend_tripped)
+ keysend_tripped = TRUE
+ next_keysend_trip_reset = world.time + (2 SECONDS)
+ else
+ log_admin("Client [ckey] was just autokicked for flooding keysends; likely abuse but potentially lagspike.")
+ message_admins("Client [ckey] was just autokicked for flooding keysends; likely abuse but potentially lagspike.")
+ QDEL_IN(src, 1)
+ return
+
+ ///Check if the key is short enough to even be a real key
+ if(LAZYLEN(_key) > MAX_KEYPRESS_COMMANDLENGTH)
+ to_chat(src, "Invalid KeyDown detected! You have been disconnected from the server automatically.")
+ log_admin("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.")
+ message_admins("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.")
+ QDEL_IN(src, 1)
+ return
+ //offset by 1 because the buffer address is 0 indexed because the math was simpler
+ keys_held[current_key_address + 1] = _key
+ //the time a key was pressed isn't actually used anywhere (as of 2019-9-10) but this allows easier access usage/checking
+
keys_held[_key] = world.time
+
+ current_key_address = ((current_key_address + 1) % HELD_KEY_BUFFER_LENGTH)
+
var/movement = SSinput.movement_keys[_key]
if (prefs.toggles & AZERTY) movement = SSinput.alt_movement_keys[_key]
if(!(next_move_dir_sub & movement) && !keys_held["Ctrl"])
@@ -40,7 +79,11 @@
/client/verb/keyUp(_key as text)
set instant = TRUE
set hidden = TRUE
- keys_held -= _key
+ //Can't just do a remove because it would alter the length of the rolling buffer, instead search for the key then null it out if it exists
+ for(var/i in 1 to HELD_KEY_BUFFER_LENGTH)
+ if(keys_held[i] == _key)
+ keys_held[i] = null
+ break
var/movement = SSinput.movement_keys[_key]
if (prefs.toggles & AZERTY) movement = SSinput.alt_movement_keys[_key]
if(!(next_move_dir_add & movement))
diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm
index cc76256386e..b6e80452304 100644
--- a/code/modules/keybindings/setup.dm
+++ b/code/modules/keybindings/setup.dm
@@ -1,9 +1,14 @@
/client
- var/list/keys_held = list() // A list of any keys held currently
- // These next two vars are to apply movement for keypresses and releases made while move delayed.
- // Because discarding that input makes the game less responsive.
- var/next_move_dir_add // On next move, add this dir to the move that would otherwise be done
- var/next_move_dir_sub // On next move, subtract this dir from the move that would otherwise be done
+ /// A rolling buffer of any keys held currently
+ var/list/keys_held = list()
+ ///used to keep track of the current rolling buffer position
+ var/current_key_address = 0
+ /// These next two vars are to apply movement for keypresses and releases made while move delayed.
+ /// Because discarding that input makes the game less responsive.
+ /// On next move, add this dir to the move that would otherwise be done
+ var/next_move_dir_add
+ /// On next move, subtract this dir from the move that would otherwise be done
+ var/next_move_dir_sub
// Set a client's focus to an object and override these procs on that object to let it handle keypresses
@@ -31,6 +36,11 @@
/client/proc/set_macros()
set waitfor = FALSE
+ //Reset and populate the rolling buffer
+ keys_held.Cut()
+ for(var/i in 1 to HELD_KEY_BUFFER_LENGTH)
+ keys_held += null
+
erase_all_macros()
var/list/macro_sets = SSinput.macro_sets
diff --git a/code/modules/martial_arts/martial.dm b/code/modules/martial_arts/martial.dm
index 2940e810ade..571eefcfb00 100644
--- a/code/modules/martial_arts/martial.dm
+++ b/code/modules/martial_arts/martial.dm
@@ -277,7 +277,7 @@
return ..()
return ..()
-/obj/item/twohanded/bostaff/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
+/obj/item/twohanded/bostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(wielded)
return ..()
return 0
diff --git a/code/modules/mining/lavaland/loot/ashdragon_loot.dm b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
index c9b35e6f883..6a1e563da7a 100644
--- a/code/modules/mining/lavaland/loot/ashdragon_loot.dm
+++ b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
@@ -101,7 +101,7 @@
user.visible_message("[user] strikes with the force of [ghost_counter] vengeful spirits!")
..()
-/obj/item/melee/ghost_sword/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type)
+/obj/item/melee/ghost_sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
var/ghost_counter = ghost_check()
final_block_chance += Clamp((ghost_counter * 5), 0, 75)
owner.visible_message("[owner] is protected by a ring of [ghost_counter] ghosts!")
diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
index bf2158ae58e..f950eee4dbf 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
@@ -99,7 +99,7 @@
var/blocked = 0
if(ishuman(A))
var/mob/living/carbon/human/H = A
- if(H.check_shields(0, "the [name]", src, attack_type = LEAP_ATTACK))
+ if(H.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK))
blocked = 1
if(!blocked)
L.visible_message("[src] pounces on [L]!", "[src] pounces on you!")
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 99b7b339d90..73147afb93a 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -34,7 +34,7 @@ emp_act
return -1 // complete projectile permutation
//Shields
- if(check_shields(P.damage, "the [P.name]", P, PROJECTILE_ATTACK, P.armour_penetration))
+ if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
P.on_hit(src, 100, def_zone)
return 2
@@ -136,24 +136,24 @@ emp_act
//End Here
-/mob/living/carbon/human/proc/check_shields(damage = 0, attack_text = "the attack", atom/movable/AM, attack_type = MELEE_ATTACK, armour_penetration = 0)
+/mob/living/carbon/human/proc/check_shields(atom/AM, var/damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
var/block_chance_modifier = round(damage / -3)
if(l_hand && !istype(l_hand, /obj/item/clothing))
var/final_block_chance = l_hand.block_chance - (Clamp((armour_penetration-l_hand.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
- if(l_hand.hit_reaction(src, attack_text, final_block_chance, damage, attack_type, AM))
+ if(l_hand.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
if(r_hand && !istype(r_hand, /obj/item/clothing))
var/final_block_chance = r_hand.block_chance - (Clamp((armour_penetration-r_hand.armour_penetration)/2,0,100)) + block_chance_modifier //Need to reset the var so it doesn't carry over modifications between attempts
- if(r_hand.hit_reaction(src, attack_text, final_block_chance, damage, attack_type, AM))
+ if(r_hand.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
if(wear_suit)
var/final_block_chance = wear_suit.block_chance - (Clamp((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier
- if(wear_suit.hit_reaction(src, attack_text, final_block_chance, damage, attack_type, AM))
+ if(wear_suit.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
if(w_uniform)
var/final_block_chance = w_uniform.block_chance - (Clamp((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier
- if(w_uniform.hit_reaction(src, attack_text, final_block_chance, damage, attack_type, AM))
+ if(w_uniform.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
return 0
@@ -217,7 +217,7 @@ emp_act
if(user != src)
user.do_attack_animation(src)
- if(check_shields(I.force, "the [I.name]", I, MELEE_ATTACK, I.armour_penetration))
+ if(check_shields(I, I.force, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
return 0
if(check_block())
@@ -311,7 +311,7 @@ emp_act
throwpower = I.throwforce
if(I.thrownby == src) //No throwing stuff at yourself to trigger reactions
return ..()
- if(check_shields(throwpower, "\the [AM.name]", AM, THROWN_PROJECTILE_ATTACK))
+ if(check_shields(AM, throwpower, "\the [AM.name]", THROWN_PROJECTILE_ATTACK))
hitpush = 0
skipcatch = 1
blocked = 1
@@ -392,7 +392,7 @@ emp_act
updatehealth("larva attack")
/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(check_shields(0, M.name))
+ if(check_shields(M, 0, M.name))
visible_message("[M] attempted to touch [src]!")
return 0
@@ -440,7 +440,7 @@ emp_act
. = ..()
if(.)
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
- if(check_shields(damage, "the [M.name]", null, MELEE_ATTACK, M.armour_penetration))
+ if(check_shields(M, damage, "the [M.name]", MELEE_ATTACK, M.armour_penetration))
return FALSE
var/dam_zone = pick("head", "chest", "groin", "l_arm", "l_hand", "r_arm", "r_hand", "l_leg", "l_foot", "r_leg", "r_foot")
var/obj/item/organ/external/affecting = get_organ(ran_zone(dam_zone))
diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm
index dbb7b8731fc..87c9c90359b 100644
--- a/code/modules/mob/living/carbon/human/species/_species.dm
+++ b/code/modules/mob/living/carbon/human/species/_species.dm
@@ -522,7 +522,7 @@
to_chat(M, "You can't use your hand.")
return
- if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(0, M.name, attack_type = UNARMED_ATTACK))
+ if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK))
add_attack_logs(M, H, "Melee attacked with fists (miss/block)")
H.visible_message("[M] attempted to touch [H]!")
return FALSE
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 699376c927f..76c7f5bc1af 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -252,7 +252,7 @@
modules += new /obj/item/soap/nanotrasen(src)
modules += new /obj/item/storage/bag/trash/cyborg(src)
modules += new /obj/item/mop/advanced/cyborg(src)
- modules += new /obj/item/lightreplacer(src)
+ modules += new /obj/item/lightreplacer/cyborg(src)
modules += new /obj/item/holosign_creator(src)
emag = new /obj/item/reagent_containers/spray(src)
@@ -544,7 +544,7 @@
modules += new /obj/item/crowbar/cyborg(src)
modules += new /obj/item/wirecutters/cyborg(src)
modules += new /obj/item/multitool/cyborg(src)
- modules += new /obj/item/lightreplacer(src)
+ modules += new /obj/item/lightreplacer/cyborg(src)
modules += new /obj/item/gripper(src)
modules += new /obj/item/matter_decompiler(src)
modules += new /obj/item/reagent_containers/spray/cleaner/drone(src)
@@ -562,10 +562,6 @@
/obj/item/robot_module/drone/respawn_consumable(mob/living/silicon/robot/R)
var/obj/item/reagent_containers/spray/cleaner/C = locate() in modules
C.reagents.add_reagent("cleaner", 3)
-
- var/obj/item/lightreplacer/LR = locate() in modules
- LR.Charge(R)
-
..()
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index b186e862f01..6b4b5f05e82 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -303,10 +303,7 @@
//Light replacer code
if(istype(W, /obj/item/lightreplacer))
var/obj/item/lightreplacer/LR = W
- if(isliving(user))
- var/mob/living/U = user
- LR.ReplaceLight(src, U)
- return
+ LR.ReplaceLight(src, user)
// attempt to insert light
if(istype(W, /obj/item/light))
diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm
index 560ecf44684..9196596c8b5 100644
--- a/code/modules/projectiles/guns/magic/staff.dm
+++ b/code/modules/projectiles/guns/magic/staff.dm
@@ -89,7 +89,7 @@
sharp = 1
max_charges = 4
-/obj/item/gun/magic/staff/spellblade/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type)
+/obj/item/gun/magic/staff/spellblade/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(attack_type == PROJECTILE_ATTACK)
final_block_chance = 0
return ..()
diff --git a/code/modules/reagents/chemistry/reagents/medicine.dm b/code/modules/reagents/chemistry/reagents/medicine.dm
index 6862e51a04c..01ccfa36dbb 100644
--- a/code/modules/reagents/chemistry/reagents/medicine.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine.dm
@@ -291,11 +291,6 @@
addiction_chance = 5
taste_description = "health"
-/datum/reagent/medicine/omnizine/godblood
- name = "Godblood"
- description = "Slowly heals all damage types. Has a rather high overdose threshold. Glows with mysterious power."
- overdose_threshold = 150
-
/datum/reagent/medicine/omnizine/on_mob_life(mob/living/M)
var/update_flags = STATUS_UPDATE_NONE
update_flags |= M.adjustToxLoss(-1*REAGENTS_EFFECT_MULTIPLIER, FALSE)
@@ -964,6 +959,12 @@
metabolization_rate = 0.1
taste_description = "faint hope"
+/datum/reagent/medicine/omnizine_diluted/godblood
+ name = "Godblood"
+ id = "godblood"
+ description = "Slowly heals all damage types. Has a rather high overdose threshold. Glows with mysterious power."
+ overdose_threshold = 150
+
/datum/reagent/medicine/omnizine_diluted/on_mob_life(mob/living/M)
var/update_flags = STATUS_UPDATE_NONE
update_flags |= M.adjustToxLoss(-0.5*REAGENTS_EFFECT_MULTIPLIER, FALSE)
diff --git a/code/modules/ruins/lavalandruin_code/fountain_hall.dm b/code/modules/ruins/lavalandruin_code/fountain_hall.dm
index 917ea4e4bd0..3de758ac0c9 100644
--- a/code/modules/ruins/lavalandruin_code/fountain_hall.dm
+++ b/code/modules/ruins/lavalandruin_code/fountain_hall.dm
@@ -38,7 +38,7 @@
return
last_process = world.time
to_chat(user, "The water feels warm and soothing as you touch it. The fountain immediately dries up shortly afterwards.")
- user.reagents.add_reagent(/datum/reagent/medicine/omnizine/godblood, 20)
+ user.reagents.add_reagent("godblood", 20)
update_icon()
addtimer(CALLBACK(src, .proc/update_icon), time_between_uses)
diff --git a/html/changelogs/AutoChangeLog-pr-12251.yml b/html/changelogs/AutoChangeLog-pr-12251.yml
new file mode 100644
index 00000000000..98f31a5ec8d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12251.yml
@@ -0,0 +1,5 @@
+author: "variableundefined"
+delete-after: True
+changes:
+ - tweak: "Hit_reaction proc has been refactored."
+ - tweak: "Flamethrower and grenade detonation by shot is now logged."
diff --git a/html/changelogs/AutoChangeLog-pr-12255.yml b/html/changelogs/AutoChangeLog-pr-12255.yml
new file mode 100644
index 00000000000..a320bb2b102
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12255.yml
@@ -0,0 +1,7 @@
+author: "Fox McCloud"
+delete-after: True
+changes:
+ - tweak: "Plasma glass shards do less damage when attacking, but slightly more when stepping on them"
+ - tweak: "Spears made out of plasma glass do slightly more damage"
+ - tweak: "Light replacer can now be used in-hand to attempt to reload empty lighting fixtures around you in addition to showing how many lights it has"
+ - tweak: "Light replacer needs less shards to increment bulbs"
diff --git a/html/changelogs/AutoChangeLog-pr-12265.yml b/html/changelogs/AutoChangeLog-pr-12265.yml
new file mode 100644
index 00000000000..1abb27cad08
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12265.yml
@@ -0,0 +1,4 @@
+author: "TDSSS"
+delete-after: True
+changes:
+ - bugfix: "healing fountain lavaland ruin now correctly heals"
diff --git a/html/changelogs/AutoChangeLog-pr-12276.yml b/html/changelogs/AutoChangeLog-pr-12276.yml
new file mode 100644
index 00000000000..731eb403af1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12276.yml
@@ -0,0 +1,4 @@
+author: "Kyep"
+delete-after: True
+changes:
+ - bugfix: "fixed an issue with keyboard input"
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index 10eef3b0337..7d0961fc449 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 926e04b28bf..5850e4d8d8c 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index 463e135d35f..35f0fb7349d 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ