diff --git a/code/__HELPERS/traits.dm b/code/__HELPERS/traits.dm
index 6faff552ff5..74760fd22b4 100644
--- a/code/__HELPERS/traits.dm
+++ b/code/__HELPERS/traits.dm
@@ -152,6 +152,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_NOEXAMINE "no_examine"
#define TRAIT_NOPAIN "no_pain"
+/// Blowing kisses actually does damage to the victim
+#define TRAIT_KISS_OF_DEATH "kiss_of_death"
+
//
// common trait sources
#define TRAIT_GENERIC "generic"
diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm
index 906b4b608c1..382303c1212 100644
--- a/code/_globalvars/traits.dm
+++ b/code/_globalvars/traits.dm
@@ -45,6 +45,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_DWARF" = TRAIT_DWARF,
"TRAIT_SILENT_FOOTSTEPS" = TRAIT_SILENT_FOOTSTEPS,
"TRAIT_ALCOHOL_TOLERANCE" = TRAIT_ALCOHOL_TOLERANCE,
+ "TRAIT_KISS_OF_DEATH" = TRAIT_KISS_OF_DEATH,
"TRAIT_COMIC_SANS" = TRAIT_COMIC_SANS,
"TRAIT_NOFINGERPRINTS" = TRAIT_NOFINGERPRINTS,
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 456d30c0059..1fe1c68522b 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -31,7 +31,7 @@
return FALSE
/obj/attackby(obj/item/I, mob/living/user, params)
- return ..() || (can_be_hit && I.attack_obj(src, user))
+ return ..() || (can_be_hit && I.attack_obj(src, user, params))
/mob/living/attackby(obj/item/I, mob/living/user, params)
user.changeNext_move(CLICK_CD_MELEE)
@@ -87,7 +87,7 @@
//the equivalent of the standard version of attack() but for object targets.
-/obj/item/proc/attack_obj(obj/O, mob/living/user)
+/obj/item/proc/attack_obj(obj/O, mob/living/user, params)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_OBJ, O, user) & COMPONENT_NO_ATTACK_OBJ)
return
if(flags & (NOBLUDGEON))
diff --git a/code/game/objects/items/hand_item.dm b/code/game/objects/items/hand_item.dm
new file mode 100644
index 00000000000..7f378aa6cdc
--- /dev/null
+++ b/code/game/objects/items/hand_item.dm
@@ -0,0 +1,116 @@
+/obj/item/slapper
+ name = "slapper"
+ desc = "This is how real men fight."
+ icon_state = "latexballon"
+ item_state = "nothing"
+ force = 0
+ throwforce = 0
+ flags = DROPDEL | ABSTRACT
+ attack_verb = list("slaps")
+ hitsound = 'sound/weapons/slap.ogg'
+ /// How many smaller table smacks we can do before we're out
+ var/table_smacks_left = 3
+
+/obj/item/slapper/attack(mob/M, mob/living/carbon/human/user)
+ user.do_attack_animation(M)
+ playsound(M, hitsound, 50, TRUE, -1)
+ user.visible_message("[user] slaps [M]!", "You slap [M]!", "You hear a slap.")
+
+/obj/item/slapper/attack_obj(obj/O, mob/living/user, params)
+ if(!istype(O, /obj/structure/table))
+ return ..()
+
+ var/obj/structure/table/the_table = O
+
+ if(user.a_intent == INTENT_HARM && table_smacks_left == initial(table_smacks_left)) // so you can't do 2 weak slaps followed by a big slam
+ transform = transform.Scale(1.5) // BIG slap
+ if(HAS_TRAIT(user, TRAIT_HULK))
+ transform = transform.Scale(2)
+ color = COLOR_GREEN
+ user.do_attack_animation(the_table)
+ if(ishuman(user))
+ var/mob/living/carbon/human/human_user = user
+ if(istype(human_user.shoes, /obj/item/clothing/shoes/cowboy))
+ human_user.say(pick("Hot damn!", "Hoo-wee!", "Got-dang!"))
+ playsound(get_turf(the_table), 'sound/effects/tableslam.ogg', 110, TRUE)
+ user.visible_message("[user] slams [user.p_their()] fist down on [the_table]!", "You slam your fist down on [the_table]!")
+ qdel(src)
+ else
+ user.do_attack_animation(the_table)
+ playsound(get_turf(the_table), 'sound/effects/tableslam.ogg', 40, TRUE)
+ user.visible_message("[user] slaps [user.p_their()] hand on [the_table].", "You slap your hand on [the_table].")
+ table_smacks_left--
+ if(table_smacks_left <= 0)
+ qdel(src)
+
+/obj/item/kisser
+ name = "kiss"
+ desc = "I want you all to know, everyone and anyone, to seal it with a kiss."
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "heart"
+ item_state = "nothing"
+ force = 0
+ throwforce = 0
+ flags = DROPDEL | ABSTRACT
+ /// The kind of projectile this version of the kiss blower fires
+ var/kiss_type = /obj/item/projectile/kiss
+
+/obj/item/kisser/afterattack(atom/target, mob/user, flag, params)
+ var/turf/user_turf = get_turf(user)
+ var/obj/item/projectile/blown_kiss = new kiss_type(user_turf)
+ user.visible_message("[user] blows \a [blown_kiss] at [target]!", "You blow \a [blown_kiss] at [target]!")
+
+ //Shooting Code:
+ blown_kiss.spread = 0
+ blown_kiss.original = target
+ blown_kiss.firer = user // don't hit ourself that would be really annoying
+ blown_kiss.preparePixelProjectile(target, user_turf, user, params)
+ blown_kiss.fire()
+ qdel(src)
+
+/obj/item/kisser/death
+ name = "kiss of death"
+ desc = "If looks could kill, they'd be this."
+ color = COLOR_BLACK
+ kiss_type = /obj/item/projectile/kiss/death
+
+/obj/item/projectile/kiss
+ name = "kiss"
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "heart"
+ hitsound = 'sound/effects/kiss.ogg'
+ hitsound_wall = 'sound/effects/kiss.ogg'
+ pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
+ speed = 1.6
+ damage_type = BRUTE
+ damage = 0
+ nodamage = TRUE // love can't actually hurt you
+ armour_penetration = 100 // but if it could, it would cut through even the thickest plate
+ flag = "magic" // and most importantly, love is magic~
+
+/obj/item/projectile/kiss/fire(angle)
+ if(firer)
+ name = "[name] blown by [firer]"
+ return ..()
+
+/obj/item/projectile/kiss/on_hit(atom/target, blocked, hit_zone)
+ def_zone = BODY_ZONE_HEAD // let's keep it PG, people
+ . = ..()
+
+/obj/item/projectile/kiss/death
+ name = "kiss of death"
+ nodamage = FALSE // okay i kinda lied about love not being able to hurt you
+ damage = 35
+ sharp = TRUE
+ color = COLOR_BLACK
+
+/obj/item/projectile/kiss/death/on_hit(atom/target, blocked, pierce_hit)
+ . = ..()
+ if(!iscarbon(target))
+ return
+ var/mob/living/carbon/heartbreakee = target
+ var/obj/item/organ/internal/heart/dont_go_breakin_my_heart = heartbreakee.get_organ_slot("heart")
+ if(dont_go_breakin_my_heart)
+ dont_go_breakin_my_heart.receive_damage(999)
+ else // You're probably a snowflakey species or Xenomorph
+ heartbreakee.adjustFireLoss(1000) // the sickest of burns
diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm
index 1b1352c372f..ecc485737a4 100644
--- a/code/game/objects/items/weapons/extinguisher.dm
+++ b/code/game/objects/items/weapons/extinguisher.dm
@@ -57,7 +57,7 @@
to_chat(user, "The safety is [safety ? "on" : "off"].")
return
-/obj/item/extinguisher/attack_obj(obj/O, mob/living/user)
+/obj/item/extinguisher/attack_obj(obj/O, mob/living/user, params)
if(AttemptRefill(O, user))
refilling = TRUE
return FALSE
diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm
index c7c776f631d..ee160ed3bcc 100644
--- a/code/modules/mob/living/carbon/alien/special/facehugger.dm
+++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm
@@ -38,7 +38,7 @@
Die()
/obj/item/clothing/mask/facehugger/attackby(obj/item/O, mob/user, params)
- return O.attack_obj(src, user)
+ return O.attack_obj(src, user, params)
/obj/item/clothing/mask/facehugger/attack_alien(mob/user) //can be picked up by aliens
return attack_hand(user)
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index cec48e0a9ea..b8257bb877f 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -123,7 +123,7 @@
on_CD = handle_emote_CD(50) //longer cooldown
if("fart", "farts", "flip", "flips", "snap", "snaps")
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
- if("cough", "coughs", "slap", "slaps", "highfive")
+ if("cough", "coughs", "highfive")
on_CD = handle_emote_CD()
if("gasp", "gasps")
on_CD = handle_emote_CD()
@@ -133,6 +133,8 @@
on_CD = handle_emote_CD()
if("clap", "claps")
on_CD = handle_emote_CD()
+ if("kiss", "kisses", "slap", "slaps")
+ on_CD = handle_emote_CD(3 SECONDS)
//Everything else, including typos of the above emotes
else
on_CD = FALSE //If it doesn't induce the cooldown, we won't check for the cooldown
@@ -502,6 +504,19 @@
message = "[src] nods[M ? " at [M]" : ""]."
m_type = 1
+ if("kiss", "kisses")
+ var/kiss_type = /obj/item/kisser
+
+ if(HAS_TRAIT(src, TRAIT_KISS_OF_DEATH))
+ kiss_type = /obj/item/kisser/death
+
+ var/obj/item/kiss_blower = new kiss_type(src)
+ if(put_in_hands(kiss_blower))
+ to_chat(src, "You ready your kiss-blowing hand.")
+ else
+ qdel(kiss_blower)
+ to_chat(src, "You're incapable of blowing a kiss in your current state.")
+
if("blush", "blushes")
message = "[src] blushes."
m_type = 1
@@ -841,16 +856,12 @@
message = "[src] sadly can't find anybody to give daps to, and daps [p_them()]self. Shameful."
if("slap", "slaps")
- m_type = 1
- if(!restrained())
- var/M = handle_emote_param(param, null, 1)
-
- if(M)
- message = "[src] slaps [M] across the face. Ouch!"
- else
- message = "[src] slaps [p_them()]self!"
- adjustFireLoss(4)
- playsound(loc, 'sound/effects/snap.ogg', 50, 1)
+ var/obj/item/slapper/N = new(src)
+ if(put_in_hands(N))
+ to_chat(src, "You ready your slapping hand.")
+ else
+ qdel(N)
+ to_chat(src, "You're incapable of slapping in your current state.")
if("scream", "screams")
var/M = handle_emote_param(param)
@@ -934,8 +945,8 @@
if("help")
var/emotelist = "aflap(s), airguitar, blink(s), blink(s)_r, blush(es), bow(s)-none/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s), cry, cries, custom, dance, dap(s)-none/mob," \
+ " deathgasp(s), drool(s), eyebrow, fart(s), faint(s), flap(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-none/mob, grin(s), groan(s), grumble(s), grin(s)," \
- + " handshake-mob, hug(s)-none/mob, hem, highfive, johnny, jump, laugh(s), look(s)-none/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-none/mob, scream(s), shake(s)," \
- + " shiver(s), shrug(s), sigh(s), signal(s)-#1-10,slap(s)-none/mob, smile(s),snap(s), sneeze(s), sniff(s), snore(s), stare(s)-none/mob, tremble(s), twitch(es), twitch(es)_s," \
+ + " handshake-mob, hug(s)-none/mob, hem, highfive, johnny, jump, kiss(es), laugh(s), look(s)-none/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-none/mob, scream(s), shake(s)," \
+ + " shiver(s), shrug(s), sigh(s), signal(s)-#1-10, slap(s), smile(s),snap(s), sneeze(s), sniff(s), snore(s), stare(s)-none/mob, tremble(s), twitch(es), twitch(es)_s," \
+ " wave(s), whimper(s), wink(s), yawn(s)"
switch(dna.species.name)
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 01e707063a4..e7aafa88fac 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -830,7 +830,7 @@
..()
shatter()
-/obj/item/light/attack_obj(obj/O, mob/living/user)
+/obj/item/light/attack_obj(obj/O, mob/living/user, params)
..()
shatter()
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 5f1e84b2316..96f89935f6d 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -291,7 +291,7 @@
else
return ..()
-/obj/item/gun/attack_obj(obj/O, mob/user)
+/obj/item/gun/attack_obj(obj/O, mob/user, params)
if(user.a_intent == INTENT_HARM)
if(bayonet)
O.attackby(bayonet, user)
diff --git a/paradise.dme b/paradise.dme
index 062734bc36e..cb57760a665 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -827,6 +827,7 @@
#include "code\game\objects\items\dehy_carp.dm"
#include "code\game\objects\items\documents.dm"
#include "code\game\objects\items\flag.dm"
+#include "code\game\objects\items\hand_item.dm"
#include "code\game\objects\items\latexballoon.dm"
#include "code\game\objects\items\misc.dm"
#include "code\game\objects\items\mixing_bowl.dm"
diff --git a/sound/effects/kiss.ogg b/sound/effects/kiss.ogg
new file mode 100644
index 00000000000..699b13a8de8
Binary files /dev/null and b/sound/effects/kiss.ogg differ
diff --git a/sound/effects/tableslam.ogg b/sound/effects/tableslam.ogg
new file mode 100644
index 00000000000..6d1ba5ce215
Binary files /dev/null and b/sound/effects/tableslam.ogg differ
diff --git a/sound/weapons/slap.ogg b/sound/weapons/slap.ogg
new file mode 100644
index 00000000000..99a9ec788c4
Binary files /dev/null and b/sound/weapons/slap.ogg differ