Add messages (paper, photos, cash) in bottles. (#85703)

## About The Pull Request
This PR adds a new persistent feature: message inside bottles. These are
basically glass bottles with inside a piece of paper, a photo or space
cash (no holocredits, and most bills rarely go over 1000 credits anyway)
from a previous round, which can be fished at the beach, or from the
relative fishing portals.

Each piece of written paper or photo that isn't map-loaded has a roughly
a 0.2% chance to be added to the message bottles database at the end of
the round. However, you can also manually toss a glass bottle with
inside a paper/photo/bill into the ocean (or a fishing portal generator
with the ocean/beach module loaded) for guaranteed results.

The bottles are removed from the database once fished up by the by,
unless tossed back into the ocean.

I've also offset a couple bottle sprites that weren't properly aligned
(for the message overlays).

TODO:
- [x] add a couple (20 prob or less) message bottle spawners to the
beach away mission or something.
- [x] add a few sounds for adding and removing the message from the
bottle. (pickup/drop sounds already handle that)
- [x] test it properly.

## Why It's Good For The Game
I think it'd be neat to have a way to send photos, snarky "seek grass"
messages, as well as the occasional financial aid to future players, and
furthermore, another thing to tie fishing to.

## Changelog

🆑
add: You can place papers, photos and cash bills (no holochips) inside
bottles and then toss them into the ocean (or fishing portal gen with
relative settings) with right-click, for others to fish them up on
future rounds.
/🆑
This commit is contained in:
Ghom
2024-08-24 01:31:38 -04:00
committed by GitHub
parent a64780f23d
commit 73081bcff0
28 changed files with 527 additions and 145 deletions
@@ -39,11 +39,93 @@
var/bottle_knockdown_duration = BOTTLE_KNOCKDOWN_DEFAULT_DURATION
tool_behaviour = TOOL_ROLLINGPIN // Used to knock out the Chef.
toolspeed = 1.3 //it's a little awkward to use, but it's a cylinder alright.
/// A contained piece of paper, a photo, or space cash, that we can use as a message or gift to future spessmen.
var/obj/item/message_in_a_bottle
/obj/item/reagent_containers/cup/glass/bottle/Initialize(mapload, vol)
. = ..()
var/static/list/recipes = list(/datum/crafting_recipe/molotov)
AddElement(/datum/element/slapcrafting, recipes)
register_context()
register_item_context()
/obj/item/reagent_containers/cup/glass/bottle/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
if(message_in_a_bottle)
return NONE
if(istype(held_item, /obj/item/paper) || istype(held_item, /obj/item/stack/spacecash) || istype(held_item, /obj/item/photo))
context[SCREENTIP_CONTEXT_LMB] = "Insert message"
return CONTEXTUAL_SCREENTIP_SET
return NONE
/obj/item/reagent_containers/cup/glass/bottle/add_item_context(obj/item/source, list/context, atom/target, mob/living/user)
if(message_in_a_bottle && HAS_TRAIT(target, TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION))
context[SCREENTIP_CONTEXT_RMB] = "Toss message"
return CONTEXTUAL_SCREENTIP_SET
return NONE
/obj/item/reagent_containers/cup/glass/bottle/Exited(atom/movable/gone, atom/newloc)
if(gone == message_in_a_bottle)
message_in_a_bottle = null
if(!QDELETED(src))
update_icon(UPDATE_OVERLAYS)
return ..()
/obj/item/reagent_containers/cup/glass/bottle/CheckParts(list/parts_list)
. = ..()
var/obj/item/reagent_containers/cup/glass/bottle/bottle = locate() in contents
if(bottle.message_in_a_bottle)
message_in_a_bottle = bottle.message_in_a_bottle
bottle.message_in_a_bottle.forceMove(src)
/obj/item/reagent_containers/cup/glass/bottle/examine(mob/user)
. = ..()
if(message_in_a_bottle)
. += span_info("there's \a [message_in_a_bottle] inside it. Break it to take it out, or find a beach or ocean and toss it with [EXAMINE_HINT("right-click")].")
else if(isGlass)
. += span_tinynoticeital("you could place a paper, photo or space cash inside it...")
/obj/item/reagent_containers/cup/glass/bottle/update_overlays()
. = ..()
if(message_in_a_bottle)
var/overlay = add_message_overlay()
if(overlay)
. += overlay
/obj/item/reagent_containers/cup/glass/bottle/interact_with_atom_secondary(atom/target, mob/living/user, list/modifiers)
if(user.combat_mode || !HAS_TRAIT(target, TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION))
return ..()
if(!user.temporarilyRemoveItemFromInventory(src))
balloon_alert(user, "it's stuck to your hand!")
return ITEM_INTERACT_BLOCKING
user.visible_message(span_notice("[user] tosses [src] in [target]"), span_notice("You toss [src] in [target]"), span_notice("you hear a splash."))
SSpersistence.save_message_bottle(message_in_a_bottle, type)
playsound(target, 'sound/effects/bigsplash.ogg', 70)
qdel(src)
return ITEM_INTERACT_SUCCESS
/obj/item/reagent_containers/cup/glass/bottle/item_interaction(mob/living/user, obj/item/item, list/modifiers)
if(!isGlass)
return NONE
if(!istype(item, /obj/item/paper) && !istype(item, /obj/item/stack/spacecash) && !istype(item, /obj/item/photo))
return NONE
if(message_in_a_bottle)
balloon_alert(user, "has a message already!")
return ITEM_INTERACT_BLOCKING
if(!user.transferItemToLoc(item, src))
balloon_alert(user, "it's stuck to your hand!")
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "message inserted")
message_in_a_bottle = item
update_icon(UPDATE_OVERLAYS)
return ITEM_INTERACT_SUCCESS
/obj/item/reagent_containers/cup/glass/bottle/proc/add_message_overlay()
if(istype(message_in_a_bottle, /obj/item/paper))
return "paper_in_bottle"
if(istype(message_in_a_bottle, /obj/item/photo))
return "photo_in_bottle"
if(istype(message_in_a_bottle, /obj/item/stack/spacecash))
return "cash_in_bottle"
/obj/item/reagent_containers/cup/glass/bottle/small
name = "small glass bottle"
@@ -56,14 +138,16 @@
if(bartender_check(target) && ranged)
return
SplashReagents(target, ranged, override_spillable = TRUE)
var/obj/item/broken_bottle/B = new(drop_location())
var/obj/item/broken_bottle/broken = new(drop_location())
if(!ranged && thrower)
thrower.put_in_hands(B)
B.mimic_broken(src, target, break_top)
B.inhand_icon_state = broken_inhand_icon_state
thrower.put_in_hands(broken)
broken.mimic_broken(src, target, break_top)
broken.inhand_icon_state = broken_inhand_icon_state
if(message_in_a_bottle)
message_in_a_bottle.forceMove(drop_location())
qdel(src)
target.Bumped(B)
target.Bumped(broken)
/obj/item/reagent_containers/cup/glass/bottle/try_splash(mob/living/user, atom/target)
@@ -339,6 +423,9 @@
list_reagents = list(/datum/reagent/water/holywater = 100)
drink_type = NONE
/obj/item/reagent_containers/cup/glass/bottle/holywater/add_message_overlay()
return //looks too weird...
/obj/item/reagent_containers/cup/glass/bottle/holywater/hell
desc = "A flask of holy water...it's been sitting in the Necropolis a while though."
icon_state = "unholyflask"
@@ -501,7 +588,6 @@
list_reagents = list(/datum/reagent/consumable/ethanol/sake = 100)
/obj/item/reagent_containers/cup/glass/bottle/sake/Initialize(mapload)
. = ..()
if(prob(10))
name = "Fluffy Tail Sake"
desc += " On the bottle is a picture of a kitsune with nine touchable tails."
@@ -510,6 +596,12 @@
name = "Inubashiri's Home Brew"
desc += " Awoo."
icon_state = "sakebottle_i"
return ..()
/obj/item/reagent_containers/cup/glass/bottle/sake/add_message_overlay()
if(icon_state == "sakebottle_k") //doesn't fit the sprite
return
return ..()
/obj/item/reagent_containers/cup/glass/bottle/fernet
name = "Fernet Bronca"
@@ -530,6 +622,9 @@
icon_state = "curacao_bottle"
list_reagents = list(/datum/reagent/consumable/ethanol/curacao = 100)
/obj/item/reagent_containers/cup/glass/bottle/curacao/add_message_overlay()
return //doesn't fit the sprite
/obj/item/reagent_containers/cup/glass/bottle/navy_rum
name = "Pride of the Union Navy-Strength Rum"
desc = "Ironically named, given it's made in Bermuda."
@@ -574,6 +669,9 @@
///Whether this bottle was a victim of a successful sabrage attempt
var/sabraged = FALSE
/obj/item/reagent_containers/cup/glass/bottle/champagne/add_message_overlay()
return //doesn't stylistically fit the sprite
/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
@@ -733,12 +831,18 @@
icon_state = "hoochbottle"
list_reagents = list(/datum/reagent/consumable/ethanol/hooch = 100)
/obj/item/reagent_containers/cup/glass/bottle/hooch/add_message_overlay()
return //doesn't fit the sprite
/obj/item/reagent_containers/cup/glass/bottle/moonshine
name = "moonshine jug"
desc = "It is said that the ancient Applalacians used these stoneware jugs to capture lightning in a bottle."
icon_state = "moonshinebottle"
list_reagents = list(/datum/reagent/consumable/ethanol/moonshine = 100)
/obj/item/reagent_containers/cup/glass/bottle/moonshine/add_message_overlay()
return //doesn't fit the sprite
/obj/item/reagent_containers/cup/glass/bottle/mushi_kombucha
name = "Solzara Brewing Company Mushi Kombucha"
desc = "Best drunk over ice to savour the mushroomy flavour."
@@ -790,15 +894,15 @@
)
/obj/item/reagent_containers/cup/glass/bottle/molotov/CheckParts(list/parts_list)
..()
var/obj/item/reagent_containers/cup/glass/bottle/B = locate() in contents
if(B)
icon_state = B.icon_state
B.reagents.copy_to(src, 100)
if(istype(B, /obj/item/reagent_containers/cup/glass/bottle/juice))
desc += " You're not sure if making this out of a carton was the brightest idea."
isGlass = FALSE
return
. = ..()
var/obj/item/reagent_containers/cup/glass/bottle/bottle = locate() in contents
if(!bottle)
return
icon_state = bottle.icon_state
bottle.reagents.copy_to(src, 100)
if(istype(bottle, /obj/item/reagent_containers/cup/glass/bottle/juice))
desc += " You're not sure if making this out of a carton was the brightest idea."
isGlass = FALSE
/obj/item/reagent_containers/cup/glass/bottle/molotov/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum, do_splash = FALSE)
..(hit_atom, throwingdatum, do_splash = FALSE)