Merge pull request #16072 from SandPoot/mail

Adds mail to cargo
This commit is contained in:
deathride58
2024-04-12 20:42:29 -04:00
committed by GitHub
66 changed files with 1099 additions and 119 deletions
+5
View File
@@ -1,4 +1,9 @@
/// Number of paychecks jobs start with at the creation of a new bank account for a player (So at shift-start or game join, but not a blank new account.)
#define STARTING_PAYCHECKS 5
/// How much mail the Economy SS will create per minute, regardless of firing time.
#define MAX_MAIL_PER_MINUTE 3
/// Probability of using letters of envelope sprites on all letters.
#define FULL_CRATE_LETTER_ODDS 70
#define PAYCHECK_ASSISTANT 25
#define PAYCHECK_MINIMAL 75
+2
View File
@@ -0,0 +1,2 @@
/// From the item_scaling element
#define ITEM_SCALING_TRAIT "item_scaling"
+2
View File
@@ -360,3 +360,5 @@ GLOBAL_LIST_INIT(eye_types, list("normal", "insect", "moth", "double", "double2"
GLOBAL_LIST_INIT(bodypart_names, list(num2text(HEAD) = "Head", num2text(CHEST) = "Chest", num2text(LEG_LEFT) = "Left Leg", num2text(LEG_RIGHT) = "Right Leg", num2text(ARM_LEFT) = "Left Arm", num2text(ARM_RIGHT) = "Right Arm"))
// list linking bodypart names back to the bitflags
GLOBAL_LIST_INIT(bodypart_values, list("Head" = num2text(HEAD), "Chest" = num2text(CHEST), "Left Leg" = num2text(LEG_LEFT), "Right Leg" = num2text(LEG_RIGHT), "Left Arm" = num2text(ARM_LEFT), "Right Arm" = num2text(ARM_RIGHT)))
GLOBAL_LIST_INIT(junkmail_messages, world.file2list("strings/junkmail.txt"))
+10 -1
View File
@@ -55,6 +55,13 @@ SUBSYSTEM_DEF(economy)
var/civ_bounty_tracker = 0
/// Contains the message to send to newscasters about earnings, updated on price_update()
/// Total value of exported materials.
var/export_total = 0
/// Total value of imported goods.
var/import_total = 0
/// Number of mail items generated.
var/mail_waiting = 0
/datum/controller/subsystem/economy/Initialize(timeofday)
var/budget_to_hand_out = round(budget_pool / department_accounts.len)
for(var/A in department_accounts)
@@ -62,6 +69,7 @@ SUBSYSTEM_DEF(economy)
return ..()
/datum/controller/subsystem/economy/fire(resumed = 0)
var/delta_time = wait * 0.2
eng_payout() // Payout based on nothing. What will replace it? Surplus power, powered APC's, air alarms? Who knows.
sci_payout() // Payout based on slimes.
secmedsrv_payout() // Payout based on crew safety, health, and mood.
@@ -70,7 +78,8 @@ SUBSYSTEM_DEF(economy)
for(var/account in bank_accounts)
var/datum/bank_account/bank_account = account
bank_account.payday(1)
var/effective_mailcount = round(living_player_count() / (rand(1, 5) - 0.5)) // fake inflation // (inflation_value - 0.5)) //More mail at low inflation, and vis versa.
mail_waiting += clamp(effective_mailcount, 1, MAX_MAIL_PER_MINUTE * delta_time)
/datum/controller/subsystem/economy/proc/get_dep_account(dep_id)
for(var/datum/bank_account/department/D in generated_accounts)
+108
View File
@@ -0,0 +1,108 @@
/**
* Element for scaling item appearances in the overworld or in inventory/storage.
*
* This bespoke element allows for items to have varying sizes depending on their location.
* The overworld simply refers to items being on a turf. Inventory includes HUD item slots,
* and storage is anywhere a storage component is used.
* Scaling should affect the item's icon and all attached overlays (such as blood decals).
*
*/
/datum/element/item_scaling
element_flags = ELEMENT_BESPOKE
id_arg_index = 2
/// Scaling value when the attached item is in the overworld (on a turf).
var/overworld_scaling
/// Scaling value when the attached item is in a storage component or inventory slot.
var/storage_scaling
/**
* Attach proc for the item_scaling element
*
* The proc checks the target's type before attaching. It then initializes
* the target to overworld scaling. The target should then rescale if it is placed
* in inventory/storage on initialization. Relevant signals are registered to listen
* for pickup/drop or storage events. Scaling values of 1 will result in items
* returning to their original size.
* Arguments:
* * target - Datum to attach the element to.
* * overworld_scaling - Integer or float to scale the item in the overworld.
* * storage_scaling - Integer or float to scale the item in storage/inventory.
*/
/datum/element/item_scaling/Attach(atom/target, overworld_scaling, storage_scaling)
. = ..()
if(!isatom(target))
return ELEMENT_INCOMPATIBLE
// Initial scaling set to overworld_scaling when item is spawned.
scale(target, overworld_scaling)
src.overworld_scaling = overworld_scaling
src.storage_scaling = storage_scaling
// Make sure overlays also inherit the scaling.
ADD_KEEP_TOGETHER(target, ITEM_SCALING_TRAIT)
// When moved sends a signal.
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(scale_by_loc))
/**
* Detach proc for the item_scaling element.
*
* All registered signals are unregistered, and the attached element is removed from the target datum.
* Arguments:
* * target - Datum which the element is attached to.
*/
/datum/element/item_scaling/Detach(atom/target)
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
REMOVE_KEEP_TOGETHER(target, ITEM_SCALING_TRAIT)
return ..()
/**
* Scales the attached item's matrix.
*
* The proc first narrows the type of the source to (datums do not have a transform matrix).
* It then creates an identity matrix, M, which is transformed by the scaling value.
* The object's transform variable (matrix) is then set to the resulting value of M.
* Arguments:
* * source - Source datum which sent the signal.
* * scaling - Integer or float to scale the item's matrix.
*/
/datum/element/item_scaling/proc/scale(datum/source, scaling)
var/atom/scalable_object = source
var/matrix/M = matrix()
scalable_object.transform = M.Scale(scaling)
//Grabs any move signals and checks its loc, properly scaling it when in storage,inhand, or in world.
/datum/element/item_scaling/proc/scale_by_loc(atom/scale)
if(isturf(scale.loc))
scale_overworld(scale)
else
scale_storage(scale)
/**
* Shrinks when inworld
*
* Longer detailed paragraph about the proc
* including any relevant detail
* Arguments:
* * source - Source datum which sent the signal.
*/
/datum/element/item_scaling/proc/scale_overworld(datum/source)
SIGNAL_HANDLER
scale(source, overworld_scaling)
/**
* Enlarges when inhand or in storage.
*
* Longer detailed paragraph about the proc
* including any relevant detail
* Arguments:
* * source - Source datum which sent the signal.
*/
/datum/element/item_scaling/proc/scale_storage(datum/source)
SIGNAL_HANDLER
scale(source, storage_scaling)
+16 -3
View File
@@ -1,20 +1,33 @@
//every quirk in this folder should be coded around being applied on spawn
//these are NOT "mob quirks" like GOTTAGOFAST, but exist as a medium to apply them and other different effects
/datum/quirk
/// The name of the quirk
var/name = "Test Quirk"
/// The description of the quirk
var/desc = "This is a test quirk."
/// What the quirk is worth in preferences, zero = neutral / free
var/value = 0
var/human_only = TRUE
/// Text displayed when this quirk is assigned to a mob (and not transferred)
var/gain_text
/// Text displayed when this quirk is removed from a mob (and not transferred)
var/lose_text
var/medical_record_text //This text will appear on medical records for the trait. Not yet implemented
var/antag_removal_text // Text will be given to the quirk holder if they get an antag that has it blacklisted.
/// This text will appear on medical records for the trait.
var/medical_record_text
/// Text will be given to the quirk holder if they get an antag that has it blacklisted.
var/antag_removal_text
var/mood_quirk = FALSE //if true, this quirk affects mood and is unavailable if moodlets are disabled
var/mob_trait //if applicable, apply and remove this mob trait
/// if applicable, apply and remove this mob trait
var/mob_trait
/// should we immediately call on_spawn or add a timer to trigger
var/on_spawn_immediate = TRUE
/// Reference to the mob currently tied to this quirk datum. Quirks are not singletons.
var/mob/living/quirk_holder
var/processing_quirk = FALSE
/// A lazylist of items people can receive from mail who have this quirk enabled
/// The base weight for the each quirk's mail goodies list to be selected is 5
/// then the item selected is determined by pick(selected_quirk.mail_goodies)
var/list/mail_goodies
/datum/quirk/New(mob/living/quirk_mob, spawn_effects)
if(!quirk_mob || (human_only && !ishuman(quirk_mob)) || quirk_mob.has_quirk(type))
+24
View File
@@ -9,6 +9,12 @@
antag_removal_text = "Your antagonistic nature has removed your blood deficiency."
medical_record_text = "Patient requires regular treatment for blood loss due to low production of blood."
/datum/quirk/blooddeficiency/add()
RegisterSignal(quirk_holder, COMSIG_SPECIES_GAIN, PROC_REF(update_mail))
var/mob/living/carbon/human/human_holder = quirk_holder
update_mail(new_species = human_holder.dna.species)
/datum/quirk/blooddeficiency/on_process()
var/mob/living/carbon/human/H = quirk_holder
if(NOBLOOD in H.dna.species.species_traits) //can't lose blood if your species doesn't have any
@@ -16,6 +22,24 @@
else
quirk_holder.blood_volume -= 0.2
/datum/quirk/blooddeficiency/proc/update_mail(datum/source, datum/species/new_species, datum/species/old_species)
SIGNAL_HANDLER
mail_goodies.Cut()
if(isnull(new_species.exotic_blood)) // && isnull(new_species.exotic_bloodtype)) // We don't really support your blood yet :(
if(NOBLOOD in new_species.inherent_traits)
return
mail_goodies += /obj/item/reagent_containers/blood/OMinus
return
for(var/obj/item/reagent_containers/blood/blood_bag as anything in typesof(/obj/item/reagent_containers/blood))
var/right_blood_type = !isnull(new_species.exotic_bloodtype) && initial(blood_bag.blood_type) == new_species.exotic_bloodtype
// var/right_blood_reagent = !isnull(new_species.exotic_blood) && initial(blood_bag.unique_blood) == new_species.exotic_blood
if(right_blood_type) // || right_blood_reagent)
mail_goodies += blood_bag
/datum/quirk/depression
name = "Depression"
desc = "You sometimes just hate life."
+1 -1
View File
@@ -28,7 +28,7 @@ GLOBAL_VAR_INIT(hsboxspawn, TRUE)
var/static/list/spawn_forbidden = list(
/obj/item/tk_grab, /obj/item/implant, // not implanter, the actual thing that is inside you
/obj/item/assembly, /obj/item/onetankbomb, /obj/item/pda/ai,
/obj/item/smallDelivery, /obj/item/projectile,
/obj/item/small_delivery, /obj/item/projectile,
/obj/item/borg/sight, /obj/item/borg/stun, /obj/item/robot_module)
/datum/hSB/proc/update()
@@ -774,3 +774,31 @@
/obj/item/ammo_casing/shotgun = 8,
/obj/item/ammo_casing/shotgun/incendiary = 10,
)
/// Mail loot spawner. Some sort of random and rare building tool. No alien tech here.
/obj/effect/spawner/lootdrop/space/fancytool/engineonly
loot = list(
/obj/item/wrench/caravan = 1,
/obj/item/wirecutters/caravan = 1,
/obj/item/screwdriver/caravan = 1,
/obj/item/crowbar/red/caravan = 1
)
/// Mail loot spawner. Drop pool of advanced medical tools typically from research. Not endgame content.
/obj/effect/spawner/lootdrop/space/fancytool/advmedicalonly
loot = list(
/obj/item/scalpel/advanced = 1,
/obj/item/retractor/advanced = 1,
/obj/item/surgicaldrill/advanced = 1
)
/// Mail loot spawner. Some sort of random and rare surgical tool. Alien tech found here.
/obj/effect/spawner/lootdrop/space/fancytool/raremedicalonly
loot = list(
/obj/item/scalpel/alien = 1,
/obj/item/hemostat/alien = 1,
/obj/item/retractor/alien = 1,
/obj/item/circular_saw/alien = 1,
/obj/item/surgicaldrill/alien = 1,
/obj/item/cautery/alien = 1
)
+479
View File
@@ -0,0 +1,479 @@
/// Mail is tamper-evident and unresealable, postmarked by CentCom for an individual recepient.
/obj/item/mail
name = "mail"
gender = NEUTER
desc = "An officially postmarked, tamper-evident parcel regulated by CentCom and made of high-quality materials."
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "mail_small"
item_state = "paper"
item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_SMALL
// drop_sound = 'sound/items/handling/paper_drop.ogg'
// pickup_sound = 'sound/items/handling/paper_pickup.ogg'
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
/// Destination tagging for the mail sorter.
var/sort_tag = 0
/// Weak reference to who this mail is for and who can open it.
var/datum/weakref/recipient_ref
/// How many goodies this mail contains.
var/goodie_count = 1
/// Goodies which can be given to anyone. The base weight for cash is 56. For there to be a 50/50 chance of getting a department item, they need 56 weight as well.
var/list/generic_goodies = list(
/obj/item/stack/spacecash/c50 = 10,
/obj/item/stack/spacecash/c100 = 25,
/obj/item/stack/spacecash/c200 = 15,
/obj/item/stack/spacecash/c500 = 5,
/obj/item/stack/spacecash/c1000 = 1,
)
// Overlays (pure fluff)
/// Does the letter have the postmark overlay?
var/postmarked = TRUE
/// Does the letter have a stamp overlay?
var/stamped = TRUE
/// List of all stamp overlays on the letter.
var/list/stamps = list()
/// Maximum number of stamps on the letter.
var/stamp_max = 1
/// Physical offset of stamps on the object. X direction.
var/stamp_offset_x = 0
/// Physical offset of stamps on the object. Y direction.
var/stamp_offset_y = 2
///mail will have the color of the department the recipient is in.
var/static/list/department_colors
/obj/item/mail/envelope
name = "envelope"
icon_state = "mail_large"
goodie_count = 2
stamp_max = 2
stamp_offset_y = 5
/obj/item/mail/Initialize()
. = ..()
RegisterSignal(src, COMSIG_MOVABLE_DISPOSING, PROC_REF(disposal_handling))
AddElement(/datum/element/item_scaling, 0.5, 1)
if(isnull(department_colors))
department_colors = list(
ACCOUNT_CIV = COLOR_WHITE,
ACCOUNT_ENG = COLOR_PALE_ORANGE,
ACCOUNT_SCI = COLOR_PALE_PURPLE_GRAY,
ACCOUNT_MED = COLOR_PALE_BLUE_GRAY,
ACCOUNT_SRV = COLOR_PALE_GREEN_GRAY,
ACCOUNT_CAR = COLOR_BEIGE,
ACCOUNT_SEC = COLOR_PALE_RED_GRAY,
)
// Icons
// Add some random stamps.
if(stamped == TRUE)
var/stamp_count = rand(1, stamp_max)
for(var/i = 1, i <= stamp_count, i++)
stamps += list("stamp_[rand(2, 6)]")
update_icon()
/obj/item/mail/update_overlays()
. = ..()
var/bonus_stamp_offset = 0
for(var/stamp in stamps)
var/image/stamp_image = image(
icon = icon,
icon_state = stamp,
pixel_x = stamp_offset_x,
pixel_y = stamp_offset_y + bonus_stamp_offset
)
stamp_image.appearance_flags |= RESET_COLOR
bonus_stamp_offset -= 5
. += stamp_image
if(postmarked == TRUE)
var/image/postmark_image = image(
icon = icon,
icon_state = "postmark",
pixel_x = stamp_offset_x + rand(-3, 1),
pixel_y = stamp_offset_y + rand(bonus_stamp_offset + 3, 1)
)
postmark_image.appearance_flags |= RESET_COLOR
. += postmark_image
/obj/item/mail/attackby(obj/item/W, mob/user, params)
// Destination tagging
if(istype(W, /obj/item/dest_tagger))
var/obj/item/dest_tagger/destination_tag = W
if(sort_tag != destination_tag.currTag)
var/tag = uppertext(GLOB.TAGGERLOCATIONS[destination_tag.currTag])
to_chat(user, span_notice("*[tag]*"))
sort_tag = destination_tag.currTag
playsound(loc, 'sound/machines/twobeep_high.ogg', vol = 100, vary = TRUE)
/obj/item/mail/multitool_act(mob/living/user, obj/item/tool)
if(user.get_inactive_held_item() == src)
balloon_alert(user, "nothing to disable!")
return TRUE
balloon_alert(user, "hold it!")
return FALSE
/obj/item/mail/attack_self(mob/user)
if(!unwrap(user))
return FALSE
return after_unwrap(user)
/// proc for unwrapping a mail. Goes just for an unwrapping procces, returns FALSE if it fails.
/obj/item/mail/proc/unwrap(mob/user)
if(recipient_ref)
var/datum/mind/recipient = recipient_ref.resolve()
// If the recipient's mind has gone, then anyone can open their mail
// whether a mind can actually be qdel'd is an exercise for the reader
if(recipient && recipient != user?.mind)
to_chat(user, span_notice("You can't open somebody else's mail! That's <em>illegal</em>!"))
return FALSE
balloon_alert(user, "unwrapping...")
if(!do_after(user, 1.5 SECONDS, target = user))
return FALSE
return TRUE
// proc that goes after unwrapping a mail.
/obj/item/mail/proc/after_unwrap(mob/user)
user.temporarilyRemoveItemFromInventory(src, force = TRUE)
for(var/obj/stuff as anything in contents) // Mail and envelope actually can have more than 1 item.
if(isitem(stuff))
user.put_in_hands(stuff)
else
stuff.forceMove(drop_location())
playsound(loc, 'sound/items/poster_ripped.ogg', vol = 50, vary = TRUE)
qdel(src)
return TRUE
/obj/item/mail/examine_more(mob/user)
. = ..()
if(!postmarked)
. += span_info("This mail has no postmarking of any sort...")
else
. += span_notice("<i>You notice the postmarking on the front of the mail...</i>")
var/datum/mind/recipient = recipient_ref.resolve()
if(recipient)
. += span_info("[postmarked ? "Certified NT" : "Uncertified"] mail for [recipient].")
else if(postmarked)
. += span_info("Certified mail for [GLOB.station_name].")
else
. += span_info("This is a dead letter mail with no recipient.")
. += span_info("Distribute by hand or via destination tagger using the certified NT disposal system.")
/// Accepts a mind to initialize goodies for a piece of mail.
/obj/item/mail/proc/initialize_for_recipient(datum/mind/recipient)
name = "[initial(name)] for [recipient.name] ([recipient.assigned_role])"
recipient_ref = WEAKREF(recipient)
var/mob/living/body = recipient.current
var/list/goodies = generic_goodies
var/datum/job/this_job = SSjob.name_occupations[recipient.assigned_role]
var/is_mail_restricted = FALSE // certain roles and jobs (prisoner) do not receive generic gifts
if(this_job)
if(this_job.paycheck_department && department_colors[this_job.paycheck_department])
color = department_colors[this_job.paycheck_department]
var/list/job_goodies = this_job.get_mail_goodies()
is_mail_restricted = this_job.exclusive_mail_goodies
if(LAZYLEN(job_goodies))
if(is_mail_restricted)
goodies = job_goodies
else
goodies += job_goodies
if(!is_mail_restricted)
// the weighted list is 50 (generic items) + 50 (job items)
// every quirk adds 5 to the final weighted list (regardless the number of items or weights in the quirk list)
// 5% is not too high or low so that stacking multiple quirks doesn't tilt the weighted list too much
for(var/datum/quirk/quirk as anything in body.roundstart_quirks)
if(LAZYLEN(quirk.mail_goodies))
var/quirk_goodie = pick(quirk.mail_goodies)
goodies[quirk_goodie] = 5
// A little boost for the special times!
for(var/datum/holiday/holiday as anything in SSevents.holidays)
if(LAZYLEN(holiday.mail_goodies))
var/holiday_goodie = pick(holiday.mail_goodies)
goodies[holiday_goodie] = holiday.mail_goodies[holiday_goodie]
for(var/iterator in 1 to goodie_count)
var/target_good = pickweight(goodies)
var/atom/movable/target_atom = new target_good(src)
body.log_message("received [target_atom.name] in the mail ([target_good])", LOG_GAME)
return TRUE
/// Alternate setup, just complete garbage inside and anyone can open
/obj/item/mail/proc/junk_mail()
var/obj/junk = /obj/item/paper/fluff/junkmail_generic
var/special_name = FALSE
if(prob(25))
special_name = TRUE
junk = pick(list(/obj/item/paper/pamphlet/gateway, /obj/item/paper/pamphlet/violent_video_games, /obj/item/paper/fluff/junkmail_redpill, /obj/effect/decal/cleanable/ash))
var/list/junk_names = list(
/obj/item/paper/pamphlet/gateway = "[initial(name)] for [pick(GLOB.adjectives)] adventurers",
/obj/item/paper/pamphlet/violent_video_games = "[initial(name)] for the truth about the arcade centcom doesn't want to hear",
/obj/item/paper/fluff/junkmail_redpill = "[initial(name)] for those feeling [pick(GLOB.adjectives)] working at Nanotrasen",
/obj/effect/decal/cleanable/ash = "[initial(name)] with INCREDIBLY IMPORTANT ARTIFACT- DELIVER TO SCIENCE DIVISION. HANDLE WITH CARE.",
)
color = pick(department_colors) //eh, who gives a shit.
name = special_name ? junk_names[junk] : "important [initial(name)]"
junk = new junk(src)
return TRUE
/obj/item/mail/proc/disposal_handling(disposal_source, obj/structure/disposalholder/disposal_holder, obj/machinery/disposal/disposal_machine, hasmob)
SIGNAL_HANDLER
if(!hasmob)
disposal_holder.destinationTag = sort_tag
/// Subtype that's always junkmail
/obj/item/mail/junkmail/Initialize()
..()
junk_mail()
/// Crate for mail from CentCom.
/obj/structure/closet/crate/mail
name = "mail crate"
desc = "A certified post crate from CentCom."
icon_state = "mail"
base_icon_state = "mail"
///if it'll show the nt mark on the crate
var/postmarked = TRUE
/obj/structure/closet/crate/mail/update_icon_state()
. = ..()
if(opened)
icon_state = "[base_icon_state]open"
if(locate(/obj/item/mail) in src)
icon_state = base_icon_state
else
icon_state = "[base_icon_state]sealed"
/obj/structure/closet/crate/mail/update_overlays()
. = ..()
if(postmarked)
. += "mail_nt"
/// Fills this mail crate with N pieces of mail, where N is the lower of the amount var passed, and the maximum capacity of this crate. If N is larger than the number of alive human players, the excess will be junkmail.
/obj/structure/closet/crate/mail/proc/populate(amount)
var/mail_count = min(amount, storage_capacity)
// Fills the
var/list/mail_recipients = list()
for(var/mob/living/carbon/human/human in GLOB.player_list)
if(human.stat == DEAD || !human.mind)
continue
// Skip wizards, nuke ops, cyborgs; Centcom does not send them mail
if(!(human.mind.assigned_role in get_all_jobs()))
continue
mail_recipients += human.mind
for(var/i in 1 to mail_count)
var/obj/item/mail/new_mail
if(prob(FULL_CRATE_LETTER_ODDS))
new_mail = new /obj/item/mail(src)
else
new_mail = new /obj/item/mail/envelope(src)
var/datum/mind/recipient = pick_n_take(mail_recipients)
if(recipient)
new_mail.initialize_for_recipient(recipient)
else
new_mail.junk_mail()
update_icon()
/// Crate for mail that automatically depletes the economy subsystem's pending mail counter.
/obj/structure/closet/crate/mail/economy/Initialize(mapload)
. = ..()
populate(SSeconomy.mail_waiting)
SSeconomy.mail_waiting = 0
/// Crate for mail that automatically generates a lot of mail. Usually only normal mail, but on lowpop it may end up just being junk.
/obj/structure/closet/crate/mail/full
name = "brimming mail crate"
desc = "A certified post crate from CentCom. Looks stuffed to the gills."
/obj/structure/closet/crate/mail/full/Initialize(mapload)
. = ..()
populate(INFINITY)
///Used in the mail strike shuttle loan event
/* /obj/structure/closet/crate/mail/full/mail_strike
desc = "A post crate from somewhere else. It has no NT logo on it."
postmarked = FALSE
/obj/structure/closet/crate/mail/full/mail_strike/populate(amount)
var/strike_mail_to_spawn = rand(1, storage_capacity-1)
for(var/i in 1 to strike_mail_to_spawn)
if(prob(95))
new /obj/item/mail/mail_strike(src)
else
new /obj/item/mail/traitor/mail_strike(src)
return ..(storage_capacity - strike_mail_to_spawn) */
/// Opened mail crate
/obj/structure/closet/crate/mail/preopen
opened = TRUE
icon_state = "mailopen"
/// Mailbag.
/obj/item/storage/bag/mail
name = "mail bag"
desc = "A bag for letters, envelopes, and other postage."
icon = 'icons/obj/library.dmi'
icon_state = "bookbag"
item_state = "bookbag"
resistance_flags = FLAMMABLE
/obj/item/storage/bag/mail/ComponentInitialize()
. = ..()
var/datum/component/storage/storage = GetComponent(/datum/component/storage)
storage.max_w_class = WEIGHT_CLASS_NORMAL
storage.max_combined_w_class = 42
storage.max_items = 21
storage.display_numerical_stacking = FALSE
storage.can_hold = list(
/obj/item/mail,
/obj/item/small_delivery,
/obj/item/paper
)
/obj/item/paper/fluff/junkmail_redpill
name = "smudged paper"
icon_state = "scrap"
var/nuclear_option_odds = 0.1
/obj/item/paper/fluff/junkmail_redpill/Initialize()
. = ..()
if(!prob(nuclear_option_odds)) // 1 in 1000 chance of getting 2 random nuke code characters.
info = "<i>You need to escape the simulation. Don't forget the numbers, they help you remember:</i> '[rand(0,9)][rand(0,9)][rand(0,9)]...'"
return
var/code = random_nukecode()
for(var/obj/machinery/nuclearbomb/selfdestruct/self_destruct in GLOB.nuke_list)
self_destruct.r_code = code
message_admins("Through junkmail, the self-destruct code was set to \"[code]\".")
info = "<i>You need to escape the simulation. Don't forget the numbers, they help you remember:</i> '[code[rand(1,5)]][code[rand(1,5)]]...'"
/obj/item/paper/fluff/junkmail_redpill/true //admin letter enabling players to brute force their way through the nuke code if they're so inclined.
nuclear_option_odds = 100
/obj/item/paper/fluff/junkmail_generic
name = "important document"
icon_state = "paper_words"
/obj/item/paper/fluff/junkmail_generic/Initialize()
. = ..()
info = pick(GLOB.junkmail_messages)
/* Maybe some other time
/obj/item/mail/traitor
var/armed = FALSE
var/datum/weakref/made_by_ref
/// Cached information about who made it for logging purposes
var/made_by_cached_name
/// Cached information about who made it for logging purposes
var/made_by_cached_ckey
goodie_count = 0
/obj/item/mail/traitor/envelope
name = "envelope"
icon_state = "mail_large"
stamp_max = 2
stamp_offset_y = 5
/obj/item/mail/traitor/after_unwrap(mob/user)
user.temporarilyRemoveItemFromInventory(src, force = TRUE)
playsound(loc, 'sound/items/poster_ripped.ogg', vol = 50, vary = TRUE)
for(var/obj/item/stuff as anything in contents) // Mail and envelope actually can have more than 1 item.
if(user.put_in_hands(stuff) && armed)
var/whomst = made_by_cached_name ? "[made_by_cached_name] ([made_by_cached_ckey])" : "no one in particular"
log_bomber(user, "opened armed mail made by [whomst], activating", stuff)
INVOKE_ASYNC(stuff, TYPE_PROC_REF(/obj/item, attack_self), user)
qdel(src)
return TRUE
/obj/item/mail/traitor/multitool_act(mob/living/user, obj/item/tool)
if(armed == FALSE || user.get_inactive_held_item() != src)
return ..()
if(IS_WEAKREF_OF(user.mind, made_by_ref))
balloon_alert(user, "disarming trap...")
if(!do_after(user, 2 SECONDS, target = src))
return FALSE
balloon_alert(user, "disarmed")
playsound(src, 'sound/machines/defib_ready.ogg', vol = 100, vary = TRUE)
armed = FALSE
return TRUE
else
balloon_alert(user, "tinkering with something...")
if(!do_after(user, 2 SECONDS, target = src))
after_unwrap(user)
return FALSE
if(prob(50))
balloon_alert(user, "disarmed something...?")
playsound(src, 'sound/machines/defib_ready.ogg', vol = 100, vary = TRUE)
armed = FALSE
return TRUE
else
after_unwrap(user)
return TRUE
///Generic mail used in the mail strike shuttle loan event
/obj/item/mail/mail_strike
name = "dead mail"
desc = "An unmarked parcel of unknown origins, effectively undeliverable."
postmarked = FALSE
generic_goodies = list(
/obj/effect/spawner/random/entertainment/money_medium = 2,
/obj/effect/spawner/random/contraband = 2,
/obj/effect/spawner/random/entertainment/money_large = 1,
/obj/effect/spawner/random/entertainment/coin = 1,
/obj/effect/spawner/random/food_or_drink/any_snack_or_beverage = 1,
/obj/effect/spawner/random/entertainment/drugs = 1,
/obj/effect/spawner/random/contraband/grenades = 1,
)
/obj/item/mail/mail_strike/Initialize(mapload)
if(prob(35))
stamped = FALSE
if(prob(35))
name = "dead envelope"
icon_state = "mail_large"
goodie_count = 2
stamp_max = 2
stamp_offset_y = 5
. = ..()
color = pick(COLOR_SILVER, COLOR_DARK, COLOR_DRIED_TAN, COLOR_ORANGE_BROWN, COLOR_BROWN, COLOR_SYNDIE_RED)
for(var/goodie in 1 to goodie_count)
var/target_good = pick_weight(generic_goodies)
new target_good(src)
///Also found in the mail strike shuttle loan. It contains a random grenade that'll be triggered when unwrapped
/obj/item/mail/traitor/mail_strike
name = "dead mail"
desc = "An unmarked parcel of unknown origins, effectively undeliverable."
postmarked = FALSE
/obj/item/mail/traitor/mail_strike/Initialize(mapload)
if(prob(35))
stamped = FALSE
if(prob(35))
name = "dead envelope"
icon_state = "mail_large"
goodie_count = 2
stamp_max = 2
stamp_offset_y = 5
. = ..()
color = pick(COLOR_SILVER, COLOR_DARK, COLOR_DRIED_TAN, COLOR_ORANGE_BROWN, COLOR_BROWN, COLOR_SYNDIE_RED)
new /obj/effect/spawner/random/contraband/grenades/dangerous(src)
*/
@@ -147,6 +147,9 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \
. = ..()
. += GLOB.uranium_recipes
/obj/item/stack/sheet/mineral/uranium/five
amount = 5
/*
* Plasma
*/
@@ -192,6 +195,12 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \
atmos_spawn_air("plasma=[amount*10];TEMP=[exposed_temperature]")
qdel(src)
/obj/item/stack/sheet/mineral/plasma/five
amount = 5
/obj/item/stack/sheet/mineral/plasma/thirty
amount = 30
/*
* Gold
*/
+4 -4
View File
@@ -49,7 +49,7 @@
/obj/item/stack/packageWrap/suicide_act(mob/living/user)
user.visible_message("<span class='suicide'>[user] begins wrapping [user.p_them()]self in \the [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
if(use(3))
var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(user.loc))
var/obj/structure/big_delivery/P = new /obj/structure/big_delivery(get_turf(user.loc))
P.icon_state = "deliverypackage5"
user.forceMove(P)
P.add_fingerprint(user)
@@ -67,7 +67,7 @@
/obj/item/storage/box/can_be_package_wrapped()
return TRUE
/obj/item/smallDelivery/can_be_package_wrapped()
/obj/item/small_delivery/can_be_package_wrapped()
return FALSE
/obj/item/stack/packageWrap/afterattack(obj/target, mob/user, proximity)
@@ -89,7 +89,7 @@
else if(!isturf(I.loc))
return
if(use(1))
var/obj/item/smallDelivery/P = new /obj/item/smallDelivery(get_turf(I.loc))
var/obj/item/small_delivery/P = new /obj/item/small_delivery(get_turf(I.loc))
if(user.Adjacent(I))
P.add_fingerprint(user)
I.add_fingerprint(user)
@@ -109,7 +109,7 @@
to_chat(user, "<span class='warning'>You can't wrap this!</span>")
return
if(use(3))
var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc))
var/obj/structure/big_delivery/P = new /obj/structure/big_delivery(get_turf(O.loc))
P.icon_state = O.delivery_icon
O.forceMove(P)
P.add_fingerprint(user)
+1 -1
View File
@@ -1464,7 +1464,7 @@
/obj/item/storage/box/shipping/PopulateContents()
var/static/items_inside = list(
/obj/item/destTagger=1,\
/obj/item/dest_tagger=1,\
/obj/item/sales_tagger=1,\
/obj/item/export_scanner=1,\
/obj/item/stack/packageWrap/small=2,\
+1 -1
View File
@@ -6,7 +6,7 @@
k_elasticity = 0
unit_name = "crate"
export_types = list(/obj/structure/closet/crate)
exclude_types = list(/obj/structure/closet/crate/large, /obj/structure/closet/crate/wooden, /obj/structure/closet/crate/bin)
exclude_types = list(/obj/structure/closet/crate/large, /obj/structure/closet/crate/wooden, /obj/structure/closet/crate/bin, /obj/structure/closet/crate/mail)
/datum/export/large/crate/total_printout(datum/export_report/ex, notes = TRUE) // That's why a goddamn metal crate costs that much.
. = ..()
+2 -2
View File
@@ -23,7 +23,7 @@
/obj/item/stack/packageWrap,
/obj/item/stack/packageWrap,
/obj/item/stack/packageWrap,
/obj/item/destTagger,
/obj/item/dest_tagger,
/obj/item/hand_labeler)
crate_type = /obj/structure/closet/crate/wooden
crate_name = "wrapping paper crate"
@@ -35,7 +35,7 @@
contains = list(/obj/item/stamp,
/obj/item/stamp/denied,
/obj/item/export_scanner,
/obj/item/destTagger,
/obj/item/dest_tagger,
/obj/item/hand_labeler,
/obj/item/toner,
/obj/item/toner,
@@ -473,3 +473,17 @@
list_reagents = list(/datum/reagent/consumable/eggyolk = 5)
tastes = list("dried eggs" = 1, "confusion" = 1)
dried_being = /mob/living/simple_animal/chicken
/obj/item/reagent_containers/food/snacks/cube/chicken
name = "chicken cube"
desc = "A new Nanotrasen classic, the chicken cube. Tastes like everything!"
list_reagents = list(/datum/reagent/consumable/eggyolk = 30, /datum/reagent/medicine/strange_reagent = 1)
tastes = list("chicken" = 1, "the country" = 1, "chicken bouillon" = 1)
dried_being = /mob/living/simple_animal/chicken
/obj/item/reagent_containers/food/snacks/cube/bee
name = "bee cube"
desc = "We were sure it was a good idea. Just add water."
list_reagents = list(/datum/reagent/consumable/honey = 10, /datum/reagent/toxin = 5, /datum/reagent/medicine/strange_reagent = 1)
tastes = list("buzzing" = 1, "honey" = 1, "regret" = 1)
dried_being = /mob/living/simple_animal/hostile/poison/bees
+8
View File
@@ -12,6 +12,9 @@
var/year_offset = 0
var/obj/item/drone_hat //If this is defined, drones without a default hat will spawn with this one during the holiday; check drones_as_items.dm to see this used
// Special things to be given during this!
var/list/mail_goodies
// This proc gets run before the game starts when the holiday is activated. Do festive shit here.
/datum/holiday/proc/celebrate()
return
@@ -398,6 +401,11 @@
end_day = 2
end_month = NOVEMBER
mail_goodies = list(
/obj/item/reagent_containers/food/snacks/lollipop = 10,
/obj/item/reagent_containers/food/snacks/chocolatebar = 10
)
/datum/holiday/halloween/greet()
return "Have a spooky Halloween!"
+12
View File
@@ -76,6 +76,14 @@
var/bounty_types = CIV_JOB_BASIC
/// Goodies that can be received via the mail system.
// this is a weighted list.
/// Keep the _job definition for this empty and use /obj/item/mail to define general gifts.
var/list/mail_goodies = list()
/// If this job's mail goodies compete with generic goodies.
var/exclusive_mail_goodies = FALSE
//If a job complies with dresscodes, loadout items will not be equipped instead of the job's outfit, instead placing the items into the player's backpack.
var/dresscodecompliant = TRUE
// How much threat this job is worth in dynamic. Is subtracted if the player's not an antag, added if they are.
@@ -396,3 +404,7 @@
/datum/job/proc/after_latejoin_spawn(mob/living/spawning)
SHOULD_CALL_PARENT(TRUE)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_JOB_AFTER_LATEJOIN_SPAWN, src, spawning)
/// An overridable getter for more dynamic goodies.
/datum/job/proc/get_mail_goodies(mob/recipient)
return mail_goodies
+10 -1
View File
@@ -20,11 +20,20 @@ Assistant
dresscodecompliant = FALSE
always_can_respawn_as = TRUE
threat = 0.2
family_heirlooms = list(
/obj/item/clothing/gloves/cut/family
)
mail_goodies = list(
/obj/item/storage/box/donkpockets = 10,
/obj/item/clothing/mask/gas = 10,
/obj/item/clothing/gloves/color/fyellow = 7,
/obj/item/choice_beacon/music = 5,
/obj/item/toy/sprayoncan = 3,
/obj/item/crowbar/large = 1
)
/datum/job/assistant/get_access()
if(CONFIG_GET(flag/assistants_have_maint_access) || !CONFIG_GET(flag/jobs_have_minimal_access)) //Config has assistant maint access set
. = ..()
+8 -1
View File
@@ -20,13 +20,20 @@
bounty_types = CIV_JOB_DRINK
display_order = JOB_DISPLAY_ORDER_BARTENDER
threat = 0.5
family_heirlooms = list(
/obj/item/reagent_containers/rag,
/obj/item/clothing/head/that,
/obj/item/reagent_containers/food/drinks/shaker
)
mail_goodies = list(
/obj/item/storage/box/rubbershot = 30,
/datum/reagent/consumable/clownstears = 10,
/obj/item/stack/sheet/mineral/plasma = 10,
/obj/item/stack/sheet/mineral/uranium = 10,
)
/datum/outfit/job/bartender
name = "Bartender"
jobtype = /datum/job/bartender
+9
View File
@@ -26,6 +26,15 @@
/obj/item/toy/plush/beeplushie,
)
mail_goodies = list(
/datum/reagent/toxin/mutagen = 20,
/datum/reagent/saltpetre = 20,
/datum/reagent/diethylamine = 20,
/obj/item/gun/energy/floragun = 10,
/obj/effect/spawner/lootdrop/seed_vault = 5,// These are strong, rare seeds, so use sparingly.
/obj/item/reagent_containers/food/snacks/cube/bee = 2
)
/datum/outfit/job/botanist
name = "Botanist"
jobtype = /datum/job/hydro
+6
View File
@@ -38,6 +38,12 @@
/obj/item/toy/figure/captain
)
mail_goodies = list(
/obj/item/clothing/mask/cigarette/cigar/havana = 20,
/obj/item/storage/fancy/cigarettes/cigars/havana = 15,
/obj/item/reagent_containers/food/drinks/bottle/champagne = 10
)
/datum/job/captain/get_access()
return get_all_accesses()
@@ -21,11 +21,18 @@
display_order = JOB_DISPLAY_ORDER_CARGO_TECHNICIAN
bounty_types = CIV_JOB_RANDOM
threat = 0.2
family_heirlooms = list(
/obj/item/clipboard
)
mail_goodies = list(
/obj/item/pizzabox = 10,
/obj/item/stack/sheet/mineral/gold = 5,
/obj/item/stack/sheet/mineral/uranium = 4,
/obj/item/stack/sheet/mineral/diamond = 3,
/obj/item/gun/ballistic/shotgun/boltaction = 1
)
/datum/outfit/job/cargo_tech
name = "Cargo Technician"
jobtype = /datum/job/cargo_tech
+8 -1
View File
@@ -19,12 +19,19 @@
display_order = JOB_DISPLAY_ORDER_CHAPLAIN
threat = 0.5
family_heirlooms = list(
/obj/item/toy/windupToolbox,
/obj/item/reagent_containers/food/drinks/bottle/holywater
)
mail_goodies = list(
/obj/item/reagent_containers/food/drinks/bottle/holywater = 30,
/obj/item/toy/plush/awakenedplushie = 10,
/obj/item/grenade/chem_grenade/holy = 5,
/obj/item/toy/plush/narplush = 2,
// /obj/item/toy/plush/ratplush = 1
)
/datum/job/chaplain/after_spawn(mob/living/H, client/C)
. = ..()
+8 -1
View File
@@ -24,12 +24,19 @@
threat = 1.5
starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
family_heirlooms = list(
/obj/item/book/manual/wiki/chemistry,
/obj/item/fermichem/pHbooklet
)
mail_goodies = list(
/datum/reagent/flash_powder = 15,
// /datum/reagent/exotic_stabilizer = 5,
/datum/reagent/toxin/leadacetate = 5,
/obj/item/paper/secretrecipe = 1
)
/datum/outfit/job/chemist
name = "Chemist"
jobtype = /datum/job/chemist
+10 -1
View File
@@ -37,7 +37,7 @@
display_order = JOB_DISPLAY_ORDER_CHIEF_ENGINEER
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/paraplegic, /datum/quirk/insanity)
threat = 2
family_heirlooms = list(
/obj/item/clothing/head/hardhat,
/obj/item/screwdriver/brass/family,
@@ -47,6 +47,15 @@
/obj/item/wirecutters/brass/family
)
mail_goodies = list(
/obj/item/reagent_containers/food/snacks/cracker = 25, //you know. for poly
/obj/item/stack/sheet/mineral/diamond = 15,
/obj/item/stack/sheet/mineral/uranium/five = 15,
/obj/item/stack/sheet/mineral/plasma/five = 15,
/obj/item/stack/sheet/mineral/gold = 15,
/obj/effect/spawner/lootdrop/space/fancytool/engineonly = 3
)
/datum/outfit/job/ce
name = "Chief Engineer"
jobtype = /datum/job/chief_engineer
@@ -35,7 +35,7 @@
threat = 2
starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
family_heirlooms = list(
/obj/item/storage/firstaid/ancient/heirloom,
/obj/item/scalpel,
@@ -45,6 +45,13 @@
/obj/item/cautery
)
mail_goodies = list(
/obj/effect/spawner/lootdrop/organ_spawner = 10,
// /obj/effect/spawner/lootdrop/memeorgans = 8,
/obj/effect/spawner/lootdrop/space/fancytool/advmedicalonly = 4,
/obj/effect/spawner/lootdrop/space/fancytool/raremedicalonly = 1
)
/datum/outfit/job/cmo
name = "Chief Medical Officer"
jobtype = /datum/job/cmo
+9 -1
View File
@@ -21,11 +21,19 @@
display_order = JOB_DISPLAY_ORDER_CLOWN
threat = 0 // honk
family_heirlooms = list(
/obj/item/bikehorn/golden
)
mail_goodies = list(
/obj/item/reagent_containers/food/snacks/grown/banana = 100,
/obj/item/reagent_containers/food/snacks/pie/cream = 50,
/obj/item/clothing/shoes/clown_shoes/combat = 10,
/obj/item/reagent_containers/spray/waterflower/lube = 20, // lube
/obj/item/reagent_containers/spray/waterflower/superlube = 1 // Superlube, good lord.
)
/datum/outfit/job/clown
name = "Clown"
jobtype = /datum/job/clown
+11
View File
@@ -28,6 +28,17 @@
/obj/item/clothing/head/chefhat
)
mail_goodies = list(
/obj/item/storage/box/ingredients/wildcard = 80,
/datum/reagent/consumable/caramel = 20,
/obj/item/reagent_containers/food/condiment/flour = 20,
/obj/item/reagent_containers/food/condiment/rice = 20,
/obj/item/reagent_containers/food/condiment/enzyme = 15,
/obj/item/reagent_containers/food/condiment/soymilk = 15,
/obj/item/kitchen/knife = 4,
/obj/item/kitchen/knife/butcher = 2
)
/datum/outfit/job/cook
name = "Cook"
jobtype = /datum/job/cook
+12 -1
View File
@@ -27,11 +27,22 @@
display_order = JOB_DISPLAY_ORDER_DETECTIVE
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/nonviolent, /datum/quirk/paraplegic, /datum/quirk/monophobia)
threat = 1
family_heirlooms = list(
/obj/item/reagent_containers/food/drinks/flask/det
)
mail_goodies = list(
/obj/item/storage/fancy/cigarettes = 25,
/obj/item/ammo_box/c38 = 25,
/obj/item/ammo_box/c38/dumdum = 5,
/obj/item/ammo_box/c38/hotshot = 5,
/obj/item/ammo_box/c38/iceblox = 5,
/obj/item/ammo_box/c38/match = 5,
/obj/item/ammo_box/c38/trac = 5,
/obj/item/storage/belt/holster/full = 1 // detective/full
)
/datum/outfit/job/detective
name = "Detective"
jobtype = /datum/job/detective
+5 -1
View File
@@ -24,11 +24,15 @@
threat = 1.5
starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
family_heirlooms = list(
/obj/item/clothing/under/shorts/purple
)
mail_goodies = list(
/obj/item/storage/box/monkeycubes = 10
)
/datum/outfit/job/geneticist
name = "Geneticist"
jobtype = /datum/job/geneticist
@@ -39,11 +39,15 @@
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/prosopagnosia, /datum/quirk/insanity)
threat = 2
family_heirlooms = list(
/obj/item/reagent_containers/food/drinks/trophy/silver_cup
)
mail_goodies = list(
/obj/item/card/id/silver = 10,
/obj/item/stack/sheet/bone = 5
)
/datum/outfit/job/hop
name = "Head of Personnel"
@@ -59,3 +63,11 @@
/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced = 1)
chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/hop)
//only pet worth reviving
/datum/job/hop/get_mail_goodies(mob/recipient)
. = ..()
// Strange Reagent if the pet is dead.
for(var/mob/living/simple_animal/pet/dog/corgi/Ian/staff_pet in GLOB.dead_mob_list)
. += list(/datum/reagent/medicine/strange_reagent = 20)
break
+7 -1
View File
@@ -19,7 +19,7 @@
display_order = JOB_DISPLAY_ORDER_JANITOR
threat = 0.2
family_heirlooms = list(
/obj/item/mop,
/obj/item/clothing/suit/caution,
@@ -27,6 +27,12 @@
/obj/item/soap
)
mail_goodies = list(
/obj/item/grenade/chem_grenade/cleaner = 30,
/obj/item/storage/box/lights/mixed = 20,
/obj/item/lightreplacer = 10
)
/datum/outfit/job/janitor
name = "Janitor"
jobtype = /datum/job/janitor
+11 -1
View File
@@ -22,7 +22,7 @@
threat = 0.5
starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
family_heirlooms = list(
/obj/item/storage/firstaid/ancient/heirloom,
/obj/item/scalpel,
@@ -32,6 +32,16 @@
/obj/item/cautery
)
mail_goodies = list(
/obj/item/healthanalyzer/advanced = 15,
/obj/item/scalpel/advanced = 6,
/obj/item/retractor/advanced = 6,
/obj/item/surgicaldrill/advanced = 6,
/datum/reagent/toxin/formaldehyde = 6,
/obj/effect/spawner/lootdrop/organ_spawner = 5,
// /obj/effect/spawner/lootdrop/memeorgans = 1
)
/datum/outfit/job/doctor
name = "Medical Doctor"
jobtype = /datum/job/doctor
+8 -1
View File
@@ -20,11 +20,18 @@
display_order = JOB_DISPLAY_ORDER_MIME
threat = 0
family_heirlooms = list(
/obj/item/reagent_containers/food/snacks/baguette
)
mail_goodies = list(
/obj/item/reagent_containers/food/snacks/baguette = 15,
/obj/item/reagent_containers/food/snacks/store/cheesewheel = 10,
/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing = 10,
// /obj/item/book/mimery = 1,
)
/datum/job/mime/after_spawn(mob/living/carbon/human/H, client/C)
. = ..()
H.apply_pref_name("mime", C)
+10 -1
View File
@@ -23,11 +23,20 @@
threat = 0.5
starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
family_heirlooms = list(
/obj/item/storage/firstaid/ancient/heirloom
)
mail_goodies = list(
/obj/item/reagent_containers/hypospray/medipen = 20,
/obj/item/reagent_containers/hypospray/medipen/oxandrolone = 10,
/obj/item/reagent_containers/hypospray/medipen/salacid = 10,
/obj/item/reagent_containers/hypospray/medipen/salbutamol = 10,
/obj/item/reagent_containers/hypospray/medipen/penacid = 10,
/obj/item/reagent_containers/hypospray/medipen/survival = 5 // survival/luxury
)
/datum/outfit/job/paramedic
name = "Paramedic"
jobtype = /datum/job/paramedic
+6 -1
View File
@@ -13,11 +13,16 @@
plasma_outfit = /datum/outfit/plasmaman/prisoner
display_order = JOB_DISPLAY_ORDER_PRISONER
family_heirlooms = list(
/obj/item/pen/blue
)
exclusive_mail_goodies = TRUE
mail_goodies = list(
/obj/effect/spawner/lootdrop/prison_contraband = 1
)
/datum/job/prisoner/get_latejoin_spawn_point()
return get_roundstart_spawn_point()
+5 -1
View File
@@ -32,12 +32,16 @@
display_order = JOB_DISPLAY_ORDER_QUARTERMASTER
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
threat = 0.5
family_heirlooms = list(
/obj/item/stamp,
/obj/item/stamp/denied
)
mail_goodies = list(
/obj/item/circuitboard/machine/emitter = 3
)
/datum/outfit/job/quartermaster
name = "Quartermaster"
jobtype = /datum/job/qm
@@ -38,11 +38,17 @@
starting_modifiers = list(/datum/skill_modifier/job/level/wiring)
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
threat = 5
family_heirlooms = list(
/obj/item/toy/plush/slimeplushie
)
mail_goodies = list(
/obj/item/storage/box/monkeycubes = 30,
/obj/item/circuitboard/machine/sleeper/party = 3,
/obj/item/borg/upgrade/ai = 2
)
/datum/outfit/job/rd
name = "Research Director"
jobtype = /datum/job/rd
+7 -1
View File
@@ -24,11 +24,17 @@
display_order = JOB_DISPLAY_ORDER_ROBOTICIST
threat = 1
family_heirlooms = list(
/obj/item/toy/figure/borg
)
mail_goodies = list(
/obj/item/storage/box/flashes = 20,
/obj/item/stack/sheet/metal/twenty = 15,
/obj/item/modular_computer/tablet/preset/advanced = 5
)
/datum/outfit/job/roboticist
name = "Roboticist"
jobtype = /datum/job/roboticist
+7 -1
View File
@@ -22,11 +22,17 @@
starting_modifiers = list(/datum/skill_modifier/job/level/wiring/basic)
display_order = JOB_DISPLAY_ORDER_SCIENTIST
threat = 1.2
family_heirlooms = list(
/obj/item/toy/plush/slimeplushie
)
mail_goodies = list(
/obj/item/raw_anomaly_core/random = 10,
// /obj/item/disk/tech_disk/spaceloot = 2,
/obj/item/camera_bug = 1
)
/datum/outfit/job/scientist
name = "Scientist"
jobtype = /datum/job/scientist
@@ -34,6 +34,14 @@
/obj/item/clothing/head/beret/sec
)
mail_goodies = list(
/obj/item/reagent_containers/food/snacks/donut/caramel = 10,
/obj/item/reagent_containers/food/snacks/donut/matcha = 10,
/obj/item/reagent_containers/food/snacks/donut/blumpkin = 5,
// /obj/item/clothing/mask/whistle = 5,
/obj/item/melee/baton/boomerang/loaded = 1
)
/datum/job/officer/get_access()
var/list/L = list()
L |= ..() | check_config_for_sec_maint()
@@ -27,7 +27,7 @@
display_order = JOB_DISPLAY_ORDER_STATION_ENGINEER
threat = 1
family_heirlooms = list(
/obj/item/clothing/head/hardhat,
/obj/item/screwdriver/brass/family,
@@ -37,6 +37,13 @@
/obj/item/wirecutters/brass/family
)
mail_goodies = list(
/obj/item/storage/box/lights/mixed = 20,
/obj/item/lightreplacer = 10,
/obj/item/holosign_creator/engineering = 8,
/obj/item/clothing/head/hardhat/red/upgraded = 1
)
/datum/outfit/job/engineer
name = "Station Engineer"
jobtype = /datum/job/engineer
+9 -1
View File
@@ -25,11 +25,19 @@
threat = 1.5
starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
family_heirlooms = list(
/obj/item/reagent_containers/syringe
)
mail_goodies = list(
/obj/item/reagent_containers/glass/bottle/random_virus = 15,
/obj/item/reagent_containers/glass/bottle/formaldehyde = 10,
/obj/item/reagent_containers/glass/bottle/synaptizine = 10,
/obj/item/stack/sheet/mineral/plasma = 10,
/obj/item/stack/sheet/mineral/uranium = 5
)
/datum/outfit/job/virologist
name = "Virologist"
jobtype = /datum/job/virologist
+9
View File
@@ -34,6 +34,15 @@
/obj/item/book/manual/wiki/security_space_law
)
mail_goodies = list(
/obj/item/storage/fancy/cigarettes = 15,
/obj/item/storage/box/handcuffs = 10,
/obj/item/storage/box/teargas = 10,
/obj/item/storage/box/flashbangs = 10,
/obj/item/storage/box/rubbershot = 10,
/obj/item/storage/box/lethalshot = 5
)
/datum/job/warden/get_access()
var/list/L = list()
L = ..() | check_config_for_sec_maint()
@@ -903,7 +903,7 @@
/obj/item/gripper/mining,
/obj/item/cyborg_clamp,
/obj/item/stack/marker_beacon/cyborg,
/obj/item/destTagger,
/obj/item/dest_tagger,
/obj/item/stack/packageWrap/cyborg,
/obj/item/card/id/miningborg)
emag_modules = list(/obj/item/borg/stun)
@@ -1063,7 +1063,7 @@
/obj/item/stack/sheet/rglass/cyborg,
/obj/item/stack/rods/cyborg,
/obj/item/stack/tile/plasteel/cyborg,
/obj/item/destTagger/borg,
/obj/item/dest_tagger/borg,
/obj/item/stack/cable_coil/cyborg,
/obj/item/pinpointer/syndicate_cyborg,
/obj/item/borg_chameleon,
@@ -1192,7 +1192,7 @@
/obj/item/stack/sheet/rglass/cyborg,
/obj/item/stack/rods/cyborg,
/obj/item/stack/tile/plasteel/cyborg,
/obj/item/destTagger/borg,
/obj/item/dest_tagger/borg,
/obj/item/stack/cable_coil/cyborg,
/obj/item/borg_chameleon,
/obj/item/pinpointer/spider_cyborg)
+1 -1
View File
@@ -51,7 +51,7 @@
return
if(!mod.wearer.Adjacent(target))
return
if(istype(target, /obj/structure/closet) || istype(target, /obj/structure/bigDelivery))
if(istype(target, /obj/structure/closet) || istype(target, /obj/structure/big_delivery))
var/atom/movable/picked_crate = target
if(!check_crate_pickup(picked_crate))
return
+1 -1
View File
@@ -210,7 +210,7 @@
flush = FALSE
/obj/machinery/disposal/proc/newHolderDestination(obj/structure/disposalholder/H)
for(var/obj/item/smallDelivery/O in src)
for(var/obj/item/small_delivery/O in src)
H.tomail = TRUE
return
+8 -14
View File
@@ -41,21 +41,15 @@
// now everything inside the disposal gets put into the holder
// note AM since can contain mobs or objs
for(var/A in D)
var/atom/movable/AM = A
if(AM == src)
var/atom/movable/atom_in_transit = A
if(atom_in_transit == src)
continue
SEND_SIGNAL(AM, COMSIG_MOVABLE_DISPOSING, src, D)
AM.forceMove(src)
if(istype(AM, /obj/structure/bigDelivery) && !hasmob)
var/obj/structure/bigDelivery/T = AM
src.destinationTag = T.sortTag
if(istype(AM, /obj/item/smallDelivery) && !hasmob)
var/obj/item/smallDelivery/T = AM
src.destinationTag = T.sortTag
else if(istype(AM, /mob/living/silicon/robot))
var/obj/item/destTagger/borg/tagger = locate() in AM
if (tagger)
src.destinationTag = tagger.currTag
SEND_SIGNAL(atom_in_transit, COMSIG_MOVABLE_DISPOSING, src, D, hasmob)
atom_in_transit.forceMove(src)
if(iscyborg(atom_in_transit))
var/obj/item/dest_tagger/borg/tagger = locate() in atom_in_transit
if(tagger)
destinationTag = tagger.currTag
// start the movement process
@@ -60,8 +60,8 @@
/obj/structure/disposalpipe/sorting/mail/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/destTagger))
var/obj/item/destTagger/O = I
if(istype(I, /obj/item/dest_tagger))
var/obj/item/dest_tagger/O = I
if(O.currTag)// Tagger has a tag set
if(O.currTag in sortTypes)
+48 -31
View File
@@ -1,4 +1,4 @@
/obj/structure/bigDelivery
/obj/structure/big_delivery
name = "large parcel"
desc = "A large delivery parcel."
icon = 'icons/obj/storage.dmi'
@@ -6,10 +6,14 @@
density = TRUE
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
var/giftwrapped = FALSE
var/sortTag = 0
var/sort_tag = 0
var/obj/item/barcode/sticker
/obj/structure/bigDelivery/interact(mob/user)
/obj/structure/big_delivery/Initialize()
. = ..()
RegisterSignal(src, COMSIG_MOVABLE_DISPOSING, PROC_REF(disposal_handling))
/obj/structure/big_delivery/interact(mob/user)
to_chat(user, "<span class='notice'>You start to unwrap the package...</span>")
if(!do_after(user, 15, target = user))
return
@@ -18,29 +22,29 @@
unwrap_contents()
qdel(src)
/obj/structure/bigDelivery/Destroy()
/obj/structure/big_delivery/Destroy()
var/turf/T = get_turf(src)
for(var/atom/movable/AM in contents)
AM.forceMove(T)
return ..()
/obj/structure/bigDelivery/examine(mob/user)
/obj/structure/big_delivery/examine(mob/user)
. = ..()
if(sticker)
. += "There's a barcode attached to the side."
/obj/structure/bigDelivery/contents_explosion(severity, target, origin)
/obj/structure/big_delivery/contents_explosion(severity, target, origin)
for(var/atom/movable/AM in contents)
AM.ex_act(severity, target, origin)
/obj/structure/bigDelivery/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/destTagger))
var/obj/item/destTagger/O = W
/obj/structure/big_delivery/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/dest_tagger))
var/obj/item/dest_tagger/O = W
if(sortTag != O.currTag)
if(sort_tag != O.currTag)
var/tag = uppertext(GLOB.TAGGERLOCATIONS[O.currTag])
to_chat(user, "<span class='notice'>*[tag]*</span>")
sortTag = O.currTag
sort_tag = O.currTag
playsound(loc, 'sound/machines/twobeep.ogg', 100, 1)
else if(istype(W, /obj/item/pen))
@@ -108,7 +112,7 @@
else
return ..()
/obj/structure/bigDelivery/relay_container_resist(mob/living/user, obj/O)
/obj/structure/big_delivery/relay_container_resist(mob/living/user, obj/O)
if(ismovable(loc))
var/atom/movable/AM = loc //can't unwrap the wrapped container if it's inside something.
AM.relay_container_resist(user, O)
@@ -127,26 +131,35 @@
if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded.
to_chat(user, "<span class='warning'>You fail to remove [O]'s wrapping!</span>")
/obj/structure/bigDelivery/proc/unwrap_contents()
/obj/structure/big_delivery/proc/unwrap_contents()
if(!sticker)
return
for(var/obj/I in src.GetAllContents())
SEND_SIGNAL(I, COMSIG_STRUCTURE_UNWRAPPED)
/obj/item/smallDelivery
/obj/structure/big_delivery/proc/disposal_handling(disposal_source, obj/structure/disposalholder/disposal_holder, obj/machinery/disposal/disposal_machine, hasmob)
SIGNAL_HANDLER
if(!hasmob)
disposal_holder.destinationTag = sort_tag
/obj/item/small_delivery
name = "parcel"
desc = "A brown paper delivery parcel."
icon = 'icons/obj/storage.dmi'
icon_state = "deliverypackage3"
var/giftwrapped = 0
var/sortTag = 0
var/sort_tag = 0
var/obj/item/barcode/sticker
/obj/item/smallDelivery/contents_explosion(severity, target, origin)
/obj/item/small_delivery/Initialize()
. = ..()
RegisterSignal(src, COMSIG_MOVABLE_DISPOSING, PROC_REF(disposal_handling))
/obj/item/small_delivery/contents_explosion(severity, target, origin)
for(var/atom/movable/AM in contents)
AM.ex_act(severity, target, origin)
/obj/item/smallDelivery/attack_self(mob/user)
/obj/item/small_delivery/attack_self(mob/user)
to_chat(user, "<span class='notice'>You start to unwrap the package...</span>")
if(!do_after(user, 15, target = user))
return
@@ -159,7 +172,7 @@
new /obj/effect/decal/cleanable/wrapping(get_turf(user))
qdel(src)
/obj/item/smallDelivery/attack_self_tk(mob/user)
/obj/item/small_delivery/attack_self_tk(mob/user)
if(ismob(loc))
var/mob/M = loc
M.temporarilyRemoveItemFromInventory(src, TRUE)
@@ -175,14 +188,14 @@
unwrap_contents()
qdel(src)
/obj/item/smallDelivery/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/destTagger))
var/obj/item/destTagger/O = W
/obj/item/small_delivery/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/dest_tagger))
var/obj/item/dest_tagger/O = W
if(sortTag != O.currTag)
if(sort_tag != O.currTag)
var/tag = uppertext(GLOB.TAGGERLOCATIONS[O.currTag])
to_chat(user, "<span class='notice'>*[tag]*</span>")
sortTag = O.currTag
sort_tag = O.currTag
playsound(loc, 'sound/machines/twobeep.ogg', 100, 1)
else if(istype(W, /obj/item/pen))
@@ -249,19 +262,23 @@
overlaystring = copytext_char(overlaystring, 5) //5 == length("gift") + 1
add_overlay(overlaystring)
/obj/item/smallDelivery/proc/unwrap_contents()
/obj/item/small_delivery/proc/unwrap_contents()
if(!sticker)
return
for(var/obj/I in src.GetAllContents())
SEND_SIGNAL(I, COMSIG_ITEM_UNWRAPPED)
/obj/item/smallDelivery/examine(mob/user)
/obj/item/small_delivery/examine(mob/user)
. = ..()
if(sticker)
. += "There's a barcode attached to the side."
/obj/item/small_delivery/proc/disposal_handling(disposal_source, obj/structure/disposalholder/disposal_holder, obj/machinery/disposal/disposal_machine, hasmob)
SIGNAL_HANDLER
if(!hasmob)
disposal_holder.destinationTag = sort_tag
/obj/item/destTagger
/obj/item/dest_tagger
name = "destination tagger"
desc = "Used to set the destination of properly wrapped packages."
icon = 'icons/obj/device.dmi'
@@ -275,11 +292,11 @@
flags_1 = CONDUCT_1
slot_flags = ITEM_SLOT_BELT
/obj/item/destTagger/borg
/obj/item/dest_tagger/borg
name = "cyborg destination tagger"
desc = "Used to fool the disposal mail network into thinking that you're a harmless parcel. Does actually work as a regular destination tagger as well."
/obj/item/destTagger/suicide_act(mob/living/user)
/obj/item/dest_tagger/suicide_act(mob/living/user)
user.visible_message("<span class='suicide'>[user] begins tagging [user.p_their()] final destination! It looks like [user.p_theyre()] trying to commit suicide!</span>")
if (islizard(user))
to_chat(user, "<span class='notice'>*HELL*</span>")//lizard nerf
@@ -288,7 +305,7 @@
playsound(src, 'sound/machines/twobeep.ogg', 100, 1)
return BRUTELOSS
/obj/item/destTagger/proc/openwindow(mob/user)
/obj/item/dest_tagger/proc/openwindow(mob/user)
var/dat = "<tt><center><h1><b>TagMaster 2.2</b></h1></center>"
dat += "<table style='width:100%; padding:4px;'><tr>"
@@ -303,12 +320,12 @@
user << browse(dat, "window=destTagScreen;size=450x350")
onclose(user, "destTagScreen")
/obj/item/destTagger/attack_self(mob/user)
/obj/item/dest_tagger/attack_self(mob/user)
if(!locked_destination)
openwindow(user)
return
/obj/item/destTagger/Topic(href, href_list)
/obj/item/dest_tagger/Topic(href, href_list)
add_fingerprint(usr)
if(href_list["nextTag"])
var/n = text2num(href_list["nextTag"])
@@ -56,7 +56,7 @@
id = "desttagger"
build_type = AUTOLATHE | PROTOLATHE
materials = list(/datum/material/iron = 250, /datum/material/glass = 125)
build_path = /obj/item/destTagger
build_path = /obj/item/dest_tagger
category = list("initial", "Electronics")
/datum/design/handlabeler
+26
View File
@@ -27,6 +27,9 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
/obj/machinery/syndicatebomb,
/obj/item/hilbertshotel,
/obj/machinery/launchpad,
/obj/machinery/disposal,
/obj/structure/disposalpipe,
/obj/item/mail,
/obj/item/hilbertshotel,
/obj/machinery/camera,
/obj/item/gps,
@@ -102,6 +105,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
/obj/docking_port/mobile/supply/initiate_docking()
if(getDockedId() == "supply_away") // Buy when we leave home.
buy()
create_mail()
. = ..() // Fly/enter transit.
if(. != DOCKING_SUCCESS)
return
@@ -236,6 +240,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
SO.generateCombo(miscboxes[I], I, misc_contents[I])
qdel(SO)
SSeconomy.import_total += value
var/datum/bank_account/cargo_budget = SSeconomy.get_dep_account(ACCOUNT_CAR)
investigate_log("[purchases] orders in this shipment, worth [value] credits. [cargo_budget.account_balance] credits left.", INVESTIGATE_CARGO)
@@ -286,8 +291,29 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
D.adjust_money(gain)
msg = copytext_char(msg, 1, MAX_MESSAGE_LEN)
SSeconomy.export_total += (D.account_balance - presale_points)
SSshuttle.centcom_message = msg
investigate_log("Shuttle contents sold for [D.account_balance - presale_points] credits. Contents: [ex.exported_atoms ? ex.exported_atoms.Join(",") + "." : "none."] Message: [SSshuttle.centcom_message || "none."]", INVESTIGATE_CARGO)
/*
Generates a box of mail depending on our exports and imports.
Applied in the cargo shuttle sending/arriving, by building the crate if the round is ready to introduce mail based on the economy subsystem.
Then, fills the mail crate with mail, by picking applicable crew who can recieve mail at the time to sending.
*/
/obj/docking_port/mobile/supply/proc/create_mail()
//Early return if there's no mail waiting to prevent taking up a slot.
if(!SSeconomy.mail_waiting)
return
//spawn crate
var/list/empty_turfs = list()
for(var/area/shuttle/shuttle_area as anything in shuttle_areas)
for(var/turf/open/floor/shuttle_floor in shuttle_area)
if(is_blocked_turf(shuttle_floor))
continue
empty_turfs += shuttle_floor
new /obj/structure/closet/crate/mail/economy(pick(empty_turfs))
#undef GOODY_FREE_SHIPPING_MAX
#undef CRATE_TAX
+18 -10
View File
@@ -144,16 +144,24 @@
icon_state = "cargodrobe"
product_ads = "Upgraded Assistant Style! Pick yours today!;These shorts are comfy and easy to wear, get yours now!"
vend_reply = "Thank you for using the CargoDrobe!"
products = list(/obj/item/clothing/suit/hooded/wintercoat/cargo = 3,
/obj/item/clothing/under/rank/cargo/tech = 5,
/obj/item/clothing/under/rank/cargo/tech/skirt = 5,
/obj/item/clothing/under/rank/cargo/util = 5,
/obj/item/clothing/suit/toggle/labcoat/depjacket/sup = 5,
/obj/item/clothing/under/rank/cargo/tech/long = 5,
/obj/item/clothing/shoes/sneakers/black = 5,
/obj/item/clothing/gloves/fingerless = 5,
/obj/item/clothing/head/soft = 5,
/obj/item/radio/headset/headset_cargo = 3)
products = list(
/obj/item/storage/bag/mail = 3,
/obj/item/clothing/suit/hooded/wintercoat/cargo = 3,
/obj/item/clothing/under/rank/cargo/tech = 3,
/obj/item/clothing/under/rank/cargo/tech/skirt = 3,
/obj/item/clothing/under/rank/cargo/util = 3,
/obj/item/clothing/suit/toggle/labcoat/depjacket/sup = 3,
/obj/item/clothing/under/rank/cargo/tech/long = 3,
/obj/item/clothing/shoes/sneakers/black = 3,
/obj/item/clothing/gloves/fingerless = 3,
/obj/item/clothing/head/soft = 3,
/obj/item/radio/headset/headset_cargo = 3
)
premium = list(
/obj/item/clothing/under/rank/cargo/miner = 3,
/obj/item/clothing/head/mailman = 1,
/obj/item/clothing/under/misc/mailman = 1
)
refill_canister = /obj/item/vending_refill/wardrobe/cargo_wardrobe
payment_department = ACCOUNT_CAR