New Station Trait: Cybernetic Revolution + Body Purist Quirk (#21882)

* first half of port

* no mail goodies

* no more errors in vsc, but errors in build

* debugging and setting implants

* quirk blacklist

* discounts and markups

* station must load first and THEN research

* round up

* quirk works now

* signals

* runover

* and thats it

* it is illegal to be too different :\

* ya meson eyes for janitor just sucks ass, so get a worse organ (heart)

* whoops double discount

* alphabetical

* zzz

* why extra tab

* no need for extra linebreak

* zzz2

* comment: makes it clear that body purist prevents effect :)
This commit is contained in:
Rune Knight
2024-04-27 18:43:41 -07:00
committed by GitHub
parent 23c82c63ea
commit b76e8c45ec
11 changed files with 248 additions and 11 deletions

View File

@@ -141,8 +141,8 @@
#define INIT_ORDER_VIS 80
#define INIT_ORDER_SECURITY_LEVEL 79
#define INIT_ORDER_MATERIALS 76
#define INIT_ORDER_RESEARCH 75
#define INIT_ORDER_STATION 74
#define INIT_ORDER_STATION 75
#define INIT_ORDER_RESEARCH 74
#define INIT_ORDER_QUIRKS 73
#define INIT_ORDER_EVENTS 70
#define INIT_ORDER_JOBS 65

View File

@@ -17,13 +17,18 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
list("Ageusia","Vegetarian","Deviant Tastes"),
list("Ananas Affinity","Ananas Aversion"),
list("Alcohol Tolerance","Light Drinker"),
list("Prosthetic Limb (Left Arm)","Prosthetic Limb"),
list("Prosthetic Limb (Right Arm)","Prosthetic Limb"),
list("Prosthetic Limb (Left Leg)","Prosthetic Limb"),
list("Prosthetic Limb (Right Leg)","Prosthetic Limb"),
list("Prosthetic Limb (Left Leg)","Paraplegic"),
list("Prosthetic Limb (Right Leg)","Paraplegic"),
list("Prosthetic Limb","Paraplegic")
list("Prosthetic Limb (Left Arm)","Prosthetic Limb", "Body Purist"),
list("Prosthetic Limb (Right Arm)","Prosthetic Limb", "Body Purist"),
list("Prosthetic Limb (Left Leg)","Prosthetic Limb", "Body Purist"),
list("Prosthetic Limb (Right Leg)","Prosthetic Limb", "Body Purist"),
list("Prosthetic Limb (Left Leg)","Paraplegic", "Body Purist"),
list("Prosthetic Limb (Right Leg)","Paraplegic", "Body Purist"),
list("Prosthetic Limb", "Paraplegic"),
list("Prosthetic Limb", "Body Purist"),
list("Cybernetic Organ (Lungs)", "Body Purist"),
list("Cybernetic Organ (Heart)", "Body Purist"),
list("Cybernetic Organ (Liver)", "Body Purist"),
list("Upgraded Cybernetic Organ", "Body Purist")
)
/datum/controller/subsystem/processing/quirks/Initialize(timeofday)

View File

@@ -238,3 +238,9 @@
/datum/mood_event/surgery
description = "<span class='boldwarning'>HE'S CUTTING ME OPEN!!</span>\n"
mood_change = -8
/datum/mood_event/body_purist
description = span_warning("I feel cybernetics attached to me, and I HATE IT!")
/datum/mood_event/body_purist/add_effects(power)
mood_change = power

View File

@@ -130,3 +130,75 @@
weight = 4
trait_to_give = STATION_TRAIT_SHUTTLE_SALE
show_in_report = TRUE
/datum/station_trait/cybernetic_revolution
name = "Cybernetic Revolution"
trait_type = STATION_TRAIT_POSITIVE
weight = 1
show_in_report = TRUE
report_message = "The new trends in cybernetics have come to the station! Everyone has some form of cybernetic implant."
trait_to_give = STATION_TRAIT_CYBERNETIC_REVOLUTION
/// List of all job types with the cybernetics they should receive.
// Should be themed around their job/department. If no theme is possible, a basic cybernetic organ is fine.
var/static/list/job_to_cybernetic = list(
/datum/job/assistant = /obj/item/organ/heart/cybernetic,
/datum/job/artist = /obj/item/organ/heart/cybernetic,
/datum/job/atmos = /obj/item/organ/cyberimp/mouth/breathing_tube, // Inhaling gases.
/datum/job/bartender = /obj/item/organ/liver/cybernetic/upgraded, // Drinking their own drinks.
/datum/job/brigphysician = /obj/item/organ/cyberimp/eyes/hud/medical,
/datum/job/captain = /obj/item/organ/heart/cybernetic/upgraded,
/datum/job/cargo_tech = /obj/item/organ/stomach/cybernetic,
/datum/job/chaplain = /obj/item/organ/cyberimp/brain/anti_drop, // Preventing null rod loss.
/datum/job/chemist = /obj/item/organ/cyberimp/eyes/hud/science, // For seeing reagents.
/datum/job/chief_engineer = /obj/item/organ/cyberimp/chest/thrusters,
/datum/job/clerk = /obj/item/organ/stomach/cybernetic,
/datum/job/clown = /obj/item/organ/cyberimp/brain/anti_stun, // Funny.
/datum/job/cmo = /obj/item/organ/cyberimp/chest/reviver,
/datum/job/cook = /obj/item/organ/cyberimp/chest/nutriment/plus,
/datum/job/curator = /obj/item/organ/eyes/robotic/glow, // Spookie.
/datum/job/detective = /obj/item/organ/lungs/cybernetic/upgraded, // Smoker.
/datum/job/doctor = /obj/item/organ/cyberimp/arm/toolset/surgery,
/datum/job/engineer = /obj/item/organ/cyberimp/arm/toolset,
/datum/job/geneticist = /obj/item/organ/stomach/fly,
/datum/job/head_of_personnel = /obj/item/organ/eyes/robotic,
/datum/job/hos = /obj/item/organ/cyberimp/brain/anti_drop,
/datum/job/hydro = /obj/item/organ/cyberimp/chest/nutriment,
/datum/job/janitor = /obj/item/organ/heart/cybernetic, // ACTUAL x-ray eyes is likely "not balanced" and all alternatives suck. So boring heart.
/datum/job/lawyer = /obj/item/organ/heart/cybernetic/upgraded,
/datum/job/mime = /obj/item/organ/tongue/robot, // ...
/datum/job/mining = /obj/item/organ/cyberimp/chest/reviver, // Replace with a reusable mining-specific implant if one is added later.
/datum/job/miningmedic = /obj/item/organ/cyberimp/eyes/hud/medical,
/datum/job/network_admin = /obj/item/organ/cyberimp/arm/toolset,
/datum/job/officer = /obj/item/organ/cyberimp/arm/flash,
/datum/job/paramedic = /obj/item/organ/cyberimp/eyes/hud/medical,
/datum/job/psych = /obj/item/organ/ears/cybernetic,
/datum/job/qm = /obj/item/organ/stomach/cybernetic,
/datum/job/rd = /obj/item/organ/cyberimp/eyes/hud/diagnostic, // Replace with a very cool science implant if one is added later.
/datum/job/roboticist = /obj/item/organ/cyberimp/eyes/hud/diagnostic, // Robots and mechs.
/datum/job/scientist = /obj/item/organ/cyberimp/eyes/hud/science, // Science, duh.
/datum/job/tourist = /obj/item/organ/heart/cybernetic,
/datum/job/virologist = /obj/item/organ/lungs/cybernetic/upgraded,
/datum/job/warden = /obj/item/organ/cyberimp/eyes/hud/security,
)
/datum/station_trait/cybernetic_revolution/New()
. = ..()
RegisterSignal(SSdcs, COMSIG_GLOB_JOB_AFTER_SPAWN, PROC_REF(on_job_after_spawn))
/datum/station_trait/cybernetic_revolution/proc/on_job_after_spawn(datum/source, datum/job/job, mob/living/living_mob, mob/new_player_mob, joined_late)
// Having the Body Purist quirk prevents the effects of this station trait from being applied to you.
var/datum/quirk/body_purist/body_purist = /datum/quirk/body_purist
if(initial(body_purist.name) in new_player_mob.client.prefs.all_quirks)
return
var/cybernetic_type = job_to_cybernetic[job.type]
if(cybernetic_type)
var/obj/item/organ/cybernetic = new cybernetic_type()
// Timer is needed because doing it immediately doesn't REPLACE organs for some unknown reason, so got to do it next tick or whatever.
addtimer(CALLBACK(cybernetic, TYPE_PROC_REF(/obj/item/organ, Insert), living_mob), 1)
return
if(isAI(living_mob))
var/mob/living/silicon/ai/ai = living_mob
ai.eyeobj.relay_speech = TRUE
return

View File

@@ -833,3 +833,71 @@
if(disallowed_trait)
return "You have no DNA!"
return FALSE
/datum/quirk/body_purist
name = "Body Purist"
desc = "You believe your body is a temple and its natural form is an embodiment of perfection. Accordingly, you despise the idea of ever augmenting it with unnatural parts, cybernetic, prosthetic, or anything like it."
icon = "person-rays"
value = -2
mood_quirk = TRUE
gain_text = span_danger("You now begin to hate the idea of having cybernetic implants.")
lose_text = span_notice("Maybe cybernetics aren't so bad. You now feel okay with augmentations and prosthetics.")
medical_record_text = "This patient has disclosed an extreme hatred for unnatural bodyparts and augmentations."
var/cybernetics_level = 0
/datum/quirk/body_purist/add()
check_cybernetics()
RegisterSignal(quirk_holder, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(on_organ_gain))
RegisterSignal(quirk_holder, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(on_organ_lose))
RegisterSignal(quirk_holder, COMSIG_CARBON_ATTACH_LIMB, PROC_REF(on_limb_gain))
RegisterSignal(quirk_holder, COMSIG_CARBON_REMOVE_LIMB, PROC_REF(on_limb_lose))
/datum/quirk/body_purist/remove()
UnregisterSignal(quirk_holder, list(
COMSIG_CARBON_GAIN_ORGAN,
COMSIG_CARBON_LOSE_ORGAN,
COMSIG_CARBON_ATTACH_LIMB,
COMSIG_CARBON_REMOVE_LIMB,
))
SEND_SIGNAL(quirk_holder, COMSIG_CLEAR_MOOD_EVENT, "body_purist")
/datum/quirk/body_purist/proc/check_cybernetics()
var/mob/living/carbon/owner = quirk_holder
if(!istype(owner))
return
for(var/obj/item/bodypart/limb as anything in owner.bodyparts)
if(!limb.is_organic_limb())
cybernetics_level++
for(var/obj/item/organ/organ as anything in owner.internal_organs)
if(organ.organ_flags & ORGAN_SYNTHETIC || organ.status == ORGAN_ROBOTIC)
cybernetics_level++
update_mood()
/datum/quirk/body_purist/proc/update_mood()
SEND_SIGNAL(quirk_holder, COMSIG_CLEAR_MOOD_EVENT, "body_purist")
if(cybernetics_level)
SEND_SIGNAL(quirk_holder, COMSIG_ADD_MOOD_EVENT, "body_purist", /datum/mood_event/body_purist, -cybernetics_level * 10)
/datum/quirk/body_purist/proc/on_organ_gain(datum/source, obj/item/organ/new_organ, special)
SIGNAL_HANDLER
if(new_organ.organ_flags & ORGAN_SYNTHETIC || new_organ.status == ORGAN_ROBOTIC)
cybernetics_level++
update_mood()
/datum/quirk/body_purist/proc/on_organ_lose(datum/source, obj/item/organ/old_organ, special)
SIGNAL_HANDLER
if(old_organ.organ_flags & ORGAN_SYNTHETIC || old_organ.status == ORGAN_ROBOTIC)
cybernetics_level--
update_mood()
/datum/quirk/body_purist/proc/on_limb_gain(datum/source, obj/item/bodypart/new_limb, special)
SIGNAL_HANDLER
if(!new_limb.is_organic_limb())
cybernetics_level++
update_mood()
/datum/quirk/body_purist/proc/on_limb_lose(datum/source, obj/item/bodypart/old_limb, special)
SIGNAL_HANDLER
if(!old_limb.is_organic_limb())
cybernetics_level--
update_mood()

View File

@@ -531,6 +531,11 @@
design_ids = list("cybernetic_heart", "cybernetic_liver", "cybernetic_lungs", "cybernetic_stomach", "cybernetic_ears", "cybernetic_appendix")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000)
datum/techweb_node/cyber_organs/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 500)
/datum/techweb_node/cyber_organs_upgraded
id = "cyber_organs_upgraded"
display_name = "Upgraded Cybernetic Organs"
@@ -539,6 +544,11 @@
design_ids = list("cybernetic_heart_u", "cybernetic_liver_u", "cybernetic_lungs_u", "cybernetic_stomach_u")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500)
/datum/techweb_node/cyber_organs_upgraded/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 750)
/datum/techweb_node/ipc_organs
id = "ipc_organs"
display_name = "IPC Parts"
@@ -555,6 +565,11 @@
design_ids = list("ci-nutriment", "ci-breather", "ci-gloweyes", "ci-meson", "ci-welding", "ci-medhud", "ci-sechud", "ci-scihud", "ci-diaghud")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/cyber_implants/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1250)
/datum/techweb_node/adv_cyber_implants
id = "adv_cyber_implants"
display_name = "Advanced Cybernetic Implants"
@@ -563,6 +578,11 @@
design_ids = list("ci-toolset", "ci-surgery", "ci-reviver", "ci-nutrimentplus", "ci-magboots")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/adv_cyber_implants/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1250)
/datum/techweb_node/combat_cyber_implants
id = "combat_cyber_implants"
display_name = "Combat Cybernetic Implants"
@@ -571,6 +591,11 @@
design_ids = list("ci-antidrop", "ci-antistun", "ci-thrusters", "ci-jumpboots", "ci-wheelies")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
/datum/techweb_node/combat_cyber_implants/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1250)
/datum/techweb_node/illegal_cyber_implants
id = "illegal_cyber_implants"
display_name = "Illegal Cybernetic Implants"
@@ -579,6 +604,11 @@
design_ids = list("ci-noslipwater")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000)
/datum/techweb_node/illegal_cyber_implants/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
////////////////////////Tools////////////////////////
/datum/techweb_node/basic_mining

View File

@@ -324,6 +324,7 @@
/obj/item/bodypart/proc/attach_limb(mob/living/carbon/C, special)
moveToNullspace()
set_owner(C)
SEND_SIGNAL(C, COMSIG_CARBON_ATTACH_LIMB, src, special)
C.bodyparts += src
if(held_index)
if(held_index > C.hand_bodyparts.len)

View File

@@ -57,6 +57,7 @@
for(var/X in actions)
var/datum/action/A = X
A.Grant(M)
SEND_SIGNAL(M, COMSIG_CARBON_GAIN_ORGAN, src, special)
//Special is for instant replacement like autosurgeons
/obj/item/organ/proc/Remove(mob/living/carbon/M, special = FALSE)
@@ -70,7 +71,7 @@
for(var/X in actions)
var/datum/action/A = X
A.Remove(M)
SEND_SIGNAL(M, COMSIG_CARBON_LOSE_ORGAN, src, special)
/obj/item/organ/proc/on_find(mob/living/finder)
return

View File

@@ -84,6 +84,7 @@
#include "reagent_recipe_collisions.dm"
#include "spawn_humans.dm"
#include "species_whitelists.dm"
#include "station_trait_tests.dm"
#include "subsystem_init.dm"
#include "timer_sanity.dm"
#include "trait_addition_and_removal.dm"

View File

@@ -0,0 +1,10 @@
/// This test spawns various station traits and looks through them to see if there's any errors.
/datum/unit_test/station_traits
/datum/unit_test/station_traits/Run()
var/datum/station_trait/cybernetic_revolution/cyber_trait = allocate(/datum/station_trait/cybernetic_revolution)
for(var/datum/job/job in subtypesof(/datum/job))
if(!(initial(job.faction) || job.faction != "Station")) // Replace with job types if it gets ported.
continue
if(!(job in cyber_trait.job_to_cybernetic))
Fail("Job [job] does not have an assigned cybernetic for [cyber_trait.type] station trait.")

View File

@@ -833,6 +833,11 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
Loaded with bullets which release micro-electromagnetic pulses on hit, disrupting electronics on the target hit."
item = /obj/item/ammo_box/magazine/m10mm/emp
/datum/uplink_item/ammo/pistol/emp/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
cost *= 3
/datum/uplink_item/ammo/shotgun
cost = 2
include_modes = list(/datum/game_mode/nuclear)
@@ -1241,6 +1246,11 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 2
manufacturer = /datum/corporation/traitor/cybersun
/datum/uplink_item/explosives/emp/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
cost *= 3
/datum/uplink_item/explosives/ducky
name = "Exploding Rubber Duck"
desc = "A seemingly innocent rubber duck. When placed, it arms, and will violently explode when stepped on."
@@ -1312,6 +1322,11 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/sbeacondrop/emp
cost = 7
/datum/uplink_item/explosives/syndicate_bomb/emp/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
cost *= 2
/datum/uplink_item/explosives/syndicate_detonator
name = "Syndicate Detonator"
desc = "The Syndicate detonator is a companion device to the Syndicate bomb. Simply press the included button \
@@ -1561,6 +1576,11 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
manufacturer = /datum/corporation/traitor/donkco
surplus = 30
/datum/uplink_item/stealthy_tools/emplight/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
cost *= 3
/datum/uplink_item/stealthy_tools/mulligan
name = "Mulligan"
desc = "Screwed up and have security on your tail? This handy syringe will give you a completely new identity \
@@ -1846,6 +1866,11 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 4
exclude_modes = list(/datum/game_mode/nuclear) //Buy your own ammo you lazy sods
/datum/uplink_item/device_tools/illegal_ammo_disk/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
cost *= 3 // Can print EMP.
/datum/uplink_item/device_tools/medgun
name = "Medbeam Gun"
desc = "A wonder of Syndicate engineering, the Medbeam gun, or Medi-Gun enables a medic to keep his fellow \
@@ -2091,6 +2116,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
category = "Implants"
surplus = 50
/datum/uplink_item/implants/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
// All implants are half off and can be as low as one TC.
cost = max(1, ROUND_UP(cost/2))
/datum/uplink_item/implants/reusable
name = "Reusable Autosurgeon"
desc = "An empty autosurgeon, but unlike others can be used multiple times. More suspicious than others."
@@ -2228,7 +2260,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
desc = "A modified version of the Stechkin pistol placed inside of the forearm to allow for easy concealment."
item = /obj/item/autosurgeon/arm/syndicate/stechkin_implant
cost = 9
/datum/uplink_item/implants/noslipall
name = "Slip Prevention Implant"
desc = "An implant that uses advanced sensors to detect when you are slipping and utilize motors in order to prevent it."
@@ -2352,6 +2384,11 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/autosurgeon/arm/syndicate/syndie_hammer
restricted_species = list("preternis")
/datum/uplink_item/race_restricted/hammerimplant/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
cost = max(1, ROUND_UP(cost/2))
/datum/uplink_item/race_restricted/killertomatos
name = "Killer Tomatoes"
desc = "The Syndicates local gardeners brewed these up for our plant comrades (does not work against fellow plants)."
@@ -2433,6 +2470,12 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 8
manufacturer = /datum/corporation/traitor/vahlen
/datum/uplink_item/role_restricted/arm_medical_gun/New()
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
// All implants are half off (rounded) and can be as low as one TC.
cost = max(1, ROUND_UP(cost/2))
/datum/uplink_item/role_restricted/brainwash_disk
name = "Brainwashing Surgery Program"
desc = "A disk containing the procedure to perform a brainwashing surgery, allowing you to implant an objective onto a target. \