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