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
@@ -48,6 +48,17 @@ SUBSYSTEM_DEF(persistence)
var/tram_hits_this_round = 0
var/tram_hits_last_round = 0
/// A json database to data/message_bottles.json
var/datum/json_database/message_bottles_database
/// An index used to create unique ids for the message bottles database
var/message_bottles_index = 0
/**
* A list of non-maploaded photos or papers that met the 0.2% chance to be saved in the message bottles database
* because I don't want the database to feel empty unless there's someone constantly throwing bottles in the
* sea or beach/ocean fishing portals.
*/
var/list/queued_message_bottles
/datum/controller/subsystem/persistence/Initialize()
load_poly()
load_wall_engravings()
@@ -72,11 +83,13 @@ SUBSYSTEM_DEF(persistence)
save_scars()
save_custom_outfits()
save_delamination_counter()
save_queued_message_bottles()
if(SStransport.can_fire)
for(var/datum/transport_controller/linear/tram/transport as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM])
save_tram_history(transport.specific_transport_id)
save_tram_counter()
///Loads up Poly's speech buffer.
/datum/controller/subsystem/persistence/proc/load_poly()
for(var/mob/living/basic/parrot/poly/bird in GLOB.alive_mob_list)
@@ -0,0 +1,54 @@
///This proc is used to save photos, papers and cash stored inside a bottle when tossed into the ocean.
/datum/controller/subsystem/persistence/proc/save_message_bottle(obj/item/message, bottle_type = /obj/item/reagent_containers/cup/glass/bottle)
if(isnull(message_bottles_database))
message_bottles_database = new("data/message_bottles.json")
var/list/data = list()
data["bottle_type"] = text2path(bottle_type)
if(istype(message, /obj/item/paper))
var/obj/item/paper/paper = message
if(!length(paper.raw_text_inputs) && !length(paper.raw_stamp_data) && !length(paper.raw_field_input_data))
return
data["paper"] = paper.convert_to_data()
else if(istype(message, /obj/item/photo))
var/obj/item/photo/photo = message
if(!photo.picture?.id)
return
data["photo_id"] = photo.picture.id
else if(istype(message, /obj/item/stack/spacecash))
var/obj/item/stack/spacecash/cash = message
data["cash"] = text2path(cash.type)
data["amount"] = cash.amount
message_bottles_index++
message_bottles_database.set_key("message-[GLOB.round_id]-[message_bottles_index]", data)
/datum/controller/subsystem/persistence/proc/load_message_bottle(atom/loc)
if(isnull(message_bottles_database))
message_bottles_database = new("data/message_bottles.json")
var/list/data = message_bottles_database.pick_and_take_key()
if(!data)
var/obj/item/reagent_containers/cup/glass/bottle/bottle = new(loc)
return bottle
var/bottle_type = text2path(data["bottle_type"]) || /obj/item/reagent_containers/cup/glass/bottle
var/obj/item/reagent_containers/cup/glass/bottle/bottle = new bottle_type(loc)
bottle.reagents.remove_all(bottle.reagents.maximum_volume)
if(data["photo_id"])
var/obj/item/photo/old/photo = load_photo_from_disk(data["photo_id"], bottle)
bottle.message_in_a_bottle = photo
else if(data["cash"])
var/cash_type = text2path(data["cash"]) || /obj/item/stack/spacecash/c10
var/obj/item/stack/spacecash/cash = new cash_type(bottle, data["amount"])
bottle.message_in_a_bottle = cash
else if(data["paper"])
var/obj/item/paper/paper = new(bottle)
paper.write_from_data(data["paper"])
bottle.message_in_a_bottle = paper
bottle.update_icon(UPDATE_OVERLAYS)
/datum/controller/subsystem/persistence/proc/save_queued_message_bottles()
for(var/item in queued_message_bottles)
save_message_bottle(item)
queued_message_bottles = null