[MIRROR] Adds Sabrage [MDB IGNORE] (#17548)

Adds Sabrage (#70755)

This PR adds an interaction to champagne bottles that allows the user to
pull off the cork with an edged (for code purposes, sharp) item. The
sharper the item, the better your chance is to pull the stunt off.
Minimum force is 5, which lets you do it with a captain's pen, for
instance. It's slower than just removing the cork by hand, as to
simulate the player removing the foil before taking the swing. Heads of
staff get a +20% chance to succeed due to being officers in some
capacity. A skillchip that can be bought from the Library Play Room
vendor increases the chance by +35%. Failing the stunt will smash the
bottle in your hands, spilling the contents all over you. This will
produce a bottle with the neck broken off, instead of its bottom.

Pulling the stunt off provides a weak mood buff for the user, and a
weaker mood buff for any witnesses. However, if someone else pulls the
sabrage off after you, you will get your success buff removed. Think of
it like pulling any other stunt and challenging someone else to do it,
only for them to succeed as well. Makes you bitter, doesn't it? Failing
the stunt also produces a weak mood debuff to the user.

Co-authored-by: Sealed101 <75863639+Sealed101@users.noreply.github.com>
This commit is contained in:
GoldenAlpharex
2022-11-17 15:36:54 -08:00
committed by GitHub
co-authored by Sealed101
parent 9caf0b2e89
commit 07df01d6b9
9 changed files with 176 additions and 16 deletions
+1
View File
@@ -474,6 +474,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_KNOW_CYBORG_WIRES "know_cyborg_wires"
#define TRAIT_KNOW_ENGI_WIRES "know_engi_wires"
#define TRAIT_ENTRAILS_READER "entrails_reader"
#define TRAIT_SABRAGE_PRO "sabrage_pro"
/// this skillchip trait lets you wash brains in washing machines to heal them
#define TRAIT_BRAINWASHING "brainwashing"
/// Allows chef's to chefs kiss their food, to make them with love
@@ -415,3 +415,8 @@
description = "I ripped their tail right off, what have I done!"
mood_change = -5
timeout = 30 SECONDS
/datum/mood_event/sabrage_fail
description = "Blast it! That stunt didn't go as planned!"
mood_change = -2
timeout = 4 MINUTES
@@ -329,3 +329,13 @@
description = "You are all loved by the Universe. Im not alone, and you arent either."
mood_change = 14
timeout = 10 SECONDS
/datum/mood_event/sabrage_success
description = "I pulled that sabrage stunt off! Feels good to be a show-off."
mood_change = 2
timeout = 4 MINUTES
/datum/mood_event/sabrage_witness
description = "I saw someone pop the cork off a champagne bottle in quite a radical fashion."
mood_change = 1
timeout = 2 MINUTES
+4 -2
View File
@@ -37,8 +37,10 @@
mail_goodies = list(
/obj/item/clothing/mask/cigarette/cigar/havana = 20,
/obj/item/storage/fancy/cigarettes/cigars/havana = 15,
/obj/item/reagent_containers/cup/glass/bottle/champagne = 10,
/obj/item/toy/captainsaid/collector = 20
/obj/item/reagent_containers/cup/glass/bottle/champagne = 5,
/obj/item/reagent_containers/cup/glass/bottle/champagne/cursed = 5,
/obj/item/toy/captainsaid/collector = 20,
/obj/item/skillchip/sabrage = 5,
)
job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE | JOB_BOLD_SELECT_TEXT | JOB_REOPEN_ON_ROUNDSTART_LOSS | JOB_ASSIGN_QUIRKS | JOB_CAN_BE_INTERN
@@ -450,6 +450,16 @@
activate_message = span_notice("You feel that you can recognize special, minute details on ID cards.")
deactivate_message = span_notice("Was there something special about certain IDs?")
/obj/item/skillchip/sabrage
name = "Le S48R4G3 skillchip"
auto_traits = list(TRAIT_SABRAGE_PRO)
skill_name = "Sabrage Proficiency"
skill_description = "Grants the user knowledge of the intricate structure of a champagne bottle's structural weakness at the neck, \
improving their proficiency at being a show-off at officer parties."
skill_icon = "bottle-droplet"
activate_message = span_notice("You feel a new understanding of champagne bottles and methods on how to remove their corks.")
deactivate_message = span_notice("The knowledge of the subtle physics residing inside champagne bottles fades from your mind.")
/obj/item/skillchip/brainwashing
name = "suspicious skillchip"
auto_traits = list(TRAIT_BRAINWASHING)
@@ -17,7 +17,7 @@
if(!.) //if the bottle wasn't caught
smash(hit_atom, throwingdatum?.thrower, TRUE)
/obj/item/reagent_containers/cup/glass/proc/smash(atom/target, mob/thrower, ranged = FALSE)
/obj/item/reagent_containers/cup/glass/proc/smash(atom/target, mob/thrower, ranged = FALSE, break_top = FALSE)
if(!isGlass)
return
if(QDELING(src) || !target) //Invalid loc
@@ -26,7 +26,7 @@
return
SplashReagents(target, ranged, override_spillable = TRUE)
var/obj/item/broken_bottle/B = new (loc)
B.mimic_broken(src, target)
B.mimic_broken(src, target, break_top)
qdel(src)
target.Bumped(B)
@@ -31,14 +31,14 @@
volume = 50
custom_price = PAYCHECK_CREW * 0.9
/obj/item/reagent_containers/cup/glass/bottle/smash(mob/living/target, mob/thrower, ranged = FALSE)
/obj/item/reagent_containers/cup/glass/bottle/smash(mob/living/target, mob/thrower, ranged = FALSE, break_top)
if(bartender_check(target) && ranged)
return
SplashReagents(target, ranged, override_spillable = TRUE)
var/obj/item/broken_bottle/B = new(loc)
var/obj/item/broken_bottle/B = new(drop_location())
if(!ranged && thrower)
thrower.put_in_hands(B)
B.mimic_broken(src, target)
B.mimic_broken(src, target, break_top)
qdel(src)
target.Bumped(B)
@@ -106,6 +106,39 @@
return TRUE
/*
* Proc to make the bottle spill some of its contents out in a froth geyser of varying intensity/height
* Arguments:
* * offset_x = pixel offset by x from where the froth animation will start
* * offset_y = pixel offset by y from where the froth animation will start
* * intensity = how strong the effect is, both visually and in the amount of reagents lost. comes in three flavours
*/
/obj/item/reagent_containers/cup/glass/bottle/proc/make_froth(offset_x, offset_y, intensity)
if(!intensity)
return
if(!reagents.total_volume)
return
var/amount_lost = intensity * 5
reagents.remove_any(amount_lost)
visible_message(span_warning("Some of [name]'s contents are let loose!"))
var/intensity_state = null
switch(intensity)
if(1)
intensity_state = "low"
if(2)
intensity_state = "medium"
if(3)
intensity_state = "high"
///The froth fountain that we are sticking onto the bottle
var/mutable_appearance/froth = mutable_appearance(icon, "froth_bottle_[intensity_state]")
froth.pixel_x = offset_x
froth.pixel_y = offset_y
add_overlay(froth)
addtimer(CALLBACK(src, /atom/proc/cut_overlay, froth), 2 SECONDS)
//Keeping this here for now, I'll ask if I should keep it here.
/obj/item/broken_bottle
name = "broken bottle"
@@ -125,7 +158,10 @@
attack_verb_continuous = list("stabs", "slashes", "attacks")
attack_verb_simple = list("stab", "slash", "attack")
sharpness = SHARP_EDGED
///The mask image for mimicking a broken-off bottom of the bottle
var/static/icon/broken_outline = icon('icons/obj/drinks.dmi', "broken")
///The mask image for mimicking a broken-off neck of the bottle
var/static/icon/flipped_broken_outline = icon('icons/obj/drinks.dmi', "broken-flipped")
/obj/item/broken_bottle/Initialize(mapload)
. = ..()
@@ -137,10 +173,14 @@
/// Mimics the appearance and properties of the passed in bottle.
/// Takes the broken bottle to mimic, and the thing the bottle was broken agaisnt as args
/obj/item/broken_bottle/proc/mimic_broken(obj/item/reagent_containers/cup/glass/to_mimic, atom/target)
/obj/item/broken_bottle/proc/mimic_broken(obj/item/reagent_containers/cup/glass/to_mimic, atom/target, break_top)
icon_state = to_mimic.icon_state
var/icon/drink_icon = new(to_mimic.icon, icon_state)
drink_icon.Blend(broken_outline, ICON_OVERLAY, rand(5), 1)
if(break_top) //if the bottle breaks its top off instead of the bottom
desc = "A bottle with its neck smashed off."
drink_icon.Blend(flipped_broken_outline, ICON_OVERLAY, rand(5), 0)
else
drink_icon.Blend(broken_outline, ICON_OVERLAY, rand(5), 1)
drink_icon.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0))
icon = drink_icon
@@ -473,30 +513,111 @@
reagent_flags = TRANSPARENT
spillable = FALSE
list_reagents = list(/datum/reagent/consumable/ethanol/champagne = 100)
///Used for sabrage; increases the chance of success per 1 force of the attacking sharp item
var/sabrage_success_percentile = 5
///Whether this bottle was a victim of a successful sabrage attempt
var/sabraged = FALSE
/obj/item/reagent_containers/cup/glass/bottle/champagne/cursed
sabrage_success_percentile = 0 //force of the sharp item used to sabrage will not increase success chance
/obj/item/reagent_containers/cup/glass/bottle/champagne/attack_self(mob/user)
if(spillable)
return ..()
balloon_alert(user, "fiddling with cork...")
if(do_after(user, 1 SECONDS, src))
return pop_cork(user)
return pop_cork(user, sabrage = FALSE, froth_severity = pick(0, 1))
/obj/item/reagent_containers/cup/glass/bottle/champagne/attackby(obj/item/attacking_item, mob/living/user, params)
. = ..()
if(spillable)
return
if(attacking_item.sharpness != SHARP_EDGED)
return
if(attacking_item != user.get_active_held_item()) //no TK allowed
to_chat(user, span_userdanger("Such a feat is beyond your skills of telekinesis!"))
return
if(attacking_item.force < 5)
balloon_alert(user, "not strong enough!")
return
playsound(user, 'sound/items/unsheath.ogg', 25, TRUE)
balloon_alert(user, "preparing to swing...")
if(!do_after(user, 2 SECONDS, src)) //takes longer because you are supposed to take the foil off the bottle first
return
///The bonus to success chance that the user gets for being a command role
var/command_bonus = user.mind?.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND ? 20 : 0
///The bonus to success chance that the user gets for having a sabrage skillchip installed/otherwise having the trait through other means
var/skillchip_bonus = HAS_TRAIT(user, TRAIT_SABRAGE_PRO) ? 35 : 0
//calculate success chance. example: captain's sabre - 15 force = 75% chance
var/sabrage_chance = (attacking_item.force * sabrage_success_percentile) + command_bonus + skillchip_bonus
if(prob(sabrage_chance))
///Severity of the resulting froth to pass to make_froth()
var/severity_to_pass
if(sabrage_chance > 100)
severity_to_pass = 0
else
switch(sabrage_chance) //the less likely we were to succeed, the more of the drink will end up wasted in froth
if(1 to 33)
severity_to_pass = 3
if(34 to 66)
severity_to_pass = 2
if(67 to 99)
severity_to_pass = 1
return pop_cork(user, sabrage = TRUE, froth_severity = severity_to_pass)
else //you dun goofed
user.visible_message(
span_danger("[user] fumbles the sabrage and cuts [src] in half, spilling it over themselves!"),
span_danger("You fail your stunt and cut [src] in half, spilling it over you!"),
)
user.add_mood_event("sabrage_fail", /datum/mood_event/sabrage_fail)
return smash(target = user, ranged = FALSE, break_top = TRUE)
/obj/item/reagent_containers/cup/glass/bottle/champagne/update_icon_state()
. = ..()
if(spillable)
icon_state = "[base_icon_state]_popped"
if(sabraged)
icon_state = "[base_icon_state]_sabrage"
else
icon_state = "[base_icon_state]_popped"
else
icon_state = base_icon_state
/obj/item/reagent_containers/cup/glass/bottle/champagne/proc/pop_cork(mob/user)
user.visible_message(span_danger("[user] loosens the cork of [src] causing it to pop out of the bottle with great force."), \
span_nicegreen("You elegantly loosen the cork of [src] causing it to pop out of the bottle with great force."))
/obj/item/reagent_containers/cup/glass/bottle/champagne/proc/pop_cork(mob/living/user, sabrage, froth_severity)
if(!sabrage)
user.visible_message(
span_danger("[user] loosens the cork of [src], causing it to pop out of the bottle with great force."),
span_nicegreen("You elegantly loosen the cork of [src], causing it to pop out of the bottle with great force."),
)
else
sabraged = TRUE
user.visible_message(
span_danger("[user] cleanly slices off the cork of [src], causing it to fly off the bottle with great force."),
span_nicegreen("You elegantly slice the cork off of [src], causing it to fly off the bottle with great force."),
)
for(var/mob/living/carbon/stunt_witness in view(7, user))
stunt_witness.clear_mood_event("sabrage_success")
if(stunt_witness == user)
stunt_witness.add_mood_event("sabrage_success", /datum/mood_event/sabrage_success)
continue
stunt_witness.add_mood_event("sabrage_witness", /datum/mood_event/sabrage_witness)
reagents.flags |= OPENCONTAINER
playsound(src, 'sound/items/champagne_pop.ogg', 70, TRUE)
spillable = TRUE
update_appearance()
var/obj/projectile/bullet/reusable/champagne_cork/popped_cork = new (get_turf(src))
popped_cork.firer = user
make_froth(offset_x = 0, offset_y = sabraged ? 13 : 15, intensity = froth_severity) //the y offset for sabraged is lower because the bottle's lip is smashed
///Type of cork to fire away
var/obj/projectile/bullet/reusable/cork_to_fire = sabraged ? /obj/projectile/bullet/reusable/champagne_cork/sabrage : /obj/projectile/bullet/reusable/champagne_cork
///Our resulting cork projectile
var/obj/projectile/bullet/reusable/champagne_cork/popped_cork = new cork_to_fire (drop_location())
popped_cork.firer = user
popped_cork.fired_from = src
popped_cork.fire(dir2angle(user.dir) + rand(-30, 30))
@@ -516,11 +637,21 @@
knockdown = 2 SECONDS
ammo_type = /obj/item/trash/champagne_cork
/obj/projectile/bullet/reusable/champagne_cork/sabrage
icon_state = "champagne_cork_sabrage"
damage = 12
ricochets_max = 2 //bit heavier
range = 6
ammo_type = /obj/item/trash/champagne_cork/sabrage
/obj/item/trash/champagne_cork
name = "champagne cork"
icon = 'icons/obj/drinks.dmi'
icon_state = "champagne_cork"
/obj/item/trash/champagne_cork/sabrage
icon_state = "champagne_cork_sabrage"
/obj/item/reagent_containers/cup/glass/bottle/blazaam
name = "Ginbad's Blazaam"
desc = "You feel like you should give the bottle a good rub before opening."
+1
View File
@@ -53,6 +53,7 @@
/obj/item/skillchip/basketweaving = 2,
/obj/item/skillchip/bonsai = 2,
/obj/item/skillchip/light_remover = 2,
/obj/item/skillchip/sabrage = 2,
/obj/item/skillchip/useless_adapter = 5,
/obj/item/skillchip/wine_taster = 2,
),
Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 130 KiB