Revises and adds several new bounties for assistants, roboticists, and medical doctors. (#89772)

## About The Pull Request

This pull request makes several balance adjustments to older bounties,
primarily for the roboticist and assistant. Additionally, this adds a
new type of medical doctor bounty as well.

### Bounty Modifications:

**Assistant**: Toolbox bounty
The toolbox bounty now requests 1 toolbox instead of 6. However, the
toolbox bounty now requires a fully packed mechanical toolbox worth of
contents. That means any toolbox, containing a screwdriver, wrench,
welding tool, crowbar, analyzer, and wire cutters. When shipped,
non-toolbox contents are dropped.

Why It's Good For The Game (**WIGFTG**):
This bounty follows bad design principles, being a bounty that can be
solved entirely from a lathe. For any of these cases, we want to either
replace them or recontexualize them into an activity that forces players
to either learn more about the mechanics in and around that area as a
form of played tutorial, give them a toe-dip into the mechanics required
to complete the activity, or perform an activity that makes the station
better for having completed it.

For the toolbox bounty, this goes all in on teaching players about the
full set of toolbox equipment, instead of just needing one printable
item, it takes them through the full autolathe menu and gives them
plausible deniability for getting a full set of tools.

**Assistant:** Potted Plants.
The potted plant bounty now requires 3 potted plants as opposed to 8.
Most stations are going to be completely devoid of potted plants after
collecting 8 of these, where lowering the quantity to 3 allows for a
larger amount of competition for this type of bounty. This also
disallows using plastic potted plants from being used in the bounty as a
trade off, as real potted plants are available through other means.

**WIGFTG**: Removes a lathe-solved bounty, and adjusts the quantity to
compensate for the fact that previously you would loot the entire
station of all of it's potted plants in order to complete this bounty
one time.

**Assistant:** Action Figures -> Toys
Action figures and their general availability widely varies by maps. At
best, you can snag one per office on (I think) delta, and at worse
you'll need to fish them out of arcade machines across the station.
Considering how often new toys are added to the vending machine, this
can be a very raw deal where you might be spending 10s of minutes just
for maybe one or two action figures. Instead, it feels like a wider and
better solution is to just make this touch the whole toys category.

WIGFTG: For the toys bounty, it's far too scarce to complete regularly,
but instead now it gives makes players interact with the arcade machine
wholistically, which in turn requires players to have to play an arcade
machine just enough that they're likely to gains a level in the gamer
skill, and serve as a primer to interact with how skills interact with
the round at large. Granted, it's the gamer skill, so it's not the end
of the world if players are getting skill increases here as opposed to
other skills that may have more of an effect on the round at large.

**Assistant:** Pens.
Fuck this bounty. I have removed it. 

**WIGFTG**:
Allow me to elaborate.
So the pens bounty requires 10 pens. However, it requires specifically
`/obj/item/pen`, no subtypes. `/obj/item/pen` is not printable. It is
not found at quantities that make it easy to specifically complete. You
cannot use red pens. Or fountain pens. Or blue pens. Or Crayons. Just
standard black pens that spawn in your PDA and on paper bins. And you
need 10. There is **A** printable pen, however,
`/obj/item/pen/red/security`, which is however printable from
autolathes, leading many players and myself to think that this is
another easy printable bounty. But EVEN THEN, even if those pens WERE
ACCEPTABLE, having to manually carry 10 tiny objects to complete a
bounty worth not even 200 credits to the bounty holder? This just sucks.
It's Bleem. Get it outta here.


**Robotics**: All current mech bounties (MK 2 Ripley, Clarke, Odysseus,
Gygax, and Durand)
Robotics bounties have been reworked. Now, mecha bounties require that a
new mecha of that type be built, and that a holodiagnostic scan be
completed of the mech. This can be done once-per mech, which will print
out a holodiagnostic sheet onto the floor. This sheet is what is turned
in for the bounty. As a result, the value of these bounties have been
roughly halved. For those looking to collect the rest of the previous
value, all 5 of these mechs can now be sold on the cargo shuttle for the
remaining value of the old bounties.

**WIGFTG**: The biggest hurdle for roboticists when it comes to economy
is twofold: Roboticist need resources far more than most other jobs in
the game. No metal means no cyborgs, or mechs, or cool equipment for
robotics. But, if a roboticist needs credits, they have to trade away a
new mech in exchange for some of the largest credit pool bounties in the
game. If they can't spend those credits, or can't receive anything using
those credits, that's effort wasted.

There's a tremendous amount of uncertainty when it comes to robotics
being able to meaningfully interact with the credit economy as it
currently stands, or being able to leverage the credit economy to solve
any of their issues. If the player really does just want to sell their
mech for credits, this also provides them with a method of doing so that
will still reward them even further if they feel they truly do not need
it. Side note, the cargo loader mech "old bess" has the trait provided
by generating a diagnostic already, preventing them from just scanning
that for an easy minute 1 bounty.

Ultimately, having to sell a mech for credits as opposed to getting to
use it is not *fun*. Getting to get paid for doing your job, and getting
the benefits of something you'll have spend a reasonable amount of time
and the station's resources on is *fun*. It's a better pay off. It's why
we're here.


![image](https://github.com/user-attachments/assets/d372a338-14dc-49a3-8279-4cb379c13c10)


**Medical:** Crew Scan Bounties.
Medical staff are now given the chance to perform routine medical scan
bounties. These require a medical doctor to scan another crew member who
is above 90% health, and then print the reports to submit. Some
stipulations:
* The report cannot be of the bounty holder.
* A scanned crewmate must be scanned above 90% heath. 
* When the report is printed, the target is given a trait for 5 minutes,
`TRAIT_RECENTLY_TREATED`, which disqualifies them being the target of a
submitted medical report. This is to encourage the doctor to check up on
several members of the crew when submitting this bounty.

**WIGFTG**:
Medical bounties are in an awkward place, honestly. They are possible to
become purely printable bounties using either advanced organs, or
through the organ grower. However, both of these outcomes are research
locked, and will require a more through look down the line, don't get me
wrong. In the meantime, this falls squarely under that area of "getting
medical doctor bounties to be more closely aligned with doing what
they're already supposed to be doing".

I also floated the idea of making medical bounties pick a random
crewmate for a check-up as opposed to a few different members of the
crew from anyone. I might follow up on that at a later date, but this PR
was already getting a bit overloaded.


![image](https://github.com/user-attachments/assets/63ab2a4f-1eab-410b-9b37-c9299199191b)


### Some other things tacked on here:
I swear I'll be fast.

The `/obj/item/paper/medical_report` created is a new subtype of paper
as opposed to the old type that was used by health analyzers, which
holds the last scanned mob as a weakref as opposed to just creating a
snowflaked paper as we were doing before.

The bounty pad, when it generates it's list of bounties, now works
slightly differently so that there's no chance of getting a list of
three "random" bounties that are all exactly the same thing, called in a
new proc, `generate_bounty_list()`.

I've added a new debug item, called the `/obj/item/bounty_voucher`. This
item allows you to use it in-hand and it gives the activating player a
new bounty from a list of all possible bounties. This makes my life,
just specifically just me and nobody else, easier when testing bounties.

As mentioned above, the mecha UI required adding a new button to it in
order to create holoscans. It's fairly innocuous if I do say so myself,
but I can make further tweaks if it's an issue.

## Why It's Good For The Game

I've sprinkled a good bit of this in above, but in general, bounties
needed some more TLC to make sure they align with their place as a
tertiary source of making money in the game. I've talked about this
before in some now-ancient design documents, but in summary, there's
three forms of credit sources in the game:

* Primary sources: This is regular payroll, earned by playing the game
when the economy SS fires. In theory, this is how much money you can
spend without needing to think about making a purchase most of the time.
* Secondary sources: This is from sources like tourist bots. Ignore the
design decisions they inhabit, they're gameplay loops that allow you to
make additional credits while still performing the functions of your job
for the station, which in tourist bot's case, is making food and drinks
and serving people, making up for any costs incurred by their presence.
* Tertiary sources: This is bounties. These are activities that exist as
a fallback from the secondary sources, where you may not be performing
the duties of your job in order to get credits, should they be more
critical as a resource than the service you provide to the station as a
result.

...Everyone has been fairly clear that doing bounties is not very good.
If you're playing medical doctor and want a shiny medical doctor thing,
you would hope that the majority of your time is spent still playing
medical doctor, or scientist, or whatever. However, of all the jobs that
have fairly sub-par bounties, the one job that I've heard time and again
that I actually got *right* was surprisingly, security officer. Their
sets of bounties, (Which aren't just looting the locker room mind
you...) between the contraband bounty and the n-spect scanner bounties,
actually encourages players to basically do tasks that are already part
of their job obligations, without needing to run to the nearest lathe or
to _steal 8 boar tusks that drop from the barrens_. The bounties are
basically, "Go on patrol to this area", "look for suspicious items on
the station", etc.

In effect, those are *secondary credit sources*. Which is fantastic! It
gave me the idea to revisit a few of these job bounties to try and make
them a bit less exhausting to have to deal with, and as usual I got a
bit distracted and the scope got a bit too big and now it's march. God
damnit.

But yeah if this goes well, I'd love to see about adjust a few of the
bounty methodologies to be in-line with the changes I've implemented
here. More bounties that encourage players to be doing what they're
already doing, bounties that encourage players to learn more about the
game when it comes to assistant bounties or that encourage them to get a
toe-dip report on mechanics that they may not be introduced to yet, and
get rid of some of the CBT bounties that nobody in their god damn mind
wants to do.

## Changelog

🆑
add: New Medical bounty! Scan crewmates who have been healed or
currently have a clean bill of health, and ship the medical report to
prove that you're not accidently letting them die on your watch. Most of
the time.
balance: Assistant bounties for toolboxes now only require 1, but the
toolbox must be fully stocked like standard mechanical toolboxes.
balance: Potted plant bounties no longer accept plastic plants. They
only require 3 plants now, however.
balance: The action figure bounty now only requires toys instead.
del: Removed the pens bounty.
balance: The robotics mech bounty now requires a diagnostic scan of a
newly completed mech as opposed to sending the whole mech itself.
Diagnostic scans can now be generated by riding in a mech and completing
the action from the UI menu. Mech bounties are worth about half as much.
add: Mechs can be sold on the cargo shuttle for the remaining half of
the value from previous mech bounties.
fix: You can now no longer roll duplicates of the same bounties when
generating a new bounty from the civilian bounty console.
/🆑

---------

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
This commit is contained in:
ArcaneMusic
2025-04-05 16:53:02 +02:00
committed by GitHub
co-authored by MrMelbert
parent da91634d18
commit fbbddbb012
19 changed files with 307 additions and 75 deletions
+6
View File
@@ -25,3 +25,9 @@
MENTAL_UNSTABLE, \
MENTAL_INSANE, \
)
/// The percentage amount of health required for a mob to be considered to be
#define CLEAN_BILL_OF_HEALTH_RATIO 0.9
///Cooldown for being on the recently treated trait for the purposes for bounty submission
#define RECENTLY_HEALED_COOLDOWN 5 MINUTES
+5
View File
@@ -212,6 +212,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_ANTIMAGIC_NO_SELFBLOCK "anti_magic_no_selfblock"
/// This mob recently blocked magic with some form of antimagic
#define TRAIT_RECENTLY_BLOCKED_MAGIC "recently_blocked_magic"
/// This mob was recently treated and scanned by a medical scanner.
#define TRAIT_RECENTLY_TREATED "recently_treated"
/// The user can do things like use magic staffs without penalty
#define TRAIT_MAGICALLY_GIFTED "magically_gifted"
/// This object innately spawns with fantasy variables already applied (the magical component is given to it on initialize), and thus we never want to give it the component again.
@@ -1029,6 +1031,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
///A trait for mechs that were created through the normal construction process, and not spawned by map or other effects.
#define TRAIT_MECHA_CREATED_NORMALLY "trait_mecha_created_normally"
/// Trait to apply to mechs after a diagnostic scan has been created, to prevent you from generating duplicates of a scan on the same machine.
#define TRAIT_MECHA_DIAGNOSTIC_CREATED "trait_mecha_diagnostic_created"
/// Stops a movable from being removed from the mob it's in by the content_barfer component.
#define TRAIT_NOT_BARFABLE "not_barfable"
+3 -1
View File
@@ -461,6 +461,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_RDS_SUPPRESSED" = TRAIT_RDS_SUPPRESSED,
"TRAIT_REAGENT_SCANNER" = TRAIT_REAGENT_SCANNER,
"TRAIT_RECENTLY_BLOCKED_MAGIC" = TRAIT_RECENTLY_BLOCKED_MAGIC,
"TRAIT_RECENTLY_TREATED" = TRAIT_RECENTLY_TREATED,
"TRAIT_REGEN_SHIELD" = TRAIT_REGEN_SHIELD,
"TRAIT_RELAYING_ATTACKER" = TRAIT_RELAYING_ATTACKER,
"TRAIT_REMOTE_TASTING" = TRAIT_REMOTE_TASTING,
@@ -739,7 +740,8 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_OREBOX_FUNCTIONAL" = TRAIT_OREBOX_FUNCTIONAL,
),
/obj/vehicle/sealed/mecha = list(
"TRAIT_MECHA_CREATED_NORMALLY" = TRAIT_MECHA_CREATED_NORMALLY
"TRAIT_MECHA_CREATED_NORMALLY" = TRAIT_MECHA_CREATED_NORMALLY,
"TRAIT_MECHA_DIAGNOSTIC_CREATED" = TRAIT_MECHA_DIAGNOSTIC_CREATED,
),
/turf = list(
"TRAIT_CHASM_STOPPED" = TRAIT_CHASM_STOPPED,
+24 -3
View File
@@ -160,12 +160,33 @@
if(!id_account.account_job)
say("Requesting ID card has no job assignment registered!")
return FALSE
var/list/datum/bounty/crumbs = list(random_bounty(id_account.account_job.bounty_types), // We want to offer 2 bounties from their appropriate job catagories
random_bounty(id_account.account_job.bounty_types), // and 1 guaranteed assistant bounty if the other 2 suck.
random_bounty(CIV_JOB_BASIC))
var/list/datum/bounty/crumbs = generate_bounty_list(id_account.account_job.bounty_types)
COOLDOWN_START(id_account, bounty_timer, (5 MINUTES) - cooldown_reduction)
id_account.bounties = crumbs
/**
* Generates a list of bounties for use with the civilian bounty pad.
* @param bounty_types the define taken from a job for selection of a random_bounty() proc.
* @param bounty_rolls the number of bounties to be selected from.
* @param assistant_failsafe Do we guarentee one assistant bounty per generated list? Used for non-assistant jobs to give an easier alternative to that job's default bounties.
*/
/obj/machinery/computer/piratepad_control/civilian/proc/generate_bounty_list(bounty_types, bounty_rolls = 3, assistant_failsafe = TRUE)
var/list/rolling_list = list()
if(assistant_failsafe)
rolling_list += random_bounty(CIV_JOB_BASIC)
while(bounty_rolls > 1)
var/datum/bounty/potential_bounty = random_bounty(bounty_types)
var/repeats_bool = FALSE
for(var/datum/iterator in rolling_list)
if(iterator.type == potential_bounty.type)
repeats_bool = TRUE
if(repeats_bool)
continue
rolling_list += potential_bounty
bounty_rolls -= 1
return rolling_list
/**
* Proc that assigned a civilian bounty to an ID card, from the list of potential bounties that that bank account currently has available.
* Available choices are assigned during add_bounties, and one is locked in here.
@@ -32,6 +32,8 @@
var/give_wound_treatment_bonus = FALSE
var/last_scan_text
var/scanner_busy = FALSE
/// Weakref to the last mob scanned by a health analyzer. Used to generate official medical reports.
var/datum/weakref/last_healthy_scanned
/obj/item/healthanalyzer/Initialize(mapload)
. = ..()
@@ -97,6 +99,10 @@
switch (scanmode)
if (SCANMODE_HEALTH)
last_scan_text = healthscan(user, M, mode, advanced, tochat = readability_check)
if((M.health / M.maxHealth) > CLEAN_BILL_OF_HEALTH_RATIO)
last_healthy_scanned = WEAKREF(M)
else
last_healthy_scanned = null
if (SCANMODE_WOUND)
if(readability_check)
woundscan(user, M, src)
@@ -423,10 +429,10 @@
return
scanner_busy = TRUE
balloon_alert(user, "printing report...")
addtimer(CALLBACK(src, PROC_REF(print_report)), 2 SECONDS)
addtimer(CALLBACK(src, PROC_REF(print_report), user), 2 SECONDS)
/obj/item/healthanalyzer/proc/print_report(mob/user)
var/obj/item/paper/report_paper = new(get_turf(src))
var/obj/item/paper/medical_report/report_paper = new(get_turf(src))
report_paper.color = "#99ccff"
report_paper.name = "health scan report - [station_time_timestamp()]"
@@ -436,14 +442,41 @@
report_paper.add_raw_text(report_text)
report_paper.update_appearance()
if(ismob(loc))
var/mob/printer = loc
printer.put_in_hands(report_paper)
balloon_alert(printer, "logs cleared")
user.put_in_hands(report_paper)
balloon_alert(user, "logs cleared")
resolve_patient_eligibility(report_paper, user)
report_text = list()
scanner_busy = FALSE
/**
* Checks the mob and the medical report that the scanner is trying to print, checks the traits and statuses of the mob, and then resolves by true or false.
* Applies traits to the patient if the scanning is eligable to turn in for a bounty, with callbacks to remove after a cooldown.
*/
/obj/item/healthanalyzer/proc/resolve_patient_eligibility(obj/item/paper/medical_report/report_paper, mob/scanner)
var/mob/living/patient = last_healthy_scanned?.resolve()
if(!patient)
return FALSE
if(scanner == patient)
return FALSE //You can't just scan yourself.
if(HAS_TRAIT(patient, TRAIT_RECENTLY_TREATED))
return FALSE
report_paper.last_healthy_scanned_mob = last_healthy_scanned
ADD_TRAIT(patient, TRAIT_RECENTLY_TREATED, ANALYZER_TRAIT)
addtimer(TRAIT_CALLBACK_REMOVE(patient, RECENTLY_HEALED_COOLDOWN, ANALYZER_TRAIT), RECENTLY_HEALED_COOLDOWN)
return TRUE
/obj/item/healthanalyzer/proc/clear_treatment(mob/living/target)
if(!target)
return
if(QDELETED(target))
return
REMOVE_TRAIT(target, TRAIT_RECENTLY_TREATED, ANALYZER_TRAIT)
return TRUE
/proc/chemscan(mob/living/user, mob/living/target)
if(user.incapacitated)
return
@@ -719,6 +752,18 @@
scanner.emotion = AID_EMOTION_WARN
playsound(scanner, 'sound/machines/beep/twobeep.ogg', 50, FALSE)
/obj/item/paper/medical_report
color = "#99ccff"
desc = "An official medical bill of health generated by a computerized medical scanner."
/// A reference to a mob's weakref that was last scanned by the medical scanner.
var/datum/weakref/last_healthy_scanned_mob
/obj/item/paper/medical_report/examine(mob/user)
. = ..()
if(last_healthy_scanned_mob)
. += span_notice("This medical report is applicable for medical bounties.")
#undef SCANMODE_HEALTH
#undef SCANMODE_WOUND
#undef SCANMODE_COUNT
+42 -17
View File
@@ -41,11 +41,41 @@
wanted_types = list(/obj/item/spear = TRUE)
/datum/bounty/item/assistant/toolbox
name = "Toolboxes"
description = "There's an absence of robustness at Central Command. Hurry up and ship some toolboxes as a solution."
name = "Stocked Toolbox"
description = "There's an absence of robustness at Central Command. Ship them a fully packed toolbox as a solution, containing a screwdriver, wrench, welding tool, crowbar, analyzer, and wirecutters."
reward = CARGO_CRATE_VALUE * 4
required_count = 6
wanted_types = list(/obj/item/storage/toolbox = TRUE)
/// Typecache of tools that we want to see sorted into a toolbox. Unpacked in New(), verified in applies_to(), and then contents are filtered out in ship().
var/list/static_packing_list = list(
/obj/item/screwdriver = TRUE,
/obj/item/wrench = TRUE,
/obj/item/weldingtool = TRUE,
/obj/item/crowbar = TRUE,
/obj/item/analyzer = TRUE,
/obj/item/wirecutters = TRUE,
)
/datum/bounty/item/assistant/toolbox/New()
. = ..()
static_packing_list = string_assoc_list(zebra_typecacheof(static_packing_list, only_root_path = FALSE))
/datum/bounty/item/assistant/toolbox/applies_to(obj/shipped)
var/list/packing_list = static_packing_list.Copy()
for(var/obj/item_contents as anything in shipped.contents)
if(is_type_in_typecache(item_contents.type, packing_list))
packing_list -= subtypesof(item_contents.type)
packing_list -= item_contents.type
if(!length(packing_list))
return ..()
return FALSE
/datum/bounty/item/assistant/toolbox/ship(obj/shipped)
. = ..()
for(var/obj/object as anything in shipped.contents)
if(!is_type_in_typecache(object.type, static_packing_list))
object.forceMove(shipped.drop_location())
/datum/bounty/item/assistant/statue
name = "Statue"
@@ -133,8 +163,11 @@
name = "Potted Plants"
description = "Central Command is looking to commission a new BirdBoat-class station. You've been ordered to supply the potted plants."
reward = CARGO_CRATE_VALUE * 4
required_count = 8
wanted_types = list(/obj/item/kirbyplants = TRUE)
required_count = 3
wanted_types = list(
/obj/item/kirbyplants = TRUE,
/obj/item/kirbyplants/synthetic = FALSE
)
/datum/bounty/item/assistant/monkey_cubes
name = "Monkey Cubes"
@@ -156,12 +189,12 @@
reward = CARGO_CRATE_VALUE * 6
wanted_types = list(/obj/item/food/meat/slab/corgi = TRUE)
/datum/bounty/item/assistant/action_figures
name = "Action Figures"
description = "The vice president's son saw an ad for action figures on the telescreen and now he won't shut up about them. Ship some to ease his complaints."
/datum/bounty/item/assistant/toys
name = "Arcade Toys"
description = "The vice president's son saw an ad for new toys on the telescreen and now he won't shut up about them. Ship some arcade toys over to ease his complaints."
reward = CARGO_CRATE_VALUE * 8
required_count = 5
wanted_types = list(/obj/item/toy/figure = TRUE)
wanted_types = list(/obj/item/toy = TRUE)
/datum/bounty/item/assistant/paper_bin
name = "Paper Bins"
@@ -177,14 +210,6 @@
required_count = 8
wanted_types = list(/obj/item/toy/crayon = TRUE)
/datum/bounty/item/assistant/pens
name = "Pens"
description = "We are hosting the intergalactic pen balancing competition. We need you to send us some standardized black ballpoint pens."
reward = CARGO_CRATE_VALUE * 4
required_count = 10
include_subtypes = FALSE
wanted_types = list(/obj/item/pen = TRUE)
/datum/bounty/item/assistant/water_tank
name = "Water Tank"
description = "We need more water for our hydroponics bay. Find a water tank and ship it out to us."
+24
View File
@@ -35,3 +35,27 @@
/// If the user can actually get this bounty as a selection.
/datum/bounty/proc/can_get()
return TRUE
/**
* Debug item because it took less time to code this than it did to roll ONE toolbox bounty.
*/
/obj/item/bounty_voucher
name = "bounty voucher"
desc = "A certificate for ONE FREE BOUNTY of your choice! Wow!"
icon = 'icons/obj/service/bureaucracy.dmi'
icon_state = "paperslip_words"
/obj/item/bounty_voucher/attack_self(mob/user, modifiers)
. = ..()
if(!isliving(user))
return
var/mob/living/living_user = user
var/obj/item/card/id/id = living_user.get_idcard()
if(!id?.registered_account)
return
var/choice = tgui_input_list(living_user, "Choose a bounty.", "New Bounty", subtypesof(/datum/bounty))
var/datum/bounty/new_chore = text2path("[choice]")
id.registered_account.civilian_bounty = new new_chore
balloon_alert(user, "new bounty acquired!")
playsound(src, 'sound/effects/coin2.ogg', 30, TRUE)
qdel(src)
-35
View File
@@ -1,35 +0,0 @@
/datum/bounty/item/mech/New()
..()
description = "Upper management has requested one [name] mech be sent as soon as possible. Ship it to receive a large payment."
/datum/bounty/item/mech/ship(obj/shipped)
. = ..()
if(!.)
return
var/obj/vehicle/sealed/mecha/mecha = shipped
mecha.wreckage = null // So the mech doesn't explode.
/datum/bounty/item/mech/ripleymk2
name = "APLU MK-II \"Ripley\""
reward = CARGO_CRATE_VALUE * 26
wanted_types = list(/obj/vehicle/sealed/mecha/ripley/mk2 = TRUE)
/datum/bounty/item/mech/clarke
name = "Clarke"
reward = CARGO_CRATE_VALUE * 32
wanted_types = list(/obj/vehicle/sealed/mecha/clarke = TRUE)
/datum/bounty/item/mech/odysseus
name = "Odysseus"
reward = CARGO_CRATE_VALUE * 22
wanted_types = list(/obj/vehicle/sealed/mecha/odysseus = TRUE)
/datum/bounty/item/mech/gygax
name = "Gygax"
reward = CARGO_CRATE_VALUE * 56
wanted_types = list(/obj/vehicle/sealed/mecha/gygax = TRUE)
/datum/bounty/item/mech/durand
name = "Durand"
reward = CARGO_CRATE_VALUE * 40
wanted_types = list(/obj/vehicle/sealed/mecha/durand = TRUE)
+45
View File
@@ -0,0 +1,45 @@
/datum/bounty/item/mech
wanted_types = list(/obj/item/mecha_diagnostic = TRUE)
/// What mech do we need data of inside this mecha diagnostic?
var/required_data = null
/datum/bounty/item/mech/New()
..()
description = "Upper management has requested holodiagnostic scans of \a [name] mech be sent as soon as possible. A diagnostic holoscan can be generated from inside a new mecha. Ship it to receive a large payment."
/datum/bounty/item/mech/applies_to(obj/shipped)
. = ..()
if(istype(shipped, /obj/vehicle/sealed/mecha))
shipped.balloon_alert_to_viewers("make diagnostic from inside!")
var/obj/item/mecha_diagnostic/diagnostic_sheet = shipped
if(!diagnostic_sheet.mech_data)
CRASH("Diagnostic sheet submitted with no mech data contained!")
if(istype(diagnostic_sheet.mech_data, required_data))
return TRUE
return FALSE
/datum/bounty/item/mech/ripleymk2
name = "APLU MK-II \"Ripley\""
reward = CARGO_CRATE_VALUE * 6.5
required_data = /obj/vehicle/sealed/mecha/ripley/mk2
/datum/bounty/item/mech/clarke
name = "Clarke"
reward = CARGO_CRATE_VALUE * 12
required_data = /obj/vehicle/sealed/mecha/clarke
/datum/bounty/item/mech/odysseus
name = "Odysseus"
reward = CARGO_CRATE_VALUE * 5.5
required_data = /obj/vehicle/sealed/mecha/odysseus
/datum/bounty/item/mech/gygax
name = "Gygax"
reward = CARGO_CRATE_VALUE * 28
required_data = /obj/vehicle/sealed/mecha/gygax
/datum/bounty/item/mech/durand
name = "Durand"
reward = CARGO_CRATE_VALUE * 20
required_data = /obj/vehicle/sealed/mecha/durand
+20
View File
@@ -104,3 +104,23 @@
description = "After a recent influx of infected crew members, we've seen that masks just aren't cutting it alone. Silver operating tables might just do the trick though, send us one to use."
reward = CARGO_CRATE_VALUE * 6
wanted_types = list(/obj/structure/table/optable = TRUE)
/datum/bounty/item/medical/scanning
name = "Crew Medical Scanning"
description = "Conduct a routine medical scan using any health analyzer of a crew member with with a near perfect bill of health or better to ensure the crew is taking their medical care seriously. Then, print the medical report and ship it back to us."
reward = CARGO_CRATE_VALUE * 8
required_count = 2
wanted_types = list(/obj/item/paper/medical_report = TRUE)
/datum/bounty/item/medical/scanning/applies_to(obj/shipped)
. = ..()
if(!istype(shipped, /obj/item/paper/medical_report))
return FALSE
var/obj/item/paper/medical_report/report = shipped
if(!report)
return FALSE
var/mob/living/patient = report.last_healthy_scanned_mob?.resolve()
if(patient)
return TRUE
return FALSE
+6 -6
View File
@@ -19,26 +19,26 @@
D.adjust_money(reward * SSeconomy.bounty_modifier)
claimed = TRUE
/// If an item sent in the cargo shuttle can satisfy the bounty.
/// If an item in question can satisfy the bounty.
/datum/bounty/proc/applies_to(obj/O)
return FALSE
/// Called when an object is shipped on the cargo shuttle.
/// Called when an object is sent on the bounty pad.
/datum/bounty/proc/ship(obj/O)
return
/** Returns a new bounty of random type, but does not add it to GLOB.bounties_list.
*
* *Guided determines what specific catagory of bounty should be chosen.
* * Category determines what specific catagory of bounty should be chosen.
*/
/proc/random_bounty(guided = 0)
/proc/random_bounty(category = 0)
var/bounty_num
var/chosen_type
var/bounty_succeeded = FALSE
var/datum/bounty/item/bounty_ref
while(!bounty_succeeded)
if(guided && (guided != CIV_JOB_RANDOM))
bounty_num = guided
if(category && (category != CIV_JOB_RANDOM))
bounty_num = category
else
bounty_num = rand(1, MAXIMUM_BOUNTY_JOBS)
switch(bounty_num)
+24
View File
@@ -0,0 +1,24 @@
/datum/export/mecha/ripley
cost = CARGO_CRATE_VALUE * 13
unit_name = "APLU MK-II Ripley"
export_types = list(/obj/vehicle/sealed/mecha/ripley/mk2)
/datum/export/mecha/clarke
cost = CARGO_CRATE_VALUE * 16
unit_name = "Clarke"
export_types = list(/obj/vehicle/sealed/mecha/clarke)
/datum/export/mecha/odysseus
cost = CARGO_CRATE_VALUE * 11
unit_name = "Odysseus"
export_types = list(/obj/vehicle/sealed/mecha/odysseus)
/datum/export/mecha/gygax
cost = CARGO_CRATE_VALUE * 28
unit_name = "Gygax"
export_types = list(/obj/vehicle/sealed/mecha/gygax)
/datum/export/mecha/durand
cost = CARGO_CRATE_VALUE * 20
unit_name = "Durand"
export_types = list(/obj/vehicle/sealed/mecha/durand)
@@ -0,0 +1,26 @@
/obj/item/mecha_diagnostic
name = "mecha holodiagnostic"
desc = "A holographic datasheet of unique data related to the mecha's construction and any production differences between the published designs to increment improvements."
icon = 'icons/obj/devices/scanner.dmi'
icon_state = "holosheet"
w_class = WEIGHT_CLASS_SMALL
layer = ABOVE_MOB_LAYER
light_system = OVERLAY_LIGHT
light_range = 1
light_power = 2
light_color = "#79aeeb"
/// What mech was this diagnostic sheet generated from? Used for applicability in bounties.
var/obj/vehicle/sealed/mecha/mech_data
/obj/item/mecha_diagnostic/Initialize(mapload)
. = ..()
set_light_on(TRUE)
/obj/item/mecha_diagnostic/Destroy(force)
. = ..()
mech_data = null
/obj/item/mecha_diagnostic/examine(mob/user)
. = ..()
if(mech_data)
. += "This holodata sheet consists of data from a <b>[initial(mech_data.name)]</b>."
+8
View File
@@ -60,6 +60,7 @@
"MECHA_INT_CONTROL_LOST" = MECHA_INT_CONTROL_LOST,
"MECHA_INT_SHORT_CIRCUIT" = MECHA_INT_SHORT_CIRCUIT,
)
data["diagnostic_status"] = HAS_TRAIT(src, TRAIT_MECHA_DIAGNOSTIC_CREATED)
var/list/regions = list()
var/list/tgui_region_data = SSid_access.all_region_access_tgui
@@ -225,5 +226,12 @@
if("equip_act")
var/obj/item/mecha_parts/mecha_equipment/gear = locate(params["ref"]) in flat_equipment
return gear?.ui_act(params["gear_action"], params, ui, state)
if("diagnostic")
if(HAS_TRAIT(src, TRAIT_MECHA_DIAGNOSTIC_CREATED))
return FALSE
var/obj/item/mecha_diagnostic/diagnostic = new /obj/item/mecha_diagnostic(get_turf(src))
diagnostic.name = "mecha holodiagnostic ([src.name])"
diagnostic.mech_data += src
ADD_TRAIT(src, TRAIT_MECHA_DIAGNOSTIC_CREATED, REF(src))
return TRUE
@@ -276,6 +276,7 @@ GLOBAL_DATUM(cargo_ripley, /obj/vehicle/sealed/mecha/ripley/cargo)
take_damage(max_integrity * 0.5, sound_effect=FALSE) //Low starting health
if(!GLOB.cargo_ripley && mapload)
GLOB.cargo_ripley = src
ADD_TRAIT(src, TRAIT_MECHA_DIAGNOSTIC_CREATED, REF(src)) //It was built *long* before the shift started.
/obj/vehicle/sealed/mecha/ripley/cargo/Destroy()
if(GLOB.cargo_ripley == src)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 29 KiB

+3 -1
View File
@@ -3760,7 +3760,7 @@
#include "code\modules\cargo\bounties\chef.dm"
#include "code\modules\cargo\bounties\engineering.dm"
#include "code\modules\cargo\bounties\item.dm"
#include "code\modules\cargo\bounties\mech.dm"
#include "code\modules\cargo\bounties\mecha.dm"
#include "code\modules\cargo\bounties\medical.dm"
#include "code\modules\cargo\bounties\mining.dm"
#include "code\modules\cargo\bounties\reagent.dm"
@@ -3779,6 +3779,7 @@
#include "code\modules\cargo\exports\lavaland.dm"
#include "code\modules\cargo\exports\manifest.dm"
#include "code\modules\cargo\exports\materials.dm"
#include "code\modules\cargo\exports\mecha.dm"
#include "code\modules\cargo\exports\organs.dm"
#include "code\modules\cargo\exports\parts.dm"
#include "code\modules\cargo\exports\seeds.dm"
@@ -6368,6 +6369,7 @@
#include "code\modules\vehicles\mecha\mecha_control_console.dm"
#include "code\modules\vehicles\mecha\mecha_damage.dm"
#include "code\modules\vehicles\mecha\mecha_defense.dm"
#include "code\modules\vehicles\mecha\mecha_diagnostic.dm"
#include "code\modules\vehicles\mecha\mecha_helpers.dm"
#include "code\modules\vehicles\mecha\mecha_mob_interaction.dm"
#include "code\modules\vehicles\mecha\mecha_movement.dm"
@@ -54,6 +54,7 @@ export type MainData = {
modules: MechModule[];
selected_module_index: number;
sheet_material_amount: number;
diagnostic_status: BooleanLike;
};
export type MechModule = {
+18 -6
View File
@@ -38,6 +38,7 @@ export const Content = (props) => {
one_access,
regions,
accesses,
diagnostic_status,
} = data;
const id_lock = mecha_flags & mechflag_keys['ID_LOCK_ON'];
return (
@@ -49,12 +50,23 @@ export const Content = (props) => {
fill
title={name}
buttons={
<Button
icon="edit"
tooltip="Rename"
tooltipPosition="left"
onClick={() => act('changename')}
/>
<>
<Button
icon="edit"
tooltip="Rename"
tooltipPosition="left"
onClick={() => act('changename')}
/>
{!diagnostic_status && (
<Button
icon="tachograph-digital"
color="violet"
tooltip="Diagnostic"
tooltipPosition="left"
onClick={() => act('diagnostic')}
/>
)}
</>
}
>
<Stack fill vertical>