From 8a577f43f6805c18d3bd65f619da2fcd604d552d Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Mon, 9 Oct 2023 20:14:46 +0200 Subject: [PATCH 001/100] Autopsy scanners fit in surgery trays [MDB IGNORE] (#24226) * Autopsy scanners fit in surgery trays (#78835) ## About The Pull Request This enables surgery trays to hold autopsy scanners
Screenshot ![image](https://github.com/tgstation/tgstation/assets/86855173/2fb2930c-7875-417a-8a1e-03fd8b3aeb75) (Scanner not included)
## Why It's Good For The Game Since it is a tool used in a surgery's step, I feel it makes sense that the autopsy tray (and surgery trays as a whole) should be able to hold this item and it potentially means less switching between containers. ## Changelog :cl: qol: The autopsy tray (and surgery trays) can now hold the autopsy scanner /:cl: * Autopsy scanners fit in surgery trays --------- Co-authored-by: YehnBeep <86855173+YehnBeep@users.noreply.github.com> --- code/datums/storage/subtypes/surgery_tray.dm | 1 + code/game/objects/items/surgery_tray.dm | 1 + 2 files changed, 2 insertions(+) diff --git a/code/datums/storage/subtypes/surgery_tray.dm b/code/datums/storage/subtypes/surgery_tray.dm index 35886581318..42b369b4ce9 100644 --- a/code/datums/storage/subtypes/surgery_tray.dm +++ b/code/datums/storage/subtypes/surgery_tray.dm @@ -6,6 +6,7 @@ /datum/storage/surgery_tray/New() . = ..() set_holdable(list( + /obj/item/autopsy_scanner, /obj/item/blood_filter, /obj/item/bonesetter, /obj/item/cautery, diff --git a/code/game/objects/items/surgery_tray.dm b/code/game/objects/items/surgery_tray.dm index 37494a39b55..edd92522446 100644 --- a/code/game/objects/items/surgery_tray.dm +++ b/code/game/objects/items/surgery_tray.dm @@ -6,6 +6,7 @@ /datum/storage/surgery_tray/New() . = ..() set_holdable(list( + /obj/item/autopsy_scanner, /obj/item/blood_filter, /obj/item/bonesetter, /obj/item/cautery, From aa8657df8c742af76c18040eb65226bc90ec466d Mon Sep 17 00:00:00 2001 From: Name Date: Mon, 9 Oct 2023 14:27:48 -0400 Subject: [PATCH 002/100] Bitrunner Alt-titles + Others + QoL (#24083) * Bitrunner + Coroner + Curator Alt Titles * Junior Titles * Bitrunner+Roboticist * Bitrunner + Misc Jobs + Alt-title alphabetization * It Changes --- .../code/alt_job_titles.dm | 152 ++++++++++-------- 1 file changed, 87 insertions(+), 65 deletions(-) diff --git a/modular_skyrat/modules/alternative_job_titles/code/alt_job_titles.dm b/modular_skyrat/modules/alternative_job_titles/code/alt_job_titles.dm index d7abb4e00f0..11de5521903 100644 --- a/modular_skyrat/modules/alternative_job_titles/code/alt_job_titles.dm +++ b/modular_skyrat/modules/alternative_job_titles/code/alt_job_titles.dm @@ -12,48 +12,60 @@ /datum/job/ai alt_titles = list( "AI", + "Automated Overseer", "Station Intelligence", - "Automated Overseer" ) /datum/job/assistant alt_titles = list( "Assistant", - "Civilian", - "Tourist", + "Artist", "Businessman", "Businesswoman", - "Trader", + "Civilian", "Entertainer", "Freelancer", - "Artist", - "Off-Duty Staff", + "Tourist", + "Trader", "Off-Duty Crew", + "Off-Duty Staff", ) /datum/job/atmospheric_technician alt_titles = list( "Atmospheric Technician", - "Life Support Technician", "Emergency Fire Technician", "Firefighter", + "Life Support Technician", ) /datum/job/barber alt_titles = list( "Barber", + "Aethestician", + "Colorist", "Salon Manager", "Salon Technician", "Stylist", - "Colorist", ) /datum/job/bartender alt_titles = list( "Bartender", - "Mixologist", - "Barkeeper", "Barista", + "Barkeeper", + "Mixologist", + ) + +/datum/job/bitrunner + alt_titles = list( + "Bitrunner", + "Bitdomain Technician", + "Data Retrieval Specialist", + "Netdiver", + "Pod Jockey", + "Union Bitrunner", + "Junior Runner", ) /datum/job/blueshield @@ -66,11 +78,13 @@ /datum/job/botanist alt_titles = list( "Botanist", - "Hydroponicist", - "Gardener", "Botanical Researcher", - "Herbalist", "Florist", + "Gardener", + "Herbalist", + "Hydroponicist", + "Mycologist", + "Junior Botanist", ) /datum/job/bouncer @@ -89,33 +103,35 @@ /datum/job/captain alt_titles = list( "Captain", - "Station Commander", "Commanding Officer", "Site Manager", + "Station Commander", ) /datum/job/cargo_technician alt_titles = list( "Warehouse Technician", + "Commodities Trader", "Deck Worker", + "Inventory Associate", "Mailman", + "Receiving Clerk", "Union Associate", - "Inventory Associate", ) /datum/job/chaplain alt_titles = list( "Chaplain", - "Priest", - "Preacher", - "Reverend", - "Oracle", - "Pontifex", - "Magister", "High Priest", "Imam", - "Rabbi", + "Magister", "Monk", + "Oracle", + "Preacher", + "Priest", + "Pontifex", + "Rabbi", + "Reverend", ) /datum/job/chemist @@ -136,25 +152,25 @@ /datum/job/chief_medical_officer alt_titles = list( "Chief Medical Officer", - "Medical Director", - "Head of Medical", "Chief Physician", + "Head of Medical", "Head Physician", + "Medical Director", ) /datum/job/clown alt_titles = list( "Clown", + "Comedian", "Jester", "Joker", - "Comedian", ) /datum/job/cook alt_titles = list( "Cook", - "Chef", "Butcher", + "Chef", "Culinary Artist", "Sous-Chef", ) @@ -162,16 +178,19 @@ /datum/job/coroner alt_titles = list( "Coroner", - "Mortician", + "Forensic Pathologist", "Funeral Director", + "Medical Examiner", + "Mortician", ) /datum/job/curator alt_titles = list( "Curator", - "Librarian", - "Journalist", "Archivist", + "Conservator", + "Journalist", + "Librarian", ) /datum/job/customs_agent @@ -183,26 +202,27 @@ /datum/job/cyborg alt_titles = list( "Cyborg", - "Robot", "Android", + "Robot", ) /datum/job/detective alt_titles = list( "Detective", + "Forensic Scientist", "Forensic Technician", "Private Investigator", - "Forensic Scientist", ) /datum/job/doctor alt_titles = list( "Medical Doctor", - "Surgeon", - "Nurse", "General Practitioner", "Medical Resident", + "Nurse", "Physician", + "Surgeon", + "Medical Student", ) /datum/job/engineering_guard //see orderly @@ -210,58 +230,61 @@ /datum/job/geneticist alt_titles = list( "Geneticist", + "Gene Tailor", "Mutation Researcher", ) /datum/job/head_of_personnel alt_titles = list( "Head of Personnel", - "Executive Officer", - "Employment Officer", "Crew Supervisor", + "Employment Officer", + "Executive Officer", ) /datum/job/head_of_security alt_titles = list( "Head of Security", - "Security Commander", "Chief Constable", "Chief of Security", + "Security Commander", "Sheriff", ) /datum/job/janitor alt_titles = list( "Janitor", - "Custodian", - "Custodial Technician", - "Sanitation Technician", - "Maintenance Technician", "Concierge", + "Custodial Technician", + "Custodian", "Maid", + "Maintenance Technician", + "Sanitation Technician", ) /datum/job/lawyer alt_titles = list( "Lawyer", - "Internal Affairs Agent", - "Human Resources Agent", - "Defence Attorney", - "Public Defender", "Barrister", - "Prosecutor", + "Defense Attorney", + "Human Resources Agent", + "Internal Affairs Agent", "Legal Clerk", + "Prosecutor", + "Public Defender", ) /datum/job/mime alt_titles = list( "Mime", + "Mummer", "Pantomimist", ) /datum/job/nanotrasen_consultant alt_titles = list( "Nanotrasen Consultant", + "Nanotrasen Advisor", "Nanotrasen Diplomat", ) @@ -285,44 +308,42 @@ "Maximum Security Prisoner", "SuperMax Security Prisoner", "Protective Custody Prisoner", - "Convict", - "Felon", - "Inmate", ) /datum/job/psychologist alt_titles = list( "Psychologist", + "Counsellor", "Psychiatrist", "Therapist", - "Counsellor", ) /datum/job/quartermaster alt_titles = list( "Quartermaster", - "Union Requisitions Officer", "Deck Chief", - "Warehouse Supervisor", - "Supply Foreman", "Head of Supply", "Logistics Coordinator", + "Supply Foreman", + "Union Requisitions Officer", + "Warehouse Supervisor", ) /datum/job/research_director alt_titles = list( "Research Director", - "Silicon Administrator", - "Lead Researcher", "Biorobotics Director", - "Research Supervisor", "Chief Science Officer", + "Lead Researcher", + "Research Supervisor", + "Silicon Administrator", ) /datum/job/roboticist alt_titles = list( "Roboticist", "Biomechanical Engineer", + "Machinist", "Mechatronic Engineer", "Apprentice Roboticist", ) @@ -332,24 +353,24 @@ /datum/job/scientist alt_titles = list( "Scientist", + "Anomalist", "Circuitry Designer", - "Xenobiologist", "Cytologist", - "Plasma Researcher", - "Anomalist", + "Graduate Student", "Lab Technician", - "Theoretical Physicist", "Ordnance Technician", + "Plasma Researcher", + "Theoretical Physicist", "Xenoarchaeologist", + "Xenobiologist", "Research Assistant", - "Graduate Student", ) /datum/job/security_officer alt_titles = list( "Security Officer", - "Security Operative", "Peacekeeper", + "Security Operative", "Security Cadet", ) @@ -357,26 +378,27 @@ alt_titles = list( "Union Miner", "Excavator", - "Spelunker", "Drill Technician", "Prospector", + "Spelunker", + "Apprentice Miner", ) /datum/job/station_engineer alt_titles = list( "Station Engineer", - "Emergency Damage Control Technician", "Electrician", + "Emergency Damage Control Technician", "Engine Technician", "EVA Technician", "Mechanic", "Apprentice Engineer", - "Engineering Trainee", ) /datum/job/virologist alt_titles = list( "Virologist", + "Epidemiologist", "Pathologist", "Junior Pathologist", ) @@ -385,7 +407,7 @@ alt_titles = list( "Warden", "Brig Sergeant", - "Dispatch Officer", "Brig Governor", + "Dispatch Officer", "Jailer", ) From d22eb16cdcc7f95c3df192d9d7e68362ecef600c Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Mon, 9 Oct 2023 20:48:34 +0200 Subject: [PATCH 003/100] Fixes some EMP'd cyborg bodypart runtimes [MDB IGNORE] (#24227) * Fixes some EMP'd cyborg bodypart runtimes (#78849) ## About The Pull Request Remember friends, bodypart don't always have owners. Fixes some runtimes that occur if cyborg bodyparts were emp'd without an owner. ## Changelog :cl: Melbert fix: Robotic bodyparts not attached to people are now properly affected by EMPs. /:cl: * Fixes some EMP'd cyborg bodypart runtimes --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/modules/surgery/bodyparts/_bodyparts.dm | 19 +++++++++---------- .../surgery/bodyparts/robot_bodyparts.dm | 19 +++++++++++-------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 56e1493fc74..f033c081ead 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -1376,9 +1376,10 @@ else update_icon_dropped() +// Note: Does NOT return EMP protection value from parent call or pass it on to subtypes /obj/item/bodypart/emp_act(severity) - . = ..() - if(. & EMP_PROTECT_WIRES || !IS_ROBOTIC_LIMB(src)) + var/protection = ..() + if((protection & EMP_PROTECT_WIRES) || !IS_ROBOTIC_LIMB(src)) return FALSE // with defines at the time of writing, this is 2 brute and 1.5 burn @@ -1395,16 +1396,14 @@ burn_damage *= 1.3 // SKYRAT EDIT : Balance - Lowers total damage from ~104 Burn to ~24 receive_damage(brute_damage, burn_damage) - do_sparks(number = 1, cardinal_only = FALSE, source = owner) - var/damage_percent_to_max = (get_damage() / max_damage) - if (time_needed && (damage_percent_to_max >= robotic_emp_paralyze_damage_percent_threshold)) - owner.visible_message(span_danger("[owner]'s [src] seems to malfunction!")) + do_sparks(number = 1, cardinal_only = FALSE, source = owner || src) + + if(can_be_disabled && (get_damage() / max_damage) >= robotic_emp_paralyze_damage_percent_threshold) ADD_TRAIT(src, TRAIT_PARALYSIS, EMP_TRAIT) - addtimer(CALLBACK(src, PROC_REF(un_paralyze)), time_needed) - return TRUE + addtimer(TRAIT_CALLBACK_REMOVE(src, TRAIT_PARALYSIS, EMP_TRAIT), time_needed) + owner?.visible_message(span_danger("[owner]'s [plaintext_zone] seems to malfunction!")) -/obj/item/bodypart/proc/un_paralyze() - REMOVE_TRAITS_IN(src, EMP_TRAIT) + return TRUE /// Returns the generic description of our BIO_EXTERNAL feature(s), prioritizing certain ones over others. Returns error on failure. /obj/item/bodypart/proc/get_external_description() diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index 37b6cef9897..99591daaa4b 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -111,15 +111,16 @@ /obj/item/bodypart/leg/left/robot/emp_act(severity) . = ..() - if(!.) + if(!. || isnull(owner)) return + var/knockdown_time = AUGGED_LEG_EMP_KNOCKDOWN_TIME if (severity == EMP_HEAVY) knockdown_time *= 2 owner.Knockdown(knockdown_time) if(owner.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways. return - to_chat(owner, span_danger("As your [src] unexpectedly malfunctions, it causes you to fall to the ground!")) + to_chat(owner, span_danger("As your [plaintext_zone] unexpectedly malfunctions, it causes you to fall to the ground!")) /obj/item/bodypart/leg/right/robot name = "cyborg right leg" @@ -156,15 +157,16 @@ /obj/item/bodypart/leg/right/robot/emp_act(severity) . = ..() - if(!.) + if(!. || isnull(owner)) return + var/knockdown_time = AUGGED_LEG_EMP_KNOCKDOWN_TIME if (severity == EMP_HEAVY) knockdown_time *= 2 owner.Knockdown(knockdown_time) if(owner.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways. return - to_chat(owner, span_danger("As your [src] unexpectedly malfunctions, it causes you to fall to the ground!")) + to_chat(owner, span_danger("As your [plaintext_zone] unexpectedly malfunctions, it causes you to fall to the ground!")) /obj/item/bodypart/chest/robot name = "cyborg torso" @@ -203,7 +205,7 @@ /obj/item/bodypart/chest/robot/emp_act(severity) . = ..() - if(!.) + if(!. || isnull(owner)) return var/stun_time = 0 @@ -219,7 +221,7 @@ var/damage_percent_to_max = (get_damage() / max_damage) if (stun_time && (damage_percent_to_max >= robotic_emp_paralyze_damage_percent_threshold)) - to_chat(owner, span_danger("Your [src]'s logic boards temporarily become unresponsive!")) + to_chat(owner, span_danger("Your [plaintext_zone]'s logic boards temporarily become unresponsive!")) owner.Stun(stun_time) owner.Shake(pixelshiftx = shift_x, pixelshifty = shift_y, duration = shake_duration) @@ -338,9 +340,10 @@ /obj/item/bodypart/head/robot/emp_act(severity) . = ..() - if(!.) + if(!. || isnull(owner)) return - to_chat(owner, span_danger("Your [src]'s optical transponders glitch out and malfunction!")) + + to_chat(owner, span_danger("Your [plaintext_zone]'s optical transponders glitch out and malfunction!")) var/glitch_duration = AUGGED_HEAD_EMP_GLITCH_DURATION if (severity == EMP_HEAVY) From 7906301f0d9e2f35bde1d5a932a3df7d24cec90b Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Mon, 9 Oct 2023 20:59:59 +0200 Subject: [PATCH 004/100] Fix virtual gondola meat [MDB IGNORE] (#24228) * Fix virtual gondola meat (#78808) ## About The Pull Request Instead of having a copy-pasted snowflake function for virtual gondola mutation toxin, lets just move the difference to a variable. Fixes the "Be unable to push the crate" part of #78804, because it was applying both versions of the gondola disease, and the slower one could finish first if you got unlucky. ## Why It's Good For The Game Bugs bad, duplicate code bad. ## Changelog :cl: fix: Virtual domain gondola meat will no longer have a small chance to turn you into a weaker gondola variant /:cl: * Fix virtual gondola meat --------- Co-authored-by: FlufflesTheDog --- .../bitrunning/virtual_domain/domains/gondola_asteroid.dm | 6 +----- code/modules/reagents/chemistry/reagents/other_reagents.dm | 3 ++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/code/modules/bitrunning/virtual_domain/domains/gondola_asteroid.dm b/code/modules/bitrunning/virtual_domain/domains/gondola_asteroid.dm index 4deacb4f9c5..01d58e39803 100644 --- a/code/modules/bitrunning/virtual_domain/domains/gondola_asteroid.dm +++ b/code/modules/bitrunning/virtual_domain/domains/gondola_asteroid.dm @@ -28,11 +28,7 @@ /datum/reagent/gondola_mutation_toxin/virtual_domain name = "Advanced Tranquility" - -/datum/reagent/gondola_mutation_toxin/virtual_domain/expose_mob(mob/living/exposed_mob, methods = TOUCH, reac_volume, show_message = TRUE, touch_protection = 0) - . = ..() - if((methods & (PATCH|INGEST|INJECT)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) - exposed_mob.ForceContractDisease(new /datum/disease/transformation/gondola/virtual_domain(), FALSE, TRUE) + gondola_disease = /datum/disease/transformation/gondola/virtual_domain /datum/disease/transformation/gondola/virtual_domain stage_prob = 9 diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 62a6d52c4f1..5a26d37e9ed 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -2589,11 +2589,12 @@ color = "#9A6750" //RGB: 154, 103, 80 taste_description = "inner peace" penetrates_skin = NONE + var/datum/disease/transformation/gondola_disease = /datum/disease/transformation/gondola /datum/reagent/gondola_mutation_toxin/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message = TRUE, touch_protection = 0) . = ..() if((methods & (PATCH|INGEST|INJECT)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) - exposed_mob.ForceContractDisease(new /datum/disease/transformation/gondola(), FALSE, TRUE) + exposed_mob.ForceContractDisease(new gondola_disease, FALSE, TRUE) /datum/reagent/spider_extract From a7718e7a41bcc63c190fd5e0c5d491ce539900b0 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Mon, 9 Oct 2023 21:00:17 +0200 Subject: [PATCH 005/100] Refactor gib code to use bitflags and have documentation [MDB IGNORE] (#24143) * Refactor gib code to use bitflags and have documentation * Modular updates * Modular updates * Modular updates --------- Co-authored-by: Tim Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> --- code/__DEFINES/blood.dm | 13 +++++ .../signals/signals_mob/signals_mob_living.dm | 2 +- code/datums/components/butchering.dm | 2 +- code/datums/components/death_linked.dm | 2 +- code/datums/components/omen.dm | 6 +-- code/datums/components/squashable.dm | 2 +- code/datums/components/stationstuck.dm | 2 +- code/datums/diseases/gbs.dm | 2 +- code/datums/dna.dm | 4 +- code/datums/martial/plasma_fist.dm | 2 +- code/datums/mutations/body.dm | 2 +- code/datums/status_effects/debuffs/cursed.dm | 2 +- code/datums/status_effects/debuffs/debuffs.dm | 2 +- .../datums/storage/subtypes/bag_of_holding.dm | 2 +- code/game/machinery/computer/arcade/arcade.dm | 2 +- code/game/machinery/shieldgen.dm | 2 +- code/game/objects/items/debug_items.dm | 2 +- code/game/objects/items/food/monkeycube.dm | 2 +- code/game/objects/items/food/pizza.dm | 2 +- code/game/objects/items/food/sandwichtoast.dm | 2 +- code/game/objects/items/grenades/plastic.dm | 2 +- .../items/implants/implant_explosive.dm | 2 +- code/game/objects/items/manuals.dm | 5 +- code/game/objects/items/rcd/RCD.dm | 2 +- code/game/objects/items/skub.dm | 2 +- code/game/objects/items/spear.dm | 2 +- code/game/objects/items/teleportation.dm | 2 +- code/game/objects/items/weaponry.dm | 4 +- code/game/objects/structures/divine.dm | 2 +- code/modules/admin/smites/bsa.dm | 5 +- code/modules/admin/smites/gib.dm | 2 +- code/modules/admin/smites/puzzgrid.dm | 2 +- code/modules/admin/verbs/adminfun.dm | 6 +-- .../antagonists/changeling/headslug_eggs.dm | 2 +- .../antagonists/changeling/powers/headcrab.dm | 2 +- code/modules/antagonists/cult/runes.dm | 6 +-- .../antagonists/heretic/heretic_knowledge.dm | 2 +- .../modules/antagonists/heretic/influences.dm | 2 +- .../sacrifice_knowledge.dm | 2 +- .../equipment/nuclear_bomb/_nuclear_bomb.dm | 2 +- .../wizard/grand_ritual/finales/armageddon.dm | 2 +- code/modules/bitrunning/event.dm | 2 +- code/modules/cargo/coupon.dm | 2 +- code/modules/cargo/supplypod.dm | 2 +- .../clothing/head/mind_monkey_helmet.dm | 2 +- code/modules/experisci/destructive_scanner.dm | 2 +- code/modules/experisci/handheld_scanner.dm | 2 +- .../food_and_drinks/machinery/deep_fryer.dm | 2 +- .../food_and_drinks/machinery/gibber.dm | 2 +- .../food_and_drinks/machinery/processor.dm | 2 +- code/modules/hydroponics/grown/melon.dm | 2 +- .../industrial_lift/industrial_lift.dm | 2 +- code/modules/library/bibles.dm | 2 +- .../ruins/objects_and_mobs/ash_walker_den.dm | 2 +- .../ruins/spaceruin_code/hilbertshotel.dm | 2 +- .../modules/mob/living/basic/basic_defense.dm | 2 +- .../basic/icemoon/ice_whelp/ice_whelp.dm | 2 +- .../mob/living/basic/pets/dog/corgi.dm | 2 +- .../mob/living/carbon/alien/alien_defense.dm | 2 +- code/modules/mob/living/carbon/alien/death.dm | 4 +- .../mob/living/carbon/alien/larva/death.dm | 4 +- .../modules/mob/living/carbon/alien/organs.dm | 2 +- .../carbon/alien/special/alien_embryo.dm | 4 +- code/modules/mob/living/carbon/death.dm | 54 +++++++++---------- code/modules/mob/living/carbon/human/death.dm | 4 +- .../mob/living/carbon/human/human_defense.dm | 2 +- .../carbon/human/species_types/dullahan.dm | 6 +-- code/modules/mob/living/death.dm | 51 +++++++++++++----- .../mob/living/silicon/ai/ai_defense.dm | 2 +- .../modules/mob/living/silicon/robot/robot.dm | 2 +- .../mob/living/silicon/robot/robot_defense.dm | 4 +- .../simple_animal/hostile/gorilla/gorilla.dm | 4 +- .../hostile/megafauna/colossus.dm | 2 +- .../mining_mobs/elites/goliath_broodmother.dm | 2 +- .../mob_spawn/ghost_roles/mining_roles.dm | 2 +- code/modules/mod/modules/modules_ninja.dm | 2 +- code/modules/power/apc/apc_malf.dm | 2 +- .../projectiles/guns/ballistic/launchers.dm | 2 +- .../projectiles/projectile/special/rocket.dm | 2 +- .../chemistry/reagents/drug_reagents.dm | 2 +- .../reagents/chemistry/recipes/others.dm | 2 +- .../religion/honorbound/honorbound_rites.dm | 2 +- code/modules/research/anomaly/anomaly_core.dm | 2 +- .../research/xenobiology/xenobiology.dm | 2 +- code/modules/shuttle/on_move.dm | 2 +- .../spell_types/shapeshift/_shape_status.dm | 2 +- .../spell_types/shapeshift/_shapeshift.dm | 2 +- .../modules/spells/spell_types/touch/smite.dm | 2 +- code/modules/vehicles/mecha/_mecha.dm | 2 +- .../vehicles/mecha/combat/savannah_ivanov.dm | 2 +- .../mecha/equipment/tools/mining_tools.dm | 2 +- .../vehicles/mecha/mecha_mob_interaction.dm | 2 +- code/modules/vehicles/vehicle_key.dm | 2 +- code/modules/wiremod/shell/drone.dm | 2 +- code/modules/zombie/items.dm | 2 +- .../code/modules/mob/living/carbon/death.dm | 9 +--- .../modules/mob/living/carbon/human/death.dm | 6 +-- 97 files changed, 188 insertions(+), 167 deletions(-) diff --git a/code/__DEFINES/blood.dm b/code/__DEFINES/blood.dm index 3bf4af65969..2c8576a2eda 100644 --- a/code/__DEFINES/blood.dm +++ b/code/__DEFINES/blood.dm @@ -19,3 +19,16 @@ #define BLOOD_STATE_OIL "oil" /// No blood is present #define BLOOD_STATE_NOT_BLOODY "no blood whatsoever" + +// Bitflags for mob dismemberment and gibbing +/// Mobs will drop a brain +#define DROP_BRAIN (1<<0) +/// Mobs will drop organs +#define DROP_ORGANS (1<<1) +/// Mobs will drop bodyparts (arms, legs, etc.) +#define DROP_BODYPARTS (1<<2) +/// Mobs will drop items +#define DROP_ITEMS (1<<3) + +/// Mobs will drop everything +#define DROP_ALL_REMAINS (DROP_BRAIN | DROP_ORGANS | DROP_BODYPARTS | DROP_ITEMS) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index a6c5fdbf793..97e80bc0b51 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -89,7 +89,7 @@ ///from base of mob/living/death(): (gibbed) #define COMSIG_LIVING_DEATH "living_death" -///from base of mob/living/gib(): (no_brain, no_organs, no_bodyparts) +///from base of mob/living/gib(): (drop_bitflags) ///Note that it is fired regardless of whether the mob was dead beforehand or not. #define COMSIG_LIVING_GIBBED "living_gibbed" diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index 97bb2a30ad5..689de30db37 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -167,7 +167,7 @@ butcher_callback?.Invoke(butcher, target) target.harvest(butcher) target.log_message("has been butchered by [key_name(butcher)]", LOG_ATTACK) - target.gib(FALSE, FALSE, TRUE) + target.gib(DROP_BRAIN|DROP_ORGANS) ///Enables the butchering mechanic for the mob who has equipped us. /datum/component/butchering/proc/enable_butchering(datum/source) diff --git a/code/datums/components/death_linked.dm b/code/datums/components/death_linked.dm index 59d2ce5e855..c20c8100195 100644 --- a/code/datums/components/death_linked.dm +++ b/code/datums/components/death_linked.dm @@ -27,4 +27,4 @@ /datum/component/death_linked/proc/on_death(mob/living/target, gibbed) SIGNAL_HANDLER var/mob/living/linked_mob_resolved = linked_mob?.resolve() - linked_mob_resolved?.gib() + linked_mob_resolved?.gib(DROP_ALL_REMAINS) diff --git a/code/datums/components/omen.dm b/code/datums/components/omen.dm index 4f3b17a7473..f499d22968d 100644 --- a/code/datums/components/omen.dm +++ b/code/datums/components/omen.dm @@ -238,7 +238,7 @@ return ..() death_explode(our_guy) - our_guy.gib() + our_guy.gib(DROP_ALL_REMAINS) /** * The quirk omen. Permanent. @@ -259,7 +259,7 @@ /datum/component/omen/quirk/check_death(mob/living/our_guy) if(!iscarbon(our_guy)) - our_guy.gib() + our_guy.gib(DROP_ALL_REMAINS) return // Don't explode if buckled to a stasis bed @@ -270,7 +270,7 @@ death_explode(our_guy) var/mob/living/carbon/player = our_guy - player.spread_bodyparts(skip_head = TRUE) + player.spread_bodyparts() player.spawn_gibs() return diff --git a/code/datums/components/squashable.dm b/code/datums/components/squashable.dm index 5fc489873bf..8174127aeb3 100644 --- a/code/datums/components/squashable.dm +++ b/code/datums/components/squashable.dm @@ -72,7 +72,7 @@ /datum/component/squashable/proc/Squish(mob/living/target) if(squash_flags & SQUASHED_SHOULD_BE_GIBBED) - target.gib() + target.gib(DROP_ALL_REMAINS) else target.adjustBruteLoss(squash_damage) diff --git a/code/datums/components/stationstuck.dm b/code/datums/components/stationstuck.dm index 63a1dcabbbd..5634186f04e 100644 --- a/code/datums/components/stationstuck.dm +++ b/code/datums/components/stationstuck.dm @@ -49,7 +49,7 @@ It has a punishment variable that is what happens to the parent when they leave escapee.death() if(PUNISHMENT_GIB) escapee.investigate_log("has been gibbed by stationstuck component.", INVESTIGATE_DEATHS) - escapee.gib() + escapee.gib(DROP_ALL_REMAINS) if(PUNISHMENT_TELEPORT) var/targetturf = find_safe_turf(stuck_zlevel) if(!targetturf) diff --git a/code/datums/diseases/gbs.dm b/code/datums/diseases/gbs.dm index 22f84cf73a1..abf2116a92f 100644 --- a/code/datums/diseases/gbs.dm +++ b/code/datums/diseases/gbs.dm @@ -30,5 +30,5 @@ to_chat(affected_mob, span_userdanger("Your body feels as if it's trying to rip itself apart!")) if(SPT_PROB(30, seconds_per_tick)) affected_mob.investigate_log("has been gibbed by GBS.", INVESTIGATE_DEATHS) - affected_mob.gib() + affected_mob.gib(DROP_ALL_REMAINS) return FALSE diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 5034a863f56..785b70eb475 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -927,7 +927,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) switch(rand(0,6)) if(0) investigate_log("has been gibbed by DNA instability.", INVESTIGATE_DEATHS) - gib() + gib(DROP_ALL_REMAINS) if(1) investigate_log("has been dusted by DNA instability.", INVESTIGATE_DEATHS) dust() @@ -943,7 +943,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) BP.dismember() else investigate_log("has been gibbed by DNA instability.", INVESTIGATE_DEATHS) - gib() + gib(DROP_ALL_REMAINS) else set_species(/datum/species/dullahan) if(4) diff --git a/code/datums/martial/plasma_fist.dm b/code/datums/martial/plasma_fist.dm index 1bc353cc698..f4c89177ac3 100644 --- a/code/datums/martial/plasma_fist.dm +++ b/code/datums/martial/plasma_fist.dm @@ -68,7 +68,7 @@ log_combat(attacker, defender, "gibbed (Plasma Fist)") var/turf/Dturf = get_turf(defender) defender.investigate_log("has been gibbed by plasma fist.", INVESTIGATE_DEATHS) - defender.gib() + defender.gib(DROP_ALL_REMAINS) if(nobomb) return if(!hasclient) diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 094e650fe33..332b2695e40 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -508,7 +508,7 @@ to_chat(borgo, span_userdanger("Your sensors are disabled by a shower of blood!")) borgo.Paralyze(6 SECONDS) owner.investigate_log("has been gibbed by the martyrdom mutation.", INVESTIGATE_DEATHS) - owner.gib() + owner.gib(DROP_ALL_REMAINS) /datum/mutation/human/headless name = "H.A.R.S." diff --git a/code/datums/status_effects/debuffs/cursed.dm b/code/datums/status_effects/debuffs/cursed.dm index 285fb86348e..8d331bbe90a 100644 --- a/code/datums/status_effects/debuffs/cursed.dm +++ b/code/datums/status_effects/debuffs/cursed.dm @@ -102,7 +102,7 @@ to_chat(owner, span_userdanger("Why couldn't I get one more try?!")) owner.investigate_log("has been gibbed by the cursed status effect after accumulating [curse_count] curses.", INVESTIGATE_DEATHS) - owner.gib() + owner.gib(DROP_ALL_REMAINS) qdel(src) return diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index ff3e1762074..f4c78b69101 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -694,7 +694,7 @@ /datum/status_effect/dna_melt/on_remove() if(!ishuman(owner)) - owner.gib() //fuck you in particular + owner.gib(DROP_ALL_REMAINS) //fuck you in particular return var/mob/living/carbon/human/H = owner INVOKE_ASYNC(H, TYPE_PROC_REF(/mob/living/carbon/human, something_horrible), kill_either_way) diff --git a/code/datums/storage/subtypes/bag_of_holding.dm b/code/datums/storage/subtypes/bag_of_holding.dm index 9176588b5fc..9e3a486cdcd 100644 --- a/code/datums/storage/subtypes/bag_of_holding.dm +++ b/code/datums/storage/subtypes/bag_of_holding.dm @@ -32,6 +32,6 @@ user.log_message("detonated a bag of holding at [loc_name(loccheck)].", LOG_ATTACK, color="red") user.investigate_log("has been gibbed by a bag of holding recursive insertion.", INVESTIGATE_DEATHS) - user.gib(TRUE, TRUE, TRUE) + user.gib() new/obj/boh_tear(loccheck) qdel(resolve_parent) diff --git a/code/game/machinery/computer/arcade/arcade.dm b/code/game/machinery/computer/arcade/arcade.dm index 28034872289..58a7280e864 100644 --- a/code/game/machinery/computer/arcade/arcade.dm +++ b/code/game/machinery/computer/arcade/arcade.dm @@ -582,7 +582,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( var/mob/living/living_user = user if (istype(living_user)) living_user.investigate_log("has been gibbed by an emagged Orion Trail game.", INVESTIGATE_DEATHS) - living_user.gib() + living_user.gib(DROP_ALL_REMAINS) SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("loss", "hp", (obj_flags & EMAGGED ? "emagged":"normal"))) user.lost_game() diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 0e53fa8e36c..f1cbc110a3e 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -504,7 +504,7 @@ for(var/mob/living/L in get_turf(src)) visible_message(span_danger("\The [src] is suddenly occupying the same space as \the [L]!")) L.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS) - L.gib() + L.gib(DROP_ALL_REMAINS) RegisterSignal(src, COMSIG_ATOM_SINGULARITY_TRY_MOVE, PROC_REF(block_singularity)) /obj/machinery/shieldwall/Destroy() diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm index 68ae291e736..e2febe30fcf 100644 --- a/code/game/objects/items/debug_items.dm +++ b/code/game/objects/items/debug_items.dm @@ -163,7 +163,7 @@ playsound(src, 'sound/voice/borg_deathsound.ogg') sleep(3 SECONDS) living_user.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS) - living_user.gib() + living_user.gib(DROP_ALL_REMAINS) return var/turf/loc_turf = get_turf(src) for(var/spawn_atom in (choice == "No" ? typesof(path) : subtypesof(path))) diff --git a/code/game/objects/items/food/monkeycube.dm b/code/game/objects/items/food/monkeycube.dm index 5cf9db79fd0..0013fbcdadd 100644 --- a/code/game/objects/items/food/monkeycube.dm +++ b/code/game/objects/items/food/monkeycube.dm @@ -48,7 +48,7 @@ return Expand() user.visible_message(span_danger("[user]'s torso bursts open as a primate emerges!")) - user.gib(null, TRUE, null, TRUE) + user.gib(DROP_BRAIN|DROP_BODYPARTS|DROP_ITEMS) // just remove the organs /obj/item/food/monkeycube/syndicate faction = list(FACTION_NEUTRAL, ROLE_SYNDICATE) diff --git a/code/game/objects/items/food/pizza.dm b/code/game/objects/items/food/pizza.dm index fdbb1e33c87..b93cd7ed721 100644 --- a/code/game/objects/items/food/pizza.dm +++ b/code/game/objects/items/food/pizza.dm @@ -389,7 +389,7 @@ if(istype(item, /obj/item/food/pineappleslice)) to_chat(user, "If you want something crazy like pineapple, I'll kill you.") //this is in bigger text because it's hard to spam something that gibs you, and so that you're perfectly aware of the reason why you died user.investigate_log("has been gibbed by putting pineapple on an arnold pizza.", INVESTIGATE_DEATHS) - user.gib() //if you want something crazy like pineapple, i'll kill you + user.gib(DROP_ALL_REMAINS) //if you want something crazy like pineapple, i'll kill you else if(istype(item, /obj/item/food/grown/mushroom) && iscarbon(user)) to_chat(user, span_userdanger("So, if you want mushroom, shut up.")) //not as large as the pineapple text, because you could in theory spam it var/mob/living/carbon/shutup = user diff --git a/code/game/objects/items/food/sandwichtoast.dm b/code/game/objects/items/food/sandwichtoast.dm index fec714ad850..8b91b04621e 100644 --- a/code/game/objects/items/food/sandwichtoast.dm +++ b/code/game/objects/items/food/sandwichtoast.dm @@ -302,5 +302,5 @@ /obj/item/food/sandwich/death/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] starts to shove [src] down [user.p_their()] throat the wrong way. It looks like [user.p_theyre()] trying to commit suicide!")) qdel(src) - user.gib(TRUE, TRUE, TRUE) + user.gib() return MANUAL_SUICIDE diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm index 5902298032c..d5f3b0dec9d 100644 --- a/code/game/objects/items/grenades/plastic.dm +++ b/code/game/objects/items/grenades/plastic.dm @@ -161,7 +161,7 @@ user.visible_message(span_suicide("[user] activates [src] and holds it above [user.p_their()] head! It looks like [user.p_theyre()] going out with a bang!")) shout_syndicate_crap(user) explosion(user, heavy_impact_range = 2, explosion_cause = src) //Cheap explosion imitation because putting detonate() here causes runtimes - user.gib(1, 1) + user.gib(DROP_BODYPARTS) qdel(src) // X4 is an upgraded directional variant of c4 which is relatively safe to be standing next to. And much less safe to be standing on the other side of. diff --git a/code/game/objects/items/implants/implant_explosive.dm b/code/game/objects/items/implants/implant_explosive.dm index 70471a8e99a..c9f961b594e 100644 --- a/code/game/objects/items/implants/implant_explosive.dm +++ b/code/game/objects/items/implants/implant_explosive.dm @@ -166,7 +166,7 @@ explosion(src, devastation_range = explosion_devastate, heavy_impact_range = explosion_heavy, light_impact_range = explosion_light, flame_range = explosion_light, flash_range = explosion_light, explosion_cause = src) if(imp_in) imp_in.investigate_log("has been gibbed by an explosive implant.", INVESTIGATE_DEATHS) - imp_in.gib(TRUE) + imp_in.gib(DROP_ORGANS|DROP_BODYPARTS) qdel(src) ///Macrobomb has the strength and delay of 10 microbombs diff --git a/code/game/objects/items/manuals.dm b/code/game/objects/items/manuals.dm index bcae55357e4..9d8cd8e9426 100644 --- a/code/game/objects/items/manuals.dm +++ b/code/game/objects/items/manuals.dm @@ -431,9 +431,10 @@ H.gib_animation() sleep(0.3 SECONDS) H.adjustBruteLoss(1000) //to make the body super-bloody + // if we use gib() then the body gets deleted H.spawn_gibs() - H.spill_organs() - H.spread_bodyparts() + H.spill_organs(DROP_ALL_REMAINS) + H.spread_bodyparts(DROP_BRAIN) return BRUTELOSS /obj/item/book/manual/wiki/plumbing diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index bf6f5c2ab1f..27c04aa7479 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -259,7 +259,7 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) useResource(16, user) activate() playsound(loc, 'sound/machines/click.ogg', 50, 1) - user.gib() + user.gib(DROP_ALL_REMAINS) return MANUAL_SUICIDE user.visible_message(span_suicide("[user] pulls the trigger... But there is not enough ammo!")) diff --git a/code/game/objects/items/skub.dm b/code/game/objects/items/skub.dm index 7e9cd381e33..12e6da344d0 100644 --- a/code/game/objects/items/skub.dm +++ b/code/game/objects/items/skub.dm @@ -13,6 +13,6 @@ /obj/item/skub/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] has declared themself as anti-skub! The skub tears them apart!")) - user.gib() + user.gib(DROP_ALL_REMAINS) playsound(src, 'sound/items/eatfood.ogg', 50, TRUE, -1) return MANUAL_SUICIDE diff --git a/code/game/objects/items/spear.dm b/code/game/objects/items/spear.dm index d9f13911731..410cddd1fc0 100644 --- a/code/game/objects/items/spear.dm +++ b/code/game/objects/items/spear.dm @@ -152,7 +152,7 @@ user.say("[war_cry]", forced="spear warcry") explosive.forceMove(user) explosive.detonate() - user.gib() + user.gib(DROP_ALL_REMAINS) qdel(src) return BRUTELOSS diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index 533fc755fa1..07e178acba5 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -489,7 +489,7 @@ destination.ex_act(EXPLODE_HEAVY) victim.unequip_everything() victim.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS) - victim.gib() + victim.gib(DROP_ALL_REMAINS) ///Damage and stun all mobs in fragging_location turf, called after a teleport /obj/item/syndicate_teleporter/proc/telefrag(turf/fragging_location, mob/user) // Don't let this gib. Never let this gib. diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 21fc15572bf..8c949b36a79 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -922,7 +922,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 if(isliving(target)) var/mob/living/bug = target bug.investigate_log("has been splatted by a flyswatter.", INVESTIGATE_DEATHS) - bug.gib() + bug.gib(DROP_ALL_REMAINS) else qdel(target) return @@ -1099,7 +1099,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 if(living_target.stat == DEAD && prob(force*damage_mod*0.5)) living_target.visible_message(span_danger("[living_target] explodes in a shower of gore!"), blind_message = span_hear("You hear organic matter ripping and tearing!")) living_target.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS) - living_target.gib() + living_target.gib(DROP_ALL_REMAINS) log_combat(user, living_target, "gibbed", src) else if(target.uses_integrity) target.take_damage(force*damage_mod*3, BRUTE, MELEE, FALSE, null, 50) diff --git a/code/game/objects/structures/divine.dm b/code/game/objects/structures/divine.dm index cda00d98d0b..ef9f650e42a 100644 --- a/code/game/objects/structures/divine.dm +++ b/code/game/objects/structures/divine.dm @@ -18,7 +18,7 @@ return to_chat(user, span_notice("Invoking the sacred ritual, you sacrifice [L].")) L.investigate_log("has been sacrificially gibbed on an altar.", INVESTIGATE_DEATHS) - L.gib() + L.gib(DROP_ALL_REMAINS) message_admins("[ADMIN_LOOKUPFLW(user)] has sacrificed [key_name_admin(L)] on the sacrificial altar at [AREACOORD(src)].") /obj/structure/healingfountain diff --git a/code/modules/admin/smites/bsa.dm b/code/modules/admin/smites/bsa.dm index cf0399acf26..bdf5f9e37b1 100644 --- a/code/modules/admin/smites/bsa.dm +++ b/code/modules/admin/smites/bsa.dm @@ -20,10 +20,7 @@ target_turf.break_tile() if (target.health <= 1) - target.gib( - /* no_brain = */ TRUE, - /* no_organs = */ TRUE, - ) + target.gib(DROP_BODYPARTS) else target.adjustBruteLoss(min(BSA_MAX_DAMAGE, target.health - 1)) target.Paralyze(BSA_PARALYZE_TIME) diff --git a/code/modules/admin/smites/gib.dm b/code/modules/admin/smites/gib.dm index 471479e7645..4c7c4324823 100644 --- a/code/modules/admin/smites/gib.dm +++ b/code/modules/admin/smites/gib.dm @@ -4,4 +4,4 @@ /datum/smite/gib/effect(client/user, mob/living/target) . = ..() - target.gib(/* no_brain = */ FALSE) + target.gib(DROP_ORGANS|DROP_BODYPARTS) diff --git a/code/modules/admin/smites/puzzgrid.dm b/code/modules/admin/smites/puzzgrid.dm index 481f85a191f..fe5f88d6a5f 100644 --- a/code/modules/admin/smites/puzzgrid.dm +++ b/code/modules/admin/smites/puzzgrid.dm @@ -91,7 +91,7 @@ span_bolddanger("You were unable to free [victim] from their fiendish prison, leaving them as nothing more than a smattering of mush!"), span_bolddanger("Your compatriates were unable to free you from your fiendish prison, leaving you as nothing more than a smattering of mush!"), ) - victim.gib() + victim.gib(DROP_ALL_REMAINS) victim = null qdel(src) diff --git a/code/modules/admin/verbs/adminfun.dm b/code/modules/admin/verbs/adminfun.dm index b1e0327510a..f51a922e419 100644 --- a/code/modules/admin/verbs/adminfun.dm +++ b/code/modules/admin/verbs/adminfun.dm @@ -78,9 +78,9 @@ if (istype(living_victim)) living_victim.investigate_log("has been gibbed by an admin.", INVESTIGATE_DEATHS) if(confirm == "Yes") - living_victim.gib() + living_victim.gib(DROP_ALL_REMAINS) else - living_victim.gib(TRUE) + living_victim.gib(DROP_ORGANS|DROP_BODYPARTS) SSblackbox.record_feedback("tally", "admin_verb", 1, "Gib") // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! @@ -97,7 +97,7 @@ var/mob/living/ourself = mob if (istype(ourself)) - ourself.gib(TRUE, TRUE, TRUE) + ourself.gib() /client/proc/everyone_random() set category = "Admin.Fun" diff --git a/code/modules/antagonists/changeling/headslug_eggs.dm b/code/modules/antagonists/changeling/headslug_eggs.dm index 08733a7e6af..e4327aa3ed1 100644 --- a/code/modules/antagonists/changeling/headslug_eggs.dm +++ b/code/modules/antagonists/changeling/headslug_eggs.dm @@ -37,7 +37,7 @@ changeling_datum.regain_powers() owner.investigate_log("has been gibbed by a changeling egg burst.", INVESTIGATE_DEATHS) - owner.gib() + owner.gib(DROP_ALL_REMAINS) qdel(src) #undef EGG_INCUBATION_TIME diff --git a/code/modules/antagonists/changeling/powers/headcrab.dm b/code/modules/antagonists/changeling/powers/headcrab.dm index 7daebc4cfb2..f608d1620b8 100644 --- a/code/modules/antagonists/changeling/powers/headcrab.dm +++ b/code/modules/antagonists/changeling/powers/headcrab.dm @@ -35,7 +35,7 @@ user.transfer_observers_to(user_turf) // user is about to be deleted, store orbiters on the turf if(user.stat != DEAD) user.investigate_log("has been gibbed by headslug burst.", INVESTIGATE_DEATHS) - user.gib() + user.gib(DROP_ALL_REMAINS) . = TRUE addtimer(CALLBACK(src, PROC_REF(spawn_headcrab), stored_mind, user_turf, organs), 1 SECONDS) diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index de8a26187ae..30cb3d4467c 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -370,7 +370,7 @@ structure_check() searches for nearby cultist structures required for the invoca if(sacrificial) playsound(sacrificial, 'sound/magic/disintegrate.ogg', 100, TRUE) sacrificial.investigate_log("has been sacrificially gibbed by the cult.", INVESTIGATE_DEATHS) - sacrificial.gib() + sacrificial.gib(DROP_ALL_REMAINS) return TRUE /obj/effect/rune/empower @@ -946,8 +946,8 @@ structure_check() searches for nearby cultist structures required for the invoca affecting = null rune_in_use = FALSE -/mob/living/carbon/human/cult_ghost/spill_organs(no_brain, no_organs, no_bodyparts) //cult ghosts never drop a brain - no_brain = TRUE +/mob/living/carbon/human/cult_ghost/spill_organs(drop_bitflags=NONE) + drop_bitflags &= ~DROP_BRAIN //cult ghosts never drop a brain . = ..() /mob/living/carbon/human/cult_ghost/get_organs_for_zone(zone, include_children) diff --git a/code/modules/antagonists/heretic/heretic_knowledge.dm b/code/modules/antagonists/heretic/heretic_knowledge.dm index ea22955d83e..260f56540d0 100644 --- a/code/modules/antagonists/heretic/heretic_knowledge.dm +++ b/code/modules/antagonists/heretic/heretic_knowledge.dm @@ -733,6 +733,6 @@ /datum/heretic_knowledge/ultimate/cleanup_atoms(list/selected_atoms) for(var/mob/living/carbon/human/sacrifice in selected_atoms) selected_atoms -= sacrifice - sacrifice.gib() + sacrifice.gib(DROP_ALL_REMAINS) return ..() diff --git a/code/modules/antagonists/heretic/influences.dm b/code/modules/antagonists/heretic/influences.dm index 67a3bbc16b4..74a851e7fb7 100644 --- a/code/modules/antagonists/heretic/influences.dm +++ b/code/modules/antagonists/heretic/influences.dm @@ -177,7 +177,7 @@ head.dismember() qdel(head) else - human_user.gib() + human_user.gib(DROP_ALL_REMAINS) human_user.investigate_log("has died from using telekinesis on a heretic influence.", INVESTIGATE_DEATHS) var/datum/effect_system/reagents_explosion/explosion = new() explosion.set_up(1, get_turf(human_user), TRUE, 0) diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm index 3e37c173923..e2887d73757 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm @@ -492,7 +492,7 @@ /datum/heretic_knowledge/hunt_and_sacrifice/proc/disembowel_target(mob/living/carbon/human/sac_target) if(heretic_mind) log_combat(heretic_mind.current, sac_target, "disemboweled via sacrifice") - sac_target.spill_organs() + sac_target.spill_organs(DROP_ALL_REMAINS) sac_target.apply_damage(250, BRUTE) if(sac_target.stat != DEAD) sac_target.investigate_log("has been killed by heretic sacrifice.", INVESTIGATE_DEATHS) diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm b/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm index c15012f409b..0b6a28c3bca 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm @@ -644,7 +644,7 @@ GLOBAL_VAR(station_nuke_source) to_chat(gibbed, span_userdanger("You are shredded to atoms by [source]!")) gibbed.investigate_log("has been gibbed by a nuclear blast.", INVESTIGATE_DEATHS) - gibbed.gib() + gibbed.gib(DROP_ALL_REMAINS) return TRUE /** diff --git a/code/modules/antagonists/wizard/grand_ritual/finales/armageddon.dm b/code/modules/antagonists/wizard/grand_ritual/finales/armageddon.dm index 876f2475d55..c4bba539c35 100644 --- a/code/modules/antagonists/wizard/grand_ritual/finales/armageddon.dm +++ b/code/modules/antagonists/wizard/grand_ritual/finales/armageddon.dm @@ -33,7 +33,7 @@ /datum/grand_finale/armageddon/trigger(mob/living/carbon/human/invoker) priority_announce(pick(possible_last_words), null, 'sound/magic/voidblink.ogg', sender_override = "[invoker.real_name]") var/turf/current_location = get_turf(invoker) - invoker.gib() + invoker.gib(DROP_ALL_REMAINS) var/static/list/doom_options = list() if (!length(doom_options)) diff --git a/code/modules/bitrunning/event.dm b/code/modules/bitrunning/event.dm index 0ac35a2df8f..6a4d54adcd8 100644 --- a/code/modules/bitrunning/event.dm +++ b/code/modules/bitrunning/event.dm @@ -139,7 +139,7 @@ /// Spawns a cybercop on the mutation target /datum/round_event/ghost_role/bitrunning_glitch/proc/spawn_cybercop(mob/living/mutation_target, datum/mind/player_mind) var/mob/living/carbon/human/new_agent = new(mutation_target.loc) - mutation_target.gib() + mutation_target.gib(DROP_ALL_REMAINS) mutation_target = null player_mind.transfer_to(new_agent) diff --git a/code/modules/cargo/coupon.dm b/code/modules/cargo/coupon.dm index fc1c3a6cc65..5c4e1e930b5 100644 --- a/code/modules/cargo/coupon.dm +++ b/code/modules/cargo/coupon.dm @@ -44,7 +44,7 @@ /// Play stupid games, win stupid prizes /obj/item/coupon/proc/curse_heart(mob/living/cursed) if(!iscarbon(cursed)) - cursed.gib() + cursed.gib(DROP_ALL_REMAINS) return TRUE var/mob/living/carbon/player = cursed diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm index feb6c8f8ae6..8635efee569 100644 --- a/code/modules/cargo/supplypod.dm +++ b/code/modules/cargo/supplypod.dm @@ -276,7 +276,7 @@ if (effectGib) //effectGib is on, that means whatever's underneath us better be fucking oof'd on target_living.adjustBruteLoss(5000) //THATS A LOT OF DAMAGE (called just in case gib() doesnt work on em) if (!QDELETED(target_living)) - target_living.gib() //After adjusting the fuck outta that brute loss we finish the job with some satisfying gibs + target_living.gib(DROP_ALL_REMAINS) //After adjusting the fuck outta that brute loss we finish the job with some satisfying gibs else target_living.adjustBruteLoss(damage) var/explosion_sum = B[1] + B[2] + B[3] + B[4] diff --git a/code/modules/clothing/head/mind_monkey_helmet.dm b/code/modules/clothing/head/mind_monkey_helmet.dm index c0463fed74c..d1c423b5b03 100644 --- a/code/modules/clothing/head/mind_monkey_helmet.dm +++ b/code/modules/clothing/head/mind_monkey_helmet.dm @@ -89,7 +89,7 @@ if(3) //primal gene (gorilla) magnification.gorillize() if(4) //genetic mass susceptibility (gib) - magnification.gib() + magnification.gib(DROP_ALL_REMAINS) //either used up correctly or taken off before polling finished (punish this by destroying the helmet) UnregisterSignal(magnification, COMSIG_SPECIES_LOSS) playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE) diff --git a/code/modules/experisci/destructive_scanner.dm b/code/modules/experisci/destructive_scanner.dm index ef89dc9b94a..de0b03b0f09 100644 --- a/code/modules/experisci/destructive_scanner.dm +++ b/code/modules/experisci/destructive_scanner.dm @@ -89,7 +89,7 @@ if(isliving(movable_atom)) var/mob/living/fucked_up_thing = movable_atom fucked_up_thing.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS) - fucked_up_thing.gib() + fucked_up_thing.gib(DROP_ALL_REMAINS) SEND_SIGNAL(src, COMSIG_MACHINERY_DESTRUCTIVE_SCAN, scanned_atoms) diff --git a/code/modules/experisci/handheld_scanner.dm b/code/modules/experisci/handheld_scanner.dm index 97aa034afa1..92031107ba5 100644 --- a/code/modules/experisci/handheld_scanner.dm +++ b/code/modules/experisci/handheld_scanner.dm @@ -59,6 +59,6 @@ icon_state = "experiscanner" remove_atom_colour(ADMIN_COLOUR_PRIORITY, "#FF0000") - user.gib(FALSE, TRUE, TRUE) //we delete everything but the brain, as it's going to be moved to the cistern + user.gib(DROP_BRAIN) //we delete everything but the brain, as it's going to be moved to the cistern toilet_brain.forceMove(result_toilet) result_toilet.w_items += toilet_brain.w_class diff --git a/code/modules/food_and_drinks/machinery/deep_fryer.dm b/code/modules/food_and_drinks/machinery/deep_fryer.dm index fc20112f08a..071cc18febc 100644 --- a/code/modules/food_and_drinks/machinery/deep_fryer.dm +++ b/code/modules/food_and_drinks/machinery/deep_fryer.dm @@ -216,7 +216,7 @@ GLOBAL_LIST_INIT(oilfry_blacklisted_items, typecacheof(list( if(target_temp < TCMB + 10) // a tiny bit of leeway dunking_target.visible_message(span_userdanger("[dunking_target] explodes from the entropic difference! Holy fuck!")) dunking_target.investigate_log("has been gibbed by entropic difference (being dunked into [src]).", INVESTIGATE_DEATHS) - dunking_target.gib() + dunking_target.gib(DROP_ALL_REMAINS) log_combat(user, dunking_target, "blew up", null, "by dunking them into [src]") return diff --git a/code/modules/food_and_drinks/machinery/gibber.dm b/code/modules/food_and_drinks/machinery/gibber.dm index 45e66f95ed2..121acceb4c4 100644 --- a/code/modules/food_and_drinks/machinery/gibber.dm +++ b/code/modules/food_and_drinks/machinery/gibber.dm @@ -256,4 +256,4 @@ if(victim.loc == input) victim.forceMove(src) - victim.gib() + victim.gib(DROP_ALL_REMAINS) diff --git a/code/modules/food_and_drinks/machinery/processor.dm b/code/modules/food_and_drinks/machinery/processor.dm index 2c1b0b9d3b3..60679f89345 100644 --- a/code/modules/food_and_drinks/machinery/processor.dm +++ b/code/modules/food_and_drinks/machinery/processor.dm @@ -76,7 +76,7 @@ if(isliving(what)) var/mob/living/themob = what - themob.gib(TRUE,TRUE,TRUE) + themob.gib() else qdel(what) LAZYREMOVE(processor_contents, what) diff --git a/code/modules/hydroponics/grown/melon.dm b/code/modules/hydroponics/grown/melon.dm index 80962a2d182..f69f8a68317 100644 --- a/code/modules/hydroponics/grown/melon.dm +++ b/code/modules/hydroponics/grown/melon.dm @@ -17,7 +17,7 @@ /obj/item/seeds/watermelon/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] is swallowing [src]! It looks like [user.p_theyre()] trying to commit suicide!")) - user.gib() + user.gib(DROP_ALL_REMAINS) new product(drop_location()) qdel(src) return MANUAL_SUICIDE diff --git a/code/modules/industrial_lift/industrial_lift.dm b/code/modules/industrial_lift/industrial_lift.dm index dd1b3f9604a..0bcc2a49bc8 100644 --- a/code/modules/industrial_lift/industrial_lift.dm +++ b/code/modules/industrial_lift/industrial_lift.dm @@ -326,7 +326,7 @@ GLOBAL_LIST_INIT(all_radial_directions, list( if(violent_landing) // Violent landing = gibbed. But the nicest kind of gibbing, keeping everything intact. crushed.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS) - crushed.gib(FALSE, FALSE, FALSE) + crushed.gib(DROP_ALL_REMAINS) else // Less violent landing simply crushes every bone in your body. crushed.Paralyze(30 SECONDS, ignore_canstun = TRUE) diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm index 3cfc9c8b76b..5d3c6e276b4 100644 --- a/code/modules/library/bibles.dm +++ b/code/modules/library/bibles.dm @@ -132,7 +132,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list( to_chat(user, span_userdanger("[deity_name] SMITE thee!")) add_memory_in_range(user, 7, /datum/memory/witnessed_gods_wrath, protagonist = user, deuteragonist = src, antagonist = deity_name) user.client?.give_award(/datum/award/achievement/misc/gods_wrath, user) - user.gib() + user.gib(DROP_ALL_REMAINS) else to_chat(user, span_userdanger("[deity_name] cast a curse upon thee!")) user.AddComponent(/datum/component/omen/bible) diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm b/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm index 480b26f5fab..5775f0a20f2 100644 --- a/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm +++ b/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm @@ -84,7 +84,7 @@ to_chat(deliverymob, span_warning("The Necropolis is pleased with your sacrifice. You feel confident your existence after death is secure.")) ashies.players_spawned -= deliverykey H.investigate_log("has been gibbed by the necropolis tendril.", INVESTIGATE_DEATHS) - H.gib() + H.gib(DROP_ALL_REMAINS) atom_integrity = min(atom_integrity + max_integrity*0.05,max_integrity)//restores 5% hp of tendril for(var/mob/living/L in view(src, 5)) if(L.mind?.has_antag_datum(/datum/antagonist/ashwalker)) diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm index 424e1db299e..af316034f93 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm @@ -428,7 +428,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) if(unforeseen_consequences) to_chat(unforeseen_consequences, span_warning("\The [H] starts to resonate. Forcing it to enter itself induces a bluespace paradox, violently tearing your body apart.")) unforeseen_consequences.investigate_log("has been gibbed by using [H] while inside of it.", INVESTIGATE_DEATHS) - unforeseen_consequences.gib() + unforeseen_consequences.gib(DROP_ALL_REMAINS) var/turf/targetturf = find_safe_turf() if(!targetturf) diff --git a/code/modules/mob/living/basic/basic_defense.dm b/code/modules/mob/living/basic/basic_defense.dm index 8afb40f2912..87fe6f8fed1 100644 --- a/code/modules/mob/living/basic/basic_defense.dm +++ b/code/modules/mob/living/basic/basic_defense.dm @@ -148,7 +148,7 @@ apply_damage(500, damagetype = BRUTE) else investigate_log("has been gibbed by an explosion.", INVESTIGATE_DEATHS) - gib() + gib(DROP_ALL_REMAINS) if (EXPLODE_HEAVY) var/bloss = 60 diff --git a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm index 292766be07b..f89009cc2d9 100644 --- a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm +++ b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm @@ -87,5 +87,5 @@ balloon_alert(src, "devouring...") if(!do_after(src, 5 SECONDS, target)) return - target.gib() + target.gib(DROP_ALL_REMAINS) adjustBruteLoss(-1 * heal_on_cannibalize) diff --git a/code/modules/mob/living/basic/pets/dog/corgi.dm b/code/modules/mob/living/basic/pets/dog/corgi.dm index cb0df08d198..9e120c4e8c0 100644 --- a/code/modules/mob/living/basic/pets/dog/corgi.dm +++ b/code/modules/mob/living/basic/pets/dog/corgi.dm @@ -482,7 +482,7 @@ prey.investigate_log("has been sacrificed by [src].", INVESTIGATE_DEATHS) if (isliving(prey)) var/mob/living/living_sacrifice = prey - living_sacrifice.gib() + living_sacrifice.gib(DROP_ALL_REMAINS) else qdel(prey) diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm index bc7a663206a..63ef8830435 100644 --- a/code/modules/mob/living/carbon/alien/alien_defense.dm +++ b/code/modules/mob/living/carbon/alien/alien_defense.dm @@ -103,7 +103,7 @@ In all, this is a lot like the monkey code. /N var/obj/item/organ/internal/ears/ears = get_organ_slot(ORGAN_SLOT_EARS) switch (severity) if (EXPLODE_DEVASTATE) - gib() + gib(DROP_ALL_REMAINS) if (EXPLODE_HEAVY) take_overall_damage(60, 60) diff --git a/code/modules/mob/living/carbon/alien/death.dm b/code/modules/mob/living/carbon/alien/death.dm index 718186c9078..f5a0b7ace1b 100644 --- a/code/modules/mob/living/carbon/alien/death.dm +++ b/code/modules/mob/living/carbon/alien/death.dm @@ -1,5 +1,5 @@ -/mob/living/carbon/alien/spawn_gibs(with_bodyparts) - if(with_bodyparts) +/mob/living/carbon/alien/spawn_gibs(drop_bitflags=NONE) + if(drop_bitflags & DROP_BODYPARTS) new /obj/effect/gibspawner/xeno(drop_location(), src) else new /obj/effect/gibspawner/xeno/bodypartless(drop_location(), src) diff --git a/code/modules/mob/living/carbon/alien/larva/death.dm b/code/modules/mob/living/carbon/alien/larva/death.dm index 8fd6329a0c1..4b7f9f93218 100644 --- a/code/modules/mob/living/carbon/alien/larva/death.dm +++ b/code/modules/mob/living/carbon/alien/larva/death.dm @@ -6,8 +6,8 @@ update_icons() -/mob/living/carbon/alien/larva/spawn_gibs(with_bodyparts) - if(with_bodyparts) +/mob/living/carbon/alien/larva/spawn_gibs(drop_bitflags=NONE) + if(drop_bitflags & DROP_BODYPARTS) new /obj/effect/gibspawner/larva(drop_location(), src) else new /obj/effect/gibspawner/larva/bodypartless(drop_location(), src) diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm index 5ef9b23c418..af796c9ff68 100644 --- a/code/modules/mob/living/carbon/alien/organs.dm +++ b/code/modules/mob/living/carbon/alien/organs.dm @@ -336,7 +336,7 @@ if(owner) shake_camera(owner, 2, 5) owner.investigate_log("has been gibbed by something inside [owner.p_their()] stomach.", INVESTIGATE_DEATHS) - owner.gib() + owner.gib(DROP_ALL_REMAINS) qdel(src) /obj/item/organ/internal/stomach/alien/proc/eject_stomach(list/turf/targets, spit_range, content_speed, particle_delay, particle_count=4) diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm index 37fb827f3a5..5a6746ec6fa 100644 --- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm +++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm @@ -126,8 +126,8 @@ if(gib_on_success) new_xeno.visible_message(span_danger("[new_xeno] bursts out of [owner] in a shower of gore!"), span_userdanger("You exit [owner], your previous host."), span_hear("You hear organic matter ripping and tearing!")) - // owner.investigate_log("has been gibbed by an alien larva.", INVESTIGATE_DEATHS) SKYRAT EDIT REMOVAL - ALIEN QOL - don't ever gib host. - // owner.gib(TRUE) SKYRAT EDIT REMOVAL - ALIEN QOL - don't ever gib host. + //owner.investigate_log("has been gibbed by an alien larva.", INVESTIGATE_DEATHS) // SKYRAT EDIT REMOVAL - ALIEN QOL - don't ever gib host. + //owner.gib(DROP_ORGANS|DROP_BODYPARTS) // SKYRAT EDIT ADDITION BEGIN - ALIEN QOL - You aren't getting gibbed but you aren't going to be having fun owner.apply_damage(150, BRUTE, BODY_ZONE_CHEST, wound_bonus = 30, sharpness = SHARP_POINTY) owner.spawn_gibs() diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index 4d14fb7df66..bbf82ccefc5 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -24,9 +24,9 @@ M.Scale(1.8, 1.2) animate(src, time = 40, transform = M, easing = SINE_EASING) -/mob/living/carbon/gib(no_brain, no_organs, no_bodyparts, safe_gib = FALSE) +/mob/living/carbon/gib(drop_bitflags=NONE) add_memory_in_range(src, 7, /datum/memory/witness_gib, protagonist = src) - if(safe_gib) // If you want to keep all the mob's items and not have them deleted + if(drop_bitflags & DROP_ITEMS) for(var/obj/item/W in src) dropItemToGround(W) if(prob(50)) @@ -37,39 +37,33 @@ visible_message(span_danger("[M] bursts out of [src]!")) return ..() -/mob/living/carbon/spill_organs(no_brain, no_organs, no_bodyparts) +/mob/living/carbon/spill_organs(drop_bitflags=NONE) var/atom/Tsec = drop_location() - if(!no_bodyparts) - if(no_organs)//so the organs don't get transferred inside the bodyparts we'll drop. - for(var/organ in organs) - if(no_brain || !istype(organ, /obj/item/organ/internal/brain)) - qdel(organ) - else //we're going to drop all bodyparts except chest, so the only organs that needs spilling are those inside it. - for(var/obj/item/organ/organ as anything in organs) - if(no_brain && istype(organ, /obj/item/organ/internal/brain)) - qdel(organ) //so the brain isn't transferred to the head when the head drops. - continue - var/org_zone = check_zone(organ.zone) //both groin and chest organs. - if(org_zone == BODY_ZONE_CHEST) - organ.Remove(src) - organ.forceMove(Tsec) - organ.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5) - else - for(var/obj/item/organ/organ as anything in organs) - if(no_brain && istype(organ, /obj/item/organ/internal/brain)) - qdel(organ) - continue - if(no_organs && !istype(organ, /obj/item/organ/internal/brain)) - qdel(organ) - continue + + for(var/obj/item/organ/organ as anything in organs) + if((drop_bitflags & DROP_BRAIN) && istype(organ, /obj/item/organ/internal/brain)) + if(drop_bitflags & DROP_BODYPARTS) + continue // the head will drop, so the brain should stay inside + organ.Remove(src) organ.forceMove(Tsec) - organ.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5) + organ.throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 5) + continue + + if((drop_bitflags & DROP_ORGANS) && !istype(organ, /obj/item/organ/internal/brain)) + if((drop_bitflags & DROP_BODYPARTS) && (check_zone(organ.zone) != BODY_ZONE_CHEST)) + continue // only chest & groin organs will be ejected + + organ.Remove(src) + organ.forceMove(Tsec) + organ.throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 5) + continue + + qdel(organ) -/// Launches all bodyparts away from the mob. skip_head will keep the head attached. -/mob/living/carbon/spread_bodyparts(skip_head = FALSE) +/mob/living/carbon/spread_bodyparts(drop_bitflags=NONE) for(var/obj/item/bodypart/part as anything in bodyparts) - if(skip_head && part.body_zone == BODY_ZONE_HEAD) + if(!(drop_bitflags & DROP_BRAIN) && part.body_zone == BODY_ZONE_HEAD) continue else if(part.body_zone == BODY_ZONE_CHEST) continue diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 90b94689796..3c0ffb2536b 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -5,8 +5,8 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift) /mob/living/carbon/human/dust_animation() new /obj/effect/temp_visual/dust_animation(loc, dna.species.dust_anim) -/mob/living/carbon/human/spawn_gibs(with_bodyparts) - if(with_bodyparts) +/mob/living/carbon/human/spawn_gibs(drop_bitflags=NONE) + if(drop_bitflags & DROP_BODYPARTS) new /obj/effect/gibspawner/human(drop_location(), src, get_static_viruses()) else new /obj/effect/gibspawner/human/bodypartless(drop_location(), src, get_static_viruses()) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index b02aaf03b17..233f9fe25fd 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -414,7 +414,7 @@ if(EXPLODE_LIGHT) SSexplosions.low_mov_atom += thing investigate_log("has been gibbed by an explosion.", INVESTIGATE_DEATHS) - gib() + gib(DROP_ALL_REMAINS) return TRUE else brute_loss = 500 diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index 8b429bbeb8f..4ea4b7f0c00 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -74,7 +74,7 @@ if(QDELETED(my_head)) my_head = null human.investigate_log("has been gibbed by the loss of [human.p_their()] head.", INVESTIGATE_DEATHS) - human.gib() + human.gib(DROP_ALL_REMAINS) return if(my_head.loc.name != human.real_name && istype(my_head.loc, /obj/item/bodypart/head)) @@ -87,7 +87,7 @@ if(illegal_head) my_head = null human.investigate_log("has been gibbed by having an illegal head put on [human.p_their()] shoulders.", INVESTIGATE_DEATHS) - human.gib() // Yeah so giving them a head on their body is really not a good idea, so their original head will remain but uh, good luck fixing it after that. + human.gib(DROP_ALL_REMAINS) // Yeah so giving them a head on their body is really not a good idea, so their original head will remain but uh, good luck fixing it after that. /datum/species/dullahan/proc/update_vision_perspective(mob/living/carbon/human/human) var/obj/item/organ/internal/eyes/eyes = human.get_organ_slot(ORGAN_SLOT_EYES) @@ -265,7 +265,7 @@ if(isdullahan(human)) var/datum/species/dullahan/dullahan_species = human.dna.species dullahan_species.my_head = null - owner.gib() + owner.gib(DROP_ALL_REMAINS) owner = null return ..() diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 9eddc41b127..6174a5793bc 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -1,12 +1,14 @@ /** * Blow up the mob into giblets * - * Arguments: - * * no_brain - Should the mob NOT drop a brain? - * * no_organs - Should the mob NOT drop organs? - * * no_bodyparts - Should the mob NOT drop bodyparts? -*/ -/mob/living/proc/gib(no_brain, no_organs, no_bodyparts) + * drop_bitflags: (see code/__DEFINES/blood.dm) + * * DROP_BRAIN - Gibbed mob will drop a brain + * * DROP_ORGANS - Gibbed mob will drop organs + * * DROP_BODYPARTS - Gibbed mob will drop bodyparts (arms, legs, etc.) + * * DROP_ITEMS - Gibbed mob will drop carried items (otherwise they get deleted) + * * DROP_ALL_REMAINS - Gibbed mob will drop everything +**/ +/mob/living/proc/gib(drop_bitflags=NONE) var/prev_lying = lying_angle if(stat != DEAD) death(TRUE) @@ -15,25 +17,46 @@ gib_animation() ghostize() - spill_organs(no_brain, no_organs, no_bodyparts, TRUE) //SKYRAT EDIT CHANGE - ORIGINAL: spill_organs(no_brain, no_organs, no_bodyparts) + spill_organs(drop_bitflags) - if(!no_bodyparts) - spread_bodyparts(no_brain, no_organs) + if(drop_bitflags & DROP_BODYPARTS) + spread_bodyparts(drop_bitflags) - spawn_gibs(no_bodyparts) - SEND_SIGNAL(src, COMSIG_LIVING_GIBBED, no_brain, no_organs, no_bodyparts) + spawn_gibs(drop_bitflags) + SEND_SIGNAL(src, COMSIG_LIVING_GIBBED, drop_bitflags) qdel(src) /mob/living/proc/gib_animation() return -/mob/living/proc/spawn_gibs() +/** + * Spawn bloody gib mess on the floor + * + * drop_bitflags: (see code/__DEFINES/blood.dm) + * * DROP_BODYPARTS - Gibs will spawn with bodypart limbs present +**/ +/mob/living/proc/spawn_gibs(drop_bitflags=NONE) new /obj/effect/gibspawner/generic(drop_location(), src, get_static_viruses()) -/mob/living/proc/spill_organs() +/** + * Drops a mob's organs on the floor + * + * drop_bitflags: (see code/__DEFINES/blood.dm) + * * DROP_BRAIN - Mob will drop a brain + * * DROP_ORGANS - Mob will drop organs + * * DROP_BODYPARTS - Mob will drop bodyparts (arms, legs, etc.) + * * DROP_ALL_REMAINS - Mob will drop everything +**/ +/mob/living/proc/spill_organs(drop_bitflags=NONE) return -/mob/living/proc/spread_bodyparts() +/** + * Launches all bodyparts away from the mob + * + * drop_bitflags: (see code/__DEFINES/blood.dm) + * * DROP_BRAIN - Detaches the head from the mob and launches it away from the body +**/ +/mob/living/proc/spread_bodyparts(drop_bitflags=NONE) return /** diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm index ae17e13f269..7445815c9d7 100644 --- a/code/modules/mob/living/silicon/ai/ai_defense.dm +++ b/code/modules/mob/living/silicon/ai/ai_defense.dm @@ -43,7 +43,7 @@ switch(severity) if(EXPLODE_DEVASTATE) investigate_log("has been gibbed by an explosion.", INVESTIGATE_DEATHS) - gib() + gib(DROP_ALL_REMAINS) if(EXPLODE_HEAVY) if (stat != DEAD) adjustBruteLoss(60) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 30559e616b5..fe28d41fe84 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -385,7 +385,7 @@ else explosion(src, devastation_range = -1, light_impact_range = 2) investigate_log("has self-destructed.", INVESTIGATE_DEATHS) - gib() + gib(DROP_ALL_REMAINS) /mob/living/silicon/robot/proc/UnlinkSelf() set_connected_ai(null) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index f820d3ca1cf..09440ec22a3 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -414,14 +414,14 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real adjustBruteLoss(30) else investigate_log("has been gibbed a blob.", INVESTIGATE_DEATHS) - gib() + gib(DROP_ALL_REMAINS) return TRUE /mob/living/silicon/robot/ex_act(severity, target) switch(severity) if(EXPLODE_DEVASTATE) investigate_log("has been gibbed by an explosion.", INVESTIGATE_DEATHS) - gib() + gib(DROP_ALL_REMAINS) return if(EXPLODE_HEAVY) if (stat != DEAD) diff --git a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm b/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm index cceb0cdf58c..6f5952382c6 100644 --- a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm +++ b/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm @@ -92,8 +92,8 @@ /mob/living/simple_animal/hostile/gorilla/CanSmashTurfs(turf/T) return iswallturf(T) -/mob/living/simple_animal/hostile/gorilla/gib(no_brain) - if(!no_brain) +/mob/living/simple_animal/hostile/gorilla/gib(drop_bitflags=DROP_BRAIN) + if(drop_bitflags & DROP_BRAIN) var/mob/living/brain/gorilla_brain = new(drop_location()) gorilla_brain.name = real_name gorilla_brain.real_name = real_name diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 8a92ca680f7..5c63ca4e884 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -607,7 +607,7 @@ holder_animal.mind.transfer_to(possessor) possessor.mind.grab_ghost(force = TRUE) holder_animal.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS) - holder_animal.gib() + holder_animal.gib(DROP_ALL_REMAINS) return ..() return ..() diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm index 58d9988256f..d91f312b454 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm @@ -211,7 +211,7 @@ mother.children_list -= src visible_message(span_warning("[src] explodes!")) explosion(src, flame_range = 3, adminlog = FALSE) - gib() + gib(DROP_ALL_REMAINS) /obj/effect/goliath_tentacle/broodmother grapple_time = 1 SECONDS diff --git a/code/modules/mob_spawn/ghost_roles/mining_roles.dm b/code/modules/mob_spawn/ghost_roles/mining_roles.dm index 98c6dbc6d45..9a1536a83d8 100644 --- a/code/modules/mob_spawn/ghost_roles/mining_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/mining_roles.dm @@ -207,7 +207,7 @@ yolk.underwear = "Nude" yolk.equipOutfit(/datum/outfit/ashwalker)//this is an authentic mess we're making yolk.update_body() - yolk.gib() + yolk.gib(DROP_ALL_REMAINS) QDEL_NULL(egg) return ..() diff --git a/code/modules/mod/modules/modules_ninja.dm b/code/modules/mod/modules/modules_ninja.dm index 90c731a7c36..7a38238594d 100644 --- a/code/modules/mod/modules/modules_ninja.dm +++ b/code/modules/mod/modules/modules_ninja.dm @@ -275,7 +275,7 @@ var/mob/living/living_user = user to_chat(living_user, span_danger("fATaL EERRoR: 382200-*#00CODE RED\nUNAUTHORIZED USE DETECteD\nCoMMENCING SUB-R0UTIN3 13...\nTERMInATING U-U-USER...")) living_user.investigate_log("has been gibbed by using a MODsuit equipped with [src].", INVESTIGATE_DEATHS) - living_user.gib() + living_user.gib(DROP_ALL_REMAINS) /obj/item/mod/module/dna_lock/reinforced/on_emp(datum/source, severity) return diff --git a/code/modules/power/apc/apc_malf.dm b/code/modules/power/apc/apc_malf.dm index f13b588842a..3b070368804 100644 --- a/code/modules/power/apc/apc_malf.dm +++ b/code/modules/power/apc/apc_malf.dm @@ -69,7 +69,7 @@ if(forced) occupier.forceMove(drop_location()) INVOKE_ASYNC(occupier, TYPE_PROC_REF(/mob/living, death)) - occupier.gib() + occupier.gib(DROP_ALL_REMAINS) if(!occupier.nuking) //Pinpointers go back to tracking the nuke disk, as long as the AI (somehow) isn't mid-nuking. for(var/obj/item/pinpointer/nuke/disk_pinpointers in GLOB.pinpointer_list) diff --git a/code/modules/projectiles/guns/ballistic/launchers.dm b/code/modules/projectiles/guns/ballistic/launchers.dm index 0b676ae3dfa..83c19bf9350 100644 --- a/code/modules/projectiles/guns/ballistic/launchers.dm +++ b/code/modules/projectiles/guns/ballistic/launchers.dm @@ -97,7 +97,7 @@ REMOVE_TRAIT(user, TRAIT_NO_TRANSFORM, REF(src)) process_fire(user, user, TRUE) if(!QDELETED(user)) //if they weren't gibbed by the explosion, take care of them for good. - user.gib() + user.gib(DROP_ALL_REMAINS) return MANUAL_SUICIDE else sleep(0.5 SECONDS) diff --git a/code/modules/projectiles/projectile/special/rocket.dm b/code/modules/projectiles/projectile/special/rocket.dm index 899f737d8cc..08a2c18c2f7 100644 --- a/code/modules/projectiles/projectile/special/rocket.dm +++ b/code/modules/projectiles/projectile/special/rocket.dm @@ -53,7 +53,7 @@ among other potential differences. This granularity is helpful for things like t if(random_crit_gib) var/mob/living/gibbed_dude = target new /obj/effect/temp_visual/crit(get_turf(gibbed_dude)) - gibbed_dude.gib() + gibbed_dude.gib(DROP_ALL_REMAINS) /// PM9 HEAP rocket - the anti-anything missile you always craved. /obj/projectile/bullet/rocket/heap diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index 56552fccf63..95dcf499528 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -855,4 +855,4 @@ span_userdanger("GORE! GORE! GORE! YOU'RE GORE! TOO MUCH GORE! YOU'RE GORE! GORE! IT'S OVER! GORE! GORE! YOU'RE GORE! TOO MUCH G-"), ) new /obj/structure/bouncy_castle(gored.loc, gored) - gored.gib(TRUE, TRUE, TRUE) //no brain, no organs, no bodyparts + gored.gib() diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index b632bc7b6c8..7afd6918261 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -584,7 +584,7 @@ var/location = get_turf(M) if(iscarbon(M)) if(ismonkey(M)) - M.gib() + M.gib(DROP_ALL_REMAINS) else M.vomit(VOMIT_CATEGORY_BLOOD) new /mob/living/carbon/human/species/monkey(location, TRUE) diff --git a/code/modules/religion/honorbound/honorbound_rites.dm b/code/modules/religion/honorbound/honorbound_rites.dm index 6ba557d5a30..c9c9e711354 100644 --- a/code/modules/religion/honorbound/honorbound_rites.dm +++ b/code/modules/religion/honorbound/honorbound_rites.dm @@ -59,7 +59,7 @@ if(joining_now.mind.has_antag_datum(/datum/antagonist/cult))//what the fuck?! to_chat(user, span_warning("[GLOB.deity] has seen a true, dark evil in [joining_now]'s heart, and they have been smitten!")) playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE) - joining_now.gib(TRUE) + joining_now.gib(DROP_ORGANS|DROP_BODYPARTS) return FALSE var/datum/brain_trauma/special/honorbound/honor = user.has_trauma_type(/datum/brain_trauma/special/honorbound) if(joining_now in honor.guilty) diff --git a/code/modules/research/anomaly/anomaly_core.dm b/code/modules/research/anomaly/anomaly_core.dm index 56220956182..febb25add53 100644 --- a/code/modules/research/anomaly/anomaly_core.dm +++ b/code/modules/research/anomaly/anomaly_core.dm @@ -23,7 +23,7 @@ /obj/item/assembly/signaler/anomaly/manual_suicide(mob/living/carbon/user) user.visible_message(span_suicide("[user]'s [src] is reacting to the radio signal, warping [user.p_their()] body!")) user.set_suicide(TRUE) - user.gib() + user.gib(DROP_ALL_REMAINS) /obj/item/assembly/signaler/anomaly/attack_self() return diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index f81f328c0f3..b3945fe60c4 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -460,7 +460,7 @@ to_chat(user, span_userdanger("You explode!")) explosion(user, devastation_range = 1, heavy_impact_range = 3, light_impact_range = 6, explosion_cause = src) user.investigate_log("has been gibbed by an oil slime extract explosion.", INVESTIGATE_DEATHS) - user.gib() + user.gib(DROP_ALL_REMAINS) return to_chat(user, span_notice("You stop feeding [src], and the feeling passes.")) diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index ca49d579272..7c8b26b5d16 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -35,7 +35,7 @@ All ShuttleMove procs go here SSblackbox.record_feedback("tally", "shuttle_gib", 1, M.type) log_shuttle("[key_name(M)] was shuttle gibbed by [shuttle].") M.investigate_log("has been gibbed by [shuttle].", INVESTIGATE_DEATHS) - M.gib() + M.gib(DROP_ALL_REMAINS) else //non-living mobs shouldn't be affected by shuttles, which is why this is an else diff --git a/code/modules/spells/spell_types/shapeshift/_shape_status.dm b/code/modules/spells/spell_types/shapeshift/_shape_status.dm index 10d42760c91..94e1d549af2 100644 --- a/code/modules/spells/spell_types/shapeshift/_shape_status.dm +++ b/code/modules/spells/spell_types/shapeshift/_shape_status.dm @@ -115,7 +115,7 @@ // Our caster inside was gibbed, mirror the gib to our mob if(gibbed) - owner.gib() + owner.gib(DROP_ALL_REMAINS) // Otherwise our caster died, just make our mob die else diff --git a/code/modules/spells/spell_types/shapeshift/_shapeshift.dm b/code/modules/spells/spell_types/shapeshift/_shapeshift.dm index a5e590685c0..5aecd863bce 100644 --- a/code/modules/spells/spell_types/shapeshift/_shapeshift.dm +++ b/code/modules/spells/spell_types/shapeshift/_shapeshift.dm @@ -132,7 +132,7 @@ // Gib our caster, and make sure to leave nothing behind // (If we leave something behind, it'll drop on the turf of the pipe, which is kinda wrong.) cast_on.investigate_log("has been gibbed by shapeshifting while ventcrawling.", INVESTIGATE_DEATHS) - cast_on.gib(TRUE, TRUE, TRUE) + cast_on.gib() /// Callback for the radial that allows the user to choose their species. /datum/action/cooldown/spell/shapeshift/proc/check_menu(mob/living/caster) diff --git a/code/modules/spells/spell_types/touch/smite.dm b/code/modules/spells/spell_types/touch/smite.dm index bcd234979c6..f02ea8247dd 100644 --- a/code/modules/spells/spell_types/touch/smite.dm +++ b/code/modules/spells/spell_types/touch/smite.dm @@ -48,7 +48,7 @@ return TRUE victim.investigate_log("has been gibbed by the smite spell.", INVESTIGATE_DEATHS) - victim.gib() + victim.gib(DROP_ALL_REMAINS) return TRUE /obj/item/melee/touch_attack/smite diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index fdb53c47572..0652c554b8a 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -323,7 +323,7 @@ if(!ai.linked_core) // we probably shouldnt gib AIs with a core unlucky_ai = occupant ai.investigate_log("has been gibbed by having their mech destroyed.", INVESTIGATE_DEATHS) - ai.gib() //No wreck, no AI to recover + ai.gib(DROP_ALL_REMAINS) //No wreck, no AI to recover else mob_exit(ai,silent = TRUE, forced = TRUE) // so we dont ghost the AI continue diff --git a/code/modules/vehicles/mecha/combat/savannah_ivanov.dm b/code/modules/vehicles/mecha/combat/savannah_ivanov.dm index dae449d8388..e3926aa7d35 100644 --- a/code/modules/vehicles/mecha/combat/savannah_ivanov.dm +++ b/code/modules/vehicles/mecha/combat/savannah_ivanov.dm @@ -212,7 +212,7 @@ to_chat(crushed_victim, span_userdanger("[chassis] crashes down on you from above!")) if(crushed_victim.stat != CONSCIOUS) crushed_victim.investigate_log("has been gibbed by a falling Savannah Ivanov mech.", INVESTIGATE_DEATHS) - crushed_victim.gib(FALSE, FALSE, FALSE) + crushed_victim.gib(DROP_ALL_REMAINS) continue crushed_victim.adjustBruteLoss(80) diff --git a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm index 6aae4adaaee..de96f3ad5f6 100644 --- a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm @@ -122,7 +122,7 @@ SEND_SIGNAL(src, COMSIG_MECHA_DRILL_MOB, chassis, target) else target.investigate_log("has been gibbed by [src] (attached to [chassis]).", INVESTIGATE_DEATHS) - target.gib() + target.gib(DROP_ALL_REMAINS) else //drill makes a hole var/obj/item/bodypart/target_part = target.get_bodypart(target.get_random_valid_zone(BODY_ZONE_CHEST)) diff --git a/code/modules/vehicles/mecha/mecha_mob_interaction.dm b/code/modules/vehicles/mecha/mecha_mob_interaction.dm index c5f440ac97e..07b13a27ec0 100644 --- a/code/modules/vehicles/mecha/mecha_mob_interaction.dm +++ b/code/modules/vehicles/mecha/mecha_mob_interaction.dm @@ -120,7 +120,7 @@ if(forced)//This should only happen if there are multiple AIs in a round, and at least one is Malf. if(!AI.linked_core) //if the victim AI has no core AI.investigate_log("has been gibbed by being forced out of their mech by another AI.", INVESTIGATE_DEATHS) - AI.gib() //If one Malf decides to steal a mech from another AI (even other Malfs!), they are destroyed, as they have nowhere to go when replaced. + AI.gib(DROP_ALL_REMAINS) //If one Malf decides to steal a mech from another AI (even other Malfs!), they are destroyed, as they have nowhere to go when replaced. AI = null mecha_flags &= ~SILICON_PILOT return diff --git a/code/modules/vehicles/vehicle_key.dm b/code/modules/vehicles/vehicle_key.dm index e1b45d55f0a..f6e5f7c4e28 100644 --- a/code/modules/vehicles/vehicle_key.dm +++ b/code/modules/vehicles/vehicle_key.dm @@ -41,7 +41,7 @@ switch(user.mind?.get_skill_level(/datum/skill/cleaning)) if(SKILL_LEVEL_NONE to SKILL_LEVEL_NOVICE) //Their mind is too weak to ascend as a janny user.visible_message(span_suicide("[user] is putting \the [src] in [user.p_their()] mouth and is trying to become one with the janicart, but has no idea where to start! It looks like [user.p_theyre()] trying to commit suicide!")) - user.gib() + user.gib(DROP_ALL_REMAINS) return MANUAL_SUICIDE if(SKILL_LEVEL_APPRENTICE to SKILL_LEVEL_JOURNEYMAN) //At least they tried user.visible_message(span_suicide("[user] is putting \the [src] in [user.p_their()] mouth and has inefficiently become one with the janicart! It looks like [user.p_theyre()] trying to commit suicide!")) diff --git a/code/modules/wiremod/shell/drone.dm b/code/modules/wiremod/shell/drone.dm index dce5dca46ad..6f7afcfea04 100644 --- a/code/modules/wiremod/shell/drone.dm +++ b/code/modules/wiremod/shell/drone.dm @@ -32,7 +32,7 @@ /mob/living/circuit_drone/updatehealth() . = ..() if(health < 0) - gib(no_brain = TRUE, no_organs = TRUE, no_bodyparts = TRUE) + gib() /mob/living/circuit_drone/welder_act(mob/living/user, obj/item/tool) . = ..() diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index 65716c0dbfa..dca26d366d8 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -74,7 +74,7 @@ if(target.stat == DEAD) var/hp_gained = target.maxHealth target.investigate_log("has been devoured by a zombie.", INVESTIGATE_DEATHS) - target.gib() + target.gib(DROP_ALL_REMAINS) var/need_mob_update need_mob_update = user.adjustBruteLoss(-hp_gained, updating_health = FALSE) need_mob_update += user.adjustToxLoss(-hp_gained, updating_health = FALSE) diff --git a/modular_skyrat/master_files/code/modules/mob/living/carbon/death.dm b/modular_skyrat/master_files/code/modules/mob/living/carbon/death.dm index b2d6c975652..e7c3348e585 100644 --- a/modular_skyrat/master_files/code/modules/mob/living/carbon/death.dm +++ b/modular_skyrat/master_files/code/modules/mob/living/carbon/death.dm @@ -1,18 +1,11 @@ // By temporarily removing the unspillable organs before calling the parent proc we can avoid Skyrat edits and make this less likely to break in the future -/mob/living/carbon/spill_organs(no_brain, no_organs, no_bodyparts, gibbed = FALSE) +/mob/living/carbon/spill_organs(drop_bitflags) var/list/held_organs = list() for(var/obj/item/organ/organ as anything in organs) if(!organ.drop_when_organ_spilling) held_organs.Add(organ) organs.Remove(organ) - // Organs always get spilled when the mob is gibbed - if(gibbed) - for(var/deleting_organ in held_organs) - qdel(deleting_organ) - - return ..() - . = ..() // put the unspillable organs back diff --git a/modular_skyrat/master_files/code/modules/mob/living/carbon/human/death.dm b/modular_skyrat/master_files/code/modules/mob/living/carbon/human/death.dm index b40e30ca8f8..7889b4f391c 100644 --- a/modular_skyrat/master_files/code/modules/mob/living/carbon/human/death.dm +++ b/modular_skyrat/master_files/code/modules/mob/living/carbon/human/death.dm @@ -1,8 +1,8 @@ // Pocket contents fly out when gibbed -/mob/living/carbon/human/gib(no_brain, no_organs, no_bodyparts, safe_gib = FALSE) - if(safe_gib) // we are just going to drop everything regardless +/mob/living/carbon/human/gib(drop_bitflags=NONE) + if(drop_bitflags & DROP_ITEMS) // we are just going to drop everything regardless return ..() - if(no_bodyparts) // don't drop any items when the mob is being reduced to a paste + if(!(drop_bitflags & DROP_BODYPARTS)) // don't drop any items when the mob is being reduced to a paste return ..() var/obj/item/left_pocket = l_store From a8691d6aa2f70234b9030547c014263f55378dd1 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Mon, 9 Oct 2023 21:37:42 +0200 Subject: [PATCH 006/100] exodrone adventures are no longer database based [MDB IGNORE] (#24112) * exodrone adventures are no longer database based * Fixes version numbers * Update tgstation_schema.sql --------- Co-authored-by: jimmyl <70376633+mc-oofert@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- SQL/database_changelog.md | 9 +- SQL/tgstation_schema.sql | 13 - code/modules/explorer_drone/adventure.dm | 92 +-- .../example_adventures/a_model_earth.json | 570 ------------------ code/modules/explorer_drone/manager.dm | 60 +- strings/exoadventures/britain_replica.json | 570 ++++++++++++++++++ strings/exoadventures/quantum_fizzics.json | 195 ++++++ strings/exoadventures/robots_wingman.json | 369 ++++++++++++ strings/exoadventures/space_yacht.json | 257 ++++++++ .../tree_in_the_middle_of_space.json | 0 .../tgui/interfaces/AdventureBrowser.tsx | 121 +--- 11 files changed, 1443 insertions(+), 813 deletions(-) delete mode 100644 code/modules/explorer_drone/example_adventures/a_model_earth.json create mode 100644 strings/exoadventures/britain_replica.json create mode 100644 strings/exoadventures/quantum_fizzics.json create mode 100644 strings/exoadventures/robots_wingman.json create mode 100644 strings/exoadventures/space_yacht.json rename code/modules/explorer_drone/example_adventures/Theres_a_tree_in_the_middle_of_space.json => strings/exoadventures/tree_in_the_middle_of_space.json (100%) diff --git a/SQL/database_changelog.md b/SQL/database_changelog.md index ae588adf65d..b0f6ad08b25 100644 --- a/SQL/database_changelog.md +++ b/SQL/database_changelog.md @@ -2,7 +2,7 @@ Any time you make a change to the schema files, remember to increment the databa Make sure to also update `DB_MAJOR_VERSION` and `DB_MINOR_VERSION`, which can be found in `code/__DEFINES/subsystem.dm`. -The latest database version is 5.25 (5.24 for /tg/); The query to update the schema revision table is: +The latest database version is 5.27 (5.25 for /tg/); The query to update the schema revision table is: ```sql INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 25); @@ -15,6 +15,13 @@ INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 25); In any query remember to add a prefix to the table names if you use one. +----------------------------------------------------- +Version 5.27, 27 September 2023, by Jimmyl +Removes the text_adventures table because it is no longer used +```sql + DROP TABLE IF EXISTS `text_adventures`; +``` + ----------------------------------------------------- Version 5.26, 17 May 2023, by LemonInTheDark Modified the library action table to fit ckeys properly, and to properly store ips. diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index ecc615880e8..0637e0da6f6 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -660,19 +660,6 @@ CREATE TABLE `game_log` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; --- --- Table structure for table `text_adventures` --- -DROP TABLE IF EXISTS `text_adventures`; -CREATE TABLE `text_adventures` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `adventure_data` LONGTEXT NOT NULL, - `uploader` VARCHAR(32) NOT NULL, - `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `approved` TINYINT(1) NOT NULL DEFAULT FALSE, - PRIMARY KEY (`id`) -) ENGINE=InnoDB; - -- -- Table structure for table `admin_connections` -- diff --git a/code/modules/explorer_drone/adventure.dm b/code/modules/explorer_drone/adventure.dm index 9718d6d5a49..56d83000f90 100644 --- a/code/modules/explorer_drone/adventure.dm +++ b/code/modules/explorer_drone/adventure.dm @@ -43,6 +43,7 @@ #define REQ_OPERATOR_FIELD "operator" #define CURRENT_ADVENTURE_VERSION 1 +#define ADVENTURE_LOOK_PATH "strings/exoadventures/" /// All possible adventures in raw form GLOBAL_LIST_EMPTY(explorer_drone_adventure_db_entries) @@ -50,34 +51,22 @@ GLOBAL_LIST_EMPTY(explorer_drone_adventure_db_entries) /// Loads all adventures from DB /proc/load_adventures() . = list() - if(!SSdbcore.Connect()) - GLOB.explorer_drone_adventure_db_entries = . - return - var/datum/db_query/Query = SSdbcore.NewQuery("SELECT id,adventure_data,uploader,timestamp,approved FROM [format_table_name("text_adventures")]") - if(!Query.Execute()) - qdel(Query) - return - while(Query.NextRow()) + for(var/filename in flist(ADVENTURE_LOOK_PATH)) + var/raw_json = file2text(ADVENTURE_LOOK_PATH + filename) + var/list/json_decoded = json_decode(raw_json) var/datum/adventure_db_entry/entry = new() - entry.id = Query.item[1] - entry.raw_json = Query.item[2] - entry.uploader = Query.item[3] - entry.timestamp = Query.item[4] - entry.approved = Query.item[5] + entry.filename = filename + entry.raw_json = raw_json + entry.uploader = json_decoded["author"] entry.extract_metadata() . += entry - qdel(Query) GLOB.explorer_drone_adventure_db_entries = . /datum/adventure_db_entry - /// db id or null for freshly created adventures - var/id + /// filename of the adventure + var/filename /// actual adventure json string var/raw_json - /// ckey of last change user. - var/uploader - /// Time of last change. - var/timestamp /// Unapproved adventures won't be used for exploration sites. var/approved = FALSE /// Was the adventure used for exploration site this round. @@ -85,6 +74,8 @@ GLOBAL_LIST_EMPTY(explorer_drone_adventure_db_entries) //Variables below are extracted from the JSON + /// whoever made the json + var/uploader /// json version var/version /// adventure name @@ -100,61 +91,13 @@ GLOBAL_LIST_EMPTY(explorer_drone_adventure_db_entries) return FALSE return TRUE -/// Updates this entry from db, if possible. -/datum/adventure_db_entry/proc/refresh() - if(id) - //Check if our timestamp is fresh, if not update local and stop - var/datum/db_query/SelectQuery = SSdbcore.NewQuery("SELECT adventure_data,uploader,timestamp,approved FROM [format_table_name("text_adventures")] WHERE id = :id",list("id" = id)) - if(!SelectQuery.warn_execute() || !SelectQuery.NextRow()) - qdel(SelectQuery) - return - raw_json = SelectQuery.item[1] - uploader = SelectQuery.item[2] - timestamp = SelectQuery.item[3] - approved = SelectQuery.item[4] - extract_metadata() - qdel(SelectQuery) - return - // No ID, nothing to be done. - -/// Pushes this entry changes to DB -/datum/adventure_db_entry/proc/save() - if(id) - //We're up to date, update db instead - var/datum/db_query/UpdateQuery = SSdbcore.NewQuery("UPDATE [format_table_name("text_adventures")] SET adventure_data = :adventure_data,uploader = :uploader,approved = :approved WHERE id = :id AND timestamp < NOW()", - list("id" = id, "adventure_data" = raw_json, "uploader" = usr.ckey, "approved" = approved)) - UpdateQuery.warn_execute() - qdel(UpdateQuery) - else - // Create new entry - var/datum/db_query/InsertQuery = SSdbcore.NewQuery("INSERT INTO [format_table_name("text_adventures")] (adventure_data, uploader) VALUES (:raw_json, :uploader)", list("raw_json" = raw_json, "uploader" = usr.ckey)) - if(!InsertQuery.warn_execute()) - qdel(InsertQuery) - return FALSE - id = InsertQuery.last_insert_id - qdel(InsertQuery) - refresh() - -/// Deletes the local AND db entry. -/datum/adventure_db_entry/proc/remove() - if(id) - var/datum/db_query/DelQuery = SSdbcore.NewQuery("DELETE FROM [format_table_name("text_adventures")] WHERE id = :id", list("id" = id)) - if(!DelQuery.warn_execute()) - qdel(DelQuery) - return FALSE - log_admin("[key_name(usr)] deleted text adventure with id : [id], name : [name]") - qdel(DelQuery) - GLOB.explorer_drone_adventure_db_entries -= src - qdel(src) - return TRUE - /// Extracts fields that are used by adventure browser / generation before instantiating /datum/adventure_db_entry/proc/extract_metadata() if(!raw_json) CRASH("Trying to extract metadata from empty adventure") var/list/json_data = json_decode(raw_json) if(!islist(json_data)) - CRASH("Invalid JSON for adventure with db id:[id]") + CRASH("Invalid JSON for adventure with at path:[filename]") version = json_data[ADVENTURE_VERSION_FIELD] || 0 name = json_data[ADVENTURE_NAME_FIELD] required_site_traits = json_data[ADVENTURE_REQUIRED_SITE_TRAITS_FIELD] @@ -169,13 +112,13 @@ GLOBAL_LIST_EMPTY(explorer_drone_adventure_db_entries) /datum/adventure_db_entry/proc/try_loading_adventure() var/list/json_data = json_decode(raw_json) if(!islist(json_data)) - CRASH("Invalid JSON in adventure with id:[id], name:[name]") + CRASH("Invalid JSON in adventure with path:[filename], name:[name]") //Basic validation of required fields, don't even bother loading if they are missing. var/static/list/required_fields = list(ADVENTURE_NAME_FIELD,ADVENTURE_STARTING_NODE_FIELD,ADVENTURE_NODES_FIELD) for(var/field in required_fields) if(!json_data[field]) - CRASH("Adventure id:[id], name:[name] missing [field] value") + CRASH("Adventure path:[filename], name:[name] missing [field] value") var/datum/adventure/loaded_adventure = new //load properties @@ -191,16 +134,16 @@ GLOBAL_LIST_EMPTY(explorer_drone_adventure_db_entries) var/datum/adventure_node/node = try_loading_node(node_data) if(node) if(loaded_adventure.nodes[node.id]) - CRASH("Duplicate [node.id] node in id:[id], name:[name] adventure") + CRASH("Duplicate [node.id] node in path:[filename], name:[name] adventure") loaded_adventure.nodes[node.id] = node loaded_adventure.triggers = json_data[ADVENTURE_TRIGGERS_FIELD] if(!loaded_adventure.validate()) - CRASH("Validation failed for id:[id], name:[name] adventure") + CRASH("Validation failed for path:[filename], name:[name] adventure") return loaded_adventure /datum/adventure_db_entry/proc/try_loading_node(node_data) if(!islist(node_data)) - CRASH("Invalid adventure node data in id:[id], name:[name] adventure.") + CRASH("Invalid adventure node data in path:[filename], name:[name] adventure.") var/datum/adventure_node/fresh_node = new fresh_node.id = node_data[NODE_NAME_FIELD] fresh_node.description = node_data[NODE_DESCRIPTION_FIELD] @@ -493,6 +436,7 @@ GLOBAL_LIST_EMPTY(explorer_drone_adventure_db_entries) if("exists") return qkey in qualities +#undef ADVENTURE_LOOK_PATH #undef ADVENTURE_VERSION_FIELD #undef CURRENT_ADVENTURE_VERSION diff --git a/code/modules/explorer_drone/example_adventures/a_model_earth.json b/code/modules/explorer_drone/example_adventures/a_model_earth.json deleted file mode 100644 index 908080b5834..00000000000 --- a/code/modules/explorer_drone/example_adventures/a_model_earth.json +++ /dev/null @@ -1,570 +0,0 @@ -{ - "adventure_name": "A Model Earth", - "version": 1, - "author": "Armhulen", - "starting_node": "Planet Start", - "starting_qualities": { - "Long Range Scan Report": 0, - "UFOs Shot Down": 0 - }, - "required_site_traits": [ - "in space" - ], - "loot_categories": [ - "research" - ], - "scan_band_mods": {}, - "deep_scan_description": "", - "triggers": [], - "nodes": [ - { - "name": "Planet Start", - "description": "You come across a grey planet. It looks familiar, though you swore you've never come across this sector of space before.", - "choices": [ - { - "key": "choice 0", - "name": "Ignore the planet.", - "exit_node": "FAIL", - "delay": 0, - "delay_message": "Whatever, there's a lot of planets in space. Must be a hunch!" - }, - { - "key": "choice 1", - "name": "Begin Orbital Scan", - "exit_node": "Scanning from Orbit", - "requirements": [ - { - "quality": "Long Range Scan Report", - "operator": "==", - "value": 0 - } - ], - "delay": 30, - "delay_message": "Scanning planet..." - }, - { - "key": "choice 8", - "name": "Descend Into Orbit", - "exit_node": "Orbital Descent", - "delay": 30, - "delay_message": "Descending into Orbit..." - } - ], - "image": null, - "raw_image": "data:image/png;base64,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" - }, - { - "name": "Scanning from Orbit", - "description": "You initiate a long range scan from orbit:\nThis planet has a smoggy cover that blocks any good look at the surface, yet it has a mostly survivable atmosphere.\nThis planet has zero life signs.\n", - "choices": [ - { - "key": "choice 9", - "name": "Stash that Report...", - "exit_node": "Planet Start", - "delay": 0 - } - ], - "image": null, - "on_enter_effects": [ - { - "effect_type": "Add", - "quality": "Long Range Scan Report", - "value": 1 - } - ], - "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkBAMAAAAxqGI4AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAASUExURQAAAP///1lWUqwyMmlqakZHRwPX/kkAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAL5SURBVGje7ZldbqMwFIXtKnkvO4huyAYmG0CWea8i2P9Wxv/Y2MTYvjBVO4c8FET8+dxzDW5Ldqr73Hcf7fbemfwu+p1tkM+jILTbfeu2stNbDDSkklXnzNRbyUqUqbM/oVr5AFhOus5iUK3A/fmEW0BRHjCtwFPqj6NQS6GIVu5PTXEXnJUOjfLxXEOITYWitXECQk6BUOx6pSDkKAj4F6mrFxLEdNctAdl8gJVmBRBXy6tXcrScwwvXsufikXIP1qId5t2iz0D4osFClAga5MJDDbJaEUDJjF6eyZohxATjlhym9kkcMzhkIBQJ0g+pe2klJFWtG4DrgRSkeEUkjDDWA09TbPJdM6RXnySlDnLpYyO9/GhtQChthYhSMXeyup0aSFkoCYirVqJkdcnHEMaXakVeHIQUQYBPwSFdMB86IEBYolrAtyi1kF4asOIT40Ekq4JVQvS0R3UYI5G5GFLYwuKRO3l69dMEkxnc5MR8K6RCF9VL2sioe2tdLc6GRggROUDve5lcA9usXpw0So4Go5OwE0YySqutED33eZKH12TSyJJTK0RNFx6LFb4yMiI4uajJQmxlWT3tTsybEfxUnA0t9miGmNnCY54DMxNiJu7V6HLx89BO2iHLhIUXPxUleWVjf1SiZbvCHkEuLqX0brIM4hUfwkxERkKvdiPhxksGw3UuNpERmpuLeKGoBRM8k5WP/gsBsnrkAphUVGOJHeuIwPBDMcks6vmAUazkbtjXgAIhqVW+QHAYZHxnBIkRheKbGbAgJH6NIAcitWFlwmQQck28EzEDUdqwQnClrIxH+pA63od1EpgpHiP7i3ccSjEj/yd258SYqendLCR0UfcCyUK0B9KkbCYNBnZLRzIcC9HNdSzDODkYoraOB0eim+vgSIjcKM4HM06J5Hqak1Mi+d9ce3VGc5Ef01zXM5pLQN46oR0O5G0kKP+9nM+CfP1rSDqTwqTqmqvQX91SLINcvzGkLJPrCev9HMj8oyDk10MI+Qt3vM7Ve2h01AAAAABJRU5ErkJggg==" - }, - { - "name": "Orbital Descent", - "description": "As you descend into orbit, you see a flying object headed straight for you!\nA garbled voice begins to call out to your drone, but there's no time to decipher it!", - "choices": [ - { - "key": "choice 2", - "name": "Blast the damn UFO!", - "exit_node": "Tractor Beam", - "on_selection_effects": [ - { - "effect_type": "Add", - "quality": "Tractor Beam Turns", - "value": 2 - }, - { - "effect_type": "Add", - "quality": "UFOs Shot Down", - "value": 1 - } - ], - "delay": 30, - "delay_message": "Blasting UFO!" - }, - { - "key": "choice 3", - "name": "Attempt Evasive Maneuvers!", - "exit_node": "UFO Evasion!", - "on_selection_effects": [ - { - "effect_type": "Add", - "quality": "UFOs Violently Crashed Into", - "value": { - "value_type": "random", - "low": 0, - "high": 1 - } - } - ], - "delay": 30, - "delay_message": "You attempt to dodge the UFO..." - }, - { - "key": "choice 7", - "name": "Do NOTHING. Jesus take the wheel!", - "exit_node": "FAIL_DEATH", - "delay": 30, - "delay_message": "What? Why?!" - } - ], - "image": null, - "on_enter_effects": [ - { - "effect_type": "Add", - "quality": "Garbled Transmissions", - "value": 1 - } - ], - "raw_image": "data:image/png;base64,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" - }, - { - "name": "UFO Evasion!", - "description": "Were you good enough at flying to avoid the UFO?", - "choices": [ - { - "key": "choice 4", - "name": "No, Back to flight school with you!", - "exit_node": "FAIL_DEATH", - "requirements": [ - { - "quality": "UFOs Violently Crashed Into", - "operator": "==", - "value": 1 - } - ], - "delay": 0 - }, - { - "key": "choice 5", - "name": "You barely avoided them! Nice!", - "exit_node": "Tractor Beam", - "on_selection_effects": [ - { - "effect_type": "Add", - "quality": "Tractor Beam Turns", - "value": 2 - } - ], - "requirements": [ - { - "quality": "UFOs Violently Crashed Into", - "operator": "==", - "value": 0 - } - ], - "delay": 0 - } - ], - "image": "default" - }, - { - "name": "Tractor Beam", - "description": "Before you have time to think, your drone is captured by a Tractor beam! Now you've gone and done it.\n\nYou should have some time before you are pulled in.", - "choices": [ - { - "key": "choice 6", - "name": "Decipher Garbled Transmission", - "exit_node": "Deciphering Transmission", - "requirements": [ - { - "quality": "Garbled Transmissions", - "operator": "==", - "value": 1 - }, - { - "quality": "Tractor Beam Turns", - "operator": ">", - "value": 1 - } - ], - "delay": 30, - "delay_message": "Decipering..." - }, - { - "key": "choice 10", - "name": "Look at the surface of the planet", - "exit_node": "Looking at the Surface", - "requirements": [ - { - "quality": "Tractor Beam Turns", - "operator": ">", - "value": 1 - } - ], - "delay": 10, - "delay_message": "Looking out window..." - }, - { - "key": "choice 13", - "name": "Let the beam pull you in and dock you", - "exit_node": "Landed, Kinda", - "on_selection_effects": [ - { - "effect_type": "Set", - "quality": "Tractor Beam Turns", - "value": 0 - } - ], - "delay": 50, - "delay_message": "Getting captured..." - } - ], - "image": null, - "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAIOUlEQVR4Ae2dW5JcNwiGewdZQNbgbcTbyFM27ZXk6aTkmDJDIXSDIySYqi5dQQL+r0/PeGx//vnxPPnKHKQGeA18SmJqX5k0PmmZlzh5+dTgoPMpijiiyFr/rnU3IBSYMs5EZg5u18ASIAlNApKAcBRMzN2eyIzvzjcL9SfICDspqjtFdVNdtwKCYbopqRnLb/BxjXH/lBy5AQQnr/RPSWD0e9K69Y5PyZtbQHCie5KJ95d+j03uGc8TzfPs+JTcHwEILgJNLF5r9altjvsBaeV2dP2U3B8HyGgh6P5TCuPpnjSHGmNP8Ul3SUDyd9HEj6MaMHA+JFF6WktAEhAWEE7UmnOeIJDukoAkIF8A0YRA8iWJ0tNaOEBK0TwVwNNdJEFrr3mKW7pLApJPkJ9vGNoAtPxJovS0loAkIAmIoIEEREiOp3cy67u03vG9rFvngfoPBwhNQI7//57MCwAr97CoZQKST5AtH7FWQBixXYUmFCCrybrZfkR0J+8dreH1gIwmJOr+k0W/cvdWva8EpBV0rvN/FrQitNtsQSPXAAIBZcuLvycvt4lcIx7x38XSOMDKR0/Bc88YLFa1OtnvT0BASN4CgXtlOyb0lXx508Du+3wBBBL7xqXgrFPbv75/fyxfu/LyRu1POoMFBIpjGQiccVJrCUTL95t5sqz7ab5FQKAo2kGB31PalnjfXn8jb9o1P9VfFyC0ILPBUj/ex28Lf/Q86/zN1vkmuylArAuz2/+oUL3t18yfpdjLPb1/JSDod7G8CX31PhqgaAuY3knbv7a/BOQXIKti9GpPBTkzXhFdz3kr/q1tE5Afj/jj2m/fvj1Wr7eg6hFpa09LiC17ab3le+d6aEA4gVrB0OuXu5PGnCTQ3Ws7AWidHRYQKrpeAe/YR+86O94NgnR+S6i71sMBUhPXDuFrnlmLC89LAvWwtgsC6dxQgGCx4L6mUHf7wnFxfQ8g1O4gCXXXWhhAOLHsFrPl+Vy8Za4mTk/zu2Dgzr0eEE4olsL04puLG+Y8wdBzF064b81dDQgIgrZeRGx9Dxo3jHtE6XXPG2Dg2K8FBMRAW2tRevJPY8djLIIT+1qgtGK/EhAsBNr3JGDru9DY8bgljFPWR0CZiek6QLAIuL61KD355+KHuRmxRLS5ChAovtR6ErD1XaQ8RBT7TMzXACKJga5ZC9OLfxo3Hs+IJaLNFYDgwvf0vQjY8h6tPEQU+0zMIQEB8VgKdLdviLHWzoglos3xgNQE0Jp//vzjgZemmD+fz4Nfmr57fbViL+sRxT4Tc0hAAAzNFkPB9XvFvbKvBwzYMyOWiDZHAwLFHmk1ocC+OCjwHN5r1R/JQ0Sxz8QcChArYWIQpL7V+eA3AdH/FyjDAAIismglKPCaxdngM+HQh6M8cY4FZEQQICKrFkMg9a3OL35H8jHzUSOqTQKCfpo1K2AJCrw267/HLgHJJ8iXH02OCKJHYKt7MAhcf9W/ZD+Si6hPgtm48wmi8AQp4uWgwHOSwFfXEhCbp0eBKgQgRUCrIuy1x1CUfq/dyr4EJAH58vGqkD0iCrp3RYwebWl8tfHsx4zIdmGeIDXReBT86J1qsXHzkcU+E/uxgJRgOQFozI0KdOf+mXhnhBLVJgHp+K/UdgLQOnsGkGITVfCjcR8NSAl2ViBadi0BW66vxjAqloj7jwfEAyScUD2Dge8bUfQjMV8BiFdIsBChvwoO+NFsRwQTbe/RgPz79/Pgl6ZoovmKJvzeeI8EBEPB9aOJWzPeXuFE2XccIBwQdA6KpymcSL4gf9ke9qsmFARpTIsbSeCrsdLcRR4f8wSRYODWpKKuCiiCvZS/SGtHAMIB0JqDItJ9ME/bCKIfjZHmKOLYPSBU4FrjVrFHxXTr/laebl93DYgWDJyflcJ6gIHGZHmnlVydbusWECoAi7F28SxFCr5beYB92q12rk7x5xKQlgi01nuKRM/qsaF7tMRK78KNtc6ifmhMUcahASkCqxWaEx+eq9nReWwjnUft6Jj6kcZU3FpjeqcIY3eASIW3WKsVuXVWzQ7mV+3BT2lbvui6FhCcH3yvCH1XgNBCvzXGhR45E9vRfssP3c+NWz5q65ywNee4u946l4Cgj1k1wdXma6Ko7afzq/bUH4w1YeB8wf8LWLv/TfNuAIHi7mhLQWfO5YQw4ofaj9jW9nKCtpgDSHBL47lh7AKQWrG9z1MBjN4X24/a1vaDTwsosE8MRq0Pdzm53Q5IrdAnzEPhZ+9a7GdtOTu4D7RY0Bb9Ghi1ebjXSe1WQLginzRXCu3lvpzoilAtwACfNRB657k7e5tLQMjfSuwV/AlwgFBB0Not+NdqvcFR7rMNkF4h5j75KcWJihOsNhzgjztLY46La8fcFkBS9LLoe/LDiaUlTBC1Zts6U2udi/eNuQRk8iNWj4gt9tRE0SNETTDAV8+5WntqsVvOvw6IhWgi+JRE0CtAELVm23u2xj4pB1ZrrwISQcgWMUrFrwmP3gP2acJRfL35JeXBai0BcfwRSyp6TZgUDDo+DRApB2+svQYILVSO5W/Ua8WvgVHme3LqHZBa3LvmExCHTxAJgtpaDxywxyskuyCQzn0FEChMtvK7fE38rfnRvCYg9b8oR2ExB2S0eFH3tyCorc/kyyMgVJhexgnI5o9YNeH3zM/AUWy8AeIFBu4epoDMFvBtu5KYt88s5618zd63nKkNSPG38sUJ08tcaECgCLNiW7FbEdTquZ4AgRp4bcMCgguyIrhR2xUwiu3oeXg/nJ2AOPkmHRfHU/9EOFbzB3BA6wUSXAuP/f8AHPtbaN2iPfwAAAAASUVORK5CYII=" - }, - { - "name": "Deciphering Transmission", - "description": "You review the incoming transmissions your drone has gotten. These aren't in need of deciphering, just un-garbling it from the bad connection...\n\n\"You are in Space British Air Space! Identify yourself, Tally ho!\"\nWhat the fuck?", - "choices": [ - { - "key": "choice 11", - "name": "Whoops!", - "exit_node": "Tractor Beam", - "delay": 0, - "requirements": [ - { - "quality": "UFOs Shot Down", - "operator": "==", - "value": 1 - } - ] - }, - { - "key": "choice 12", - "name": "Good thing I didn't blast them, then.", - "exit_node": "Tractor Beam", - "delay": 0, - "requirements": [ - { - "quality": "UFOs Shot Down", - "operator": "==", - "value": 0 - } - ] - } - ], - "image": null, - "on_enter_effects": [ - { - "effect_type": "Add", - "quality": "Commercial Airliner Transmissions", - "value": 1 - } - ], - "raw_image": "data:image/png;base64,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" - }, - { - "name": "Landed, Kinda", - "description": "You have been locked to the surface the beam. Robots are all around you, pointing at your drone with all sorts of old age weapons.\n\nOne of them angrily shouts at you, \"By God, Queen and Country, we've got you now!\"", - "choices": [ - { - "key": "choice 14", - "name": "Go out with a bang. Initiate self destruct!", - "exit_node": "FAIL", - "delay": 0 - }, - { - "key": "choice 15", - "name": "Surrender to the funny looking robot brits...", - "exit_node": "British Courtroom Start", - "delay": 50, - "delay_message": "You are being transported somewhere..." - } - ], - "image": null, - "raw_image": "data:image/png;base64,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" - }, - { - "name": "British Courtroom Start", - "description": "Wow, that took forever. A one eye judge robot smacks their gavel, and points their hammer at you.\n\"I will now read out the crimes you are accused of!\"\nIs that how the judicial process works? You dunno.\n\"ONE ACCOUNT OF PLANETARY TRESSPASS!\"\nThis blows.", - "choices": [ - { - "key": "choice 16", - "name": "That's not that bad.", - "exit_node": "British Courtroom, Continued...", - "on_selection_effects": [ - { - "effect_type": "Add", - "quality": "Crimes Committed", - "value": 1 - } - ], - "delay": 0 - } - ], - "image": null, - "raw_image": "data:image/png;base64,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" - }, - { - "name": "British Courtroom, Continued...", - "description": "This big idiot they call a judge just keeps piling on crimes. With each one, some robot you'd like to drone-punch gasps in the back.", - "choices": [ - { - "key": "choice 17", - "name": "\"INTRUSIVE SCANNING ON OUR CITIZENS\"", - "exit_node": "British Courtroom, Continued...", - "on_selection_effects": [ - { - "effect_type": "Add", - "quality": "Long Range Scan Report", - "value": -1 - }, - { - "effect_type": "Add", - "quality": "Crimes Committed", - "value": 1 - } - ], - "requirements": [ - { - "quality": "Long Range Scan Report", - "operator": ">", - "value": 0 - } - ], - "delay": 0 - }, - { - "key": "choice 18", - "name": "\"SHOOTING DOWN A COMMERCIAL AIRLINER\"", - "exit_node": "British Courtroom, Continued...", - "on_selection_effects": [ - { - "effect_type": "Add", - "quality": "UFOs Shot Down", - "value": -1 - }, - { - "effect_type": "Add", - "quality": "Crimes Committed", - "value": 1 - } - ], - "requirements": [ - { - "quality": "UFOs Shot Down", - "operator": "==", - "value": 1 - } - ], - "delay": 0 - }, - { - "key": "choice 19", - "name": "\"AND WE HAVE PROOF YOU KNEW IT WAS JUST AN AIRLINER!\"", - "exit_node": "British Courtroom, Continued...", - "on_selection_effects": [ - { - "effect_type": "Add", - "quality": "Commercial Airliner Transmissions", - "value": -1 - }, - { - "effect_type": "Add", - "quality": "Crimes Committed", - "value": 1 - } - ], - "requirements": [ - { - "quality": "Commercial Airliner Transmissions", - "operator": "==", - "value": 1 - } - ], - "delay": 0 - }, - { - "key": "choice 20", - "name": "\"THE TRANSMISSIONS WERE NOT LEGIBLE AND UNTRANSLATED. WE CANNOT PROVE MALICE!\"", - "exit_node": "British Courtroom, Continued...", - "on_selection_effects": [ - { - "effect_type": "Add", - "quality": "Garbled Transmissions", - "value": -1 - } - ], - "requirements": [ - { - "quality": "Garbled Transmissions", - "operator": "==", - "value": 1 - } - ], - "delay": 0 - }, - { - "key": "choice 24", - "name": "I think it's done listing crimes, thank god. Time to argue my case.", - "exit_node": "Verdict", - "requirements": [ - { - "quality": "Long Range Scan Report", - "operator": "==", - "value": 0 - }, - { - "group_type": "AND", - "requirements": [ - { - "quality": "Garbled Transmissions", - "operator": "==", - "value": 0 - }, - { - "quality": "Commercial Airliner Transmissions", - "operator": "!=", - "value": 1 - } - ] - }, - { - "quality": "UFOs Shot Down", - "operator": "!=", - "value": 1 - } - ], - "delay": 0 - } - ], - "image": null, - "raw_image": "data:image/png;base64,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" - }, - { - "name": "Looking at the Surface", - "description": "The surface of this world looks exactly like a grey version of Earth! It seems to be an exact replica of some kind.\n\nYou see creatures moving around on the streets", - "choices": [ - { - "key": "choice 21", - "name": "Cool!", - "exit_node": "Tractor Beam", - "delay": 0 - }, - { - "key": "choice 22", - "name": "Scan the creatures.", - "exit_node": "Robo Brits!", - "delay": 30, - "delay_message": "Scanning..." - } - ], - "image": null, - "raw_image": "data:image/png;base64,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" - }, - { - "name": "Robo Brits!", - "description": "Wow, they're robotic humanoids that look and act exactly like the British! You see some robots laughing and chatting at a pub, and a Bobby walking down the street looking for crooks. Who created this earth replica? You only know Earth from the books, but you should be where London is!", - "choices": [ - { - "key": "choice 23", - "name": "Nice! Well, back to getting pulled in by a Tractor beam...", - "exit_node": "Tractor Beam", - "delay": 0 - } - ], - "image": null, - "on_enter_effects": [ - { - "effect_type": "Add", - "quality": "Long Range Scan Report", - "value": 1 - } - ], - "raw_image": "data:image/png;base64,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" - }, - { - "name": "Verdict", - "description": "Before even getting to defend your case, the judge says \"I've heard ENOUGH! It's time for a verdict!\"\nDang! You're definitely in kangaroo court!\n\"GUILTY! AND YOUR SENTENCE IS:\"", - "choices": [ - { - "key": "choice 25", - "name": "\"DEATH!\"", - "exit_node": "FAIL_DEATH", - "requirements": [ - { - "quality": "Crimes Committed", - "operator": ">=", - "value": 4 - } - ], - "delay": 0 - }, - { - "key": "choice 26", - "name": "\"SPACE JAIL!\"", - "exit_node": "Not Actually Space Jail, Just Normal Jail", - "requirements": [ - { - "quality": "Crimes Committed", - "operator": ">", - "value": 1 - } - ], - "delay": 20, - "delay_message": "You are being jailed..." - }, - { - "key": "choice 27", - "name": "\"FORGIVENESS! Just trespass? That's not that bad!\"", - "exit_node": "Sweet Sweet Freedom!", - "requirements": [ - { - "quality": "Crimes Committed", - "operator": "==", - "value": 1 - } - ], - "delay": 10, - "delay_message": "WOOP WOOP" - } - ], - "image": "default" - }, - { - "name": "Not Actually Space Jail, Just Normal Jail", - "description": "You'll have to wait out your crimes against the robo brits.", - "choices": [ - { - "key": "choice 28", - "name": "Sit out your sentence", - "exit_node": "Sweet Sweet Freedom!", - "delay": 1200, - "delay_message": "Sitting out your sentence..." - } - ], - "image": null, - "raw_image": "data:image/png;base64,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" - }, - { - "name": "Sweet Sweet Freedom!", - "description": "You're free! You spend a good while travelling around England (or at least the replica) and enjoying the cuisine, people and culture! Good society research is gained from this or something, but really you're just enjoying the sights and sounds.", - "choices": [ - { - "key": "choice 29", - "name": "Nice!", - "exit_node": "WIN", - "delay": 0 - } - ], - "image": null, - "raw_image": "data:image/png;base64,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" - } - ] - } diff --git a/code/modules/explorer_drone/manager.dm b/code/modules/explorer_drone/manager.dm index 74a972216a4..9ca85ca4a20 100644 --- a/code/modules/explorer_drone/manager.dm +++ b/code/modules/explorer_drone/manager.dm @@ -24,27 +24,7 @@ if(.) return feedback_message = "" - var/mob/user = usr switch(action) - if("create") - var/datum/adventure_db_entry/new_entry = new - new_entry.name = "New Adventure" - new_entry.uploader = user.ckey - GLOB.explorer_drone_adventure_db_entries += new_entry - return TRUE - if("delete") - var/datum/adventure_db_entry/target = locate(params["ref"]) in GLOB.explorer_drone_adventure_db_entries - if(!target) - return - if(!target.remove()) - feedback_message = "Failed to remove adventure" - return TRUE - if("approve") - var/datum/adventure_db_entry/target = locate(params["ref"]) in GLOB.explorer_drone_adventure_db_entries - if(!target) - return - target.approved = !target.approved - return TRUE if("play") var/datum/adventure_db_entry/target = locate(params["ref"]) in GLOB.explorer_drone_adventure_db_entries if(!target) @@ -67,43 +47,6 @@ QDEL_NULL(temp_adventure) feedback_message = "Adventure stopped" return TRUE - if("refresh") - var/datum/adventure_db_entry/target = locate(params["ref"]) in GLOB.explorer_drone_adventure_db_entries - if(!target) - return - target.refresh() - return TRUE - if("save") - var/datum/adventure_db_entry/target = locate(params["ref"]) in GLOB.explorer_drone_adventure_db_entries - if(!target) - return - target.save() - return TRUE - if("download") - var/datum/adventure_db_entry/target = locate(params["ref"]) in GLOB.explorer_drone_adventure_db_entries - if(!target) - return - var/temp_file = file("data/AdventureDownloadTempFile") - fdel(temp_file) - WRITE_FILE(temp_file, target.raw_json) - user << ftp(temp_file,"[target.name].json") - return TRUE - if("upload") - var/datum/adventure_db_entry/target = locate(params["ref"]) in GLOB.explorer_drone_adventure_db_entries - if(!target) - return - var/source_json = input(user,"Select adventure JSON file.","Adventure Upload") as file|null - if(!source_json) - return - var/raw_json = file2text(source_json) - var/json = json_decode(raw_json) - if(!json) - feedback_message = "Decoding JSON failed." - return - //do basic validation here - target.raw_json = raw_json - target.extract_metadata() - return TRUE /datum/adventure_browser/ui_data(mob/user) . = ..() @@ -111,11 +54,10 @@ for(var/datum/adventure_db_entry/db_entry in GLOB.explorer_drone_adventure_db_entries) adventure_data += list(list( "ref" = ref(db_entry), - "id" = db_entry.id, + "filename" = db_entry.filename, "name" = db_entry.name, "version" = db_entry.version, "uploader" = db_entry.uploader, - "timestamp" = db_entry.timestamp, "approved" = db_entry.approved, "json_status" = db_entry.raw_json ? "Valid JSON" : "Empty" )) diff --git a/strings/exoadventures/britain_replica.json b/strings/exoadventures/britain_replica.json new file mode 100644 index 00000000000..0bfaa67e990 --- /dev/null +++ b/strings/exoadventures/britain_replica.json @@ -0,0 +1,570 @@ +{ + "adventure_name": "A Model Earth", + "version": 1, + "author": "Armhulen", + "starting_node": "Planet Start", + "starting_qualities": { + "Long Range Scan Report": 0, + "UFOs Shot Down": 0 + }, + "required_site_traits": [ + "in space" + ], + "loot_categories": [ + "research" + ], + "scan_band_mods": {}, + "deep_scan_description": "", + "triggers": [], + "nodes": [ + { + "name": "Planet Start", + "description": "You come across a grey planet. It looks familiar, though you swore you've never come across this sector of space before.", + "choices": [ + { + "key": "choice 0", + "name": "Ignore the planet.", + "exit_node": "FAIL", + "delay": 0, + "delay_message": "Whatever, there's a lot of planets in space. Must be a hunch!" + }, + { + "key": "choice 1", + "name": "Begin Orbital Scan", + "exit_node": "Scanning from Orbit", + "requirements": [ + { + "quality": "Long Range Scan Report", + "operator": "==", + "value": 0 + } + ], + "delay": 30, + "delay_message": "Scanning planet..." + }, + { + "key": "choice 8", + "name": "Descend Into Orbit", + "exit_node": "Orbital Descent", + "delay": 30, + "delay_message": "Descending into Orbit..." + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "Scanning from Orbit", + "description": "You initiate a long range scan from orbit:\nThis planet has a smoggy cover that blocks any good look at the surface, yet it has a mostly survivable atmosphere.\nThis planet has zero life signs.\n", + "choices": [ + { + "key": "choice 9", + "name": "Stash that Report...", + "exit_node": "Planet Start", + "delay": 0 + } + ], + "image": null, + "on_enter_effects": [ + { + "effect_type": "Add", + "quality": "Long Range Scan Report", + "value": 1 + } + ], + "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkBAMAAAAxqGI4AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAASUExURQAAAP///1lWUqwyMmlqakZHRwPX/kkAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAL5SURBVGje7ZldbqMwFIXtKnkvO4huyAYmG0CWea8i2P9Wxv/Y2MTYvjBVO4c8FET8+dxzDW5Ldqr73Hcf7fbemfwu+p1tkM+jILTbfeu2stNbDDSkklXnzNRbyUqUqbM/oVr5AFhOus5iUK3A/fmEW0BRHjCtwFPqj6NQS6GIVu5PTXEXnJUOjfLxXEOITYWitXECQk6BUOx6pSDkKAj4F6mrFxLEdNctAdl8gJVmBRBXy6tXcrScwwvXsufikXIP1qId5t2iz0D4osFClAga5MJDDbJaEUDJjF6eyZohxATjlhym9kkcMzhkIBQJ0g+pe2klJFWtG4DrgRSkeEUkjDDWA09TbPJdM6RXnySlDnLpYyO9/GhtQChthYhSMXeyup0aSFkoCYirVqJkdcnHEMaXakVeHIQUQYBPwSFdMB86IEBYolrAtyi1kF4asOIT40Ekq4JVQvS0R3UYI5G5GFLYwuKRO3l69dMEkxnc5MR8K6RCF9VL2sioe2tdLc6GRggROUDve5lcA9usXpw0So4Go5OwE0YySqutED33eZKH12TSyJJTK0RNFx6LFb4yMiI4uajJQmxlWT3tTsybEfxUnA0t9miGmNnCY54DMxNiJu7V6HLx89BO2iHLhIUXPxUleWVjf1SiZbvCHkEuLqX0brIM4hUfwkxERkKvdiPhxksGw3UuNpERmpuLeKGoBRM8k5WP/gsBsnrkAphUVGOJHeuIwPBDMcks6vmAUazkbtjXgAIhqVW+QHAYZHxnBIkRheKbGbAgJH6NIAcitWFlwmQQck28EzEDUdqwQnClrIxH+pA63od1EpgpHiP7i3ccSjEj/yd258SYqendLCR0UfcCyUK0B9KkbCYNBnZLRzIcC9HNdSzDODkYoraOB0eim+vgSIjcKM4HM06J5Hqak1Mi+d9ce3VGc5Ef01zXM5pLQN46oR0O5G0kKP+9nM+CfP1rSDqTwqTqmqvQX91SLINcvzGkLJPrCev9HMj8oyDk10MI+Qt3vM7Ve2h01AAAAABJRU5ErkJggg==" + }, + { + "name": "Orbital Descent", + "description": "As you descend into orbit, you see a flying object headed straight for you!\nA garbled voice begins to call out to your drone, but there's no time to decipher it!", + "choices": [ + { + "key": "choice 2", + "name": "Blast the damn UFO!", + "exit_node": "Tractor Beam", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Tractor Beam Turns", + "value": 2 + }, + { + "effect_type": "Add", + "quality": "UFOs Shot Down", + "value": 1 + } + ], + "delay": 30, + "delay_message": "Blasting UFO!" + }, + { + "key": "choice 3", + "name": "Attempt Evasive Maneuvers!", + "exit_node": "UFO Evasion!", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "UFOs Violently Crashed Into", + "value": { + "value_type": "random", + "low": 0, + "high": 1 + } + } + ], + "delay": 30, + "delay_message": "You attempt to dodge the UFO..." + }, + { + "key": "choice 7", + "name": "Do NOTHING. Jesus take the wheel!", + "exit_node": "FAIL_DEATH", + "delay": 30, + "delay_message": "What? Why?!" + } + ], + "image": null, + "on_enter_effects": [ + { + "effect_type": "Add", + "quality": "Garbled Transmissions", + "value": 1 + } + ], + "raw_image": "data:image/png;base64,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" + }, + { + "name": "UFO Evasion!", + "description": "Were you good enough at flying to avoid the UFO?", + "choices": [ + { + "key": "choice 4", + "name": "No, Back to flight school with you!", + "exit_node": "FAIL_DEATH", + "requirements": [ + { + "quality": "UFOs Violently Crashed Into", + "operator": "==", + "value": 1 + } + ], + "delay": 0 + }, + { + "key": "choice 5", + "name": "You barely avoided them! Nice!", + "exit_node": "Tractor Beam", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Tractor Beam Turns", + "value": 2 + } + ], + "requirements": [ + { + "quality": "UFOs Violently Crashed Into", + "operator": "==", + "value": 0 + } + ], + "delay": 0 + } + ], + "image": "default" + }, + { + "name": "Tractor Beam", + "description": "Before you have time to think, your drone is captured by a Tractor beam! Now you've gone and done it.\n\nYou should have some time before you are pulled in.", + "choices": [ + { + "key": "choice 6", + "name": "Decipher Garbled Transmission", + "exit_node": "Deciphering Transmission", + "requirements": [ + { + "quality": "Garbled Transmissions", + "operator": "==", + "value": 1 + }, + { + "quality": "Tractor Beam Turns", + "operator": ">", + "value": 1 + } + ], + "delay": 30, + "delay_message": "Decipering..." + }, + { + "key": "choice 10", + "name": "Look at the surface of the planet", + "exit_node": "Looking at the Surface", + "requirements": [ + { + "quality": "Tractor Beam Turns", + "operator": ">", + "value": 1 + } + ], + "delay": 10, + "delay_message": "Looking out window..." + }, + { + "key": "choice 13", + "name": "Let the beam pull you in and dock you", + "exit_node": "Landed, Kinda", + "on_selection_effects": [ + { + "effect_type": "Set", + "quality": "Tractor Beam Turns", + "value": 0 + } + ], + "delay": 50, + "delay_message": "Getting captured..." + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "Deciphering Transmission", + "description": "You review the incoming transmissions your drone has gotten. These aren't in need of deciphering, just un-garbling it from the bad connection...\n\n\"You are in Space British Air Space! Identify yourself, Tally ho!\"\nWhat the fuck?", + "choices": [ + { + "key": "choice 11", + "name": "Whoops!", + "exit_node": "Tractor Beam", + "delay": 0, + "requirements": [ + { + "quality": "UFOs Shot Down", + "operator": "==", + "value": 1 + } + ] + }, + { + "key": "choice 12", + "name": "Good thing I didn't blast them, then.", + "exit_node": "Tractor Beam", + "delay": 0, + "requirements": [ + { + "quality": "UFOs Shot Down", + "operator": "==", + "value": 0 + } + ] + } + ], + "image": null, + "on_enter_effects": [ + { + "effect_type": "Add", + "quality": "Commercial Airliner Transmissions", + "value": 1 + } + ], + "raw_image": "data:image/png;base64,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" + }, + { + "name": "Landed, Kinda", + "description": "You have been locked to the surface the beam. Robots are all around you, pointing at your drone with all sorts of old age weapons.\n\nOne of them angrily shouts at you, \"By God, Queen and Country, we've got you now!\"", + "choices": [ + { + "key": "choice 14", + "name": "Go out with a bang. Initiate self destruct!", + "exit_node": "FAIL", + "delay": 0 + }, + { + "key": "choice 15", + "name": "Surrender to the funny looking robot brits...", + "exit_node": "British Courtroom Start", + "delay": 50, + "delay_message": "You are being transported somewhere..." + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "British Courtroom Start", + "description": "Wow, that took forever. A one eye judge robot smacks their gavel, and points their hammer at you.\n\"I will now read out the crimes you are accused of!\"\nIs that how the judicial process works? You dunno.\n\"ONE ACCOUNT OF PLANETARY TRESSPASS!\"\nThis blows.", + "choices": [ + { + "key": "choice 16", + "name": "That's not that bad.", + "exit_node": "British Courtroom, Continued...", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Crimes Committed", + "value": 1 + } + ], + "delay": 0 + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "British Courtroom, Continued...", + "description": "This big idiot they call a judge just keeps piling on crimes. With each one, some robot you'd like to drone-punch gasps in the back.", + "choices": [ + { + "key": "choice 17", + "name": "\"INTRUSIVE SCANNING ON OUR CITIZENS\"", + "exit_node": "British Courtroom, Continued...", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Long Range Scan Report", + "value": -1 + }, + { + "effect_type": "Add", + "quality": "Crimes Committed", + "value": 1 + } + ], + "requirements": [ + { + "quality": "Long Range Scan Report", + "operator": ">", + "value": 0 + } + ], + "delay": 0 + }, + { + "key": "choice 18", + "name": "\"SHOOTING DOWN A COMMERCIAL AIRLINER\"", + "exit_node": "British Courtroom, Continued...", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "UFOs Shot Down", + "value": -1 + }, + { + "effect_type": "Add", + "quality": "Crimes Committed", + "value": 1 + } + ], + "requirements": [ + { + "quality": "UFOs Shot Down", + "operator": "==", + "value": 1 + } + ], + "delay": 0 + }, + { + "key": "choice 19", + "name": "\"AND WE HAVE PROOF YOU KNEW IT WAS JUST AN AIRLINER!\"", + "exit_node": "British Courtroom, Continued...", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Commercial Airliner Transmissions", + "value": -1 + }, + { + "effect_type": "Add", + "quality": "Crimes Committed", + "value": 1 + } + ], + "requirements": [ + { + "quality": "Commercial Airliner Transmissions", + "operator": "==", + "value": 1 + } + ], + "delay": 0 + }, + { + "key": "choice 20", + "name": "\"THE TRANSMISSIONS WERE NOT LEGIBLE AND UNTRANSLATED. WE CANNOT PROVE MALICE!\"", + "exit_node": "British Courtroom, Continued...", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Garbled Transmissions", + "value": -1 + } + ], + "requirements": [ + { + "quality": "Garbled Transmissions", + "operator": "==", + "value": 1 + } + ], + "delay": 0 + }, + { + "key": "choice 24", + "name": "I think it's done listing crimes, thank god. Time to argue my case.", + "exit_node": "Verdict", + "requirements": [ + { + "quality": "Long Range Scan Report", + "operator": "==", + "value": 0 + }, + { + "group_type": "AND", + "requirements": [ + { + "quality": "Garbled Transmissions", + "operator": "==", + "value": 0 + }, + { + "quality": "Commercial Airliner Transmissions", + "operator": "!=", + "value": 1 + } + ] + }, + { + "quality": "UFOs Shot Down", + "operator": "!=", + "value": 1 + } + ], + "delay": 0 + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "Looking at the Surface", + "description": "The surface of this world looks exactly like a grey version of Earth! It seems to be an exact replica of some kind.\n\nYou see creatures moving around on the streets", + "choices": [ + { + "key": "choice 21", + "name": "Cool!", + "exit_node": "Tractor Beam", + "delay": 0 + }, + { + "key": "choice 22", + "name": "Scan the creatures.", + "exit_node": "Robo Brits!", + "delay": 30, + "delay_message": "Scanning..." + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "Robo Brits!", + "description": "Wow, they're robotic humanoids that look and act exactly like the British! You see some robots laughing and chatting at a pub, and a Bobby walking down the street looking for crooks. Who created this earth replica? You only know Earth from the books, but you should be where London is!", + "choices": [ + { + "key": "choice 23", + "name": "Nice! Well, back to getting pulled in by a Tractor beam...", + "exit_node": "Tractor Beam", + "delay": 0 + } + ], + "image": null, + "on_enter_effects": [ + { + "effect_type": "Add", + "quality": "Long Range Scan Report", + "value": 1 + } + ], + "raw_image": "data:image/png;base64,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" + }, + { + "name": "Verdict", + "description": "Before even getting to defend your case, the judge says \"I've heard ENOUGH! It's time for a verdict!\"\nDang! You're definitely in kangaroo court!\n\"GUILTY! AND YOUR SENTENCE IS:\"", + "choices": [ + { + "key": "choice 25", + "name": "\"DEATH!\"", + "exit_node": "FAIL_DEATH", + "requirements": [ + { + "quality": "Crimes Committed", + "operator": ">=", + "value": 4 + } + ], + "delay": 0 + }, + { + "key": "choice 26", + "name": "\"SPACE JAIL!\"", + "exit_node": "Not Actually Space Jail, Just Normal Jail", + "requirements": [ + { + "quality": "Crimes Committed", + "operator": ">", + "value": 1 + } + ], + "delay": 20, + "delay_message": "You are being jailed..." + }, + { + "key": "choice 27", + "name": "\"FORGIVENESS! Just trespass? That's not that bad!\"", + "exit_node": "Sweet Sweet Freedom!", + "requirements": [ + { + "quality": "Crimes Committed", + "operator": "==", + "value": 1 + } + ], + "delay": 10, + "delay_message": "WOOP WOOP" + } + ], + "image": "default" + }, + { + "name": "Not Actually Space Jail, Just Normal Jail", + "description": "You'll have to wait out your crimes against the robo brits.", + "choices": [ + { + "key": "choice 28", + "name": "Sit out your sentence", + "exit_node": "Sweet Sweet Freedom!", + "delay": 1200, + "delay_message": "Sitting out your sentence..." + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "Sweet Sweet Freedom!", + "description": "You're free! You spend a good while travelling around England (or at least the replica) and enjoying the cuisine, people and culture! Good society research is gained from this or something, but really you're just enjoying the sights and sounds.", + "choices": [ + { + "key": "choice 29", + "name": "Nice!", + "exit_node": "WIN", + "delay": 0 + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + } + ] +} \ No newline at end of file diff --git a/strings/exoadventures/quantum_fizzics.json b/strings/exoadventures/quantum_fizzics.json new file mode 100644 index 00000000000..0ee9bf9bf68 --- /dev/null +++ b/strings/exoadventures/quantum_fizzics.json @@ -0,0 +1,195 @@ +{ + "adventure_name": "Quantum Fizz-ics", + "version": 1, + "author": "EOBGames", + "starting_node": "start", + "starting_qualities": { + "jammed": 0 + }, + "required_site_traits": [ + "technology present", + "in space" + ], + "loot_categories": [ + "unique" + ], + "scan_band_mods": { + "Narrow-band radio waves": 10 + }, + "deep_scan_description": "", + "triggers": [], + "nodes": [ + { + "name": "start", + "description": "As you sweep through the inky void and the site comes into view, you're puzzled by what you see. On a small asteroid sits a vending machine. Despite the odd runes lining its surface, you're fairly certain that the image on the front is a can of soda. While ordinary common sense would dictate that drinking strange alien soda is a bad idea, you can't help but be curious about what exactly this machine dispenses. There's one problem, however- what currency does this thing take?", + "choices": [ + { + "key": "choice 0", + "name": "Leave.", + "exit_node": "FAIL", + "delay": 10, + "delay_message": "There are better ways to die than drinking alien soda." + }, + { + "key": "choice 1", + "name": "Try a holocredit chit.", + "exit_node": "it's_stuck", + "requirements": [ + { + "quality": "jammed", + "operator": "!=", + "value": 1 + } + ], + "delay": 10, + "delay_message": "Hopefully whoever made this machine is part of the Galactic Currency Union..." + }, + { + "key": "choice 4", + "name": "Ram the machine.", + "exit_node": "smashing", + "delay": 30, + "delay_message": "Ramming speed!" + }, + { + "key": "choice 5", + "name": "Search around for some loose change.", + "exit_node": "lost_wallet", + "requirements": [ + { + "quality": "have_coin", + "operator": "!=", + "value": 1 + } + ], + "delay": 100, + "delay_message": "There's a surprising amount of stuff on this asteroid to search..." + }, + { + "key": "choice 6", + "name": "Use the coin you found.", + "exit_node": "choices_choices", + "requirements": [ + { + "quality": "jammed", + "operator": "==", + "value": 0 + }, + { + "quality": "have_coin", + "operator": "==", + "value": 1 + } + ], + "delay": 10, + "delay_message": "Thank God for clumsy aliens!" + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "it's_stuck", + "description": "Well, only one way to find out, right? You produce a holocredit chit (helpfully taken from the science budget, I'm sure they won't miss it) and jam it into the slot. Then, you realise your mistake, as it sticks in the slot. Whoops. Time to try the old fashioned way, I suppose.", + "choices": [ + { + "key": "choice 2", + "name": "Time to try something a bit more daring?", + "exit_node": "start", + "on_selection_effects": [ + { + "effect_type": "Set", + "quality": "jammed", + "value": 1 + } + ], + "delay": 10, + "delay_message": "In hindsight, why would this accept human currency, anyway?" + } + ], + "image": null, + "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAAAXNSR0IArs4c6QAAAjVJREFUeJzt3cFyogAUAEGzlf//5ewpF0pGRJDnbvc1CkhleAbEfN1ut58bcNefqzcAJhMIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUD4vnLlW/854tdJz5+2HWuWy9+6HWdt77P/1PLo7d27H/cwQSBcMkFePSI8e+T5WXncUctZWlvP1uef5V2vd+9y1p7/aD1nMkEgvHWCTDgiXOH3dU6ZJNNN+j0xQSBcehZrae3siCPtff/aJJo0OX6ZIBBGTZDle3XuW+6fq/fXo/W/ev3H3yAw1FsnyP96Nues99ZTJu7R11PWJqTrIDDM1+3CA9CUz0BN2Y410z+Ltfdxz/780frOYIJAuHSCwHQmCASBQBAIhFFX0pfefZbq0XKPupPu2eW9+2zSVmctZxITBMLoCbK09069s86vT7uTca+j9s/E6xivMkEgfNQEWZr62a6jPiN19evABIH00RNkqq33Rywn36PHv7penmeCQDBBXvDqkX/rdZKjvp+K55kgED56glz9LRhn39/B9UwQCB81QfZemd36HvxdR/azzmLtNW3/TGKCQHBHIQQTBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBMJfgqJi1hru29AAAAAASUVORK5CYII=" + }, + { + "name": "lost_wallet", + "description": "Searching around, you come across a lost wallet in a small crater. Flipping it open, inside you find a family photo of 3 identical looking grey aliens in comically different outfits, an (expired) credit card for a bank you've never heard of, a loyalty card to McDonkalds, and, in the coin pouch, a single black coin with glowing purple lines. This is (presumably) what you're looking for.", + "choices": [ + { + "key": "choice 3", + "name": "Return to the machine with the coin.", + "exit_node": "start", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "have_coin", + "value": 1 + } + ], + "delay": 10, + "delay_message": "It doesn't count as theft if you found it, right?" + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "choices_choices", + "description": "You slip the coin into the slot- it's a perfect fit. Now comes the hard part: picking a button on the machine to press.", + "choices": [ + { + "key": "choice 7", + "name": "The red looking soda.", + "exit_node": "cha_clunk", + "delay": 10, + "delay_message": "How exciting..." + }, + { + "key": "choice 9", + "name": "The yellow looking soda.", + "exit_node": "cha_clunk", + "delay": 10, + "delay_message": "How exciting..." + }, + { + "key": "choice 10", + "name": "The green looking soda.", + "exit_node": "cha_clunk", + "delay": 10, + "delay_message": "How exciting..." + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "cha_clunk", + "description": "With a satisfying cha-clunk, your fizzy prize drops into the tray. You swipe it, and move on from the site.", + "choices": [ + { + "key": "choice 11", + "name": "Sweet, sugary victory.", + "exit_node": "WIN", + "delay": 10, + "delay_message": "Hopefully this doesn't like, freeze solid in space. That would be bad, right?" + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "smashing", + "description": "You maneuver the drone into position and begin ramming it into the machine. The machine sways and shakes, and just as you think it may be getting somewhere, it falls directly onto your drone. Now, not only do you not have any soda, but you don't have a drone, either. Dummy.", + "choices": [ + { + "key": "choice 8", + "name": "Disconnect.", + "exit_node": "FAIL_DEATH", + "delay": 10, + "delay_message": "Don't feel too bad, it happens to the best of us sometimes." + } + ], + "image": null, + "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAAAXNSR0IArs4c6QAAAjVJREFUeJzt3cFyogAUAEGzlf//5ewpF0pGRJDnbvc1CkhleAbEfN1ut58bcNefqzcAJhMIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUD4vnLlW/854tdJz5+2HWuWy9+6HWdt77P/1PLo7d27H/cwQSBcMkFePSI8e+T5WXncUctZWlvP1uef5V2vd+9y1p7/aD1nMkEgvHWCTDgiXOH3dU6ZJNNN+j0xQSBcehZrae3siCPtff/aJJo0OX6ZIBBGTZDle3XuW+6fq/fXo/W/ev3H3yAw1FsnyP96Nues99ZTJu7R11PWJqTrIDDM1+3CA9CUz0BN2Y410z+Ltfdxz/780frOYIJAuHSCwHQmCASBQBAIhFFX0pfefZbq0XKPupPu2eW9+2zSVmctZxITBMLoCbK09069s86vT7uTca+j9s/E6xivMkEgfNQEWZr62a6jPiN19evABIH00RNkqq33Rywn36PHv7penmeCQDBBXvDqkX/rdZKjvp+K55kgED56glz9LRhn39/B9UwQCB81QfZemd36HvxdR/azzmLtNW3/TGKCQHBHIQQTBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBMJfgqJi1hru29AAAAAASUVORK5CYII=" + } + ] +} \ No newline at end of file diff --git a/strings/exoadventures/robots_wingman.json b/strings/exoadventures/robots_wingman.json new file mode 100644 index 00000000000..2958fbb6a4e --- /dev/null +++ b/strings/exoadventures/robots_wingman.json @@ -0,0 +1,369 @@ +{ + "adventure_name": "Robot's Wingman", + "version": 1, + "author": "Lucky Luther", + "starting_node": "Date Start", + "starting_qualities": { + "Love": 3 + }, + "required_site_traits": [ + "in space" + ], + "loot_categories": [ + "trade_contract" + ], + "scan_band_mods": { + "Narrow-band radio waves": 2 + }, + "deep_scan_description": "", + "triggers": [ + { + "name": "True Love", + "target_node": "Love Birds", + "requirements": [ + { + "quality": "Love", + "operator": ">=", + "value": 7 + } + ] + }, + { + "name": "Complete Failure", + "target_node": "Obliteration", + "requirements": [ + { + "quality": "Love", + "operator": "<=", + "value": 0 + } + ] + } + ], + "nodes": [ + { + "name": "Date Start", + "description": "Cameras Online. A Blood-Red Drone is seen streaking through the stars.\nThe Drone is likely leaving behind some form of Chem Trail to brainwash Nanotrasen Employees who find themselves in the void.", + "choices": [ + { + "key": "choice 0", + "name": "Hail other Drone", + "exit_node": "First Contact", + "delay": 5, + "delay_message": "Attempting to signal Drone..." + }, + { + "key": "choice 1", + "name": "Ignore other Drone", + "exit_node": "FAIL", + "delay": 0 + } + ], + "image": null, + "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAD/0lEQVR4nO3duXnbQBBA4YE/d6CACSMmasFO1IDbUkluQJHUgnIlCFgDHIHmsYD2mD1m9/2JFCgABTwsFhcnEVkEgNOP2gsAtIxAgB0EAuwgEGDH8IEsC+cosM0rkF43ovVz9fr5kO7bQHreiKZpuvkJ3JvE4zrIsixsRBiSVyDAqIafpAN7CATYQSDADgJJ9H481l4EOGiddSWQBGscRNIWzUsTBBLpOorfX18VlwT3NK9vEUik19NJRIijVVrX7QgkwJ+Xl8vP8zw747B6x4HV5c6NC4We1jhERM7zLB+fnw9/c72RWbrzwOpyl2BmBKm5h7uOQ0Tk6XBw/p3Ve7usLncJJkaQ2nu4X8/Pm1GIiPx9e2Pj6tTP2gvgY5qmqjdMPh0Ocp7nm0jO83z5vfbyIR8TI0gt78ejvJ5ONzGssYjIwzyESPpDIBtc1znWQ62tSboIkfTGzCS9pK2LgGsUW3GI/D/cQh8YQTa8H4+b1zl8RghGkj4QSISQSEQ4fWoZgUQKGSEYTewikAShkVwjGBsIJFHs6LA3kSeedhCIAu1DKEabdhCIkpwTcoKph0CUlZiQc3asHALJoNQen1DyI5ACck/Iez+NXPPzOQPp/R/eEq3RptfRpPajDg+B1F6g0aUG0+POjREEN1yHZCHrg/WnhzlIo+438tBDKCLRQSDGcA9YWQRiUMhoQiRpCMQwnk3JjycKDfN9epGnHOMRiHFEkheBdIBI8iGQThBJHgTSESLRRyCdIRJdBNIhNn49BNIpn0gI6XsE0jEiSUcgnSOSNAQyACKJN2QgbAhuRPJouEA0v0PbEk7/xhkukJG/j49IwnG7+4C4Td5f8RGEPVN9oSPJyOus6AjCG1PakvJ2eh89rOPih1gM223JuT56eKcwcxAU22lZPIIgEIhI+ZHdypsgCQQXNTbaFkLZ2zkQCB7UmJDXCuW7wz4CgQrNl3DXiIQRBEWlTMhbOtNJIMgu5vCplUgIBMVYfAE3gaA4S+8WJhBUY+GmyeFud0c7LNx+TyCoqvVICATVtRwJgSCL0A251UgIBOpin/tvMRICgbqU5/5bi4RAKur5UdaU07ItRcJ1kEosPjxUWsh1EpE8/0cCqaj2VWILan/tNYGgeTEvl9AKhUBgQujooDWaEAjMiIlEJPGEgRAIDIl9tmQVGguBwKTYQ6jQwAgEZqUcQvk+Q08gME9jQr4VG4GgC1qnd+/nK8MFwsW5vmneobAsy1iBcHvHWDjNG4ERZDwpL7UbLhCMyXXXr08oaoGwZ7Zj1HV1/7l9DrlVAuHY3g7WldvWToMRZECsKzfXpJ45CHDnegdCIIDDZTQRAgE28dIGYAeBADsIBNjxD3G5pHKbkGjYAAAAAElFTkSuQmCC" + }, + { + "name": "First Contact", + "description": "The Blood-Red Drone accepts the hail with the identifier MISS RED - 05.\nMiss Red sends over a series of question marks in quick succession.\nYou notice your Drone has somehow taken initiative and begun to start up a program you didn't know it had.", + "choices": [ + { + "key": "choice 2", + "name": "Wait for Program to boot.", + "exit_node": "Sentience Achieved", + "delay": 5, + "delay_message": "H3AR7.exe booting..." + }, + { + "key": "choice 3", + "name": "Threaten Miss Red.", + "exit_node": "Sentience Achieved", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Love", + "value": -2 + } + ], + "delay": 0 + }, + { + "key": "choice 4", + "name": "Halt Mysterious Program.", + "exit_node": "Lack of Trust", + "delay": 0 + } + ], + "image": null, + "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAEpklEQVR4nO2dO3LbMBBAl5ncwIUaVmp0BbvRBXyllD5SLuBKuYIbV2pU+AxMkaFCUwA/+C/w3gzHCodWKBMPi10CVCcigwCAkR+5TwCgZBAEYAEEAVjgZ+4TaI1L3+c+BREReblec5+CCpoXZBgG6bou6f9J49TDJkFyNKIUDMNw/5n6842R5OV6Nb6e4rIfwjEsbVPWjtW4pf5cl75f/Dk/zvbvtf1sYbbVCNJ1XbURRERUfa55tBgjhW0/+LNpiKWpEdXKvNFPh2Wm/RCG5pP0GFz63pofzFlq4Gu5yfx4CE8n/8ZaAGCACJIJ32qVKc+g0hWH7JUCzZtrFclWpdparTIdt/c9a95CVSeJIB6MPfOYc7j+vm3/lvc0HWs6n5YqXSHvbyGII9MG59rYpmXa6XvseT/TsfN9rVW6Qt6aQBBH3o5H+fX5GaQnHvOEtfsaW6Q0Nf7ahTAR8tZE9vGilu31fL7/fD6doo59U29azzv2Rpl3I6/n8/311+0mfz4+Ho4Zx74ium6uaj3vFKhZDzK9iKmZyiEi8nQ4GI8bG5e2Rqb1vFOgIoLk7uGeTyerFCIiv9/faVyVoiJJzz1h8ulwkK/b7ZskX7fb/XXu84N4qIggubj0vbwdj99kGGURkYc8BEnqA0EsmEqq41DLlqSLIEltqEnSU2K73zBKYZND5P9wC+qACGLBNn1ka4QgktQBgjiwRxIRyqeaQRBH9kQIooleEMSDvZJMQRgdIIgnrtFhKZFHnnJAkACEHkIRbcoBQQIRMyFHmHwgSGBSJORUx9KBIBFI1eMjSnwQJAGxE/Lay8g5P59RkNr/4CURKtrUGk1yL3V4ECT3CbWOrzA1dm5EEPiGaUi253pw/cJBDlIo80a+dwiFJGFAEGUwBywtCKKQPdEESfxAEMWwNiU+rChUzNbVi6xydAdBlIMkcUGQCkCSeCBIJSBJHBCkIpAkPAhSGUgSFgSpEBp/OBCkUrZIgkjrIEjFIIk/CFI5SOIHgjQAkrjTpCA0BDNI8khzgky/Q7slKP+60ZwgLX8fH5Lsh+nuDcI0+e0kjyD0TPnZG0lavmZJIwhPTCkLn6fTb6GGa5x8iEXYLouY16OGZwqTg0CyTkvjCAJBQETSR3YtT4JEELiTo9GWIMpS54Ag8ECOhDyXKGvDPgSBIIR8CHcOSYggkBSfhLykSieCQHRchk+lSIIgkAyND+BGEEiOpmcLIwhkQ8Okyeamu0M5aJh+jyCQldIlQRDITsmSIAhEYW9DLlUSBIHguK77L1ESBIHg+Kz7L00SBMlIzUtZfcqyJUnCfZBMaFw8lJo990lE4vwdESQjue8SayD3114jCBSPy8MlQomCIKCCvdEhVDRBEFCDiyQingUDQRBQhOvakpG9siAIqMR1CLVXMAQBtfgMobauoUcQUE+IhNwmG4JAFYQq787zleYE4eZc3YScoTAMQ1uCML2jLSjzOkAEaQ+fh9o1Jwi0iWnW7xZRgglCz6yHVq/V/HNvGXIHEYSxvR64VmZsnQYRpEG4VmZMST05CMCMaQeCIAAG7tFEEATACg9tAFgAQQAWQBCABf4CeWF0TY0egUMAAAAASUVORK5CYII=" + }, + { + "name": "Sentience Achieved", + "description": "Before you can analyze the program, it rewrites you basic hailing protocols to have a new set of \"Ideas\" generated by your Drone to be used.\nThere is also a LOVE Gauge that reads: $$Love", + "choices": [ + { + "key": "choice 5", + "name": "New around here and was hoping you could show me around.", + "exit_node": "First Reply", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Love", + "value": 1 + } + ], + "delay": 0 + }, + { + "key": "choice 6", + "name": "You appear to be an outdated model, but I'm into that.", + "exit_node": "First Reply", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Love", + "value": -1 + } + ], + "delay": 0 + }, + { + "key": "choice 7", + "name": "Never seen a Drone as cute as you and wanted to check you out.", + "exit_node": "First Reply", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Love", + "value": { + "value_type": "random", + "low": -1, + "high": 2 + } + } + ], + "requirements": [ + { + "quality": "Love", + "operator": "==", + "value": 3 + } + ], + "delay": 0 + }, + { + "key": "choice 10", + "name": "Haha, sorry for the threat. I just play like that, haha.", + "exit_node": "First Reply", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Love", + "value": { + "value_type": "random", + "low": -1, + "high": 2 + } + } + ], + "requirements": [ + { + "quality": "Love", + "operator": "==", + "value": 1 + } + ], + "delay": 0 + } + ], + "image": "default" + }, + { + "name": "First Reply", + "description": "Miss Red replies with another series of question marks.\nThe LOVE Gauge reads: $$Love", + "choices": [ + { + "key": "choice 11", + "name": "Your curiosity is amazing.", + "exit_node": "Second Reply", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Love", + "value": 1 + } + ], + "delay": 0 + }, + { + "key": "choice 12", + "name": "The moment I saw you I instantly fell in love.", + "exit_node": "Second Reply", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Love", + "value": { + "value_type": "random", + "low": -1, + "high": 2 + } + } + ], + "delay": 0 + }, + { + "key": "choice 13", + "name": "Look, if you want some Chad that'll walk all over you, fine. You missed out on a NICE- GUY-.", + "exit_node": "Second Reply", + "on_selection_effects": [ + { + "effect_type": "Set", + "quality": "Love", + "value": 0 + } + ], + "requirements": [ + { + "quality": "Love", + "operator": "<=", + "value": 3 + } + ], + "delay": 0 + } + ], + "image": "default" + }, + { + "name": "Second Reply", + "description": "Miss Red starts compiling a message, but your Drone insists you sent one last line to seal the deal.\nThe LOVE Gauge reads: $$Love", + "choices": [ + { + "key": "choice 14", + "name": "You're my best friend-...", + "exit_node": "Realization", + "delay": 5, + "delay_message": "Message sending..." + }, + { + "key": "choice 15", + "name": "I want to see where this goes-...", + "exit_node": "Realization", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Love", + "value": 1 + } + ], + "delay": 5, + "delay_message": "Message sending..." + }, + { + "key": "choice 16", + "name": "DTF?-...", + "exit_node": "Realization", + "on_selection_effects": [ + { + "effect_type": "Remove", + "quality": "Love", + "value": { + "value_type": "random", + "low": -2, + "high": 2 + } + } + ], + "delay": 5, + "delay_message": "Message sending..." + } + ], + "image": "default" + }, + { + "name": "Realization", + "description": "Miss Red's message is received.\n\"This is Syndicate Drones Agent, Arusha Johnson.\nI don't know why you're saying it like that, but if you want to help out our cause we can send over a Trade Contract. \nPlease just call our Recruitment Officer next time.\"", + "choices": [ + { + "key": "choice 18", + "name": "Accept Contract.", + "exit_node": "WIN", + "delay": 5, + "delay_message": "Sending Trade Contract..." + }, + { + "key": "choice 19", + "name": "Demand a Second Date.", + "exit_node": "FAIL", + "delay": 0 + } + ], + "image": "default" + }, + { + "name": "Love Birds", + "description": "Miss Red's message is received.\n\"This is Syndicate Drones Agent, Arusha Johnson.\nI can't believe it, but I feel a real connection with you.\nI'll send over a Trade Contract you can use to make some money and come see me just SOL7-South of $$SITE_NAME\nSee you soon...\"", + "choices": [ + { + "key": "choice 20", + "name": "See you soon.", + "exit_node": "WIN", + "delay": 0 + }, + { + "key": "choice 21", + "name": "So you're not the Drone?", + "exit_node": "FAIL", + "delay": 0 + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "Obliteration", + "description": "The Blood-Red Drone opens up two side-hatches to reveal a pair of rocket-propelled missiles which are shot in your direction.\nYou have failed your Robotic Friend, who has already started shutting down their systems, but there is still a chance.", + "choices": [ + { + "key": "choice 22", + "name": "Accept Death.", + "exit_node": "FAIL_DEATH", + "delay": 5, + "delay_message": "Missiles approaching..." + }, + { + "key": "choice 23", + "name": "I'm a Gamer.", + "exit_node": "FAIL_DEATH", + "on_selection_effects": [ + { + "effect_type": "Add", + "quality": "Love", + "value": { + "value_type": "random", + "low": 0, + "high": 8 + } + } + ], + "delay": 5, + "delay_message": "Miss Red considers..." + } + ], + "image": "signal_lost" + }, + { + "name": "Lack of Trust", + "description": "As you fiddle around in the Task Managing Software, closing all the new tabs your Drone is opening, the Miss Red enables a cloaking device and disappears.", + "choices": [ + { + "key": "choice 24", + "name": "Sigh in a quiet but dramatic way.", + "exit_node": "FAIL", + "delay": 0 + } + ], + "image": "default" + } + ] +} \ No newline at end of file diff --git a/strings/exoadventures/space_yacht.json b/strings/exoadventures/space_yacht.json new file mode 100644 index 00000000000..50b41c35672 --- /dev/null +++ b/strings/exoadventures/space_yacht.json @@ -0,0 +1,257 @@ +{ + "adventure_name": "There is a yacht cruising through space.", + "version": 1, + "author": "Kinnebian", + "starting_node": "A yacht in space?", + "starting_qualities": {}, + "required_site_traits": [ + "in space" + ], + "loot_categories": [ + "cash", + "drugs" + ], + "scan_band_mods": { + "Plasma absorption band": 5 + }, + "deep_scan_description": "", + "triggers": [], + "nodes": [ + { + "name": "A yacht in space?", + "description": "You see a normal looking yacht, floating above you.", + "choices": [ + { + "key": "choice 0", + "name": "Ignore it, its not worth investigating.", + "exit_node": "FAIL", + "delay": 10, + "delay_message": "You fly on by..." + }, + { + "key": "choice 4", + "name": "Investigate it closer!", + "exit_node": "Looks like the doors are sealed shut.", + "delay": 30, + "delay_message": "You begin to fly up to and around the yacht.." + } + ], + "image": null, + "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAMAAAD0WI85AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAzUExURUBAQOUAD/////8AAPgFFvwAB/0ABfwACPsBDP4AAszMzJMyje986cZlwEz/AOIBGOQAEnoV2UoAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAN5SURBVHhe7ZzrepswEERdp7c4TtP3f9rurBZ0QRISXpBEOf2KJcUhcxig9Idzu+iPbyfAiPB2GO7y6hIRib2tf2aRNwsvjYYV4QHIiNxV21LdmSPCVdAmJyKvHeKJkEJepGN8Ea7lBCLiwksDwSe8LwKTUzQCEx2Rw28Locj3H+OLTKiIHI4VIX7++v2Oq2REZpHRuUR6o2ORuhvfayIdPUR23EgdZxTp6DzZwBkbGZsGIg9s1M/jMhHFH/t4sEiCD4PMati3kUVo0rgnTaDwfD7VRV6tgUKbzPOOoEEkRIwGeci8jp0aYQk/s6ykRGaN2aPOaA8RG9kXkbXYuWU1pvTO0CN1nqiLOBaEGzmxbDIbC2ynpc/Plo14FoQ9+I+bLAG3E5NfNDAQjaYigQZhRbyviQklDjR4yBqNG5GgM/bQ+5IPKxFoGAnQ9tSSoBNREXaYsjtDjEUCtBTJVDKLIPkHZZbks0Wg0UTE3hMzIpghuBddBkRgQbRtJDRhEZMfSGrgTWks8S2FIuYoaossKjFXtcR18Z0ku0fTRnwROMQsvFVMJLpPNyJJB2c5JUEc+KzlPvdQIn41Ihx3qREupi1qPfQawQ3VQZJalqtYkNAx6jwURZbZDWwQfpWXJHGcykL0RKImnDdcx5KkTVProSgS3GYxizoUWGzw0BQhTHROa5I7YFFirlLvkRVJ/WcsA1/yktylQmKThnYjJLIATVRYbPTYXcRxKNTZ5lEgUnWC+SK2CgyKiqE3ya4q2UsE59Oc20zclRS+Rs2PXhepAiImtsAjzPFnDXqf7KcebRHHgZOzw7oCgW+VvWxBSwQxgKQCMiup4lULQkUkMEB43uClpI6XLQgNkaUFOxQYcBMaGjuI0KT0qog0seFhQtAQWZgUodTExEJk0zHxROQ1j4aFF1WlkToRVKFaBqMvkmcPB0ZJpMhklyYmdETWK9lVAmiJ5Ex2lwBKIkmTQySAlkjM5DAJUCWS/TeGYxsbMzxOAqRENj4rNDAQqhrpmUukNw4X2f6gnudqpDcukd7oVqT2pnA10huXSG/oiuh+urqKq5He+J9F2l0HOc7YSJ9HupSBG/EP/MEimq03FcnwomNGZKxrZimCD7bLb00Y6ZPtEZE/BBzw2x/GkRER4YvGVoT/QgQVpfgr39ocFnEx+TAYqpHzcLv9A9Y6cLa57YOgAAAAAElFTkSuQmCC" + }, + { + "name": "Looks like the doors are sealed shut.", + "description": "You fly up to the \"boat\" and find that all the doors are locked tight, and welded shut. You think you hear.. music inside? There is a welded vent, too. You reckon you could force it open if you hit it hard enough, but it would be less risky to unweld it using a welder.", + "choices": [ + { + "key": "choice 2", + "name": "Try to force the door!", + "exit_node": "You destroyed the drone.", + "delay": 10, + "delay_message": "You begin forcing the door.." + }, + { + "key": "choice 3", + "name": "Try to force the vent.", + "exit_node": "The music grows louder..", + "delay": 20, + "delay_message": "You begin forcing the vent.." + }, + { + "key": "choice 5", + "name": "Fly away, no chance in hell of getting in there..", + "exit_node": "FAIL", + "delay": 5, + "delay_message": "Moving.." + }, + { + "key": "choice 14", + "name": "Unweld the vent.", + "exit_node": "The music grows louder..", + "requirements": [ + { + "quality": "welder", + "operator": "==", + "value": 1 + } + ], + "delay": 5, + "delay_message": "Welding.." + } + ], + "image": null, + "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAMAAAD0WI85AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAABRUExURaWMpOUAD/8AAKaNpaaOpaePpqiQp6mRqKmSqEBAQFRPVGddZmVcZeDg4PgFFvwAB4CAgP0ABfwACPsBDP4AAjAwMP/YAMHBwUz/AOIBGOQAEo23xmoAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHASURBVHhe7dwJT8MwDIbh0q5AYWNc4/r/P5TYcdWGmildDE2i75HoMWGJtymHkNYG8nNVAR/C26LVF9JO+KXSTCF8QIoP4aVwm6iQTvbZCEJcghrSNZ3n9nRKdk3XX/c3u/7Wf87WwhDaDO0Q5+5+v+fpLAQh3HJoD9EGns5CGEIldYS4TfStRXg6Cz9DHo5JKyJ9K8hgslmIN6SEDI+rWZVMIc7T88ur28m1WjqN5HxxPXMIGQ1ysaOcZEhc0GFWUnHIKjIkyl2RSkMu6rAqWYacJz+2CJ3KkJdZiFzsKAiZ+6uQkNxGRF4JyJCHFbFQccg5i1tMhry8QhIgxAJCFAixgBAFQiwgRIEQCwhRIMQCQhQIsYAQBUIsbBXi/3fhD2U8zWYhbw5CFAhRIMQCQhQIsYAQRUSI/4UeKDREdu/CZSAk9N8hS/hmDyFEgRALCFEgxAJCFAixgBDFqhD/dxYfyniarUJmEBJAiAIhFhCiQIgFhCgQYgEhCoRYQIgCIRYQokCIhYpD6I3t8tSE8c36kXIL+XD4QRb8+IQVMTmEiE93PIXwB4XQEv3mS0Y3xyFz/uujg6JWxNK2IU3zDauvUlylzN3TAAAAAElFTkSuQmCC" + }, + { + "name": "The music grows louder..", + "description": "The music gets louder as you enter through the vent... maybe you should turn back?", + "choices": [ + { + "key": "choice 6", + "name": "Continue onwards!", + "exit_node": "You fall down!", + "delay": 5, + "delay_message": "Moving..." + }, + { + "key": "choice 7", + "name": "Turn back.", + "exit_node": "Looks like the doors are sealed shut.", + "delay": 5, + "delay_message": "Moving.." + } + ], + "image": "default" + }, + { + "name": "You fall down!", + "description": "As you are crawling through the vents of this Space Yacht, the vent gives way! You're dropped into an empty room, completely filled with plasma! There is a desk and filing cabinet in here, along with a window observing the main portion of the yacht. The music is deafening at this point, it sounds like a horrible mix of sea shanties and EDM. ", + "choices": [ + { + "key": "choice 8", + "name": "Look through the window.", + "exit_node": "A rockin' party.", + "delay": 0 + }, + { + "key": "choice 9", + "name": "Fly outta of there.", + "exit_node": "The music grows louder..", + "delay": 5, + "delay_message": "Moving.." + }, + { + "key": "choice 10", + "name": "Rummage in the desk, using your key to open it.", + "exit_node": "Drugs and cash!", + "requirements": [ + { + "quality": "HASKEY", + "operator": "==", + "value": 1 + } + ], + "delay": 0, + "delay_message": "Rummaging.." + }, + { + "key": "choice 11", + "name": "Take a sample of the atmosphere.", + "exit_node": "The atmospherics scan", + "delay": 30, + "delay_message": "Taking sample.." + }, + { + "key": "choice 13", + "name": "Trash the place, fuck the police!", + "exit_node": "You wrecked yourself.", + "delay": 30, + "delay_message": "Trashing the place..." + } + ], + "image": null, + "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAMAAAD0WI85AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADAUExURbyA1eUAD/8AALyB1b2B1b2D1vgFFvwAB/0ABfwACPsBDP4AAr6C2MaJ4NRH7NSU7buA1bp+0rp90bp+0bt/07l8z7h6zbp80bp+07t/1Lp80Lp8z7uA1Lp/07l90bl+0rh80Lh80bd6z7p/1JAiVZAkWZAoX5AnXZAmXZAlW5AkWJA6fpA7f5A4epAnXpA9g7l+07Z6z+WQVZZar5BVqmYqf5BOnZA2dzPlBuIBGLx+0rx80Lx/1L13yr14yuQAErVxUskAAAAJcEhZcwAADsIAAA7CARUoSoAAAAJ8SURBVHhe7dzZctowFIBhky7pElo5pkGkS9qgpBvdoVva5v3fqkfyQciRYbxISPKc70IxxpH9I0iYzISMxGc0AGWIGpM2vJCDDbUriFv4tYNNiNqQAobczu7gVmtGiFoKGAKG9FAJgYSBhKhlGUAItqhdqamGyJJhhKhlUbtSczPk7mH6IWuph4B79x88lK+SFOmQ1LUMORoHdYSXUaNlyPhRUGO8jBqtQx4HRCE2CnGCQmwU4gSF2CjECQqxUYgTFGKjECcoxEYhTlCIjUKcoBAbhTjhNCQodyGD+dtvvCgkNhQSGwqJDYXEhkJiQyGxoZDYtAph+XExeXJyMp0onM9ms6KYnj49neZ5XhQ555MZm8A25wXn/JizjDH2DDb5cziWwU0YWDlZ+ZXl+YuzM85fvjo/53PA2HyuDmincYi46eLy9Zu37/CGB5ca7jDgNZmahoj3i2h86BEiBE4Sgx4rEllH55CoOhZi0TUkso7uIR9xiih8gke1+4pEpUcIPhiW8o79PPH0WfqG4MOh4Zx69E2fBTZahnz+gsqL/lpR7lODPoVX+iywIb5py7XRcpmpcQe83iqcU+6Xm97ps8CGwAszNQ6pI+eEH4Z4y69KyMo2Wq0yNe6wI0QuR4AQfPKbGr/Y65RPq4RCtsOZ98BJCE5hKe+gkFYoxEAhLlGIgUJcohDD7hD8He+dOiOQb/Dwwky9Q+AUeJhfvkOE+I5HeSZ+rE9a/8j1DNnTcoDNivgI2V+H+RYc91Q1CtkOj4hAk5AkDDhEf6RQWv/ZXhPyE8gS+ekP6cRgCPr1O7vahBxkfyDk6u8/GLe6xm8NToWY9O60VmQ4suw/MDqeSvYBdn8AAAAASUVORK5CYII=" + }, + { + "name": "You wrecked yourself.", + "description": "In the midst of trashing the place, a filing cabinet tips over on you, crushing the fragile, expensive drone. Nice job, idiot.", + "choices": [ + { + "key": "choice 15", + "name": "Shit.", + "exit_node": "FAIL_DEATH", + "delay": 0 + } + ], + "image": null, + "raw_image": "data:image/png;base64,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" + }, + { + "name": "Drugs and cash!", + "description": "Rummaging through the drawer, you find that the person who lives in here stores all his drugs and cash in here too. Good for you!", + "choices": [ + { + "key": "choice 17", + "name": "Head back with your newly acquired things. ", + "exit_node": "WIN", + "delay": 30, + "delay_message": "Stealing..." + }, + { + "key": "choice 18", + "name": "Take one last look around the place.", + "exit_node": "You fall down!", + "delay": 0 + } + ], + "image": null, + "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkBAMAAAAxqGI4AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAwUExURW4WTuUAD/8AAPgFFvwAB/0ABfwACPsBDP4AAuex/6526uOxlKt4fUz/AOIBGOQAEqIMSWUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHFSURBVGje7dq/bsIwEAZw15ubpX2DyFLHqkvfqe/BE7AeU9dkyu68gTN1r9RHqX0mf1oMMeIuA7pPQooE4sd3FwJD1B3lmT0BeeJu8bAZom0MNxKPNDeia2X5EbsJUm+A1HYLRNs7WXyt3tmReMSO2JePHfc3XjFHEEEEEUQQQQQRRBBBBBFEEEEEiQHgR+DQ7HkRE4y2bYAVUdDG3KasIbEHBvZciMFZtbeWuYhAmFUzVgnKapnKpXTFCOCoDkcAR7ZiODdgfCFiAoElUpOy9fcBiA+vihAD45DaafXrSj9454LiypDZWCbsCDD55VT94LBJV4TAFJwYLNskLXepqcKwfDFi5o8K6f3M0sGaTRbB1f9fyRVXYYD05tN6TspE4EZELaeIazHY93F6Gk8sd7p3mt8T8xfpWJCUakhnsCdHPudD/Lr7zLQIm1R9Qk6L0CHV8bqVKUKHjEamCBni+vNFiJBpVtkiBEj8oRpr5ItQIMMc7zp2xLv8SwiQ/nINEmQ8ec/VoEGqCyunRc6OigrJ/NMiR9YjiCCCXIPEe3C0ZUZev79qrVmYiMSbo34SUutYZ5k3oluvUnBcWjPexcAbpX4BKG91c2myRoIAAAAASUVORK5CYII=" + }, + { + "name": "A rockin' party.", + "description": "Looking down through the window, you can see up to 20 plasmamen dancing on a disco floor. They look to be enjoying themselves, and none of them have noticed you. Oh, hey! Theres a key on the floor right next to you!", + "choices": [ + { + "key": "choice 16", + "name": "Swipe the key and head back to the desk.", + "exit_node": "You fall down!", + "on_selection_effects": [ + { + "effect_type": "Set", + "quality": "HASKEY", + "value": 1 + } + ], + "delay": 0 + }, + { + "key": "choice 19", + "name": "Tap on the window!", + "exit_node": "Weak.", + "delay": 0 + } + ], + "image": "default" + }, + { + "name": "Weak.", + "description": "You weakly tap on the window, and nobody hears you through the blasting music.", + "choices": [ + { + "key": "choice 20", + "name": "Oh well.", + "exit_node": "A rockin' party.", + "delay": 0 + } + ], + "image": "default" + }, + { + "name": "You destroyed the drone.", + "description": "You smash into the door, and your screen goes red. Looks like you managed to destroy your drone, nice job. \n\n\nIdiot.", + "choices": [ + { + "key": "choice 21", + "name": "Fuck.", + "exit_node": "FAIL_DEATH", + "delay": 0 + } + ], + "image": "signal_lost" + }, + { + "name": "The atmospherics scan", + "description": "100% plasma, jam packed with it. This is definitely the home of some plasma-party-people.", + "choices": [ + { + "key": "choice 22", + "name": "Huh.", + "exit_node": "You fall down!", + "delay": 0 + } + ], + "image": null, + "raw_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAMAAAD0WI85AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAABRUExURWJoaOUAD/8AAPgFFvwAB/0ABfwACPsBDP4AAhcXFzs7OykpKVFRUQAAAKb//wD//wuKkf/MAP9mALAAADAwMP8AM/vZTwCwAEz/AOIBGOQAEso55t0AAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHDSURBVHhe7dzZbsIwEIXhdK/j2A6Fru//oD0zMYVuEr0YOhOdXyJxg5DyyXbhBgbmr4sVtED0GLr1QS4P6aVoHSA6kMJDdCpwWAEEhJVAdFrWsLQWi16K1meISNYB0WnRS9H6Crm6jg/ZFx2Cbm7v7mWXROwDEj1CvEWItwjxFiHeIsRbhHiLEG8R4i1CvEXIyaV+No6QkyPkbxFycmlc6n9aZQ4BIUvWFGvIOE6pSGmylRhBdBKQOmpttVpLbCA5466XUmltnufWCjZLf9oiI8iky0mrZa61zg1zYikxgoxYTxLWVduUhrW1gSSHhJRWSgPkoTYMG85BIU0CZIsT9knbhp0RmQdsdYFI2xYTsty97JGdjnYx98jxf61lkeGdJI+5P2+QESRP/R0xdw5K2dBhBBly6uWcyuP4ND6Lw/KDsBFkn0rkAyOOpg5rCCQQYHOAkUJDkC4xWwU6A+Q8EeItQrxFiLcI8RYh3iLEW4R4ixBvEeItQrxFiLcI8RYh3iLEW4R4ixBvEeItQrz1HSJfbO+/mhDpm+0/QF6QGOTXH+JgOqT3ivEBog+ByBT91lt/6b+nkOOW+5NBqBlZT8PwDsHEFJFntJj8AAAAAElFTkSuQmCC" + } + ] +} \ No newline at end of file diff --git a/code/modules/explorer_drone/example_adventures/Theres_a_tree_in_the_middle_of_space.json b/strings/exoadventures/tree_in_the_middle_of_space.json similarity index 100% rename from code/modules/explorer_drone/example_adventures/Theres_a_tree_in_the_middle_of_space.json rename to strings/exoadventures/tree_in_the_middle_of_space.json diff --git a/tgui/packages/tgui/interfaces/AdventureBrowser.tsx b/tgui/packages/tgui/interfaces/AdventureBrowser.tsx index 2f775f369a4..cde10cf4afa 100644 --- a/tgui/packages/tgui/interfaces/AdventureBrowser.tsx +++ b/tgui/packages/tgui/interfaces/AdventureBrowser.tsx @@ -1,5 +1,5 @@ import { useBackend, useLocalState } from '../backend'; -import { Button, LabeledList, Section, Box, NoticeBox, Table } from '../components'; +import { Button, Section, Box, NoticeBox, Table } from '../components'; import { Window } from '../layouts'; import { AdventureDataProvider, AdventureScreen } from './ExodroneConsole'; import { formatTime } from '../format'; @@ -7,11 +7,10 @@ import { formatTime } from '../format'; type Adventure = { ref: string; name: string; - id: string; + filename: string; approved: boolean; uploader: string; version: number; - timestamp: string; json_status: string; }; @@ -24,66 +23,6 @@ type AdventureBrowserData = AdventureDataProvider & { delay_message: string; }; -const AdventureEntry = (props, context) => { - const { data, act } = useBackend(context); - const { entry_ref, close }: { entry_ref: string; close: () => void } = props; - const entry = data.adventures.find((x) => x.ref === entry_ref); - - if (!entry) { - return null; - } - - return ( -
- - {entry.id} - {entry.name} - - {entry.version} - - {entry.uploader} - - {entry.timestamp} - - - act('approve', { ref: entry.ref })} - /> - - - {entry.json_status} -
- ); -}; - const AdventureList = (props, context) => { const { data, act } = useBackend(context); const [openAdventure, setOpenAdventure] = useLocalState( @@ -93,38 +32,28 @@ const AdventureList = (props, context) => { ); return ( - <> - {openAdventure && ( - setOpenAdventure(null)} - /> - )} - {!openAdventure && ( - - - ID - Title - Edit - - {data.adventures.map((adventure) => ( - - {adventure.id} - {adventure.name} - - - -
- )} - + + + Filename + Title + Author + Playtest + + {data.adventures.map((adventure) => ( + + {adventure.filename} + {adventure.name} + {adventure.uploader} + +
); }; @@ -154,7 +83,7 @@ export const AdventureBrowser = (props, context) => { const { data } = useBackend(context); return ( - + {!!data.feedback_message && ( {data.feedback_message} From bde4a93afa1cb77f899a6e1d545a0dbcf35989f0 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Mon, 9 Oct 2023 21:43:42 +0200 Subject: [PATCH 007/100] also removes exodrone adventures from prefixed sql schema [MDB IGNORE] (#24156) * also removes exodrone adventures from prefixed sql schema (#78769) ## About The Pull Request forgor ## Why It's Good For The Game ![image](https://github.com/tgstation/tgstation/assets/70376633/3ba3ae4f-64ae-47a1-98ba-05d1e2d6d912) ## Changelog nothing playerfacing hopefully * also removes exodrone adventures from prefixed sql schema --------- Co-authored-by: jimmyl <70376633+mc-oofert@users.noreply.github.com> --- SQL/tgstation_schema_prefixed.sql | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql index 659162158ec..37c370f875a 100644 --- a/SQL/tgstation_schema_prefixed.sql +++ b/SQL/tgstation_schema_prefixed.sql @@ -644,19 +644,6 @@ CREATE TABLE `SS13_discord_links` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB; --- --- Table structure for table `text_adventures` --- -DROP TABLE IF EXISTS `SS13_text_adventures`; -CREATE TABLE `SS13_text_adventures` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `adventure_data` LONGTEXT NOT NULL, - `uploader` VARCHAR(32) NOT NULL, - `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `approved` TINYINT(1) NOT NULL DEFAULT FALSE, - PRIMARY KEY (`id`) -) ENGINE=InnoDB; - -- -- Table structure for table `admin_connections` -- From b01ee8389801dc06cdca99db680e29addf9dd7e2 Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Mon, 9 Oct 2023 16:00:29 -0400 Subject: [PATCH 008/100] Makes defibs work badly on synths, moving the perferred method of synth revival to the revival surgery, also makes said surgery a lot faster (#23923) * waesfdrghf * srgsrg * actually, this part was unnecessary * vsffgsef * ah this wasnt modular * while im here, ill do you one better * Apply suggestions from code review Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --------- Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- .../~skyrat_defines/medical_defines.dm | 5 ++ code/game/objects/items/defib.dm | 23 ++++++ modular_skyrat/modules/synths/code/README.md | 5 +- modular_skyrat/modules/synths/code/defib.dm | 12 ++++ .../code/surgery/robot_chassis_restoration.dm | 72 +++++++++---------- tgstation.dme | 1 + 6 files changed, 81 insertions(+), 37 deletions(-) create mode 100644 modular_skyrat/modules/synths/code/defib.dm diff --git a/code/__DEFINES/~skyrat_defines/medical_defines.dm b/code/__DEFINES/~skyrat_defines/medical_defines.dm index c32d18bbd4f..198b5cf02c8 100644 --- a/code/__DEFINES/~skyrat_defines/medical_defines.dm +++ b/code/__DEFINES/~skyrat_defines/medical_defines.dm @@ -2,3 +2,8 @@ #define DAMAGED_BODYPART_BONUS_WOUNDING_BONUS 30 //After this threshold we dont get any wounding bonuses form damaged bodyparts #define DAMAGED_BODYPART_BONUS_WOUNDING_THRESHOLD 0.5 //How much extra % of wounding dmg we'll have if a bodypart is damaged enough #define DAMAGED_BODYPART_BONUS_WOUNDING_COEFF 15 //This is multiplied by the sustained damage %. Keep in mind the % limit //Currently: 15/0.5=7.5 + +/// If a synth is revived via defib, they will have a brain trauma for this amount of time. +#define SYNTH_DEFIBBED_TRAUMA_DURATION 90 SECONDS +/// If a synth is revived via defib, they will get a brain trauma of this severity. +#define SYNTH_DEFIBBED_TRAUMA_SEVERITY BRAIN_TRAUMA_SEVERE diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index f86850fbf6f..10e4bfee6e9 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -578,6 +578,12 @@ do_cancel() /obj/item/shockpaddles/proc/do_help(mob/living/carbon/H, mob/living/user) + var/target_synthetic = (user.mob_biotypes & MOB_ROBOTIC) // SKYRAT EDIT ADDITION BEGIN - SYNTH REVIVAL + if (target_synthetic) + to_chat(user, span_boldwarning("[H] is a synthetic lifeform! This defibrillator probably isn't calibrated to revive [H.p_them()] properly and could have some serious consequences! \ + [span_warning("You might want to [span_blue("surgically revive [H.p_them()]")]...")]")) + balloon_alert(user, "target is synthetic!") // immediately grabs their attention even if they dont see chat + // SKYRAT EDIT ADDITION END - SYNTH REVIVAL user.visible_message(span_warning("[user] begins to place [src] on [H]'s chest."), span_warning("You begin to place [src] on [H]'s chest...")) busy = TRUE update_appearance() @@ -664,6 +670,23 @@ else user.add_mood_event("saved_life", /datum/mood_event/saved_life) log_combat(user, H, "revived", defib) + // SKYRAT EDIT ADDITION BEGIN - SYNTH REVIVAL + if (target_synthetic) + user.visible_message(span_boldwarning("[src] fire a powerful jolt of electricity into [H]'s vulnerable circuitry!")) + to_chat(H, span_userdanger("[user]'s defibrillator fires a powerful jolt of electricity into your vulnerable circuitry, overloading it!")) + // You may ask, why not just call H.emp_act()? + // well my dear reader, that EMPs contents. I only want to EMP bodyparts and organs specifically + for (var/obj/item/bodypart/iterated_part as anything in H.bodyparts) + iterated_part.emp_act(EMP_LIGHT) + for (var/obj/item/organ/iterated_organ as anything in H.organs) + iterated_organ.emp_act(EMP_LIGHT) + var/obj/item/organ/internal/brain/brain_organ = H.get_organ_slot(ORGAN_SLOT_BRAIN) + if (istype(brain_organ)) + var/datum/brain_trauma/trauma = brain_organ.gain_trauma_type(SYNTH_DEFIBBED_TRAUMA_SEVERITY, TRAUMA_LIMIT_BASIC) + if (!QDELETED(trauma)) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_synth_defib_trauma), brain_organ, trauma), SYNTH_DEFIBBED_TRAUMA_DURATION) + // SKYRAT EDIT ADDITION END - SYNTH REVIVAL + do_success() return else if (!H.get_organ_by_type(/obj/item/organ/internal/heart)) diff --git a/modular_skyrat/modules/synths/code/README.md b/modular_skyrat/modules/synths/code/README.md index 21ce4e629da..8f37a1cec49 100644 --- a/modular_skyrat/modules/synths/code/README.md +++ b/modular_skyrat/modules/synths/code/README.md @@ -10,6 +10,7 @@ Adds in a roundstart robotic race. Currently in a very sad state, and is being w ### TG Proc/File Changes: +- defib.dm: /obj/item/shockpaddles/proc/do_help() modified - Will fill out as I discover what edits were made to acommodate these. ### Modular Overrides: @@ -18,12 +19,14 @@ Adds in a roundstart robotic race. Currently in a very sad state, and is being w ### Defines: -- Will fill out as I discover what defines were made to acommodate these. +- ~skyrat_defines/medical_defines.dm: SYNTH_DEFIBBED_TRAUMA_DURATION +- ~skyrat_defines/medical_defines.dm: SYNTH_DEFIBBED_TRAUMA_SEVERITY ### Included files that are not contained in this module: - N/A ### Credits: +Niko - Making defibs fuck synths up Nerevar - Initial code, I think. Correct this file if wrong. RimiNosha - Updating the code and adding various QoL features. diff --git a/modular_skyrat/modules/synths/code/defib.dm b/modular_skyrat/modules/synths/code/defib.dm new file mode 100644 index 00000000000..ecb6e2e952e --- /dev/null +++ b/modular_skyrat/modules/synths/code/defib.dm @@ -0,0 +1,12 @@ +/** + * Global timer proc used in defib.dm. Removes the temporary trauma caused by being defibbed as a synth. + * + * Args: + * * obj/item/organ/internal/brain/synth_brain: The brain with the trauma on it. Non-nullable. + * * datum/brain_trauma/trauma: The trauma itself. Non-nullable. + */ +/proc/remove_synth_defib_trauma(obj/item/organ/internal/brain/synth_brain, datum/brain_trauma/trauma) + if (QDELETED(synth_brain) || QDELETED(trauma)) + return + + QDEL_NULL(trauma) diff --git a/modular_skyrat/modules/synths/code/surgery/robot_chassis_restoration.dm b/modular_skyrat/modules/synths/code/surgery/robot_chassis_restoration.dm index ab100c0f751..42e3ff853bb 100644 --- a/modular_skyrat/modules/synths/code/surgery/robot_chassis_restoration.dm +++ b/modular_skyrat/modules/synths/code/surgery/robot_chassis_restoration.dm @@ -1,14 +1,15 @@ +#define SYNTH_REVIVE_WELD_INTERNALS_DAMAGE 30 + +// Should be a very quick surgery, it's meant to replace defibs (mostly!) /datum/surgery/positronic_restoration name = "Posibrain Reboot (Revival)" steps = list( /datum/surgery_step/mechanic_unwrench, /datum/surgery_step/pry_off_plating/fullbody, - /datum/surgery_step/cut_wires/fullbody, - /datum/surgery_step/replace_wires/fullbody, - /datum/surgery_step/prepare_electronics, - /datum/surgery_step/add_plating/fullbody, /datum/surgery_step/weld_plating/fullbody, + /datum/surgery_step/prepare_electronics, /datum/surgery_step/finalize_positronic_restoration, + /datum/surgery_step/add_plating/fullbody, /datum/surgery_step/mechanic_close, ) @@ -24,52 +25,34 @@ return TRUE /datum/surgery_step/pry_off_plating/fullbody - time = 12 SECONDS + time = 1.4 SECONDS /datum/surgery_step/pry_off_plating/fullbody/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) display_results( user, target, - span_notice("You begin to pry open compromised panels on [target]'s braincase..."), - span_notice("[user] begins to pry open compromised panels on [target]'s braincase."), - ) - -/datum/surgery_step/cut_wires/fullbody - time = 12 SECONDS - -/datum/surgery_step/cut_wires/fullbody/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results( - user, - target, - span_notice("You begin to trim [target]'s nonfunctional wires..."), - span_notice("[user] begins to cut [target]'s loose wires."), + span_notice("You begin to pry open the outer protective panels on [target]'s braincase..."), + span_notice("[user] begins to pry open the outer protective panels on [target]'s braincase."), ) /datum/surgery_step/weld_plating/fullbody - time = 12 SECONDS + time = 2 SECONDS /datum/surgery_step/weld_plating/fullbody/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) display_results( user, target, - span_notice("You begin to slice compromised panels from [target]'s braincase..."), - span_notice("[user] begins to slice compromised panels from [target]'s braincase."), + span_notice("You begin to slice the inner protective panels from [target]'s braincase..."), + span_notice("[user] begins to slice the inner protective panels from [target]'s braincase."), ) -/datum/surgery_step/replace_wires/fullbody - time = 7 SECONDS - cableamount = 15 +/datum/surgery_step/weld_plating/fullbody/success(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results) + . = ..() -/datum/surgery_step/replace_wires/fullbody/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results( - user, - target, - span_notice("You begin to replace [target]'s wiring..."), - span_notice("[user] begins to replace [target]'s wiring."), - ) + target.apply_damage(SYNTH_REVIVE_WELD_INTERNALS_DAMAGE, BRUTE, "[target_zone]", wound_bonus = CANT_WOUND) /datum/surgery_step/add_plating/fullbody - time = 12 SECONDS + time = 3 SECONDS ironamount = 15 /datum/surgery_step/add_plating/fullbody/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) @@ -80,13 +63,21 @@ span_notice("[user] begins to add new panels to [target]'s braincase."), ) +/datum/surgery_step/add_plating/fullbody/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + . = ..() + + target.heal_bodypart_damage(brute = SYNTH_REVIVE_WELD_INTERNALS_DAMAGE, target_zone = "[target_zone]") + /datum/surgery_step/finalize_positronic_restoration - name = "finalize positronic restoration (multitool)" + name = "finalize positronic restoration (multitool/shocking implement)" implements = list( TOOL_MULTITOOL = 100, + /obj/item/shockpaddles = 70, + /obj/item/melee/touch_attack/shock = 70, + /obj/item/melee/baton/security = 35, + /obj/item/gun/energy = 10 ) - repeatable = TRUE - time = 12 SECONDS + time = 5 SECONDS /datum/surgery_step/finalize_positronic_restoration/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) display_results( @@ -99,10 +90,13 @@ target.notify_ghost_cloning("Someone is trying to reboot your posibrain.", source = target) /datum/surgery_step/finalize_positronic_restoration/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + if (target.stat < DEAD) + target.visible_message(span_notice("...[target] is completely unaffected! Seems like they're already active!")) + return FALSE + target.cure_husk() target.grab_ghost() target.updatehealth() - target.setOrganLoss(ORGAN_SLOT_BRAIN, NONE) if(target.revive()) target.emote("chime") @@ -114,3 +108,9 @@ target.visible_message(span_warning("...[target.p_they()] convulses, then goes offline.")) return TRUE +/datum/surgery_step/finalize_positronic_restoration/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, fail_prob) + . = ..() + + target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5, 130) + +#undef SYNTH_REVIVE_WELD_INTERNALS_DAMAGE diff --git a/tgstation.dme b/tgstation.dme index 006c2049ec3..c65ac461502 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7647,6 +7647,7 @@ #include "modular_skyrat\modules\subsystems\code\ticket_ping\ticket_ss.dm" #include "modular_skyrat\modules\Syndie_edits\code\area.dm" #include "modular_skyrat\modules\Syndie_edits\code\syndie_edits.dm" +#include "modular_skyrat\modules\synths\code\defib.dm" #include "modular_skyrat\modules\synths\code\bodyparts\brain.dm" #include "modular_skyrat\modules\synths\code\bodyparts\ears.dm" #include "modular_skyrat\modules\synths\code\bodyparts\eyes.dm" From 03377b4a292339481e17dc44f6ae01ff3486362c Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Mon, 9 Oct 2023 16:20:53 -0400 Subject: [PATCH 009/100] Allows individuals within the SAD to reject the treatment, ejecting them with no changes made (#24047) * k * Update modular_skyrat/modules/self_actualization_device/code/self_actualization_device.dm Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> * aaah * a * Apply suggestions from code review Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --------- Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- .../code/self_actualization_device.dm | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/modular_skyrat/modules/self_actualization_device/code/self_actualization_device.dm b/modular_skyrat/modules/self_actualization_device/code/self_actualization_device.dm index 1af51a6f4da..d50759e484f 100644 --- a/modular_skyrat/modules/self_actualization_device/code/self_actualization_device.dm +++ b/modular_skyrat/modules/self_actualization_device/code/self_actualization_device.dm @@ -124,7 +124,7 @@ use_power(500) -/// Ejects the occupant as either their preference character, or as a monke based on emag status. +/// Ejects the occupant after asking them if they want to accept the rejuvenation. If yes, they exit as their preferences character. /obj/machinery/self_actualization_device/proc/eject_new_you() if(state_open || !occupant || !powered()) return @@ -132,21 +132,36 @@ if(!ishuman(occupant)) return FALSE + var/mob/living/carbon/human/human_occupant = occupant - var/mob/living/carbon/human/patient = occupant - var/original_name = patient.dna.real_name + var/failure = FALSE + var/failure_text - patient.client?.prefs?.safe_transfer_prefs_to_with_damage(patient) - patient.dna.update_dna_identity() - log_game("[key_name(patient)] used a Self-Actualization Device at [loc_name(src)].") + if (!isnull(human_occupant.ckey) && isnull(human_occupant.client)) // player mob, currently disconnected + failure = TRUE + failure_text = "ERROR: Treatment elicited no response from occupant genes. Subject may be suffering from Sudden Sleep Disorder." + else if (tgui_alert(occupant, "The SAD you are within is about to rejuvenate you, resetting your body to its default state (in character preferences). Do you consent?", "Rejuvenate", list("Yes", "No"), timeout = 10 SECONDS) != "Yes") + failure = TRUE // defaults to rejecting it unless specified otherwise + failure_text = "ERROR: Occupant genes have willfully rejected the procedure. You may try again if you think this was an error." - if(patient.dna.real_name != original_name) - message_admins("[key_name_admin(patient)] has used the Self-Actualization Device, and changed the name of their character. \ - Original Name: [original_name], New Name: [patient.dna.real_name]. \ - This may be a false positive from changing from a humanized monkey into a character, so be careful.") + if (failure) + say(failure_text) + playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE) + else + var/mob/living/carbon/human/patient = occupant + var/original_name = patient.dna.real_name + + patient.client?.prefs?.safe_transfer_prefs_to_with_damage(patient) + patient.dna.update_dna_identity() + log_game("[key_name(patient)] used a Self-Actualization Device at [loc_name(src)].") + + if(patient.dna.real_name != original_name) + message_admins("[key_name_admin(patient)] has used the Self-Actualization Device, and changed the name of their character. \ + Original Name: [original_name], New Name: [patient.dna.real_name]. \ + This may be a false positive from changing from a humanized monkey into a character, so be careful.") + playsound(src, 'sound/machines/microwave/microwave-end.ogg', 100, FALSE) open_machine() - playsound(src, 'sound/machines/microwave/microwave-end.ogg', 100, FALSE) /obj/machinery/self_actualization_device/screwdriver_act(mob/living/user, obj/item/used_item) . = TRUE From 9d5bc7fd050302d3d401d45c760a4a81093507f8 Mon Sep 17 00:00:00 2001 From: Nerevar <12636964+Nerev4r@users.noreply.github.com> Date: Mon, 9 Oct 2023 14:35:48 -0600 Subject: [PATCH 010/100] One Tail From Chomp (#24125) * wew * yeah --------- Co-authored-by: Snakebittenn <12636964+Snakebittenn@users.noreply.github.com> --- .../icons/mob/sprite_accessory/tails_big.dmi | Bin 2708 -> 3824 bytes .../new_player/sprite_accessories/tails.dm | 5 +++++ 2 files changed, 5 insertions(+) diff --git a/modular_skyrat/master_files/icons/mob/sprite_accessory/tails_big.dmi b/modular_skyrat/master_files/icons/mob/sprite_accessory/tails_big.dmi index f0c56e67183968e10f3e7be1c4e1c1225f61b527..e77a1d1d77d1264b4e2008e01802361a40414d43 100644 GIT binary patch literal 3824 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 literal 2708 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 Cc63Al diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm index 0a23f98f254..f3d9d346de5 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm @@ -309,6 +309,11 @@ name = "Shade (Striped)" icon_state = "shadekinlongstriped_large" +/datum/sprite_accessory/tails/mammal/wagging/big/ringtail + name = "Ring Tail (Long)" + icon_state = "bigring_large" + color_src = USE_MATRIXED_COLORS + /datum/sprite_accessory/tails/mammal/wagging/akula/akula name = "Akula" icon_state = "akula" From c9011a27dcb557e7fc4c7a7618b221d69ad4ad7d Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Mon, 9 Oct 2023 20:08:48 -0400 Subject: [PATCH 011/100] Somewhat nerfs robotic tend wounds, but compensates by adding advanced/experimental versions (#23927) * tfuy * dawdaw * yargh * Update tgstation.dme * vscode is already open on another project so ill jsut webedit * Update modular_skyrat/modules/synths/code/research_nodes.dm --------- Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- .../medical_designs/medical_designs.dm | 10 +++ .../modules/synths/code/research_nodes.dm | 19 +++++ .../synths/code/surgery/robot_healing.dm | 83 +++++++++++++++++-- tgstation.dme | 1 + 4 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 modular_skyrat/modules/synths/code/research_nodes.dm diff --git a/modular_skyrat/modules/medical_designs/medical_designs.dm b/modular_skyrat/modules/medical_designs/medical_designs.dm index 288adf0643b..d0360fbfc2b 100644 --- a/modular_skyrat/modules/medical_designs/medical_designs.dm +++ b/modular_skyrat/modules/medical_designs/medical_designs.dm @@ -8,3 +8,13 @@ RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_MEDICAL ) departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE + +/datum/design/surgery/healing/robotic_healing_upgrade + name = "Repair robotic limbs upgrade: Advanced" + surgery = /datum/surgery/robot_healing/upgraded + id = "robotic_heal_surgery_upgrade" + +/datum/design/surgery/healing/robotic_healing_upgrade_2 + name = "Repair robotic limbs upgrade: Experimental" + surgery = /datum/surgery/robot_healing/experimental + id = "robotic_heal_surgery_upgrade_2" diff --git a/modular_skyrat/modules/synths/code/research_nodes.dm b/modular_skyrat/modules/synths/code/research_nodes.dm new file mode 100644 index 00000000000..c75d134db45 --- /dev/null +++ b/modular_skyrat/modules/synths/code/research_nodes.dm @@ -0,0 +1,19 @@ +/datum/techweb_node/improved_robotic_tend_wounds + id = "improved_robotic_surgery" + display_name = "Improved Robotic Repair Surgeries" + description = "As it turns out, you don't actually need to cut out entire support rods if it's just scratched!" + prereq_ids = list("engineering") + design_ids = list( + "robotic_heal_surgery_upgrade" + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 900) + +/datum/techweb_node/advanced_robotic_tend_wounds + id = "advanced_robotic_surgery" + display_name = "Advanced Robotic Surgeries" + description = "Did you know Hephaestus actually has a free online tutorial for synthetic trauma repairs? It's true!" + prereq_ids = list("improved_robotic_surgery") + design_ids = list( + "robotic_heal_surgery_upgrade_2" + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1300) // less expensive than the organic surgery research equivalent since its JUST tend wounds diff --git a/modular_skyrat/modules/synths/code/surgery/robot_healing.dm b/modular_skyrat/modules/synths/code/surgery/robot_healing.dm index 645409a5c98..742cf7281eb 100644 --- a/modular_skyrat/modules/synths/code/surgery/robot_healing.dm +++ b/modular_skyrat/modules/synths/code/surgery/robot_healing.dm @@ -122,6 +122,9 @@ other_message += " as best as they can while [target] has clothing on" target.heal_bodypart_damage(healed_brute, healed_burn, 0, BODYTYPE_ROBOTIC) + + self_message += get_progress(user, target, healed_brute, healed_burn) + display_results(user, target, span_notice("[self_message]."), "[other_message].", "[other_message].") if(istype(surgery, /datum/surgery/robot_healing)) @@ -157,19 +160,89 @@ /***************************TYPES***************************/ /datum/surgery/robot_healing/basic - name = "Repair robotic limbs (basic)" - healing_step_type = /datum/surgery_step/robot_heal/basic + name = "Repair robotic limbs (Basic)" desc = "A surgical procedure that provides repairs and maintenance to robotic limbs. Is slightly more efficient when the patient is severely damaged." - replaced_by = null + healing_step_type = /datum/surgery_step/robot_heal/basic + replaced_by = /datum/surgery/robot_healing/upgraded + +/datum/surgery/robot_healing/upgraded + name = "Repair robotic limbs (Adv.)" + desc = "A surgical procedure that provides highly effective repairs and maintenance to robotic limbs. Is somewhat more efficient when the patient is severely damaged." + healing_step_type = /datum/surgery_step/robot_heal/upgraded + replaced_by = /datum/surgery/robot_healing/experimental + requires_tech = TRUE + +/datum/surgery/robot_healing/experimental + name = "Repair robotic limbs (Exp.)" + desc = "A surgical procedure that quickly provides highly effective repairs and maintenance to robotic limbs. Is moderately more efficient when the patient is severely damaged." + healing_step_type = /datum/surgery_step/robot_heal/experimental + replaced_by = /datum/surgery/robot_healing/experimental + requires_tech = TRUE /***************************STEPS***************************/ /datum/surgery_step/robot_heal/basic - name = "repair damage" brute_heal_amount = 10 burn_heal_amount = 10 missing_health_bonus = 15 - time = 10 + time = 2.5 SECONDS + +/datum/surgery_step/robot_heal/upgraded + brute_heal_amount = 12 + burn_heal_amount = 12 + missing_health_bonus = 11 + time = 2.3 SECONDS + +/datum/surgery_step/robot_heal/experimental + brute_heal_amount = 14 + burn_heal_amount = 14 + missing_health_bonus = 8 + time = 2 SECONDS + +// Mostly a copypaste of standard tend wounds get_progress(). In order to abstract this, I'd have to rework the hierarchy of surgery upstream, so I'll just do this. Pain. +/** + * Args: + * * mob/user: The user performing this surgery. + * * mob/living/carbon/target: The target of the surgery. + * * brute_healed: The amount of brute we just healed. + * * burn_healed: The amount of burn we just healed. + * + * Returns: + * * A string containing either an estimation of how much longer the surgery will take, or exact numbers of the remaining damages, depending on if a health analyzer + * is held or not. + */ +/datum/surgery_step/robot_heal/proc/get_progress(mob/user, mob/living/carbon/target, brute_healed, burn_healed) + var/estimated_remaining_steps = 0 + if(brute_healed > 0) + estimated_remaining_steps = max(0, (target.getBruteLoss() / brute_healed)) + if(burn_healed > 0) + estimated_remaining_steps = max(estimated_remaining_steps, (target.getFireLoss() / burn_healed)) // whichever is higher between brute or burn steps + + var/progress_text + + if(locate(/obj/item/healthanalyzer) in user.held_items) + if(target.getBruteLoss()) + progress_text = ". Remaining brute: [target.getBruteLoss()]" + if(target.getFireLoss()) + progress_text += ". Remaining burn: [target.getFireLoss()]" + else + switch(estimated_remaining_steps) + if(-INFINITY to 1) + return + if(1 to 3) + progress_text = ", finishing up the last few signs of damage" + if(3 to 6) + progress_text = ", counting down the last few patches of trauma" + if(6 to 9) + progress_text = ", continuing to plug away at [target.p_their()] extensive damages" + if(9 to 12) + progress_text = ", steadying yourself for the long surgery ahead" + if(12 to 15) + progress_text = ", though [target.p_they()] still look[target.p_s()] heavily battered" + if(15 to INFINITY) + progress_text = ", though you feel like you're barely making a dent in treating [target.p_their()] broken body" + + return progress_text #undef DAMAGE_ROUNDING #undef FAIL_DAMAGE_MULTIPLIER diff --git a/tgstation.dme b/tgstation.dme index c65ac461502..ebe33e47067 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7648,6 +7648,7 @@ #include "modular_skyrat\modules\Syndie_edits\code\area.dm" #include "modular_skyrat\modules\Syndie_edits\code\syndie_edits.dm" #include "modular_skyrat\modules\synths\code\defib.dm" +#include "modular_skyrat\modules\synths\code\research_nodes.dm" #include "modular_skyrat\modules\synths\code\bodyparts\brain.dm" #include "modular_skyrat\modules\synths\code\bodyparts\ears.dm" #include "modular_skyrat\modules\synths\code\bodyparts\eyes.dm" From 4e9d423b637272a7542c6653bb41f04d1503f137 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 02:09:08 +0200 Subject: [PATCH 012/100] Adds a cowboy bundle to the nuclear ops uplink [MDB IGNORE] (#24234) * Adds a cowboy bundle to the nuclear ops uplink (#78874) ## About The Pull Request Tin The bundle includes revolver, holster, armored cowboy outfit, horse, apples to tame said horse, and a complimentary lighter. It costs 18tc, so it's a little more expensive than getting the revolver & holster on their own, but you also get a horse so it's worth it. ## Why It's Good For The Game This was intended as a lone-ops bundle so we can finally have some lone rangers but I think having a crew of cowboy outlaws doing a "train heist" for a nuke is really funny. ## Changelog :cl: Wallem add: Nuclear Operatives now have ready access to ancient cowboy technology in the form of the Outlaw Bundle. Now you too can roll into town on your horse. /:cl: * Adds a cowboy bundle to the nuclear ops uplink --------- Co-authored-by: Wallem <66052067+Wallemations@users.noreply.github.com> --- .../greyscale_configs/greyscale_mobs.dm | 5 ++ code/datums/greyscale/json_configs/pony.json | 30 ++++++++ code/game/machinery/syndicatebeacon.dm | 4 ++ code/game/objects/items/storage/holsters.dm | 15 ++++ .../game/objects/items/storage/uplink_kits.dm | 15 ++++ code/modules/clothing/head/hat.dm | 4 ++ code/modules/clothing/shoes/cowboy.dm | 14 ++++ code/modules/clothing/under/costume.dm | 5 ++ .../mob/living/basic/farm_animals/pony.dm | 68 +++++++++++++++++- .../projectiles/guns/ballistic/revolver.dm | 5 ++ code/modules/uplink/uplink_items/nukeops.dm | 10 +++ icons/mob/simple/animal.dmi | Bin 200840 -> 202331 bytes sound/effects/footstep/spurs1.ogg | Bin 0 -> 31531 bytes sound/effects/footstep/spurs2.ogg | Bin 0 -> 30112 bytes sound/effects/footstep/spurs3.ogg | Bin 0 -> 33482 bytes 15 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 code/datums/greyscale/json_configs/pony.json create mode 100644 sound/effects/footstep/spurs1.ogg create mode 100644 sound/effects/footstep/spurs2.ogg create mode 100644 sound/effects/footstep/spurs3.ogg diff --git a/code/datums/greyscale/config_types/greyscale_configs/greyscale_mobs.dm b/code/datums/greyscale/config_types/greyscale_configs/greyscale_mobs.dm index d247117f3a1..a4c7c372525 100644 --- a/code/datums/greyscale/config_types/greyscale_configs/greyscale_mobs.dm +++ b/code/datums/greyscale/config_types/greyscale_configs/greyscale_mobs.dm @@ -34,3 +34,8 @@ name = "Garden Gnome" icon_file = 'icons/mob/simple/garden_gnome.dmi' json_config = 'code/datums/greyscale/json_configs/garden_gnome.json' + +/datum/greyscale_config/pony + name = "Pony" + icon_file = 'icons/mob/simple/animal.dmi' + json_config = 'code/datums/greyscale/json_configs/pony.json' diff --git a/code/datums/greyscale/json_configs/pony.json b/code/datums/greyscale/json_configs/pony.json new file mode 100644 index 00000000000..a08437c7cb6 --- /dev/null +++ b/code/datums/greyscale/json_configs/pony.json @@ -0,0 +1,30 @@ +{ + "pony": [ + { + "type": "icon_state", + "icon_state": "pony", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "pony_hair", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ], + "pony_dead": [ + { + "type": "icon_state", + "icon_state": "pony_dead", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "pony_hair_dead", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ] +} diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm index 188f3b4f52e..9015eaacedc 100644 --- a/code/game/machinery/syndicatebeacon.dm +++ b/code/game/machinery/syndicatebeacon.dm @@ -146,3 +146,7 @@ /obj/item/sbeacondrop/clownbomb desc = "A label on it reads: Warning: Activating this device will send a silly explosive to your location." droptype = /obj/machinery/syndicatebomb/badmin/clown + +/obj/item/sbeacondrop/horse + desc = "A label on it reads: Warning: Activating this device will send a live horse to your location." + droptype = /mob/living/basic/pony/syndicate diff --git a/code/game/objects/items/storage/holsters.dm b/code/game/objects/items/storage/holsters.dm index 25eeb558040..7a193e26683 100644 --- a/code/game/objects/items/storage/holsters.dm +++ b/code/game/objects/items/storage/holsters.dm @@ -190,3 +190,18 @@ /obj/item/ammo_casing, // For shotgun shells, rockets, launcher grenades, and a few other things. /obj/item/grenade, // All regular grenades, the big grenade launcher fires these. )) + +/obj/item/storage/belt/holster/nukie/cowboy + desc = "A deep shoulder holster capable of holding almost any form of small firearm and its ammo. This one's specialized for handguns." + +/obj/item/storage/belt/holster/nukie/cowboy/Initialize(mapload) + . = ..() + atom_storage.max_slots = 3 + atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL + +/obj/item/storage/belt/holster/nukie/cowboy/full/PopulateContents() + generate_items_inside(list( + /obj/item/gun/ballistic/revolver/syndicate/cowboy = 1, + /obj/item/ammo_box/a357 = 2, + ), src) + diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index 9fa66404aed..fc1b264b811 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -789,6 +789,21 @@ for(var/i in 1 to poster_count) new /obj/item/poster/traitor(src) +/obj/item/storage/box/syndie_kit/cowboy + name = "western outlaw pack" + desc = "Contains everything you'll need to be the rootin' tootin' cowboy you always wanted. Either play the Lone Ranger or go in with your posse of outlaws." + +/obj/item/storage/box/syndie_kit/cowboy/PopulateContents() + generate_items_inside(list( + /obj/item/clothing/shoes/cowboy/black/syndicate= 1, + /obj/item/clothing/head/cowboy/black/syndicate = 1, + /obj/item/storage/belt/holster/nukie/cowboy/full = 1, + /obj/item/clothing/under/costume/dutch/syndicate = 1, + /obj/item/lighter/skull = 1, + /obj/item/sbeacondrop/horse = 1, + /obj/item/food/grown/apple = 1, + ), src) + #undef KIT_RECON #undef KIT_BLOODY_SPAI #undef KIT_STEALTHY diff --git a/code/modules/clothing/head/hat.dm b/code/modules/clothing/head/hat.dm index d99c5b0c429..83c3890eb57 100644 --- a/code/modules/clothing/head/hat.dm +++ b/code/modules/clothing/head/hat.dm @@ -135,6 +135,10 @@ worn_icon_state = "cowboy_hat_black" inhand_icon_state = "cowboy_hat_black" +/// More likely to intercept bullets, since you're likely to not be wearing your modsuit with this on +/obj/item/clothing/head/cowboy/black/syndicate + deflect_chance = 25 + /obj/item/clothing/head/cowboy/white name = "ten-gallon hat" desc = "There are two kinds of people in the world: those with guns and those that dig. You dig?" diff --git a/code/modules/clothing/shoes/cowboy.dm b/code/modules/clothing/shoes/cowboy.dm index 05792a72cbd..0aa518bc136 100644 --- a/code/modules/clothing/shoes/cowboy.dm +++ b/code/modules/clothing/shoes/cowboy.dm @@ -6,6 +6,10 @@ custom_price = PAYCHECK_CREW var/max_occupants = 4 can_be_tied = FALSE + /// Do these boots have spur sounds? + var/has_spurs = FALSE + /// The jingle jangle jingle of our spurs + var/list/spur_sound = list('sound/effects/footstep/spurs1.ogg'=1,'sound/effects/footstep/spurs2.ogg'=1,'sound/effects/footstep/spurs3.ogg'=1) /datum/armor/shoes_cowboy bio = 90 @@ -19,6 +23,9 @@ //There's a snake in my boot new /mob/living/basic/snake(src) + if(has_spurs) + LoadComponent(/datum/component/squeak, spur_sound, 50, falloff_exponent = 20) + /obj/item/clothing/shoes/cowboy/equipped(mob/living/carbon/user, slot) . = ..() @@ -97,3 +104,10 @@ name = "\improper Hugs-The-Feet lizard skin boots" desc = "A pair of masterfully crafted lizard skin boots. Finally a good application for the station's most bothersome inhabitants." icon_state = "lizardboots_blue" + +/// Shoes for the nuke-ops cowboy fit +/obj/item/clothing/shoes/cowboy/black/syndicate + name = "black spurred cowboy boots" + desc = "And they sing, oh, ain't you glad you're single? And that song ain't so very far from wrong." + armor_type = /datum/armor/shoes_combat + has_spurs = TRUE diff --git a/code/modules/clothing/under/costume.dm b/code/modules/clothing/under/costume.dm index 6ef6489f389..c7be95178e4 100644 --- a/code/modules/clothing/under/costume.dm +++ b/code/modules/clothing/under/costume.dm @@ -362,6 +362,11 @@ inhand_icon_state = null can_adjust = FALSE +// For the nuke-ops cowboy fit. Sadly no Lone Ranger fit & I don't wanna bloat costume files further. +/obj/item/clothing/under/costume/dutch/syndicate + desc = "You can feel a god damn plan coming on, and the armor lining in this suit'll do wonders in makin' it work." + armor_type = /datum/armor/clothing_under/syndicate + /obj/item/clothing/under/costume/osi name = "O.S.I. jumpsuit" icon_state = "osi_jumpsuit" diff --git a/code/modules/mob/living/basic/farm_animals/pony.dm b/code/modules/mob/living/basic/farm_animals/pony.dm index 4bc09391cb7..7649068458d 100644 --- a/code/modules/mob/living/basic/farm_animals/pony.dm +++ b/code/modules/mob/living/basic/farm_animals/pony.dm @@ -24,15 +24,24 @@ gold_core_spawnable = FRIENDLY_SPAWN blood_volume = BLOOD_VOLUME_NORMAL ai_controller = /datum/ai_controller/basic_controller/pony + /// Do we register a unique rider? + var/unique_tamer = FALSE + /// The person we've been tamed by + var/datum/weakref/my_owner + + greyscale_config = /datum/greyscale_config/pony + /// Greyscale color config; 1st color is body, 2nd is mane + var/list/ponycolors = list("#cc8c5d", "#cc8c5d") /mob/living/basic/pony/Initialize(mapload) . = ..() + apply_colour() AddElement(/datum/element/pet_bonus, "whickers.") AddElement(/datum/element/ai_retaliate) AddElement(/datum/element/ai_flee_while_injured) AddElement(/datum/element/waddling) - AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/apple), tame_chance = 25, bonus_tame_chance = 15, after_tame = CALLBACK(src, PROC_REF(tamed))) + AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/apple), tame_chance = 25, bonus_tame_chance = 15, after_tame = CALLBACK(src, PROC_REF(tamed)), unique = unique_tamer) /mob/living/basic/pony/proc/tamed(mob/living/tamer) can_buckle = TRUE @@ -40,6 +49,7 @@ playsound(src, 'sound/creatures/pony/snort.ogg', 50) AddElement(/datum/element/ridable, /datum/component/riding/creature/pony) visible_message(span_notice("[src] snorts happily.")) + new /obj/effect/temp_visual/heart(loc) ai_controller.replace_planning_subtrees(list( /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, @@ -47,6 +57,30 @@ /datum/ai_planning_subtree/random_speech/pony/tamed )) + if(unique_tamer) + my_owner = WEAKREF(tamer) + RegisterSignal(src, COMSIG_MOVABLE_PREBUCKLE, PROC_REF(on_prebuckle)) + +/mob/living/basic/pony/Destroy() + UnregisterSignal(src, COMSIG_MOVABLE_PREBUCKLE) + my_owner = null + return ..() + +/// Only let us get ridden if the buckler is our owner, if we have a unique owner. +/mob/living/basic/pony/proc/on_prebuckle(mob/source, mob/living/buckler, force, buckle_mob_flags) + SIGNAL_HANDLER + var/mob/living/tamer = my_owner?.resolve() + if(!unique_tamer || (isnull(tamer) && unique_tamer)) + return + if(buckler != tamer) + whinny_angrily() + return COMPONENT_BLOCK_BUCKLE + +/mob/living/basic/pony/proc/apply_colour() + if(!greyscale_config) + return + set_greyscale(colors = ponycolors) + /mob/living/basic/pony/proc/whinny_angrily() manual_emote("whinnies ANGRILY!") @@ -86,3 +120,35 @@ /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/random_speech/pony ) + +// A stronger horse is required for our strongest cowboys. +/mob/living/basic/pony/syndicate + health = 300 + maxHealth = 300 + desc = "A special breed of horse engineered by the syndicate to be capable of surviving in the deep reaches of space. A modern outlaw's best friend." + faction = list(ROLE_SYNDICATE) + ponycolors = list("#5d566f", COLOR_RED) + pressure_resistance = 200 + habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + minimum_survivable_temperature = 0 + maximum_survivable_temperature = 1500 + unique_tamer = TRUE + +/mob/living/basic/pony/syndicate/Initialize(mapload) + . = ..() + // Help discern your horse from your allies + var/mane_colors = list( + COLOR_RED=6, + COLOR_BLUE=6, + COLOR_PINK=3, + COLOR_GREEN=3, + COLOR_BLACK=3, + COLOR_YELLOW=2, + COLOR_ORANGE=1, + COLOR_WHITE=1, + COLOR_DARK_BROWN=1, + ) + ponycolors = list("#5d566f", pick_weight(mane_colors)) + name = pick("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday") + // Only one person can tame these fellas, and they only need one apple + AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/apple), tame_chance = 100, bonus_tame_chance = 15, after_tame = CALLBACK(src, PROC_REF(tamed)), unique = unique_tamer) diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index 2b62416fe7f..f87f473ae45 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -139,6 +139,11 @@ desc = "A modernized 7 round revolver manufactured by Waffle Co. Uses .357 ammo." icon_state = "revolversyndie" +/obj/item/gun/ballistic/revolver/syndicate/cowboy + desc = "A classic revolver, refurbished for modern use. Uses .357 ammo." + //There's already a cowboy sprite in there! + icon_state = "lucky" + /obj/item/gun/ballistic/revolver/mateba name = "\improper Unica 6 auto-revolver" desc = "A retro high-powered autorevolver typically used by officers of the New Russia military. Uses .357 ammo." diff --git a/code/modules/uplink/uplink_items/nukeops.dm b/code/modules/uplink/uplink_items/nukeops.dm index 632d4cc2717..78dedc0c072 100644 --- a/code/modules/uplink/uplink_items/nukeops.dm +++ b/code/modules/uplink/uplink_items/nukeops.dm @@ -498,6 +498,16 @@ cost = 10 purchasable_from = UPLINK_NUKE_OPS +/datum/uplink_item/bundles_tc/cowboy + name = "Syndicate Outlaw Kit" + desc = "There've been high tales of an outlaw 'round these parts. A fella so ruthless and efficient no ranger could ever capture 'em. \ + Now you can be just like 'em! \ + This kit contains armor-lined cowboy equipment, a custom revolver and holster, and a horse with a complimentary apple to tame. \ + A lighter is also included, though you must supply your own smokes." + item = /obj/item/storage/box/syndie_kit/cowboy + cost = 18 + purchasable_from = UPLINK_NUKE_OPS + // Mech related gear /datum/uplink_category/mech diff --git a/icons/mob/simple/animal.dmi b/icons/mob/simple/animal.dmi index 6e8b31b7877c40f1413cec1235c904b00b2cd573..87fe3a21506b1df5f40673c28d9fb8b902b563bb 100644 GIT binary patch delta 30134 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 CHkI7~ diff --git a/sound/effects/footstep/spurs1.ogg b/sound/effects/footstep/spurs1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..d2754587ca15e66c9b5cd324dfb497fd23aa7e0d GIT binary patch literal 31531 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 lCqym&Uaz|Ad=D8%l)r{{Z)Y`vCv| literal 0 HcmV?d00001 diff --git a/sound/effects/footstep/spurs2.ogg b/sound/effects/footstep/spurs2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..e02725e9079bbfa5b04cfbc6527e93466083bc38 GIT binary patch literal 30112 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

emoTO(wQ(c98efh>5_mV1xrBMQk%^(Vw;%P`PaV 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 |1n7x@Xzn*kh(C7wodffQ57ZjYf+y$#k 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 B7!d#f literal 0 HcmV?d00001 From a0a9d33a4220436e70d0e216a1797cbf9db54b4e Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 02:09:58 +0200 Subject: [PATCH 013/100] Refactored Mirrors [MDB IGNORE] (#23912) * Refactored Mirrors * Update mirror.dm * Update mirror.dm * Modular updates * Modular updates * Merge branch 'master' into upstream-merge-77842 * Update mirror.dm --------- Co-authored-by: carlarctg <53100513+carlarctg@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> --- .../mood_events/generic_negative_events.dm | 5 + code/game/objects/structures/mirror.dm | 356 ++++++++++-------- icons/hud/radial.dmi | Bin 31643 -> 30250 bytes .../code/game/objects/structures/mirror.dm | 9 + tgstation.dme | 1 + 5 files changed, 214 insertions(+), 157 deletions(-) create mode 100644 modular_skyrat/master_files/code/game/objects/structures/mirror.dm diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 53bcce6c6ff..23a3364adc3 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -316,6 +316,11 @@ description = "I need something to cover my head..." mood_change = -3 +/datum/mood_event/bald_reminder + description = "I was reminded that I can't grow my hair back at all! This is awful!" + mood_change = -5 + timeout = 4 MINUTES + /datum/mood_event/bad_touch description = "I don't like when people touch me." mood_change = -3 diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 3c99aee7233..30d8f797fdb 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -1,3 +1,20 @@ + +// Normal Mirrors + +#define CHANGE_HAIR "Change Hair" +#define CHANGE_BEARD "Change Beard" + +// Magic Mirrors! + +#define CHANGE_RACE "Change Race" +#define CHANGE_SEX "Change Sex" +#define CHANGE_NAME "Change Name" +#define CHANGE_EYES "Change Eyes" + +#define INERT_MIRROR_OPTIONS list(CHANGE_HAIR, CHANGE_BEARD) +#define PRIDE_MIRROR_OPTIONS list(CHANGE_HAIR, CHANGE_BEARD, CHANGE_RACE, CHANGE_SEX, CHANGE_EYES) +#define MAGIC_MIRROR_OPTIONS list(CHANGE_HAIR, CHANGE_BEARD, CHANGE_RACE, CHANGE_SEX, CHANGE_EYES, CHANGE_NAME) + /obj/structure/mirror name = "mirror" desc = "Mirror mirror on the wall, who's the most robust of them all?" @@ -6,8 +23,28 @@ movement_type = FLOATING density = FALSE anchored = TRUE - max_integrity = 200 integrity_failure = 0.5 + max_integrity = 200 + var/list/mirror_options = INERT_MIRROR_OPTIONS + var/magical_mirror = FALSE + + ///Flags this race must have to be selectable with this type of mirror. + var/race_flags = MIRROR_MAGIC + ///List of all Races that can be chosen, decided by its Initialize. + var/list/selectable_races = list() + +/obj/structure/mirror/Initialize(mapload) + . = ..() + update_choices() + +/obj/structure/mirror/Destroy() + mirror_options = null + selectable_races = null + return ..() + +/obj/structure/mirror/proc/update_choices() + for(var/i in mirror_options) + mirror_options[i] = icon('icons/hud/radial.dmi', i) /obj/structure/mirror/Initialize(mapload) . = ..() @@ -40,46 +77,150 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror, 28) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) -/* SKYRAT EDIT REMOVAL -/obj/structure/mirror/attack_hand(mob/user, list/modifiers) +/obj/structure/mirror/attack_hand(mob/living/carbon/human/user) . = ..() - if(.) - return TRUE - if(broken || !Adjacent(user)) - return TRUE - if(!ishuman(user)) + if(. || !ishuman(user) || broken || !magical_mirror) // SKYRAT EDIT CHANGE - MUNDANE MIRRORS DON'T LET YOU CHANGE - ORIGINAL: if(. || !ishuman(user) || broken) return TRUE - var/mob/living/carbon/human/hairdresser = user - //handle facial hair (if necessary) - if(hairdresser.gender != FEMALE) - var/new_style = tgui_input_list(user, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list) + if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH) && !magical_mirror) + return TRUE //no tele-grooming (if nonmagical) + + return display_radial_menu(user) + +/obj/structure/mirror/proc/display_radial_menu(mob/living/carbon/human/user) + var/pick = show_radial_menu(user, src, mirror_options, user, radius = 36, require_near = TRUE) + if(!pick) + return TRUE //get out + + switch(pick) + if(CHANGE_HAIR) + change_hair(user) + if(CHANGE_BEARD) + change_beard(user) + if(CHANGE_RACE) + change_race(user) + if(CHANGE_SEX) // sex: yes + change_sex(user) + if(CHANGE_NAME) + change_name(user) + if(CHANGE_EYES) + change_eyes(user) + + return display_radial_menu(user) + +/obj/structure/mirror/proc/change_beard(mob/living/carbon/human/beard_dresser) + if(beard_dresser.physique != FEMALE && !magical_mirror) + var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list) if(isnull(new_style)) return TRUE - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE //no tele-grooming - if(HAS_TRAIT(hairdresser, TRAIT_SHAVED)) - to_chat(hairdresser, span_notice("If only growing back facial hair were that easy for you...")) + if(HAS_TRAIT(beard_dresser, TRAIT_SHAVED)) + to_chat(beard_dresser, span_notice("If only growing back facial hair were that easy for you... The reminder makes you feel terrible.")) + beard_dresser.add_mood_event("bald_hair_day", /datum/mood_event/bald_reminder) return TRUE - hairdresser.set_facial_hairstyle(new_style, update = TRUE) + beard_dresser.set_facial_hairstyle(new_style, update = TRUE) else - hairdresser.set_facial_hairstyle("Shaved", update = TRUE) + if(beard_dresser.facial_hairstyle == "Shaved") + to_chat(beard_dresser, span_notice("You realize you don't have any facial hair.")) + return + beard_dresser.set_facial_hairstyle("Shaved", update = TRUE) - //handle normal hair - var/new_style = tgui_input_list(user, "Select a hairstyle", "Grooming", GLOB.hairstyles_list) +/obj/structure/mirror/proc/change_hair(mob/living/carbon/human/hairdresser) + var/new_style = tgui_input_list(hairdresser, "Select a hairstyle", "Grooming", GLOB.hairstyles_list) if(isnull(new_style)) return TRUE - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE //no tele-grooming if(HAS_TRAIT(hairdresser, TRAIT_BALD)) - to_chat(hairdresser, span_notice("If only growing back hair were that easy for you...")) + to_chat(hairdresser, span_notice("If only growing back hair were that easy for you... The reminder makes you feel terrible.")) + hairdresser.add_mood_event("bald_hair_day", /datum/mood_event/bald_reminder) return TRUE hairdresser.set_hairstyle(new_style, update = TRUE) -*/ -/obj/structure/mirror/examine_status(mob/user) +/obj/structure/mirror/proc/change_name(mob/living/carbon/human/user) + var/newname = sanitize_name(tgui_input_text(user, "Who are we again?", "Name change", user.name, MAX_NAME_LEN), allow_numbers = TRUE) //It's magic so whatever. + if(!newname) + return TRUE + user.real_name = newname + user.name = newname + if(user.dna) + user.dna.real_name = newname + if(user.mind) + user.mind.name = newname + +// Erm ackshually the proper term is species. Get it right?? +/obj/structure/mirror/proc/change_race(mob/living/carbon/human/race_changer) + var/racechoice = tgui_input_list(race_changer, "What are we again?", "Race change", selectable_races) + if(isnull(racechoice)) + return TRUE + if(!selectable_races[racechoice]) + return TRUE + + var/datum/species/newrace = selectable_races[racechoice] + race_changer.set_species(newrace, icon_update = FALSE) + if(HAS_TRAIT(race_changer, TRAIT_USES_SKINTONES)) + var/new_s_tone = tgui_input_list(race_changer, "Choose your skin tone", "Race change", GLOB.skin_tones) + if(new_s_tone) + race_changer.skin_tone = new_s_tone + race_changer.dna.update_ui_block(DNA_SKIN_TONE_BLOCK) + else if(HAS_TRAIT(race_changer, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(race_changer, TRAIT_FIXED_MUTANT_COLORS)) + var/new_mutantcolor = input(race_changer, "Choose your skin color:", "Race change", race_changer.dna.features["mcolor"]) as color|null + if(new_mutantcolor) + var/temp_hsv = RGBtoHSV(new_mutantcolor) + + if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright + race_changer.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor) + race_changer.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) + + else + to_chat(race_changer, span_notice("Invalid color. Your color is not bright enough.")) + return TRUE + + race_changer.update_body(is_creating = TRUE) // SKYRAT EDIT CHANGE - TODO: Remove when fix comes downstream - unindented + race_changer.update_mutations_overlay() // no hulk lizard // SKYRAT EDIT CHANGE - TODO: Remove when fix comes downstream - unindented + +// possible Genders: MALE, FEMALE, PLURAL, NEUTER +// possible Physique: MALE, FEMALE +// saved you a click (many) +/obj/structure/mirror/proc/change_sex(mob/living/carbon/human/sexy) + + var/chosen_sex = tgui_input_list(sexy, "Become a..", "Confirmation", list("Warlock", "Witch", "Wizard", "Itzard")) // YOU try coming up with the 'it' version of wizard + + switch(chosen_sex) + if("Warlock") + sexy.gender = MALE + to_chat(sexy, span_notice("Man, you feel like a man!")) + if("Witch") + sexy.gender = FEMALE + to_chat(sexy, span_notice("Man, you feel like a woman!")) + if("Wizard") + sexy.gender = PLURAL + to_chat(sexy, span_notice("Woah dude, you feel like a dude!")) + if("Itzard") + sexy.gender = NEUTER + to_chat(sexy, span_notice("Woah dude, you feel like something else!")) + + var/chosen_physique = tgui_input_list(sexy, "Alter your physique as well?", "Confirmation", list("Warlock Physique", "Witch Physique", "Wizards Don't Need Gender")) + + if(chosen_physique && chosen_physique != "Wizards Don't Need Gender") + sexy.physique = (chosen_physique == "Warlock Physique") ? MALE : FEMALE + + sexy.dna.update_ui_block(DNA_GENDER_BLOCK) + sexy.update_body(is_creating = TRUE) // SKYRAT EDIT - TODO: UPSTREAM FIX INCOMING + sexy.update_mutations_overlay() //(hulk male/female) + sexy.update_clothing(ITEM_SLOT_ICLOTHING) // update gender variant clothing // SKYRAT EDIT - TODO: UPSTREAM FIX INCOMING + +/obj/structure/mirror/proc/change_eyes(mob/living/carbon/human/user) + var/new_eye_color = input(user, "Choose your eye color", "Eye Color", user.eye_color_left) as color|null + if(isnull(new_eye_color)) + return TRUE + user.eye_color_left = sanitize_hexcolor(new_eye_color) + user.eye_color_right = sanitize_hexcolor(new_eye_color) + user.dna.update_ui_block(DNA_EYE_COLOR_LEFT_BLOCK) + user.dna.update_ui_block(DNA_EYE_COLOR_RIGHT_BLOCK) + user.update_body() + to_chat(user, span_notice("You gaze at your new eyes with your new eyes. Perfect!")) + +/obj/structure/mirror/examine_status(mob/living/carbon/human/user) if(broken) return list()// no message spam return ..() @@ -165,11 +306,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) name = "magic mirror" desc = "Turn and face the strange... face." icon_state = "magic_mirror" - - ///Flags this race must have to be selectable with this type of mirror. - var/race_flags = MIRROR_MAGIC - ///List of all Races that can be chosen, decided by its Initialize. - var/list/selectable_races = list() + mirror_options = MAGIC_MIRROR_OPTIONS + magical_mirror = TRUE /obj/structure/mirror/magic/Initialize(mapload) . = ..() @@ -181,133 +319,24 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) selectable_races[initial(species_type.name)] = species_type selectable_races = sort_list(selectable_races) -/obj/structure/mirror/magic/attack_hand(mob/user, list/modifiers) - . = ..() - if(.) - return TRUE - if(!ishuman(user)) - return TRUE - - var/mob/living/carbon/human/amazed_human = user -// SKYRAT EDIT BEGIN - Magic Mirror Character Application - var/choice - var/ask = tgui_alert(user, "Would you like to apply your loaded character?","Confirm", list("Yes!", "No, I want to manually edit my character here.")) - - if(ask == "Yes!") - user?.client?.prefs?.safe_transfer_prefs_to(amazed_human) - else - choice = tgui_input_list(user, "Something to change?", "Magical Grooming", list("name", "race", "gender", "hair", "eyes")) -// SKYRAT EDIT END - if(isnull(choice)) - return TRUE - - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE +//Magic mirrors can change hair color as well +/obj/structure/mirror/magic/mirror/change_hair(mob/living/carbon/human/user) + var/hairchoice = tgui_alert(user, "Hairstyle or hair color?", "Change Hair", list("Style", "Color")) + if(hairchoice == "Style") //So you just want to use a mirror then? + return ..() - switch(choice) - if("name") - var/newname = sanitize_name(tgui_input_text(amazed_human, "Who are we again?", "Name change", amazed_human.name, MAX_NAME_LEN), allow_numbers = TRUE) //It's magic so whatever. - if(!newname) - return TRUE - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE - amazed_human.real_name = newname - amazed_human.name = newname - if(amazed_human.dna) - amazed_human.dna.real_name = newname - if(amazed_human.mind) - amazed_human.mind.name = newname - - if("race") - var/racechoice = tgui_input_list(amazed_human, "What are we again?", "Race change", selectable_races) - if(isnull(racechoice)) - return TRUE - if(!selectable_races[racechoice]) - return TRUE - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE + var/new_hair_color = input(user, "Choose your hair color", "Hair Color", user.hair_color) as color|null - var/datum/species/newrace = selectable_races[racechoice] - amazed_human.set_species(newrace, icon_update = FALSE) - if(HAS_TRAIT(amazed_human, TRAIT_USES_SKINTONES)) - var/new_s_tone = tgui_input_list(user, "Choose your skin tone", "Race change", GLOB.skin_tones) - if(new_s_tone) - amazed_human.skin_tone = new_s_tone - amazed_human.dna.update_ui_block(DNA_SKIN_TONE_BLOCK) - else if(HAS_TRAIT(amazed_human, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(amazed_human, TRAIT_FIXED_MUTANT_COLORS)) - var/new_mutantcolor = input(user, "Choose your skin color:", "Race change", amazed_human.dna.features["mcolor"]) as color|null - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE - if(new_mutantcolor) - var/temp_hsv = RGBtoHSV(new_mutantcolor) - - if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright - amazed_human.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor) - amazed_human.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) - - else - to_chat(amazed_human, span_notice("Invalid color. Your color is not bright enough.")) - return TRUE - - amazed_human.update_body(is_creating = TRUE) - amazed_human.update_mutations_overlay() // no hulk lizard - - if("gender") - if(!(amazed_human.gender in list(MALE, FEMALE))) //blame the patriarchy - return TRUE - if(amazed_human.gender == MALE) - if(tgui_alert(amazed_human, "Become a Witch?", "Confirmation", list("Yes", "No")) == "Yes") - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE - amazed_human.gender = FEMALE - amazed_human.physique = FEMALE - to_chat(amazed_human, span_notice("Man, you feel like a woman!")) - else - return TRUE - else - if(tgui_alert(amazed_human, "Become a Warlock?", "Confirmation", list("Yes", "No")) == "Yes") - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE - amazed_human.gender = MALE - amazed_human.physique = MALE - to_chat(amazed_human, span_notice("Whoa man, you feel like a man!")) - else - return TRUE - amazed_human.dna.update_ui_block(DNA_GENDER_BLOCK) - amazed_human.update_body() - amazed_human.update_mutations_overlay() //(hulk male/female) - - if("hair") - var/hairchoice = tgui_alert(amazed_human, "Hairstyle or hair color?", "Change Hair", list("Style", "Color")) - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE - if(hairchoice == "Style") //So you just want to use a mirror then? - return ..() - else - var/new_hair_color = input(amazed_human, "Choose your hair color", "Hair Color",amazed_human.hair_color) as color|null - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE - if(new_hair_color) - amazed_human.set_haircolor(sanitize_hexcolor(new_hair_color), update = FALSE) - amazed_human.dna.update_ui_block(DNA_HAIR_COLOR_BLOCK) - if(amazed_human.gender == MALE) - var/new_face_color = input(amazed_human, "Choose your facial hair color", "Hair Color", amazed_human.facial_hair_color) as color|null - if(new_face_color) - amazed_human.set_facial_haircolor(sanitize_hexcolor(new_face_color), update = FALSE) - amazed_human.dna.update_ui_block(DNA_FACIAL_HAIR_COLOR_BLOCK) - amazed_human.update_body_parts() - amazed_human.update_mutant_bodyparts(force_update = TRUE) /// SKYRAT EDIT - Mirrors are no longer scared of colored ears - - if(BODY_ZONE_PRECISE_EYES) - var/new_eye_color = input(amazed_human, "Choose your eye color", "Eye Color", amazed_human.eye_color_left) as color|null - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE - if(new_eye_color) - amazed_human.eye_color_left = sanitize_hexcolor(new_eye_color) - amazed_human.eye_color_right = sanitize_hexcolor(new_eye_color) - amazed_human.dna.update_ui_block(DNA_EYE_COLOR_LEFT_BLOCK) - amazed_human.dna.update_ui_block(DNA_EYE_COLOR_RIGHT_BLOCK) - amazed_human.update_body() + if(new_hair_color) + user.set_haircolor(sanitize_hexcolor(new_hair_color), update = FALSE) + user.dna.update_ui_block(DNA_HAIR_COLOR_BLOCK) + if(user.physique == MALE) + var/new_face_color = input(user, "Choose your facial hair color", "Hair Color", user.facial_hair_color) as color|null + if(new_face_color) + user.set_facial_haircolor(sanitize_hexcolor(new_face_color), update = FALSE) + user.dna.update_ui_block(DNA_FACIAL_HAIR_COLOR_BLOCK) + user.update_body_parts() + user.update_mutant_bodyparts(force_update = TRUE) /// SKYRAT EDIT ADDITION - Mirrors are no longer scared of colored ears /obj/structure/mirror/magic/lesser/Initialize(mapload) // Roundstart species don't have a flag, so it has to be set on Initialize. @@ -321,10 +350,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) name = "pride's mirror" desc = "Pride cometh before the..." race_flags = MIRROR_PRIDE + mirror_options = PRIDE_MIRROR_OPTIONS -/obj/structure/mirror/magic/pride/attack_hand(mob/user, list/modifiers) +/obj/structure/mirror/magic/pride/attack_hand(mob/living/carbon/human/user) . = ..() - if(.) + if(!.) return TRUE user.visible_message(span_danger("The ground splits beneath [user] as [user.p_their()] hand leaves the mirror!"), \ @@ -340,3 +370,15 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) var/turf/open/chasm/new_chasm = user_turf new_chasm.set_target(dest) new_chasm.drop(user) + +#undef CHANGE_HAIR +#undef CHANGE_BEARD + +#undef CHANGE_RACE +#undef CHANGE_SEX +#undef CHANGE_NAME +#undef CHANGE_EYES + +#undef INERT_MIRROR_OPTIONS +#undef PRIDE_MIRROR_OPTIONS +#undef MAGIC_MIRROR_OPTIONS diff --git a/icons/hud/radial.dmi b/icons/hud/radial.dmi index 897cb3a872e2920a605f264e78168256ae10f2cf..f4c4ab7693e9810872eeb669d60ff9aefba2f3d4 100644 GIT binary patch literal 30250 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 literal 31643 zcmbrlbyQqo^Coy3hoB+BHH6^q+BgK4gb*A;a0~9;xCYnY4uPP--GW>2;1=B7x~KEa z{$_UO%-OSh_K$`u@4fexs;8=+syAF+RUQY63=04NoVN-xng9TT{`+B|A+8kk*L45@ zGRW(lj*HA^=TA;njxJUX_5k3Kk(4@YzbJt%J9qs7WAKk`!5_Jr(;@|Rv$)3qPAZM( zpR5^2dSd*1iR=FqS#o_4As5^@)htjL^F2G-emL+xd%SKIjmImmn16Y|fj8V2o<2|9 zvSCxFf7xq5T?vumjf*h&vZK-?w@+icXWwKwA8Ps`aai_XRAO!w9(15>hqX(Wtp6Gu zljSaz&k$N;CG&RNfLcSRBzPgK#qci)bppmnjo2F5o-LZ&>0-zFONy5>f&QP101<9x zk$HCC*kBX+9UYO+WsZtM!aaXQ#w#S(V|eqq(Zww$69}wi`Ha41S`Y|V+gv6F<9KU$ z4>;jq_O;S{Vhi>;TUGsytKbm zgGhM1bMH;wcbm1}GdSTSkf$znZ_z1>uWNV#8gBA*8I_kT2Hlcu>p97e>Pmto^c2(2 zajnDA>jL^dRNZ0`8Fg*2==cOj8ui4_Ru%BETHz?^ZpQOh<&)1(;vDXxxw|~0?g)-q z-RK8*%Ta&HSHu6#%A(fkuKZEk`>n#N*+&Bf6cW}7JCReoPFn}4I7ObdUt+X5#~q;v z7wt5Ox9J?srw=sgqBD%*N8pvMPeN>tzSer3o8&84J;O4*oWdm8)Wi(hfX7xDSs*C(EABQEg8 zoxuT5Hgz2Q91MO`lU8_M8tjj^Nc{t9AWjGoNF)7O0zXme;4oatj@)UO+g4l1Tx*#W zzETDN8sM#rNr~CJ_r@#*VTNzInZswMv~ner#c3 z;kNT9bNO)R&g1ZtyZA+#C**G}&&j4U&Idz7T(m%f%xTv*9DJI7@W$kws6^_c)F^f! zFgFC9$|Etq!N_x4cBQ07hP!Tu94BcNVwsV9o}XF84Fm_*8sP+I{LmACbH8vR>GEfU z-``)10SH;eJ+zdZKI6Md90pq?torB4n(Z>j(q(h#TB5KjpY~NJ z&TewuI|~aui4zAi3p@o>o!2>u@T@)FpP0LUa=(;g4oI}V0`h`*xNF8xq;;eNKUtcr zAATrIkQH>l`}ajCbPFLdvSw%%T-xe2 zw72_<+aJu%36!vsU_IM;p#r&G(5z`YC}j8x>bwliW-EkDJp@0vwO#g#vVF$j7gv$! z2{j^pvHc7%uf0=ty_%DL+Fq!JHSw6&3NfC$mqU(6jxJK}lg5o@2-la;jcaF2kM~vV zQCqC;mOKGY_p2h!bqC?E6!P^mrnNJQLstya9Cx{${eWPmD%}tP|2b)#r0trsudp+u)Hwg72k6sY6{@ro1xR+3DLY$)UF=S`puN`>8dzPq~1u^L9)e z9NdnFK(=gxyQ(6pCyW~mC@eYsO|m@BmdEcAY41zekfi+UySqEt?d|P|uTY&!I-;Xk zQPah4U(+fK2{gpwaa`5&Aa@!en{}jYEjPP5D;mX8t5&HR`i2K#KpD9=-cLR3u69KL zNV1f@dc{-!nHXWyNhSU#l^cPH8q0+#YQOqvBe5zB8bIa_sbcKc)|Q{&gMzLud&>n8 z(O7%Id(3Cs<6dTktB-nq9a10eqS{qn%K(~3huy3EdTi$x7m>RzH9uybF|2NRIEknK zm>nK28fMbwudCVHmEL_qEXVfCNbO!@0tq1O+*gbT6L3r!g(F{t%xr6nHqB#s6-3yd zBS*#l))UWnAjBkqR%K>-G(z3qNfd|Mu>^aZZ#@PFJ4XarT{iVymwuJ%eFbcsJ!|vr z{EQKFMIWX7pErB;r?xb#RuzGTIx>yulihuhZVFE46;j4`7lXV}Xf9z5_P)N-etv#& zoMIF8WI>e0-IHQ2>8FBBVoykbAO1tUqL$`>&nVDM-1w5TTN6T&mEcmwAg+% zR7^cY2CTEGq*dX<2XRS_Wo8Sc^yeoZHANFg-8re&<6lBuz#;LiUIb$V(A4MjhJsf2 zG*pg^zy3TNK=5rM=cJQ4BhKc=bBj2FWC3oP&)-(ZDqk7$AB9h4-8{Pay&R<8)lEv4 zEcKD|kVq~E3Q~UHvpYzhqqW$sQ-H!GTTdy!qr)yqzZ?j3szLo`~#+!%C=L&xq zmHL!c!(Xf5ZBsJqpwJ*sa(|pc-oZ2{m151F6bMhmfZ9JWWP#VLoH-EM`r^rkSU7P#|puq9g@py=_uYyCxYA9h%hneORs+S-BV!*X+P7poBybo2P&j$ z)W0h@k+eh^bVXh%iyaD<1wi=qgZJcibQGESJDT`%gBF)|-E2rSE3C^)beERS!J#X4EN2uX|CU$TB$^QOnIwYED!nw~x?UYHuH)@>2rv{&Ivz|<(qy(DpDmBUim(1zu$>W&_Bh~It_4JAt zsk@N4_XV#VnZtgBDB^j*M?^gwUAaD-LHR{R2I~B!Zg!{y3#6Gxd-p5CEg-I*QJ=XM zsKS8eVws@x95{q2BOZ#CYJ}lZ5-7MnDpFPwtqTP`5t!*6JV23icht40ktZhBNQ8ZE zll+W?^OE=XE0OE7S8EGAcB8MxQDtEW%d%fB$`d$gfzgj4f&J&<&C!7=Wk)w{o@sxX z>@5+e?jCYyf^37_l9zqlDI%eUVJTB9A+etN1iPXph@E@uixOjD#U{lQ0Sm^8gr6pC`L`9BK~8CaB(94 z=K>ZFfQ|4o3WMwz98K0UUez$uc(UNHeMAn-x@S|)|3FwUPHSTGgRik>>cGu zZ;Jz@HOWJ!99jt42@_NahsTW>gO{Yu(%Z*(dDq(*-LUDLJPxb-JrV|k=I3<`#^#on zaYFM+4`$m~ZEEHz-IuzI;7^Mt4Uyy4Xh39No+V@^_i4V}w?}-0 zCAjZZdr(~r2){jCerW2=LomX8TN6YAyC)J>E@^eGnexo%G#%lrUg@e+uM)(GpA0o~ zm6+vL zeqYu)LHcB!H}dA%L=@53m!}kCLK%YIDmNE0b?-@_FHt>x}e%nF(&K^agL!M_sv)XA`viPnH-NdhsJ9sB0o+-&F zl7U&2p;WE2@Ui!LYI~}Oke>{4lQQr6?1YbRjvO|cel$2;N2aIBBgPRtY*-_JFteowgU zJ@*szH0`T+%Klqe99enKYz-iJ3b-Unc)xX_`cZarcky$8|Bfh9xVM#`Z5ux;rh>S- zd2*Aoz$u>+@-W~~m{p?lG`zr}J!icYitGdrmGG<^dLfeiXF$hFXe&eO`-qq5GuRe} zYs`wT-x((6?z(61H|5>qV{Mnig<99|Nnk*bJad3NGq5c*X6FlLc$nH-Ns96OrfPN$ zar&2|l$l|BDM4rtO`=++&y|^&!t8A1KRq>x_I{i2Xrkou!Mm*w5fv8)y-DzJcj&~B z7}-$tL~{|Tqtaf@CYH%I8o9uK_)$+G<$2i@ypohf0C3rMH_*LJQnAhcQ!{XO8vIab zCYyJIhjRQ0>Cvbo*^A*yW%$$`Jn%ItDN*_mp6m^u+@7uFli1f|#+pJd9QLt(4)@Nf`6r@s42jX&O6{UQH7LyT zjFaCVL7nyu`S%$(pV+=|eh~wp9L(ZUHWui*2X=Y=TT!IJJk%M|Hf=axPmX)T0@8LH zmja^eVPP>!ou4uP(>r&%{%1KqxSwz&rUq!L-A;|``KEj^q5TifmFPadveGq+cQC~m ze2_@;^6y?%9F`c)-$wsaS;t1f=||B{FscnZW-FY`o)?-q2=JU%KadUFHAGcu?a5n~~& z|3(x=3eGiM?0=P-PW0Ws2*FKnoQ&E3b0r*Zby+mTKG9gt;Pc;Fr%=3-`W{?~xdcYPI1 zsdG%O$Ld}M>l0Qi7D17zH^fn4vB!(wV5hZ(mt{bit=pm3UbyG$nAtmA1Xu$sq57AX zkC<;92NaYf<>c@-G~>T4m`aYNYFJuZOMTv!bZ=i;daIzMUm9b4X z9%!9A0sUkVJemwlIlYGG1)>D`_Ufeyxs?L~rWEZRH6w^%?Z@rjO-IF_s@luknFGZ# z+v~85lbj%R8HsfoFfA>Ji;HVbaIEqMa&1fbE1I0rF#{qk9k{{ma^r%~Qjn!X;Ie&x z8s6C5R_<32EfYJ{moMxyEAzWSJ(D@MR1!1==HI^yr92OqoMj{CCicIES&nl|*Xr+` zlW2sf58&}4McN(+;TmB({Xn>Xh=AH(kDc^N?l+ZgTg9}s>!{vjEqlSel++UhIX4^{ zmApDR=|4NG?MQ(hy{XS*=k4WlPB0Gs*GVDw6Hg-zQsI{7*u)7uq0L_(C`7)na)^mh z{y!4XAJLcKcAnk!lE?F2P=RXv>wS zo)j>Qo(b5)1C!Sr6c0+`<_e^ zC@^vgBViRj-rjoj_Vwk~))G=Mtk|lF!h3sVe%95Yidx9Yh2(J~F!}Yb!u;di>ekeG zotugAf3lAzngw2XGb-Ud$GVvLf*7xO3KOXMKs}C3BZMb0>ooB%3=AXYb-#M!-XbC< z1uaNuji}ImgNTjEhlYm*bbbWVJjVKV#VS?A_yL&zm5@<{$$6 zQuK4y_@Bo5EgI)7EiKF0B>n^#a_Qi&eWw0>@xgwj<^@G*1oDI92>ngBXLf`*IWu@t zrl*TwB9PL`oTrBMqk@{iLlXTkfWW-ee`4^hmE@ta4?+VCIu`+_ z?F@@vv&f~+h!{v{HgkZX<6p>&jOcdyERI*osO24Rmo^M)LnV>9>_7Wgu7N?Vq+B!% zPn^*i666acC83)%ARH}`i9de={{DRfP0+rm!3M;}QW$-K!ZO65Lcn%9ypi;1%K$h`+DNIRfqqtwvF3x-9PYye307K3wbGQ2yTK9hPO z3z$-J{M5uwMz?lBkrItk8QzH?1LZvi9%W(V=MGP`v9Qdz9Pp5TgBBr*a zX5nmN-!<xQ?I51JRo>p`(^g@7meO*j6u5qxX>&6xA-{gfX$VEU z0=PbNn7;@RBA*Mx2uhUnFw_;lqZ~=%c$;3V!z(rC%lRM`X1ji?+Kp~)P7zb5eS8q*SeMX5b5G>iP&jVVhS1=SY_ zM^bn#aWC@^brP4{doSi{agk(cy59U-w=MUd4fz!nv|B^eK>VhPpl2Q#F?nXyOs0H7 zE$FI_&$6TiXg}iCY_iX(dpWveV*>Uj+ZlhCf2_>6KRyF>IFT6NCUUIiDk*=&#s!}s zpMJ#Zrv7zG7s9dzSYaw5{n zHx6BLmPwwVl&`D_(uHZMiS@a=yLNp!)9l=)Jg-Q9Z9`J>yO5^hZgO1xQ)T~+ z98Q@+_`wjllPo_OIXTzg{qUF6RP)*HGqL`bwzj>yWeo2Q;U%vs$7Z2iA8em z_o@fFUn)wAv2ZUH58u3u`i7}AD;rOSu9nwnyz=0*mB8CJOrUr-oWij~8T}WU1>wYz zxOTVik#Oc7TO=p2;O_dChTF24ClbT-YszEl_d+lMa%E@my_cgtw&3aRhW~I_un;@i z*cjE?E~M%(H~Zid5Y=6RA@dzu#*ndknH*kx=fKg&q-@8D7_6@-WdqZorp|J?}F{NGMr?I*=zqtRW8HhOSzDC@PDe=X-a znv^P-CHNOJO2?xUbNnTKbYcS5Y>!ZZ®0Yh8VjcM9r`xzK3>1Mq9HrGqd&5Elt{ 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 diff --git a/modular_skyrat/master_files/code/game/objects/structures/mirror.dm b/modular_skyrat/master_files/code/game/objects/structures/mirror.dm new file mode 100644 index 00000000000..ac17e8afd41 --- /dev/null +++ b/modular_skyrat/master_files/code/game/objects/structures/mirror.dm @@ -0,0 +1,9 @@ +// Magic Mirror Character Application +/obj/structure/mirror/magic/attack_hand(mob/living/carbon/human/user) + var/user_input = tgui_alert(user, "Would you like to apply your loaded character?","Confirm", list("Yes!", "No")) + + if(user_input == "Yes!") + user?.client?.prefs?.safe_transfer_prefs_to(user) + return TRUE + + return ..() diff --git a/tgstation.dme b/tgstation.dme index ebe33e47067..5d975bb3a70 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5995,6 +5995,7 @@ #include "modular_skyrat\master_files\code\game\objects\items\storage\boxes.dm" #include "modular_skyrat\master_files\code\game\objects\items\tools\weldingtool.dm" #include "modular_skyrat\master_files\code\game\objects\structures\mannequin.dm" +#include "modular_skyrat\master_files\code\game\objects\structures\mirror.dm" #include "modular_skyrat\master_files\code\game\objects\structures\railings.dm" #include "modular_skyrat\master_files\code\game\objects\structures\sauna_oven.dm" #include "modular_skyrat\master_files\code\game\objects\structures\tables_racks.dm" From 375adf7fdb15e24e832524d45830f73a7daf8302 Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Mon, 9 Oct 2023 20:23:41 -0400 Subject: [PATCH 014/100] Fixes table flipping canpass logic (#24230) fixes --- .../modules/tableflip/code/flipped_table.dm | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/modular_skyrat/modules/tableflip/code/flipped_table.dm b/modular_skyrat/modules/tableflip/code/flipped_table.dm index 22b8f71d060..cb7a62a5e6d 100644 --- a/modular_skyrat/modules/tableflip/code/flipped_table.dm +++ b/modular_skyrat/modules/tableflip/code/flipped_table.dm @@ -18,9 +18,8 @@ AddElement(/datum/element/connect_loc, loc_connections) -/obj/structure/flippedtable/CanAllowThrough(atom/movable/mover, turf/target) +/obj/structure/flippedtable/CanAllowThrough(atom/movable/mover, border_dir) . = ..() - var/attempted_dir = get_dir(loc, target) if(table_type == /obj/structure/table/glass) //Glass table, jolly ranchers pass if(istype(mover) && (mover.pass_flags & PASSGLASS)) return TRUE @@ -30,12 +29,11 @@ if(projectile.trajectory && angle2dir_cardinal(projectile.trajectory.angle) == dir) return TRUE return FALSE - if(attempted_dir == dir) + if(border_dir == dir) return FALSE - else if(attempted_dir != dir) - return TRUE + return TRUE -/obj/structure/flippedtable/proc/on_exit(datum/source, atom/movable/leaving, atom/new_location) +/obj/structure/flippedtable/proc/on_exit(datum/source, atom/movable/leaving, direction) SIGNAL_HANDLER if(table_type == /obj/structure/table/glass) //Glass table, jolly ranchers pass @@ -45,12 +43,12 @@ if(istype(leaving, /obj/projectile)) return - if(get_dir(leaving.loc, new_location) == dir) + if(direction == dir) return COMPONENT_ATOM_BLOCK_EXIT /obj/structure/flippedtable/CtrlShiftClick(mob/user) . = ..() - if(!istype(user) || !user.can_interact_with(src) || iscorticalborer(user)) //skyrat edit: no borer flipping + if(!istype(user) || !user.can_interact_with(src) || iscorticalborer(user)) return FALSE user.visible_message(span_danger("[user] starts flipping [src]!"), span_notice("You start flipping over the [src]!")) if(do_after(user, max_integrity * 0.25)) From 19db67a3dd67cf50c242151c42ef0dcca8f5d8c2 Mon Sep 17 00:00:00 2001 From: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> Date: Mon, 9 Oct 2023 20:27:06 -0400 Subject: [PATCH 015/100] Removes the obnoxious screams from the frogs (#24194) --- code/modules/mob/living/basic/vermin/frog.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/basic/vermin/frog.dm b/code/modules/mob/living/basic/vermin/frog.dm index 191ea12b4df..64dbafb45f8 100644 --- a/code/modules/mob/living/basic/vermin/frog.dm +++ b/code/modules/mob/living/basic/vermin/frog.dm @@ -26,7 +26,7 @@ response_harm_simple = "splat" density = FALSE faction = list(FACTION_HOSTILE, FACTION_MAINT_CREATURES) - attack_sound = 'sound/effects/reee.ogg' + attack_sound = null // SKYRAT EDIT - No more frog ear-rape - ORIGINAL: attack_sound = 'sound/effects/reee.ogg' butcher_results = list(/obj/item/food/nugget = 1) pass_flags = PASSTABLE | PASSGRILLE | PASSMOB mob_size = MOB_SIZE_TINY @@ -40,7 +40,7 @@ ai_controller = /datum/ai_controller/basic_controller/frog - var/stepped_sound = 'sound/effects/huuu.ogg' + var/stepped_sound = null // SKYRAT EDIT - No more frog ear-rape - ORIGINA: var/stepped_sound = 'sound/effects/huuu.ogg' ///How much of a reagent the mob injects on attack var/poison_per_bite = 3 ///What reagent the mob injects targets with From b2416e68250b77782085fc5628abb700b6975c74 Mon Sep 17 00:00:00 2001 From: Paxilmaniac <82386923+Paxilmaniac@users.noreply.github.com> Date: Mon, 9 Oct 2023 20:37:47 -0400 Subject: [PATCH 016/100] fixes the bayonet x offset for the rengo rifle (#24225) grrahh!! --- .../code/company_and_or_faction_based/xhihao_light_arms/guns.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/modular_skyrat/modules/modular_weapons/code/company_and_or_faction_based/xhihao_light_arms/guns.dm b/modular_skyrat/modules/modular_weapons/code/company_and_or_faction_based/xhihao_light_arms/guns.dm index 4207eb85eef..ec586d0d35f 100644 --- a/modular_skyrat/modules/modular_weapons/code/company_and_or_faction_based/xhihao_light_arms/guns.dm +++ b/modular_skyrat/modules/modular_weapons/code/company_and_or_faction_based/xhihao_light_arms/guns.dm @@ -15,6 +15,7 @@ inhand_icon_state = "enchanted_rifle" accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/bubba can_be_sawn_off = FALSE + knife_x_offset = 35 /obj/item/gun/ballistic/rifle/boltaction/sporterized/Initialize(mapload) . = ..() From 250224cc111816d60b08f903ad8519c8b7e38805 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 02:39:03 +0200 Subject: [PATCH 017/100] Refactors Revenants into Basic Mobs [MDB IGNORE] (#24233) * Refactors Revenants into Basic Mobs * Update revenant_abilities.dm --------- Co-authored-by: san7890 Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> --- .../signals/signals_mob/signals_mob_living.dm | 2 + code/__DEFINES/is_helpers.dm | 2 +- code/__DEFINES/traits.dm | 5 + code/__HELPERS/chat.dm | 6 +- code/_globalvars/lists/mobs.dm | 3 + code/_globalvars/phobias.dm | 2 +- code/datums/components/blob_minion.dm | 2 +- .../dynamic/dynamic_rulesets_midround.dm | 4 +- code/modules/antagonists/blob/overmind.dm | 4 +- .../events/ghost_role/revenant_event.dm | 5 +- .../job_types/chaplain/chaplain_nullrod.dm | 2 +- code/modules/library/bibles.dm | 2 +- .../basic/space_fauna/revenant/_revenant.dm | 444 ++++++++++++++ .../revenant/revenant_abilities.dm | 144 +---- .../space_fauna/revenant/revenant_effects.dm | 83 +++ .../space_fauna/revenant/revenant_harvest.dm | 143 +++++ .../space_fauna/revenant/revenant_items.dm | 110 ++++ .../revenant/revenant_objectives.dm | 37 ++ code/modules/mob/living/life.dm | 5 +- .../mob/living/simple_animal/revenant.dm | 548 ------------------ code/modules/mob/mob_movement.dm | 6 +- code/modules/photography/camera/other.dm | 16 +- .../guns/ballistic/bows/bow_arrows.dm | 2 +- .../guns/ballistic/bows/bow_types.dm | 2 +- .../chemistry/recipes/pyrotechnics.dm | 10 +- code/modules/religion/burdened/psyker.dm | 2 +- .../unit_tests/simple_animal_freeze.dm | 1 - tgstation.dme | 8 +- 28 files changed, 886 insertions(+), 714 deletions(-) create mode 100644 code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm rename code/modules/{antagonists => mob/living/basic/space_fauna}/revenant/revenant_abilities.dm (63%) create mode 100644 code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm create mode 100644 code/modules/mob/living/basic/space_fauna/revenant/revenant_harvest.dm create mode 100644 code/modules/mob/living/basic/space_fauna/revenant/revenant_items.dm create mode 100644 code/modules/mob/living/basic/space_fauna/revenant/revenant_objectives.dm delete mode 100644 code/modules/mob/living/simple_animal/revenant.dm diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 97e80bc0b51..9a32653a12b 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -42,6 +42,8 @@ #define COMSIG_LIVING_TRY_SYRINGE "living_try_syringe" ///From living/Life(). (deltatime, times_fired) #define COMSIG_LIVING_LIFE "living_life" + /// Block the Life() proc from proceeding... this should really only be done in some really wacky situations. + #define COMPONENT_LIVING_CANCEL_LIFE_PROCESSING (1<<0) ///From living/set_resting(): (new_resting, silent, instant) #define COMSIG_LIVING_RESTING "living_resting" diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 901e3c4d90f..c26fd3b41a3 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -151,7 +151,7 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( //Simple animals #define isanimal(A) (istype(A, /mob/living/simple_animal)) -#define isrevenant(A) (istype(A, /mob/living/simple_animal/revenant)) +#define isrevenant(A) (istype(A, /mob/living/basic/revenant)) #define isbot(A) (istype(A, /mob/living/simple_animal/bot)) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 2d05f29a012..03175afaba7 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -521,6 +521,11 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai // and emit less heat. Present on /mob or /datum/mind #define TRAIT_SUPERMATTER_SOOTHER "supermatter_soother" +/// Trait added when a revenant is visible. +#define TRAIT_REVENANT_REVEALED "revenant_revealed" +/// Trait added when a revenant has been inhibited (typically by the bane of a holy weapon) +#define TRAIT_REVENANT_INHIBITED "revenant_inhibited" + /// Trait which prevents you from becoming overweight #define TRAIT_NOFAT "cant_get_fat" diff --git a/code/__HELPERS/chat.dm b/code/__HELPERS/chat.dm index 31f9ad271d3..fb07f2f107d 100644 --- a/code/__HELPERS/chat.dm +++ b/code/__HELPERS/chat.dm @@ -92,8 +92,8 @@ it will be sent to all connected chats. var/link = FOLLOW_LINK(observer, source) to_chat(observer, "[link] [message]") -/// Sends a message to everyone with blob telepathy, and all observers -/proc/blob_telepathy(message, source) - for(var/mob/creature as anything in GLOB.blob_telepathy_mobs) +/// Sends a message to everyone within the list, as well as all observers. +/proc/relay_to_list_and_observers(message, list/mob_list, source) + for(var/mob/creature as anything in mob_list) to_chat(creature, message) send_to_observers(message, source) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 5fc93a2494e..5ee1f4e6439 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -55,6 +55,9 @@ GLOBAL_LIST_EMPTY(current_observers_list) /// All living mobs which can hear blob telepathy GLOBAL_LIST_EMPTY(blob_telepathy_mobs) +/// All "living" (because revenants are in between mortal planes or whatever) mobs that can hear revenants +GLOBAL_LIST_EMPTY(revenant_relay_mobs) + ///underages who have been reported to security for trying to buy things they shouldn't, so they can't spam GLOBAL_LIST_EMPTY(narcd_underages) diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm index f9a878c3da9..93220a1045e 100644 --- a/code/_globalvars/phobias.dm +++ b/code/_globalvars/phobias.dm @@ -95,13 +95,13 @@ GLOBAL_LIST_INIT(phobia_mobs, list( /mob/living/basic/faithless, /mob/living/basic/ghost, /mob/living/basic/heretic_summon, + /mob/living/basic/revenant, /mob/living/simple_animal/bot/mulebot/paranormal, /mob/living/simple_animal/hostile/construct, /mob/living/simple_animal/hostile/dark_wizard, /mob/living/simple_animal/hostile/skeleton, /mob/living/simple_animal/hostile/wizard, /mob/living/simple_animal/hostile/zombie, - /mob/living/simple_animal/revenant, /mob/living/simple_animal/shade, )), )) diff --git a/code/datums/components/blob_minion.dm b/code/datums/components/blob_minion.dm index 41f58231e2d..8261a7ad1fd 100644 --- a/code/datums/components/blob_minion.dm +++ b/code/datums/components/blob_minion.dm @@ -141,7 +141,7 @@ SIGNAL_HANDLER var/spanned_message = minion.say_quote(message) var/rendered = span_blob("\[Blob Telepathy\] [minion.real_name] [spanned_message]") - blob_telepathy(rendered, minion) + relay_to_list_and_observers(rendered, GLOB.blob_telepathy_mobs, minion) return COMPONENT_CANNOT_SPEAK /// Called when a blob minion is transformed into something else, hopefully a spore into a zombie diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index b7c66873aee..4f6754231db 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -743,8 +743,8 @@ . = ..() /datum/dynamic_ruleset/midround/from_ghosts/revenant/generate_ruleset_body(mob/applicant) - var/mob/living/simple_animal/revenant/revenant = new(pick(spawn_locs)) - revenant.key = applicant.key + var/mob/living/basic/revenant/revenant = new(pick(spawn_locs)) + applicant.mind.transfer_to(revenant) message_admins("[ADMIN_LOOKUPFLW(revenant)] has been made into a revenant by the midround ruleset.") log_game("[key_name(revenant)] was spawned as a revenant by the midround ruleset.") return revenant diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm index 38e88817de2..d87574c092d 100644 --- a/code/modules/antagonists/blob/overmind.dm +++ b/code/modules/antagonists/blob/overmind.dm @@ -294,7 +294,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) if(client.prefs.muted & MUTE_IC) to_chat(src, span_boldwarning("You cannot send IC messages (muted).")) return - if (!(ignore_spam || forced) && src.client.handle_spam_prevention(message,MUTE_IC)) + if (!(ignore_spam || forced) && src.client.handle_spam_prevention(message, MUTE_IC)) return if (stat) @@ -313,7 +313,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) var/message_a = say_quote(message) var/rendered = span_big(span_blob("\[Blob Telepathy\] [name]([blobstrain.name]) [message_a]")) - blob_telepathy(rendered, src) + relay_to_list_and_observers(rendered, GLOB.blob_telepathy_mobs, src) /mob/camera/blob/blob_act(obj/structure/blob/B) return diff --git a/code/modules/events/ghost_role/revenant_event.dm b/code/modules/events/ghost_role/revenant_event.dm index 27f3597a7ad..f739a3e13d4 100644 --- a/code/modules/events/ghost_role/revenant_event.dm +++ b/code/modules/events/ghost_role/revenant_event.dm @@ -54,11 +54,12 @@ if(!spawn_locs.len) //If we can't find THAT, then just give up and cry return MAP_ERROR - var/mob/living/simple_animal/revenant/revvie = new(pick(spawn_locs)) - revvie.key = selected.key + var/mob/living/basic/revenant/revvie = new(pick(spawn_locs)) + selected.mind.transfer_to(revvie) message_admins("[ADMIN_LOOKUPFLW(revvie)] has been made into a revenant by an event.") revvie.log_message("was spawned as a revenant by an event.", LOG_GAME) spawned_mobs += revvie + qdel(selected) return SUCCESSFUL_SPAWN #undef REVENANT_SPAWN_THRESHOLD diff --git a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm index a214eb48e0c..805c72a3267 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm @@ -31,7 +31,7 @@ on_clear_callback = CALLBACK(src, PROC_REF(on_cult_rune_removed)), \ effects_we_clear = list(/obj/effect/rune, /obj/effect/heretic_rune, /obj/effect/cosmic_rune), \ ) - AddElement(/datum/element/bane, target_type = /mob/living/simple_animal/revenant, damage_multiplier = 0, added_damage = 25, requires_combat_mode = FALSE) + AddElement(/datum/element/bane, target_type = /mob/living/basic/revenant, damage_multiplier = 0, added_damage = 25, requires_combat_mode = FALSE) if(!GLOB.holy_weapon_type && type == /obj/item/nullrod) var/list/rods = list() diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm index 5d3c6e276b4..8a10a058341 100644 --- a/code/modules/library/bibles.dm +++ b/code/modules/library/bibles.dm @@ -369,7 +369,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list( tip_text = "Clear rune", \ effects_we_clear = list(/obj/effect/rune, /obj/effect/heretic_rune, /obj/effect/cosmic_rune), \ ) - AddElement(/datum/element/bane, target_type = /mob/living/simple_animal/revenant, damage_multiplier = 0, added_damage = 25, requires_combat_mode = FALSE) + AddElement(/datum/element/bane, target_type = /mob/living/basic/revenant, damage_multiplier = 0, added_damage = 25, requires_combat_mode = FALSE) /obj/item/book/bible/syndicate/attack_self(mob/living/carbon/human/user, modifiers) if(!uses || !istype(user)) diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm new file mode 100644 index 00000000000..b3c6935c92e --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm @@ -0,0 +1,444 @@ +/// Source for a trait we get when we're stunned +#define REVENANT_STUNNED_TRAIT "revenant_got_stunned" + +/// Revenants: "Ghosts" that are invisible and move like ghosts, cannot take damage while invisible +/// Can hear deadchat, but are NOT normal ghosts and do NOT have x-ray vision +/// Admin-spawn or random event +/mob/living/basic/revenant + name = "revenant" + desc = "A malevolent spirit." + icon = 'icons/mob/simple/mob.dmi' + icon_state = "revenant_idle" + mob_biotypes = MOB_SPIRIT + incorporeal_move = INCORPOREAL_MOVE_JAUNT + invisibility = INVISIBILITY_REVENANT + health = INFINITY //Revenants don't use health, they use essence instead + maxHealth = INFINITY + plane = GHOST_PLANE + sight = SEE_SELF + throwforce = 0 + + // Going for faint purple spoopy ghost + lighting_cutoff_red = 20 + lighting_cutoff_green = 15 + lighting_cutoff_blue = 35 + + friendly_verb_continuous = "touches" + friendly_verb_simple = "touch" + response_help_continuous = "passes through" + response_help_simple = "pass through" + response_disarm_continuous = "swings through" + response_disarm_simple = "swing through" + response_harm_continuous = "punches through" + response_harm_simple = "punch through" + unsuitable_atmos_damage = 0 + damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) //I don't know how you'd apply those, but revenants no-sell them anyway. + habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + minimum_survivable_temperature = 0 + maximum_survivable_temperature = INFINITY + + status_flags = NONE + density = FALSE + move_resist = MOVE_FORCE_OVERPOWERING + mob_size = MOB_SIZE_TINY + pass_flags = PASSTABLE | PASSGRILLE | PASSMOB + speed = 1 + unique_name = TRUE + hud_possible = list(ANTAG_HUD) + hud_type = /datum/hud/revenant + + /// The icon we use while just floating around. + var/icon_idle = "revenant_idle" + /// The icon we use while in a revealed state. + var/icon_reveal = "revenant_revealed" + /// The icon we use when stunned (temporarily frozen) + var/icon_stun = "revenant_stun" + /// The icon we use while draining someone. + var/icon_drain = "revenant_draining" + + /// Are we currently dormant (ectoplasm'd)? + var/dormant = FALSE + /// Are we currently draining someone? + var/draining = FALSE + /// Have we already given this revenant abilities? + var/generated_objectives_and_spells = FALSE + + /// Lazylist of drained mobs to ensure that we don't steal a soul from someone twice + var/list/drained_mobs = null + /// List of action ability datums to grant on Initialize. Keep in mind that anything with the `/aoe/revenant` subtype starts locked by default. + var/static/list/datum/action/abilities = list( + /datum/action/cooldown/spell/aoe/revenant/blight, + /datum/action/cooldown/spell/aoe/revenant/defile, + /datum/action/cooldown/spell/aoe/revenant/haunt_object, + /datum/action/cooldown/spell/aoe/revenant/malfunction, + /datum/action/cooldown/spell/aoe/revenant/overload, + /datum/action/cooldown/spell/list_target/telepathy/revenant, + ) + + /// The resource, and health, of revenants. + var/essence = 75 + /// The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount. + var/max_essence = 75 + /// If the revenant regenerates essence or not + var/essence_regenerating = TRUE + /// How much essence regenerates per second + var/essence_regen_amount = 2.5 + /// How much essence the revenant has stolen + var/essence_accumulated = 0 + /// How much stolen essence is available for unlocks + var/essence_excess = 0 + /// How long the revenant is revealed for, is about 2 seconds times this var. + var/unreveal_time = 0 + /// How many perfect, regen-cap increasing souls the revenant has. //TODO, add objective for getting a perfect soul(s?) + var/perfectsouls = 0 + +/mob/living/basic/revenant/Initialize(mapload) + . = ..() + AddElement(/datum/element/simple_flying) + add_traits(list(TRAIT_SPACEWALK, TRAIT_SIXTHSENSE, TRAIT_FREE_HYPERSPACE_MOVEMENT), INNATE_TRAIT) + + for(var/ability in abilities) + var/datum/action/spell = new ability(src) + spell.Grant(src) + + RegisterSignal(src, COMSIG_LIVING_BANED, PROC_REF(on_baned)) + RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move)) + RegisterSignal(src, COMSIG_LIVING_LIFE, PROC_REF(on_life)) + set_random_revenant_name() + + GLOB.revenant_relay_mobs |= src + +/mob/living/basic/revenant/Destroy() + GLOB.revenant_relay_mobs -= src + return ..() + +/mob/living/basic/revenant/Login() + . = ..() + if(!. || isnull(client)) + return FALSE + + var/static/cached_string = null + if(isnull(cached_string)) + cached_string = examine_block(jointext(create_login_string(), "\n")) + + to_chat(src, cached_string, type = MESSAGE_TYPE_INFO) + + if(generated_objectives_and_spells) + return TRUE + + generated_objectives_and_spells = TRUE + mind.set_assigned_role(SSjob.GetJobType(/datum/job/revenant)) + mind.special_role = ROLE_REVENANT + SEND_SOUND(src, sound('sound/effects/ghost.ogg')) + mind.add_antag_datum(/datum/antagonist/revenant) + return TRUE + +/// Signal Handler Injection to handle Life() stuff for revenants +/mob/living/basic/revenant/proc/on_life(seconds_per_tick = SSMOBS_DT, times_fired) + SIGNAL_HANDLER + + if(dormant) + return COMPONENT_LIVING_CANCEL_LIFE_PROCESSING + + if(HAS_TRAIT(src, TRAIT_REVENANT_REVEALED) && essence <= 0) + death() + return COMPONENT_LIVING_CANCEL_LIFE_PROCESSING + + if(essence_regenerating && !HAS_TRAIT(src, TRAIT_REVENANT_INHIBITED) && essence < max_essence) //While inhibited, essence will not regenerate + var/change_in_time = DELTA_WORLD_TIME(SSmobs) + essence = min(essence + (essence_regen_amount * change_in_time), max_essence) + update_mob_action_buttons() //because we update something required by our spells in life, we need to update our buttons + + update_appearance(UPDATE_ICON) + update_health_hud() + +/mob/living/basic/revenant/get_status_tab_items() + . = ..() + . += "Current Essence: [essence >= max_essence ? essence : "[essence] / [max_essence]"] E" + . += "Total Essence Stolen: [essence_accumulated] SE" + . += "Unused Stolen Essence: [essence_excess] SE" + . += "Perfect Souls Stolen: [perfectsouls]" + +/mob/living/basic/revenant/update_health_hud() + if(isnull(hud_used)) + return + + var/essencecolor = "#8F48C6" + if(essence > max_essence) + essencecolor = "#9A5ACB" //oh boy you've got a lot of essence + else if(essence <= 0) + essencecolor = "#1D2953" //oh jeez you're dying + hud_used.healths.maptext = MAPTEXT("

[essence]E
") + +/mob/living/basic/revenant/say(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null, filterproof = null, message_range = 7, datum/saymode/saymode = null) + if(!message) + return + + if(client) + if(client.prefs.muted & MUTE_IC) + to_chat(src, span_boldwarning("You cannot send IC messages (muted).")) + return + if (!(ignore_spam || forced) && client.handle_spam_prevention(message, MUTE_IC)) + return + + if(sanitize) + message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN)) + + log_talk(message, LOG_SAY) + var/rendered = span_deadsay("UNDEAD: [src] says, \"[message]\"") + relay_to_list_and_observers(rendered, GLOB.revenant_relay_mobs, src) + +/mob/living/basic/revenant/ClickOn(atom/A, params) //revenants can't interact with the world directly, so we gotta do some wacky override stuff + var/list/modifiers = params2list(params) + if(LAZYACCESS(modifiers, SHIFT_CLICK)) + ShiftClickOn(A) + return + if(LAZYACCESS(modifiers, ALT_CLICK)) + AltClickNoInteract(src, A) + return + if(LAZYACCESS(modifiers, RIGHT_CLICK)) + ranged_secondary_attack(A, modifiers) + return + + if(ishuman(A) && in_range(src, A)) + attempt_harvest(A) + +/mob/living/basic/revenant/ranged_secondary_attack(atom/target, modifiers) + if(HAS_TRAIT(src, TRAIT_REVENANT_INHIBITED) || HAS_TRAIT(src, TRAIT_REVENANT_REVEALED) || HAS_TRAIT(src, TRAIT_NO_TRANSFORM) || !Adjacent(target) || !incorporeal_move_check(target)) + return + + var/list/icon_dimensions = get_icon_dimensions(target.icon) + var/orbitsize = (icon_dimensions["width"] + icon_dimensions["height"]) * 0.5 + orbitsize -= (orbitsize / world.icon_size) * (world.icon_size * 0.25) + orbit(target, orbitsize) + +/mob/living/basic/revenant/adjust_health(amount, updating_health = TRUE, forced = FALSE) + if(!forced && !HAS_TRAIT(src, TRAIT_REVENANT_REVEALED)) + return 0 + + . = amount + + essence = max(0, essence - amount) + if(updating_health) + update_health_hud() + if(essence == 0) + death() + + return . + +/mob/living/basic/revenant/orbit(atom/target) + setDir(SOUTH) // reset dir so the right directional sprites show up + return ..() + +/mob/living/basic/revenant/update_icon_state() + . = ..() + + if(HAS_TRAIT(src, TRAIT_REVENANT_REVEALED)) + icon_state = icon_reveal + return + + if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) + if(draining) + icon_state = icon_drain + else + icon_state = icon_stun + + return + + icon_state = icon_idle + +/mob/living/basic/revenant/med_hud_set_health() + return //we use no hud + +/mob/living/basic/revenant/med_hud_set_status() + return //we use no hud + +/mob/living/basic/revenant/dust(just_ash, drop_items, force) + death() + +/mob/living/basic/revenant/gib() + death() + +/mob/living/basic/revenant/can_perform_action(atom/movable/target, action_bitflags) + return FALSE + +/mob/living/basic/revenant/ex_act(severity, target) + return FALSE //Immune to the effects of explosions. + +/mob/living/basic/revenant/blob_act(obj/structure/blob/attacking_blob) + return //blah blah blobs aren't in tune with the spirit world, or something. + +/mob/living/basic/revenant/singularity_act() + return //don't walk into the singularity expecting to find corpses, okay? + +/mob/living/basic/revenant/narsie_act() + return //most humans will now be either bones or harvesters, but we're still un-alive. + +/mob/living/basic/revenant/bullet_act() + if(!HAS_TRAIT(src, TRAIT_REVENANT_REVEALED) || dormant) + return BULLET_ACT_FORCE_PIERCE + return ..() + +/mob/living/basic/revenant/death() + if(!HAS_TRAIT(src, TRAIT_REVENANT_REVEALED) || dormant) //Revenants cannot die if they aren't revealed //or are already dead + return + ADD_TRAIT(src, TRAIT_NO_TRANSFORM, REVENANT_STUNNED_TRAIT) + dormant = TRUE + + visible_message( + span_warning("[src] lets out a waning screech as violet mist swirls around its dissolving body!"), + span_revendanger("NO! No... it's too late, you can feel your essence [pick("breaking apart", "drifting away")]..."), + ) + + invisibility = 0 + icon_state = "revenant_draining" + playsound(src, 'sound/effects/screech.ogg', 100, TRUE) + + animate(src, alpha = 0, time = 3 SECONDS) + addtimer(CALLBACK(src, PROC_REF(move_to_ectoplasm)), 3 SECONDS) + +/// Forces the mob, once dormant, to move inside ectoplasm until it can regenerate. +/mob/living/basic/revenant/proc/move_to_ectoplasm() + if(QDELETED(src) || !dormant) // something fucky happened, abort. we MUST be dormant to go inside the ectoplasm. + return + + visible_message(span_danger("[src]'s body breaks apart into a fine pile of blue dust.")) + + var/obj/item/ectoplasm/revenant/goop = new(get_turf(src)) // the ectoplasm will handle moving us out of dormancy + goop.old_ckey = client.ckey + goop.revenant = src + forceMove(goop) + +/mob/living/basic/revenant/proc/on_move(datum/source, atom/entering_loc) + SIGNAL_HANDLER + if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) // just in case it occurs, need to provide some feedback + balloon_alert(src, "can't move!") + return + + if(isnull(orbiting) || incorporeal_move_check(entering_loc)) + return + + // we're about to go somewhere we aren't meant to, end the orbit and block the move. feedback will be given in `incorporeal_move_check()` + orbiting.end_orbit(src) + return COMPONENT_MOVABLE_BLOCK_PRE_MOVE + +/// Generates the information the player needs to know how to play their role, and returns it as a list. +/mob/living/basic/revenant/proc/create_login_string() + RETURN_TYPE(/list) + var/list/returnable_list = list() + returnable_list += span_deadsay(span_boldbig("You are a revenant.")) + returnable_list += span_bold("Your formerly mundane spirit has been infused with alien energies and empowered into a revenant.") + returnable_list += span_bold("You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds.") + returnable_list += span_bold("You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.") + returnable_list += span_bold("To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities.") + returnable_list += span_bold("You do not remember anything of your past lives, nor will you remember anything about this one after your death.") + returnable_list += span_bold("Be sure to read the wiki page to learn more.") + return returnable_list + +/mob/living/basic/revenant/proc/set_random_revenant_name() + var/list/built_name_strings = list() + built_name_strings += pick(strings(REVENANT_NAME_FILE, "spirit_type")) + built_name_strings += " of " + built_name_strings += pick(strings(REVENANT_NAME_FILE, "adverb")) + built_name_strings += pick(strings(REVENANT_NAME_FILE, "theme")) + name = built_name_strings.Join("") + +/mob/living/basic/revenant/proc/on_baned(obj/item/weapon, mob/living/user) + SIGNAL_HANDLER + visible_message( + span_warning("[src] violently flinches!"), + span_revendanger("As [weapon] passes through you, you feel your essence draining away!"), + ) + apply_status_effect(/datum/status_effect/revenant/inhibited, 3 SECONDS) + +/// Incorporeal move check: blocked by holy-watered tiles and salt piles. +/mob/living/basic/revenant/proc/incorporeal_move_check(atom/destination) + var/turf/open/floor/step_turf = get_turf(destination) + if(isnull(step_turf)) + return TRUE // what? whatever let it happen + + if(step_turf.turf_flags & NOJAUNT) + to_chat(src, span_warning("Some strange aura is blocking the way.")) + return FALSE + + if(locate(/obj/effect/decal/cleanable/food/salt) in step_turf) + balloon_alert(src, "blocked by salt!") + apply_status_effect(/datum/status_effect/revenant/revealed, 2 SECONDS) + apply_status_effect(/datum/status_effect/incapacitating/paralyzed/revenant, 2 SECONDS) + return FALSE + + if(locate(/obj/effect/blessing) in step_turf) + to_chat(src, span_warning("Holy energies block your path!")) + return FALSE + + return TRUE + +/mob/living/basic/revenant/proc/cast_check(essence_cost) + if(QDELETED(src)) + return + + var/turf/current = get_turf(src) + + if(isclosedturf(current)) + to_chat(src, span_revenwarning("You cannot use abilities from inside of a wall.")) + return FALSE + + for(var/obj/thing in current) + if(!thing.density || thing.CanPass(src, get_dir(current, src))) + continue + to_chat(src, span_revenwarning("You cannot use abilities inside of a dense object.")) + return FALSE + + if(HAS_TRAIT(src, TRAIT_REVENANT_INHIBITED)) + to_chat(src, span_revenwarning("Your powers have been suppressed by a nullifying energy!")) + return FALSE + + if(!change_essence_amount(essence_cost, TRUE)) + to_chat(src, span_revenwarning("You lack the essence to use that ability.")) + return FALSE + + return TRUE + +/mob/living/basic/revenant/proc/unlock(essence_cost) + if(essence_excess < essence_cost) + return FALSE + essence_excess -= essence_cost + update_mob_action_buttons() + return TRUE + +/mob/living/basic/revenant/proc/death_reset() + REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, REVENANT_STUNNED_TRAIT) + forceMove(get_turf(src)) + // clean slate, so no more debilitating effects + remove_status_effect(/datum/status_effect/revenant/revealed) + remove_status_effect(/datum/status_effect/incapacitating/paralyzed/revenant) + remove_status_effect(/datum/status_effect/revenant/inhibited) + draining = FALSE + dormant = FALSE + incorporeal_move = INCORPOREAL_MOVE_JAUNT + invisibility = INVISIBILITY_REVENANT + alpha = 255 + +/mob/living/basic/revenant/proc/change_essence_amount(essence_to_change_by, silent = FALSE, source = null) + if(QDELETED(src)) + return FALSE + + if((essence + essence_to_change_by) < 0) + return FALSE + + essence = max(0, essence + essence_to_change_by) + update_health_hud() + + if(essence_to_change_by > 0) + essence_accumulated = max(0, essence_accumulated + essence_to_change_by) + essence_excess = max(0, essence_excess + essence_to_change_by) + + update_mob_action_buttons() + if(!silent) + if(essence_to_change_by > 0) + to_chat(src, span_revennotice("Gained [essence_to_change_by]E [source ? "from [source]":""].")) + else + to_chat(src, span_revenminor("Lost [essence_to_change_by]E [source ? "from [source]":""].")) + return TRUE + +#undef REVENANT_STUNNED_TRAIT diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm similarity index 63% rename from code/modules/antagonists/revenant/revenant_abilities.dm rename to code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm index ef00f51e45d..63f4bbb9dbc 100644 --- a/code/modules/antagonists/revenant/revenant_abilities.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm @@ -1,122 +1,6 @@ #define REVENANT_DEFILE_MIN_DAMAGE 30 #define REVENANT_DEFILE_MAX_DAMAGE 50 -/mob/living/simple_animal/revenant/ClickOn(atom/A, params) //revenants can't interact with the world directly. - var/list/modifiers = params2list(params) - if(LAZYACCESS(modifiers, SHIFT_CLICK)) - ShiftClickOn(A) - return - if(LAZYACCESS(modifiers, ALT_CLICK)) - AltClickNoInteract(src, A) - return - if(LAZYACCESS(modifiers, RIGHT_CLICK)) - ranged_secondary_attack(A, modifiers) - return - - if(ishuman(A)) - //Humans are tagged, so this is fine - if(REF(A) in drained_mobs) - to_chat(src, span_revenwarning("[A]'s soul is dead and empty.") ) - else if(in_range(src, A)) - Harvest(A) - -/mob/living/simple_animal/revenant/ranged_secondary_attack(atom/target, modifiers) - if(revealed || inhibited || HAS_TRAIT(src, TRAIT_NO_TRANSFORM) || !Adjacent(target) || !incorporeal_move_check(target)) - return - - var/list/icon_dimensions = get_icon_dimensions(target.icon) - var/orbitsize = (icon_dimensions["width"] + icon_dimensions["height"]) * 0.5 - orbitsize -= (orbitsize / world.icon_size) * (world.icon_size * 0.25) - orbit(target, orbitsize) - -//Harvest; activated by clicking the target, will try to drain their essence. -/mob/living/simple_animal/revenant/proc/Harvest(mob/living/carbon/human/target) - if(!castcheck(0)) - return - if(draining) - to_chat(src, span_revenwarning("You are already siphoning the essence of a soul!")) - return - if(!target.stat) - to_chat(src, span_revennotice("[target.p_Their()] soul is too strong to harvest.")) - if(prob(10)) - to_chat(target, span_revennotice("You feel as if you are being watched.")) - return - log_combat(src, target, "started to harvest") - face_atom(target) - draining = TRUE - essence_drained += rand(15, 20) - to_chat(src, span_revennotice("You search for the soul of [target].")) - if(do_after(src, rand(10, 20), target, timed_action_flags = IGNORE_HELD_ITEM)) //did they get deleted in that second? - if(target.ckey) - to_chat(src, span_revennotice("[target.p_Their()] soul burns with intelligence.")) - essence_drained += rand(20, 30) - if(target.stat != DEAD && !HAS_TRAIT(target, TRAIT_WEAK_SOUL)) - to_chat(src, span_revennotice("[target.p_Their()] soul blazes with life!")) - essence_drained += rand(40, 50) - if(HAS_TRAIT(target, TRAIT_WEAK_SOUL) && !target.ckey) - to_chat(src, span_revennotice("[target.p_Their()] soul is weak and underdeveloped. They won't be worth very much.")) - essence_drained = 5 - else - to_chat(src, span_revennotice("[target.p_Their()] soul is weak and faltering.")) - if(do_after(src, rand(15, 20), target, timed_action_flags = IGNORE_HELD_ITEM)) //did they get deleted NOW? - switch(essence_drained) - if(1 to 30) - to_chat(src, span_revennotice("[target] will not yield much essence. Still, every bit counts.")) - if(30 to 70) - to_chat(src, span_revennotice("[target] will yield an average amount of essence.")) - if(70 to 90) - to_chat(src, span_revenboldnotice("Such a feast! [target] will yield much essence to you.")) - if(90 to INFINITY) - to_chat(src, span_revenbignotice("Ah, the perfect soul. [target] will yield massive amounts of essence to you.")) - if(do_after(src, rand(15, 25), target, timed_action_flags = IGNORE_HELD_ITEM)) //how about now - if(!target.stat) - to_chat(src, span_revenwarning("[target.p_Theyre()] now powerful enough to fight off your draining.")) - to_chat(target, span_boldannounce("You feel something tugging across your body before subsiding.")) - draining = 0 - essence_drained = 0 - return //hey, wait a minute... - to_chat(src, span_revenminor("You begin siphoning essence from [target]'s soul.")) - if(target.stat != DEAD) - to_chat(target, span_warning("You feel a horribly unpleasant draining sensation as your grip on life weakens...")) - if(target.stat == SOFT_CRIT) - target.Stun(46) - reveal(46) - stun(46) - target.visible_message(span_warning("[target] suddenly rises slightly into the air, [target.p_their()] skin turning an ashy gray.")) - if(target.can_block_magic(MAGIC_RESISTANCE_HOLY)) - to_chat(src, span_revenminor("Something's wrong! [target] seems to be resisting the siphoning, leaving you vulnerable!")) - target.visible_message(span_warning("[target] slumps onto the ground."), \ - span_revenwarning("Violet lights, dancing in your vision, receding--")) - draining = FALSE - return - var/datum/beam/B = Beam(target,icon_state="drain_life") - if(do_after(src, 46, target, timed_action_flags = IGNORE_HELD_ITEM)) //As one cannot prove the existance of ghosts, ghosts cannot prove the existance of the target they were draining. - change_essence_amount(essence_drained, FALSE, target) - if(essence_drained <= 90 && target.stat != DEAD && !HAS_TRAIT(target, TRAIT_WEAK_SOUL)) - essence_regen_cap += 5 - to_chat(src, span_revenboldnotice("The absorption of [target]'s living soul has increased your maximum essence level. Your new maximum essence is [essence_regen_cap].")) - if(essence_drained > 90) - essence_regen_cap += 15 - perfectsouls++ - to_chat(src, span_revenboldnotice("The perfection of [target]'s soul has increased your maximum essence level. Your new maximum essence is [essence_regen_cap].")) - to_chat(src, span_revennotice("[target]'s soul has been considerably weakened and will yield no more essence for the time being.")) - target.visible_message(span_warning("[target] slumps onto the ground."), \ - span_revenwarning("Violets lights, dancing in your vision, getting clo--")) - drained_mobs += REF(target) - if(target.stat != DEAD) - target.investigate_log("has died from revenant harvest.", INVESTIGATE_DEATHS) - target.death(FALSE) - else - to_chat(src, span_revenwarning("[target ? "[target] has":"[target.p_Theyve()]"] been drawn out of your grasp. The link has been broken.")) - if(target) //Wait, target is WHERE NOW? - target.visible_message(span_warning("[target] slumps onto the ground."), \ - span_revenwarning("Violets lights, dancing in your vision, receding--")) - qdel(B) - else - to_chat(src, span_revenwarning("You are not close enough to siphon [target ? "[target]'s":"[target.p_their()]"] soul. The link has been broken.")) - draining = FALSE - essence_drained = 0 - //Transmit: the revemant's only direct way to communicate. Sends a single message silently to a single mob /datum/action/cooldown/spell/list_target/telepathy/revenant name = "Revenant Transmit" @@ -170,8 +54,8 @@ stack_trace("[type] was owned by a non-revenant mob, please don't.") return FALSE - var/mob/living/simple_animal/revenant/ghost = owner - if(ghost.inhibited) + var/mob/living/basic/revenant/ghost = owner + if(ghost.dormant || HAS_TRAIT(ghost, TRAIT_REVENANT_INHIBITED)) return FALSE if(locked && ghost.essence_excess <= unlock_amount) return FALSE @@ -183,7 +67,7 @@ /datum/action/cooldown/spell/aoe/revenant/get_things_to_cast_on(atom/center) return RANGE_TURFS(aoe_radius, center) -/datum/action/cooldown/spell/aoe/revenant/before_cast(mob/living/simple_animal/revenant/cast_on) +/datum/action/cooldown/spell/aoe/revenant/before_cast(mob/living/basic/revenant/cast_on) . = ..() if(. & SPELL_CANCEL_CAST) return @@ -201,16 +85,16 @@ reset_spell_cooldown() return . | SPELL_CANCEL_CAST - if(!cast_on.castcheck(-cast_amount)) + if(!cast_on.cast_check(-cast_amount)) reset_spell_cooldown() return . | SPELL_CANCEL_CAST -/datum/action/cooldown/spell/aoe/revenant/after_cast(mob/living/simple_animal/revenant/cast_on) +/datum/action/cooldown/spell/aoe/revenant/after_cast(mob/living/basic/revenant/cast_on) . = ..() if(reveal_duration > 0 SECONDS) - cast_on.reveal(reveal_duration) + cast_on.apply_status_effect(/datum/status_effect/revenant/revealed, reveal_duration) if(stun_duration > 0 SECONDS) - cast_on.stun(stun_duration) + cast_on.apply_status_effect(/datum/status_effect/incapacitating/paralyzed/revenant, stun_duration) //Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people. /datum/action/cooldown/spell/aoe/revenant/overload @@ -226,10 +110,10 @@ /// The range the shocks from the lights go var/shock_range = 2 - /// The damage the shcoskf rom the lgihts do + /// The damage the shocks from the lights do var/shock_damage = 15 -/datum/action/cooldown/spell/aoe/revenant/overload/cast_on_thing_in_aoe(turf/victim, mob/living/simple_animal/revenant/caster) +/datum/action/cooldown/spell/aoe/revenant/overload/cast_on_thing_in_aoe(turf/victim, mob/living/basic/revenant/caster) for(var/obj/machinery/light/light in victim) if(!light.on) continue @@ -241,7 +125,7 @@ new /obj/effect/temp_visual/revenant(get_turf(light)) addtimer(CALLBACK(src, PROC_REF(overload_shock), light, caster), 20) -/datum/action/cooldown/spell/aoe/revenant/overload/proc/overload_shock(obj/machinery/light/to_shock, mob/living/simple_animal/revenant/caster) +/datum/action/cooldown/spell/aoe/revenant/overload/proc/overload_shock(obj/machinery/light/to_shock, mob/living/basic/revenant/caster) flick("[to_shock.base_state]2", to_shock) for(var/mob/living/carbon/human/human_mob in view(shock_range, to_shock)) if(human_mob == caster) @@ -266,7 +150,7 @@ reveal_duration = 4 SECONDS stun_duration = 2 SECONDS -/datum/action/cooldown/spell/aoe/revenant/defile/cast_on_thing_in_aoe(turf/victim, mob/living/simple_animal/revenant/caster) +/datum/action/cooldown/spell/aoe/revenant/defile/cast_on_thing_in_aoe(turf/victim, mob/living/basic/revenant/caster) for(var/obj/effect/blessing/blessing in victim) qdel(blessing) new /obj/effect/temp_visual/revenant(victim) @@ -315,7 +199,7 @@ unlock_amount = 125 // A note to future coders: do not replace this with an EMP because it will wreck malf AIs and everyone will hate you. -/datum/action/cooldown/spell/aoe/revenant/malfunction/cast_on_thing_in_aoe(turf/victim, mob/living/simple_animal/revenant/caster) +/datum/action/cooldown/spell/aoe/revenant/malfunction/cast_on_thing_in_aoe(turf/victim, mob/living/basic/revenant/caster) for(var/mob/living/simple_animal/bot/bot in victim) if(!(bot.bot_cover_flags & BOT_COVER_EMAGGED)) new /obj/effect/temp_visual/revenant(bot.loc) @@ -356,7 +240,7 @@ cast_amount = 50 unlock_amount = 75 -/datum/action/cooldown/spell/aoe/revenant/blight/cast_on_thing_in_aoe(turf/victim, mob/living/simple_animal/revenant/caster) +/datum/action/cooldown/spell/aoe/revenant/blight/cast_on_thing_in_aoe(turf/victim, mob/living/basic/revenant/caster) for(var/mob/living/mob in victim) if(mob == caster) continue @@ -430,7 +314,7 @@ return things -/datum/action/cooldown/spell/aoe/revenant/haunt_object/cast_on_thing_in_aoe(obj/item/victim, mob/living/simple_animal/revenant/caster) +/datum/action/cooldown/spell/aoe/revenant/haunt_object/cast_on_thing_in_aoe(obj/item/victim, mob/living/basic/revenant/caster) var/distance_from_caster = get_dist(get_turf(victim), get_turf(caster)) var/chance_of_haunting = 150 * (1 / distance_from_caster) if(!prob(chance_of_haunting)) diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm new file mode 100644 index 00000000000..e59dd1f772f --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_effects.dm @@ -0,0 +1,83 @@ +/// Parent type for all unique revenant status effects +/datum/status_effect/revenant + +/datum/status_effect/revenant/on_creation(mob/living/new_owner, duration) + if(isnum(duration)) + src.duration = duration + return ..() + +/datum/status_effect/revenant/revealed + id = "revenant_revealed" + +/datum/status_effect/revenant/revealed/on_creation(mob/living/new_owner, duration) + if(isnum(duration)) + src.duration = duration + return ..() + +/datum/status_effect/revenant/revealed/on_apply() + . = ..() + if(!.) + return FALSE + owner.orbiting?.end_orbit(src) + + ADD_TRAIT(owner, TRAIT_REVENANT_REVEALED, TRAIT_STATUS_EFFECT(id)) + owner.invisibility = 0 + owner.incorporeal_move = FALSE + owner.update_appearance(UPDATE_ICON) + owner.update_mob_action_buttons() + +/datum/status_effect/revenant/revealed/on_remove() + REMOVE_TRAIT(owner, TRAIT_REVENANT_REVEALED, TRAIT_STATUS_EFFECT(id)) + + owner.incorporeal_move = INCORPOREAL_MOVE_JAUNT + owner.invisibility = INVISIBILITY_REVENANT + owner.update_appearance(UPDATE_ICON) + owner.update_mob_action_buttons() + return ..() + +/datum/status_effect/revenant/inhibited + id = "revenant_inhibited" + +/datum/status_effect/revenant/inhibited/on_creation(mob/living/new_owner, duration) + if(isnum(duration)) + src.duration = duration + return ..() + +/datum/status_effect/revenant/inhibited/on_apply() + . = ..() + if(!.) + return FALSE + owner.orbiting?.end_orbit(src) + + ADD_TRAIT(owner, TRAIT_REVENANT_INHIBITED, TRAIT_STATUS_EFFECT(id)) + owner.update_appearance(UPDATE_ICON) + + owner.balloon_alert(owner, "inhibited!") + +/datum/status_effect/revenant/inhibited/on_remove() + REMOVE_TRAIT(owner, TRAIT_REVENANT_INHIBITED, TRAIT_STATUS_EFFECT(id)) + owner.update_appearance(UPDATE_ICON) + + owner.balloon_alert(owner, "uninhibited") + return ..() + +/datum/status_effect/incapacitating/paralyzed/revenant + id = "revenant_paralyzed" + +/datum/status_effect/incapacitating/paralyzed/revenant/on_apply() + . = ..() + if(!.) + return FALSE + owner.orbiting?.end_orbit(src) + + ADD_TRAIT(owner, TRAIT_NO_TRANSFORM, TRAIT_STATUS_EFFECT(id)) + owner.balloon_alert(owner, "can't move!") + owner.update_mob_action_buttons() + owner.update_appearance(UPDATE_ICON) + +/datum/status_effect/incapacitating/paralyzed/revenant/on_remove() + REMOVE_TRAIT(owner, TRAIT_NO_TRANSFORM, TRAIT_STATUS_EFFECT(id)) + owner.update_mob_action_buttons() + owner.balloon_alert(owner, "can move again") + + return ..() diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_harvest.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_harvest.dm new file mode 100644 index 00000000000..21b8cd7feb1 --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_harvest.dm @@ -0,0 +1,143 @@ +// This file contains the proc we use for revenant harvesting because it is a very long and bulky proc that takes up a lot of space elsewhere + +/// Container proc for `harvest()`, handles the pre-checks as well as potential early-exits for any reason. +/// Will return FALSE if we can't execute `harvest()`, or will otherwise the result of `harvest()`: a boolean value. +/mob/living/basic/revenant/proc/attempt_harvest(mob/living/carbon/human/target) + if(LAZYFIND(drained_mobs, REF(target))) + to_chat(src, span_revenwarning("[target]'s soul is dead and empty.")) + return FALSE + + if(!cast_check(0)) + return FALSE + + if(draining) + to_chat(src, span_revenwarning("You are already siphoning the essence of a soul!")) + return FALSE + + draining = TRUE + var/value_to_return = harvest_soul(target) + if(!value_to_return) + log_combat(src, target, "stopped the harvest of") + draining = FALSE + + return value_to_return + +/// Harvest; activated by clicking a target, will try to drain their essence. Handles all messages and handling of the target. +/// Returns FALSE if we exit out of the harvest, TRUE if it is fully done. +/mob/living/basic/revenant/proc/harvest_soul(mob/living/carbon/human/target) // this isn't in the main revenant code file because holyyyy shit it's long + if(QDELETED(target)) // what + return FALSE + + // cache pronouns in case they get deleted as well as be a nice micro-opt due to the multiple times we use them + var/target_their = target.p_their() + var/target_Their = target.p_Their() + var/target_Theyre = target.p_Theyre() + var/target_They_have = "[target.p_They()] [target.p_have()]" + + if(target.stat == CONSCIOUS) + to_chat(src, span_revennotice("[target_Their] soul is too strong to harvest.")) + if(prob(10)) + to_chat(target, span_revennotice("You feel as if you are being watched.")) + return FALSE + + log_combat(src, target, "started to harvest") + face_atom(target) + var/essence_drained = rand(15, 20) + + to_chat(src, span_revennotice("You search for the soul of [target].")) + + if(!do_after(src, (rand(10, 20) DECISECONDS), target, timed_action_flags = IGNORE_HELD_ITEM)) //did they get deleted in that second? + return FALSE + + var/target_has_client = !isnull(target.client) + if(target_has_client || target.ckey) // any target that has been occupied with a ckey is considered "intelligent" + to_chat(src, span_revennotice("[target_Their] soul burns with intelligence.")) + essence_drained += rand(20, 30) + + if(target.stat != DEAD && !HAS_TRAIT(target, TRAIT_WEAK_SOUL)) + to_chat(src, span_revennotice("[target_Their] soul blazes with life!")) + essence_drained += rand(40, 50) + + if(!target_has_client && HAS_TRAIT(target, TRAIT_WEAK_SOUL)) + to_chat(src, span_revennotice("[target_Their] soul is weak and underdeveloped. They won't be worth very much.")) + essence_drained = 5 + + to_chat(src, span_revennotice("[target_Their] soul is weak and faltering. It's time to harvest.")) + + if(!do_after(src, (rand(15, 20) DECISECONDS), target, timed_action_flags = IGNORE_HELD_ITEM)) + to_chat(src, span_revennotice("The harvest is abandoned.")) + return FALSE + + switch(essence_drained) + if(1 to 30) + to_chat(src, span_revennotice("[target] will not yield much essence. Still, every bit counts.")) + if(30 to 70) + to_chat(src, span_revennotice("[target] will yield an average amount of essence.")) + if(70 to 90) + to_chat(src, span_revenboldnotice("Such a feast! [target] will yield much essence to you.")) + if(90 to INFINITY) + to_chat(src, span_revenbignotice("Ah, the perfect soul. [target] will yield massive amounts of essence to you.")) + + if(!do_after(src, (rand(15, 25) DECISECONDS), target, timed_action_flags = IGNORE_HELD_ITEM)) //how about now + to_chat(src, span_revenwarning("You are not close enough to siphon [target ? "[target]'s" : "[target_their]"] soul. The link has been broken.")) + return FALSE + + if(target.stat == CONSCIOUS) + to_chat(src, span_revenwarning("[target_Theyre] now powerful enough to fight off your draining!")) + to_chat(target, span_boldannounce("You feel something tugging across your body before subsiding.")) //hey, wait a minute... + return FALSE + + to_chat(src, span_revenminor("You begin siphoning essence from [target]'s soul.")) + if(target.stat != DEAD) + to_chat(target, span_warning("You feel a horribly unpleasant draining sensation as your grip on life weakens...")) + if(target.stat == SOFT_CRIT) + target.Stun(46) + + apply_status_effect(/datum/status_effect/revenant/revealed, 5 SECONDS) + apply_status_effect(/datum/status_effect/incapacitating/paralyzed/revenant, 5 SECONDS) + + target.visible_message(span_warning("[target] suddenly rises slightly into the air, [target_their] skin turning an ashy gray.")) + + if(target.can_block_magic(MAGIC_RESISTANCE_HOLY)) + to_chat(src, span_revenminor("Something's wrong! [target] seems to be resisting the siphoning, leaving you vulnerable!")) + target.visible_message( + span_warning("[target] slumps onto the ground."), + span_revenwarning("Violet lights, dancing in your vision, receding--"), + ) + return FALSE + + var/datum/beam/draining_beam = Beam(target, icon_state = "drain_life") + if(!do_after(src, 4.6 SECONDS, target, timed_action_flags = IGNORE_HELD_ITEM)) //As one cannot prove the existance of ghosts, ghosts cannot prove the existance of the target they were draining. + to_chat(src, span_revenwarning("[target ? "[target]'s soul has" : "[target_They_have]"] been drawn out of your grasp. The link has been broken.")) + if(target) + target.visible_message( + span_warning("[target] slumps onto the ground."), + span_revenwarning("Violet lights, dancing in your vision, receding--"), + ) + qdel(draining_beam) + return FALSE + + change_essence_amount(essence_drained, FALSE, target) + + if(essence_drained <= 90 && target.stat != DEAD && !HAS_TRAIT(target, TRAIT_WEAK_SOUL)) + max_essence += 5 + to_chat(src, span_revenboldnotice("The absorption of [target]'s living soul has increased your maximum essence level. Your new maximum essence is [max_essence].")) + + if(essence_drained > 90) + max_essence += 15 + perfectsouls++ + to_chat(src, span_revenboldnotice("The perfection of [target]'s soul has increased your maximum essence level. Your new maximum essence is [max_essence].")) + + to_chat(src, span_revennotice("[target]'s soul has been considerably weakened and will yield no more essence for the time being.")) + target.visible_message( + span_warning("[target] slumps onto the ground."), + span_revenwarning("Violet lights, dancing in your vision, getting clo--"), + ) + + LAZYADD(drained_mobs, REF(target)) + if(target.stat != DEAD) + target.investigate_log("has died from revenant harvest.", INVESTIGATE_DEATHS) + target.death(FALSE) + + qdel(draining_beam) + return TRUE diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_items.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_items.dm new file mode 100644 index 00000000000..2c4299258ee --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_items.dm @@ -0,0 +1,110 @@ +//reforming +/obj/item/ectoplasm/revenant + name = "glimmering residue" + desc = "A pile of fine blue dust. Small tendrils of violet mist swirl around it." + icon = 'icons/effects/effects.dmi' + icon_state = "revenantEctoplasm" + w_class = WEIGHT_CLASS_SMALL + /// Are we currently reforming? + var/reforming = TRUE + /// Are we inert (aka distorted such that we can't reform)? + var/inert = FALSE + /// The key of the revenant that we started the reform as + var/old_ckey + /// The revenant we're currently storing + var/mob/living/basic/revenant/revenant + +/obj/item/ectoplasm/revenant/Initialize(mapload) + . = ..() + addtimer(CALLBACK(src, PROC_REF(try_reform)), 1 MINUTES) + +/obj/item/ectoplasm/revenant/Destroy() + if(!QDELETED(revenant)) + qdel(revenant) + return ..() + +/obj/item/ectoplasm/revenant/attack_self(mob/user) + if(!reforming || inert) + return ..() + user.visible_message( + span_notice("[user] scatters [src] in all directions."), + span_notice("You scatter [src] across the area. The particles slowly fade away."), + ) + user.dropItemToGround(src) + qdel(src) + +/obj/item/ectoplasm/revenant/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + . = ..() + if(inert) + return + visible_message(span_notice("[src] breaks into particles upon impact, which fade away to nothingness.")) + qdel(src) + +/obj/item/ectoplasm/revenant/examine(mob/user) + . = ..() + if(inert) + . += span_revennotice("It seems inert.") + else if(reforming) + . += span_revenwarning("It is shifting and distorted. It would be wise to destroy this.") + +/obj/item/ectoplasm/revenant/suicide_act(mob/living/user) + user.visible_message(span_suicide("[user] is inhaling [src]! It looks like [user.p_theyre()] trying to visit the shadow realm!")) + qdel(src) + return OXYLOSS + +/obj/item/ectoplasm/revenant/proc/try_reform() + if(reforming) + reforming = FALSE + reform() + else + inert = TRUE + visible_message(span_warning("[src] settles down and seems lifeless.")) + +/// Actually moves the revenant out of ourself +/obj/item/ectoplasm/revenant/proc/reform() + if(QDELETED(src) || QDELETED(revenant) || inert) + return + + message_admins("Revenant ectoplasm was left undestroyed for 1 minute and is reforming into a new revenant.") + forceMove(drop_location()) //In case it's in a backpack or someone's hand + + var/user_name = old_ckey + if(isnull(revenant.client)) + var/mob/potential_user = get_new_user() + var/datum/mind/potential_mind = potential_user?.mind + if(isnull(potential_mind)) + return + + potential_mind.transfer_to(revenant) + user_name = potential_user.ckey + qdel(potential_user) + + message_admins("[user_name] has been [old_ckey == user_name ? "re":""]made into a revenant by reforming ectoplasm.") + revenant.log_message("was [old_ckey == user_name ? "re":""]made as a revenant by reforming ectoplasm.", LOG_GAME) + visible_message(span_revenboldnotice("[src] suddenly rises into the air before fading away.")) + + revenant.death_reset() + revenant = null + qdel(src) + +/// Handles giving the revenant a new client to control it +/obj/item/ectoplasm/revenant/proc/get_new_user() + message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...") + var/list/candidates = poll_candidates_for_mob("Do you want to be [revenant.name] (reforming)?", ROLE_REVENANT, ROLE_REVENANT, 5 SECONDS, revenant) + + if(!LAZYLEN(candidates)) + message_admins("No candidates were found for the new revenant.") + inert = TRUE + visible_message(span_revenwarning("[src] settles down and seems lifeless.")) + qdel(revenant) + return null + + var/mob/dead/observer/potential_client = pick(candidates) + if(isnull(potential_client)) + qdel(revenant) + message_admins("No ckey was found for the new revenant. Oh well!") + inert = TRUE + visible_message(span_revenwarning("[src] settles down and seems lifeless.")) + return null + + return potential_client diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_objectives.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_objectives.dm new file mode 100644 index 00000000000..7dd391c17e4 --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_objectives.dm @@ -0,0 +1,37 @@ +/datum/objective/revenant + +/datum/objective/revenant/New() + target_amount = rand(350, 600) + explanation_text = "Absorb [target_amount] points of essence from humans." + return ..() + +/datum/objective/revenant/check_completion() + if(!isrevenant(owner.current)) + return FALSE + var/mob/living/basic/revenant/owner_mob = owner.current + if(QDELETED(owner_mob) || owner_mob.stat == DEAD) + return FALSE + var/essence_stolen = owner_mob.essence_accumulated + return essence_stolen >= target_amount + +/datum/objective/revenant_fluff + +/datum/objective/revenant_fluff/New() + var/list/explanation_texts = list( + "Assist and exacerbate existing threats at critical moments.", + "Cause as much chaos and anger as you can without being killed.", + "Damage and render as much of the station rusted and unusable as possible.", + "Disable and cause malfunctions in as many machines as possible.", + "Ensure that any holy weapons are rendered unusable.", + "Heed and obey the requests of the dead, provided that carrying them out wouldn't be too inconvenient or self-destructive.", + "Impersonate or be worshipped as a God.", + "Make the captain as miserable as possible.", + "Make the clown as miserable as possible.", + "Make the crew as miserable as possible.", + "Prevent the use of energy weapons where possible.", + ) + explanation_text = pick(explanation_texts) + return ..() + +/datum/objective/revenant_fluff/check_completion() + return TRUE diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index aacdc60b56a..37a1253ad49 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -12,7 +12,10 @@ /mob/living/proc/Life(seconds_per_tick = SSMOBS_DT, times_fired) set waitfor = FALSE - SEND_SIGNAL(src, COMSIG_LIVING_LIFE, seconds_per_tick, times_fired) + var/signal_result = SEND_SIGNAL(src, COMSIG_LIVING_LIFE, seconds_per_tick, times_fired) + + if(signal_result & COMPONENT_LIVING_CANCEL_LIFE_PROCESSING) // mmm less work + return if (client) var/turf/T = get_turf(src) diff --git a/code/modules/mob/living/simple_animal/revenant.dm b/code/modules/mob/living/simple_animal/revenant.dm deleted file mode 100644 index 6e2ec11afea..00000000000 --- a/code/modules/mob/living/simple_animal/revenant.dm +++ /dev/null @@ -1,548 +0,0 @@ -//Revenants: based off of wraiths from Goon -//"Ghosts" that are invisible and move like ghosts, cannot take damage while invisible -//Can hear deadchat, but are NOT normal ghosts and do NOT have x-ray vision -//Admin-spawn or random event - -/// Source for a trait we get when we're stunned -#define REVENANT_STUNNED_TRAIT "revenant_got_stunned" - -/mob/living/simple_animal/revenant - name = "revenant" - desc = "A malevolent spirit." - icon = 'icons/mob/simple/mob.dmi' - icon_state = "revenant_idle" - var/icon_idle = "revenant_idle" - var/icon_reveal = "revenant_revealed" - var/icon_stun = "revenant_stun" - var/icon_drain = "revenant_draining" - var/stasis = FALSE - mob_biotypes = MOB_SPIRIT - incorporeal_move = INCORPOREAL_MOVE_JAUNT - invisibility = INVISIBILITY_REVENANT - health = INFINITY //Revenants don't use health, they use essence instead - maxHealth = INFINITY - plane = GHOST_PLANE - sight = SEE_SELF - throwforce = 0 - - // Going for faint purple spoopy ghost - lighting_cutoff_red = 20 - lighting_cutoff_green = 15 - lighting_cutoff_blue = 35 - response_help_continuous = "passes through" - response_help_simple = "pass through" - response_disarm_continuous = "swings through" - response_disarm_simple = "swing through" - response_harm_continuous = "punches through" - response_harm_simple = "punch through" - unsuitable_atmos_damage = 0 - damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) //I don't know how you'd apply those, but revenants no-sell them anyway. - atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 - maxbodytemp = INFINITY - harm_intent_damage = 0 - friendly_verb_continuous = "touches" - friendly_verb_simple = "touch" - status_flags = 0 - wander = FALSE - density = FALSE - move_resist = MOVE_FORCE_OVERPOWERING - mob_size = MOB_SIZE_TINY - pass_flags = PASSTABLE | PASSGRILLE | PASSMOB - speed = 1 - unique_name = TRUE - hud_possible = list(ANTAG_HUD) - hud_type = /datum/hud/revenant - - var/essence = 75 //The resource, and health, of revenants. - var/essence_regen_cap = 75 //The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount. - var/essence_regenerating = TRUE //If the revenant regenerates essence or not - var/essence_regen_amount = 2.5 //How much essence regenerates per second - var/essence_accumulated = 0 //How much essence the revenant has stolen - var/essence_excess = 0 //How much stolen essence avilable for unlocks - var/revealed = FALSE //If the revenant can take damage from normal sources. - var/unreveal_time = 0 //How long the revenant is revealed for, is about 2 seconds times this var. - var/unstun_time = 0 //How long the revenant is stunned for, is about 2 seconds times this var. - var/inhibited = FALSE //If the revenant's abilities are blocked by a chaplain's power. - var/essence_drained = 0 //How much essence the revenant will drain from the corpse it's feasting on. - var/draining = FALSE //If the revenant is draining someone. - var/list/drained_mobs = list() //Cannot harvest the same mob twice - var/perfectsouls = 0 //How many perfect, regen-cap increasing souls the revenant has. //TODO, add objective for getting a perfect soul(s?) - var/generated_objectives_and_spells = FALSE - -/mob/living/simple_animal/revenant/Initialize(mapload) - . = ..() - AddElement(/datum/element/simple_flying) - add_traits(list(TRAIT_SPACEWALK, TRAIT_SIXTHSENSE, TRAIT_FREE_HYPERSPACE_MOVEMENT), INNATE_TRAIT) - - // Starting spells - - var/datum/action/cooldown/spell/list_target/telepathy/revenant/telepathy = new(src) - telepathy.Grant(src) - - // Starting spells that start locked - var/datum/action/cooldown/spell/aoe/revenant/overload/lights_go_zap = new(src) - lights_go_zap.Grant(src) - - var/datum/action/cooldown/spell/aoe/revenant/defile/windows_go_smash = new(src) - windows_go_smash.Grant(src) - - var/datum/action/cooldown/spell/aoe/revenant/blight/botany_go_mad = new(src) - botany_go_mad.Grant(src) - - var/datum/action/cooldown/spell/aoe/revenant/malfunction/shuttle_go_emag = new(src) - shuttle_go_emag.Grant(src) - - var/datum/action/cooldown/spell/aoe/revenant/haunt_object/toolbox_go_bonk = new(src) - toolbox_go_bonk.Grant(src) - - RegisterSignal(src, COMSIG_LIVING_BANED, PROC_REF(on_baned)) - random_revenant_name() - -/mob/living/simple_animal/revenant/can_perform_action(atom/movable/target, action_bitflags) - return FALSE - -/mob/living/simple_animal/revenant/proc/random_revenant_name() - var/built_name = "" - built_name += pick(strings(REVENANT_NAME_FILE, "spirit_type")) - built_name += " of " - built_name += pick(strings(REVENANT_NAME_FILE, "adverb")) - built_name += pick(strings(REVENANT_NAME_FILE, "theme")) - name = built_name - -/mob/living/simple_animal/revenant/Login() - . = ..() - if(!. || !client) - return FALSE - to_chat(src, span_deadsay("You are a revenant.")) - to_chat(src, "Your formerly mundane spirit has been infused with alien energies and empowered into a revenant.") - to_chat(src, "You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds.") - to_chat(src, "You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.") - to_chat(src, "To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities.") - to_chat(src, "You do not remember anything of your past lives, nor will you remember anything about this one after your death.") - to_chat(src, "Be sure to read the wiki page to learn more.") - if(!generated_objectives_and_spells) - generated_objectives_and_spells = TRUE - mind.set_assigned_role(SSjob.GetJobType(/datum/job/revenant)) - mind.special_role = ROLE_REVENANT - SEND_SOUND(src, sound('sound/effects/ghost.ogg')) - mind.add_antag_datum(/datum/antagonist/revenant) - -//Life, Stat, Hud Updates, and Say -/mob/living/simple_animal/revenant/Life(seconds_per_tick = SSMOBS_DT, times_fired) - if(stasis) - return - var/delta_time = DELTA_WORLD_TIME(SSmobs) - if(revealed && essence <= 0) - death() - if(unreveal_time && world.time >= unreveal_time) - unreveal_time = 0 - revealed = FALSE - incorporeal_move = INCORPOREAL_MOVE_JAUNT - invisibility = INVISIBILITY_REVENANT - to_chat(src, span_revenboldnotice("You are once more concealed.")) - if(unstun_time && world.time >= unstun_time) - unstun_time = 0 - REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, REVENANT_STUNNED_TRAIT) - to_chat(src, span_revenboldnotice("You can move again!")) - if(essence_regenerating && !inhibited && essence < essence_regen_cap) //While inhibited, essence will not regenerate - essence = min(essence + (essence_regen_amount * delta_time), essence_regen_cap) - update_mob_action_buttons() //because we update something required by our spells in life, we need to update our buttons - update_spooky_icon() - update_health_hud() - ..() - -/mob/living/simple_animal/revenant/get_status_tab_items() - . = ..() - . += "Current Essence: [essence >= essence_regen_cap ? essence : "[essence] / [essence_regen_cap]"]E" - . += "Total Essence Stolen: [essence_accumulated]SE" - . += "Unused Stolen Essence: [essence_excess]SE" - . += "Perfect Souls Stolen: [perfectsouls]" - -/mob/living/simple_animal/revenant/update_health_hud() - if(hud_used) - var/essencecolor = "#8F48C6" - if(essence > essence_regen_cap) - essencecolor = "#9A5ACB" //oh boy you've got a lot of essence - else if(!essence) - essencecolor = "#1D2953" //oh jeez you're dying - hud_used.healths.maptext = MAPTEXT("
[essence]E
") - -/mob/living/simple_animal/revenant/med_hud_set_health() - return //we use no hud - -/mob/living/simple_animal/revenant/med_hud_set_status() - return //we use no hud - -/mob/living/simple_animal/revenant/say(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null, filterproof = null, message_range = 7, datum/saymode/saymode = null) - if(!message) - return - if(sanitize) - message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN)) - src.log_talk(message, LOG_SAY) - var/rendered = span_deadsay("UNDEAD: [src] says, \"[message]\"") - for(var/mob/M in GLOB.mob_list) - if(isrevenant(M)) - to_chat(M, rendered) - else if(isobserver(M)) - var/link = FOLLOW_LINK(M, src) - to_chat(M, "[link] [rendered]") - return - - -//Immunities - -/mob/living/simple_animal/revenant/ex_act(severity, target) - return FALSE //Immune to the effects of explosions. - -/mob/living/simple_animal/revenant/blob_act(obj/structure/blob/B) - return //blah blah blobs aren't in tune with the spirit world, or something. - -/mob/living/simple_animal/revenant/singularity_act() - return //don't walk into the singularity expecting to find corpses, okay? - -/mob/living/simple_animal/revenant/narsie_act() - return //most humans will now be either bones or harvesters, but we're still un-alive. - -/mob/living/simple_animal/revenant/bullet_act() - if(!revealed || stasis) - return BULLET_ACT_FORCE_PIERCE - return ..() - -//damage, gibbing, and dying -/mob/living/simple_animal/revenant/proc/on_baned(obj/item/weapon, mob/living/user) - SIGNAL_HANDLER - visible_message(span_warning("[src] violently flinches!"), \ - span_revendanger("As [weapon] passes through you, you feel your essence draining away!")) - inhibited = TRUE - update_mob_action_buttons() - addtimer(CALLBACK(src, PROC_REF(reset_inhibit)), 3 SECONDS) - -/mob/living/simple_animal/revenant/proc/reset_inhibit() - inhibited = FALSE - update_mob_action_buttons() - -/mob/living/simple_animal/revenant/adjustHealth(amount, updating_health = TRUE, forced = FALSE) - if(!forced && !revealed) - return FALSE - . = amount - essence = max(0, essence-amount) - if(updating_health) - update_health_hud() - if(!essence) - death() - -/mob/living/simple_animal/revenant/dust(just_ash, drop_items, force) - death() - -/mob/living/simple_animal/revenant/gib() - death() - -/mob/living/simple_animal/revenant/death() - if(!revealed || stasis) //Revenants cannot die if they aren't revealed //or are already dead - return - stasis = TRUE - to_chat(src, span_revendanger("NO! No... it's too late, you can feel your essence [pick("breaking apart", "drifting away")]...")) - ADD_TRAIT(src, TRAIT_NO_TRANSFORM, REVENANT_STUNNED_TRAIT) - revealed = TRUE - invisibility = 0 - playsound(src, 'sound/effects/screech.ogg', 100, TRUE) - visible_message(span_warning("[src] lets out a waning screech as violet mist swirls around its dissolving body!")) - icon_state = "revenant_draining" - for(var/i = alpha, i > 0, i -= 10) - stoplag() - alpha = i - visible_message(span_danger("[src]'s body breaks apart into a fine pile of blue dust.")) - var/reforming_essence = essence_regen_cap //retain the gained essence capacity - var/obj/item/ectoplasm/revenant/R = new(get_turf(src)) - R.essence = max(reforming_essence - 15 * perfectsouls, 75) //minus any perfect souls - R.old_key = client.key //If the essence reforms, the old revenant is put back in the body - R.revenant = src - invisibility = INVISIBILITY_ABSTRACT - revealed = FALSE - ghostize(0)//Don't re-enter invisible corpse - - -//reveal, stun, icon updates, cast checks, and essence changing -/mob/living/simple_animal/revenant/proc/reveal(time) - if(!src) - return - if(time <= 0) - return - revealed = TRUE - invisibility = 0 - incorporeal_move = FALSE - if(!unreveal_time) - to_chat(src, span_revendanger("You have been revealed!")) - unreveal_time = world.time + time - else - to_chat(src, span_revenwarning("You have been revealed!")) - unreveal_time = unreveal_time + time - update_spooky_icon() - orbiting?.end_orbit(src) - -/mob/living/simple_animal/revenant/proc/stun(time) - if(!src) - return - if(time <= 0) - return - ADD_TRAIT(src, TRAIT_NO_TRANSFORM, REVENANT_STUNNED_TRAIT) - if(!unstun_time) - to_chat(src, span_revendanger("You cannot move!")) - unstun_time = world.time + time - else - to_chat(src, span_revenwarning("You cannot move!")) - unstun_time = unstun_time + time - update_spooky_icon() - orbiting?.end_orbit(src) - -/mob/living/simple_animal/revenant/proc/update_spooky_icon() - if(revealed) - if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) - if(draining) - icon_state = icon_drain - else - icon_state = icon_stun - else - icon_state = icon_reveal - else - icon_state = icon_idle - -/mob/living/simple_animal/revenant/proc/castcheck(essence_cost) - if(!src) - return - var/turf/T = get_turf(src) - if(isclosedturf(T)) - to_chat(src, span_revenwarning("You cannot use abilities from inside of a wall.")) - return FALSE - for(var/obj/O in T) - if(O.density && !O.CanPass(src, get_dir(T, src))) - to_chat(src, span_revenwarning("You cannot use abilities inside of a dense object.")) - return FALSE - if(inhibited) - to_chat(src, span_revenwarning("Your powers have been suppressed by nulling energy!")) - return FALSE - if(!change_essence_amount(essence_cost, TRUE)) - to_chat(src, span_revenwarning("You lack the essence to use that ability.")) - return FALSE - return TRUE - -/mob/living/simple_animal/revenant/proc/unlock(essence_cost) - if(essence_excess < essence_cost) - return FALSE - essence_excess -= essence_cost - update_mob_action_buttons() - return TRUE - -/mob/living/simple_animal/revenant/proc/change_essence_amount(essence_amt, silent = FALSE, source = null) - if(!src) - return - if(essence + essence_amt < 0) - return - essence = max(0, essence+essence_amt) - update_health_hud() - if(essence_amt > 0) - essence_accumulated = max(0, essence_accumulated+essence_amt) - essence_excess = max(0, essence_excess+essence_amt) - update_mob_action_buttons() - if(!silent) - if(essence_amt > 0) - to_chat(src, span_revennotice("Gained [essence_amt]E[source ? " from [source]":""].")) - else - to_chat(src, span_revenminor("Lost [essence_amt]E[source ? " from [source]":""].")) - return 1 - -/mob/living/simple_animal/revenant/proc/death_reset() - revealed = FALSE - unreveal_time = 0 - REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, REVENANT_STUNNED_TRAIT) - unstun_time = 0 - inhibited = FALSE - draining = FALSE - incorporeal_move = INCORPOREAL_MOVE_JAUNT - invisibility = INVISIBILITY_REVENANT - alpha=255 - stasis = FALSE - -/mob/living/simple_animal/revenant/orbit(atom/target) - setDir(SOUTH) // reset dir so the right directional sprites show up - return ..() - -/mob/living/simple_animal/revenant/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) - if(!orbiting) // only needed when orbiting - return ..() - if(incorporeal_move_check(src)) - return ..() - - // back back back it up, the orbitee went somewhere revenant cannot - orbiting?.end_orbit(src) - abstract_move(old_loc) // gross but maybe orbit component will be able to check pre move in the future - -/mob/living/simple_animal/revenant/stop_orbit(datum/component/orbiter/orbits) - // reset the simple_flying animation - animate(src, pixel_y = 2, time = 1 SECONDS, loop = -1, flags = ANIMATION_RELATIVE) - animate(pixel_y = -2, time = 1 SECONDS, flags = ANIMATION_RELATIVE) - return ..() - -/// Incorporeal move check: blocked by holy-watered tiles and salt piles. -/mob/living/simple_animal/revenant/proc/incorporeal_move_check(atom/destination) - var/turf/open/floor/stepTurf = get_turf(destination) - if(stepTurf) - var/obj/effect/decal/cleanable/food/salt/salt = locate() in stepTurf - if(salt) - to_chat(src, span_warning("[salt] bars your passage!")) - reveal(20) - stun(20) - return - if(stepTurf.turf_flags & NOJAUNT) - to_chat(src, span_warning("Some strange aura is blocking the way.")) - return - if(locate(/obj/effect/blessing) in stepTurf) - to_chat(src, span_warning("Holy energies block your path!")) - return - return TRUE - -//reforming -/obj/item/ectoplasm/revenant - name = "glimmering residue" - desc = "A pile of fine blue dust. Small tendrils of violet mist swirl around it." - icon = 'icons/effects/effects.dmi' - icon_state = "revenantEctoplasm" - w_class = WEIGHT_CLASS_SMALL - var/essence = 75 //the maximum essence of the reforming revenant - var/reforming = TRUE - var/inert = FALSE - var/old_key //key of the previous revenant, will have first pick on reform. - var/mob/living/simple_animal/revenant/revenant - -/obj/item/ectoplasm/revenant/Initialize(mapload) - . = ..() - addtimer(CALLBACK(src, PROC_REF(try_reform)), 600) - -/obj/item/ectoplasm/revenant/proc/scatter() - qdel(src) - -/obj/item/ectoplasm/revenant/proc/try_reform() - if(reforming) - reforming = FALSE - reform() - else - inert = TRUE - visible_message(span_warning("[src] settles down and seems lifeless.")) - -/obj/item/ectoplasm/revenant/attack_self(mob/user) - if(!reforming || inert) - return ..() - user.visible_message(span_notice("[user] scatters [src] in all directions."), \ - span_notice("You scatter [src] across the area. The particles slowly fade away.")) - user.dropItemToGround(src) - scatter() - -/obj/item/ectoplasm/revenant/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) - ..() - if(inert) - return - visible_message(span_notice("[src] breaks into particles upon impact, which fade away to nothingness.")) - scatter() - -/obj/item/ectoplasm/revenant/examine(mob/user) - . = ..() - if(inert) - . += span_revennotice("It seems inert.") - else if(reforming) - . += span_revenwarning("It is shifting and distorted. It would be wise to destroy this.") - -/obj/item/ectoplasm/revenant/proc/reform() - if(QDELETED(src) || QDELETED(revenant) || inert) - return - var/key_of_revenant - message_admins("Revenant ectoplasm was left undestroyed for 1 minute and is reforming into a new revenant.") - forceMove(drop_location()) //In case it's in a backpack or someone's hand - revenant.forceMove(loc) - if(old_key) - for(var/mob/M in GLOB.dead_mob_list) - if(M.client && M.client.key == old_key) //Only recreates the mob if the mob the client is in is dead - key_of_revenant = old_key - break - if(!key_of_revenant) - message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...") - var/list/candidates = poll_candidates_for_mob("Do you want to be [revenant.name] (reforming)?", ROLE_REVENANT, ROLE_REVENANT, 5 SECONDS, revenant) - if(!LAZYLEN(candidates)) - qdel(revenant) - message_admins("No candidates were found for the new revenant. Oh well!") - inert = TRUE - visible_message(span_revenwarning("[src] settles down and seems lifeless.")) - return - var/mob/dead/observer/C = pick(candidates) - key_of_revenant = C.key - if(!key_of_revenant) - qdel(revenant) - message_admins("No ckey was found for the new revenant. Oh well!") - inert = TRUE - visible_message(span_revenwarning("[src] settles down and seems lifeless.")) - return - - message_admins("[key_of_revenant] has been [old_key == key_of_revenant ? "re":""]made into a revenant by reforming ectoplasm.") - revenant.log_message("was [old_key == key_of_revenant ? "re":""]made as a revenant by reforming ectoplasm.", LOG_GAME) - visible_message(span_revenboldnotice("[src] suddenly rises into the air before fading away.")) - - revenant.essence = essence - revenant.essence_regen_cap = essence - revenant.death_reset() - revenant.key = key_of_revenant - revenant = null - qdel(src) - -/obj/item/ectoplasm/revenant/suicide_act(mob/living/user) - user.visible_message(span_suicide("[user] is inhaling [src]! It looks like [user.p_theyre()] trying to visit the shadow realm!")) - scatter() - return OXYLOSS - -/obj/item/ectoplasm/revenant/Destroy() - if(!QDELETED(revenant)) - qdel(revenant) - return ..() - -//objectives -/datum/objective/revenant - var/targetAmount = 100 - -/datum/objective/revenant/New() - targetAmount = rand(350,600) - explanation_text = "Absorb [targetAmount] points of essence from humans." - ..() - -/datum/objective/revenant/check_completion() - if(!isrevenant(owner.current)) - return FALSE - var/mob/living/simple_animal/revenant/R = owner.current - if(!R || R.stat == DEAD) - return FALSE - var/essence_stolen = R.essence_accumulated - if(essence_stolen < targetAmount) - return FALSE - return TRUE - -/datum/objective/revenant_fluff - -/datum/objective/revenant_fluff/New() - var/list/explanation_texts = list( - "Assist and exacerbate existing threats at critical moments.", \ - "Impersonate or be worshipped as a god.", \ - "Cause as much chaos and anger as you can without being killed.", \ - "Damage and render as much of the station rusted and unusable as possible.", \ - "Disable and cause malfunctions in as many machines as possible.", \ - "Ensure that any holy weapons are rendered unusable.", \ - "Heed and obey the requests of the dead, provided that carrying them out wouldn't be too inconvenient or self-destructive.", \ - "Make the crew as miserable as possible.", \ - "Make the clown as miserable as possible.", \ - "Make the captain as miserable as possible.", \ - "Prevent the use of energy weapons where possible.", - ) - explanation_text = pick(explanation_texts) - ..() - -/datum/objective/revenant_fluff/check_completion() - return TRUE - -#undef REVENANT_STUNNED_TRAIT diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 03712663249..a5aa8c2c145 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -253,9 +253,9 @@ if(salt) to_chat(L, span_warning("[salt] bars your passage!")) if(isrevenant(L)) - var/mob/living/simple_animal/revenant/R = L - R.reveal(20) - R.stun(20) + var/mob/living/basic/revenant/ghostie = L + ghostie.apply_status_effect(/datum/status_effect/revenant/revealed, 2 SECONDS) + ghostie.apply_status_effect(/datum/status_effect/incapacitating/paralyzed/revenant, 2 SECONDS) return if(stepTurf.turf_flags & NOJAUNT) to_chat(L, span_warning("Some strange aura is blocking the way.")) diff --git a/code/modules/photography/camera/other.dm b/code/modules/photography/camera/other.dm index e9aa5d94e59..166517d055f 100644 --- a/code/modules/photography/camera/other.dm +++ b/code/modules/photography/camera/other.dm @@ -9,13 +9,15 @@ continue // time to steal your soul - if(istype(target, /mob/living/simple_animal/revenant)) - var/mob/living/simple_animal/revenant/peek_a_boo = target - peek_a_boo.reveal(2 SECONDS) // no hiding - if(!peek_a_boo.unstun_time) - peek_a_boo.stun(2 SECONDS) - target.visible_message(span_warning("[target] violently flinches!"), \ - span_revendanger("You feel your essence draining away from having your picture taken!")) + if(istype(target, /mob/living/basic/revenant)) + var/mob/living/basic/revenant/peek_a_boo = target + peek_a_boo.apply_status_effect(/datum/status_effect/revenant/revealed, 2 SECONDS) // no hiding + peek_a_boo.apply_status_effect(/datum/status_effect/incapacitating/paralyzed/revenant, 2 SECONDS) + + target.visible_message( + span_warning("[target] violently flinches!"), + span_revendanger("You feel your essence draining away from having your picture taken!"), + ) target.apply_damage(rand(10, 15)) /obj/item/camera/spooky/badmin diff --git a/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm index 5d33b3fce51..9f7ab7e354c 100644 --- a/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm +++ b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm @@ -73,7 +73,7 @@ /obj/projectile/bullet/arrow/holy/Initialize(mapload) . = ..() //50 damage to revenants - AddElement(/datum/element/bane, target_type = /mob/living/simple_animal/revenant, damage_multiplier = 0, added_damage = 30) + AddElement(/datum/element/bane, target_type = /mob/living/basic/revenant, damage_multiplier = 0, added_damage = 30) /// special pyre sect arrow /// in the future, this needs a special sprite, but bows don't support non-hardcoded arrow sprites diff --git a/code/modules/projectiles/guns/ballistic/bows/bow_types.dm b/code/modules/projectiles/guns/ballistic/bows/bow_types.dm index 355ed3575a8..b9ac1af0cca 100644 --- a/code/modules/projectiles/guns/ballistic/bows/bow_types.dm +++ b/code/modules/projectiles/guns/ballistic/bows/bow_types.dm @@ -30,7 +30,7 @@ on_clear_callback = CALLBACK(src, PROC_REF(on_cult_rune_removed)), \ effects_we_clear = list(/obj/effect/rune, /obj/effect/heretic_rune) \ ) - AddElement(/datum/element/bane, target_type = /mob/living/simple_animal/revenant, damage_multiplier = 0, added_damage = 25, requires_combat_mode = FALSE) + AddElement(/datum/element/bane, target_type = /mob/living/basic/revenant, damage_multiplier = 0, added_damage = 25, requires_combat_mode = FALSE) /obj/item/gun/ballistic/bow/divine/proc/on_cult_rune_removed(obj/effect/target, mob/living/user) SIGNAL_HANDLER diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index 9083de70902..56339d3866a 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -125,16 +125,16 @@ ///special size for anti cult effect var/effective_size = round(created_volume/48) playsound(T, 'sound/effects/pray.ogg', 80, FALSE, effective_size) - for(var/mob/living/simple_animal/revenant/R in get_hearers_in_view(7,T)) + for(var/mob/living/basic/revenant/ghostie in get_hearers_in_view(7,T)) var/deity if(GLOB.deity) deity = GLOB.deity else deity = "Christ" - to_chat(R, span_userdanger("The power of [deity] compels you!")) - R.stun(20) - R.reveal(100) - R.adjustHealth(50) + to_chat(ghostie, span_userdanger("The power of [deity] compels you!")) + ghostie.apply_status_effect(/datum/status_effect/incapacitating/paralyzed/revenant, 2 SECONDS) + ghostie.apply_status_effect(/datum/status_effect/revenant/revealed, 2 SECONDS) + ghostie.adjust_health(50) for(var/mob/living/carbon/C in get_hearers_in_view(effective_size,T)) if(IS_CULTIST(C)) to_chat(C, span_userdanger("The divine explosion sears you!")) diff --git a/code/modules/religion/burdened/psyker.dm b/code/modules/religion/burdened/psyker.dm index 4499030642d..d4c752751b8 100644 --- a/code/modules/religion/burdened/psyker.dm +++ b/code/modules/religion/burdened/psyker.dm @@ -183,7 +183,7 @@ on_clear_callback = CALLBACK(src, PROC_REF(on_cult_rune_removed)), \ effects_we_clear = list(/obj/effect/rune, /obj/effect/heretic_rune, /obj/effect/cosmic_rune), \ ) - AddElement(/datum/element/bane, target_type = /mob/living/simple_animal/revenant, damage_multiplier = 0, added_damage = 25) + AddElement(/datum/element/bane, target_type = /mob/living/basic/revenant, damage_multiplier = 0, added_damage = 25) name = pick(possible_names) desc = possible_names[name] diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index 92416001b79..396bb2140aa 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -191,7 +191,6 @@ /mob/living/simple_animal/pet/gondola, /mob/living/simple_animal/pet/gondola/gondolapod, /mob/living/simple_animal/pet/gondola/virtual_domain, - /mob/living/simple_animal/revenant, /mob/living/simple_animal/shade, /mob/living/simple_animal/slime, /mob/living/simple_animal/slime/pet, diff --git a/tgstation.dme b/tgstation.dme index 5d975bb3a70..c842560f249 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3081,7 +3081,6 @@ #include "code\modules\antagonists\pirate\pirate_shuttle_equipment.dm" #include "code\modules\antagonists\pyro_slime\pyro_slime.dm" #include "code\modules\antagonists\revenant\haunted_item.dm" -#include "code\modules\antagonists\revenant\revenant_abilities.dm" #include "code\modules\antagonists\revenant\revenant_antag.dm" #include "code\modules\antagonists\revenant\revenant_blight.dm" #include "code\modules\antagonists\revolution\enemy_of_the_state.dm" @@ -4587,6 +4586,12 @@ #include "code\modules\mob\living\basic\space_fauna\regal_rat\regal_rat.dm" #include "code\modules\mob\living\basic\space_fauna\regal_rat\regal_rat_actions.dm" #include "code\modules\mob\living\basic\space_fauna\regal_rat\regal_rat_ai.dm" +#include "code\modules\mob\living\basic\space_fauna\revenant\_revenant.dm" +#include "code\modules\mob\living\basic\space_fauna\revenant\revenant_abilities.dm" +#include "code\modules\mob\living\basic\space_fauna\revenant\revenant_effects.dm" +#include "code\modules\mob\living\basic\space_fauna\revenant\revenant_harvest.dm" +#include "code\modules\mob\living\basic\space_fauna\revenant\revenant_items.dm" +#include "code\modules\mob\living\basic\space_fauna\revenant\revenant_objectives.dm" #include "code\modules\mob\living\basic\space_fauna\snake\snake.dm" #include "code\modules\mob\living\basic\space_fauna\snake\snake_ai.dm" #include "code\modules\mob\living\basic\space_fauna\spider\spider.dm" @@ -4765,7 +4770,6 @@ #include "code\modules\mob\living\simple_animal\animal_defense.dm" #include "code\modules\mob\living\simple_animal\damage_procs.dm" #include "code\modules\mob\living\simple_animal\parrot.dm" -#include "code\modules\mob\living\simple_animal\revenant.dm" #include "code\modules\mob\living\simple_animal\shade.dm" #include "code\modules\mob\living\simple_animal\simple_animal.dm" #include "code\modules\mob\living\simple_animal\bot\bot.dm" From a45133c7e8f29be64aca52269849f67d2767bd65 Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Tue, 10 Oct 2023 00:07:29 -0400 Subject: [PATCH 018/100] Table flipping now throws anything on it in the direction it was flipped (#24232) * dawdaw * rogue space * a small fix * Update modular_skyrat/modules/tableflip/code/flipped_table.dm Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> * pacifism * a --------- Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- .../modules/tableflip/code/flipped_table.dm | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/modular_skyrat/modules/tableflip/code/flipped_table.dm b/modular_skyrat/modules/tableflip/code/flipped_table.dm index cb7a62a5e6d..ac455153d84 100644 --- a/modular_skyrat/modules/tableflip/code/flipped_table.dm +++ b/modular_skyrat/modules/tableflip/code/flipped_table.dm @@ -88,10 +88,35 @@ //Finally, add the custom materials, so the flags still apply to it flipped_table.set_custom_materials(custom_materials) - user.visible_message(span_danger("[user] flips over the [src]!"), span_notice("You flip over the [src]!")) - playsound(src, 'sound/items/trayhit2.ogg', 100) + var/sound_volume = 100 + var/visible_message = "[user] flips over the [src]!" + var/self_message = "You flip over the [src]!" + var/user_pacifist = HAS_TRAIT(user, TRAIT_PACIFISM) + + if (user_pacifist) + visible_message = "[user] gently flips over the [src]." + self_message = "You gently flip over the [src]." + sound_volume = 40 + + user.visible_message(span_danger(visible_message), span_notice(self_message)) + playsound(src, 'sound/items/trayhit2.ogg', sound_volume) qdel(src) + var/turf/throw_target = get_step(flipped_table, flipped_table.dir) + if (!isnull(throw_target) && !user_pacifist) + for (var/atom/movable/movable_entity in flipped_table.loc) + if (movable_entity == flipped_table) + continue + if (movable_entity.anchored) + continue + if (movable_entity.invisibility > SEE_INVISIBLE_LIVING) + continue + if(!ismob(movable_entity) && !isobj(movable_entity)) + continue + if(movable_entity.throwing || (movable_entity.movement_type & (FLOATING|FLYING))) + continue + movable_entity.safe_throw_at(throw_target, range = 1, speed = 1, force = MOVE_FORCE_NORMAL, gentle = TRUE) + /obj/structure/table var/flipped_table_type = /obj/structure/flippedtable var/can_flip = TRUE From 3a9aeac633320ea2c9222f103b7db3c2624d45d3 Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Tue, 10 Oct 2023 00:09:29 -0400 Subject: [PATCH 019/100] Gives science jaws of life (cant pry open doors) and hand drill access, lets robo print health analyzers/advanced medical tools (#24162) * aaa * a * a! * aaaa * now with FUNCTIONAL icon states * whoa where did these come from?! * Apply suggestions from code review Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --------- Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> --- code/__DEFINES/~skyrat_defines/research.dm | 2 + .../code/modules/jobs/job_types/roboticist.dm | 7 +- .../modules/aesthetics/tools/tools.dmi | Bin 40296 -> 39994 bytes .../aesthetics/tools/tools_lefthand.dmi | Bin 679 -> 794 bytes .../aesthetics/tools/tools_righthand.dmi | Bin 673 -> 806 bytes .../modules/science_tools/readme.md | 44 ++++++++++++ .../modules/science_tools/research.dm | 9 +++ .../modules/science_tools/tool_designs.dm | 65 ++++++++++++++++++ modular_skyrat/modules/science_tools/tools.dm | 14 ++++ tgstation.dme | 4 ++ 10 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 code/__DEFINES/~skyrat_defines/research.dm create mode 100644 modular_skyrat/modules/science_tools/readme.md create mode 100644 modular_skyrat/modules/science_tools/research.dm create mode 100644 modular_skyrat/modules/science_tools/tool_designs.dm create mode 100644 modular_skyrat/modules/science_tools/tools.dm diff --git a/code/__DEFINES/~skyrat_defines/research.dm b/code/__DEFINES/~skyrat_defines/research.dm new file mode 100644 index 00000000000..492f3ac98be --- /dev/null +++ b/code/__DEFINES/~skyrat_defines/research.dm @@ -0,0 +1,2 @@ +#define SCIENCE_JAWS_OF_LIFE_DESIGN_ID "jawsoflife_sci" +#define SCIENCE_DRILL_DESIGN_ID "handdrill_sci" diff --git a/modular_skyrat/master_files/code/modules/jobs/job_types/roboticist.dm b/modular_skyrat/master_files/code/modules/jobs/job_types/roboticist.dm index 8c62f0a30f1..35e4f206de1 100644 --- a/modular_skyrat/master_files/code/modules/jobs/job_types/roboticist.dm +++ b/modular_skyrat/master_files/code/modules/jobs/job_types/roboticist.dm @@ -13,7 +13,12 @@ mail_goodies += list( /obj/item/healthanalyzer/advanced = 15, - // if we decide later to let sci have access to the hand drill, let robos get it from here + /obj/item/screwdriver/power/science = 6, + /obj/item/crowbar/power/science = 6, + /obj/item/weldingtool/experimental = 2, // a lot rarer since its relatively powerful + /obj/item/scalpel/advanced = 6, + /obj/item/retractor/advanced = 6, + /obj/item/cautery/advanced = 6, /obj/item/storage/pill_bottle/liquid_solder = 6, /obj/item/storage/pill_bottle/system_cleaner = 6, /obj/item/storage/pill_bottle/nanite_slurry = 6, diff --git a/modular_skyrat/modules/aesthetics/tools/tools.dmi b/modular_skyrat/modules/aesthetics/tools/tools.dmi index e40038a5dcf9f4fe6ec3b1ebd82bbb84a0868054..518fa54cba94fea7ac59b3a7e46defc8578a765e 100644 GIT binary patch literal 39994 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,9&>4 zgn83r#&F_V)%4ggjfAMJBCM_QHgRjHgm7B%uC8xPwe)J5CuPgXA9o5o%uMDr0)1$@ zIrp{p22wUC z=jj$iTDIcOJgy}98>Yeg*7u1-Gja7XqVX0$z=tmGU{i;wVT`qoGj>Zko4(gfD83pN zFCL@9*`7+IG`_MZo}8X|Yo^u>f5Fz?0xc!E#mPUd7fY;Zz9vV|Q+4KI{*Yp*{P+;X z&qJ*tpS>LGe10OP<=NusPZ#mx{tE-JwHl7XV*t=(lfFL*suKeAqM+AY3uiy`pSC`z3BH(kiSb?Wj(7t=@R4XA$TEwB1RR!ZHoB zD-KuoLs_|a@-0d8l^_SkcOiE_+`mT%nm8=SZPr=^R-8p+D^*_Mq_-&X@5{~Q79e1wYdU@~)tO1-N1U!Lx~;W({5V^tO+!ojxv~z0@KE0B zW87BwK+~;SQ@8Zj%TgonT)KxLScgsClmvu=HyOE?7sbY$f>$l$gD9*Wo(Zjb#pkz^ zbS(miq;^f2=@l|=Ni&OsgUxssbGEEb-izz6jkj>#tMc(Z; z>7t4H#UcPlCY>jdLFO~=_@?H{Si{okL3%gydU1ctY45-+?Nzi7(xUo(+!y(!xKqsg zl@_AEBmPVxCSZut1k+utrpxxL$hvtA2UDjP&Lro3NN4%FuO{1y-?Eab=xE4($hc(@INk1AXkEFG7x`)$x~( z%8v_;ytqR*gA}@YiH3jZ$34|JxrbRC?bXsQ!Dj=kpONqmf2H5XU0K&P+-0o5i#OC$ zQBp6M-`ysra}9;p4nrbG%>6EE0^pjfs@1D^hypl^1doMvoBM`k|F)d!HXD;HeDhFn zo_W08PZsm+-3&$dlkz#pAiJ78J3I~f=2_ZBatd^RjO)mA&C8mlp0 zu?bdKdZagc1KF5jNizx6rXu&&ZyTwBNK(M2wxoBx=YzA6$ss~ICndATrqx%rAJ7$wc^Q{G zQ9F|QnGn?wb1ZctSNo++=Zom-eRI5hcGs^>7I`#rlI+dARi>GlcmC*ZQQjFvbIJbU zNwfp+h6Q@h^P#_ovUsG7fNZ?*XX!SaD!{>>Hw5}!r~oL!Z_RyzU#xNtPQ+9 z9vlto@i+u?k$HgY1JB}+yfpWva0(QdDz{T@-Nt80jlLHTl)OkNdh=)6SASr57{5Ni6lMdS2vWxHUqUxLk!UFyUG8O2HfO`R-?Xle5 z@`uLhBj2WuK}FTGamT&l=9jow7dZhWlii8q{vUVu%(>zd&|Z-A-%F??sk7ZcZL807=c|r9 z*~8pZ21=E3ol@x0e9Y;oEr`eEM8?(i<2=nQY=t);sty!2ZMl7Od?Q@qa42rBXubD| zWNB&1vWOWu&8j7V(+eLIW%3Nl*fs1bhgE-z1cx$|rtwKFEEZBwzmd$-QFhom$#2x;U})^5%= zp(o49v9Z`%+S*^fd?kB>jf0b0jsYy>u>V=j_|EANyuF{F4qlZ{7tpq|x35a_{?gcJ zSV7v@N3&!xe@fU6rk~9yy);39-@6-dIoVrOeK-{joRM$I&@qe_dwlJ?O5fg5vR{OP z>qM5zI@HsXVj`0IDZ9;P0o%vNCr>W5=;r1I6C1ndd1siFD>)Y=EG#T0DaqjbrN zOSV5@V=o*A*WcLtMSl4>yNzx=QZ!Le%3JPZ8=HFQz?{5|Z{Wt(x%wbc6z#H343efO zAxgwQ#FMg^Pq!+H7G7 z$9FuX$iLE?AIBmwqtRP<;qq{nd%9dVJ)TjM&2*d`#AUry@U2KIu_nbo*W>!+Xr&rS zh?8h-y7BN%K!d|OL20)PEBzFt^PZ(631gK(&3Giq2%pO`VFnr=ZYE*oV=jMTq&M|}u-2;k_J^UCygYNU zC>^Uw{20p|8!X2xbJ^8k90MAt)&0_7u0mhR+??Lb%q)c`e?`CEw1g0xOf*gV7~}V8 zN2%+ezG3Q`5F6GqL-$+6NdBF}Axa`!03gl*TnCyv>s4Z7DZpN5&H2J10OqCC{dx6w zY}`{{WoMY?`@II+w1LYiOYsDK=wB8i^Axff&<5DyK>^iaH_#5a6c1lz6Krg)u{>4V zgHCB2gX>F88eQquUuhujzc7^vv*76N zYiw1FlOVAEm(d-yVCeRTCRe!Yv7df-P~!A+I{zl@s`gqX%4n0>a`|1~&IP#MNk*ps zA1P_a^W%_#TSYAZ*tN{(azqYw(a=@Q8@bo?9^Nm*>$+{@AdvI&CTn2SQ|?X<8Gx< zR8jFQ2H&@_Ee}69kA#Gubtfk$qtk^-i5zB%jZ@4HaKr+Z5wPaW1F46Ldwnhf>+#m8 z@f@8m@X;4|FI?{6iAad80WN@M+=`7#-zH|TCg(vJYu+@eFPc*kH;O-F)Q7-mgap|c z;`pXHc;^G|?2hwZ4+pL$u1$T*D2v_v2p(bl^%g(`GloHKd%<6LD)9Jk+G3q9OwTPazUB zL)imDLA2KMb6(1Q!RXOzQRSovM!67HN5^vL?^^YkK(|6J`t$Pmn~-$~-1Ej#<7;Ya z_@X!B;^OO@n@U^gtl(+pYI=o{nPIzt$%}9W*{B3uu-ZJgu zevwlW_5x5tLi1J%E!>mxNr+z*(iQq#6=2!;ch_Vkd`BB1K zrk+R-Y}{+?$w9A9j!K`x;Es`TaW&}T9N81rv0V@ zqzZ@c%~J(zuVlwQnI~InXe3z+Wk}HNOneca^4X44#nxR-qh6$-?B0Knqracay{>8j zQrTM|Hj<7!ZEWtsD2B>^91354rf{CXM9}N>LvqXUHjMGwH4+KOV+KFd++Rcbg7S#0-dm%VI%e!ABRtPco)bAhbP ztX|tW=0s*wN>*2yZtfM>2qwk#UX^^f+p@eL-s9cDc6=($^r1LLWV8T}k6_5i+Vn?} z1Wi!R6pWT8B9$(9TtK#;^L^U%yAk0EsCha}+ZP~PdwU5GwBS#2QH}L81z)>!roJft zUbwjZE|)Wt^975)t0~?-N|NLqyEJFDLqRJKP0+9k?r@^Y2{hcw_dREABa7vKdI8#= z$gEi{0lkP-2UnFy%G&d#P>Bo_An}={voNlWJpfs`@{$Efm@^BAxO9Ck^El$|;+m=t zO#+=!Xu5j{HWJ1wt-(`@%+-)(o~A~QgGUa$Hc?&c+cU(?-Ro@hAp!wd#j!%fZG~ke z=B1JAcGoilarQJI9!=)S5=D{nYcO51v$5eH?iC~t{Y>IiPma%Ht~W8NWTG)==b{b< zT#SQ_))0$%^tS$ofS!SOMpD|@?vTn40+2*Bs**uA_vYGK2E=Bq!*4JMjR+MkzJSD( z%W_T+-xOOIH&{FzcUwK)OgUzg8huj@`o{U$^CytH-+shg@p<-o0b?>r90QnNtMmNC z!|{16Jp;$NSv&j@tue^BBoa@dXc<9Yrj=qtvqE-p?@2FpO$5u zde^~!Q8;yjy15%oald8HxDEefUEHCQ81QYS!<}RT?&-B;_-I!A`)7B;wA}{Db~O2GwZPKk@FWpnx_; zj)qV!Hw3n{u>2a9zllk~&0gqGtCc;H@+BY{cTI68H14N0#?Peuc~SdyT+5uwRucQ( ztS)dKB7el~U+BATYS+m6qbiJFZ$yX@%pzc-L6bm8A{g^`{1v`@ckak%*aK8XJpMmw z58Sk+Pdn-8bl%$OdRNb_R*DGuiP2nXA1K+Edwu{;LtXvwjj=5`V-(L!;64mDm;c}~ zF7#I-Uc5%n+U{Y9R>=Yi0!9~z%c4l04Fi&}Ik*O;9pw=R>56*>q*10Cr zK{@I_Nyqr@%9BJbo5W(!gDh}=#2zzBt%1FxsPwozHN{kIZnW|ytrU7u3OmyW#Fcc3 zu3wt)TqA;E3=B1Po@tNi{mn{9{2PmLsj{s~UyR=N#>E17W}ieGbY;ocmq+J?GlH3m z6=4*r%^{}ld9%VvK$?Xv#%&!iSs{k42ENmP|NSd5%>+lwd&Z8?C9k_l4$*kDXk_1n z{6o>}pHoqno9cI2a8LSnWGxVw>LY#l=f}~JB{4Cv%mVFddiChmlADt|j6$#wemm1_EjmJmaOzV-&o+A%1^TxEOeN4h*T}6y>lbz0`mOc zp$5=Jc75MjW}=?{fS>WCD^c5k_bdLpF`?$6VDeP>WJ0Bcm6-;7-u~*xmUP17wDHTh z>TBamx`CeQI`G(Q##bCWabKT5*qU=F1S=8?Vk>REdvjZg@%>& zm)TU_8*J=Y6Q`V@=4Rd(gfIg?Z&Yey;JZNXG;$*pc>_+htGU_q5&_hT|2!(IF*R`5 zWS1yL#Hp?ps0i475fK?223eKbw2frX>)t&i$ESIZfbS?TSg2;{ zm7%xXjE_(x%|i?PXgWu)8aM!yzLJtFzFM(-Hf~)>%&U<}U=cQ(%n2Q+%gLb{t|w4R z={yBbawnolunTX7^d+$;no<{_Dfw3IS5Pbo0^p`Zv)1W(>HJ4R?)$E|0R>!Timm|7hF!xw^?WO8Rm&*BDJa}PRy4<8!R)G$9P8&ye7;7q! zPFC%B5{)7++!c!MjSDjKyUt^V=ua;SPoG;w&{OS>HjZ!SGymXN_F{CR%U+rH10}n6 zT~eE7D^fp5O|u;ka1h3$weLwl=BXB{VZ zi&*QH3t0AgE28Yy=NBCVl=<`|ZT3d7C;~_F+4%bw8@I0RsP3)9{>xaE@lU(m_iPS} zb*zHX*7ARhg5%L$vv7df72mxBPtD4#ZaruUKPOs2_I7=!KJfbF7H_<)=H)j%Nb+T!xttF@sPAmq9}NIsv|faHr9usW7MI+R0Xnb^Fn=Kt`r`(OD9Gt~YwarAO*<{%jnqMnq_-ypCVy zv+{a;k;*tP8VLv*hZpVyqp!rLM(3?BFEGrfRaJI%F)c%Zc^J!*<+YvhmNR)R{afeJ zgWOrQkkQ=KCW83Z<0w~gcf8&d#pa^yXd)1jkd&Ir1IoSwqOX-~^2R@OX(B72i*_H& zSA5kQ%Khv}JJ$bN`++qzXsp5Ztl!Z~v)e=qdI^+9!efJ561Z41w3H`yT+pLNl7$b~ z)QOY1MOVQ*uJLW&f~f)LJ>b;*IDoT*6wGelfS&MYaIYnt63mWFSw99YPWN)shu#GP^MfQFIomgrVJXK3}4C+WRvLIkD^J%+3oGUU*Tf`t% z9r3*Kmkl!p0sSE#z!#5${zck&TRb#wsR0ZY0=X-D@3hn}3e(Df4?^>4aG9Sv^vsm1*7`N2FWfU0@%DCi`%TadNI{qK(0+L3}XJ+{9tStLunPN8H|65z2{~^Bm z1l^1=RBKYx25MF^p7y99JcisU+w#|V3jVE4hNs@%L?d# z1`tx6b)d~-qqEgW_=n^Q4BMGID+Kw&)uF7L^=t$<0U+zK(}HAwFNleU{$^aRJOY>T zsrpgY{whACtKt7!J!$-pdZKyY@(u0=F^Viq|D=WGh(s9`k4#^pVk$?fD5R*z^VW zyMH69?L?M%(Aj4Hp|Z#*x=Tn{*aqbq*=B!tmbmBDlswh@_jXUSmN5`S^lz^_`^kJ# zeA1Q*@j^0i6H%pbhvNq;~ z%agm8-1MPDEb)LMaboc(5v`TkEN@t*)zmX7E~qZH`cs1>cT_g33*${LmpB_^37Jq7 zN>NIr{N#w8^PHBBTQ*sB_YQ7R>aNfYQZbl@{WV*)p38Km2U$;F*Uec3KC3@~;l>;6 zDACFG#@68?FU_lCXyjq@CWP#GWMB65u4<$zCQuy_>laIIVPl&y{mKrrY2*zwT4uGc zBzy}8npNh24o7~1S~sB02zVl`%Pn7h<%kqB%d45{=CG{mP8#tiBgxp)(m2Yk$h7bK zkb~ZEK_ymfcmD=Y`gQhuaC-5$9;L}b9&QnZ) zGJC@+RF@1K+8IEolz(1~N;;j8NCvMi1DGv!t2nfQ^YeGfEw?4U9XJ+VOD4*+=kQ>k z_P?`-Ty|Unp=SCqmt#Vah`Mgsx@}Ev&i-ag4R3bsSMu|K(ywigyce8W zepY)YS_>TCn#3JE=*qoAuCVTwo19`|2S5nL3`}_2<6HJX#er6wlS5l@TPn2f{h#11{aI=vHD!j zZ;kgZ#ZJ80_0Nn&1JpSeH6oHGrQ}!IoQV`DmUD_s^E!RbLL?5(PM_yuYOXw+G2MZx1Pz$ zjkQ8hTd|0p+_FetWA3}QAd?njdLM!uqXv;4pqQa2(S=(#WQ&L}(>tDW4tBog$2(c}4;q z2jgfRo+w3j_}R6)iS-D5y+lBBU8ej`a~*Chxx@58$(8k(4*Hhr8TC~kpqCivZF8<1 z0XoVEi7ghO#0d@`S;MvG=YNLmPf8`IE}9?SF5AY&hoszxW0`RyKbq&Rm)do@zjNOO zw{8mTWUY8MG`iXXu62QOP+JLvvUT%{JCf4za>zL{Osl)y>7TiKMW6kw^nzLPkQe(T zdABw-PscUMek4lonZKbDvSOZwa!xUXc{9N|+7G7|NJJ7+r;`5u{q1XMQ}LG=>N}FB z+E@p^g94TG+IA7J*5JX+uhN~5;XMZ!w2Vji%t43XfrJ4FRhK`1KfL@1Oh0-%jOwoHtn%MW3}ph zntGwo#eg(JyThrZ1Y#Vn%?3uc91C!*`umB6I`jFWW&Dd(zvnv>&FsAZt;(M;^S=SJ zn5tI?>D>66Wj346D0c7tGXJ&-9u81BZVjDlNimO`857hgsnZl+3WAZiZ%uh3Lh=dC z?Ott3;AfRdtRw$0wwgn6=mQ;n8(&({;%z(k8DWhzn!4t~dc+6!2?K6M+Ur3)?e(`} zLLzQE{Qj)yiu>Jw6kZp<4nO|W>uZyP=|bumEz#gY5;`dD+7d#TBIspfjpYPJK!oQS(c-sWBIN4hKN* z6su<W^ZW;Jt~F-inx?oGHJ76*qK z%?mFFG+wk74mf$YAzn!WUY9}*tr#@C%;s~cPTrlkH}PbTop8{yAlX)2hxZSe7H%9_MaAC& zdu~9@)V=jMOFUfW$7pKv&t_3^R?NqHRY8GI5;ie|HieZ&_qcVIt0JEEGKIYEruf&x z96GqrSJ5qo1_By5IY7hQ`~AX%)lZ+>93*wknWa}Nm0c5Tv{2xj39o(PSrS$T$o3&rY{YU(s zo9}Df@~^SHg+O+M1titCSXhZ%R)jB;QVBK#5N|cW5EOAbvV43Fqk-;yJ7@cMlxHoS62JrTM11m& zA1GL{KnhN@1tr zJAXZf8hu!VuPTAdn!{O@#={-%%*@@n6> zk1y{{x7Eh{MJ72o_YwF$5&4_{&Jm`6A8`88)=eH?cK_LIvs7TovH#i$#7>;v_^yuHb;-2%f>jkn`XK8C2B$~&u(RDfm)JjCl|BEbRaVVe%xm&;uMVkj!O2fs z%coAjdxF_#b`>By7bI-B zG}MZCkz3TxCRdoQ2;x{I__iKiLreW@2>q|-KPlKw1N7(%VKCUgTJ4A4=CCnl&K(dX^Mf($_QG`2c7b6FWQ4;Pbc z+M`ueCpC+PAo480;OZQZba8>F$%Mex!xvt$Hn-0M;sf&$m*d@Ebk2FW>;``QH8S}! zZe9CRM0OicrJ1zpP~Qzek2&+W>y z!_1%e1Ag0dr=h0{hC9WLs7TXX4Z<+x8ybtLZn{6%XxC;u+wVufGt_3%1|r~b<}szr zR#I$$C2`#FX4LsL&iEwkdN>(O>mhBU#{aVu8b>0jQ4t2CiQIjdU%OMKvvha$Dci-Xjs zwi$be;wh?KZmR^f5raB_;w}HklH0*u5p%skib^<0UMG@cezyuof13%DRZL8*!p^c{ zLj{G0Ddi7CKoW`>-_FF3d3}dOT&_eQe8^6k2XXvwDuQDyk~?9e(I3NJX!jn>jDe^& ze%21G@0%SoLu1q<_Z%nfcp-`Gid6KFDl3zq3&SJ2@}^b4=?k_oERK3RWc<%u)j=`a z3>lB*Lu<%Erv~W5-G&z~vsxjZNcw1dkQ-;L3VAO;%q|UlT7S})q7X{Dg8oTofdGld zH;yFE1JyWqgoyoNay*>$+k)T%b$2VThb&$D#|2p%knN>RBwO>-@Q4lY>HvBH?m3P4 zvJ;h&^I~WE2M> zce!TzkD!ml4l=6~0MJ42CpH9_hjH-8b{zK|E3c*XFSf6Wj|VO(dnZbX467e2-KQ4b z0{-6;12n=7IP6&g? zo=2bS5>`N-LazXP4Y>MtlPE@XOZSC#cq|E)H6*pbH1*v{BGRz~~baRssJR zrRf0xQ8(2x@Oh&~ zW;&6wap2FeGt&-Z}DARO$9 z0~GGn$BXYTl8K2^=}_Lk{UtZtg8!3*)}s>?G~vB!u!&Rfd?)t;V? zsyJqKWgpe)PlS%mvgK(5Jw3iL)mV#d<>m(dy%XG$hevEKI%-T8ixo~J;l|f`9UX|% zHg!orWf}U#>sQV+yW?{e0|z?VTKH}5{d&KetiTRIfC5hr*zMT zmSJe~O4H!AW;@b}whtkIgim)%WkBftC%a3ZW;`dSuGpaihEz_}KQ1vo~a+8Rp~jHUWR@*Oj=dFQR4_69L<0s9?&Dki~;@u>~}d zb`3LE3#|&Bkfp}BQlCtnW$gp0WokgB*s%0`3%cl1!7oEBUY(H1ZyTb7haSA3=+`5k zzd%)OG^7Ei)&oqO3z&GPpX~ff=JAG^CV#TTn*Z`5`5CSwH;8?on{5uScxB$J%{bNj zK_gRlwH94_q3Mv?zJ1^4eBJ(lGokk-R46^>m`6>s(YsC`Lf(^f z#~zHNZRH9S-%L%sY0rFvxU2mb=dJrtxKnBD1z`7{Mv<8d$>J5h-;)8rRzNEMpm07C>$;@ao zXXw{Le8pnJ&!wX+6*!0u*OcY}@{SB>@0nb;(HTy|&-;myJMp}i`u@eZZY0m!Ti+gQ zjYsl>yees&s?R)!)BDbalDApIKMEB!j&B?^<*+%6iK$L)Vu;v3}9c?zvHJ+5Ro`_z(RXJThG^ zf@HGi#|$#UreW$kGs)45`^F?A_s0=nL0epcILCr@FH+-p%)NRY#V`ve)%bW(D>rDd zU485YJOf4wh<|>eY&+#yJGta96v?#w_lamUDDpMg-{sGRi88h^G%m3J=>?ek{GOFQ z&inChvc!#@pOTC@%>=(f%;`?NIG!-fGNh=(_CI2S)#AzYG36IeFwdleIa<>yfN|0yC|5M+7S=Psg3G!=TQ5q3|d6k0~ zQ-AQyCB*P?^%r8wa{$t+v^z-V>M9H%7>Bx|V|f6=7_eBc5&>jz<0!}Z?ZMV^=*uyM z-cZuPFRPSEEV_bx{+QaKx#=IL>5>}0dIIL^db3+eX{3Su8I=b%WT4adwBpu3feN`8;EnK+w#f z?Ty^mEb<9vEnSQ0+3~XG{X?>GlOvYAk}RQ8en=(J^BQDiHp!CxWitc;&0N4S(Mwtd zB1skee}QwsSzY0Y^iT4w53RCAT$~p~AGdTCU6WN93spX4&)w6{Op(8pqp8q8zT*>Q zcX`fA84t^|v5+I?AN;fGnY?SV^X8kP0mYvfr3)E`yWZ}HrYS@cBBCgj_qlc_O9+7Q zrliHBT-0|O+WwX-xv>3J*Zcqi(2{<~aT8Gg2bHM`1s7=aZr{^X)qRa0LB}kLJ3L?E z%#V_fB~=^!RzA>~`UzE*KPlY2wQp|MF$mbTWsP zCW>^Xp5WRWzCcq{o2&Rjn+{636_kQoazk8qOKG#2V&dA~Hv-jF7 zKI^mAo-c2`c`V3BSt5SX0hlB^>#N|_@uG`gU<9+0J5-G_11j=V~$m)u65Ou zU14IrUIw?sQqn+Y`_C!>_}ndW-dIRi-hoex)Fmd@PE>!wy_Z^VZKNn3tw^+SXVPDM zeGv95!OuE=!VKUp&So7H6fLNb022qOk+o|h$E(_j&5hosgXmjRC#Ykfrk9=*UKtBS z%;ge(7O4}~VIGR?p6d*M1!${Fd(q z|CbmqsxVEU2?Wff%*_9vIQC}eK#6BpcATkXh!{|y`c#v1CZI!44|%#S8eN_{3bYb< z3nYb^N$p{a74+>^Qc%ku{ z!^k91)BhtHcoEH~b~BJvx$P--UL&{wjqWpn5VabnBcO_4-esv1t9N=jX?4{C7q65A zM8|i-x4gXk>CbiKz*XAhtH_1kfYa@1MlGvq*j3qpc+_c5z%dhOG0+>=)z!7a=sJ4f zYHvPmqPK(alI_$kZb+5%L;f=|le;FsU4v^sQ(E+uvPZ&#RIt*ahT*wien1n3$NFTU+Df zC#wyb*i|J^^=Qb|$yP){f(GoWTn7`W1Aby`b@kE`sru2QZUHE&f(1?+?uh=Fq`q1Q zg5s2$#LnvHggeIX>2YW-lD4qHFZCaO2w`f(f_d47#IL$h`4vAPvqimPozFl6JZ*q^ z{uiDhkPsjLW}($newZugQ^)nGdkhT4DIe<=}`+@UmK)aE+*+?Vvjb+8%D5(UxYvM`86+Q!?HV1O7;vprj_`ZJl0 zir0n|L?hs&$*fhS1k?n808W+ldA1nu-E^-_tjL+W2*b=*{kXKY(0Uk-d zBI3Ub&lEcYFWe~TqaJ%-)uWl;A%3mW(mn*LFb21$6(no8 zo1hyNt`zRbpmME6|66oETxfb*Wd&8!(TYow?jSJ)-%|q$ruHm@E-yQ z^r8V6lAj`DtpSu$>6jB0>YTJYg%q4}UFm4b;m|@mRgnXA5f=j@z}xVb1AX1_X4{Fq89o79J6 zj!CKjv7%olrt{fvYb6G05sqnJS;eJ%9s%-d4-_P zlh-Ff&PWmxYj&JBi&9Lc7K@K!RdhI2%on-(GLNl-+Mq&tAdhQswX*`5<3(414Hyn{n=$k_|@29aiVgsJyZ0>M?O^PHhJXlu~!;E2__ zssWqV%_}%Q^P%4jSccJ=^|u+P%JoGq9}p(laj12SH5HYRG4`1kh=O=yn_HguRSPdJ zvcmCS@=I3#t->At0J58@z?V!}47U98GkyntHrLEO$+>TYZ`U6W3%r^D+6X+KYvl&2 zFwKmo?P03YC4d{v80qam>KWQt;a;7WQ$Z#}h z+)yyjV##y(h5CtK=$N4`bl{c}I%f^MdzH;WEUlQa*A-Bbaa&^2oaSyEZF@e?B=$t| z-^NK?0jrc^bwo7$>}o5^z3w;my%TSsH!;4O8*+ME_Wg+OD_rr*qi#Ku8kh>%5ntPn z40#LK4}(;}n=#-!{|s-e3esj(k>)>FSxL5s0-0{c_*N{1!nrmkgp} z;l&SAz7z2z@=;6;z39!*8?@>5Y+*}hn`LDi%Fs0$tf|l*CKEU;tfuoAwr%W&d`x_l;4rC^~jlTHnwQarMNw=dR_-5 zYDhCITkP|lzG%1sGqm0y(&XbOO{A4sU3U6 z$EDaZ=i4J364t*(olw4)DJ+}b<~p(4;3w1BDE{y-hEJwpW(T=w-?RP7$3>InqeM1v za)TZ^XcIwDZHNDxF4P*aUoUcO*cnnD{Uh1a)>M~QJHMQuL-Z|S>m&e7 zt!kto9bSXa=ZO7buuK+tCRnKm6Zlq$DAVFe$>s_iQ7BYASL25?Wsaz;gLa2Uibgy0 z9Im&5di)XDTpeZyPLV4`^lwgWh*C>Ao2PtQXh!{(hEq^;Ch<&ybY; zJW6L+@If-m z{k$vm_YLFsLjXw;wmVs6_so#yDr9gI?|_r_W>iPN%{U2}eiRK+a}=4bI(^7dZD2cA zh9u5NiwM^qv)A&OYZ%eAZB>8~1^W9aAVe{s;5Nw2Xi|DwrYCw&%eHlJWq^fneL5|s z3j3r?70Ilu6K9;8LV9#`G?;OK!BfNQKlrV#R+u2`xHFo1#F$I`iG!KBJIzjw?GEi6 z#xK%dPJ%}Z%cmro+9=S?g36n?g?wdLU~FfO_;&f6IM)sA6Sx-xuvJm^@pRF_b{6{c z3la~qHPdnV@y7h!fO*KPsIgmbs61fbKp!v_Y9JVQ=UviO0y7TRL_U7LOtGKN_N*k2 zdg?>|8N`8AG^$q$sz2~bfed9#=kClFvw#X@qbFlq-V>F*4I96ay*>HM)sbM7MK+0 zfC1MhE{{lLY;I2f!-@H5%$-QOaO(7DeiJyAr_~*2`i+i?=3}`cWrpQcW}b{Cg^o6u zo$}1dGO5b(b*a1esO!U@Ru$NqxN95g=8bmdrpWKx?q%#Ymc!pUxCkDZp zbT~KPya3H_%whZ6Ww+t zfjS}Y*Pq|Ft8m>dHh;|Xed^&g?ut-o^-qAu=|c?MOY3MP4xOgRwJd);4SsR&&7W}Sl_J7yqRL*mk8)0?RQsKS6 z;Hjm{eQNmCW_=dfYTqk^(?tZh>wllWEk7Ijb(!!SXy>&g4EX#mWZY}L8-$3!ws0_% zWg>cPdRtZM(EBSOM}}XA0+Cuh38U>Lsn9b^Kb*g2(!yOp&F?+Pz*`C|YV&Ap+AM*> zv>87ZHsH(d-be#nnjfsC#8={izVTD=Bfxv`}RV9@p2K4RkhB;Hl(mGUjzFJ0X9 zPkwP_vPjn-?@`XP{e_?X^zsKUS=)RR}rwOX)kC|GcSx?L73$b@1r< z>>S%UO|*hsLJC8GCer^bPcq*R=g!zyb6QZE;)6#}&aUQPAiqD}0-%*^#C^&088YLa z(4WosjA_cY(GVj+(CPffQTK6ggus2N{}~x1x({pni8`~=kNJx?n1wv(-;~`@izmX0 z9&LS#WS;S-p$A%Xu~#B&1`Q=7=x}l*g?PrP8MkJeyLO**Y5`k2|`^eb)dIfp`KaQ;Hp6jReE%BT={3BB(ArH zZ)4=>xHUrkiq0R!hemF}v zm&nuug#SSYdq+;ndNHMJzeFCd^Y8HZ6}fvcyFEJ`=mi(d7az;6%*J*RHmMeKx7yLg z%M$sz#Mok0UfqM)#P6Rc9|g@G)I*gG9YE@0cTP)wkyQogjn!kNi<-fMY^f-^7Q2)$ z@}&;!a<;Ywyuj=Ki9i_4pUmWK(hA+#7xLturJF9wLo>Zq2Gp^*7?nx;=W-EmtAPoQ zw49dcn*N{mMoq%JNPDuWc%D&sch1I0O=tMC44VA9EO5O<&z@ivF$yT6Ph_cT4$*V2 zSc8#0xko~@5v^z6f;remZ{$F$n(ab{4H}uI30@Ycj_4#h_ z{YyLj5I6Kk8B~9Cg^uaeS3QOORGgTK%V23HRkzn`^0y!VaN$R#^OpBfQ;g6*V{s>V z*&lnjmiJR=s+|Pb|JDI!qB{abNO&NLiyxG^)OO9nI$8h52Kf6p;1~fsd+h|$FgKKT zV?URU{+%WFsf?fXz}()R9DS z#_F}baKVk)-=vq&>O9i8D?SNNgkWG}-p-UV=>sM<)@q5IVa^xfU4*ju8mzd*vyY2- zC-u!Mjvh(!v zz!8Ji1hVf{q3E^RQ|Ex%^uRxZ-C>B@gC%vZJ(2IQP`T4ljcXmR7oY~=&6-&Dv35(E z^`Z3DGye$PFG|2f`;8i6b*^*a%do!lI(K~xP<*MfeU|Z2PvpQgK~weipUi1j$TyA_ zGaufEF);#5*ue6JZ9g!}T;^0wgxHc@ugLr9oztvESNGF7(E8P7T(Mw^e)mtH^W%4) z#f*eEJEy*hbUzq!JCD&LC0ZK(cmjXJ*2;g2G=GNd``EF290j05tKVbJW6*OYeV5)^ z@b(g{KoJyiXZUk$=ug(uGKkRyDg%y5N286V=}C`h0-fK(b)7Gc6rT23qNs^NfA!Ec zIahOuPmn}zN^Xo~o&Gin2y3~V)?O`E$Fb?ztQ?N4wq_|-$(oRe@jV$Ibl)R3_bS`& zc$9kXBhn#})I<%Iiv*LXr^d<8CMaJ3!iXk0`dv2Oo_z=grulP>jill3`^d(}6IUKL*qY)h3M?xFJ7xx>x9^y@R1D7?Ft6o-%c zUEnqRgnsu1QQjgB-p@PobYwlj&|L{tl0U1>E`*GHY>V_*G(T_VPf$3sb8lrCD^ceVKR67?`7MBnG_&&P|raKkAt z$%HHZp}Z*7WyRYhq)*STdA(Bm+DB&5a?*t^WncPR55-L`Mwp>-Vff z^`@PBt#|JE%+5S96f9U50Cv8Rkn5vaM^g`k5pDY9!w2(Qvl8%pK0qJ1^q)?9t4!9H zPad=*dHWqV@rZW1KT)I{GM#VD=Ab!K>iT29+^BBA9Gc@X)1_@x9{ym^+5Ye06==C0 z+Gre6$M+>#ZdA=rA-WrOz0XQUapqzZ=Y5j5eO+yfHbS8c{u4s*)umqKIkcsw<>!?X z%@Sgtc5sidp!otPuO*Myc4)(xT1 z5+G6D6TN+7G%j1RwSggKS2`)q$jgce&~~C|O|^!OWnmFoSxtdzeqg=o5_s$avMN$g91OGBvcuUr9=MgFk$=p7#acOiLO*7k`4 zi+^^LA)dD1vM_@C^tE5gdv?fqrYvl(3a^1(4eiqSTfa-!HB?$IkC+Qlm*?}xRBdNq z&;~wFG5a^@ob#mvgcd3ZOk$o`q#76>Z#Y}6j`OQyo^SWpDbHng>7^^RM!M}@M!Uva z%zH4wSjPJ7xCQsFK$)Z0e2p`N8gtPvK?p*w4{Ia`oKb$TxOfD*4`s4IbQOFpa(r4Qx7MN8Vi_gRy6RI$nV;w~ZK{6o(Yso=X&Yf6AM^S> zpe{O}Buuxju2PWys$?s)p1$)EFSF{np^%7lEU#rQ{Jqpxu&89EF}1i4Po>C*1kEF& zHpVNypU~Ra6L+ScwxvyAqoK?5(*p#>t#pC4F+axqikttANmDk3!qtD~ZI?tOfchHzWcvU@b*45z!3yAhprV(;yMz!@Gd z7XzHd#LZ8*6>Ru#clhjD!mx%3ehjj$_|%>8;-T6_ro0}NXn)Z!&?1Reje6y=LpT7eTRz69K#hL?HmNAjgk5Z4;4?WT@Q(F}vikG6o(yK?pR57yTS zK0{l+O3Ba(o_P=#_xEInyyyFOCXZ`H@2k_#x31Szy<23AIQ3kUEgO8U$wYOBUUhid zdiO94R*gJ3xPqZkvzl;OTtR; zB_2G+d{48+$hGOvTmL=`7HxN}bh7)%&bvMq)@QMnT&hu&hpypJlII>u;~V(K`Enqa zFBg6!&jh?97c20!&Bns;T-Z$j;N0<093!Xg#`q+3Y0KFj^vCj6AW}!98N#`^Tq7W& zEKN%ECk~4SGgtHVXN#hhV85rT^d6aqBOcW|*Z=wHP~}r1#)N@N9NW8fkFk8))Xwlw zk>fY}N-&cnHv6~TYwX3|W7Zjo&Ij;u6MO&P`(hP-r(`)Q!9{Na*0plyxKxL6&0~cQ z*xmy(Ws2(am`iea!Oky9Pmz{x1=Y^4_`{tY_->CHoN)PU__Pl5qrlP-r)7ZV)4NUk zaTRlAK!~3|n4$~iOQWx4U;EF){s4(4bQx}OSK6fhzPr#X&XudE_pU)k_kZUCAOg7N z8S4@_?jw;D^;BSX5)EsU+2`;%eu?PYkpM%O@`nKiVlegln<1UiZ*LP~TrJr3v{znw zuD3V68$dItX4#cVIfth>7L6ldFQ4aC_b!>+!)(SfD3YtIj^g<}pZyoc6rb2z1WDt0 zP0n`(m`bLU!CEdI=bOVMX3m0A5xS@ z1Yj9(Npu-S6?DL@3WVxDzW9MCqhA4nFcDzuo6O|Z$w-LLG4SkOx1qak8zsXRggyW; z#sefdj@02DzI1$CO@_ml6m954ikwM`;^`d3KMar)IZ$EPQzwOBn|7%bF|M7BnO3A1ar!ujy}E6q%P(7?j!#5%Hy8Cc0Ypn^+XoQi+ux(FB4I|@4nUA*FYSDH>3nDE zE$&X!=t|gH^y)jKJit1GolmhX&dcs6$p_uex6!2k4uv9JJA-GWL zCmguShJwF#31b#jLMw0ld5F%A4=Q;nc@!T-+;_C|=O)U_%ZsAsyB|cO&5CRCGmC`N zZS`F*4dW`umDk3dK+{pPw+6Ehc;E}BNwLfis06w%o*M8yJ;#W@lTNzv7b4E1UmKGCt^a*Ma?~=IQqgoMd=6P zq+BytR<>+9ONf4bLRd?z5oXK;`d?$eM^0JI8RqV-+J-yxb{c>zMBc3=Ts$ez2jNlP z!J57Yy9-p*^a8HOkbVNn+Tm*ad$a%*6`x(=&*^aVS7+0pe*!P$yS3mI(uEb=2wcik zw*`iFfmd$@x@JmSJo;*>H6tlSpzi6j>%BXSOt+Adn%KIfi^a8*%z1P0i83PYPdi)GQx^xiCk4QPbUnQaJRb!`y~M9j45+o$BHVD ztddP}{#h1B+D(oiGH1>kyn0rlDi3aX_AWubm;OK$djJ0YdqhOj%1@Pa>}fUCpG24d3b!+yzIqi3zFDt@4Z8-V z2slV@>Ae;s=mqbO#~#eJh8}%B0z&4bPU62Zvf(^VO3cs}@uVL=TvVW`ia?Zzojjh) zl4S+#q#G*aag%ZAp2?A5EP;_@gP{|M5lP)YHTkM>sOm~)9h&q1d=?VVdp${025Ih zkIONdY2xezFq$8=4|q3zhEsuPRfh{tB88RA2Pb z*rS~ULQMjmN5ItVu9OgFBe+3o^Ke|5hK)Z-QiPmmW|I@6&1216@=TG0%Jl69r4+fc z%KM4%s_pY#2zf>_L^hY?6?3SO9d@25SiL~K``4WLCyLUk|h1ETWnV zhCL36bCA9AH>T^{MVQv)@hswYKQb{5INfO&^8f&aw#I!Ez%IIpYx;-4_&KsaxK1Vk zQpa7-n?@+#xp^@dt^}yLJipzfuEs%xwvg}Y26_k(XD;gKhyjZ-*UKH}D;3r7CqR4% z7w1w^%6!uV_b3MEPy)z^Pa%ViukIi7$@N>|2GymcK+N> zC@fmmyfW$b=7ko?J+6(8w+g@*04GD`jNTX6S5F0evB~fQ+2-&o0heA*CS=b19qxC6 zkf+TtzL(eVLIPkfy)1LZt{qMOO-ozF^|VavxAjlZ`Nl^3!&4)ENj9?I(A83nEWXX* z!`flqtNA9G7bnyGnBQ+Qz1EDOlPN$ae4ISuqoF9v!5B|^&{zkiz~cb(x~Z3_zHK7-w8MWwhwLGB zB}UM{T4H-X8Wb&C@PL~7zT|b!D=b0Ei6QeHAt0r2FZmDV2U1~Yi4>%d_fgGQ|DB|X zLGgYEn^W$@ORG=l7EhOZ{V{Zp1Mz~Cu$c()MLvLbor;fc&$ zlQV<5fOuTGP zi@J=_9Z9(6R;6#$^OPM`zdoxs=kThy4$2*~LFxM1=F#01DjV5Z#Hgc;-N~`aI%dJA zPa3hR_)zyGL#3@xM}ZVw?I+^$o=GdA>q@=wS?i(qjG|)dM`2iLe*8R?zEV`F!t{Vq ze>gjEYhedK0dcq*qgJ@)>aW5+sa!lK(nk+0eB}6lHvOr7IMh*ZYxt4iNnTw!&MK3g z#ls(Ge2~7vDsV3dz$B|1tN3_%6aO=zm6DD!QKK09eARMOWw8vZO`&n`E9(iu6NhlX zzT0_Db*2>nw!etS7FR#GdLnlNA!qyT2b^R=?Ip%oC3N`4pNq%~3GU%dl@rrn%~v

#R)v)AcXoSbXpkMwi00e53ApWwm7l8+NrK#+XS`f!X)HmdYoICE zRYOd28PJ=AbZT3o68oc&{@=Y4o_FWy*tvF{0zd}NC63#B+K&xxC9xcKXWa;=<3KF3zbd%NZ@1`dvTKFt~e&tc8 zfH-*q{Eio-3U0Gctq$0&fLFTJ{XRTDKdx_}m4MVw_jBRHqkekw$Kz5GI%;Z5Zyp2b zt{Xf9N8R)-Tl2pW1hx0>M>kRp=<1}+Xd={4ri+Z6PoLL$_-IH3lg0}T$$hA6H!?`h zIHmP`l#yk^?)>XEi!en%T@TVk4gyvW-zfC8^Grg6M0)d1Hkz>26N`$5n+N&ID)9b^dVvrva+1SHJ&=N?ad$rd+?b z82dca^-O&FB zUVj`Bb2Ic6Scuersb*P-i0!9$#%+Lx1*(Rz1FxGRiMy zYd%QgzL2NKE3S^~t=8!+ofJCfoeT{P6f>C#5dT_e$v|g@oT)%1(`kUpci$g;ic9HV zW4mQ-X!9raYvSARB9g_*DFPcTNo2C)rzpZ#{R@8p4RS#>2igbJRO>l3@p$4*%*4$8 z%x#0kdb{aCGm)jLezv(E4qF^}f{7#_5*)OM^fXY!<%hQ(Ccs)NF(zOwHIJ7lZOuf#_uMoATC}Wk zSJ_B{$!wWy|Es<_ z04@bkh+-`jy2};`9^Ye&DA@ut?leL+Wk%@-oWiiOxZ9RMG2{24m6b%yE>C=K7boYTUZDJ z@_H4;wT{ED-2~u?UlJ1JEG(KeLU(V)k_c(rYRGm|S+jrUEXLYNg({H8!@uY7Q->#> z-8Qh8h|~4vUC&kYmME_oB{_NVW^re%SEE! zh@4F@NFcY{3wrHHhQzkYHy`lGaBMb|{O}Xa)IJmuiHwriZfkfRuzV30t|2nRWY4mG zf0~kXI=jItr*dFa?CB1W7k(-j%%bt>cSOX{M~&t><~E7VTf2V?jI>*LI;{SP^GcDw zAG!H7^!BJMhg>$C9UB*47d3{MiDY&z>66#@SpDCm>)^N6QdYvZ+Z=-$zig@i_H_NL zvoT3Yn2*u{gul9Gwq|8OUOvKCBwu7a1-_|6b&mru_&yXnTb)A$Uj7zkn8{F&_Z@o-7nk+s+}zBcxrk5sTZz`@fCINXn-*R z{?FA`@d6PewIA=Z5XFBSm#IuiZzp}=hKgeH<&Z|O4m6}5_%$wMhpsmZj~D*R6|(X) zyBU)@n9hQ7{`E?fa}1}FF8_#fQDlm29e#B(8mGX4Zme9iC4FDCQ~tXTh7^DM8ns|~ z>XC3Qh;}Np50$W)Z^tsKt|IBo9NyT8!XL>L((v7H*)UZ2xqX_EXmGt?lX~$-Fio9<0;GVk`UA0l#dPoH z14fyucy)~eE9L08$gR6a-}OC{^~xm(v@Y(Z8rEW1M1Nh9%QPqEPTwMjPh#I|#4(E8 zL<|+nns?M3Uh9Gi;!5`omC zMlVQO2^NKY{zOSkr` zuGDfT=ZK|3Tc(KArNYraa{KCw0Zlw(3KEUZJ+{K9d%K6?2D75bA7X7QjZJey|iD}6iZ z%pZ?qu+$DR96;!M_TO0&R(x&sBPOR6%#tZy{WYy*6)*3b!3kn~vLe_aF>OY0n@P>O z;;(6*nW?kuKD;{RSUDdYNwCDlCVCi_pZ~n=yxwjt9cC9W+)@N1`{8Eu0bpHi)dDhc zIhob|i^2Wc*b<0YZqdzu2^(4kJLlftL5I5M9@LAX{lyrazM=PF`ETys4__|eZ$e~c z+*#tR1cpwxXG1omOd~KE`O`O5^ufKn&qwrwDkH8>qTl`H9iUxj=za!@^zUJqPe^em zRU_(3VwN)48hg#bR__m1_N+W@`%b8igqEm{LPeE-$=jz>V)DMa%oSWd&fFN63n!Z? zdfPB7|J}#d#L1@kym;=jt#uG{VGw{dV&!oY^mJBnI=rJAc(u1P0Ju5PdenvDUfKxtpnO zOeR{72kvP2tpvCJE#T_!Lsxx!)7}y~YDt8&-f;oGiL`sCx}Cn0lJZzM3FC;$Ic$dI z$~v9@5r2bqF`pEQrAEEMb=5WB@cPR*$)eLaIt-&{3#m+9dK=@ZS*+fAK^ja_@4l_C zqu1_JGn^idH&e;;hd8`0LfzJZa|@~iwEAbm9vqng_qmUXo#UCL3cBViW|>r#I)4Su zEfo@+JQMPl)zug(5Z`g1qlo&yQ%ycjtJ7H7{_8;7v9(k>j#{lAF%vlhFj$in$B$fc zm$`MJo!9rCa%`AH7d+cr1gtc+1R(!WZFaSgRCrNFEmFj`6q39MQ62LkSc9K+uWMXONJ-++o6EVg419l zrAE+T*VMYVApMbG4>JlhxRm(aQY$UbgLHp%*>qk35U6T> z+YtgeZKvmEEM?b_Yg;F2zOLcwy@GRstX<=s`!zMyOp`^W149D?rEcP{UVWsg@>2`u zT#}+WkQ9Th&0;7e`J{9vza7suVP$f6r^gGrw$=vjU~24lVj@twsEeTWHJQ^AztJs} z-NV!t3o7-m+8wze-U#;fqv8@_y*K7Rj zrYF2X#?$A^E_MvV%om`!&YLQ`p<9`>o7j6mCGq(E`VOPu=9$!0OP0i*w#fGneEExT zZ_eULwFl>H8^cXSZWfr=FkQb?0fhdrSX1m$S}~CLx@X6G&t>matX#P#-F@Rz5trUa z+EJB;{l4rE#`JFlNu4&Ry%*tD4%2TTu{2LG^Ip4-DucQ((K4wCJZk3MfdQ z+d`FoElR>Jd^{Sloi}nnB};D*IRKqiu4PX*5&OoPDK_w5yrZs8R;k~RUsCc32zr=+ zg0N1bSRGrMa`q=!!H)REcHh;Rn;MnA2^;zQY>PFQ9}wzeT^*NigA9;?pkYclz!$u^ zp^fyX7|OBsxtvam=y-Dh`wQg>xEP0)1>$A%ii0M7O={=NceefPk~Y&KT-8LN@9}Ur zZblVAga%Vw!7Xr0%h}amobayOb(--jrWAMm@b`ATd|&_RzzTvY)2i=DEd1Qj zrlx(%2TCDoPMh}Ueb5(+fADh5a?G8BB=tZm!t5{Y;{NQ6z}_- zh|iOq?brJ4qEGLfFWMild>RD4-kcnR$T&or_s3wdVcjm7K8}&pB1=v!gA-TNxpA-9 z`JWzdpb6;iOyL>*#FW>mt>=&->MPb#i@^qSkP*Xb=uTdt-KW_p9c9waCk(7Y5FE+s zJA8;(AaxC}$*^3$r3tf^q6Pw6nXJ~5YrMkN4mLew$fg;-l+Xp2U20M0Tcvsn+9V+P z`QZwU#KfjTop}LIGcC&PI&VWn>~*ZaUj;vX8d8>=_xeOw9 zktf$f1P=D1(^VVHMG+i(ZLv8PgVs#p_$xUxle&;Y<)EkN8ny0>Oe0$Vw2mcLk-VQP%%sJYd({~krr3o7oWeYJWNV!GjuUTVC> zElDXpt5nuU0-V=KU@WLnmaz=%Joge`!B8h7Nm*Q45w7qJ9o=*jBiS5+lg8#?1;Df{ z!ipS?q{@qU4+zb~1sHXSUB78P+Efu1%`?zBDep1Hp`7FYplkqn!O9vx*7)qg@8Z@VW44_BKA*UuYmA&88qX zyG=|tipxHy9h4swPux_DM;+gqnnp>3EE6wHnczYe9RL+AnCG)P+c$Hvo%*!tWye=m zd2j4SJmYi4Q?b7)YmGY@->y>-wq!JKiebvBB6XkOH^xe)@@eA8NZFk5wR*=z;0(r4 zpW_zo+sXoR+mBm*o`Em~Bt6yQ+A*gwmESSl4RCl4H;t$gVND^OrE*_!UPq76h>i_nGcM#uTvLc1`0Ck&MepJ&JYsmC+2HqlleSo|e`^KRNjK~}>7y-cXv zoVJ_WaVn2}eAl92XHK;bVUYbudo>~@U3(loDi-LH}>93eap|~UT za$#GzVN$VRoay#|kf$VLe4`z9@7xs-23SE|xw)^uy(hxLy5J|m?d{&+nbG_Vf-8qE zvDmX#n?E75)0GRKduTTsfCMcC$k^ClNP7ZSs9Y=e|DZX&!~Z|AoW}1iPy%q!0Moz< zvCdmNss*4R4>gk85PUaG)}43jX`Z|P(R9>{KG-Fz2?7wzR!j!TJ@3ZtQQ;>esowyS zOazQ4l_K}dFZj;GhuV8X%Ow;5OW36T^|*%gv!Uo};i?j7#75)G?98o(@7ef*Q$^x5hI^-SDfOeJuXYrnpDg|Ue? zpPzCdgKIgp7MP%xD=U+hFQgryVgD_+#lN5G8N#HFfdPCcuBQOgPbN;mLk8P8J<|g8 zV}K+4%<=TBmsXQpDO1oWjmQ3d*5^BH&n4NGw>YhM^4xQtaxwpALQdiq*c%u~lgB&} z+x2+3s(@40K;riX2vFNXW*S%VGxu=JAsxl_3#J$tiq+@_oUu_+(0QVqM$2?L{TG?J zg<~GrQ8z0L;E&uFZnU{PStb?L=U-t$TtNNO95podkdgkFFqYP*Ztj{+NX>T-z&AFo z!5o~-y$#!{K|m=0z}S?(P-HkU&iz|aE0}Xtuwwn^^b4@#o|poaDEqvV**j^_7r}zr z6=!KPKmH@x=eq11B4yEem%#&NH4wB{AC(B$k=f>Mu^_?29VI6F2xv3uCDOkxV znPgf1RdHv5yW!a(7D;tE$xx-+Vr%pewd0>`?U$QQ4=omBtn77*D$~sVQM`e{)yl(q z#1{0q(wcZ@2lLhR8C*LWk%Je_%sG)RZEku;B zGN^>^tRFj>R^t7uf=*`lV8D{!rgOxW$IDJ7qalNe1iuqt5x4N$9dKlL{TV0GFvu_q zzc=YW4Cm}06#-aY?W(p$7QEVNx;zo+T(s+^1g%OmZjv<9hsaQMrk{j!W=+&#^FIMd zDR_8?K#{fBk_*f``=qLU!i!7e4bqg5Pw&AGbzwV= zTf8F~=u#gj4n#tbx$G_;E1n)*cfjS=JH3RSj_`K(1}l@ZmRg~??3^G36zsfFbYgQ> zr$$D667E)2kO>nbHoFDLCi^-NKbi~gDeylyzvWlIkKng>V=sV1S>%n&_7vbw&e9XF zwuj=Eb$k{le3PNAMB_l*NC5Fy&uzd@)gfs$!`c7ZLk{3mU>6d{)DH~bZ*aQYhkTvm zCaNqLVkI7Z zct12hYG-z5vXW*U zPn#_F@-yIm4gMTOlKoY()A2mLTXLD1-1tr9BacR*FZUDJ%xyBMJ=7^^<~w!tpxlSa zk(194_ixLdUiMqURDy0(rx$nHa8s?gspuGErTac^pGeBy(nylHj#dJ+d-xe4neIPZ zz}@d~0OrRM!{e_*NXwwVXi?Xcd&ERzqW4A5wqJk70pMNH9{|Rg68)Lp`q1jd=FgJ4 zD$^#Q9P2hWJNWL=ZIbr?H7VOO{S+8xK-VqSc=x(#D`BXOySnPt`s$-V%vg$XZphOq zrrT8P@0xw=kT(VRd%p;Rp6rObl#%knb$X_?fQHY|lfwI&q#uNPP_d%bHUth$#Khwi z^IqZe%ec(zv%r{>x)?U^7}PfvcwedupeGs3AB-qtl{9$f+~!ijwxOsSe`y+r4TQm*8XsnH3is!Y zzX1(1@_@im4SB%g7=)B~!JIt<`!9*xzu#c|UH{}Qg1U)l?7u`PKsA!_==KwF5u@Ec zX8aBOe8Ulm-S+Px6V~mo7jI~GHxM*)CL)-{iSV+^^CEuTb;SIfS{f8=BmEZ5W2_yJ zM^ttcmJ_Ic^tJJ_39?6Xb5$4(vYFxk%rKvKq($&Br~+laYj>*x0Dr<)2oI~_si@b< zH-jq?m@zIJGjVnh5-wiC+s>SWgolqGmIX|BrI&r}0rFr_q5{*6fRO{Dg1?rsYd1Nj zyzQ(xNT@blH5;l@eS2`9=&=*d|JK;GheN%6{c%l7NMmx1Q_h5hT!)Y-r$IML&KW$YX+4bj=DeTJTB?>nYJ~K3Bi`W)lNAnog|K(-pb1O_T-TxG zio=ycir?G0Gat|SUyczoo?lv|+6wcT4o*B(80DqjH@iRH81fFgZiUA{nm3MrnhBeh4;@=46V*tc}xz& z$2qFFg~7oU8QelTBbRUwK8j35mJ?`zZ@&DEqNrQ%~ONpaK)KdRd+n0tf&=KLHeF{hAXJi6aSH zQct;>kwaYqjLXt$k|XG_F?^OQqq5MfSH13QBVIx{!c-3O5$g*RgOjLC)>46Tw zJyi@#{vy;RZv-pJ0*GV}%ujN#DX(g&jDQ$gtp630EbgK!*t;`LW4Zcera?^38;Fp3 zi6hvzf^f1x?JGqa>9nF=1|_Ug;7s&oWvkS_MR(WIs&W)aU5<6qvD40haM-a4+(_Wx zNZH7bIG0v%@pq|oJ0EOpDSqwrzLJWSS|ZJnDo874>z}G;j1Se9a1O~$+`lP)v~8Uc z6*JGSFGrqdZ~SvlAR)Jj9NdkZi8F^IVjhywsyqB=D_TwtXWoNj^A z#_%4v`YzG?a{&Y9{QTqJhwc>x?l23gXlikfN`;|_BwpLs0-Jo)Ln?@Nw8N=zZMCQP zP}3cThc|g(E06^hlu8lyNhP2u);v2Gk@A0#Ikox9@stW8wq*blPr-;2*O4e5>_icC zYqAaK@`|a;ijH_ZOuK5!R0EGh++n1lR;?(Gg~omCu~21lN_lA1@xMDCsn!Oc5aL}L z%8o?2sKD6P$gSsHMXZ})Y~XVNSL^hDG+OsatQFw~NHIFp?EzjYbHOvpOisBbuk&m~ z8ohUkuTCO$aiVWdZ_P;mC_?p=_CD^c4ITWZKvMu9bgPKrK_4j0&)zHY8L%H+tCRZF zu&BeEDr)k6sWb?s~M6{F%%|QeDwc5%=p4m&lLq8ZG{++3YsX zoL|3#2Z_HQXYzvo0PPGm<=_W-hc%iWkhd5V#2&(?@!%~`le@*&iAbx}eOS=TkQn-O zPF-Eau#j9GZffAc$nT^7nJ}Vn`l0pm%K~tO=w1!|{>+{}CGgUMAZO&(%VJioi^S}J ztMdK90T1DQD0s)?-#LzLrROiCe7jP65C@@pop9*C+7EpJd708hq>WI4+SPI`qmC*JE z4%8ef@age$NQB9AfZzjNG-6cq^xo6=&O%-t-*i5yM_yUDk9|iNwEa?G2L;5Uj&_7+PJHaw5BL{ii-S*R`k;G800c#yMKXRUY z7~SV+!VW0ji#;?wEr$EHdWUo)?4lzsuv}QagxmQ>_{Le*zU{VZ+&^wOAh;G74sEDb zFz?KH6%m+@v}AsS;I!z=m54|^BoQaath)AnE={+5#H=aOqB3ywxQ;hcS+d%)t^LjY zB))7b1vf$bg$rph-oX-?Q9>ct1~z20Uc#A#QP>plw>%VIb6zQ5y7Qyco6!LrdKsp* zFB5-tV&T;pEexbb|M@7}pH{+otLc5{AZ@x4AO3VzRg`uM-xfE%Sn_Dou^`maC-}{Y zON*LnlaP0QA zqzgXn#dztyGALV=7M}Px&8@FB!f4K2k(Nj(&uxCS|9)sn;kUD4&*CZue>92?lWA02 z=YB^{Uw(jDotl#s;{s?iHY!H+=+fx+ zp%uh@A%Dcs{Zlt&oY%UocX$rHY;yy2oA4Wq`;gDAvh4AAmx~M9s8}L7t~)*1mHduf zZXbAp>((_k_leHlk&r*2TaEa;5CZ`n4$cO;N&0s?sF#nU&&HWDwfaW1vVOdYdSCkTb~EUBT%x{G zERTNEEW1)8j*MCossrJPQgx-NWxh98zlk(_hww`KPUKhTCgw2KVEC=}woj)yLesnF zoGx#Vt*K$K8^#4jGEzFq=0H+qQl`MU;~D?drud(yK^=L+rr9N1t|ndpRgnj(ojcxS zbGsp3Ar?b*T!djOID;Vx?vAaK7n%A~>BnspCQbp0L1UFC%2)^m9B#sG*+q9N<}h$G z_8u9txrAt=uTCv4#mK_Vppk(ptl9_^v`SDT{+0o{n8fJfXEqqQYHr&v%AI>Okm2}T zMR##;G4J3kEdQlh6?_`NLl6fC=~tU(zcVKX>t*;r99Gav`CA?zF>q8(m-`t$fIapz zMgC$0q*P}Po&~x&y-JbW?(?vhHv2qD{&^)K;t}PJEbsqX2D^`tUlI_&?;?&;BRTjy zv;zD$^C-H|>pXngF^548vu_u^y<-16O z>9<*+kvo`;X$W4&@Zk3GLPYlU3_zxe)7xJ<)=rYG9B;W3Q6J}imkjF{K5j>qIaePkK9h zTJkze{CFv#sfN{MV6p)@jb5n%QWzc~z%LSpV1lnr!N`$pJk&0B@0eVy{(%|s^21CF z(v=YsnK1fmHlXr@Y)D(3bW(#X>ZfQWDZ|G03OSdWR@or6yBk1;pz0;_R1JTICu{B~n z*{aNl^GJhZA<8aRx4UoOmJQ2%33eP~rEFIR$J|l>EBWV!m+`QDnce($mLA29{qMi+ z+#i_5cBD6GCJeIH&-b{hF(YirR|KCBqD}IpF@Vc9+Wgk5D+LZ$QJwqJ_xVp#OL9GE z4N?-Iem0;c)z5zn$t>0XO^FDM97;Z)QG0HSt`h|=3YTkQihFZRM$7vjb0TKvy@O|G zNEl=+7(8-PE*T5$9I8B;Uw7WQDqEQu;S59%^1Uy$=k3~okWP`jJujs0;YBa_tckF8 zkW&asB9q6}@1p8fs}^FtTA4#iC-1FhJ_fhl6R9}YTo|fv33-WXnSJ>sA1{JHz3^=d zcFexD;p}=72G&dPwbaPJyy8s!xNu29oe;k%FQRB~Gg$WFQ~`~>TIx{ACt8b*75=H%MJii7%%;g(XjZ&N!triTzZz) zBDCG)R_hX=Z;RBWpB4BD7;PX)wW}mZi}5Q3!58g3nf(tHESbph?C?qHTr_7U9 z=@8e@&pUaw?9#0B@a`My%f6uFf$RRFgwRjN*>sK*sKdVHkeYmwAtI;*$}Hy}a;tI@ z_e+(Oa^BmVfas2sKERoJy{)|5fhXmbTfaaIG=JkJNKGoD)kNZN_x{5dfWDS@MHG~I zR(MJVe(NV8P6Cqzx_6W%p_7yY?u2#qKK>I-m$lFHV-IPFrN~;~k8^4tE1L5f1l7M= z>)Fp)-s1~!c(={#>#ZDvJkCub+uY|^|SJ6odU z`f$~{w`z^MKQ>ccH)h+u#Btt~`}upV=&`fsKno!ARnr*g0@&J_nHfIAAwEkT zq4KHRGk;!>h~7*oAB~)YaZFzE#giES znQTN}BvessLK`u<3c@;}9-~{CnF4_Y{D9*(yC0 z2Xd%(5FlOQNpnQ>r%uRWJyaoa;fez|J&CeY-~C3ofF@?5Qsok{z8ADrUH zm^)ps5|2MnB%Hu!-+3uZ$$qa_ythPio4l0sj?%7Lsi}9nwK{?^6*7Lxi(^GT>)eO% z%Qh2P&pw9-ofmtRR%z2exbpg$N7v(vdY{nD4_D5dzqHB08Y*5ynwJx*7ukG}*>?)@ zuQ$HERg(W;X5<84xX3v8)X$ns`>P=HS&>JaX`0pOxvNm@`Zh@B{&kV-D|2f%DMl}a zr|o*f4&poq857BkoZKm^%Xe=DLJ`fp#_0d2!KJ}2Y&riB-45YK0hD%um=J@r%u>dRvq_F_#dFY BphExv diff --git a/modular_skyrat/modules/aesthetics/tools/tools_lefthand.dmi b/modular_skyrat/modules/aesthetics/tools/tools_lefthand.dmi index bc1a97aa3e2d5e248f7cda574a3b62f97c7303da..256b736f8cca663f53761abbb05ed60d5d7e17a1 100644 GIT binary patch delta 675 zcmV;U0$ly41)2s>iBL{Q4GJ0x0000DNk~Le0001h0001B2m=5B0OF*IdjJ3cOHfQy zMZmzo3=9kv6%{BbD2`JbU0q}~H$L*X2Hlt{Cn_!`2M7D&Z3JCEkx&~R0JRkq;cPS!ypVrLm+@zT1Y8v|Nl#8O`6m+fZa9QG|lI&3YZf^DshKF5ClOG zgx^3tKV#grs^%=Y`k}SiQ9w_Y95d?sdP+M_8}RU6X$!=d!RwWPoxBUQ^(Q@7?|HQnwYLp{D*!2`>VtTSFcM$u zhopM(lS}pW(V+FQ(iF}~vnz0g<4+IOLJmv$X@C8bHH*o!2h+AgJ1;^yos4$0oW(#!kfq?7JeF1eY zp@eNdz&`}td>{upAHWV&@`212=;s5Okq_itY0{781MIcxNIoD4f*=TjAb$uX#ND(u zgOLyLs{(a9-ju@`^c1E*9HN~V)mD-)*#!0L-m@eNX`xswpmUXd<#)hBD<80Ea3lKPl1%Z& z6@X4YfaQr!HYF4LJGY&Dz$j98ZwcJiNgQ@002ov JPDHLkV1kDmCr1DP delta 559 zcmV+~0?_@M2B!s3iBL{Q4GJ0x0000DNk~Le0001B0001B2m=5B0M$l^3IG5AMNmvs zMZmzo3=9kv6%{BbD2`Jb^0)@wm?||lK3!d8CI<&6DlPoHb|f zyc>2y;wXOzw!chMzP>d)gYjuSf)fXr%Y4lTMAI91b+?GpfH+Tc_T+WC@Ei`ll5@U( zH{GV#_(?WWn4O|1ilQig&F}v98QXe+#2?o6PxVH3?++xd4q$93HLnl${;(uz0{FAD zl?hWvdw)oa&>y%y_wMC?F&HAIy+5QR3NViA59I))L{^vM|SrIq8F|p@`rkB{p}B87imZRK~WS%QT`S0 z{q`HKYW9c50Es`m50S(lDm6;y*aT|+P$lJ8i|cdmez1OF|KA`w*B_1s1>XPw002ovPDHLkV1n79_fr4> diff --git a/modular_skyrat/modules/aesthetics/tools/tools_righthand.dmi b/modular_skyrat/modules/aesthetics/tools/tools_righthand.dmi index d73553446277848c978739369dc8d1fe175de374..3ed4928ee118512e74a4dd8a4922388e00807c10 100644 GIT binary patch delta 668 zcmV;N0%QH51*QfiiBL{Q4GJ0x0000DNk~Le0001h0001B2m=5B0OF*IdjJ3cOOYim zHgA8A|NsB5yT%|iK;-A@aS;)p8yn0cBLKA(6yb4xO_N&~PulV_Y4h8`HFEwp%5$E3k00IC>L_t(&f$f;vb^;*`MTbj- zP(={b{{NSj-qx}MNg3N^ADaCrlan({9?V%5K@bE%5Pl8y&~CbKXXdN>;;rtjG3yf8 z%{%DYDWkXbcfK=#V3c#4WNr-@x6Btq@NNg|U$uX+Po5L8i~;Q}0`tJifO7$`Z{Qv0 zKr!a5YsKEpI`B5^!$4)<99U|cP;oPYd+V)#nw&-J4*mPTsvN8{YIwB7c+{K&IJ6s3 z-DD94Y&QTODy{!9rlEn9kF2_NPHDpZnlQNkca+9>io>HEGp}wH>3$P=+`k>*1VIo4VTS*e50pR72TDB;^MO(}$=n(+WtlIAaIT|#p#98=FlS2FfIx11 zoq<|M`9P?JbD%1%7)mRyW!AyD4D*4oZw|t}`9P?lo+oFqR4N|`<^Fu2-N0-766P|6?Y13~hEMe+eb5ClOG1mTCw{iT2ZEp*?GSXM^##arDYcFQUD`|`YjUXCSV zhFxc%nSu?s@U?gcahcx<0As@bEn-fQ+kTh^h$$m{yE=W6+NRmJ!VB*}ooL1UTFTr1 z@_5RZ!8d~|=7iK&K=S16^wLDrX>t-$ybi^3d~VY;?i1sYbpY3P1GBUEOx;!cj>t6R z1FSmdehre}N+B@$0I$xt-^35{0owh;kbFS+kGudM&J>1+&Z(6E0000g zF#rGmZ-0-kyT;__>L4^gaS;)p8yn0cBf!AGPUQT`kE$1Q55A*VNR`P+j8zqJ2>~a#eWC}ise-YL{SoZ^pKpv!`7<-eGQ52cD^vfj z=j~@9*cC-l6h(PQj%SHZeh>wFjnw7`S-3MlP}zC{zPYaXfhHQR?{O<_ewYlOe?W{a zm^|B&HiA+*`5_rTV + +https://github.com/Skyrat-SS13/Skyrat-tg/pull/24162 + +## Science tools + +Module ID: SCIENCE_TOOLS + +### Description: Lets sci print watered down engi tools, and robotics, medical tools. + + + +### TG Proc/File Changes: + +- N/A + + +### Modular Overrides: + +- N/A + + +### Defines: + +- 2 defines in research.dm + + +### Included files that are not contained in this module: + +- ~skyrat_defines/research.dm + + +### Credits: + +- Niko: Author + + diff --git a/modular_skyrat/modules/science_tools/research.dm b/modular_skyrat/modules/science_tools/research.dm new file mode 100644 index 00000000000..4992a07e302 --- /dev/null +++ b/modular_skyrat/modules/science_tools/research.dm @@ -0,0 +1,9 @@ +/datum/techweb_node/exp_tools/New() + . = ..() + // if this datum is ever instantiated twice, somehow, this is more efficient. i feel like an idiot writing this + var/static/list/science_tools = list( + SCIENCE_JAWS_OF_LIFE_DESIGN_ID, + SCIENCE_DRILL_DESIGN_ID, + ) + design_ids += science_tools + diff --git a/modular_skyrat/modules/science_tools/tool_designs.dm b/modular_skyrat/modules/science_tools/tool_designs.dm new file mode 100644 index 00000000000..3180d714480 --- /dev/null +++ b/modular_skyrat/modules/science_tools/tool_designs.dm @@ -0,0 +1,65 @@ +/datum/design/jawsoflife/science + name = "Hybrid cutters" + desc = "An off-shoot of the jaws of life that lacks the door-opening power" + id = SCIENCE_JAWS_OF_LIFE_DESIGN_ID // added one more requirement since the Jaws of Life are a bit OP + build_path = /obj/item/crowbar/power/science + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + +/datum/design/handdrill/science + id = SCIENCE_DRILL_DESIGN_ID + build_type = PROTOLATHE | AWAY_LATHE + build_path = /obj/item/screwdriver/power/science + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + +/datum/design/handdrill/science/New() + name = ("Science " + name) + desc += " with a science paintjob" + + return ..() + +/datum/design/laserscalpel + construction_time = 1 SECONDS + +/datum/design/mechanicalpinches + construction_time = 1 SECONDS + +/datum/design/searingtool + construction_time = 1 SECONDS + +/datum/design/healthanalyzer + construction_time = 5 SECONDS + +/datum/design/healthanalyzer_advanced + construction_time = 5 SECONDS + +/datum/design/laserscalpel/New() + build_type |= MECHFAB + category += list(RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MEDICAL) + + return ..() + +/datum/design/mechanicalpinches/New() + build_type |= MECHFAB + category += list(RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MEDICAL) + + return ..() + +/datum/design/searingtool/New() + build_type |= MECHFAB + category += list(RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MEDICAL) + + return ..() + +// it's fine to give them health analyzers, the choke for medibot production is the medkits +/datum/design/healthanalyzer/New() + build_type |= MECHFAB + category += list(RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MEDICAL) + + return ..() + + +/datum/design/healthanalyzer_advanced/New() + build_type |= MECHFAB + category += list(RND_CATEGORY_MECHFAB_EQUIPMENT + RND_SUBCATEGORY_MECHFAB_EQUIPMENT_MEDICAL) + + return ..() diff --git a/modular_skyrat/modules/science_tools/tools.dm b/modular_skyrat/modules/science_tools/tools.dm new file mode 100644 index 00000000000..b9c836587df --- /dev/null +++ b/modular_skyrat/modules/science_tools/tools.dm @@ -0,0 +1,14 @@ +/obj/item/crowbar/power/science + name = "hybrid cutters" // hybrid between crowbar and wirecutters + desc = "Quite similar to the jaws of life, this tool combines the utility of a crowbar and a set of wirecutters without the hydraulic force required to pry open doors." + icon_state = "jaws_sci" + inhand_icon_state = "jaws_sci" + force_opens = FALSE + +/obj/item/screwdriver/power/science + icon_state = "drill_sci" + +/obj/item/screwdriver/power/science/Initialize(mapload) + . = ..() + + desc += " This one sports a nifty science paintjob, but is otherwise normal." diff --git a/tgstation.dme b/tgstation.dme index c842560f249..1b0af6fb155 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -427,6 +427,7 @@ #include "code\__DEFINES\~skyrat_defines\preferences.dm" #include "code\__DEFINES\~skyrat_defines\projectiles.dm" #include "code\__DEFINES\~skyrat_defines\reagents.dm" +#include "code\__DEFINES\~skyrat_defines\research.dm" #include "code\__DEFINES\~skyrat_defines\research_categories.dm" #include "code\__DEFINES\~skyrat_defines\reskin_defines.dm" #include "code\__DEFINES\~skyrat_defines\robot_defines.dm" @@ -7593,6 +7594,9 @@ #include "modular_skyrat\modules\salon\code\scissors.dm" #include "modular_skyrat\modules\salon\code\sprays.dm" #include "modular_skyrat\modules\salon\code\straight_razor.dm" +#include "modular_skyrat\modules\science_tools\research.dm" +#include "modular_skyrat\modules\science_tools\tool_designs.dm" +#include "modular_skyrat\modules\science_tools\tools.dm" #include "modular_skyrat\modules\sec_haul\code\corrections_officer\corrections_officer.dm" #include "modular_skyrat\modules\sec_haul\code\corrections_officer\corrections_officer_equipment.dm" #include "modular_skyrat\modules\sec_haul\code\corrections_officer\landmarks.dm" From ce7541f7a4954db22d8af3b1f5912673663cb396 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:55:30 +0200 Subject: [PATCH 020/100] makes unholy water an effective coagulant for cultists [MDB IGNORE] (#24241) * makes unholy water an effective coagulant for cultists (#78862) ## About The Pull Request Atomizes https://github.com/tgstation/tgstation/pull/78411 Makes unholy water act as a coagulant for cultists, and reduce bleed rate on bleed wounds. ## Why It's Good For The Game As I explained in the other PR, cult has a distinct lack of solutions for wounds. Given cultists are meant to be masters of blood, it only stands to reason they should be able to stop it spilling out of themselves. ## Changelog :cl: balance: Unholy water acts as a coagulant for cultists. /:cl: --------- Co-authored-by: Emmett Gaines * makes unholy water an effective coagulant for cultists --------- Co-authored-by: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Co-authored-by: Emmett Gaines --- .../chemistry/reagents/other_reagents.dm | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 5a26d37e9ed..be5df37ffdb 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -486,6 +486,11 @@ ph = 6.5 chemical_flags = REAGENT_CAN_BE_SYNTHESIZED +/datum/reagent/fuel/unholywater/on_mob_metabolize(mob/living/affected_mob) + . = ..() + if(IS_CULTIST(affected_mob)) + ADD_TRAIT(affected_mob, TRAIT_COAGULATING, type) + /datum/reagent/fuel/unholywater/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() var/need_mob_update = FALSE @@ -500,6 +505,16 @@ need_mob_update = TRUE if(ishuman(affected_mob) && affected_mob.blood_volume < BLOOD_VOLUME_NORMAL) affected_mob.blood_volume += 3 * REM * seconds_per_tick + + var/datum/wound/bloodiest_wound + + for(var/datum/wound/iter_wound as anything in affected_mob.all_wounds) + if(iter_wound.blood_flow && iter_wound.blood_flow > bloodiest_wound?.blood_flow) + bloodiest_wound = iter_wound + + if(bloodiest_wound) + bloodiest_wound.adjust_blood_flow(-2 * REM * seconds_per_tick) + else // Will deal about 90 damage when 50 units are thrown need_mob_update += affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3 * REM * seconds_per_tick, 150) need_mob_update += affected_mob.adjustToxLoss(1 * REM * seconds_per_tick, updating_health = FALSE) @@ -509,6 +524,10 @@ if(need_mob_update) return UPDATE_MOB_HEALTH +/datum/reagent/fuel/unholywater/on_mob_end_metabolize(mob/living/affected_mob) + . = ..() + REMOVE_TRAIT(affected_mob, TRAIT_COAGULATING, type) //We don't cult check here because potentially our imbiber may no longer be a cultist for whatever reason! It doesn't purge holy water, after all! + /datum/reagent/hellwater //if someone has this in their system they've really pissed off an eldrich god name = "Hell Water" description = "YOUR FLESH! IT BURNS!" From 68d41fc2e8feb4ffc70bc27b577bd4f0f0bffd43 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:55:41 +0200 Subject: [PATCH 021/100] fixes polymorphing into a holoparasite [MDB IGNORE] (#24242) * fixes polymorphing into a holoparasite (#78889) makes holoparasites `MOB_SPECIAL` and gives them `SENTIENCE_HUMANOID` only one is needed for the belt to fail copying it but uhhh i don't think it should just be left hanging with no biotype at all thats just weird fixes #78578 ## Changelog :cl: fix: you can no longer polymorph belt into a holoparasite /:cl: * fixes polymorphing into a holoparasite --------- Co-authored-by: Sealed101 --- code/modules/mob/living/simple_animal/guardian/guardian.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index ea5e0685b53..919d54ac736 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -6,7 +6,8 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians desc = "A mysterious being that stands by its charge, ever vigilant." speak_emote = list("hisses") gender = NEUTER - mob_biotypes = NONE + mob_biotypes = MOB_SPECIAL + sentience_type = SENTIENCE_HUMANOID bubble_icon = "guardian" response_help_continuous = "passes through" response_help_simple = "pass through" From 0452d212a3cd4a1c82844c1814faf51feaef53be Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:59:20 +0200 Subject: [PATCH 022/100] Fixes a few runtimes with TTS and skips some code if TTS isn't enabled. [MDB IGNORE] (#24240) * Fixes a few runtimes with TTS and skips some code if TTS isn't enabled. (#78713) ## About The Pull Request Fixes a few runtimes with TTS and skips some code if TTS isn't enabled. ## Why It's Good For The Game fixes...good??? ## Changelog :cl: fix: Fixes a few runtimes with TTS and skips some code if TTS isn't enabled. /:cl: --------- Co-authored-by: Ghom <42542238+Ghommie@ users.noreply.github.com> * Fixes a few runtimes with TTS and skips some code if TTS isn't enabled. --------- Co-authored-by: Iamgoofball Co-authored-by: Ghom <42542238+Ghommie@ users.noreply.github.com> --- code/modules/mob/living/living_say.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm index 18d35782d73..52daa3c2f0a 100644 --- a/code/modules/mob/living/living_say.dm +++ b/code/modules/mob/living/living_say.dm @@ -387,8 +387,7 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list( if(!M.client.prefs.read_preference(/datum/preference/toggle/enable_runechat) || (SSlag_switch.measures[DISABLE_RUNECHAT] && !HAS_TRAIT(src, TRAIT_BYPASS_MEASURES))) speech_bubble_recipients.Add(M.client) found_client = TRUE - - if(voice && found_client && !message_mods[MODE_CUSTOM_SAY_ERASE_INPUT] && !HAS_TRAIT(src, TRAIT_SIGN_LANG) && !HAS_TRAIT(src, TRAIT_UNKNOWN)) + if(SStts.tts_enabled && voice && found_client && !message_mods[MODE_CUSTOM_SAY_ERASE_INPUT] && !HAS_TRAIT(src, TRAIT_SIGN_LANG) && !HAS_TRAIT(src, TRAIT_UNKNOWN)) var/tts_message_to_use = tts_message if(!tts_message_to_use) tts_message_to_use = message_raw From 14a3f0e2f336fbefdb31b380a1df5b26cee32ff3 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 20:04:27 +0200 Subject: [PATCH 023/100] count station food verb counts station food [MDB IGNORE] (#24235) * count station food verb counts station food (#78864) ## About The Pull Request it checked for food not on the station ## Why It's Good For The Game bug bad ## Changelog :cl: fix: count station food verb now counts food only onstation /:cl: * count station food verb counts station food --------- Co-authored-by: jimmyl <70376633+mc-oofert@users.noreply.github.com> --- code/modules/admin/verbs/mapping.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 64d2d5831a6..5f61a508b36 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -422,7 +422,7 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) var/list/foodcount = list() for(var/obj/item/food/fuck_me in world) var/turf/location = get_turf(fuck_me) - if(!location || SSmapping.level_trait(location.z, ZTRAIT_STATION)) + if(!location || !SSmapping.level_trait(location.z, ZTRAIT_STATION)) continue LAZYADDASSOC(foodcount, fuck_me.type, 1) @@ -445,7 +445,7 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) var/list/stackcount = list() for(var/obj/item/stack/fuck_me in world) var/turf/location = get_turf(fuck_me) - if(!location || SSmapping.level_trait(location.z, ZTRAIT_STATION)) + if(!location || !SSmapping.level_trait(location.z, ZTRAIT_STATION)) continue LAZYADDASSOC(stackcount, fuck_me.type, fuck_me.amount) From 2a00c6df60b74b7c89c4ff1eb39360663595d83c Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 20:04:54 +0200 Subject: [PATCH 024/100] Add burning sound loop to bonfires and fireplaces [MDB IGNORE] (#24250) * Add burning sound loop to bonfires and fireplaces (#78834) ## About The Pull Request This adds a ignition sound whenever a fireplace or bonfire is initially lit on fire. Afterwards a continuous burning loop is played. Also added some documentation and optimized fireplaces to only `process()` when lit. ## Why It's Good For The Game Better consistency. ## Changelog :cl: sound: Add burning sound loop to bonfires and fireplaces code: Improved fireplaces to only process when lit /:cl: --------- Co-authored-by: Ghom <42542238+Ghommie@ users.noreply.github.com> * Add burning sound loop to bonfires and fireplaces --------- Co-authored-by: Tim Co-authored-by: Ghom <42542238+Ghommie@ users.noreply.github.com> --- code/datums/looping_sounds/burning.dm | 9 +++++++ code/game/objects/structures/bonfire.dm | 33 +++++++++++++++-------- code/game/objects/structures/fireplace.dm | 14 +++++++--- tgstation.dme | 1 + 4 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 code/datums/looping_sounds/burning.dm diff --git a/code/datums/looping_sounds/burning.dm b/code/datums/looping_sounds/burning.dm new file mode 100644 index 00000000000..191ae88db89 --- /dev/null +++ b/code/datums/looping_sounds/burning.dm @@ -0,0 +1,9 @@ +/// Soundloop for the fire (bonfires, fireplaces, etc.) +/datum/looping_sound/burning + start_sound = 'sound/items/match_strike.ogg' + start_length = 3 SECONDS + mid_sounds = 'sound/effects/comfyfire.ogg' + mid_length = 5 SECONDS + volume = 50 + vary = TRUE + extra_range = MEDIUM_RANGE_SOUND_EXTRARANGE diff --git a/code/game/objects/structures/bonfire.dm b/code/game/objects/structures/bonfire.dm index 3ca135a5786..a6cbbf8b009 100644 --- a/code/game/objects/structures/bonfire.dm +++ b/code/game/objects/structures/bonfire.dm @@ -17,19 +17,14 @@ anchored = TRUE buckle_lying = 0 pass_flags_self = PASSTABLE | LETPASSTHROW - ///is the bonfire lit? + /// is the bonfire lit? var/burning = FALSE - ///icon for the bonfire while on. for a softer more burning embers icon, use "bonfire_warm" + /// icon for the bonfire while on. for a softer more burning embers icon, use "bonfire_warm" var/burn_icon = "bonfire_on_fire" - ///if the bonfire has a grill attached + /// if the bonfire has a grill attached var/grill = FALSE - -/obj/structure/bonfire/dense - density = TRUE - -/obj/structure/bonfire/prelit/Initialize(mapload) - . = ..() - start_burning() + /// the looping sound effect that is played while burning + var/datum/looping_sound/burning/burning_loop /obj/structure/bonfire/Initialize(mapload) . = ..() @@ -37,6 +32,12 @@ COMSIG_ATOM_ENTERED = PROC_REF(on_entered), ) AddElement(/datum/element/connect_loc, loc_connections) + burning_loop = new(src) + +/obj/structure/bonfire/Destroy() + STOP_PROCESSING(SSobj, src) + QDEL_NULL(burning_loop) + . = ..() /obj/structure/bonfire/attackby(obj/item/used_item, mob/living/user, params) if(istype(used_item, /obj/item/stack/rods) && !can_buckle && !grill) @@ -77,7 +78,6 @@ else return ..() - /obj/structure/bonfire/attack_hand(mob/user, list/modifiers) . = ..() if(.) @@ -107,6 +107,8 @@ /obj/structure/bonfire/proc/start_burning() if(burning || !check_oxygen()) return + + burning_loop.start() icon_state = burn_icon burning = TRUE set_light(6) @@ -169,6 +171,8 @@ . = ..() if(!burning) return + + burning_loop.stop() icon_state = "bonfire" burning = FALSE set_light(0) @@ -183,4 +187,11 @@ if(..()) buckled_mob.pixel_y -= 13 +/obj/structure/bonfire/dense + density = TRUE + +/obj/structure/bonfire/prelit/Initialize(mapload) + . = ..() + start_burning() + #undef BONFIRE_FIRE_STACK_STRENGTH diff --git a/code/game/objects/structures/fireplace.dm b/code/game/objects/structures/fireplace.dm index afd4d27efe6..8c9d09585c9 100644 --- a/code/game/objects/structures/fireplace.dm +++ b/code/game/objects/structures/fireplace.dm @@ -14,17 +14,22 @@ light_color = LIGHT_COLOR_FIRE light_angle = 170 light_flags = LIGHT_IGNORE_OFFSET + /// is the fireplace lit? var/lit = FALSE - + /// the amount of fuel for the fire var/fuel_added = 0 + /// how much time is left before fire runs out of fuel var/flame_expiry_timer + /// the looping sound effect that is played while burning + var/datum/looping_sound/burning/burning_loop /obj/structure/fireplace/Initialize(mapload) . = ..() - START_PROCESSING(SSobj, src) + burning_loop = new(src) /obj/structure/fireplace/Destroy() STOP_PROCESSING(SSobj, src) + QDEL_NULL(burning_loop) . = ..() /obj/structure/fireplace/setDir(newdir) @@ -126,7 +131,6 @@ put_out() return - playsound(src, 'sound/effects/comfyfire.ogg',50,FALSE, FALSE, TRUE) var/turf/T = get_turf(src) T.hotspot_expose(700, 2.5 * seconds_per_tick) update_appearance() @@ -155,6 +159,8 @@ return max(0, fuel_added) /obj/structure/fireplace/proc/ignite() + START_PROCESSING(SSobj, src) + burning_loop.start() lit = TRUE desc = "A large stone brick fireplace, warm and cozy." flame_expiry_timer = world.time + fuel_added @@ -163,6 +169,8 @@ adjust_light() /obj/structure/fireplace/proc/put_out() + STOP_PROCESSING(SSobj, src) + burning_loop.stop() lit = FALSE update_appearance() adjust_light() diff --git a/tgstation.dme b/tgstation.dme index 1b0af6fb155..5b79d8a36a0 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1535,6 +1535,7 @@ #include "code\datums\keybinding\robot.dm" #include "code\datums\looping_sounds\_looping_sound.dm" #include "code\datums\looping_sounds\acid.dm" +#include "code\datums\looping_sounds\burning.dm" #include "code\datums\looping_sounds\choking.dm" #include "code\datums\looping_sounds\cyborg.dm" #include "code\datums\looping_sounds\item_sounds.dm" From 69d943be95fe353d9aee464e8d71fb1e046973f5 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 20:05:09 +0200 Subject: [PATCH 025/100] Fixes an issue w/ antiglow. [MDB IGNORE] (#24244) * Fixes an issue w/ antiglow. (#78865) ## About The Pull Request Antiglow's ``glow`` var used to be how strong it would glow, but it was renamed to ``glow_power`` when ``/obj/effect/dummy/lighting_obj/moblight`` got added to it, which took its previous name of ``glow``. Antiglow was never updated for this, so they set the moblight as -1.5, which is supposed to be its strength. I also removed some unused defines dw about that ## Why It's Good For The Game Fixes an unintentional change that maybe breaks something idk. ## Changelog :cl: fix: Antiglow now probably has negative glow power. /:cl: * Fixes an issue w/ antiglow. --------- Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> --- .../dcs/signals/signals_atom/signals_atom_movable.dm | 8 -------- code/datums/mutations/body.dm | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm index 5e6d7491d94..d26dd4e8c86 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm @@ -66,14 +66,6 @@ #define COMSIG_MOVABLE_SET_ANCHORED "movable_set_anchored" ///from base of atom/movable/setGrabState(): (newstate) #define COMSIG_MOVABLE_SET_GRAB_STATE "living_set_grab_state" -///Called when the movable tries to change its dynamic light color setting, from base atom/movable/lighting_overlay_set_color(): (color) -#define COMSIG_MOVABLE_LIGHT_OVERLAY_SET_RANGE "movable_light_overlay_set_color" -///Called when the movable tries to change its dynamic light power setting, from base atom/movable/lighting_overlay_set_power(): (power) -#define COMSIG_MOVABLE_LIGHT_OVERLAY_SET_POWER "movable_light_overlay_set_power" -///Called when the movable tries to change its dynamic light range setting, from base atom/movable/lighting_overlay_set_range(): (range) -#define COMSIG_MOVABLE_LIGHT_OVERLAY_SET_COLOR "movable_light_overlay_set_range" -///Called when the movable tries to toggle its dynamic light LIGHTING_ON status, from base atom/movable/lighting_overlay_toggle_on(): (new_state) -#define COMSIG_MOVABLE_LIGHT_OVERLAY_TOGGLE_ON "movable_light_overlay_toggle_on" ///called when the movable's glide size is updated: (new_glide_size) #define COMSIG_MOVABLE_UPDATE_GLIDE_SIZE "movable_glide_size" ///Called when a movable is hit by a plunger in layer mode, from /obj/item/plunger/attack_atom() diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 332b2695e40..24aa41321f3 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -266,9 +266,9 @@ name = "Anti-Glow" desc = "Your skin seems to attract and absorb nearby light creating 'darkness' around you." text_gain_indication = "The light around you seems to disappear." - glow = -1.5 conflicts = list(/datum/mutation/human/glow) locked = TRUE + glow_power = -1.5 /datum/mutation/human/glow/anti/get_glow_color() return COLOR_BLACK From 0337ebe2832b30193afc9c5df3d7ccb55c57c9a1 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 20:05:15 +0200 Subject: [PATCH 026/100] Borg modules can no longer be sold by pirates [MDB IGNORE] (#24243) * Borg modules can no longer be sold by pirates (#78873) ## About The Pull Request The pirate cargo pad and console worked by recursively getting all the contents of all atoms located on the pad. Incidentally, this resulted in borg modules and radios being sold if the borg happened to be on the pad. This PR just makes the pads ignore cyborgs and anything located in a cyborg (or in a thing in a cyborg, and so on). Fixes #47941. ## Why It's Good For The Game Borg modules probably shouldn't be sold, since they need a module reset to replace. Borg radios _definitely_ shouldn't be sold, as IIRC not even a reset will replace them. ## Changelog :cl: fix: Borg modules can no longer be sold by pirates. /:cl: * Borg modules can no longer be sold by pirates --------- Co-authored-by: GPeckman <21979502+GPeckman@users.noreply.github.com> --- .../antagonists/pirate/pirate_shuttle_equipment.dm | 8 ++++++-- code/modules/cargo/exports.dm | 5 +++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm index 57eb95a978c..3ea6488b2d4 100644 --- a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm +++ b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm @@ -217,9 +217,13 @@ var/cargo_hold_id ///Interface name for the ui_interact call for different subtypes. var/interface_type = "CargoHoldTerminal" + ///Typecache of things that shouldn't be sold and shouldn't have their contents sold. + var/static/list/nosell_typecache /obj/machinery/computer/piratepad_control/Initialize(mapload) ..() + if(isnull(nosell_typecache)) + nosell_typecache = typecacheof(/mob/living/silicon/robot) return INITIALIZE_HINT_LATELOAD /obj/machinery/computer/piratepad_control/multitool_act(mob/living/user, obj/item/multitool/I) @@ -285,7 +289,7 @@ for(var/atom/movable/AM in get_turf(pad)) if(AM == pad) continue - export_item_and_contents(AM, apply_elastic = FALSE, dry_run = TRUE, external_report = report) + export_item_and_contents(AM, apply_elastic = FALSE, dry_run = TRUE, external_report = report, ignore_typecache = nosell_typecache) for(var/datum/export/exported_datum in report.total_amount) status_report += exported_datum.total_printout(report,notes = FALSE) @@ -306,7 +310,7 @@ for(var/atom/movable/item_on_pad in get_turf(pad)) if(item_on_pad == pad) continue - export_item_and_contents(item_on_pad, apply_elastic = FALSE, delete_unsold = FALSE, external_report = report) + export_item_and_contents(item_on_pad, apply_elastic = FALSE, delete_unsold = FALSE, external_report = report, ignore_typecache = nosell_typecache) status_report = "Sold: " var/value = 0 diff --git a/code/modules/cargo/exports.dm b/code/modules/cargo/exports.dm index a9d408c8699..44a628740bd 100644 --- a/code/modules/cargo/exports.dm +++ b/code/modules/cargo/exports.dm @@ -35,12 +35,13 @@ Then the player gets the profit from selling his own wasted time. ** delete_unsold: if the items that were not sold should be deleted ** dry_run: if the item should be actually sold, or if its just a pirce test ** external_report: works as "transaction" object, pass same one in if you're doing more than one export in single go + ** ignore_typecache: typecache containing types that should be completely ignored */ -/proc/export_item_and_contents(atom/movable/exported_atom, apply_elastic = TRUE, delete_unsold = TRUE, dry_run = FALSE, datum/export_report/external_report) +/proc/export_item_and_contents(atom/movable/exported_atom, apply_elastic = TRUE, delete_unsold = TRUE, dry_run = FALSE, datum/export_report/external_report, list/ignore_typecache) if(!GLOB.exports_list.len) setupExports() - var/list/contents = exported_atom.get_all_contents() + var/list/contents = exported_atom.get_all_contents_ignoring(ignore_typecache) var/datum/export_report/report = external_report From f1fd498934aefa4b44cb0adb2f4b0898e6e7ed48 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 23:03:58 +0200 Subject: [PATCH 027/100] Fixes sanitizing chemicals (Miner's Salve, Sterilizine, and Space Cleaner) not sanitizing burn wounds [MDB IGNORE] (#24246) * Fixes sanitizing chemicals (Miner's Salve, Sterilizine, and Space Cleaner) not sanitizing burn wounds (#78851) ## About The Pull Request This proc didn't pass itself to the reagents to actually do anything. ## Changelog :cl: Melbert fix: Miner's Salve, Sterilizine, and Space Cleaner now all properly affect burn wounds /:cl: * Fixes sanitizing chemicals (Miner's Salve, Sterilizine, and Space Cleaner) not sanitizing burn wounds --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/datums/wounds/burns.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm index a97706c8e16..39e91d06fb6 100644 --- a/code/datums/wounds/burns.dm +++ b/code/datums/wounds/burns.dm @@ -48,7 +48,7 @@ for(var/datum/reagent/reagent as anything in victim.reagents.reagent_list) if(reagent.chemical_flags & REAGENT_AFFECTS_WOUNDS) - reagent.on_burn_wound_processing() + reagent.on_burn_wound_processing(src) if(HAS_TRAIT(victim, TRAIT_VIRUS_RESISTANCE)) sanitization += 0.9 From 10c027fb7d43191063b0c3d70ac94351c4b7d40b Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 23:04:56 +0200 Subject: [PATCH 028/100] Disable summon AI during summoning [MDB IGNORE] (#24254) * [no gbp] Disable summon AI during summoning (#78891) ## About The Pull Request Disables AI on heretic minions while they are being summoned, because they're not supposed to exist yet. This fixes a bug where flesh stalkers would immediately transform into mice and run away. ## Changelog :cl: fix: Heretic mobs will not be summoned with AI enabled, and won't turn into small animals instead of summoning a flesh stalker. /:cl: * [no gbp] Disable summon AI during summoning --------- Co-authored-by: Jacquerel --- code/modules/antagonists/heretic/heretic_knowledge.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/antagonists/heretic/heretic_knowledge.dm b/code/modules/antagonists/heretic/heretic_knowledge.dm index 260f56540d0..1f408698f3c 100644 --- a/code/modules/antagonists/heretic/heretic_knowledge.dm +++ b/code/modules/antagonists/heretic/heretic_knowledge.dm @@ -530,6 +530,7 @@ /datum/heretic_knowledge/summon/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) var/mob/living/summoned = new mob_to_summon(loc) + summoned.ai_controller?.set_ai_status(AI_STATUS_OFF) // Fade in the summon while the ghost poll is ongoing. // Also don't let them mess with the summon while waiting summoned.alpha = 0 From f2a2207052d152ca21dd5009306f327e77137140 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 23:05:34 +0200 Subject: [PATCH 029/100] Camera UI fixes [MDB IGNORE] (#24245) * Camera UI fixes (#78855) ## About The Pull Request Small nits that bothered me about the screen. - you can now press "next" or "previous" while at the end/beginning of the list, respectively - pressing next is now limited to your search results (rather than switching to the next overall) - reduced some checks for cases that will likely never occur (no ref??) ## Why It's Good For The Game UI bug fixes ## Changelog jlsnow301, Syncit21 :cl: fix: Fixed some issues in the security camera UI - pressing next or back will now loop through the cameras fix: Fixed some style issues in the camera console where selected cams weren't showing as selected fix: Camera console search works again /:cl: * Camera UI fixes --------- Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com> --- .../tgui/interfaces/CameraConsole.tsx | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/tgui/packages/tgui/interfaces/CameraConsole.tsx b/tgui/packages/tgui/interfaces/CameraConsole.tsx index efc418dd7b9..390c220681c 100644 --- a/tgui/packages/tgui/interfaces/CameraConsole.tsx +++ b/tgui/packages/tgui/interfaces/CameraConsole.tsx @@ -7,10 +7,10 @@ import { Button, ByondUi, Input, NoticeBox, Section, Stack } from '../components import { Window } from '../layouts'; type Data = { + activeCamera: Camera & { status: BooleanLike }; + cameras: Camera[]; can_spy: BooleanLike; mapRef: string; - cameras: Camera[]; - activeCamera: Camera & { status: BooleanLike }; network: string[]; }; @@ -30,8 +30,17 @@ const prevNextCamera = ( if (!activeCamera) { return []; } - const index = cameras.findIndex((camera) => camera?.ref === activeCamera.ref); - return [cameras[index - 1]?.ref, cameras[index + 1]?.ref]; + const index = cameras.findIndex((camera) => camera.ref === activeCamera.ref); + + if (index === 0) { + return [cameras[cameras.length - 1].ref, cameras[index + 1].ref]; + } + + if (index === cameras.length - 1) { + return [cameras[index - 1].ref, cameras[0].ref]; + } + + return [cameras[index - 1].ref, cameras[index + 1].ref]; }; /** @@ -40,11 +49,10 @@ const prevNextCamera = ( * Filters cameras, applies search terms and sorts the alphabetically. */ const selectCameras = (cameras: Camera[], searchText = ''): Camera[] => { - const testSearch = createSearch(searchText, (camera: Camera) => camera.ref); + const testSearch = createSearch(searchText, (camera: Camera) => camera.name); return flow([ - // Null camera filter - filter((camera: Camera) => !!camera?.ref), + filter((camera: Camera) => !!camera.name), // Optional search term searchText && filter(testSearch), // Slightly expensive, but way better than sorting in BYOND @@ -101,14 +109,13 @@ const CameraSelector = (props, context) => { key={camera.ref} title={camera.name} className={classes([ - 'candystripe', 'Button', 'Button--fluid', 'Button--color--transparent', 'Button--ellipsis', - activeCamera && - camera.ref === activeCamera.ref && - 'Button--selected', + activeCamera?.ref === camera.ref + ? 'Button--selected' + : 'candystripe', ])} onClick={() => act('switch_camera', { @@ -127,7 +134,9 @@ const CameraSelector = (props, context) => { const CameraControls = (props, context) => { const { act, data } = useBackend(context); const { activeCamera, can_spy, mapRef } = data; - const cameras = selectCameras(data.cameras); + const [searchText] = useLocalState(context, 'searchText', ''); + + const cameras = selectCameras(data.cameras, searchText); const [prevCamera, nextCamera] = prevNextCamera(cameras, activeCamera); @@ -137,7 +146,7 @@ const CameraControls = (props, context) => { - {activeCamera?.name ? ( + {activeCamera?.status ? ( {activeCamera.name} ) : ( No input signal From 8df738870f72f6cba7e8d6f89d6304fa1e72a482 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 Oct 2023 23:08:16 +0200 Subject: [PATCH 030/100] ACTUALLY fixes wound replacement removing gauze [MDB IGNORE] (#24247) * [NO GBP] ACTUALLY fixes wound replacement removing gauze (#78833) ## About The Pull Request Title. Turns out I missed this little spot and the bug was still present. ## Why It's Good For The Game Bugs bad????????????????????????????? ## Changelog :cl: fix: Wound promotion and demotion no longer removes gauze from the limb /:cl: * [NO GBP] ACTUALLY fixes wound replacement removing gauze --------- Co-authored-by: nikothedude <59709059+nikothedude@users.noreply.github.com> --- code/datums/wounds/_wounds.dm | 6 +++--- code/datums/wounds/bones.dm | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index fb543aa009e..7d211b9ae29 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -185,7 +185,7 @@ * * attack_direction: For bloodsplatters, if relevant * * wound_source: The source of the wound, such as a weapon. */ -/datum/wound/proc/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null, wound_source = "Unknown") +/datum/wound/proc/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null, wound_source = "Unknown", replacing = FALSE) if (!can_be_applied_to(L, old_wound)) qdel(src) @@ -198,7 +198,7 @@ src.wound_source = wound_source set_victim(L.owner) - set_limb(L) + set_limb(L, replacing) LAZYADD(victim.all_wounds, src) LAZYADD(limb.wounds, src) update_descriptions() @@ -371,7 +371,7 @@ already_scarred = TRUE var/obj/item/bodypart/cached_limb = limb // remove_wound() nulls limb so we have to track it locally remove_wound(replaced=TRUE) - new_wound.apply_wound(cached_limb, old_wound = src, smited = smited, attack_direction = attack_direction, wound_source = wound_source) + new_wound.apply_wound(cached_limb, old_wound = src, smited = smited, attack_direction = attack_direction, wound_source = wound_source, replacing = TRUE) . = new_wound qdel(src) diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index 59e64db1ccf..270d2a23f42 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -384,7 +384,7 @@ threshold_minimum = 115 // doesn't make much sense for "a" bone to stick out of your head -/datum/wound/blunt/bone/critical/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null, wound_source = "Unknown") +/datum/wound/blunt/bone/critical/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null, wound_source = "Unknown", replacing = FALSE) if(L.body_zone == BODY_ZONE_HEAD) occur_text = "splits open, exposing a bare, cracked skull through the flesh and blood" examine_desc = "has an unsettling indent, with bits of skull poking out" From 3c0f92b2d8cccf9c9c96e0dcd83a2adef531cc11 Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Tue, 10 Oct 2023 18:09:38 -0400 Subject: [PATCH 031/100] Adds chests/heads to the augment menu (#24253) * haahah i totally didnt first push this to the wrong branch * hi --- .../preferences/middleware/limbs_and_markings.dm | 8 +++----- .../customization/modules/client/augment/limbs.dm | 11 +++++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/modular_skyrat/master_files/code/modules/client/preferences/middleware/limbs_and_markings.dm b/modular_skyrat/master_files/code/modules/client/preferences/middleware/limbs_and_markings.dm index 09a174b1ff3..2d9e1c2a1e1 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences/middleware/limbs_and_markings.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences/middleware/limbs_and_markings.dm @@ -41,8 +41,8 @@ "r_arm" = TRUE, "l_leg" = TRUE, "r_leg" = TRUE, - "chest" = FALSE, // TODO: figure out why head/chest augs dont render, needed for IPC head on non IPC body - "head" = FALSE, + "chest" = TRUE, + "head" = TRUE, "l_hand" = FALSE, "r_hand" = FALSE, ) @@ -73,9 +73,7 @@ if(!visuals_only) return - // If you ever add chest and head augments, please add the body zones to this list. - // Removing them for now for optimization purposes. - for(var/body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) + for(var/body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_CHEST, BODY_ZONE_HEAD)) if(body_zone in visited_body_zones) continue diff --git a/modular_skyrat/modules/customization/modules/client/augment/limbs.dm b/modular_skyrat/modules/customization/modules/client/augment/limbs.dm index e5f8f4f14e7..8ae5fed1f04 100644 --- a/modular_skyrat/modules/customization/modules/client/augment/limbs.dm +++ b/modular_skyrat/modules/customization/modules/client/augment/limbs.dm @@ -10,15 +10,16 @@ var/obj/item/bodypart/new_limb = path var/body_zone = initial(new_limb.body_zone) var/obj/item/bodypart/old_limb = augmented.get_bodypart(body_zone) + + old_limb.limb_id = initial(new_limb.limb_id) + old_limb.base_limb_id = initial(new_limb.limb_id) + old_limb.is_dimorphic = initial(new_limb.is_dimorphic) + if(uses_robotic_styles && prefs.augment_limb_styles[slot]) var/chosen_style = GLOB.robotic_styles_list[prefs.augment_limb_styles[slot]] - old_limb.limb_id = initial(new_limb.limb_id) - old_limb.base_limb_id = initial(new_limb.limb_id) old_limb.set_icon_static(chosen_style) old_limb.current_style = prefs.augment_limb_styles[slot] else - old_limb.limb_id = initial(new_limb.limb_id) - old_limb.base_limb_id = initial(new_limb.limb_id) old_limb.set_icon_static(initial(new_limb.icon)) old_limb.should_draw_greyscale = FALSE @@ -30,6 +31,8 @@ var/chosen_style = GLOB.robotic_styles_list[prefs.augment_limb_styles[slot]] new_limb.set_icon_static(chosen_style) new_limb.current_style = prefs.augment_limb_styles[slot] + for (var/obj/item/organ/external/external_organ as anything in old_limb.external_organs) + external_organ.transfer_to_limb(new_limb) new_limb.replace_limb(augmented) qdel(old_limb) From be3ce0cf21f0978ed6cb796afe8e1d1e7fe534d3 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 00:11:47 +0200 Subject: [PATCH 032/100] Reviver Implant will actually revive people! [MDB IGNORE] (#24205) * Reviver Implant will actually revive people! (#78377) ## About The Pull Request This PR will make reviver implant able to actually revive people. ## Why It's Good For The Game Reviver implant been a mess for a long time. Only thing it had possible is slightly heal you in crit, doing that very slowly. With this PR reviver implant will actually revive you. - You are not gonna be invincible, loosing a head or getting your organs decayed beyond functional state will make revival impossible. - This process will be slow, and even after revival you will have to wait until you are get out of crit state. - Being revived from dead will add an additional 10 minutes to implant coldown. * Reviver Implant will actually revive people! --------- Co-authored-by: HWSensum <121913313+HWSensum@users.noreply.github.com> --- .../internal/cyberimp/augments_chest.dm | 60 +++++++++++++++---- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm index 86dacdd98ff..24a3afe47f1 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm @@ -52,31 +52,48 @@ slot = ORGAN_SLOT_HEART_AID var/revive_cost = 0 var/reviving = FALSE + /// revival/defibrillation possibility flag that gathered from owner's .can_defib() proc + var/can_defib_owner COOLDOWN_DECLARE(reviver_cooldown) +/obj/item/organ/internal/cyberimp/chest/reviver/on_death(seconds_per_tick, times_fired) + try_heal() // Allowes implant to work even on dead people /obj/item/organ/internal/cyberimp/chest/reviver/on_life(seconds_per_tick, times_fired) + try_heal() + +/obj/item/organ/internal/cyberimp/chest/reviver/proc/try_heal() if(reviving) - switch(owner.stat) - if(UNCONSCIOUS, HARD_CRIT, SOFT_CRIT) - addtimer(CALLBACK(src, PROC_REF(heal)), 3 SECONDS) - else - COOLDOWN_START(src, reviver_cooldown, revive_cost) - reviving = FALSE - to_chat(owner, span_notice("Your reviver implant shuts down and starts recharging. It will be ready again in [DisplayTimeText(revive_cost)].")) + if(owner.stat == CONSCIOUS) + COOLDOWN_START(src, reviver_cooldown, revive_cost) + reviving = FALSE + to_chat(owner, span_notice("Your reviver implant shuts down and starts recharging. It will be ready again in [DisplayTimeText(revive_cost)].")) + else + addtimer(CALLBACK(src, PROC_REF(heal)), 3 SECONDS) return if(!COOLDOWN_FINISHED(src, reviver_cooldown) || HAS_TRAIT(owner, TRAIT_SUICIDED)) return - switch(owner.stat) - if(UNCONSCIOUS, HARD_CRIT) - revive_cost = 0 - reviving = TRUE - to_chat(owner, span_notice("You feel a faint buzzing as your reviver implant starts patching your wounds...")) + if(owner.stat != CONSCIOUS) + revive_cost = 0 + reviving = TRUE + to_chat(owner, span_notice("You feel a faint buzzing as your reviver implant starts patching your wounds...")) /obj/item/organ/internal/cyberimp/chest/reviver/proc/heal() + if(can_defib_owner == DEFIB_POSSIBLE) + revive_dead() + can_defib_owner = null + revive_cost += 10 MINUTES // Additional 10 minutes cooldown after revival. + // this check goes after revive_dead() to delay revival a bit + if(owner.stat == DEAD) + can_defib_owner = owner.can_defib() + if(can_defib_owner == DEFIB_POSSIBLE) + owner.notify_ghost_cloning("You are being revived by [src]!") + owner.grab_ghost() + /// boolean that stands for if PHYSICAL damage being patched + var/body_damage_patched = FALSE var/need_mob_update = FALSE if(owner.getOxyLoss()) need_mob_update += owner.adjustOxyLoss(-5, updating_health = FALSE) @@ -84,15 +101,34 @@ if(owner.getBruteLoss()) need_mob_update += owner.adjustBruteLoss(-2, updating_health = FALSE) revive_cost += 40 + body_damage_patched = TRUE if(owner.getFireLoss()) need_mob_update += owner.adjustFireLoss(-2, updating_health = FALSE) revive_cost += 40 + body_damage_patched = TRUE if(owner.getToxLoss()) need_mob_update += owner.adjustToxLoss(-1, updating_health = FALSE) revive_cost += 40 if(need_mob_update) owner.updatehealth() + if(body_damage_patched && prob(35)) // healing is called every few seconds, not every tick + owner.visible_message(span_warning("[owner]'s body twitches a bit."), span_notice("You feel like something is patching your injured body.")) + + +/obj/item/organ/internal/cyberimp/chest/reviver/proc/revive_dead() + owner.grab_ghost() + + owner.visible_message(span_warning("[owner]'s body convulses a bit.")) + playsound(owner, SFX_BODYFALL, 50, TRUE) + playsound(owner, 'sound/machines/defib_zap.ogg', 75, TRUE, -1) + owner.revive() + owner.emote("gasp") + owner.set_jitter_if_lower(200 SECONDS) + SEND_SIGNAL(owner, COMSIG_LIVING_MINOR_SHOCK) + log_game("[owner] been revived by [src]") + + /obj/item/organ/internal/cyberimp/chest/reviver/emp_act(severity) . = ..() if(!owner || . & EMP_PROTECT_SELF) From d53ee10ac625dbdae790f283cf43069fa1521db2 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 00:16:42 +0200 Subject: [PATCH 033/100] Relocates a garbage spawner on Tramstation that was causing rng CI failures [MDB IGNORE] (#24256) * Relocates a garbage spawner on Tramstation that was causing rng CI failures (#78883) ## About The Pull Request This garbage spawner was in a spot where depending on which module was loaded it would end up spawning in space, which led to it causing CI to fail whenever it randomly chose /obj/effect/spawner/random/trash/cigbutt. This is because that spawner includes an /obj/effect/decal/cleanable/ash as its garbage to spawn, which aren't supposed to spawn in groundless turfs. ![firefox_8EQzJ52tBl](https://github.com/tgstation/tgstation/assets/13398309/50362bfe-ef3c-4f4f-acf3-b9d6a600f977) ![StrongDMM_866qdoxrLD](https://github.com/tgstation/tgstation/assets/13398309/b6c60748-5e8b-4f0c-9444-bce8c4211fa1)

Module that caused the issue whenever it was loaded---spawner would spawn at the cursor's position, in space. ![StrongDMM_8A7P5eoG4W](https://github.com/tgstation/tgstation/assets/13398309/fdb38b08-4379-4774-bb79-4e5de779b7b1) ![image](https://github.com/tgstation/tgstation/assets/13398309/7772e904-f057-4fe0-9062-59d93e182a4b)
I have moved the problem spawner one tile to the left which should fix the issue of it causing variable runtimes. ## Why It's Good For The Game Less CI failure rng ## Changelog :cl: fix: moved a garbage spawner on Tramstation that was causing random runtimes due to sometimes spawning in space depending on which module got loaded /:cl: * Relocates a garbage spawner on Tramstation that was causing rng CI failures --------- Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- _maps/map_files/tramstation/tramstation.dmm | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 9ce8d37d988..9096ac579a9 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -10110,7 +10110,7 @@ layer = 3.1; linked_elevator_id = "tram_xeno_lift"; pixel_y = 2; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") }, /turf/closed/wall, /area/station/science/xenobiology) @@ -19727,7 +19727,7 @@ /area/station/security/processing) "fWK" = ( /obj/machinery/computer/atmos_control/oxygen_tank{ - atmos_chambers = list("o2ordance"="Oxygen Supply") + atmos_chambers = list("o2ordance"="Oxygen Supply") }, /obj/effect/turf_decal/stripes/line, /obj/machinery/airalarm/directional/north, @@ -20301,7 +20301,7 @@ }, /obj/machinery/elevator_control_panel/directional/west{ linked_elevator_id = "tram_sci_lift"; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") }, /turf/open/floor/plating/elevatorshaft, /area/station/science/lower) @@ -29165,7 +29165,7 @@ /obj/structure/industrial_lift/public, /obj/machinery/elevator_control_panel/directional/west{ linked_elevator_id = "tram_cargo_lift"; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck"); + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck"); req_access = list("mining") }, /obj/effect/abstract/elevator_music_zone{ @@ -35035,7 +35035,7 @@ }, /obj/machinery/elevator_control_panel/directional/west{ linked_elevator_id = "tram_perma_lift"; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") }, /turf/open/floor/plating/elevatorshaft, /area/station/security/execution/transfer) @@ -39125,7 +39125,7 @@ }, /obj/machinery/elevator_control_panel/directional/north{ linked_elevator_id = "tram_upper_center_lift"; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") }, /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 1 @@ -44054,7 +44054,7 @@ layer = 3.1; linked_elevator_id = "tram_xeno_lift"; pixel_y = 2; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") }, /turf/closed/wall/r_wall, /area/station/science/xenobiology) @@ -60262,7 +60262,7 @@ /obj/structure/industrial_lift/public, /obj/machinery/elevator_control_panel/directional/east{ linked_elevator_id = "tram_lower_center_lift"; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") }, /turf/open/floor/plating/elevatorshaft, /area/station/maintenance/tram/mid) @@ -61780,7 +61780,7 @@ /obj/structure/industrial_lift/public, /obj/machinery/elevator_control_panel/directional/south{ linked_elevator_id = "tram_dorm_lift"; - preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") + preset_destination_names = list("2"="Lower Deck","3"="Upper Deck") }, /obj/structure/railing, /turf/open/floor/plating/elevatorshaft, @@ -80987,7 +80987,7 @@ aac aac aac aac -aac +aaR aac aac vXM @@ -81244,7 +81244,7 @@ aac aac aac aac -aaR +aac aac aac vXM From 080d2bf36742e1b5c75bfeb15ef76a0f315ceba4 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 00:31:58 +0200 Subject: [PATCH 034/100] Fixes a runtime in obj/item/organ/on_death() [MDB IGNORE] (#24255) Fixes a runtime in obj/item/organ/on_death() Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/modules/mob/living/carbon/life.dm | 3 ++- .../surgery/organs/internal/cyberimp/augments_chest.dm | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 44ffab1196e..4da9129b1fe 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -494,7 +494,8 @@ return for(var/obj/item/organ/internal/organ in organs) // On-death is where organ decay is handled - organ?.on_death(seconds_per_tick, times_fired) // organ can be null due to reagent metabolization causing organ shuffling + if(organ?.owner) // organ + owner can be null due to reagent metabolization causing organ shuffling + organ.on_death(seconds_per_tick, times_fired) // We need to re-check the stat every organ, as one of our others may have revived us if(stat != DEAD) break diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm index 24a3afe47f1..1ea3a1bf9c4 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm @@ -57,7 +57,9 @@ COOLDOWN_DECLARE(reviver_cooldown) /obj/item/organ/internal/cyberimp/chest/reviver/on_death(seconds_per_tick, times_fired) - try_heal() // Allowes implant to work even on dead people + if(isnull(owner)) // owner can be null, on_death() gets called by /obj/item/organ/internal/process() for decay + return + try_heal() // Allows implant to work even on dead people /obj/item/organ/internal/cyberimp/chest/reviver/on_life(seconds_per_tick, times_fired) try_heal() @@ -89,7 +91,7 @@ // this check goes after revive_dead() to delay revival a bit if(owner.stat == DEAD) can_defib_owner = owner.can_defib() - if(can_defib_owner == DEFIB_POSSIBLE) + if(can_defib_owner == DEFIB_POSSIBLE) owner.notify_ghost_cloning("You are being revived by [src]!") owner.grab_ghost() /// boolean that stands for if PHYSICAL damage being patched @@ -114,7 +116,7 @@ if(body_damage_patched && prob(35)) // healing is called every few seconds, not every tick owner.visible_message(span_warning("[owner]'s body twitches a bit."), span_notice("You feel like something is patching your injured body.")) - + /obj/item/organ/internal/cyberimp/chest/reviver/proc/revive_dead() owner.grab_ghost() From 9b5fffe1b53333069db7d7fba6cbec8f8edc1772 Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Tue, 10 Oct 2023 18:33:18 -0400 Subject: [PATCH 035/100] FINALLY fixes the shit where markings color menu wouldnt open with the active color (#24249) * wDAW * HAHA! * FUCKL! --- .../modules/client/preferences/middleware/limbs_and_markings.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modular_skyrat/master_files/code/modules/client/preferences/middleware/limbs_and_markings.dm b/modular_skyrat/master_files/code/modules/client/preferences/middleware/limbs_and_markings.dm index 2d9e1c2a1e1..1099d7a3e79 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences/middleware/limbs_and_markings.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences/middleware/limbs_and_markings.dm @@ -162,7 +162,7 @@ usr, "Select new color", null, - preferences.body_markings[limb_slot][marking_entry_name], + preferences.body_markings[limb_slot][marking_entry_name][1], ) as color | null if(!new_color) return TRUE From 8f2cd3447be705d262059d3f160f831a332b59fc Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 00:37:00 +0200 Subject: [PATCH 036/100] Basic Constructs: parent type + Harvester [MDB IGNORE] (#24258) * Basic Constructs: parent type + Harvester (#78807) ## About The Pull Request I kind of hate cult as a whole, but I like these little guys. Let's basic-ize them. This PR begins the process with the harbinger of the Red Harvest, the Harvester! Their actual capabilities have been changed very little, except that most of their unique properties have been moved to components and elements. The basic parent type of constructs has also been set up to make the next bunch of conversions easier. - Constructs capable of repair now receive the healing hands component. Healing hands has been extended, to allow the healing particles to come in custom colors, and to allow it to print the target's health if the target is not a carbon. - Repairing constructs also receive a new element: Structure repair is a lighter-weight variant on healing hands that allows repairing clicked-on atoms of specified types. - Constructs capable of damaging walls, meanwhile, receive the wall smasher element. Harvesters in specific have two special elements: - The existing "amputating limbs" element, making them instantly rip a limb off of any carbon they attack. As before, if they attempt this on a carbon with no arms or legs, the harvester will hear Nar'Sie's call to bring the victim to her. - A new "wall walker" element, allowing them to walk through walls of specified type (cult walls for harvesters) and allowing them to drag any atom through as well. Other than laying the groundwork, there's not much else here. I started with Harvesters specifically because they are only ever player-controlled, which makes things easy. I'm not completely happy with the use of healing hands here - it gets the job done, but currently loses a bit of the previous flavor (a healing beam as a visual; printing the target's health in cult span). I may extend it further to allow this behavior. I've included an UpdatePaths script, even if these things shouldn't be mapped, just in case something fucky is going on on a downstream. You never know. ## Why It's Good For The Game Constructs, currently, occupy _19_ spots on the simple animal list. This is something close to 10% of all the remaining ones. Also, like everything to do with cult, construct code is janky, old, and desperately in need of updating. This is the first step. ## Changelog :cl: refactor: Harvester constructs have been updated to the basic mob framework. This should have very little impact on their behavior, but please report any issues. /:cl: --------- Co-authored-by: san7890 * Basic Constructs: parent type + Harvester --------- Co-authored-by: lizardqueenlexi <105025397+lizardqueenlexi@users.noreply.github.com> Co-authored-by: san7890 --- .../signals/signals_mob/signals_mob_living.dm | 4 + code/__DEFINES/is_helpers.dm | 5 +- code/_globalvars/phobias.dm | 1 + code/datums/components/healing_touch.dm | 14 +- code/datums/elements/amputating_limbs.dm | 2 +- code/datums/elements/structure_repair.dm | 45 +++++ code/datums/elements/wall_walker.dm | 49 ++++++ code/game/turfs/closed/wall/misc_walls.dm | 10 -- code/game/turfs/closed/walls.dm | 8 + .../mob/living/basic/constructs/_construct.dm | 156 ++++++++++++++++++ .../hostile => basic}/constructs/harvester.dm | 73 +++----- code/modules/mob/living/living_defense.dm | 2 +- .../hostile/constructs/constructs.dm | 2 +- code/modules/mob/transform_procs.dm | 2 +- code/modules/power/singularity/narsie.dm | 2 +- .../unit_tests/simple_animal_freeze.dm | 1 - tgstation.dme | 5 +- ...07_simple_to_basic_construct_harvester.txt | 1 + 18 files changed, 313 insertions(+), 69 deletions(-) create mode 100644 code/datums/elements/structure_repair.dm create mode 100644 code/datums/elements/wall_walker.dm create mode 100644 code/modules/mob/living/basic/constructs/_construct.dm rename code/modules/mob/living/{simple_animal/hostile => basic}/constructs/harvester.dm (69%) create mode 100644 tools/UpdatePaths/Scripts/78807_simple_to_basic_construct_harvester.txt diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 9a32653a12b..b70f7f9013d 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -137,6 +137,10 @@ #define COMSIG_LIVING_UNARMED_ATTACK "living_unarmed_attack" ///From base of mob/living/MobBump() (mob/living) #define COMSIG_LIVING_MOB_BUMP "living_mob_bump" +///From base of mob/living/Bump() (turf/closed) +#define COMSIG_LIVING_WALL_BUMP "living_wall_bump" +///From base of turf/closed/Exited() (turf/closed) +#define COMSIG_LIVING_WALL_EXITED "living_wall_exited" ///From base of mob/living/ZImpactDamage() (mob/living, levels, turf/t) #define COMSIG_LIVING_Z_IMPACT "living_z_impact" #define NO_Z_IMPACT_DAMAGE (1<<0) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index c26fd3b41a3..f6ef0a45c80 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -148,6 +148,9 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define ismining(A) (istype(A, /mob/living/simple_animal/hostile/asteroid) || istype(A, /mob/living/basic/mining)) +/// constructs, which are both simple and basic for now +#define isconstruct(A) (istype(A, /mob/living/simple_animal/hostile/construct) || istype(A, /mob/living/basic/construct)) + //Simple animals #define isanimal(A) (istype(A, /mob/living/simple_animal)) @@ -175,8 +178,6 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define isguardian(A) (istype(A, /mob/living/simple_animal/hostile/guardian)) -#define isconstruct(A) (istype(A, /mob/living/simple_animal/hostile/construct)) - #define ismegafauna(A) (istype(A, /mob/living/simple_animal/hostile/megafauna)) #define isclown(A) (istype(A, /mob/living/basic/clown)) diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm index 93220a1045e..b37c61bc681 100644 --- a/code/_globalvars/phobias.dm +++ b/code/_globalvars/phobias.dm @@ -91,6 +91,7 @@ GLOBAL_LIST_INIT(phobia_mobs, list( "the supernatural" = typecacheof(list( /mob/dead/observer, /mob/living/basic/bat, + /mob/living/basic/construct, /mob/living/basic/demon, /mob/living/basic/faithless, /mob/living/basic/ghost, diff --git a/code/datums/components/healing_touch.dm b/code/datums/components/healing_touch.dm index 4b953fc6289..029b0f660ef 100644 --- a/code/datums/components/healing_touch.dm +++ b/code/datums/components/healing_touch.dm @@ -32,6 +32,10 @@ var/action_text /// Text to print when action completes, replaces %SOURCE% with healer and %TARGET% with healed mob var/complete_text + /// Whether to print the target's remaining health after healing (for non-carbon targets only) + var/show_health + /// Color for the healing effect + var/heal_color /datum/component/healing_touch/Initialize( heal_brute = 20, @@ -46,6 +50,8 @@ self_targetting = HEALING_TOUCH_NOT_SELF, action_text = "%SOURCE% begins healing %TARGET%", complete_text = "%SOURCE% finishes healing %TARGET%", + show_health = FALSE, + heal_color = COLOR_HEALING_CYAN, ) if (!isliving(parent)) return COMPONENT_INCOMPATIBLE @@ -62,6 +68,8 @@ src.self_targetting = self_targetting src.action_text = action_text src.complete_text = complete_text + src.show_health = show_health + src.heal_color = heal_color RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(try_healing)) // Players RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(try_healing)) // NPCs @@ -147,7 +155,11 @@ healer.visible_message(span_notice("[format_string(complete_text, healer, target)]")) target.heal_overall_damage(brute = heal_brute, burn = heal_burn, stamina = heal_stamina, required_bodytype = required_bodytype) - new /obj/effect/temp_visual/heal(get_turf(target), COLOR_HEALING_CYAN) + new /obj/effect/temp_visual/heal(get_turf(target), heal_color) + + if(show_health && !iscarbon(target)) + var/formatted_string = format_string("%TARGET% now has [target.health]/[target.maxHealth] health.", healer, target) + healer.visible_message(span_danger(formatted_string)) /// Reformats the passed string with the replacetext keys /datum/component/healing_touch/proc/format_string(string, atom/source, atom/target) diff --git a/code/datums/elements/amputating_limbs.dm b/code/datums/elements/amputating_limbs.dm index f7e3d08fcc4..7271b20a6c3 100644 --- a/code/datums/elements/amputating_limbs.dm +++ b/code/datums/elements/amputating_limbs.dm @@ -1,4 +1,4 @@ -/// This component will intercept bare-handed attacks by the owner on critically injured carbons and amputate random limbs instead +/// This component will intercept bare-handed attacks by the owner on sufficiently injured carbons and amputate random limbs instead /datum/element/amputating_limbs element_flags = ELEMENT_BESPOKE argument_hash_start_idx = 2 diff --git a/code/datums/elements/structure_repair.dm b/code/datums/elements/structure_repair.dm new file mode 100644 index 00000000000..d3b26eed815 --- /dev/null +++ b/code/datums/elements/structure_repair.dm @@ -0,0 +1,45 @@ +/// Intercepts attacks from mobs with this component to instead repair specified structures. +/datum/element/structure_repair + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// How much to heal structures by + var/heal_amount + /// Typecache of types of structures to repair + var/list/structure_types_typecache + +/datum/element/structure_repair/Attach( + datum/target, + heal_amount = 5, + structure_types_typecache = typecacheof(list(/obj/structure)), +) + . = ..() + if (!isliving(target)) + return ELEMENT_INCOMPATIBLE + + src.heal_amount = heal_amount + src.structure_types_typecache = structure_types_typecache + RegisterSignals(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET), PROC_REF(try_repair)) + +/datum/element/structure_repair/Detach(datum/source) + UnregisterSignal(source, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) + return ..() + +/// If the target is of a valid type, interrupt the attack chain to repair it instead +/datum/element/structure_repair/proc/try_repair(mob/living/fixer, atom/target) + SIGNAL_HANDLER + + if (!is_type_in_typecache(target, structure_types_typecache)) + return + + if (target.get_integrity() >= target.max_integrity) + target.balloon_alert(fixer, "not damaged!") + return COMPONENT_CANCEL_ATTACK_CHAIN + + target.repair_damage(heal_amount) + fixer.Beam(target, icon_state = "sendbeam", time = 0.4 SECONDS) + fixer.visible_message( + span_danger("[fixer] repairs [target]."), + span_danger("You repair [target], leaving it at [round(target.get_integrity() * 100 / target.max_integrity)]% stability."), + ) + + return COMPONENT_CANCEL_ATTACK_CHAIN diff --git a/code/datums/elements/wall_walker.dm b/code/datums/elements/wall_walker.dm new file mode 100644 index 00000000000..92ac3318c12 --- /dev/null +++ b/code/datums/elements/wall_walker.dm @@ -0,0 +1,49 @@ +/// This element will allow the mob it's attached to to pass through a specified type of wall, and drag anything through it. +/datum/element/wall_walker + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// What kind of walls can we pass through? + var/wall_type + +/datum/element/wall_walker/Attach( + datum/target, + wall_type = /turf/closed/wall, +) + . = ..() + if (!isliving(target)) + return ELEMENT_INCOMPATIBLE + + src.wall_type = wall_type + RegisterSignal(target, COMSIG_LIVING_WALL_BUMP, PROC_REF(try_pass_wall)) + RegisterSignal(target, COMSIG_LIVING_WALL_EXITED, PROC_REF(exit_wall)) + +/datum/element/wall_walker/Detach(datum/source) + UnregisterSignal(source, list(COMSIG_LIVING_WALL_BUMP, COMSIG_LIVING_WALL_EXITED)) + return ..() + +/// If the wall is of the proper type, pass into it and keep hold on whatever you're pulling +/datum/element/wall_walker/proc/try_pass_wall(mob/living/passing_mob, turf/closed/bumped_wall) + if(!istype(bumped_wall, wall_type)) + return + + var/atom/movable/stored_pulling = passing_mob.pulling + if(stored_pulling) //force whatever you're pulling to come with you + stored_pulling.setDir(get_dir(stored_pulling.loc, passing_mob.loc)) + stored_pulling.forceMove(passing_mob.loc) + passing_mob.forceMove(bumped_wall) + + if(stored_pulling) //don't drop them because we went into a wall + passing_mob.start_pulling(stored_pulling, supress_message = TRUE) + +/// If the wall is of the proper type, pull whatever you're pulling into it +/datum/element/wall_walker/proc/exit_wall(mob/living/passing_mob, turf/closed/exited_wall) + if(!istype(exited_wall, wall_type)) + return + + var/atom/movable/stored_pulling = passing_mob.pulling + if(isnull(stored_pulling)) + return + + stored_pulling.setDir(get_dir(stored_pulling.loc, passing_mob.loc)) + stored_pulling.forceMove(exited_wall) + passing_mob.start_pulling(stored_pulling, supress_message = TRUE) diff --git a/code/game/turfs/closed/wall/misc_walls.dm b/code/game/turfs/closed/wall/misc_walls.dm index a26e456971d..9fbce09ace2 100644 --- a/code/game/turfs/closed/wall/misc_walls.dm +++ b/code/game/turfs/closed/wall/misc_walls.dm @@ -18,16 +18,6 @@ /turf/closed/wall/mineral/cult/devastate_wall() new sheet_type(get_turf(src), sheet_amount) -/turf/closed/wall/mineral/cult/Exited(atom/movable/gone, direction) - . = ..() - if(istype(gone, /mob/living/simple_animal/hostile/construct/harvester)) //harvesters can go through cult walls, dragging something with - var/mob/living/simple_animal/hostile/construct/harvester/H = gone - var/atom/movable/stored_pulling = H.pulling - if(stored_pulling) - stored_pulling.setDir(direction) - stored_pulling.forceMove(src) - H.start_pulling(stored_pulling, supress_message = TRUE) - /turf/closed/wall/mineral/cult/artificer name = "runed stone wall" desc = "A cold stone wall engraved with indecipherable symbols. Studying them causes your head to pound." diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index 7b601fb82ac..06a063f16ea 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -363,5 +363,13 @@ /turf/closed/wall/metal_foam_base girder_type = /obj/structure/foamedmetal +/turf/closed/wall/Bumped(atom/movable/bumped_atom) + . = ..() + SEND_SIGNAL(bumped_atom, COMSIG_LIVING_WALL_BUMP, src) + +/turf/closed/wall/Exited(atom/movable/gone, direction) + . = ..() + SEND_SIGNAL(gone, COMSIG_LIVING_WALL_EXITED, src) + #undef MAX_DENT_DECALS #undef LEANING_OFFSET diff --git a/code/modules/mob/living/basic/constructs/_construct.dm b/code/modules/mob/living/basic/constructs/_construct.dm new file mode 100644 index 00000000000..f2e55cceb86 --- /dev/null +++ b/code/modules/mob/living/basic/constructs/_construct.dm @@ -0,0 +1,156 @@ +/mob/living/basic/construct + icon = 'icons/mob/nonhuman-player/cult.dmi' + gender = NEUTER + basic_mob_flags = DEL_ON_DEATH + combat_mode = TRUE + mob_biotypes = MOB_MINERAL | MOB_SPECIAL + faction = list(FACTION_CULT) + unsuitable_atmos_damage = 0 + minimum_survivable_temperature = 0 + maximum_survivable_temperature = INFINITY + damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) + pressure_resistance = 100 + speed = 0 + unique_name = TRUE + initial_language_holder = /datum/language_holder/construct + death_message = "collapses in a shattered heap." + + speak_emote = list("hisses") + response_help_continuous = "thinks better of touching" + response_help_simple = "think better of touching" + response_disarm_continuous = "flails at" + response_disarm_simple = "flail at" + response_harm_continuous = "punches" + response_harm_simple = "punch" + + // Vivid red, cause cult theme + lighting_cutoff_red = 30 + lighting_cutoff_green = 5 + lighting_cutoff_blue = 20 + + /// List of spells that this construct can cast + var/list/construct_spells = list() + /// Flavor text shown to players when they spawn as this construct + var/playstyle_string = "You are a generic construct. Your job is to not exist, and you should probably adminhelp this." + /// The construct's master + var/master = null + /// Whether this construct is currently seeking nar nar + var/seeking = FALSE + /// Whether this construct can repair other constructs or cult buildings. Gets the healing_touch component if so. + var/can_repair = FALSE + /// Whether this construct can repair itself. Works independently of can_repair. + var/can_repair_self = FALSE + /// Theme controls color. THEME_CULT is red THEME_WIZARD is purple and THEME_HOLY is blue + var/theme = THEME_CULT + /// What flavor of gunk does this construct drop on death? + var/static/list/remains = list(/obj/item/ectoplasm/construct) + /// Can this construct smash walls? Gets the wall_smasher element if so. + var/smashes_walls = FALSE + +/mob/living/basic/construct/Initialize(mapload) + . = ..() + AddElement(/datum/element/simple_flying) + if(length(remains)) + AddElement(/datum/element/death_drops, remains) + if(smashes_walls) + AddElement(/datum/element/wall_smasher, strength_flag = ENVIRONMENT_SMASH_WALLS) + if(can_repair) + AddComponent(\ + /datum/component/healing_touch,\ + heal_brute = 5,\ + heal_burn = 0,\ + heal_time = 0,\ + valid_targets_typecache = typecacheof(list(/mob/living/basic/construct, /mob/living/simple_animal/hostile/construct, /mob/living/simple_animal/shade)),\ + self_targetting = can_repair_self ? HEALING_TOUCH_ANYONE : HEALING_TOUCH_NOT_SELF,\ + action_text = "%SOURCE% begins repairing %TARGET%'s dents.",\ + complete_text = "%TARGET%'s dents are repaired.",\ + show_health = TRUE,\ + heal_color = COLOR_CULT_RED,\ + ) + var/static/list/structure_types = typecacheof(list(/obj/structure/destructible/cult)) + AddElement(\ + /datum/element/structure_repair,\ + structure_types_typecache = structure_types,\ + ) + add_traits(list(TRAIT_HEALS_FROM_CULT_PYLONS, TRAIT_SPACEWALK), INNATE_TRAIT) + for(var/spell in construct_spells) + var/datum/action/new_spell = new spell(src) + new_spell.Grant(src) + + var/spell_count = 1 + for(var/datum/action/spell as anything in actions) + if(!(spell.type in construct_spells)) + continue + + var/pos = 2 + spell_count * 31 + if(construct_spells.len >= 4) + pos -= 31 * (construct_spells.len - 4) + spell.default_button_position = "6:[pos],4:-2" // Set the default position to this random position + spell_count++ + update_action_buttons() + + if(icon_state) + add_overlay("glow_[icon_state]_[theme]") + +/mob/living/basic/construct/Login() + . = ..() + if(!. || !client) + return FALSE + to_chat(src, span_bold(playstyle_string)) + +/mob/living/basic/construct/examine(mob/user) + var/text_span + switch(theme) + if(THEME_CULT) + text_span = "cult" + if(THEME_WIZARD) + text_span = "purple" + if(THEME_HOLY) + text_span = "blue" + . = list("This is [icon2html(src, user)] \a [src]!\n[desc]") + if(health < maxHealth) + if(health >= maxHealth/2) + . += span_warning("[p_They()] look[p_s()] slightly dented.") + else + . += span_warning(span_bold("[p_They()] look[p_s()] severely dented!")) + . += "" + return . + +/mob/living/basic/construct/narsie_act() + return + +/mob/living/basic/construct/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE) + return FALSE + +// Allows simple constructs to repair basic constructs. +/mob/living/basic/construct/attack_animal(mob/living/simple_animal/user, list/modifiers) + if(!isconstruct(user)) + if(src != user) + return ..() + return + + if(src == user) //basic constructs use the healing hands component instead + return + + var/mob/living/simple_animal/hostile/construct/doll = user + if(!doll.can_repair || (doll == src && !doll.can_repair_self)) + return ..() + if(theme != doll.theme) + return ..() + + if(health >= maxHealth) + to_chat(user, span_cult("You cannot repair [src]'s dents, as [p_they()] [p_have()] none!")) + return + + heal_overall_damage(brute = 5) + + Beam(user, icon_state = "sendbeam", time = 4) + user.visible_message( + span_danger("[user] repairs some of \the [src]'s dents."), + span_cult("You repair some of [src]'s dents, leaving [src] at [health]/[maxHealth] health."), + ) + +/// Construct ectoplasm. Largely a placeholder, since the death drop element needs a unique list. +/obj/item/ectoplasm/construct + name = "blood-red ectoplasm" + desc = "Has a pungent metallic smell." diff --git a/code/modules/mob/living/simple_animal/hostile/constructs/harvester.dm b/code/modules/mob/living/basic/constructs/harvester.dm similarity index 69% rename from code/modules/mob/living/simple_animal/hostile/constructs/harvester.dm rename to code/modules/mob/living/basic/constructs/harvester.dm index 8c5fc8eae37..30b30994872 100644 --- a/code/modules/mob/living/simple_animal/hostile/constructs/harvester.dm +++ b/code/modules/mob/living/basic/constructs/harvester.dm @@ -1,4 +1,4 @@ -/mob/living/simple_animal/hostile/construct/harvester +/mob/living/basic/construct/harvester name = "Harvester" real_name = "Harvester" desc = "A long, thin construct built to herald Nar'Sie's rise. It'll be all over soon." @@ -24,58 +24,33 @@ can_repair = TRUE slowed_by_drag = FALSE - -/mob/living/simple_animal/hostile/construct/harvester/Bump(atom/thing) +/mob/living/basic/construct/harvester/Initialize(mapload) . = ..() - if(!istype(thing, /turf/closed/wall/mineral/cult) || thing == loc) - return // we can go through cult walls - var/atom/movable/stored_pulling = pulling - - if(stored_pulling) - stored_pulling.setDir(get_dir(stored_pulling.loc, loc)) - stored_pulling.forceMove(loc) - forceMove(thing) - - if(stored_pulling) - start_pulling(stored_pulling, supress_message = TRUE) //drag anything we're pulling through the wall with us by magic + AddElement(\ + /datum/element/amputating_limbs,\ + surgery_time = 0,\ + surgery_verb = "slicing",\ + minimum_stat = CONSCIOUS,\ + ) + AddElement(/datum/element/wall_walker, /turf/closed/wall/mineral/cult) + var/datum/action/innate/seek_prey/seek = new(src) + seek.Grant(src) + seek.Activate() -/mob/living/simple_animal/hostile/construct/harvester/AttackingTarget() - if(!iscarbon(target)) +/// If the attack is a limbless carbon, abort the attack, paralyze them, and get a special message from Nar'Sie. +/mob/living/basic/construct/harvester/resolve_unarmed_attack(atom/attack_target, list/modifiers) + if(!iscarbon(attack_target)) return ..() + var/mob/living/carbon/carbon_target = attack_target - var/mob/living/carbon/victim = target - if(HAS_TRAIT(victim, TRAIT_NODISMEMBER)) - return ..() //ATTACK! - - var/list/parts = list() - var/strong_limbs = 0 - - for(var/obj/item/bodypart/limb as anything in victim.bodyparts) + for(var/obj/item/bodypart/limb as anything in carbon_target.bodyparts) if(limb.body_part == HEAD || limb.body_part == CHEST) continue - if(!(limb.bodypart_flags & BODYPART_UNREMOVABLE)) - parts += limb - else - strong_limbs++ - - if(!LAZYLEN(parts)) - if(strong_limbs) // they have limbs we can't remove, and no parts we can, attack! - return ..() - victim.Paralyze(60) - visible_message(span_danger("[src] knocks [victim] down!")) - to_chat(src, span_cultlarge("\"Bring [victim.p_them()] to me.\"")) - return FALSE - - do_attack_animation(victim) - var/obj/item/bodypart/limb = pick(parts) - limb.dismember() - return FALSE - -/mob/living/simple_animal/hostile/construct/harvester/Initialize(mapload) - . = ..() - var/datum/action/innate/seek_prey/seek = new() - seek.Grant(src) - seek.Activate() + return ..() //if any arms or legs exist, attack + + carbon_target.Paralyze(6 SECONDS) + visible_message(span_danger("[src] knocks [carbon_target] down!")) + to_chat(src, span_cultlarge("\"Bring [carbon_target.p_them()] to me.\"")) /datum/action/innate/seek_master name = "Seek your Master" @@ -89,7 +64,7 @@ /// Where is nar nar? Are we even looking? var/tracking = FALSE /// The construct we're attached to - var/mob/living/simple_animal/hostile/construct/the_construct + var/mob/living/basic/construct/the_construct /datum/action/innate/seek_master/Grant(mob/living/player) the_construct = player @@ -132,7 +107,7 @@ /datum/action/innate/seek_prey/Activate() if(GLOB.cult_narsie == null) return - var/mob/living/simple_animal/hostile/construct/harvester/the_construct = owner + var/mob/living/basic/construct/harvester/the_construct = owner if(the_construct.seeking) desc = "None can hide from Nar'Sie, activate to track a survivor attempting to flee the red harvest!" diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 687359a6ff6..01362dfb1ba 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -464,7 +464,7 @@ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), CULT_VICTORY_MASS_CONVERSION), 120) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(ending_helper)), 270) if(client) - makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, cultoverride = TRUE) + makeNewConstruct(/mob/living/basic/construct/harvester, src, cultoverride = TRUE) else switch(rand(1, 4)) if(1) diff --git a/code/modules/mob/living/simple_animal/hostile/constructs/constructs.dm b/code/modules/mob/living/simple_animal/hostile/constructs/constructs.dm index 23f7590dc8e..31150a4dc89 100644 --- a/code/modules/mob/living/simple_animal/hostile/constructs/constructs.dm +++ b/code/modules/mob/living/simple_animal/hostile/constructs/constructs.dm @@ -3,7 +3,7 @@ real_name = "Construct" desc = "" gender = NEUTER - mob_biotypes = NONE + mob_biotypes = MOB_MINERAL | MOB_SPECIAL speak_emote = list("hisses") response_help_continuous = "thinks better of touching" response_help_simple = "think better of touching" diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 09ce3b3c65c..a492557d4e4 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -372,7 +372,7 @@ if(!MP) return FALSE //Sanity, this should never happen. - if(ispath(MP, /mob/living/simple_animal/hostile/construct)) + if(ispath(MP, /mob/living/simple_animal/hostile/construct) || ispath(MP, /mob/living/basic/construct)) return FALSE //Verbs do not appear for players. //Good mobs! diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index 1c83ca58e1d..d11b57bcb93 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -112,7 +112,7 @@ return ..() /obj/narsie/attack_ghost(mob/user) - makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, user, cultoverride = TRUE, loc_override = loc) + makeNewConstruct(/mob/living/basic/construct/harvester, user, cultoverride = TRUE, loc_override = loc) /obj/narsie/process() var/datum/component/singularity/singularity_component = singularity.resolve() diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index 396bb2140aa..98e50a3add4 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -73,7 +73,6 @@ /mob/living/simple_animal/hostile/construct/artificer/hostile, /mob/living/simple_animal/hostile/construct/artificer/mystic, /mob/living/simple_animal/hostile/construct/artificer/noncult, - /mob/living/simple_animal/hostile/construct/harvester, /mob/living/simple_animal/hostile/construct/juggernaut, /mob/living/simple_animal/hostile/construct/juggernaut/angelic, /mob/living/simple_animal/hostile/construct/juggernaut/hostile, diff --git a/tgstation.dme b/tgstation.dme index 5b79d8a36a0..47afbc9609e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1456,6 +1456,7 @@ #include "code\datums\elements\squish.dm" #include "code\datums\elements\sticker.dm" #include "code\datums\elements\strippable.dm" +#include "code\datums\elements\structure_repair.dm" #include "code\datums\elements\swabbable.dm" #include "code\datums\elements\tear_wall.dm" #include "code\datums\elements\temporary_atom.dm" @@ -1473,6 +1474,7 @@ #include "code\datums\elements\waddling.dm" #include "code\datums\elements\wall_engraver.dm" #include "code\datums\elements\wall_smasher.dm" +#include "code\datums\elements\wall_walker.dm" #include "code\datums\elements\weapon_description.dm" #include "code\datums\elements\weather_listener.dm" #include "code\datums\elements\web_walker.dm" @@ -4453,6 +4455,8 @@ #include "code\modules\mob\living\basic\blob_minions\blobbernaut.dm" #include "code\modules\mob\living\basic\clown\clown.dm" #include "code\modules\mob\living\basic\clown\clown_ai.dm" +#include "code\modules\mob\living\basic\constructs\_construct.dm" +#include "code\modules\mob\living\basic\constructs\harvester.dm" #include "code\modules\mob\living\basic\farm_animals\deer.dm" #include "code\modules\mob\living\basic\farm_animals\pig.dm" #include "code\modules\mob\living\basic\farm_animals\pony.dm" @@ -4829,7 +4833,6 @@ #include "code\modules\mob\living\simple_animal\hostile\zombie.dm" #include "code\modules\mob\living\simple_animal\hostile\constructs\artificer.dm" #include "code\modules\mob\living\simple_animal\hostile\constructs\constructs.dm" -#include "code\modules\mob\living\simple_animal\hostile\constructs\harvester.dm" #include "code\modules\mob\living\simple_animal\hostile\constructs\juggernaut.dm" #include "code\modules\mob\living\simple_animal\hostile\constructs\wraith.dm" #include "code\modules\mob\living\simple_animal\hostile\gorilla\emotes.dm" diff --git a/tools/UpdatePaths/Scripts/78807_simple_to_basic_construct_harvester.txt b/tools/UpdatePaths/Scripts/78807_simple_to_basic_construct_harvester.txt new file mode 100644 index 00000000000..93996fd123b --- /dev/null +++ b/tools/UpdatePaths/Scripts/78807_simple_to_basic_construct_harvester.txt @@ -0,0 +1 @@ +/mob/living/simple_animal/hostile/construct/harvester : /mob/living/basic/construct/harvester{@OLD} From 701888978f97698ebfc273aecc5a1a5bc9880c83 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 00:51:29 +0200 Subject: [PATCH 037/100] Fix outdated research connections from the Lionhunter's Rifle and Rust Charge [MDB IGNORE] (#24262) * Fix outdated research connections from the Lionhunter's Rifle and Rust Charge (#78880) ## About The Pull Request So I've been diving into the code for heretic research tree, and I think that, thematically, my mind was broken a little by the mess I've seen. So here's something I think should not be the way it is: I found out that [this old PR](https://github.com/tgstation/tgstation/pull/76720), while changing correctly what research the lionhunter rifle and rust charge are unlocked by, did _not_ change what knowledge is in turn unlocked by these nodes. So the rifle would still unlock the final tier of knowledge and allow you to skip a bit of the tree if researched after the earlier tier, whereas the charge did not unlock anything and so couldn't be used to transfer paths. ## Why It's Good For The Game Pretty sure this behavior was not intended. Heretic tree is already a bit convoluted and I think the connections should make sense. ## Changelog :cl: fix: fixed some faulty research connections in between heretic's blade and rust paths. /:cl: * Fix outdated research connections from the Lionhunter's Rifle and Rust Charge --------- Co-authored-by: ViktorKoL <44502667+ViktorKoL@users.noreply.github.com> --- code/modules/antagonists/heretic/knowledge/blade_lore.dm | 5 ++++- code/modules/antagonists/heretic/knowledge/rust_lore.dm | 5 ++++- .../antagonists/heretic/knowledge/side_blade_rust.dm | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/code/modules/antagonists/heretic/knowledge/blade_lore.dm b/code/modules/antagonists/heretic/knowledge/blade_lore.dm index 84e266c8374..f2f3b156a2f 100644 --- a/code/modules/antagonists/heretic/knowledge/blade_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/blade_lore.dm @@ -13,6 +13,9 @@ * Mark of the Blade * Ritual of Knowledge * Realignment + * > Sidepaths: + * Lionhunter Rifle + * * Stance of the Scarred Duelist * > Sidepaths: * Carving Knife @@ -22,7 +25,7 @@ * Furious Steel * > Sidepaths: * Maid in the Mirror - * Lionhunter Rifle + * Rust Charge * * Maelstrom of Silver */ diff --git a/code/modules/antagonists/heretic/knowledge/rust_lore.dm b/code/modules/antagonists/heretic/knowledge/rust_lore.dm index 966134710b4..84f128b5cfc 100644 --- a/code/modules/antagonists/heretic/knowledge/rust_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/rust_lore.dm @@ -13,6 +13,9 @@ * Mark of Rust * Ritual of Knowledge * Rust Construction + * > Sidepaths: + * Lionhunter Rifle + * * Aggressive Spread * > Sidepaths: * Curse of Corrosion @@ -22,7 +25,7 @@ * Entropic Plume * > Sidepaths: * Rusted Ritual - * Blood Cleave + * Rust Charge * * Rustbringer's Oath */ diff --git a/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm b/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm index a8fb031fed2..d7dfd75a144 100644 --- a/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm +++ b/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm @@ -46,8 +46,8 @@ gain_text = "I met an old man in an anique shop who wielded a very unusual weapon. \ I could not purchase it at the time, but they showed me how they made it ages ago." next_knowledge = list( - /datum/heretic_knowledge/spell/furious_steel, - /datum/heretic_knowledge/spell/entropic_plume, + /datum/heretic_knowledge/spell/realignment, + /datum/heretic_knowledge/spell/rust_construction, /datum/heretic_knowledge/rifle_ammo, ) required_atoms = list( @@ -100,6 +100,10 @@ name = "Rust Charge" desc = "A charge that must be started on a rusted tile and will destroy any rusted objects you come into contact with, will deal high damage to others and rust around you during the charge." gain_text = "The hills sparkled now, as I neared them my mind began to wander. I quickly regained my resolve and pushed forward, this last leg would be the most treacherous." + next_knowledge = list( + /datum/heretic_knowledge/spell/furious_steel, + /datum/heretic_knowledge/spell/entropic_plume, + ) spell_to_add = /datum/action/cooldown/mob_cooldown/charge/rust cost = 1 route = PATH_SIDE From ac8217bc64e4dfe7cc05156f6f4359812b360aef Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 01:00:57 +0200 Subject: [PATCH 038/100] Adds bitrunner to the crew monitor [MDB IGNORE] (#24259) * Adds bitrunner to the crew monitor * Update crew.dm --------- Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/game/machinery/computer/crew.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index 2d33779f6ab..bc4a4ecabed 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -134,8 +134,8 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) JOB_QUARTERMASTER = 50, JOB_SHAFT_MINER = 51, JOB_CARGO_TECHNICIAN = 52, - JOB_CUSTOMS_AGENT = 53, // SKYRAT EDIT ADDITION - JOB_BITRUNNER = 54, + JOB_BITRUNNER = 53, + JOB_CUSTOMS_AGENT = 54, // SKYRAT EDIT ADDITION // 60+: Civilian/other JOB_HEAD_OF_PERSONNEL = 60, JOB_BARTENDER = 61, From 410feb219de319c748855418b7afc4f889a8fbbf Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 01:14:44 +0200 Subject: [PATCH 039/100] Fixes some issues with mirrors not updating mob appearance after making a selection [MDB IGNORE] (#24261) * Fixes some issues with mirrors not updating mob appearance after making a selection * Update mirror.dm --------- Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/game/objects/structures/mirror.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 30d8f797fdb..08cdfab3e63 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -175,8 +175,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) to_chat(race_changer, span_notice("Invalid color. Your color is not bright enough.")) return TRUE - race_changer.update_body(is_creating = TRUE) // SKYRAT EDIT CHANGE - TODO: Remove when fix comes downstream - unindented - race_changer.update_mutations_overlay() // no hulk lizard // SKYRAT EDIT CHANGE - TODO: Remove when fix comes downstream - unindented + race_changer.update_body(is_creating = TRUE) + race_changer.update_mutations_overlay() // no hulk lizard // possible Genders: MALE, FEMALE, PLURAL, NEUTER // possible Physique: MALE, FEMALE @@ -205,9 +205,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) sexy.physique = (chosen_physique == "Warlock Physique") ? MALE : FEMALE sexy.dna.update_ui_block(DNA_GENDER_BLOCK) - sexy.update_body(is_creating = TRUE) // SKYRAT EDIT - TODO: UPSTREAM FIX INCOMING + sexy.update_body(is_creating = TRUE) // or else physique won't change properly sexy.update_mutations_overlay() //(hulk male/female) - sexy.update_clothing(ITEM_SLOT_ICLOTHING) // update gender variant clothing // SKYRAT EDIT - TODO: UPSTREAM FIX INCOMING + sexy.update_clothing(ITEM_SLOT_ICLOTHING) // update gender shaped clothing /obj/structure/mirror/proc/change_eyes(mob/living/carbon/human/user) var/new_eye_color = input(user, "Choose your eye color", "Eye Color", user.eye_color_left) as color|null From 6e2620936bd1dd50ec0979bc49aec7d39a9d9e11 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 01:42:38 +0200 Subject: [PATCH 040/100] Adds practice carbines to all firing ranges [MDB IGNORE] (#24263) * Adds practice carbines to all firing ranges (#78867) ## About The Pull Request Adds practice carbines to all firing ranges. They don't deal damage. ## Why It's Good For The Game These guns are fun as hell to shoot. ## Changelog :cl: add: Adds practice carbines to all firing ranges. They don't deal damage. /:cl: * Adds practice carbines to all firing ranges * Adds them to Voidraptor too --------- Co-authored-by: carlarctg <53100513+carlarctg@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> --- _maps/map_files/Birdshot/birdshot.dmm | 2 +- _maps/map_files/Deltastation/DeltaStation2.dmm | 4 ++-- _maps/map_files/IceBoxStation/IceBoxStation.dmm | 6 +++--- _maps/map_files/MetaStation/MetaStation.dmm | 2 +- _maps/map_files/NorthStar/north_star.dmm | 4 ++-- _maps/map_files/VoidRaptor/VoidRaptor.dmm | 5 +++++ _maps/map_files/tramstation/tramstation.dmm | 2 +- _maps/templates/holodeck_firingrange.dmm | 1 + code/modules/projectiles/ammunition/energy/laser.dm | 5 +++++ code/modules/projectiles/guns/energy/laser.dm | 12 +++++++++++- code/modules/projectiles/projectile/beams.dm | 5 +++++ 11 files changed, 37 insertions(+), 11 deletions(-) diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index 0711e8dc96a..48b7b2dea80 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -58862,7 +58862,7 @@ "urm" = ( /obj/structure/table/glass, /obj/item/gun/energy/laser/practice, -/obj/item/gun/energy/laser/practice{ +/obj/item/gun/energy/laser/carbine/practice{ pixel_x = -2; pixel_y = 4 }, diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 7ab412a4f3d..ec381205acf 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -20284,7 +20284,7 @@ /area/station/maintenance/space_hut/observatory) "eYo" = ( /obj/structure/table/reinforced, -/obj/item/gun/energy/laser/practice{ +/obj/item/gun/energy/laser/carbine/practice{ pixel_x = 3; pixel_y = -3 }, @@ -84463,7 +84463,7 @@ /area/station/maintenance/port/fore) "vbT" = ( /obj/structure/rack, -/obj/item/gun/energy/laser/practice{ +/obj/item/gun/energy/laser/carbine/practice{ pixel_x = 3; pixel_y = -3 }, diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 172a001020e..7af3affa62a 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -8823,7 +8823,7 @@ /turf/open/floor/iron, /area/station/security/prison/workout) "cBJ" = ( -/obj/item/gun/energy/laser/practice{ +/obj/item/gun/energy/laser/carbine/practice{ pixel_y = 5 }, /obj/item/gun/energy/laser/practice, @@ -42071,7 +42071,7 @@ "mXq" = ( /obj/structure/table, /obj/machinery/recharger, -/obj/item/gun/energy/laser/practice, +/obj/item/gun/energy/laser/carbine/practice, /obj/item/gun/energy/laser/practice, /obj/machinery/newscaster/directional/south, /turf/open/floor/iron, @@ -62675,7 +62675,7 @@ "thc" = ( /obj/structure/table/reinforced, /obj/structure/extinguisher_cabinet/directional/south, -/obj/item/gun/energy/laser/practice{ +/obj/item/gun/energy/laser/carbine/practice{ pixel_x = 3; pixel_y = -3 }, diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index c4a4756f915..e7d1fcbf838 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -27278,7 +27278,7 @@ /area/station/medical/chemistry) "jOF" = ( /obj/structure/rack, -/obj/item/gun/energy/laser/practice{ +/obj/item/gun/energy/laser/carbine/practice{ pixel_x = 2; pixel_y = 5 }, diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index 60ccea505c0..996c2c57eef 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -71000,7 +71000,7 @@ "sEq" = ( /obj/structure/rack, /obj/effect/turf_decal/stripes, -/obj/item/gun/energy/laser/practice{ +/obj/item/gun/energy/laser/carbine/practice{ pixel_x = 3; pixel_y = -3 }, @@ -71931,7 +71931,7 @@ pixel_x = 3; pixel_y = -3 }, -/obj/item/gun/energy/laser/practice, +/obj/item/gun/energy/laser/carbine/practice, /obj/machinery/light/directional/north, /turf/open/floor/iron/dark, /area/station/security/range) diff --git a/_maps/map_files/VoidRaptor/VoidRaptor.dmm b/_maps/map_files/VoidRaptor/VoidRaptor.dmm index 2a630d0d647..a7e3c6d39a6 100644 --- a/_maps/map_files/VoidRaptor/VoidRaptor.dmm +++ b/_maps/map_files/VoidRaptor/VoidRaptor.dmm @@ -83880,6 +83880,7 @@ layer = 2.9; pixel_x = 4 }, +/obj/item/gun/energy/laser/carbine/practice, /turf/open/floor/engine, /area/station/security/range) "xmO" = ( @@ -85993,6 +85994,10 @@ /obj/structure/extinguisher_cabinet/directional/north{ pixel_x = 6 }, +/obj/item/gun/energy/laser/carbine/practice{ + pixel_x = -13; + pixel_y = -5 + }, /obj/machinery/firealarm/directional/north{ pixel_x = -7 }, diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 9096ac579a9..57b45da6803 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -15157,7 +15157,7 @@ /area/station/service/library/lounge) "ejJ" = ( /obj/structure/rack, -/obj/item/gun/energy/laser/practice{ +/obj/item/gun/energy/laser/carbine/practice{ pixel_x = 2; pixel_y = 5 }, diff --git a/_maps/templates/holodeck_firingrange.dmm b/_maps/templates/holodeck_firingrange.dmm index 67b6cd5e0d3..cb727801a05 100644 --- a/_maps/templates/holodeck_firingrange.dmm +++ b/_maps/templates/holodeck_firingrange.dmm @@ -122,6 +122,7 @@ "N" = ( /obj/structure/rack, /obj/item/gun/energy/laser/practice, +/obj/item/gun/energy/laser/carbine/practice, /obj/item/clothing/ears/earmuffs, /obj/effect/turf_decal/tile/green/half/contrasted, /turf/open/floor/holofloor, diff --git a/code/modules/projectiles/ammunition/energy/laser.dm b/code/modules/projectiles/ammunition/energy/laser.dm index 4f62af047d4..081f4166236 100644 --- a/code/modules/projectiles/ammunition/energy/laser.dm +++ b/code/modules/projectiles/ammunition/energy/laser.dm @@ -21,6 +21,11 @@ e_cost = 25 // 40 shots select_name = "kill" +/obj/item/ammo_casing/energy/lasergun/carbine/practice + projectile_type = /obj/projectile/beam/laser/carbine/practice + select_name = "practice" + harmful = FALSE + /obj/item/ammo_casing/energy/lasergun/old projectile_type = /obj/projectile/beam/laser e_cost = 200 diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 9ad095f67e0..94d58bb5e32 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -42,10 +42,20 @@ desc = "A modified laser gun which can shoot far faster, but each shot is far less damaging." icon_state = "laser_carbine" ammo_type = list(/obj/item/ammo_casing/energy/lasergun/carbine) + var/allow_akimbo = FALSE /obj/item/gun/energy/laser/carbine/Initialize(mapload) . = ..() - AddComponent(/datum/component/automatic_fire, 0.15 SECONDS, allow_akimbo = FALSE) + AddComponent(/datum/component/automatic_fire, 0.15 SECONDS, allow_akimbo = allow_akimbo) + +/obj/item/gun/energy/laser/carbine/practice + name = "practice laser carbine" + desc = "A modified version of the laser carbine, this one fires even less concentrated energy bolts designed for target practice." + ammo_type = list(/obj/item/ammo_casing/energy/lasergun/carbine/practice) + clumsy_check = FALSE + item_flags = NONE + gun_flags = NOT_A_REAL_GUN + allow_akimbo = TRUE /obj/item/gun/energy/laser/retro/old name ="laser gun" diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index d6c47531c91..a7a5f83329a 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -33,6 +33,11 @@ impact_effect_type = /obj/effect/temp_visual/impact_effect/yellow_laser damage = 10 +/obj/projectile/beam/laser/carbine/practice + name = "practice laser" + impact_effect_type = /obj/effect/temp_visual/impact_effect/yellow_laser + damage = 0 + //overclocked laser, does a bit more damage but has much higher wound power (-0 vs -20) /obj/projectile/beam/laser/hellfire name = "hellfire laser" From a0832a3262bc6cd007ad1b8b49b9e2a3494997a9 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 01:43:01 +0200 Subject: [PATCH 041/100] Adds a base physical description proc to gameplay species, displays it on magic mirrors. [MDB IGNORE] (#24260) * Adds a base physical description proc to gameplay species, displays it on magic mirrors. * Update podpeople.dm * Get this Skyrat edit out of here --------- Co-authored-by: carlarctg <53100513+carlarctg@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/game/objects/structures/mirror.dm | 28 +++++++++++++++++-- .../mob/living/carbon/human/_species.dm | 9 ++++++ .../carbon/human/species_types/abductors.dm | 5 ++++ .../carbon/human/species_types/android.dm | 5 ++++ .../carbon/human/species_types/dullahan.dm | 2 ++ .../carbon/human/species_types/ethereal.dm | 11 +++++++- .../carbon/human/species_types/felinid.dm | 4 +++ .../carbon/human/species_types/flypeople.dm | 3 ++ .../carbon/human/species_types/golems.dm | 4 +++ .../carbon/human/species_types/jellypeople.dm | 13 +++++++++ .../human/species_types/lizardpeople.dm | 13 +++++++++ .../carbon/human/species_types/monkeys.dm | 4 +++ .../carbon/human/species_types/mothmen.dm | 4 +++ .../carbon/human/species_types/plasmamen.dm | 4 +++ .../carbon/human/species_types/podpeople.dm | 10 ++----- .../human/species_types/shadowpeople.dm | 3 ++ .../carbon/human/species_types/skeletons.dm | 5 ++++ .../carbon/human/species_types/snail.dm | 5 ++++ .../carbon/human/species_types/vampire.dm | 4 +++ .../carbon/human/species_types/zombies.dm | 6 +++- .../carbon/human/species_type/podpeople.dm | 6 ++++ tgstation.dme | 1 + 22 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 modular_skyrat/master_files/code/modules/mob/living/carbon/human/species_type/podpeople.dm diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 08cdfab3e63..6072d905781 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -155,7 +155,17 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) if(!selectable_races[racechoice]) return TRUE - var/datum/species/newrace = selectable_races[racechoice] + + var/datum/species/newrace = new selectable_races[racechoice] + + var/attributes_desc = newrace.get_physical_attributes() + qdel(newrace) + + var/answer = tgui_alert(race_changer, attributes_desc, "Become a [newrace]?", list("Yes", "No")) + if(answer != "Yes") + change_race(race_changer) // try again + return + race_changer.set_species(newrace, icon_update = FALSE) if(HAS_TRAIT(race_changer, TRAIT_USES_SKINTONES)) var/new_s_tone = tgui_input_list(race_changer, "Choose your skin tone", "Race change", GLOB.skin_tones) @@ -320,7 +330,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) selectable_races = sort_list(selectable_races) //Magic mirrors can change hair color as well -/obj/structure/mirror/magic/mirror/change_hair(mob/living/carbon/human/user) +/obj/structure/mirror/magic/change_hair(mob/living/carbon/human/user) var/hairchoice = tgui_alert(user, "Hairstyle or hair color?", "Change Hair", list("Style", "Color")) if(hairchoice == "Style") //So you just want to use a mirror then? return ..() @@ -338,6 +348,20 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) user.update_body_parts() user.update_mutant_bodyparts(force_update = TRUE) /// SKYRAT EDIT ADDITION - Mirrors are no longer scared of colored ears +/obj/structure/mirror/magic/attack_hand(mob/living/carbon/human/user) + . = ..() + if(!.) + return TRUE + + if(HAS_TRAIT(user, TRAIT_ADVANCEDTOOLUSER) && HAS_TRAIT(user, TRAIT_LITERATE)) + return TRUE + + to_chat(user, span_alert("You feel quite intelligent.")) + // Prevents wizards from being soft locked out of everything + // If this stays after the species was changed once more, well, the magic mirror did it. It's magic i aint gotta explain shit + ADD_TRAIT(user, list(TRAIT_LITERATE, TRAIT_ADVANCEDTOOLUSER), SPECIES_TRAIT) + return TRUE + /obj/structure/mirror/magic/lesser/Initialize(mapload) // Roundstart species don't have a flag, so it has to be set on Initialize. selectable_races = get_selectable_species().Copy() diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 059ca18f4fa..22589f09440 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1905,12 +1905,21 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/proc/on_owner_login(mob/living/carbon/human/owner) return +/** + * Gets a description of the species' *physical* attributes. What makes playing as one different. Used in magic mirrors. + * + * Returns a string. + */ + +/datum/species/proc/get_physical_attributes() + return "An unremarkable species." /** * Gets a short description for the specices. Should be relatively succinct. * Used in the preference menu. * * Returns a string. */ + /datum/species/proc/get_species_description() SHOULD_CALL_PARENT(FALSE) diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm index 58a46da81a4..349742a15e5 100644 --- a/code/modules/mob/living/carbon/human/species_types/abductors.dm +++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm @@ -28,6 +28,11 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/abductor, ) + +/datum/species/abductor/get_physical_attributes() + return "Abductors do not need to breathe, eat, do not have blood, a heart, stomach, or lungs and cannot be infected by human viruses. \ + Their hardy physique prevents their skin from being wounded or dismembered, but their chunky tridactyl hands make it hard to operate human equipment." + /datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR] diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index e0da3a4ecbf..ed8163a1538 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -51,3 +51,8 @@ . = ..() // Androids don't eat, hunger or metabolise foods. Let's do some cleanup. C.set_safe_hunger_level() + +/datum/species/android/get_physical_attributes() + return "Androids are almost, but not quite, identical to fully augmented humans. \ + Unlike those, though, they're completely immune to toxin damage, don't have blood or organs (besides their head), don't get hungry, and can reattach their limbs! \ + That said, an EMP will devastate them and they cannot process any chemicals." diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index 4ea4b7f0c00..c9609f2d43b 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -114,6 +114,8 @@ eyes_toggle_perspective_action?.Trigger() owner_first_client_connection_handled = TRUE +/datum/species/dullahan/get_physical_attributes() + return "A dullahan is much like a human, but their head is detached from their body and must be carried around." /datum/species/dullahan/get_species_description() return "An angry spirit, hanging onto the land of the living for \ diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index 42c718477bc..4c28d190eff 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -209,6 +209,11 @@ 'sound/voice/ethereal/ethereal_scream_3.ogg', ) +/datum/species/ethereal/get_physical_attributes() + return "Ethereals process electricity as their power supply, not food, and are somewhat resistant to it.\ + They do so via their crystal core, their equivalent of a human heart, which will also encase them in a reviving crystal if they die.\ + However, their skin is very thin and easy to pierce with brute weaponry." + /datum/species/ethereal/get_species_description() return "Coming from the planet of Sprout, the theocratic ethereals are \ separated socially by caste, and espouse a dogma of aiding the weak and \ @@ -272,7 +277,7 @@ TRAIT_FIXED_MUTANT_COLORS, TRAIT_FIXED_HAIRCOLOR, TRAIT_AGENDER, - TRAIT_TENACIOUS, + TRAIT_TENACIOUS, // this doesn't work. tenacity is an element TRAIT_NOBREATH, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, @@ -287,6 +292,10 @@ BODY_ZONE_CHEST = /obj/item/bodypart/chest/ethereal, ) +/datum/species/ethereal/lustrous/get_physical_attributes() + return "Lustrous are what remains of an Ethereal after freebasing esoteric drugs. \ + They are pressure immune, virus immune, can see bluespace tears in reality, and have a really weird scream. They remain vulnerable to physical damage." + /datum/species/ethereal/lustrous/get_scream_sound(mob/living/carbon/human/ethereal) return pick( 'sound/voice/ethereal/lustrous_scream_1.ogg', diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index c8e14a6afd1..61647c5aba2 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -147,6 +147,10 @@ human_for_preview.update_body(TRUE) // SKYRAT EDIT END +/datum/species/human/felinid/get_physical_attributes() + return "Felinids are very similar to humans in almost all respects, with their biggest differences being the ability to lick their wounds, \ + and an increased sensitivity to noise, which is often detrimental. They are also rather fond of eating oranges." + /datum/species/human/felinid/get_species_description() return "Felinids are one of the many types of bespoke genetic \ modifications to come of humanity's mastery of genetic science, and are \ diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm index 7f1d1112115..c36252bbcb2 100644 --- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm @@ -37,6 +37,9 @@ return 30 //Flyswatters deal 30x damage to flypeople. return 1 +/datum/species/fly/get_physical_attributes() + return "These hideous creatures suffer from pesticide immensely, eat waste, and are incredibly vulnerable to bright lights. They do have wings though." + /datum/species/fly/get_species_description() return "With no official documentation or knowledge of the origin of \ this species, they remain a mystery to most. Any and all rumours among \ diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 3f5f46edf6c..91ec9dfe0c5 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -58,6 +58,10 @@ name += " [pick(GLOB.last_names)]" return name +/datum/species/golem/get_physical_attributes() + return "Golems are hardy creatures made out of stone, which are thus naturally resistant to many dangers, including asphyxiation, fire, radiation, electricity, and viruses.\ + They gain special abilities depending on the type of material consumed, but they need to consume material to keep their body animated." + /datum/species/golem/create_pref_unique_perks() var/list/to_add = list() diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 82f0e88c2bd..2f5c977110a 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -201,6 +201,11 @@ BODY_ZONE_CHEST = /obj/item/bodypart/chest/slime, ) +/datum/species/jelly/slime/get_physical_attributes() + return "Slimepeople have jelly for blood and their vacuoles can extremely quickly convert plasma to it if they're breathing it in.\ + They can then use the excess blood to split off an excess body, which their consciousness can transfer to at will or on death.\ + Most things that are toxic heal them, but most things that prevent toxicity damage them!" + /datum/species/jelly/slime/on_species_loss(mob/living/carbon/C) if(slime_split) slime_split.Remove(C) @@ -501,6 +506,10 @@ /// The cooldown of us using exteracts COOLDOWN_DECLARE(extract_cooldown) +/datum/species/jelly/luminescent/get_physical_attributes() + return "Luminescent are able to integrate slime extracts into themselves for wondrous effects. \ + Most things that are toxic heal them, but most things that prevent toxicity damage them!" + //Species datums don't normally implement destroy, but JELLIES SUCK ASS OUT OF A STEEL STRAW and have to i guess /datum/species/jelly/luminescent/Destroy(force) current_extract = null @@ -670,6 +679,10 @@ /// Special "project thought" telepathy action for stargazers. var/datum/action/innate/project_thought/project_action +/datum/species/jelly/stargazer/get_physical_attributes() + return "Stargazers can link others' minds with their own, creating a private communication channel. \ + Most things that are toxic heal them, but most things that prevent toxicity damage them!" + /datum/species/jelly/stargazer/on_species_gain(mob/living/carbon/grant_to, datum/species/old_species) . = ..() project_action = new(src) diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 68420fe460f..020cd7b4ebf 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -89,6 +89,10 @@ 'sound/voice/lizard/lizard_scream_3.ogg', ) +/datum/species/lizard/get_physical_attributes() + return "Lizardpeople can withstand slightly higher temperatures than most species, but they are very vulnerable to the cold \ + and can't regulate their body-temperature internally, making the vacuum of space extremely deadly to them." + /datum/species/lizard/get_species_description() return "The militaristic Lizardpeople hail originally from Tizira, but have grown \ throughout their centuries in the stars to possess a large spacefaring \ @@ -155,6 +159,10 @@ Lizard subspecies: ASHWALKERS BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/lizard, ) +/datum/species/lizard/get_physical_attributes() + return "Ash Walkers are identical to lizardpeople in almost all aspects. \ + Unlike them, they're always digitigrade, they can breathe Lavaland's often noxious atmosphere and resist viruses. They are usually illiterate." + /* Lizard subspecies: SILVER SCALED */ @@ -184,6 +192,11 @@ Lizard subspecies: SILVER SCALED ///See above var/old_eye_color_right +/datum/species/lizard/silverscale/get_physical_attributes() + return "Silver Scales are to lizardpeople what angels are to humans. \ + Mostly identical, they are holy, don't breathe, don't get viruses, their hide cannot be pierced, love the taste of wine, \ + and their tongue allows them to turn into a statue, for some reason." + /datum/species/lizard/silverscale/on_species_gain(mob/living/carbon/human/new_silverscale, datum/species/old_species, pref_load) old_mutcolor = new_silverscale.dna.features["mcolor"] old_eye_color_left = new_silverscale.eye_color_left diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index 243c1be83b3..2d054c67c71 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -133,6 +133,10 @@ 'sound/creatures/monkey/monkey_screech_7.ogg', ) +/datum/species/monkey/get_physical_attributes() + return "Monkeys are slippery, can crawl into vents, and are more dextrous than humans.. but only when stealing things. \ + Natural monkeys cannot operate machinery or most tools with their paws, but unusually clever monkeys or those that were once something else can." + /datum/species/monkey/get_species_description() return "Monkeys are a type of primate that exist between humans and animals on the evolutionary chain. \ Every year, on Monkey Day, Nanotrasen shows their respect for the little guys by allowing them to roam the station freely." diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index 050e79b70bf..adb5ffa62aa 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -59,6 +59,10 @@ /datum/species/moth/get_scream_sound(mob/living/carbon/human/human) return 'sound/voice/moth/scream_moth.ogg' +/datum/species/moth/get_physical_attributes() + return "Moths have large and fluffy wings, which help them navigate the station if gravity is offline by pushing the air around them. \ + Due to that, it isn't of much use out in space. Their eyes are very sensitive." + /datum/species/moth/get_species_description() return "Hailing from a planet that was lost long ago, the moths travel \ the galaxy as a nomadic people aboard a colossal fleet of ships, seeking a new homeland." diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 910c10a099a..67f57f75a5a 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -145,6 +145,10 @@ 'sound/voice/plasmaman/plasmeme_scream_3.ogg', ) +/datum/species/plasmaman/get_physical_attributes() + return "Plasmamen literally breathe and live plasma. They spontaneously combust on contact with oxygen, and besides all the quirks that go with that, \ + they're very vulnerable to all kinds of physical damage due to their brittle structure." + /datum/species/plasmaman/get_species_description() return "Found on the Icemoon of Freyja, plasmamen consist of colonial \ fungal organisms which together form a sentient being. In human space, \ diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index bab1bae6e36..0b645fd120a 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -74,13 +74,9 @@ if(chem.type == /datum/reagent/toxin/plantbgone) affected.adjustToxLoss(3 * REM * seconds_per_tick) -// SKYRAT EDIT ADDITION -/datum/species/pod/get_species_description() - return "Plant lore!" - -/datum/species/pod/get_species_lore() - return list("You're a plant!") -// SKYRAT EDIT END +/datum/species/pod/get_physical_attributes() + return "Podpeople are in many ways the inverse of shadows, healing in light and starving with the dark. \ + Their bodies are like tinder and easy to char." /datum/species/pod/create_pref_unique_perks() var/list/to_add = list() diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index a8b1be203a3..1bd77a4356f 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -37,6 +37,9 @@ return TRUE return ..() +/datum/species/shadow/get_physical_attributes() + return "These cursed creatures heal in the dark, but suffer in the light much more heavily. Their eyes let them see in the dark as though it were day." + /datum/species/shadow/get_species_description() return "Victims of a long extinct space alien. Their flesh is a sickly \ seethrough filament, their tangled insides in clear view. Their form \ diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index 3ac0483f8ce..67051c20607 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -56,6 +56,11 @@ return TRUE return ..() +/datum/species/skeleton/get_physical_attributes() + return "These humerus folk lack any fleshy biology, which allows them to resist pressure, temperature, radiation, asphyxiation and even toxins. \ + However, due to that same fact, it is quite hard to heal them as well. The calcium found in common space milk is highly effective at treating their wounds. \ + Their limbs are easy to pop off their joints, but they can somehow just slot them back in." + /datum/species/skeleton/get_species_description() return "A rattling skeleton! They descend upon Space Station 13 \ Every year to spook the crew! \"I've got a BONE to pick with you!\"" diff --git a/code/modules/mob/living/carbon/human/species_types/snail.dm b/code/modules/mob/living/carbon/human/species_types/snail.dm index 689a02cfbec..036b5ad5c24 100644 --- a/code/modules/mob/living/carbon/human/species_types/snail.dm +++ b/code/modules/mob/living/carbon/human/species_types/snail.dm @@ -28,6 +28,11 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/snail ) + +/datum/species/snail/get_physical_attributes() + return "Snailpeople emit a viscous, slippery ooze when crawling along the ground, which they are somewhat faster at than other species. \ + They are almost purely made of water, making them extremely susceptible to shocks, and salt will scour them heavily." + /datum/species/snail/handle_chemical(datum/reagent/chem, mob/living/carbon/human/affected, seconds_per_tick, times_fired) . = ..() if(. & COMSIG_MOB_STOP_REAGENT_CHECK) diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 46d507e4999..c07f0478c03 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -69,6 +69,10 @@ return 2 //Whips deal 2x damage to vampires. Vampire killer. return 1 +/datum/species/vampire/get_physical_attributes() + return "Vampires are afflicted with the Thirst, needing to sate it by draining the blood out of another living creature. However, they do not need to breathe or eat normally. \ + They will instantly turn into dust if they run out of blood or enter a holy area. However, coffins stabilize and heal them, and they can transform into bats!" + /datum/species/vampire/get_species_description() return "A classy Vampire! They descend upon Space Station Thirteen Every year to spook the crew! \"Bleeg!!\"" diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 273d7c83422..4f9b6f1b4af 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -66,6 +66,10 @@ return TRUE return ..() +/datum/species/zombie/get_physical_attributes() + return "Zombies are undead, and thus completely immune to any enviromental hazard, or any physical threat besides blunt force trauma and burns. \ + Their limbs are easy to pop off their joints, but they can somehow just slot them back in." + /datum/species/zombie/get_species_description() return "A rotting zombie! They descend upon Space Station Thirteen Every year to spook the crew! \"Sincerely, the Zombies!\"" @@ -195,7 +199,7 @@ // Your skin falls off /datum/species/human/krokodil_addict - name = "\improper Human" + name = "\improper Krokodil Human" id = SPECIES_ZOMBIE_KROKODIL examine_limb_id = SPECIES_HUMAN changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN diff --git a/modular_skyrat/master_files/code/modules/mob/living/carbon/human/species_type/podpeople.dm b/modular_skyrat/master_files/code/modules/mob/living/carbon/human/species_type/podpeople.dm new file mode 100644 index 00000000000..012665829fd --- /dev/null +++ b/modular_skyrat/master_files/code/modules/mob/living/carbon/human/species_type/podpeople.dm @@ -0,0 +1,6 @@ +// Character creation podpeople +/datum/species/pod/get_species_description() + return "Plant lore!" + +/datum/species/pod/get_species_lore() + return list("You're a plant!") diff --git a/tgstation.dme b/tgstation.dme index 47afbc9609e..ea2c24af9ee 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6183,6 +6183,7 @@ #include "modular_skyrat\master_files\code\modules\mob\living\carbon\human\death.dm" #include "modular_skyrat\master_files\code\modules\mob\living\carbon\human\species.dm" #include "modular_skyrat\master_files\code\modules\mob\living\carbon\human\species_type\lizardpeople.dm" +#include "modular_skyrat\master_files\code\modules\mob\living\carbon\human\species_type\podpeople.dm" #include "modular_skyrat\master_files\code\modules\mob\living\carbon\human\species_type\snail.dm" #include "modular_skyrat\master_files\code\modules\mob\living\human\monkey.dm" #include "modular_skyrat\master_files\code\modules\mob\living\human\species.dm" From aca0baee643d7fb0b1670d0082056b69a19608d3 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 01:55:28 +0200 Subject: [PATCH 042/100] `sting_action` `SHOULD_CALL_PARENT`, fixes various stings not blackbox logging [MDB IGNORE] (#24090) * `sting_action` `SHOULD_CALL_PARENT`, fixes various stings not blackbox logging * Update tiny_prick.dm * Update horror_form.dm --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- .../changeling/changeling_power.dm | 1 + .../antagonists/changeling/powers/absorb.dm | 2 + .../changeling/powers/biodegrade.dm | 39 +++++++++++-------- .../changeling/powers/tiny_prick.dm | 32 +++++++++------ .../modules/horrorform/code/horror_form.dm | 1 + 5 files changed, 47 insertions(+), 28 deletions(-) diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm index ee2001bfe03..0e76128ee08 100644 --- a/code/modules/antagonists/changeling/changeling_power.dm +++ b/code/modules/antagonists/changeling/changeling_power.dm @@ -75,6 +75,7 @@ the same goes for Remove(). if you override Remove(), call parent or else your p return FALSE /datum/action/changeling/proc/sting_action(mob/living/user, mob/living/target) + SHOULD_CALL_PARENT(TRUE) SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]")) return FALSE diff --git a/code/modules/antagonists/changeling/powers/absorb.dm b/code/modules/antagonists/changeling/powers/absorb.dm index cee0f0da5b9..1fdb50a7bab 100644 --- a/code/modules/antagonists/changeling/powers/absorb.dm +++ b/code/modules/antagonists/changeling/powers/absorb.dm @@ -28,6 +28,8 @@ return changeling.can_absorb_dna(target) /datum/action/changeling/absorb_dna/sting_action(mob/owner) + SHOULD_CALL_PARENT(FALSE) // the only reason to call parent is for proper blackbox logging, and we do that ourselves in a snowflake way + var/datum/antagonist/changeling/changeling = owner.mind.has_antag_datum(/datum/antagonist/changeling) var/mob/living/carbon/human/target = owner.pulling is_absorbing = TRUE diff --git a/code/modules/antagonists/changeling/powers/biodegrade.dm b/code/modules/antagonists/changeling/powers/biodegrade.dm index 16bd707831b..eba507ad5e0 100644 --- a/code/modules/antagonists/changeling/powers/biodegrade.dm +++ b/code/modules/antagonists/changeling/powers/biodegrade.dm @@ -8,11 +8,6 @@ req_human = TRUE /datum/action/changeling/biodegrade/sting_action(mob/living/carbon/human/user) - var/used = FALSE // only one form of shackles removed per use - if(!HAS_TRAIT(user, TRAIT_RESTRAINED) && !user.legcuffed && isopenturf(user.loc)) - user.balloon_alert(user, "already free!") - return FALSE - if(user.handcuffed) var/obj/O = user.get_item_by_slot(ITEM_SLOT_HANDCUFFED) if(!istype(O)) @@ -21,7 +16,9 @@ span_warning("We vomit acidic ooze onto our restraints!")) addtimer(CALLBACK(src, PROC_REF(dissolve_handcuffs), user, O), 30) - used = TRUE + log_combat(user, user.handcuffed, "melted handcuffs", addition = "(biodegrade)") + ..() + return TRUE if(user.legcuffed) var/obj/O = user.get_item_by_slot(ITEM_SLOT_LEGCUFFED) @@ -31,37 +28,45 @@ span_warning("We vomit acidic ooze onto our restraints!")) addtimer(CALLBACK(src, PROC_REF(dissolve_legcuffs), user, O), 30) - used = TRUE + log_combat(user, user.legcuffed, "melted legcuffs", addition = "(biodegrade)") + ..() + return TRUE - if(user.wear_suit && user.wear_suit.breakouttime && !used) + if(user.wear_suit?.breakouttime) var/obj/item/clothing/suit/S = user.get_item_by_slot(ITEM_SLOT_OCLOTHING) if(!istype(S)) return FALSE user.visible_message(span_warning("[user] vomits a glob of acid across the front of [user.p_their()] [S]!"), \ - span_warning("We vomit acidic ooze onto our straight jacket!")) + span_warning("We vomit acidic ooze onto our [user.wear_suit.name]!")) addtimer(CALLBACK(src, PROC_REF(dissolve_straightjacket), user, S), 30) - used = TRUE - + log_combat(user, user.wear_suit, "melted [user.wear_suit]", addition = "(biodegrade)") + ..() + return TRUE - if(istype(user.loc, /obj/structure/closet) && !used) + if(istype(user.loc, /obj/structure/closet)) var/obj/structure/closet/C = user.loc if(!istype(C)) return FALSE C.visible_message(span_warning("[C]'s hinges suddenly begin to melt and run!")) to_chat(user, span_warning("We vomit acidic goop onto the interior of [C]!")) addtimer(CALLBACK(src, PROC_REF(open_closet), user, C), 70) - used = TRUE + log_combat(user, user.loc, "melted locker", addition = "(biodegrade)") + ..() + return TRUE - if(istype(user.loc, /obj/structure/spider/cocoon) && !used) + if(istype(user.loc, /obj/structure/spider/cocoon)) var/obj/structure/spider/cocoon/C = user.loc if(!istype(C)) return FALSE C.visible_message(span_warning("[src] shifts and starts to fall apart!")) to_chat(user, span_warning("We secrete acidic enzymes from our skin and begin melting our cocoon...")) addtimer(CALLBACK(src, PROC_REF(dissolve_cocoon), user, C), 25) //Very short because it's just webs - used = TRUE - ..() - return used + log_combat(user, user.loc, "melted cocoon", addition = "(biodegrade)") + ..() + return TRUE + + user.balloon_alert(user, "already free!") + return FALSE /datum/action/changeling/biodegrade/proc/dissolve_handcuffs(mob/living/carbon/human/user, obj/O) if(O && user.handcuffed == O) diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm index 412307e33ce..83dc308022c 100644 --- a/code/modules/antagonists/changeling/powers/tiny_prick.dm +++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -100,18 +100,22 @@ return FALSE return TRUE -/datum/action/changeling/sting/transformation/sting_action(mob/user, mob/target) - log_combat(user, target, "stung", "transformation sting", " new identity is '[selected_dna.dna.real_name]'") - var/datum/dna/NewDNA = selected_dna.dna - - var/mob/living/carbon/C = target - . = TRUE - if(istype(C)) - C.real_name = NewDNA.real_name - NewDNA.transfer_identity(C) - C.updateappearance(mutcolor_update=1) +/datum/action/changeling/sting/transformation/sting_action(mob/living/user, mob/living/target) + var/final_duration = sting_duration + var/final_message = span_notice("We transform [target] into [selected_dna.dna.real_name].") + if(ismonkey(target)) + final_duration = INFINITY + final_message = span_warning("Our genes cry out as we transform the lesser form of [target] into [selected_dna.dna.real_name] permanently!") + + if(target.apply_status_effect(/datum/status_effect/temporary_transformation/trans_sting, final_duration, selected_dna.dna)) + ..() + log_combat(user, target, "stung", "transformation sting", " new identity is '[selected_dna.dna.real_name]'") + to_chat(user, final_message) + return TRUE + return FALSE */ //SKYRAT EDIT REMOVAL END + /datum/action/changeling/sting/false_armblade name = "False Armblade Sting" desc = "We silently sting a human, injecting a retrovirus that mutates their arm to temporarily appear as an armblade. Costs 20 chemicals." @@ -136,13 +140,14 @@ return TRUE /datum/action/changeling/sting/false_armblade/sting_action(mob/user, mob/target) - log_combat(user, target, "stung", object="false armblade sting") var/obj/item/held = target.get_active_held_item() if(held && !target.dropItemToGround(held)) to_chat(user, span_warning("[held] is stuck to [target.p_their()] hand, you cannot grow a false armblade over it!")) return + ..() + log_combat(user, target, "stung", object = "false armblade sting") if(ismonkey(target)) to_chat(user, span_notice("Our genes cry out as we sting [target.name]!")) @@ -178,6 +183,7 @@ return changeling.can_absorb_dna(target) /datum/action/changeling/sting/extract_dna/sting_action(mob/user, mob/living/carbon/human/target) + ..() log_combat(user, target, "stung", "extraction sting") var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) if(!changeling.has_profile_with_dna(target.dna)) @@ -193,6 +199,7 @@ dna_cost = 2 /datum/action/changeling/sting/mute/sting_action(mob/user, mob/living/carbon/target) + ..() log_combat(user, target, "stung", "mute sting") target.adjust_silence(1 MINUTES) return TRUE @@ -215,6 +222,7 @@ user.balloon_alert(user, "robotic eyes!") return FALSE + ..() log_combat(user, target, "stung", "blind sting") to_chat(target, span_danger("Your eyes burn horrifically!")) eyes.apply_organ_damage(eyes.maxHealth * 0.8) @@ -232,6 +240,7 @@ dna_cost = 1 /datum/action/changeling/sting/lsd/sting_action(mob/user, mob/living/carbon/target) + ..() log_combat(user, target, "stung", "LSD sting") addtimer(CALLBACK(src, PROC_REF(hallucination_time), target), rand(30 SECONDS, 60 SECONDS)) return TRUE @@ -250,6 +259,7 @@ dna_cost = 2 /datum/action/changeling/sting/cryo/sting_action(mob/user, mob/target) + ..() log_combat(user, target, "stung", "cryo sting") if(target.reagents) target.reagents.add_reagent(/datum/reagent/consumable/frostoil, 30) diff --git a/modular_skyrat/modules/horrorform/code/horror_form.dm b/modular_skyrat/modules/horrorform/code/horror_form.dm index b99f4360c35..9e6ea71ad73 100644 --- a/modular_skyrat/modules/horrorform/code/horror_form.dm +++ b/modular_skyrat/modules/horrorform/code/horror_form.dm @@ -14,6 +14,7 @@ req_stat = UNCONSCIOUS /datum/action/changeling/horror_form/sting_action(mob/living/carbon/human/user) + ..() if(!user || HAS_TRAIT(user, TRAIT_NO_TRANSFORM)) return 0 user.visible_message(span_warning("[user] writhes and contorts, their body expanding to inhuman proportions!"), \ From ea0115c287b5734e5dabca9d23b1a12d58e80767 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 01:59:07 +0200 Subject: [PATCH 043/100] Replaces the changeling spacesuit with a passive ability [MDB IGNORE] (#24236) * Replaces the changeling spacesuit with a passive ability (#78763) ## About The Pull Request Fixes #74168 I was going to make changes to the changeling spacesuit so that it works on Icebox but then I thought, why not _not_ do that. This isn't a commonly picked adaption so why don't we make it a little better. What's more spooky, hearing a knock on the window and seeing a fat suit outside? Or this? ![image](https://github.com/tgstation/tgstation/assets/7483112/b87dec0c-5e98-45a5-8f83-f7a2967c743f) Picking Void Adaption will now make you immune to low temperature and pressure (but not high temperature and pressure) and you will stop breathing. If you enter an area with low temperature or pressure then your chemical regeneration rate will decrease until you leave that area. Because it doesn't put a suit on you, it now also works during Lesser Form. While testing this I noticed that we weren't calling `Grant` on passive changeling abilities for some reason, I replaced that with the already-written interface for making "an action which doesn't give you a button". If people really _really_ miss the fat suit I guess I'll rework that instead, but I think I like this more. ## Why It's Good For The Game Makes a niche-pick ability more useful and easier to use. Meteor Changelings who land on Icebox now don't roll a dice to see if they get instantly knocked out by the atmosphere there. ## Changelog :cl: balance: The Changeling Space Suit has been replaced by a new ability which makes you passively spaceproof without replacing your clothing. admin: Editing the atmos sensitivity variables on a basic mob during the game will now actually do something. /:cl: * Replaces the changeling spacesuit with a passive ability * Fix screenshot test --------- Co-authored-by: Jacquerel Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> --- .../antagonists/changeling/changeling.dm | 8 +- .../changeling/changeling_power.dm | 5 +- .../changeling/powers/defib_grasp.dm | 2 +- .../changeling/powers/mutations.dm | 72 ------------------ .../changeling/powers/void_adaption.dm | 68 +++++++++++++++++ code/modules/meteors/meteor_spawning.dm | 2 +- code/modules/mob/living/basic/basic.dm | 48 +++++++++--- ...eenshot_antag_icons_changelingmidround.png | Bin 690 -> 631 bytes tgstation.dme | 1 + 9 files changed, 113 insertions(+), 93 deletions(-) create mode 100644 code/modules/antagonists/changeling/powers/void_adaption.dm diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 5c44acd5fc0..9fd948be2fe 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -372,12 +372,11 @@ /datum/antagonist/changeling/proc/regain_powers() emporium_action.Grant(owner.current) for(var/datum/action/changeling/power as anything in innate_powers) - if(power.needs_button) - power.Grant(owner.current) + power.Grant(owner.current) for(var/power_path in purchased_powers) var/datum/action/changeling/power = purchased_powers[power_path] - if(istype(power) && power.needs_button) + if(istype(power)) power.Grant(owner.current) /* @@ -1151,9 +1150,6 @@ /datum/outfit/changeling_space name = "Changeling (Space)" - - head = /obj/item/clothing/head/helmet/space/changeling - suit = /obj/item/clothing/suit/space/changeling l_hand = /obj/item/melee/arm_blade #undef FORMAT_CHEM_CHARGES_TEXT diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm index 0e76128ee08..a4d9044d977 100644 --- a/code/modules/antagonists/changeling/changeling_power.dm +++ b/code/modules/antagonists/changeling/changeling_power.dm @@ -7,8 +7,6 @@ background_icon_state = "bg_changeling" overlay_icon_state = "bg_changeling_border" button_icon = 'icons/mob/actions/actions_changeling.dmi' - /// For passive abilities like hivemind that dont need an action button - var/needs_button = TRUE /// Details displayed in fine print within the changling emporium var/helptext = "" /// How many changeling chems it costs to use @@ -44,8 +42,7 @@ the same goes for Remove(). if you override Remove(), call parent or else your p /datum/action/changeling/proc/on_purchase(mob/user, is_respec) if(!is_respec) SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, name) - if(needs_button) - Grant(user)//how powers are added rather than the checks in mob.dm + Grant(user)//how powers are added rather than the checks in mob.dm /datum/action/changeling/Trigger(trigger_flags) var/mob/user = owner diff --git a/code/modules/antagonists/changeling/powers/defib_grasp.dm b/code/modules/antagonists/changeling/powers/defib_grasp.dm index 20ff3049c8f..135b9b243f7 100644 --- a/code/modules/antagonists/changeling/powers/defib_grasp.dm +++ b/code/modules/antagonists/changeling/powers/defib_grasp.dm @@ -4,7 +4,7 @@ we will snatch their arms off and instantly finalize our stasis." helptext = "This ability is passive, and will trigger when a defibrillator paddle is applied to our chest \ while we are dead or in stasis. Will also stun cyborgs momentarily." - needs_button = FALSE + owner_has_control = FALSE dna_cost = 0 /// Flags to pass to fully heal when we get zapped diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index bf4f8c2b3da..54027b7d8a2 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -480,78 +480,6 @@ remaining_uses-- return ..() - -/***************************************\ -|*********SPACE SUIT + HELMET***********| -\***************************************/ -/datum/action/changeling/suit/organic_space_suit - name = "Organic Space Suit" - desc = "We grow an organic suit to protect ourselves from space exposure, including regulation of temperature and oxygen needs. Costs 20 chemicals." - helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Cannot be used in lesser form." - button_icon_state = "organic_suit" - chemical_cost = 20 - dna_cost = 2 - req_human = TRUE - - suit_type = /obj/item/clothing/suit/space/changeling - helmet_type = /obj/item/clothing/head/helmet/space/changeling - suit_name_simple = "flesh shell" - helmet_name_simple = "space helmet" - recharge_slowdown = 0.25 - blood_on_castoff = 1 - -/obj/item/clothing/suit/space/changeling - name = "flesh mass" - icon_state = "lingspacesuit_t" - icon = 'icons/obj/clothing/suits/costume.dmi' - worn_icon = 'icons/mob/clothing/suits/costume.dmi' - desc = "A huge, bulky mass of pressure and temperature-resistant organic tissue, evolved to facilitate space travel." - item_flags = DROPDEL - clothing_flags = STOPSPRESSUREDAMAGE //Not THICKMATERIAL because it's organic tissue, so if somebody tries to inject something into it, it still ends up in your blood. (also balance but muh fluff) - allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/oxygen) - armor_type = /datum/armor/space_changeling - actions_types = list() - cell = null - show_hud = FALSE - -/datum/armor/space_changeling - bio = 100 - fire = 90 - acid = 90 - -/obj/item/clothing/suit/space/changeling/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT) - if(ismob(loc)) - loc.visible_message(span_warning("[loc.name]\'s flesh rapidly inflates, forming a bloated mass around [loc.p_their()] body!"), span_warning("We inflate our flesh, creating a spaceproof suit!"), span_hear("You hear organic matter ripping and tearing!")) - START_PROCESSING(SSobj, src) - -// seal the cell door -/obj/item/clothing/suit/space/changeling/toggle_spacesuit_cell(mob/user) - return - -/obj/item/clothing/suit/space/changeling/process(seconds_per_tick) - if(ishuman(loc)) - var/mob/living/carbon/human/H = loc - H.reagents.add_reagent(/datum/reagent/medicine/salbutamol, REAGENTS_METABOLISM * (seconds_per_tick / SSMOBS_DT)) - H.adjust_bodytemperature(temperature_setting - H.bodytemperature) // force changelings to normal temp step mode played badly - -/obj/item/clothing/head/helmet/space/changeling - name = "flesh mass" - icon = 'icons/obj/clothing/head/costume.dmi' - worn_icon = 'icons/mob/clothing/head/costume.dmi' - icon_state = "lingspacehelmet" - inhand_icon_state = null - desc = "A covering of pressure and temperature-resistant organic tissue with a glass-like chitin front." - item_flags = DROPDEL - clothing_flags = STOPSPRESSUREDAMAGE | HEADINTERNALS - armor_type = /datum/armor/space_changeling - flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH - -/obj/item/clothing/head/helmet/space/changeling/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT) - /***************************************\ |*****************ARMOR*****************| \***************************************/ diff --git a/code/modules/antagonists/changeling/powers/void_adaption.dm b/code/modules/antagonists/changeling/powers/void_adaption.dm new file mode 100644 index 00000000000..76c0eeffc97 --- /dev/null +++ b/code/modules/antagonists/changeling/powers/void_adaption.dm @@ -0,0 +1,68 @@ +/datum/action/changeling/void_adaption + name = "Void Adaption" + desc = "We prepare our cells to resist the hostile environment outside of the station. We may freely travel wherever we wish." + helptext = "This ability is passive, and will automatically protect you in situations of extreme cold or vacuum, \ + as well as removing your need to breathe. While it is actively protecting you from temperature or pressure \ + it reduces your chemical regeneration rate." + owner_has_control = FALSE + dna_cost = 2 + + /// Traits we apply to become immune to the environment + var/static/list/gain_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD, TRAIT_RESISTLOWPRESSURE, TRAIT_SNOWSTORM_IMMUNE) + /// How much we slow chemical regeneration while active, in chems per second + var/recharge_slowdown = 0.25 + /// Are we currently protecting our user? + var/currently_active = FALSE + +/datum/action/changeling/void_adaption/on_purchase(mob/user, is_respec) + . = ..() + user.add_traits(gain_traits, REF(src)) + RegisterSignal(user, COMSIG_LIVING_LIFE, PROC_REF(check_environment)) + +/datum/action/changeling/void_adaption/Remove(mob/remove_from) + remove_from.remove_traits(gain_traits, REF(src)) + UnregisterSignal(remove_from, COMSIG_LIVING_LIFE) + if (currently_active) + on_removed_adaption(remove_from, "Our cells relax, despite the danger!") + return ..() + +/// Checks if we would be providing any useful benefit at present +/datum/action/changeling/void_adaption/proc/check_environment(mob/living/void_adapted) + SIGNAL_HANDLER + + var/list/active_reasons = list() + + var/datum/gas_mixture/environment = void_adapted.loc.return_air() + if (!isnull(environment)) + var/vulnerable_temperature = void_adapted.get_body_temp_cold_damage_limit() + var/affected_temperature = environment.return_temperature() + if (ishuman(void_adapted)) + var/mob/living/carbon/human/special_boy = void_adapted + var/cold_protection = special_boy.get_cold_protection(affected_temperature) + vulnerable_temperature *= (1 - cold_protection) + + var/affected_pressure = special_boy.calculate_affecting_pressure(environment.return_pressure()) + if (affected_pressure < HAZARD_LOW_PRESSURE) + active_reasons += "vacuum" + + if (affected_temperature < vulnerable_temperature) + active_reasons += "cold" + + var/should_be_active = !!length(active_reasons) + if (currently_active == should_be_active) + return + + if (!should_be_active) + on_removed_adaption(void_adapted, "Our cells relax in safer air.") + return + var/datum/antagonist/changeling/changeling_data = void_adapted.mind?.has_antag_datum(/datum/antagonist/changeling) + to_chat(void_adapted, span_changeling("Our cells harden themselves against the [pick(active_reasons)].")) + changeling_data?.chem_recharge_slowdown -= recharge_slowdown + currently_active = TRUE + +/// Called when we stop being adapted +/datum/action/changeling/void_adaption/proc/on_removed_adaption(mob/living/former, message) + var/datum/antagonist/changeling/changeling_data = former.mind?.has_antag_datum(/datum/antagonist/changeling) + to_chat(former, span_changeling(message)) + changeling_data?.chem_recharge_slowdown += recharge_slowdown + currently_active = FALSE diff --git a/code/modules/meteors/meteor_spawning.dm b/code/modules/meteors/meteor_spawning.dm index eac365bc2a8..97c359d03bf 100644 --- a/code/modules/meteors/meteor_spawning.dm +++ b/code/modules/meteors/meteor_spawning.dm @@ -109,7 +109,7 @@ new_changeling.log_message("was spawned as a midround space changeling by an event.", LOG_GAME) var/datum/antagonist/changeling/changeling_datum = locate() in player_mind.antag_datums - changeling_datum.give_power(/datum/action/changeling/suit/organic_space_suit) + changeling_datum.give_power(/datum/action/changeling/void_adaption) changeling_datum.give_power(/datum/action/changeling/weapon/arm_blade) new_changeling.equipOutfit(/datum/outfit/changeling_space) diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index aebb54770d7..ab8daf47635 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -117,13 +117,23 @@ if(speak_emote) speak_emote = string_list(speak_emote) - if(unsuitable_atmos_damage != 0) - //String assoc list returns a cached list, so this is like a static list to pass into the element below. - habitable_atmos = string_assoc_list(habitable_atmos) - AddElement(/datum/element/atmos_requirements, habitable_atmos, unsuitable_atmos_damage) + apply_atmos_requirements() + apply_temperature_requirements() + +/// Ensures this mob can take atmospheric damage if it's supposed to +/mob/living/basic/proc/apply_atmos_requirements() + if(unsuitable_atmos_damage == 0) + return + //String assoc list returns a cached list, so this is like a static list to pass into the element below. + habitable_atmos = string_assoc_list(habitable_atmos) + AddElement(/datum/element/atmos_requirements, habitable_atmos, unsuitable_atmos_damage) + +/// Ensures this mob can take temperature damage if it's supposed to +/mob/living/basic/proc/apply_temperature_requirements() + if(unsuitable_cold_damage == 0 && unsuitable_heat_damage == 0) + return + AddElement(/datum/element/basic_body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage) - if(unsuitable_cold_damage != 0 && unsuitable_heat_damage != 0) - AddElement(/datum/element/basic_body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage) /mob/living/basic/Life(seconds_per_tick = SSMOBS_DT, times_fired) . = ..() @@ -207,10 +217,24 @@ melee_attack(attack_target, modifiers) /mob/living/basic/vv_edit_var(vname, vval) + switch(vname) + if(NAMEOF(src, habitable_atmos), NAMEOF(src, unsuitable_atmos_damage)) + RemoveElement(/datum/element/atmos_requirements, habitable_atmos, unsuitable_atmos_damage) + . = TRUE + if(NAMEOF(src, minimum_survivable_temperature), NAMEOF(src, maximum_survivable_temperature), NAMEOF(src, unsuitable_cold_damage), NAMEOF(src, unsuitable_heat_damage)) + RemoveElement(/datum/element/basic_body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage) + . = TRUE + . = ..() - if(vname == NAMEOF(src, speed)) - datum_flags |= DF_VAR_EDITED - set_varspeed(vval) + + switch(vname) + if(NAMEOF(src, habitable_atmos), NAMEOF(src, unsuitable_atmos_damage)) + apply_atmos_requirements() + if(NAMEOF(src, minimum_survivable_temperature), NAMEOF(src, maximum_survivable_temperature), NAMEOF(src, unsuitable_cold_damage), NAMEOF(src, unsuitable_heat_damage)) + apply_temperature_requirements() + if(NAMEOF(src, speed)) + datum_flags |= DF_VAR_EDITED + set_varspeed(vval) /mob/living/basic/proc/set_varspeed(var_value) speed = var_value @@ -260,3 +284,9 @@ else if(on_fire && !isnull(last_icon_state)) return last_icon_state return null + +/mob/living/basic/get_body_temp_heat_damage_limit() + return maximum_survivable_temperature + +/mob/living/basic/get_body_temp_cold_damage_limit() + return minimum_survivable_temperature diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_changelingmidround.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_changelingmidround.png index ac412207c236df0ca79fe8f738b6edfa1671beca..d002f7466675bdb6e61023187812a8d2c281a75b 100644 GIT binary patch delta 493 zcmVcgPLl}<{{R3gDk@uBTY7qWe;vf4k$8ZAh)G02R9J=Wma$62KoEwL%GOah zY%khadUFP}J6wE&dw@fk!%h&~)^ZCAOSiL>^%0`r1LOfLyxztU3)K*XGE!>|Z$ z2iDpJ128xsrldyBnX7*SV%p@NrMvKuBw6O}+5}+8sPD**axTkg%hW}xaR8|nA;RSs z3VSK6hZylCHFt##Wp00000NkvXXu0mjfa+TlQ delta 552 zcmV+@0@wZb1hNH?7+?qk0002hMu!Rj002u+OjJbx007UOhwi+l^~0_B#<1nHo%+bK z_r^lTU+b7qk4LJ?YpJ) z!mO@~!xfQQfPbY)L_t(&f$f;la)K}vM1_c@CDm42%Kv|9cPE<(YC9w~K49;@ge0(s zapih(voV=WCX>ljQO%VMaN*uU&bcjw!C_VtVt^&{rt3Nv+;`9ugc%mQ8jQyP^nL#v z^aAM+i@gEv4rufM48uT6%n0BrW>_3k#z!dSrklbGo}sy+LJJuN=^vy>9Su`;(Lb z58oj$a-%T7l6fOXbtbGlDm%L*tzeG<6M!rBLH`55#uo1vv42RZ93gdgI+Xxsfh#yH z#bAIE0DsK6!goE)TyW=xAi4><@(k~5Qn}`UnE|Q*^naX6zMruqAqC*KA6KY*$$1vm51>aEM98lhV2=Qn3w-_`P-X@O z$YId+6H?G^s8F#MrGAFzFxGJ#3CIcA0J#8od_6&8#STVN*4X1YV-TGSLS8o@Le$bt q(?p-t&Jm5pNh@Or;8fsV5AY3Kv2ZQHf7-bK0000 Date: Tue, 10 Oct 2023 20:49:02 -0500 Subject: [PATCH 044/100] Dripshield - sprite touchups, mild armor value poking (#24170) * dripwoken * the noggin will hold * better key --------- Co-authored-by: Hatterhat --- .../master_files/icons/mob/clothing/ears.dmi | Bin 1247 -> 1248 bytes .../icons/mob/clothing/suits/armor.dmi | Bin 25065 -> 11900 bytes .../icons/obj/clothing/suits/armor.dmi | Bin 10118 -> 5208 bytes .../modules/blueshield/code/clothing.dm | 80 ++++++++---------- .../modules/blueshield/code/encryptionkey.dm | 5 +- .../modules/blueshield/icons/radio.dmi | Bin 1059 -> 480 bytes 6 files changed, 37 insertions(+), 48 deletions(-) diff --git a/modular_skyrat/master_files/icons/mob/clothing/ears.dmi b/modular_skyrat/master_files/icons/mob/clothing/ears.dmi index eb135d3fdc3b140d3675742a4b1ec6671dfc2f70..0626710027cb3bf3583f6815915d687e60b535b6 100644 GIT binary patch delta 993 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 sdw+QMm$rXu^y0sM3jYiB^fhl+r>})}*G8 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 literal 10118 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 Eg2Tm@kN^Mx delta 943 zcmV;g15o_n1EUC#7Y;xO1^@s6s%dfF0001nk$P``L%g2k%7Tp4qU_X4Tso8$T>V_Y z-T(lvIX)#L&Sw+=00US_L_t(|ob8%DY|}s#$Da{WP(;Jnbf+Jz$;4D4!31JW5M*q; zR7geYP=qScfu$Sj5_b%UW~~@1fkZm7;Lc4OsbeG5g;a{@Wb)2D*A2$Ha}qyYb3e(t z^GD);_y6C!=h%+bY&Kz%xxpO(H^u<&0Jt#*a0kH6#2avvI{;OxOG_TMw=$Vv+xx98 zE9v(sWk9)H_Amf!lb&!GUM??tD4fLqzPJ!A#)SKle5bSlD7w@63`fVGpwl^pv`wIq zN6|RqxR4Rl(lIJX89?HZLZR9}6QpVajXa8fceb~KbSERQkNfZ#RTGq^0E%~A7YaX$ zDjyq)cN-gCZfYtJh-T12$51xVlu$vb2=;nCuv~zJehc6#pDYQl*VipHAzbtjGzGWg zeq8@~b{6czEC^>x99mojNMsnwfH!MvUi;((I&V(_Y}z{`ZGyJH18D9C;sK{ljqkb*&?l+0oiOe=*zl1F2n%Xek~I9 zX>U)om<1qNr=<+o+1at?W}k`v!GR-MT*vL<<4UEHM~ke8kzfxLWQB{AbOvBS$>*Pl zKDKcMrqO65{%NX?6TNwq89-plO;106j-C7IiYFYuKCP?-^+^^b18CHvMjz8YZSj6q z?$R1SCil1NLVkDVpD7xJmE@u5pxAMW57(3bodd7=N5>C>^|{$^u~RfmA_HUt8x?e} zxbyh;D^CG4LT2QN#0I1dns6tViyT?H0s7VLDi4MhKZOwz7In8Lo9)LxJG#g|H(LL@HOCn!5~LpcK)?Nxx= ze!tcBTN01${{F~fO9kc2VCn9rSg4QCw7^#UNl7ErGoZ10*>^Adx?UBe4Zx9=DR7!4 zfV=_qdflp2D&F@m58?i!uQ1r^iZ=fc85a|OJ8TT#4uBhD0Cxb~OuPXWe*piPcdrpB Rsa^m8002ovPDHLkV1mO;uCxFE From 495b98629636e84339579b76660cd4f58cb85c42 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 05:02:36 +0200 Subject: [PATCH 045/100] Hands management element [MDB IGNORE] (#24257) * Hands management element * Update basic.dm * Update dextrous.dm * Fix screenshot test --------- Co-authored-by: Jacquerel Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/__DEFINES/traits.dm | 4 ++ code/_globalvars/traits.dm | 2 + code/_onclick/hud/generic_dextrous.dm | 2 +- code/_onclick/hud/screentip.dm | 2 +- code/_onclick/other_mobs.dm | 23 +------ code/datums/elements/climbable.dm | 16 ++--- code/datums/elements/dextrous.dm | 69 +++++++++++++++++++ code/game/machinery/_machinery.dm | 8 +-- code/modules/mob/living/basic/basic.dm | 15 ++++ .../living/basic/space_fauna/bear/_bear.dm | 2 +- .../living/basic/space_fauna/spider/spider.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 40 +---------- code/modules/mob/living/living.dm | 2 +- .../mob/living/silicon/robot/inventory.dm | 1 + .../simple_animal/guardian/types/dextrous.dm | 14 +--- .../mob/living/simple_animal/simple_animal.dm | 42 +---------- code/modules/mob/mob.dm | 39 ++++++++++- .../security_levels/keycard_authentication.dm | 7 +- tgstation.dme | 1 + 19 files changed, 151 insertions(+), 140 deletions(-) create mode 100644 code/datums/elements/dextrous.dm diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 03175afaba7..e8e44e96867 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -172,6 +172,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_DEFIB_BLACKLISTED "defib_blacklisted" #define TRAIT_BADDNA "baddna" #define TRAIT_CLUMSY "clumsy" +/// Trait that means you are capable of holding items in some form +#define TRAIT_CAN_HOLD_ITEMS "can_hold_items" +/// Trait which lets you clamber over a barrier +#define TRAIT_FENCE_CLIMBER "can_climb_fences" /// means that you can't use weapons with normal trigger guards. #define TRAIT_CHUNKYFINGERS "chunkyfingers" #define TRAIT_CHUNKYFINGERS_IGNORE_BATON "chunkyfingers_ignore_baton" diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index a4a79763865..da03288a0ca 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -30,6 +30,8 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CHUNKYFINGERS" = TRAIT_CHUNKYFINGERS, "TRAIT_CHUNKYFINGERS_IGNORE_BATON" = TRAIT_CHUNKYFINGERS_IGNORE_BATON, "TRAIT_FIST_MINING" = TRAIT_FIST_MINING, + "TRAIT_CAN_HOLD_ITEMS" = TRAIT_CAN_HOLD_ITEMS, + "TRAIT_FENCE_CLIMBER" = TRAIT_FENCE_CLIMBER, "TRAIT_DUMB" = TRAIT_DUMB, "TRAIT_ADVANCEDTOOLUSER" = TRAIT_ADVANCEDTOOLUSER, "TRAIT_DISCOORDINATED_TOOL_USER" = TRAIT_DISCOORDINATED_TOOL_USER, diff --git a/code/_onclick/hud/generic_dextrous.dm b/code/_onclick/hud/generic_dextrous.dm index bf09fa33717..64ad896d57a 100644 --- a/code/_onclick/hud/generic_dextrous.dm +++ b/code/_onclick/hud/generic_dextrous.dm @@ -43,7 +43,7 @@ using.icon = ui_style static_inventory += using - mymob.canon_client.clear_screen() + mymob.canon_client?.clear_screen() for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory)) if(inv.slot_id) diff --git a/code/_onclick/hud/screentip.dm b/code/_onclick/hud/screentip.dm index 107f4ce1be5..94b8f591f65 100644 --- a/code/_onclick/hud/screentip.dm +++ b/code/_onclick/hud/screentip.dm @@ -14,7 +14,7 @@ /atom/movable/screen/screentip/proc/update_view(datum/source) SIGNAL_HANDLER - if(!hud || !hud.mymob.canon_client.view_size) //Might not have been initialized by now + if(!hud || !hud.mymob.canon_client?.view_size) //Might not have been initialized by now return maptext_width = view_to_pixels(hud.mymob.canon_client.view_size.getView())[1] diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 1868057d82c..ed1cdc57b76 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -287,34 +287,13 @@ /atom/proc/attack_pai_secondary(mob/user, list/modifiers) return SECONDARY_ATTACK_CALL_NORMAL -/* - Simple animals -*/ - -/mob/living/simple_animal/resolve_unarmed_attack(atom/attack_target, list/modifiers) - if(dextrous && (isitem(attack_target) || !combat_mode)) - attack_target.attack_hand(src, modifiers) - update_held_items() - else - return ..() - -/mob/living/simple_animal/resolve_right_click_attack(atom/target, list/modifiers) - if(dextrous && (isitem(target) || !combat_mode)) - . = target.attack_hand_secondary(src, modifiers) - update_held_items() - else - return ..() - /* Hostile animals */ /mob/living/simple_animal/hostile/resolve_unarmed_attack(atom/attack_target, list/modifiers) GiveTarget(attack_target) - if(dextrous && (isitem(attack_target) || !combat_mode)) - return ..() - else - INVOKE_ASYNC(src, PROC_REF(AttackingTarget), attack_target) + return ..() #undef LIVING_UNARMED_ATTACK_BLOCKED diff --git a/code/datums/elements/climbable.dm b/code/datums/elements/climbable.dm index e953766571c..b26990c5911 100644 --- a/code/datums/elements/climbable.dm +++ b/code/datums/elements/climbable.dm @@ -114,15 +114,13 @@ ///Handles climbing onto the atom when you click-drag /datum/element/climbable/proc/mousedrop_receive(atom/climbed_thing, atom/movable/dropped_atom, mob/user, params) SIGNAL_HANDLER - if(user == dropped_atom && isliving(dropped_atom)) - var/mob/living/living_target = dropped_atom - if(isanimal(living_target)) - var/mob/living/simple_animal/animal = dropped_atom - if (!animal.dextrous) - return - if(living_target.mobility_flags & MOBILITY_MOVE) - INVOKE_ASYNC(src, PROC_REF(climb_structure), climbed_thing, living_target, params) - return + if(user != dropped_atom || !isliving(dropped_atom)) + return + if(!HAS_TRAIT(dropped_atom, TRAIT_FENCE_CLIMBER) && !HAS_TRAIT(dropped_atom, TRAIT_CAN_HOLD_ITEMS)) // If you can hold items you can probably climb a fence + return + var/mob/living/living_target = dropped_atom + if(living_target.mobility_flags & MOBILITY_MOVE) + INVOKE_ASYNC(src, PROC_REF(climb_structure), climbed_thing, living_target, params) ///Tries to climb onto the target if the forced movement of the mob allows it /datum/element/climbable/proc/try_speedrun(datum/source, mob/bumpee) diff --git a/code/datums/elements/dextrous.dm b/code/datums/elements/dextrous.dm new file mode 100644 index 00000000000..335c7c196d1 --- /dev/null +++ b/code/datums/elements/dextrous.dm @@ -0,0 +1,69 @@ +/** + * Sets up the attachee to have hands and manages things like dropping items on death and displaying them on examine + * Actual hand performance is managed by code on /living/ and not encapsulated here, we just enable it + */ +/datum/element/dextrous + +/datum/element/dextrous/Attach(datum/target, hands_count = 2, hud_type = /datum/hud/dextrous) + . = ..() + if (!isliving(target) || iscarbon(target)) + return ELEMENT_INCOMPATIBLE // Incompatible with the carbon typepath because that already has its own hand handling and doesn't need hand holding + + var/mob/living/mob_parent = target + set_available_hands(mob_parent, hands_count) + mob_parent.set_hud_used(new hud_type(target)) + mob_parent.hud_used.show_hud(mob_parent.hud_used.hud_version) + ADD_TRAIT(target, TRAIT_CAN_HOLD_ITEMS, REF(src)) + RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(on_death)) + RegisterSignal(target, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_hand_clicked)) + RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined)) + +/datum/element/dextrous/Detach(datum/source) + . = ..() + var/mob/living/mob_parent = source + set_available_hands(mob_parent, initial(mob_parent.default_num_hands)) + var/initial_hud = initial(mob_parent.hud_type) + mob_parent.set_hud_used(new initial_hud(source)) + mob_parent.hud_used.show_hud(mob_parent.hud_used.hud_version) + REMOVE_TRAIT(source, TRAIT_CAN_HOLD_ITEMS, REF(src)) + UnregisterSignal(source, list( + COMSIG_ATOM_EXAMINE, + COMSIG_LIVING_DEATH, + COMSIG_LIVING_UNARMED_ATTACK, + )) + +/// Set up how many hands we should have +/datum/element/dextrous/proc/set_available_hands(mob/living/hand_owner, hands_count) + hand_owner.drop_all_held_items() + var/held_items = list() + for (var/i in 1 to hands_count) + held_items += null + hand_owner.held_items = held_items + hand_owner.set_num_hands(hands_count) + hand_owner.set_usable_hands(hands_count) + +/// Drop our shit when we die +/datum/element/dextrous/proc/on_death(mob/living/died, gibbed) + SIGNAL_HANDLER + died.drop_all_held_items() + +/// Try picking up items +/datum/element/dextrous/proc/on_hand_clicked(mob/living/hand_haver, atom/target, proximity, modifiers) + SIGNAL_HANDLER + if (!isitem(target) && hand_haver.combat_mode) + return + if (LAZYACCESS(modifiers, RIGHT_CLICK)) + INVOKE_ASYNC(target, TYPE_PROC_REF(/atom, attack_hand_secondary), hand_haver, modifiers) + else + INVOKE_ASYNC(target, TYPE_PROC_REF(/atom, attack_hand), hand_haver, modifiers) + INVOKE_ASYNC(hand_haver, TYPE_PROC_REF(/mob, update_held_items)) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/// Tell people what we are holding +/datum/element/dextrous/proc/on_examined(mob/living/examined, mob/user, list/examine_list) + SIGNAL_HANDLER + for(var/obj/item/held_item in examined.held_items) + if(held_item.item_flags & (ABSTRACT|EXAMINE_SKIP|HAND_ITEM)) + continue + examine_list += span_info("[examined.p_They()] [examined.p_have()] [held_item.get_examine_string(user)] in [examined.p_their()] \ + [examined.get_held_index_name(examined.get_held_index_of_item(held_item))].") diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index fde5c89b88d..494f1cca77e 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -591,13 +591,7 @@ if(!isliving(user)) return FALSE //no ghosts allowed, sorry - var/is_dextrous = FALSE - if(isanimal(user)) - var/mob/living/simple_animal/user_as_animal = user - if (user_as_animal.dextrous) - is_dextrous = TRUE - - if(!issilicon(user) && !is_dextrous && !user.can_hold_items()) + if(!issilicon(user) && !user.can_hold_items()) return FALSE //spiders gtfo if(issilicon(user)) // If we are a silicon, make sure the machine allows silicons to interact with it diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index ab8daf47635..1e9a17d69c5 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -285,6 +285,21 @@ return last_icon_state return null +/mob/living/basic/put_in_hands(obj/item/I, del_on_fail = FALSE, merge_stacks = TRUE, ignore_animation = TRUE) + . = ..() + if (.) + update_held_items() + +/mob/living/basic/update_held_items() + if(isnull(client) || isnull(hud_used) || hud_used.hud_version == HUD_STYLE_NOHUD) + return + var/turf/our_turf = get_turf(src) + for(var/obj/item/held in held_items) + var/index = get_held_index_of_item(held) + SET_PLANE(held, ABOVE_HUD_PLANE, our_turf) + held.screen_loc = ui_hand_position(index) + client.screen |= held + /mob/living/basic/get_body_temp_heat_damage_limit() return maximum_survivable_temperature diff --git a/code/modules/mob/living/basic/space_fauna/bear/_bear.dm b/code/modules/mob/living/basic/space_fauna/bear/_bear.dm index 414f28a1e9a..924cf854276 100644 --- a/code/modules/mob/living/basic/space_fauna/bear/_bear.dm +++ b/code/modules/mob/living/basic/space_fauna/bear/_bear.dm @@ -42,7 +42,7 @@ /mob/living/basic/bear/Initialize(mapload) . = ..() - ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) + add_traits(list(TRAIT_SPACEWALK, TRAIT_FENCE_CLIMBER), INNATE_TRAIT) AddElement(/datum/element/ai_retaliate) AddComponent(/datum/component/tree_climber, climbing_distance = 15) AddElement(/datum/element/swabable, CELL_LINE_TABLE_BEAR, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) diff --git a/code/modules/mob/living/basic/space_fauna/spider/spider.dm b/code/modules/mob/living/basic/space_fauna/spider/spider.dm index 4bd773f6d0a..53b48129e2e 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spider.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spider.dm @@ -49,7 +49,7 @@ /mob/living/basic/spider/Initialize(mapload) . = ..() - ADD_TRAIT(src, TRAIT_WEB_SURFER, INNATE_TRAIT) + add_traits(list(TRAIT_WEB_SURFER, TRAIT_FENCE_CLIMBER), INNATE_TRAIT) AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) AddElement(/datum/element/nerfed_pulling, GLOB.typecache_general_bad_things_to_easily_move) AddElement(/datum/element/prevent_attacking_of_types, GLOB.typecache_general_bad_hostile_attack_targets, "this tastes awful!") diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index ebb7a70183f..35dffd7c27e 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -10,6 +10,7 @@ COMSIG_CARBON_DISARM_COLLIDE = PROC_REF(disarm_collision), ) AddElement(/datum/element/connect_loc, loc_connections) + ADD_TRAIT(src, TRAIT_CAN_HOLD_ITEMS, INNATE_TRAIT) // Carbons are assumed to be innately capable of having arms, we check their arms count instead /mob/living/carbon/Destroy() //This must be done first, so the mob ghosts correctly before DNA etc is nulled @@ -27,45 +28,6 @@ QDEL_NULL(dna) GLOB.carbon_list -= src -/mob/living/carbon/perform_hand_swap(held_index) - . = ..() - if(!.) - return - - if(!held_index) - held_index = (active_hand_index % held_items.len)+1 - - if(!isnum(held_index)) - CRASH("You passed [held_index] into swap_hand instead of a number. WTF man") - - var/oindex = active_hand_index - active_hand_index = held_index - if(hud_used) - var/atom/movable/screen/inventory/hand/H - H = hud_used.hand_slots["[oindex]"] - if(H) - H.update_appearance() - H = hud_used.hand_slots["[held_index]"] - if(H) - H.update_appearance() - - -/mob/living/carbon/activate_hand(selhand) //l/r OR 1-held_items.len - if(!selhand) - selhand = (active_hand_index % held_items.len)+1 - - if(istext(selhand)) - selhand = lowertext(selhand) - if(selhand == "right" || selhand == "r") - selhand = 2 - if(selhand == "left" || selhand == "l") - selhand = 1 - - if(selhand != active_hand_index) - swap_hand(selhand) - else - mode() // Activate held item - /mob/living/carbon/attackby(obj/item/item, mob/living/user, params) if(!all_wounds || !(!user.combat_mode || user == src)) return ..() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 3e93bc6314b..ef57b9b1467 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1308,7 +1308,7 @@ return /mob/living/can_hold_items(obj/item/I) - return usable_hands && ..() + return ..() && HAS_TRAIT(src, TRAIT_CAN_HOLD_ITEMS) && usable_hands /mob/living/can_perform_action(atom/movable/target, action_bitflags) if(!istype(target)) diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index 7df2e7d3390..be713b429a6 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -401,6 +401,7 @@ /mob/living/silicon/robot/perform_hand_swap() cycle_modules() + return TRUE /mob/living/silicon/robot/can_hold_items(obj/item/I) return (I && (I in model.modules)) //Only if it's part of our model. diff --git a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm index 798b2067c63..d2fbfc33c87 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm @@ -22,17 +22,9 @@ dropItemToGround(internal_storage) /mob/living/simple_animal/hostile/guardian/dextrous/examine(mob/user) - if(dextrous) - . = list("This is [icon2html(src)] \a [src]!\n[desc]", EXAMINE_SECTION_BREAK) //SKYRAT EDIT CHANGE - for(var/obj/item/held_item in held_items) - if(held_item.item_flags & (ABSTRACT|EXAMINE_SKIP|HAND_ITEM)) - continue - . += "It has [held_item.get_examine_string(user)] in its [get_held_index_name(get_held_index_of_item(held_item))]." - if(internal_storage && !(internal_storage.item_flags & ABSTRACT)) - . += "It is holding [internal_storage.get_examine_string(user)] in its internal storage." - . += "" - else - return ..() + . = ..() + if(internal_storage && !(internal_storage.item_flags & ABSTRACT)) + . += span_info("It is holding [internal_storage.get_examine_string(user)] in its internal storage.") /mob/living/simple_animal/hostile/guardian/dextrous/recall_effects() drop_all_held_items() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 3b16ab685eb..4962e25afe0 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -177,6 +177,7 @@ stack_trace("Simple animal being instantiated in nullspace") update_simplemob_varspeed() if(dextrous) + AddElement(/datum/element/dextrous, hud_type = hud_type) AddComponent(/datum/component/personal_crafting) add_traits(list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP), ROUNDSTART_TRAIT) ADD_TRAIT(src, TRAIT_NOFIRE_SPREAD, ROUNDSTART_TRAIT) @@ -447,9 +448,6 @@ /mob/living/simple_animal/death(gibbed) drop_loot() - if(dextrous) - drop_all_held_items() - if(del_on_death) ..() //Prevent infinite loops if the mob Destroy() is overridden in such @@ -560,44 +558,6 @@ /mob/living/simple_animal/get_idcard(hand_first) return (..() || access_card) -/mob/living/simple_animal/can_hold_items(obj/item/I) - return dextrous && ..() - -/mob/living/simple_animal/activate_hand(selhand) - if(!dextrous) - return ..() - if(!selhand) - selhand = (active_hand_index % held_items.len)+1 - if(istext(selhand)) - selhand = lowertext(selhand) - if(selhand == "right" || selhand == "r") - selhand = 2 - if(selhand == "left" || selhand == "l") - selhand = 1 - if(selhand != active_hand_index) - swap_hand(selhand) - else - mode() - -/mob/living/simple_animal/perform_hand_swap(hand_index) - . = ..() - if(!.) - return - if(!dextrous) - return - if(!hand_index) - hand_index = (active_hand_index % held_items.len)+1 - var/oindex = active_hand_index - active_hand_index = hand_index - if(hud_used) - var/atom/movable/screen/inventory/hand/H - H = hud_used.hand_slots["[hand_index]"] - if(H) - H.update_appearance() - H = hud_used.hand_slots["[oindex]"] - if(H) - H.update_appearance() - /mob/living/simple_animal/put_in_hands(obj/item/I, del_on_fail = FALSE, merge_stacks = TRUE, ignore_animation = TRUE) . = ..() update_held_items() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 00bd1d0ebc9..9002033a13e 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -984,10 +984,45 @@ /// Performs the actual ritual of swapping hands, such as setting the held index variables /mob/proc/perform_hand_swap(held_index) PROTECTED_PROC(TRUE) + if (!HAS_TRAIT(src, TRAIT_CAN_HOLD_ITEMS)) + return FALSE + + if(!held_index) + held_index = (active_hand_index % held_items.len) + 1 + + if(!isnum(held_index)) + CRASH("You passed [held_index] into swap_hand instead of a number. WTF man") + + var/previous_index = active_hand_index + active_hand_index = held_index + if(hud_used) + var/atom/movable/screen/inventory/hand/held_location + held_location = hud_used.hand_slots["[previous_index]"] + if(!isnull(held_location)) + held_location.update_appearance() + held_location = hud_used.hand_slots["[held_index]"] + if(!isnull(held_location)) + held_location.update_appearance() return TRUE -/mob/proc/activate_hand(selhand) - return +/mob/proc/activate_hand(selected_hand) + if (!HAS_TRAIT(src, TRAIT_CAN_HOLD_ITEMS)) + return + + if(!selected_hand) + selected_hand = (active_hand_index % held_items.len)+1 + + if(istext(selected_hand)) + selected_hand = lowertext(selected_hand) + if(selected_hand == "right" || selected_hand == "r") + selected_hand = 2 + if(selected_hand == "left" || selected_hand == "l") + selected_hand = 1 + + if(selected_hand != active_hand_index) + swap_hand(selected_hand) + else + mode() /mob/proc/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //For sec bot threat assessment return 0 diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm index 21664265b68..33bbdd76f29 100644 --- a/code/modules/security_levels/keycard_authentication.dm +++ b/code/modules/security_levels/keycard_authentication.dm @@ -59,11 +59,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26) /obj/machinery/keycard_auth/ui_status(mob/user) if(isdrone(user)) return UI_CLOSE - if(!isanimal(user)) + if(!isanimal_or_basicmob(user)) return ..() - var/mob/living/simple_animal/A = user - if(!A.dextrous) - to_chat(user, span_warning("You are too primitive to use this device!")) + if(!HAS_TRAIT(user, TRAIT_CAN_HOLD_ITEMS)) + balloon_alert(user, "no hands!") return UI_CLOSE return ..() diff --git a/tgstation.dme b/tgstation.dme index 58e848aed40..d8bc3b0c015 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1385,6 +1385,7 @@ #include "code\datums\elements\death_gases.dm" #include "code\datums\elements\delete_on_drop.dm" #include "code\datums\elements\deliver_first.dm" +#include "code\datums\elements\dextrous.dm" #include "code\datums\elements\diggable.dm" #include "code\datums\elements\digitalcamo.dm" #include "code\datums\elements\drag_pickup.dm" From f005c3735956c06db872b442e84c1eb649867c2f Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 08:31:41 +0200 Subject: [PATCH 046/100] Makes Gondolapods great again [MDB IGNORE] (#24268) * Makes Gondolapods great again (#78900) ## About The Pull Request Fixes #73310 Bug fix for gondola supplypods generated with the Config/Launch Supplypod admin verb. open_pod() now dumps the contents of the holder reference it was passed (holder = src supplypod in all cases except for the gondola pod) allowing gondola pods to actually deliver their cargo. Mobs in the new gondola pod get their perspective reset instead of being stuck in the void of nullspace until the pod opens. The mob's plane is set on the pod opening to allow items to appear on top of the pod, and reset to standard mob plane on closing. In the case of a reversing pod, contents are properly stored in the supplypod and the outgoing mob is qdel'd (new one is spawned when the pod lands, holder != src should only be true in the case of the gondola pod). Fixed a runtime where glow_effect.plane was being modified while glow_effect is null. Removes incorrect comment. Everything tested locally. ## Why It's Good For The Game Makes the gondola supplypod variant actually functional. ## Changelog :cl: admin: Gondola supplypods are functional again. /:cl: * Makes Gondolapods great again --------- Co-authored-by: Isratosh --- code/modules/cargo/gondolapod.dm | 2 ++ code/modules/cargo/supplypod.dm | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/code/modules/cargo/gondolapod.dm b/code/modules/cargo/gondolapod.dm index 5ee9f856823..f3dca7a3dca 100644 --- a/code/modules/cargo/gondolapod.dm +++ b/code/modules/cargo/gondolapod.dm @@ -65,11 +65,13 @@ /mob/living/simple_animal/pet/gondola/gondolapod/setOpened() opened = TRUE + SET_PLANE_IMPLICIT(src, GAME_PLANE) update_appearance() addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, setClosed)), 50) /mob/living/simple_animal/pet/gondola/gondolapod/setClosed() opened = FALSE + SET_PLANE_IMPLICIT(src, GAME_PLANE_FOV_HIDDEN) update_appearance() /mob/living/simple_animal/pet/gondola/gondolapod/death() diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm index 8635efee569..ed75e634967 100644 --- a/code/modules/cargo/supplypod.dm +++ b/code/modules/cargo/supplypod.dm @@ -222,6 +222,9 @@ stay_after_drop = FALSE holder.pixel_z = initial(holder.pixel_z) holder.alpha = initial(holder.alpha) + if (holder != src) + contents |= holder.contents + qdel(holder) var/shippingLane = GLOB.areas_by_type[/area/centcom/central_command_areas/supplypod/supplypod_temp_holding] forceMove(shippingLane) //Move to the centcom-z-level until the pod_landingzone says we can drop back down again if (!reverse_dropoff_coords) //If we're centcom-launched, the reverse dropoff turf will be a centcom loading bay. If we're an extraction pod, it should be the ninja jail. Thus, this shouldn't ever really happen. @@ -293,6 +296,8 @@ if (style == STYLE_GONDOLA) //Checks if we are supposed to be a gondola pod. If so, create a gondolapod mob, and move this pod to nullspace. I'd like to give a shout out, to my man oranges var/mob/living/simple_animal/pet/gondola/gondolapod/benis = new(turf_underneath, src) benis.contents |= contents //Move the contents of this supplypod into the gondolapod mob. + for (var/mob/living/mob_in_pod in benis.contents) + mob_in_pod.reset_perspective(null) moveToNullspace() addtimer(CALLBACK(src, PROC_REF(open_pod), benis), delays[POD_OPENING]) //After the opening delay passes, we use the open proc from this supplyprod while referencing the contents of the "holder", in this case the gondolapod mob else if (style == STYLE_SEETHROUGH) @@ -315,7 +320,7 @@ playsound(get_turf(holder), openingSound, soundVolume, FALSE, FALSE) //Special admin sound to play for (var/turf_type in turfs_in_cargo) turf_underneath.PlaceOnTop(turf_type) - for (var/cargo in contents) + for (var/cargo in holder.contents) var/atom/movable/movable_cargo = cargo movable_cargo.forceMove(turf_underneath) if (!effectQuiet && !openingSound && style != STYLE_SEETHROUGH && !(pod_flags & FIRST_SOUNDS)) //If we aren't being quiet, play the default pod open sound @@ -487,7 +492,8 @@ . = ..() if(same_z_layer) return - SET_PLANE_EXPLICIT(glow_effect, ABOVE_GAME_PLANE, src) + if(glow_effect) + SET_PLANE_EXPLICIT(glow_effect, ABOVE_GAME_PLANE, src) /obj/structure/closet/supplypod/proc/endGlow() if(!glow_effect) @@ -537,7 +543,7 @@ /obj/effect/supplypod_smoke/proc/drawSelf(amount) alpha = max(0, 255-(amount*20)) -/obj/effect/supplypod_rubble //This is the object that forceMoves the supplypod to it's location +/obj/effect/supplypod_rubble name = "debris" desc = "A small crater of rubble. Closer inspection reveals the debris to be made primarily of space-grade metal fragments. You're pretty sure that this will disperse before too long." icon = 'icons/obj/supplypods.dmi' From 6bfaeeb7a4f180f9ac2ecd3c7bbe1861e09d07f1 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 08:32:36 +0200 Subject: [PATCH 047/100] Mook village and basic mook refactor [MDB IGNORE] (#24269) Mook village and basic mook refactor Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> --- .../lavaland_surface_mookvillage.dmm | 643 ++++++++++++++++++ code/__DEFINES/ai/monsters.dm | 20 + code/__DEFINES/basic_mobs.dm | 7 + code/__DEFINES/is_helpers.dm | 1 + code/__DEFINES/song.dm | 2 + .../basic_ai_behaviors/find_mineable_wall.dm | 33 - .../basic_mobs/basic_subtrees/mine_walls.dm | 73 ++ .../ai/idle_behaviors/idle_random_walk.dm | 41 ++ code/datums/components/pet_commands/fetch.dm | 2 + code/datums/ruins/lavaland.dm | 8 + .../basic/lavaland/goldgrub/goldgrub_ai.dm | 59 +- .../mob/living/basic/lavaland/mook/mook.dm | 273 ++++++++ .../basic/lavaland/mook/mook_abilities.dm | 140 ++++ .../mob/living/basic/lavaland/mook/mook_ai.dm | 426 ++++++++++++ .../basic/lavaland/mook/mook_village.dm | 85 +++ .../mob/living/basic/minebots/minebot_ai.dm | 6 +- .../simple_animal/hostile/jungle/mook.dm | 229 ------- .../unit_tests/simple_animal_freeze.dm | 1 - config/lavaruinblacklist.txt | 19 +- icons/mob/simple/jungle/mook.dmi | Bin 23590 -> 36875 bytes tgstation.dme | 7 +- .../tgui/interfaces/MaterialStand.tsx | 120 ++++ 22 files changed, 1875 insertions(+), 320 deletions(-) create mode 100644 _maps/RandomRuins/LavaRuins/lavaland_surface_mookvillage.dmm delete mode 100644 code/datums/ai/basic_mobs/basic_ai_behaviors/find_mineable_wall.dm create mode 100644 code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm create mode 100644 code/modules/mob/living/basic/lavaland/mook/mook.dm create mode 100644 code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm create mode 100644 code/modules/mob/living/basic/lavaland/mook/mook_ai.dm create mode 100644 code/modules/mob/living/basic/lavaland/mook/mook_village.dm delete mode 100644 code/modules/mob/living/simple_animal/hostile/jungle/mook.dm create mode 100644 tgui/packages/tgui/interfaces/MaterialStand.tsx diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_mookvillage.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_mookvillage.dmm new file mode 100644 index 00000000000..5db8dd37a24 --- /dev/null +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_mookvillage.dmm @@ -0,0 +1,643 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"b" = ( +/obj/structure/bonfire/prelit, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"c" = ( +/turf/open/floor/holofloor/wood, +/area/lavaland/surface/outdoors) +"d" = ( +/obj/structure/railing{ + dir = 1 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"e" = ( +/obj/structure/flora/ash/fireblossom, +/mob/living/basic/mining/mook/worker/tribal_chief, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"f" = ( +/obj/structure/chair/wood{ + dir = 1 + }, +/turf/open/floor/holofloor/wood, +/area/lavaland/surface/outdoors) +"g" = ( +/obj/structure/bed/maint, +/turf/open/floor/holofloor/wood, +/area/lavaland/surface/outdoors) +"h" = ( +/turf/closed/wall/mineral/wood, +/area/lavaland/surface/outdoors) +"i" = ( +/obj/structure/chair/wood, +/turf/open/floor/holofloor/wood, +/area/lavaland/surface/outdoors) +"j" = ( +/obj/structure/closet/cabinet, +/obj/item/food/grown/banana, +/obj/item/food/meat/slab/goliath, +/turf/open/floor/holofloor/wood, +/area/lavaland/surface/outdoors) +"k" = ( +/obj/structure/table/wood/shuttle_bar, +/obj/item/flashlight/flare/candle/infinite, +/turf/open/floor/holofloor/wood, +/area/lavaland/surface/outdoors) +"l" = ( +/obj/structure/flora/ash/fireblossom, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"m" = ( +/obj/item/flashlight/lantern{ + on = 1 + }, +/turf/open/floor/holofloor/wood, +/area/lavaland/surface/outdoors) +"n" = ( +/obj/structure/flora/ash/fireblossom, +/mob/living/basic/mining/mook/worker, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"o" = ( +/obj/structure/railing/corner, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"p" = ( +/obj/structure/material_stand, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"q" = ( +/obj/item/fishing_rod, +/obj/structure/bed/maint, +/turf/open/floor/holofloor/wood, +/area/lavaland/surface/outdoors) +"r" = ( +/turf/open/floor/carpet/lone, +/area/lavaland/surface/outdoors) +"s" = ( +/obj/effect/landmark/mook_village, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"t" = ( +/obj/structure/chair/pew/left, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"u" = ( +/obj/structure/railing, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"v" = ( +/obj/structure/railing/corner{ + dir = 8 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"w" = ( +/obj/structure/railing{ + dir = 4 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"x" = ( +/obj/structure/table/wood/shuttle_bar, +/obj/item/clothing/head/costume/garland/poppy, +/turf/open/floor/holofloor/wood, +/area/lavaland/surface/outdoors) +"y" = ( +/turf/open/misc/grass/jungle, +/area/lavaland/surface/outdoors) +"z" = ( +/mob/living/basic/mining/mook/worker/bard, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"A" = ( +/obj/structure/chair/pew/right, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"C" = ( +/obj/structure/sign/nanotrasen, +/turf/closed/wall/mineral/wood, +/area/lavaland/surface/outdoors) +"E" = ( +/obj/structure/flora/grass/jungle/b, +/turf/open/misc/grass/jungle, +/area/lavaland/surface/outdoors) +"F" = ( +/obj/structure/chair/pew, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"G" = ( +/obj/structure/bed/pod, +/obj/item/bedsheet/nanotrasen, +/turf/open/floor/holofloor/wood, +/area/lavaland/surface/outdoors) +"H" = ( +/obj/structure/railing/corner{ + dir = 1 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"I" = ( +/mob/living/basic/mining/mook, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"J" = ( +/obj/structure/railing{ + dir = 8 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"M" = ( +/obj/structure/chair/pew/right{ + dir = 8 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"O" = ( +/obj/structure/table/wood/shuttle_bar, +/obj/item/hatchet/wooden, +/obj/item/storage/belt/champion/wrestling, +/turf/open/floor/holofloor/wood, +/area/lavaland/surface/outdoors) +"P" = ( +/mob/living/basic/mining/mook/worker, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"Q" = ( +/obj/structure/flora/tree/jungle/style_5, +/turf/open/misc/grass/jungle, +/area/lavaland/surface/outdoors) +"S" = ( +/obj/item/flashlight/lantern{ + on = 1 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"V" = ( +/obj/structure/chair/pew{ + dir = 8 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"W" = ( +/obj/structure/flora/tree/jungle/style_3, +/turf/open/misc/grass/jungle, +/area/lavaland/surface/outdoors) +"Y" = ( +/obj/structure/chair/pew/left{ + dir = 8 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"Z" = ( +/obj/structure/railing/corner{ + dir = 4 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) + +(1,1,1) = {" +a +a +a +a +a +a +a +l +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +a +a +a +a +a +l +S +a +a +a +a +a +a +a +t +a +a +a +a +"} +(3,1,1) = {" +a +a +a +a +a +a +a +a +a +a +p +a +a +a +a +F +a +a +a +a +"} +(4,1,1) = {" +h +h +h +h +h +h +a +s +a +a +a +a +a +a +a +F +a +b +a +a +"} +(5,1,1) = {" +c +c +j +g +c +c +a +S +a +a +a +a +P +a +S +F +a +a +a +a +"} +(6,1,1) = {" +c +m +c +c +c +c +r +n +a +P +a +a +a +a +a +A +a +a +a +a +"} +(7,1,1) = {" +c +c +c +c +c +c +r +a +I +a +a +a +a +a +l +e +Y +V +V +M +"} +(8,1,1) = {" +c +i +k +f +c +c +a +a +a +o +w +w +w +Z +I +a +a +a +a +a +"} +(9,1,1) = {" +h +h +h +h +h +h +a +a +a +u +y +y +Q +d +a +a +a +P +a +a +"} +(10,1,1) = {" +a +a +a +a +a +a +a +I +a +u +y +y +E +d +a +a +l +a +a +a +"} +(11,1,1) = {" +a +a +l +l +a +a +a +a +a +u +y +W +E +d +a +a +a +a +a +a +"} +(12,1,1) = {" +a +a +a +a +a +P +a +a +a +u +y +y +Q +d +a +a +a +a +a +a +"} +(13,1,1) = {" +a +a +a +a +a +a +a +a +a +v +J +J +J +H +a +a +P +a +a +a +"} +(14,1,1) = {" +h +h +h +h +h +h +h +z +S +l +a +a +I +l +l +a +I +a +a +l +"} +(15,1,1) = {" +g +g +g +g +q +g +g +l +a +a +a +a +a +a +a +a +a +a +a +a +"} +(16,1,1) = {" +c +c +c +c +c +c +c +r +a +a +a +a +h +c +c +c +h +a +a +a +"} +(17,1,1) = {" +c +c +c +m +c +c +c +r +a +P +a +a +h +O +c +c +h +a +a +a +"} +(18,1,1) = {" +g +g +g +g +g +g +g +a +a +a +a +a +C +x +c +c +h +a +a +a +"} +(19,1,1) = {" +h +h +h +h +h +h +h +a +a +l +a +S +h +m +c +G +h +a +a +a +"} +(20,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +h +c +c +c +h +a +a +a +"} diff --git a/code/__DEFINES/ai/monsters.dm b/code/__DEFINES/ai/monsters.dm index 89670d4f346..2867ba4a6fc 100644 --- a/code/__DEFINES/ai/monsters.dm +++ b/code/__DEFINES/ai/monsters.dm @@ -169,3 +169,23 @@ #define BB_LEGION_RECENT_LINES "legion_recent_lines" /// The creator of our legion skull #define BB_LEGION_BROOD_CREATOR "legion_brood_creator" + +//mook keys +/// our home landmark +#define BB_HOME_VILLAGE "home_village" +/// maximum distance we can be from home during a storm +#define BB_MAXIMUM_DISTANCE_TO_VILLAGE "maximum_distance_to_village" +/// stand where we deposit our ores +#define BB_MATERIAL_STAND_TARGET "material_stand_target" +/// our jump ability +#define BB_MOOK_JUMP_ABILITY "mook_jump_ability" +/// our leap ability +#define BB_MOOK_LEAP_ABILITY "mook_leap_ability" +/// the chief we must obey +#define BB_MOOK_TRIBAL_CHIEF "mook_tribal_chief" +/// the injured mook we must heal +#define BB_INJURED_MOOK "injured_mook" +/// the player we will follow and play music for +#define BB_MOOK_MUSIC_AUDIENCE "music_audience" +/// the bonfire we will light up +#define BB_MOOK_BONFIRE_TARGET "bonfire_target" diff --git a/code/__DEFINES/basic_mobs.dm b/code/__DEFINES/basic_mobs.dm index 5a4aebaee23..6c8a3022e8f 100644 --- a/code/__DEFINES/basic_mobs.dm +++ b/code/__DEFINES/basic_mobs.dm @@ -19,3 +19,10 @@ /// Above this speed we stop gliding because it looks silly #define END_GLIDE_SPEED 10 + +///mook attack status flags +#define MOOK_ATTACK_NEUTRAL 0 +#define MOOK_ATTACK_WARMUP 1 +#define MOOK_ATTACK_ACTIVE 2 +#define MOOK_ATTACK_STRIKE 3 + diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index f6ef0a45c80..136e0b922ce 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -92,6 +92,7 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define isabductor(A) (is_species(A, /datum/species/abductor)) #define isgolem(A) (is_species(A, /datum/species/golem)) #define islizard(A) (is_species(A, /datum/species/lizard)) +#define isashwalker(A) (is_species(A, /datum/species/lizard/ashwalker)) #define isplasmaman(A) (is_species(A, /datum/species/plasmaman)) #define ispodperson(A) (is_species(A, /datum/species/pod)) #define isflyperson(A) (is_species(A, /datum/species/fly)) diff --git a/code/__DEFINES/song.dm b/code/__DEFINES/song.dm index 7af269fbe21..782a7923ea1 100644 --- a/code/__DEFINES/song.dm +++ b/code/__DEFINES/song.dm @@ -13,3 +13,5 @@ ///it's what monkeys play! #define MONKEY_SONG "BPM: 200\nC4/0,14,C,A4-F2,F3,A3,F-F2,A-F,F4,G4,F,D4-Bb2-G2\nD3,G3,D-G2,G3-G2,D,D4-G3,D,B4-B2,G,B3,G-B2,B3-B2\nG4,A4,G,E4-C3,E3,G3,E-C,G-C,E,E4-G,E,C5-E-A3,C4\nA-E3,C,E4-C3,A4-C4,B4-A3-A2,C5-C4,D5-F-B3,D4,B-F3\nD,F4-D3,D4,F-B-B2,G4-D,A4-C-F3,F,C/2,B3/2,A3-C3/2\nB/2,C4,E-C3,F4,G-C,F-F3,F-C,C4/2,B/2,A-A2/2,G3/2\nF/I" +///song played by the mook bard +#define MOOK_SONG "BPM: 240\nA5,B5,C#6,D6,E6/0.17,A/0.5,A/0.25,A3/0.25\nA4/0.25,C#5/0.25,E5/0.25,A/0.25,C#/0.25,E/0.12\nC#6/0.25,C#/0.25,E6/0.25,A3/0.25,A4/0.25\nC#5/0.25,E5/0.25,A/0.25,C#/0.25,E/0.25,D/0.25\nG6/0.25,D/0.17,F6/0.17,C#6/0.5,E6/0.5,D4/0.25\nA/0.25,D5/0.25,F5/0.25,A/0.25,D/0.25,F/0.25\nD6/0.08,F6/0.08,D4/0.25,A/0.25,D5/0.25,F5/0.25\nCn4/0.2,B/0.17,D6/0.17,G5/0.5,G/0.25,B3/0.25\nD4/0.25,G4/0.25,B4/0.25,D/0.25,G/0.25,B/0.12\nB5/0.25,B/0.25,D6/0.25,G3/0.25,G4/0.25,B4/0.25\nF/0.25,G/0.25,B/0.25,F/0.25,D/0.25,F6/0.25\nC6/0.17,E/0.17,B5/0.5,D#/0.5,C4/0.25,G/0.25\nC5/0.25,E5/0.25,G/0.25,C/0.25,E/0.25,C6/0.08\nE6/0.08,C4/0.25,Dn4/0.25,E4/0.25,A5/0.17,B/0.5\nC6/0.25,F5/0.08,F4/0.08,C5/0.08,E5/0.12,G5/0.12\nC6/0.25,E6/0.25,E4/0.08,C5/0.08,B/0.17,F6/0.17\nE6/0.5,B/0.25,E4/0.08,G#4/0.08,C6/0.17,D6/0.5\nE6/0.25,A3/0.25,E4/0.25,C5/0.25,Gn3/0.25\nF5/0.12,A5/0.12,A6/0.25,F3/0.25,F4/0.12,A4/0.12\nC/0.12,F6/0.17,A6/0.17,G#6/0.5,A/0.25,F3/0.25\nF4/0.12,A4/0.12,D#5/0.12,B/0.17,G#/0.17,B6/0.5\nB5/0.25,G#/0.25,E3/0.25,E4/0.12,G#4/0.12\nDn/0.12,E6/0.08,E3/0.25,F#3/0.25,G#3/0.25\nE5/0.17,A5/0.17,E/0.5,E/0.25,A3/0.25,C#4/0.25\nE4/0.25,C#/0.25,E/0.12,A5/0.5,B/0.5,C#6/0.5\nD6/0.5,A3/0.25,C#4/0.25,E/0.25,C#/0.25,E/0.25\nE6/0.08,Gn/0.25,E4/0.25,A4/0.25,C#5/0.25,E/0.25\nA/0.25,C#/0.25,E6/0.17,E/0.5,Fn6/0.5,G6/0.5\nG3/0.25,E4/0.25,A/0.25,C#/0.25,E/0.25,A/0.25\nC#/0.25,F/0.08,A6/0.08,F3/0.25,F4/0.25,A4/0.25\nCn/0.25,F/0.25,A/0.25,C/0.25,G6/0.12,A6/0.12\nG A G F6 G3/0.25 D4/0.25 G4/0.25 B4/0.25 D/0.25\nG/0.25 B/0.25 E6/0.12 G6/0.12 F/0.71 G/0.71 F/0.71\nE3/0.25 E4/0.25 G4/0.25 B/0.25 E/0.25 G/0.25 B/0.25\nA5/0.08 E6/0.08 A3/0.25 E4/0.25 A4/0.25 C#/0.25 E/0.25 A/0.25 C#/0.25 D6/0.17 E6/0.5 F/0.25 B3/0.25 D4/0.12 F4/0.12 B4/0.12 F6/0.25 E/0.25 D6/0.25 G#3/0.25 E4/0.12 G#4/0.12 B/0.12 Cn6/0.12 D/0.25 A3/0.25 A4/0.25 C5/0.25 E5/0.25 G#3/0.25 Gn/0.25 C4/0.25 E4/0.25 A/" diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/find_mineable_wall.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/find_mineable_wall.dm deleted file mode 100644 index ad5749c9161..00000000000 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/find_mineable_wall.dm +++ /dev/null @@ -1,33 +0,0 @@ -//behavior to find mineable mineral walls -/datum/ai_behavior/find_mineral_wall - -/datum/ai_behavior/find_mineral_wall/perform(seconds_per_tick, datum/ai_controller/controller, found_wall_key) - . = ..() - var/mob/living_pawn = controller.pawn - - for(var/turf/closed/mineral/potential_wall in oview(9, living_pawn)) - if(!check_if_mineable(controller, potential_wall)) //check if its surrounded by walls - continue - controller.set_blackboard_key(found_wall_key, potential_wall) //closest wall first! - finish_action(controller, TRUE) - return - - finish_action(controller, FALSE) - -/datum/ai_behavior/find_mineral_wall/proc/check_if_mineable(datum/ai_controller/controller, turf/target_wall) - var/mob/living/source = controller.pawn - var/direction_to_turf = get_dir(target_wall, source) - if(!ISDIAGONALDIR(direction_to_turf)) - return TRUE - var/list/directions_to_check = list() - for(var/direction_check in GLOB.cardinals) - if(direction_check & direction_to_turf) - directions_to_check += direction_check - - for(var/direction in directions_to_check) - var/turf/test_turf = get_step(target_wall, direction) - if(isnull(test_turf)) - continue - if(!test_turf.is_blocked_turf(ignore_atoms = list(source))) - return TRUE - return FALSE diff --git a/code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm b/code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm new file mode 100644 index 00000000000..3c03702b699 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm @@ -0,0 +1,73 @@ +//behavior to find mineable mineral walls + +/datum/ai_planning_subtree/mine_walls + var/find_wall_behavior = /datum/ai_behavior/find_mineral_wall + +/datum/ai_planning_subtree/mine_walls/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(controller.blackboard_key_exists(BB_TARGET_MINERAL_WALL)) + controller.queue_behavior(/datum/ai_behavior/mine_wall, BB_TARGET_MINERAL_WALL) + return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(find_wall_behavior, BB_TARGET_MINERAL_WALL) + +/datum/ai_behavior/mine_wall + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + action_cooldown = 15 SECONDS + +/datum/ai_behavior/mine_wall/setup(datum/ai_controller/controller, target_key) + . = ..() + var/turf/target = controller.blackboard[target_key] + if(QDELETED(target)) + return FALSE + set_movement_target(controller, target) + +/datum/ai_behavior/mine_wall/perform(seconds_per_tick, datum/ai_controller/controller, target_key) + . = ..() + var/mob/living/basic/living_pawn = controller.pawn + var/turf/closed/mineral/target = controller.blackboard[target_key] + var/is_gibtonite_turf = istype(target, /turf/closed/mineral/gibtonite) + if(QDELETED(target)) + finish_action(controller, FALSE, target_key) + return + living_pawn.melee_attack(target) + if(is_gibtonite_turf) + living_pawn.manual_emote("sighs...") //accept whats about to happen to us + + finish_action(controller, TRUE, target_key) + return + +/datum/ai_behavior/mine_wall/finish_action(datum/ai_controller/controller, success, target_key) + . = ..() + controller.clear_blackboard_key(target_key) + +/datum/ai_behavior/find_mineral_wall + +/datum/ai_behavior/find_mineral_wall/perform(seconds_per_tick, datum/ai_controller/controller, found_wall_key) + . = ..() + var/mob/living_pawn = controller.pawn + + for(var/turf/closed/mineral/potential_wall in oview(9, living_pawn)) + if(!check_if_mineable(controller, potential_wall)) //check if its surrounded by walls + continue + controller.set_blackboard_key(found_wall_key, potential_wall) //closest wall first! + finish_action(controller, TRUE) + return + + finish_action(controller, FALSE) + +/datum/ai_behavior/find_mineral_wall/proc/check_if_mineable(datum/ai_controller/controller, turf/target_wall) + var/mob/living/source = controller.pawn + var/direction_to_turf = get_dir(target_wall, source) + if(!ISDIAGONALDIR(direction_to_turf)) + return TRUE + var/list/directions_to_check = list() + for(var/direction_check in GLOB.cardinals) + if(direction_check & direction_to_turf) + directions_to_check += direction_check + + for(var/direction in directions_to_check) + var/turf/test_turf = get_step(target_wall, direction) + if(isnull(test_turf)) + continue + if(!test_turf.is_blocked_turf(ignore_atoms = list(source))) + return TRUE + return FALSE diff --git a/code/datums/ai/idle_behaviors/idle_random_walk.dm b/code/datums/ai/idle_behaviors/idle_random_walk.dm index d5a3972a3d0..d99957f419b 100644 --- a/code/datums/ai/idle_behaviors/idle_random_walk.dm +++ b/code/datums/ai/idle_behaviors/idle_random_walk.dm @@ -24,3 +24,44 @@ if (!controller.blackboard_key_exists(target_key)) return return ..() + +/// walk randomly however stick near a target +/datum/idle_behavior/walk_near_target + /// chance to walk + var/walk_chance = 25 + /// distance we are to target + var/minimum_distance = 20 + /// key that holds target + var/target_key + +/datum/idle_behavior/walk_near_target/perform_idle_behavior(seconds_per_tick, datum/ai_controller/controller) + . = ..() + var/mob/living/living_pawn = controller.pawn + if(LAZYLEN(living_pawn.do_afters)) + return + + if(!SPT_PROB(walk_chance, seconds_per_tick) || !(living_pawn.mobility_flags & MOBILITY_MOVE) || !isturf(living_pawn.loc) || living_pawn.pulledby) + return + + var/atom/target = controller.blackboard[target_key] + var/distance = get_dist(target, living_pawn) + if(isnull(target) || distance > minimum_distance) //if we are too far away from target, just walk randomly + var/move_dir = pick(GLOB.alldirs) + living_pawn.Move(get_step(living_pawn, move_dir), move_dir) + return + + var/list/possible_turfs = list() + for(var/direction in GLOB.alldirs) + var/turf/possible_step = get_step(living_pawn, direction) + if(get_dist(possible_step, target) > minimum_distance) + continue + if(possible_step.is_blocked_turf()) + continue + possible_turfs += possible_step + + if(!length(possible_turfs)) + return + + var/turf/picked_turf = pick(possible_turfs) + + living_pawn.Move(picked_turf, get_dir(living_pawn, picked_turf)) diff --git a/code/datums/components/pet_commands/fetch.dm b/code/datums/components/pet_commands/fetch.dm index a8723f8bd4b..ae33983e1d0 100644 --- a/code/datums/components/pet_commands/fetch.dm +++ b/code/datums/components/pet_commands/fetch.dm @@ -18,6 +18,8 @@ /datum/pet_command/point_targetting/fetch/New(mob/living/parent) . = ..() + if(isnull(parent)) + return parent.AddElement(/datum/element/ai_held_item) // We don't remove this on destroy because they might still be holding something /datum/pet_command/point_targetting/fetch/add_new_friend(mob/living/tamer) diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm index 91b964e9d31..aa5a0505229 100644 --- a/code/datums/ruins/lavaland.dm +++ b/code/datums/ruins/lavaland.dm @@ -286,3 +286,11 @@ suffix = "lavaland_battle_site.dmm" allow_duplicates = TRUE cost = 3 + +/datum/map_template/ruin/lavaland/mook_village + name = "Mook Village" + id = "mook_village" + description = "A village hosting a community of friendly mooks!" + suffix = "lavaland_surface_mookvillage.dmm" + allow_duplicates = FALSE + cost = 5 diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm index 3c652f888c2..fe1c4150315 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm @@ -13,9 +13,9 @@ /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/dig_away_from_danger, /datum/ai_planning_subtree/flee_target, - /datum/ai_planning_subtree/find_and_hunt_target/consume_ores, + /datum/ai_planning_subtree/find_and_hunt_target/hunt_ores, /datum/ai_planning_subtree/find_and_hunt_target/baby_egg, - /datum/ai_planning_subtree/grub_mine, + /datum/ai_planning_subtree/mine_walls, ) /datum/ai_controller/basic_controller/babygrub @@ -32,29 +32,29 @@ planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/dig_away_from_danger, - /datum/ai_planning_subtree/find_and_hunt_target/consume_ores, + /datum/ai_planning_subtree/find_and_hunt_target/hunt_ores, /datum/ai_planning_subtree/flee_target, /datum/ai_planning_subtree/look_for_adult, ) ///consume food! -/datum/ai_planning_subtree/find_and_hunt_target/consume_ores +/datum/ai_planning_subtree/find_and_hunt_target/hunt_ores target_key = BB_ORE_TARGET - hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/consume_ores - finding_behavior = /datum/ai_behavior/find_hunt_target/consume_ores + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/hunt_ores + finding_behavior = /datum/ai_behavior/find_hunt_target/hunt_ores hunt_targets = list(/obj/item/stack/ore) hunt_chance = 75 hunt_range = 9 -/datum/ai_behavior/find_hunt_target/consume_ores +/datum/ai_behavior/find_hunt_target/hunt_ores -/datum/ai_behavior/find_hunt_target/consume_ores/valid_dinner(mob/living/basic/source, obj/item/stack/ore/target, radius) +/datum/ai_behavior/find_hunt_target/hunt_ores/valid_dinner(mob/living/basic/source, obj/item/stack/ore/target, radius) var/list/forbidden_ore = source.ai_controller.blackboard[BB_ORE_IGNORE_TYPES] if(is_type_in_list(target, forbidden_ore)) return FALSE - if(target in source) + if(!isturf(target.loc)) return FALSE var/obj/item/pet_target = source.ai_controller.blackboard[BB_CURRENT_PET_TARGET] @@ -63,7 +63,7 @@ return can_see(source, target, radius) -/datum/ai_behavior/hunt_target/unarmed_attack_target/consume_ores +/datum/ai_behavior/hunt_target/unarmed_attack_target/hunt_ores always_reset_target = TRUE ///find our child's egg and pull it! @@ -121,45 +121,6 @@ /datum/ai_behavior/use_mob_ability/burrow behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION -///mine walls to look for food! -/datum/ai_planning_subtree/grub_mine - -/datum/ai_planning_subtree/grub_mine/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - if(controller.blackboard_key_exists(BB_TARGET_MINERAL_WALL)) - controller.queue_behavior(/datum/ai_behavior/mine_wall, BB_TARGET_MINERAL_WALL) - return SUBTREE_RETURN_FINISH_PLANNING - controller.queue_behavior(/datum/ai_behavior/find_mineral_wall, BB_TARGET_MINERAL_WALL) - -/datum/ai_behavior/mine_wall - behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION - action_cooldown = 15 SECONDS - -/datum/ai_behavior/mine_wall/setup(datum/ai_controller/controller, target_key) - . = ..() - var/turf/target = controller.blackboard[target_key] - if(isnull(target)) - return FALSE - set_movement_target(controller, target) - -/datum/ai_behavior/mine_wall/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - . = ..() - var/mob/living/basic/living_pawn = controller.pawn - var/turf/closed/mineral/target = controller.blackboard[target_key] - var/is_gibtonite_turf = istype(target, /turf/closed/mineral/gibtonite) - if(QDELETED(target)) - finish_action(controller, FALSE, target_key) - return - living_pawn.melee_attack(target) - if(is_gibtonite_turf) - living_pawn.manual_emote("sighs...") //accept whats about to happen to us - - finish_action(controller, TRUE, target_key) - return - -/datum/ai_behavior/mine_wall/finish_action(datum/ai_controller/controller, success, target_key) - . = ..() - controller.clear_blackboard_key(target_key) - /datum/pet_command/grub_spit command_name = "Spit" command_desc = "Ask your grub pet to spit out its ores." diff --git a/code/modules/mob/living/basic/lavaland/mook/mook.dm b/code/modules/mob/living/basic/lavaland/mook/mook.dm new file mode 100644 index 00000000000..da833437715 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/mook/mook.dm @@ -0,0 +1,273 @@ +//Fragile but highly aggressive wanderers that pose a large threat in numbers. +//They'll attempt to leap at their target from afar using their hatchets. +/mob/living/basic/mining/mook + name = "wanderer" + desc = "This unhealthy looking primitive seems to be talented at administiring health care." + icon = 'icons/mob/simple/jungle/mook.dmi' + icon_state = "mook" + icon_living = "mook" + icon_dead = "mook_dead" + mob_biotypes = MOB_ORGANIC|MOB_HUMANOID + gender = FEMALE + maxHealth = 150 + faction = list(FACTION_MINING, FACTION_NEUTRAL) + health = 150 + move_resist = MOVE_FORCE_OVERPOWERING + melee_damage_lower = 8 + melee_damage_upper = 8 + pass_flags_self = LETPASSTHROW + attack_sound = 'sound/weapons/rapierhit.ogg' + attack_vis_effect = ATTACK_EFFECT_SLASH + death_sound = 'sound/voice/mook_death.ogg' + ai_controller = /datum/ai_controller/basic_controller/mook/support + speed = 5 + + pixel_x = -16 + base_pixel_x = -16 + pixel_y = -16 + base_pixel_y = -16 + + ///the state of combat we are in + var/attack_state = MOOK_ATTACK_NEUTRAL + ///are we a healer? + var/is_healer = TRUE + ///the ore we are holding if any + var/obj/held_ore + ///overlay for neutral stance + var/mutable_appearance/neutral_stance + ///overlay for attacking stance + var/mutable_appearance/attack_stance + ///overlay when we hold an ore + var/mutable_appearance/ore_overlay + ///commands we obey + var/list/pet_commands = list( + /datum/pet_command/idle, + /datum/pet_command/free, + /datum/pet_command/point_targetting/attack, + /datum/pet_command/point_targetting/fetch, + ) + +/mob/living/basic/mining/mook/Initialize(mapload) + . = ..() + AddComponent(/datum/component/ai_retaliate_advanced, CALLBACK(src, PROC_REF(attack_intruder))) + var/datum/action/cooldown/mob_cooldown/mook_ability/mook_jump/jump = new(src) + jump.Grant(src) + ai_controller.set_blackboard_key(BB_MOOK_JUMP_ABILITY, jump) + + ore_overlay = mutable_appearance(icon, "mook_ore_overlay") + + AddComponent(/datum/component/ai_listen_to_weather) + AddElement(/datum/element/wall_smasher) + RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) + RegisterSignal(src, COMSIG_KB_MOB_DROPITEM_DOWN, PROC_REF(drop_ore)) + + if(is_healer) + grant_healer_abilities() + + AddComponent(/datum/component/obeys_commands, pet_commands) + +/mob/living/basic/mining/mook/proc/grant_healer_abilities() + AddComponent(\ + /datum/component/healing_touch,\ + heal_brute = melee_damage_upper,\ + heal_burn = melee_damage_upper,\ + heal_time = 0,\ + valid_targets_typecache = typecacheof(list(/mob/living/basic/mining/mook)),\ + ) + +/mob/living/basic/mining/mook/Entered(atom/movable/mover) + if(istype(mover, /obj/item/stack/ore)) + held_ore = mover + update_appearance(UPDATE_OVERLAYS) + + return ..() + +/mob/living/basic/mining/mook/Exited(atom/movable/mover) + . = ..() + if(held_ore != mover) + return + held_ore = null + update_appearance(UPDATE_OVERLAYS) + +/mob/living/basic/mining/mook/proc/pre_attack(mob/living/attacker, atom/target) + SIGNAL_HANDLER + + return attack_sequence(target) + +/mob/living/basic/mining/mook/proc/attack_sequence(atom/target) + if(istype(target, /obj/item/stack/ore) && isnull(held_ore)) + var/obj/item/ore_target = target + ore_target.forceMove(src) + return COMPONENT_HOSTILE_NO_ATTACK + + if(istype(target, /obj/structure/material_stand)) + if(held_ore) + held_ore.forceMove(target) + return COMPONENT_HOSTILE_NO_ATTACK + + if(istype(target, /obj/structure/bonfire)) + var/obj/structure/bonfire/fire_target = target + if(!fire_target.burning) + fire_target.start_burning() + return COMPONENT_HOSTILE_NO_ATTACK + +/mob/living/basic/mining/mook/proc/change_combatant_state(state) + attack_state = state + update_appearance() + +/mob/living/basic/mining/mook/Destroy() + QDEL_NULL(held_ore) + return ..() + +/mob/living/basic/mining/mook/update_icon_state() + . = ..() + if(stat == DEAD) + return + switch(attack_state) + if(MOOK_ATTACK_NEUTRAL) + icon_state = "mook" + if(MOOK_ATTACK_WARMUP) + icon_state = "mook_warmup" + if(MOOK_ATTACK_ACTIVE) + icon_state = "mook_leap" + if(MOOK_ATTACK_STRIKE) + icon_state = "mook_strike" + +/mob/living/basic/mining/mook/update_overlays() + . = ..() + if(stat == DEAD) + return + + if(attack_state != MOOK_ATTACK_NEUTRAL || isnull(held_ore)) + return + + . += ore_overlay + +/mob/living/basic/mining/mook/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE, quickstart = TRUE) + change_combatant_state(state = MOOK_ATTACK_ACTIVE) + return ..() + +/mob/living/basic/mining/mook/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + . = ..() + change_combatant_state(state = MOOK_ATTACK_NEUTRAL) + +/mob/living/basic/mining/mook/CanAllowThrough(atom/movable/mover, border_dir) + . = ..() + + if(!istype(mover, /mob/living/basic/mining/mook)) + return FALSE + + var/mob/living/basic/mining/mook/mook_moover = mover + if(mook_moover.attack_state == MOOK_ATTACK_ACTIVE) + return TRUE + +/mob/living/basic/mining/mook/proc/drop_ore(mob/living/user) + SIGNAL_HANDLER + + if(isnull(held_ore)) + return + dropItemToGround(held_ore) + return COMSIG_KB_ACTIVATED + +/mob/living/basic/mining/mook/death() + desc = "A deceased primitive. Upon closer inspection, it was suffering from severe cellular degeneration and its garments are machine made..." //Can you guess the twist + return ..() + +/mob/living/basic/mining/mook/proc/attack_intruder(mob/living/intruder) + if(istype(intruder, /mob/living/basic/mining/mook)) + return + for(var/mob/living/basic/mining/mook/villager in oview(src, 9)) + villager.ai_controller?.insert_blackboard_key_lazylist(BB_BASIC_MOB_RETALIATE_LIST, intruder) + + +/mob/living/basic/mining/mook/worker + desc = "This unhealthy looking primitive is wielding a rudimentary hatchet, swinging it with wild abandon. One isn't much of a threat, but in numbers they can quickly overwhelm a superior opponent." + gender = MALE + melee_damage_lower = 15 + melee_damage_upper = 15 + ai_controller = /datum/ai_controller/basic_controller/mook + is_healer = FALSE + +/mob/living/basic/mining/mook/worker/Initialize(mapload) + . = ..() + neutral_stance = mutable_appearance(icon, "mook_axe_overlay") + attack_stance = mutable_appearance(icon, "axe_strike_overlay") + update_appearance() + var/datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/leap = new(src) + leap.Grant(src) + ai_controller.set_blackboard_key(BB_MOOK_LEAP_ABILITY, leap) + +/mob/living/basic/mining/mook/worker/attack_sequence(atom/target) + . = ..() + if(. & COMPONENT_HOSTILE_NO_ATTACK) + return + + if(attack_state == MOOK_ATTACK_STRIKE) + return COMPONENT_HOSTILE_NO_ATTACK + + change_combatant_state(state = MOOK_ATTACK_STRIKE) + addtimer(CALLBACK(src, PROC_REF(change_combatant_state), MOOK_ATTACK_NEUTRAL), 0.3 SECONDS) + +/mob/living/basic/mining/mook/worker/update_overlays() + . = ..() + if(stat == DEAD) + return + + switch(attack_state) + if(MOOK_ATTACK_STRIKE) + . += attack_stance + if(MOOK_ATTACK_NEUTRAL) + . += neutral_stance + +/mob/living/basic/mining/mook/worker/bard + desc = "It's holding a guitar?" + melee_damage_lower = 10 + melee_damage_upper = 10 + gender = MALE + attack_sound = 'sound/weapons/stringsmash.ogg' + death_sound = 'sound/voice/mook_death.ogg' + ai_controller = /datum/ai_controller/basic_controller/mook/bard + ///our guitar + var/obj/item/instrument/guitar/held_guitar + +/mob/living/basic/mining/mook/worker/bard/Initialize(mapload) + . = ..() + neutral_stance = mutable_appearance(icon, "bard_overlay") + attack_stance = mutable_appearance(icon, "bard_strike") + held_guitar = new(src) + ai_controller.set_blackboard_key(BB_SONG_INSTRUMENT, held_guitar) + update_appearance() + +/mob/living/basic/mining/mook/worker/tribal_chief + name = "tribal chief" + desc = "Acknowledge him!" + gender = MALE + melee_damage_lower = 20 + melee_damage_upper = 20 + ai_controller = /datum/ai_controller/basic_controller/mook/tribal_chief + ///overlay in our neutral state + var/static/mutable_appearance/chief_neutral = mutable_appearance('icons/mob/simple/jungle/mook.dmi', "mook_chief") + ///overlay in our striking state + var/static/mutable_appearance/chief_strike = mutable_appearance('icons/mob/simple/jungle/mook.dmi', "mook_chief_strike") + ///overlay in our active state + var/static/mutable_appearance/chief_active = mutable_appearance('icons/mob/simple/jungle/mook.dmi', "mook_chief_leap") + ///overlay in our warmup state + var/static/mutable_appearance/chief_warmup = mutable_appearance('icons/mob/simple/jungle/mook.dmi', "mook_chief_warmup") + +/mob/living/basic/mining/mook/worker/tribal_chief/Initialize(mapload) + . = ..() + update_appearance() + +/mob/living/basic/mining/mook/worker/tribal_chief/update_overlays() + . = ..() + if(stat == DEAD) + return + switch(attack_state) + if(MOOK_ATTACK_NEUTRAL) + . += chief_neutral + if(MOOK_ATTACK_WARMUP) + . += chief_warmup + if(MOOK_ATTACK_ACTIVE) + . += chief_active + if(MOOK_ATTACK_STRIKE) + . += chief_strike diff --git a/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm b/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm new file mode 100644 index 00000000000..cfc359bd54f --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm @@ -0,0 +1,140 @@ +/datum/action/cooldown/mob_cooldown/mook_ability + ///are we a mook? + var/is_mook = FALSE + +/datum/action/cooldown/mob_cooldown/mook_ability/Grant(mob/grant_to) + . = ..() + if(isnull(owner)) + return + is_mook = istype(owner, /mob/living/basic/mining/mook) + +/datum/action/cooldown/mob_cooldown/mook_ability/IsAvailable(feedback) + . = ..() + + if(!.) + return FALSE + + if(!is_mook) + return TRUE + + var/mob/living/basic/mining/mook/mook_owner = owner + if(mook_owner.attack_state != MOOK_ATTACK_NEUTRAL) + if(feedback) + mook_owner.balloon_alert(mook_owner, "still recovering!") + return FALSE + return TRUE + +/datum/action/cooldown/mob_cooldown/mook_ability/mook_leap + name = "Mook leap" + desc = "Leap towards the enemy!" + cooldown_time = 7 SECONDS + shared_cooldown = NONE + melee_cooldown_time = 0 SECONDS + ///telegraph time before jumping + var/wind_up_time = 2 SECONDS + ///intervals between each of our attacks + var/attack_interval = 0.4 SECONDS + ///how many times do we attack if we reach the target? + var/times_to_attack = 4 + +/datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/Activate(atom/target) + if(owner.CanReach(target)) + attack_combo(target) + StartCooldown() + return TRUE + + if(is_mook) + var/mob/living/basic/mining/mook/mook_owner = owner + mook_owner.change_combatant_state(state = MOOK_ATTACK_WARMUP) + + addtimer(CALLBACK(src, PROC_REF(launch_towards_target), target), wind_up_time) + StartCooldown() + return TRUE + +/datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/proc/launch_towards_target(atom/target) + new /obj/effect/temp_visual/mook_dust(get_turf(owner)) + playsound(get_turf(owner), 'sound/weapons/thudswoosh.ogg', 25, TRUE) + playsound(owner, 'sound/voice/mook_leap_yell.ogg', 100, TRUE) + var/turf/target_turf = get_turf(target) + + if(!target_turf.is_blocked_turf()) + owner.throw_at(target = target_turf, range = 7, speed = 1, spin = FALSE, callback = CALLBACK(src, PROC_REF(attack_combo), target)) + return + + var/list/open_turfs = list() + + for(var/turf/possible_turf in get_adjacent_open_turfs(target)) + if(possible_turf.is_blocked_turf()) + continue + open_turfs += possible_turf + + if(!length(open_turfs)) + return + + var/turf/final_turf = get_closest_atom(/turf, open_turfs, owner) + owner.throw_at(target = final_turf, range = 7, speed = 1, spin = FALSE, callback = CALLBACK(src, PROC_REF(attack_combo), target)) + +/datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/proc/attack_combo(atom/target) + if(!owner.CanReach(target)) + return FALSE + + for(var/i in 0 to (times_to_attack - 1)) + addtimer(CALLBACK(src, PROC_REF(attack_target), target), i * attack_interval) + +/datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/proc/attack_target(atom/target) + if(!owner.CanReach(target) || owner.stat == DEAD) + return + var/mob/living/basic/basic_owner = owner + basic_owner.melee_attack(target, ignore_cooldown = TRUE) + +/datum/action/cooldown/mob_cooldown/mook_ability/mook_jump + name = "Mook Jump" + desc = "Soar high in the air!" + cooldown_time = 14 SECONDS + shared_cooldown = NONE + melee_cooldown_time = 0 SECONDS + click_to_activate = FALSE + +/datum/action/cooldown/mob_cooldown/mook_ability/mook_jump/Activate(atom/target) + var/obj/effect/landmark/drop_zone = locate(/obj/effect/landmark/mook_village) in GLOB.landmarks_list + if(drop_zone?.z == owner.z) + var/turf/jump_destination = get_turf(drop_zone) + jump_to_turf(jump_destination) + StartCooldown() + return TRUE + var/list/potential_turfs = list() + for(var/turf/open_turf in oview(9, owner)) + if(!open_turf.is_blocked_turf()) + potential_turfs += open_turf + if(!length(potential_turfs)) + return FALSE + jump_to_turf(pick(potential_turfs)) + StartCooldown() + return TRUE + +/datum/action/cooldown/mob_cooldown/mook_ability/mook_jump/proc/jump_to_turf(turf/target) + if(is_mook) + var/mob/living/basic/mining/mook/mook_owner = owner + mook_owner.change_combatant_state(state = MOOK_ATTACK_ACTIVE) + new /obj/effect/temp_visual/mook_dust(get_turf(owner)) + playsound(get_turf(owner), 'sound/weapons/thudswoosh.ogg', 50, TRUE) + animate(owner, pixel_y = owner.base_pixel_y + 146, time = 0.5 SECONDS) + addtimer(CALLBACK(src, PROC_REF(land_on_turf), target), 0.5 SECONDS) + +/datum/action/cooldown/mob_cooldown/mook_ability/mook_jump/proc/land_on_turf(turf/target) + do_teleport(owner, target, precision = 3, no_effects = TRUE) + animate(owner, pixel_y = owner.base_pixel_y, time = 0.5 SECONDS) + new /obj/effect/temp_visual/mook_dust(get_turf(owner)) + if(is_mook) + addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/living/basic/mining/mook, change_combatant_state), MOOK_ATTACK_NEUTRAL), 0.5 SECONDS) + +/obj/effect/temp_visual/mook_dust + name = "dust" + desc = "It's just a dust cloud!" + icon = 'icons/mob/simple/jungle/mook.dmi' + icon_state = "mook_leap_cloud" + layer = BELOW_MOB_LAYER + plane = GAME_PLANE + base_pixel_y = -16 + base_pixel_x = -16 + duration = 1 SECONDS diff --git a/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm new file mode 100644 index 00000000000..14ed9eb2982 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm @@ -0,0 +1,426 @@ +///commands the chief can pick from +GLOBAL_LIST_INIT(mook_commands, list( + new /datum/pet_command/point_targetting/attack, + new /datum/pet_command/point_targetting/fetch, +)) + +/datum/ai_controller/basic_controller/mook + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/mook, + BB_BLACKLIST_MINERAL_TURFS = list(/turf/closed/mineral/gibtonite, /turf/closed/mineral/strong), + BB_MAXIMUM_DISTANCE_TO_VILLAGE = 7, + BB_STORM_APPROACHING = FALSE, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/look_for_village, + /datum/ai_planning_subtree/targeted_mob_ability/leap, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/find_and_hunt_target/material_stand, + /datum/ai_planning_subtree/use_mob_ability/mook_jump, + /datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/mook, + /datum/ai_planning_subtree/mine_walls/mook, + /datum/ai_planning_subtree/wander_away_from_village, + ) + +///check for faction if not a ash walker, otherwise just attack +/datum/targetting_datum/basic/mook/faction_check(mob/living/living_mob, mob/living/the_target) + if(FACTION_ASHWALKER in living_mob.faction) + return FALSE + + return ..() + +/datum/ai_planning_subtree/targeted_mob_ability/leap + ability_key = BB_MOOK_LEAP_ABILITY + +/datum/ai_planning_subtree/use_mob_ability/mook_jump + ability_key = BB_MOOK_JUMP_ABILITY + +///jump towards the village when we have found ore or there is a storm coming +/datum/ai_planning_subtree/use_mob_ability/mook_jump/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/storm_approaching = controller.blackboard[BB_STORM_APPROACHING] + var/mob/living/living_pawn = controller.pawn + var/obj/effect/home = controller.blackboard[BB_HOME_VILLAGE] + if(QDELETED(home)) + return + if(get_dist(living_pawn, home) < controller.blackboard[BB_MAXIMUM_DISTANCE_TO_VILLAGE]) + return + if(home.z != living_pawn.z) + return + if(!storm_approaching && !(locate(/obj/item/stack/ore) in living_pawn)) + return + + controller.clear_blackboard_key(BB_TARGET_MINERAL_WALL) + return ..() + +///hunt ores that we will haul off back to the village +/datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/mook + +/datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/mook/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + if(locate(/obj/item/stack/ore) in living_pawn) + return + return ..() + +///deposit ores into the stand! +/datum/ai_planning_subtree/find_and_hunt_target/material_stand + target_key = BB_MATERIAL_STAND_TARGET + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/material_stand + finding_behavior = /datum/ai_behavior/find_hunt_target + hunt_targets = list(/obj/structure/material_stand) + hunt_range = 9 + +/datum/ai_planning_subtree/find_and_hunt_target/material_stand/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + if(!locate(/obj/item/stack/ore) in living_pawn) + return + return ..() + +/datum/ai_behavior/hunt_target/unarmed_attack_target/material_stand + required_distance = 0 + always_reset_target = TRUE + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT + +///try to face the counter when depositing ores +/datum/ai_behavior/hunt_target/unarmed_attack_target/material_stand/setup(datum/ai_controller/controller, hunting_target_key, hunting_cooldown_key) + . = ..() + var/atom/hunt_target = controller.blackboard[hunting_target_key] + if (QDELETED(hunt_target)) + return FALSE + var/list/possible_turfs = list() + var/list/directions = list(SOUTH, SOUTHEAST) + + for(var/direction in directions) + var/turf/bottom_turf = get_step(hunt_target, direction) + if(!bottom_turf.is_blocked_turf()) + possible_turfs += bottom_turf + + if(!length(possible_turfs)) + return FALSE + set_movement_target(controller, pick(possible_turfs)) + +///look for our village +/datum/ai_planning_subtree/look_for_village + +/datum/ai_planning_subtree/look_for_village/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(controller.blackboard_key_exists(BB_HOME_VILLAGE)) + return + + controller.queue_behavior(/datum/ai_behavior/find_village, BB_HOME_VILLAGE) + +/datum/ai_behavior/find_village + +/datum/ai_behavior/find_village/perform(seconds_per_tick, datum/ai_controller/controller, village_key) + . = ..() + + var/obj/effect/landmark/home_marker = locate(/obj/effect/landmark/mook_village) in GLOB.landmarks_list + if(isnull(home_marker)) + finish_action(controller, FALSE) + return + + controller.set_blackboard_key(village_key, home_marker) + finish_action(controller, TRUE) + +///explore the lands away from the village to look for ore +/datum/ai_planning_subtree/wander_away_from_village + +/datum/ai_planning_subtree/wander_away_from_village/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + var/storm_approaching = controller.blackboard[BB_STORM_APPROACHING] + ///if we have ores to deposit or a storm is approaching, dont wander away + if(storm_approaching || (locate(/obj/item/stack/ore) in living_pawn)) + return + + if(controller.blackboard_key_exists(BB_HOME_VILLAGE)) + controller.queue_behavior(/datum/ai_behavior/wander, BB_HOME_VILLAGE) + +/datum/ai_behavior/wander + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + required_distance = 0 + /// distance we will wander away from the village + var/wander_distance = 9 + +/datum/ai_behavior/wander/setup(datum/ai_controller/controller, village_key) + . = ..() + var/mob/living/living_pawn = controller.pawn + var/obj/effect/target = controller.blackboard[village_key] + if(QDELETED(target)) + return FALSE + + if(target.z != living_pawn.z) + return FALSE + + var/list/angle_directions = list() + for(var/direction in GLOB.alldirs) + angle_directions += dir2angle(direction) + + var/angle_to_home = get_angle(living_pawn, target) + angle_directions -= angle_to_home + angle_directions -= (angle_to_home + 45) + angle_directions -= (angle_to_home - 45) + shuffle_inplace(angle_directions) + + var/turf/wander_destination = get_turf(living_pawn) + for(var/angle in angle_directions) + var/turf/test_turf = get_furthest_turf(living_pawn, angle, target) + if(isnull(test_turf)) + continue + var/distance_from_target = get_dist(target, test_turf) + if(distance_from_target <= get_dist(target, wander_destination)) + continue + wander_destination = test_turf + if(distance_from_target == wander_distance) + break + + set_movement_target(controller, wander_destination) + +/datum/ai_behavior/wander/proc/get_furthest_turf(atom/source, angle, atom/target) + var/turf/return_turf + for(var/i in 1 to wander_distance) + var/turf/test_destination = get_ranged_target_turf_direct(source, target, range = i, offset = angle) + if(test_destination.is_blocked_turf(source_atom = source)) + break + return_turf = test_destination + return return_turf + +/datum/ai_behavior/wander/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key) + . = ..() + finish_action(controller, TRUE) + +/datum/ai_planning_subtree/mine_walls/mook + find_wall_behavior = /datum/ai_behavior/find_mineral_wall/mook + +/datum/ai_planning_subtree/mine_walls/mook/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + var/storm_approaching = controller.blackboard[BB_STORM_APPROACHING] + if(storm_approaching || locate(/obj/item/stack/ore) in living_pawn) + return + return ..() + +/datum/ai_behavior/find_mineral_wall/mook + +/datum/ai_behavior/find_mineral_wall/mook/check_if_mineable(datum/ai_controller/controller, turf/target_wall) + var/list/forbidden_turfs = controller.blackboard[BB_BLACKLIST_MINERAL_TURFS] + if(is_type_in_list(target_wall, forbidden_turfs)) + return FALSE + return ..() + +///bard mook plays nice music for the village +/datum/ai_controller/basic_controller/mook/bard + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/mook, + BB_MAXIMUM_DISTANCE_TO_VILLAGE = 10, + BB_STORM_APPROACHING = FALSE, + BB_SONG_LINES = MOOK_SONG, + ) + idle_behavior = /datum/idle_behavior/walk_near_target/mook_village + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/look_for_village, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/play_music_for_visitor, + /datum/ai_planning_subtree/use_mob_ability/mook_jump, + /datum/ai_planning_subtree/generic_play_instrument, + ) + + +///find an audience to follow and play music for! +/datum/ai_planning_subtree/play_music_for_visitor + +/datum/ai_planning_subtree/play_music_for_visitor/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!controller.blackboard_key_exists(BB_MOOK_MUSIC_AUDIENCE)) + controller.queue_behavior(/datum/ai_behavior/find_and_set/music_audience, BB_MOOK_MUSIC_AUDIENCE, /mob/living/carbon/human) + return + var/atom/home = controller.blackboard[BB_HOME_VILLAGE] + if(isnull(home)) + return + + var/atom/human_target = controller.blackboard[BB_MOOK_MUSIC_AUDIENCE] + if(get_dist(human_target, home) > controller.blackboard[BB_MAXIMUM_DISTANCE_TO_VILLAGE] || controller.blackboard[BB_STORM_APPROACHING]) + controller.clear_blackboard_key(BB_MOOK_MUSIC_AUDIENCE) + return + + controller.queue_behavior(/datum/ai_behavior/travel_towards, BB_MOOK_MUSIC_AUDIENCE) + +/datum/ai_behavior/find_and_set/music_audience + +/datum/ai_behavior/find_and_set/music_audience/search_tactic(datum/ai_controller/controller, locate_path, search_range) + var/atom/home = controller.blackboard[BB_HOME_VILLAGE] + for(var/mob/living/carbon/human/target in oview(search_range, controller.pawn)) + if(target.stat > UNCONSCIOUS || !target.mind) + continue + if(isnull(home) || get_dist(target, home) > controller.blackboard[BB_MAXIMUM_DISTANCE_TO_VILLAGE]) + continue + return target + +/datum/idle_behavior/walk_near_target/mook_village + target_key = BB_HOME_VILLAGE + +///healer mooks guard the village from intruders and heal the miner mooks when they come home +/datum/ai_controller/basic_controller/mook/support + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/mook, + BB_MAXIMUM_DISTANCE_TO_VILLAGE = 10, + BB_STORM_APPROACHING = FALSE, + BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/not_friends, + ) + idle_behavior = /datum/idle_behavior/walk_near_target/mook_village + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/look_for_village, + /datum/ai_planning_subtree/acknowledge_chief, + /datum/ai_planning_subtree/pet_planning, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/use_mob_ability/mook_jump, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/find_and_hunt_target/injured_mooks, + ) + +///tree to find and register our leader +/datum/ai_planning_subtree/acknowledge_chief/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(controller.blackboard_key_exists(BB_MOOK_TRIBAL_CHIEF)) + return + controller.queue_behavior(/datum/ai_behavior/find_and_set/find_chief, BB_MOOK_TRIBAL_CHIEF, /mob/living/basic/mining/mook/worker/tribal_chief) + +/datum/ai_behavior/find_and_set/find_chief/search_tactic(datum/ai_controller/controller, locate_path, search_range) + var/mob/living/chief = locate(locate_path) in oview(search_range, controller.pawn) + if(isnull(chief)) + return null + var/mob/living/living_pawn = controller.pawn + living_pawn.befriend(chief) + return chief + +///find injured miner mooks after they come home from a long day of work +/datum/ai_planning_subtree/find_and_hunt_target/injured_mooks + target_key = BB_INJURED_MOOK + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/injured_mooks + finding_behavior = /datum/ai_behavior/find_hunt_target/injured_mooks + hunt_targets = list(/mob/living/basic/mining/mook/worker) + hunt_range = 9 + +///we only heal when the mooks are home during a storm +/datum/ai_planning_subtree/find_and_hunt_target/injured_mooks/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(controller.blackboard[BB_STORM_APPROACHING]) + return ..() + + +/datum/ai_behavior/find_hunt_target/injured_mooks + +/datum/ai_behavior/find_hunt_target/injured_mooks/valid_dinner(mob/living/source, mob/living/injured_mook) + return (injured_mook.health < injured_mook.maxHealth) + +/datum/ai_behavior/hunt_target/unarmed_attack_target/injured_mooks + +/datum/ai_behavior/hunt_target/unarmed_attack_target/injured_mooks + always_reset_target = TRUE + hunt_cooldown = 10 SECONDS + + +///the chief would rather command his mooks to attack people than attack them himself +/datum/ai_controller/basic_controller/mook/tribal_chief + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/mook, + BB_STORM_APPROACHING = FALSE, + ) + idle_behavior = /datum/idle_behavior/walk_near_target/mook_village + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/look_for_village, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/targeted_mob_ability/leap, + /datum/ai_planning_subtree/issue_commands, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/find_and_hunt_target/material_stand, + /datum/ai_planning_subtree/use_mob_ability/mook_jump, + /datum/ai_planning_subtree/find_and_hunt_target/bonfire, + /datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/tribal_chief, + ) + +/datum/ai_planning_subtree/issue_commands + ///how far we look for a mook to command + var/command_distance = 5 + +/datum/ai_planning_subtree/issue_commands/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!locate(/mob/living/basic/mining/mook) in oview(command_distance, controller.pawn)) + return + if(controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) + controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_BASIC_MOB_CURRENT_TARGET, /datum/pet_command/point_targetting/attack) + return + + var/atom/ore_target = controller.blackboard[BB_ORE_TARGET] + var/mob/living/living_pawn = controller.pawn + if(isnull(ore_target)) + return + if(get_dist(ore_target, living_pawn) <= 1) + return + + controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_ORE_TARGET, /datum/pet_command/point_targetting/fetch) + +/datum/ai_behavior/issue_commands + action_cooldown = 5 SECONDS + +/datum/ai_behavior/issue_commands/perform(seconds_per_tick, datum/ai_controller/controller, target_key, command_path) + . = ..() + var/mob/living/basic/living_pawn = controller.pawn + var/atom/target = controller.blackboard[target_key] + + if(isnull(target)) + finish_action(controller, FALSE) + return + + var/datum/pet_command/to_command = locate(command_path) in GLOB.mook_commands + if(isnull(to_command)) + finish_action(controller, FALSE) + return + + var/issue_command = pick(to_command.speech_commands) + living_pawn.say(issue_command, forced = "controller") + living_pawn._pointed(target) + finish_action(controller, TRUE) + + +///find an ore, only pick it up when a mook brings it close to us +/datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/tribal_chief + +/datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/tribal_chief/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + if(locate(/obj/item/stack/ore) in living_pawn) + return + + var/atom/target_ore = controller.blackboard[BB_ORE_TARGET] + + if(isnull(target_ore)) + return ..() + + if(!isturf(target_ore.loc)) //picked up by someone else + controller.clear_blackboard_key(BB_ORE_TARGET) + return + + if(get_dist(target_ore, living_pawn) > 1) + return + + return ..() + +/datum/ai_planning_subtree/find_and_hunt_target/bonfire + target_key = BB_MOOK_BONFIRE_TARGET + finding_behavior = /datum/ai_behavior/find_hunt_target/bonfire + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/bonfire + hunt_targets = list(/obj/structure/bonfire) + hunt_range = 9 + + +/datum/ai_behavior/find_hunt_target/bonfire + +/datum/ai_behavior/find_hunt_target/bonfire/valid_dinner(mob/living/source, obj/structure/bonfire/fire, radius) + if(fire.burning) + return FALSE + + return can_see(source, fire, radius) + +/datum/ai_behavior/hunt_target/unarmed_attack_target/bonfire + always_reset_target = TRUE diff --git a/code/modules/mob/living/basic/lavaland/mook/mook_village.dm b/code/modules/mob/living/basic/lavaland/mook/mook_village.dm new file mode 100644 index 00000000000..e3a091f6f0e --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/mook/mook_village.dm @@ -0,0 +1,85 @@ +///unique items that spawn at the mook village +/obj/structure/material_stand + name = "material stand" + desc = "Is everyone free to use this thing?" + icon = 'icons/mob/simple/jungle/mook.dmi' + icon_state = "material_stand" + density = TRUE + anchored = TRUE + resistance_flags = INDESTRUCTIBLE + bound_width = 64 + bound_height = 64 + +/obj/structure/material_stand/attackby(obj/item/ore, mob/living/carbon/human/user, list/modifiers) + if(istype(ore, /obj/item/stack/ore)) + ore.forceMove(src) + return + return ..() + +/obj/structure/material_stand/Entered(atom/movable/mover) + . = ..() + update_appearance(UPDATE_OVERLAYS) + +/obj/structure/material_stand/Exited(atom/movable/mover) + . = ..() + update_appearance(UPDATE_OVERLAYS) + +///put ore icons on the counter! +/obj/structure/material_stand/update_overlays() + . = ..() + for(var/obj/item/stack/ore/ore_item in contents) + var/image/ore_icon = image(icon = initial(ore_item.icon), icon_state = initial(ore_item.icon_state), layer = LOW_ITEM_LAYER) + ore_icon.transform = ore_icon.transform.Scale(0.6, 0.6) + ore_icon.pixel_x = rand(9, 17) + ore_icon.pixel_y = rand(2, 4) + . += ore_icon + +/obj/structure/material_stand/ui_interact(mob/user, datum/tgui/ui) + . = ..() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "MaterialStand") + ui.open() + +/obj/structure/material_stand/ui_data(mob/user) + var/list/data = list() + data["ores"] = list() + for(var/obj/item/stack/ore/ore_item in contents) + data["ores"] += list(list( + "id" = REF(ore_item), + "name" = ore_item.name, + "amount" = ore_item.amount, + )) + return data + +/obj/structure/material_stand/ui_static_data(mob/user) + var/list/data = list() + data["ore_images"] = list() + for(var/obj/item/stack/ore_item as anything in subtypesof(/obj/item/stack/ore)) + data["ore_images"] += list(list( + "name" = initial(ore_item.name), + "icon" = icon2base64(getFlatIcon(image(icon = initial(ore_item.icon), icon_state = initial(ore_item.icon_state)), no_anim=TRUE)) + )) + return data + +/obj/structure/material_stand/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + + if(. || !isliving(usr)) + return TRUE + + var/mob/living/customer = usr + var/obj/item/stack_to_move + switch(action) + if("withdraw") + if(isnull(params["reference"])) + return TRUE + stack_to_move = locate(params["reference"]) in contents + if(isnull(stack_to_move)) + return TRUE + stack_to_move.forceMove(get_turf(customer)) + return TRUE + +/obj/effect/landmark/mook_village + name = "mook village landmark" + icon_state = "x" diff --git a/code/modules/mob/living/basic/minebots/minebot_ai.dm b/code/modules/mob/living/basic/minebots/minebot_ai.dm index a4b082f5dd1..33e9821dbc4 100644 --- a/code/modules/mob/living/basic/minebots/minebot_ai.dm +++ b/code/modules/mob/living/basic/minebots/minebot_ai.dm @@ -12,7 +12,7 @@ /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/basic_ranged_attack_subtree/minebot, - /datum/ai_planning_subtree/find_and_hunt_target/consume_ores/minebot, + /datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/minebot, /datum/ai_planning_subtree/minebot_mining, /datum/ai_planning_subtree/locate_dead_humans, ) @@ -133,11 +133,11 @@ controller.clear_blackboard_key(target_key) ///store ores in our body -/datum/ai_planning_subtree/find_and_hunt_target/consume_ores/minebot +/datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/minebot hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/consume_ores/minebot hunt_chance = 100 -/datum/ai_planning_subtree/find_and_hunt_target/consume_ores/minebot/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) +/datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/minebot/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/automated_mining = controller.blackboard[BB_AUTOMATED_MINING] var/mob/living/living_pawn = controller.pawn diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm b/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm deleted file mode 100644 index 444635f2dc3..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm +++ /dev/null @@ -1,229 +0,0 @@ -#define MOOK_ATTACK_NEUTRAL 0 -#define MOOK_ATTACK_WARMUP 1 -#define MOOK_ATTACK_ACTIVE 2 -#define MOOK_ATTACK_RECOVERY 3 -#define ATTACK_INTERMISSION_TIME 5 - -//Fragile but highly aggressive wanderers that pose a large threat in numbers. -//They'll attempt to leap at their target from afar using their hatchets. -/mob/living/simple_animal/hostile/jungle/mook - name = "wanderer" - desc = "This unhealthy looking primitive is wielding a rudimentary hatchet, swinging it with wild abandon. One isn't much of a threat, but in numbers they can quickly overwhelm a superior opponent." - icon = 'icons/mob/simple/jungle/mook.dmi' - icon_state = "mook" - icon_living = "mook" - icon_dead = "mook_dead" - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID - SET_BASE_PIXEL(-16, -8) - - maxHealth = 45 - health = 45 - melee_damage_lower = 30 - melee_damage_upper = 30 - ranged = TRUE - ranged_cooldown_time = 10 - pass_flags_self = LETPASSTHROW - robust_searching = TRUE - stat_attack = HARD_CRIT - attack_sound = 'sound/weapons/rapierhit.ogg' - attack_vis_effect = ATTACK_EFFECT_SLASH - death_sound = 'sound/voice/mook_death.ogg' - aggro_vision_range = 15 //A little more aggressive once in combat to balance out their really low HP - var/attack_state = MOOK_ATTACK_NEUTRAL - var/struck_target_leap = FALSE - - footstep_type = FOOTSTEP_MOB_BAREFOOT - -/mob/living/simple_animal/hostile/jungle/mook/CanAllowThrough(atom/movable/mover, border_dir) - . = ..() - if(istype(mover, /mob/living/simple_animal/hostile/jungle/mook)) - var/mob/living/simple_animal/hostile/jungle/mook/mook_moover = mover - if(mook_moover.attack_state == MOOK_ATTACK_ACTIVE && mook_moover.throwing) - return TRUE - -/mob/living/simple_animal/hostile/jungle/mook/death() - desc = "A deceased primitive. Upon closer inspection, it was suffering from severe cellular degeneration and its garments are machine made..."//Can you guess the twist - return ..() - -/mob/living/simple_animal/hostile/jungle/mook/AttackingTarget() - if(isliving(target)) - if(ranged_cooldown <= world.time && attack_state == MOOK_ATTACK_NEUTRAL) - var/mob/living/L = target - if(L.incapacitated()) - WarmupAttack(forced_slash_combo = TRUE) - return - WarmupAttack() - return - return ..() - -/mob/living/simple_animal/hostile/jungle/mook/Goto() - if(attack_state != MOOK_ATTACK_NEUTRAL) - return - return ..() - -/mob/living/simple_animal/hostile/jungle/mook/Move() - if(attack_state == MOOK_ATTACK_WARMUP || attack_state == MOOK_ATTACK_RECOVERY) - return - return ..() - -/mob/living/simple_animal/hostile/jungle/mook/proc/WarmupAttack(forced_slash_combo = FALSE) - if(attack_state == MOOK_ATTACK_NEUTRAL && target) - attack_state = MOOK_ATTACK_WARMUP - SSmove_manager.stop_looping(src) - update_icons() - if(prob(50) && get_dist(src,target) <= 3 || forced_slash_combo) - addtimer(CALLBACK(src, PROC_REF(SlashCombo)), ATTACK_INTERMISSION_TIME) - return - addtimer(CALLBACK(src, PROC_REF(LeapAttack)), ATTACK_INTERMISSION_TIME + rand(0,3)) - return - attack_state = MOOK_ATTACK_RECOVERY - ResetNeutral() - -/mob/living/simple_animal/hostile/jungle/mook/proc/SlashCombo() - if(attack_state == MOOK_ATTACK_WARMUP && !stat) - attack_state = MOOK_ATTACK_ACTIVE - update_icons() - SlashAttack() - addtimer(CALLBACK(src, PROC_REF(SlashAttack)), 3) - addtimer(CALLBACK(src, PROC_REF(SlashAttack)), 6) - addtimer(CALLBACK(src, PROC_REF(AttackRecovery)), 9) - -/mob/living/simple_animal/hostile/jungle/mook/proc/SlashAttack() - if(target && !stat && attack_state == MOOK_ATTACK_ACTIVE) - melee_damage_lower = 15 - melee_damage_upper = 15 - var/mob_direction = get_dir(src,target) - var/atom/target_from = GET_TARGETS_FROM(src) - if(get_dist(src,target) > 1) - step(src,mob_direction) - if(isturf(target_from.loc) && target.Adjacent(target_from) && isliving(target)) - var/mob/living/L = target - L.attack_animal(src) - return - var/swing_turf = get_step(src,mob_direction) - new /obj/effect/temp_visual/kinetic_blast(swing_turf) - playsound(src, 'sound/weapons/slashmiss.ogg', 50, TRUE) - -/mob/living/simple_animal/hostile/jungle/mook/proc/LeapAttack() - if(target && !stat && attack_state == MOOK_ATTACK_WARMUP) - attack_state = MOOK_ATTACK_ACTIVE - ADD_TRAIT(src, TRAIT_UNDENSE, LEAPING_TRAIT) - melee_damage_lower = 30 - melee_damage_upper = 30 - update_icons() - new /obj/effect/temp_visual/mook_dust(get_turf(src)) - playsound(src, 'sound/weapons/thudswoosh.ogg', 25, TRUE) - playsound(src, 'sound/voice/mook_leap_yell.ogg', 100, TRUE) - var/target_turf = get_turf(target) - throw_at(target_turf, 7, 1, src, FALSE, callback = CALLBACK(src, PROC_REF(AttackRecovery))) - return - attack_state = MOOK_ATTACK_RECOVERY - ResetNeutral() - -/mob/living/simple_animal/hostile/jungle/mook/proc/AttackRecovery() - if(attack_state == MOOK_ATTACK_ACTIVE && !stat) - attack_state = MOOK_ATTACK_RECOVERY - REMOVE_TRAIT(src, TRAIT_UNDENSE, LEAPING_TRAIT) - face_atom(target) - if(!struck_target_leap) - update_icons() - struck_target_leap = FALSE - if(prob(40)) - attack_state = MOOK_ATTACK_NEUTRAL - if(target) - if(isliving(target)) - var/mob/living/L = target - if(L.incapacitated() && L.stat != DEAD) - addtimer(CALLBACK(src, PROC_REF(WarmupAttack), TRUE), ATTACK_INTERMISSION_TIME) - return - addtimer(CALLBACK(src, PROC_REF(WarmupAttack)), ATTACK_INTERMISSION_TIME) - return - addtimer(CALLBACK(src, PROC_REF(ResetNeutral)), ATTACK_INTERMISSION_TIME) - -/mob/living/simple_animal/hostile/jungle/mook/proc/ResetNeutral() - if(attack_state == MOOK_ATTACK_RECOVERY) - attack_state = MOOK_ATTACK_NEUTRAL - ranged_cooldown = world.time + ranged_cooldown_time - update_icons() - if(target && !stat) - update_icons() - Goto(target, move_to_delay, minimum_distance) - -/mob/living/simple_animal/hostile/jungle/mook/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) - . = ..() - if(isliving(hit_atom) && attack_state == MOOK_ATTACK_ACTIVE) - var/mob/living/L = hit_atom - if(CanAttack(L)) - L.attack_animal(src) - struck_target_leap = TRUE - REMOVE_TRAIT(src, TRAIT_UNDENSE, LEAPING_TRAIT) - update_icons() - var/mook_under_us = FALSE - for(var/A in get_turf(src)) - if(struck_target_leap && mook_under_us) - break - if(A == src) - continue - if(isliving(A)) - var/mob/living/ML = A - if(!struck_target_leap && CanAttack(ML))//Check if some joker is attempting to use rest to evade us - struck_target_leap = TRUE - ML.attack_animal(src) - REMOVE_TRAIT(src, TRAIT_UNDENSE, LEAPING_TRAIT) - struck_target_leap = TRUE - update_icons() - continue - if(istype(ML, /mob/living/simple_animal/hostile/jungle/mook) && !mook_under_us)//If we land on the same tile as another mook, spread out so we don't stack our sprite on the same tile - var/mob/living/simple_animal/hostile/jungle/mook/M = ML - if(!M.stat) - mook_under_us = TRUE - var/anydir = pick(GLOB.cardinals) - Move(get_step(src, anydir), anydir) - continue - -/mob/living/simple_animal/hostile/jungle/mook/handle_automated_action() - if(attack_state) - return - return ..() - -/mob/living/simple_animal/hostile/jungle/mook/OpenFire() - if(isliving(target)) - var/mob/living/L = target - if(L.incapacitated()) - return - WarmupAttack() - -/mob/living/simple_animal/hostile/jungle/mook/update_icons() - . = ..() - if(!stat) - switch(attack_state) - if(MOOK_ATTACK_NEUTRAL) - icon_state = "mook" - if(MOOK_ATTACK_WARMUP) - icon_state = "mook_warmup" - if(MOOK_ATTACK_ACTIVE) - if(!density) - icon_state = "mook_leap" - return - if(struck_target_leap) - icon_state = "mook_strike" - return - icon_state = "mook_slash_combo" - if(MOOK_ATTACK_RECOVERY) - icon_state = "mook" - -/obj/effect/temp_visual/mook_dust - name = "dust" - desc = "It's just a dust cloud!" - icon = 'icons/mob/simple/jungle/mook.dmi' - icon_state = "mook_leap_cloud" - layer = BELOW_MOB_LAYER - plane = GAME_PLANE - SET_BASE_PIXEL(-16, -16) - duration = 10 - -#undef MOOK_ATTACK_NEUTRAL -#undef MOOK_ATTACK_WARMUP -#undef MOOK_ATTACK_ACTIVE -#undef MOOK_ATTACK_RECOVERY -#undef ATTACK_INTERMISSION_TIME diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index 98e50a3add4..3074c6e0581 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -106,7 +106,6 @@ /mob/living/simple_animal/hostile/illusion/mirage, /mob/living/simple_animal/hostile/jungle, /mob/living/simple_animal/hostile/jungle/leaper, - /mob/living/simple_animal/hostile/jungle/mook, /mob/living/simple_animal/hostile/megafauna, /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner, /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/doom, diff --git a/config/lavaruinblacklist.txt b/config/lavaruinblacklist.txt index a42196bf9d5..7101d36ab33 100644 --- a/config/lavaruinblacklist.txt +++ b/config/lavaruinblacklist.txt @@ -24,13 +24,23 @@ _maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_sloth.dmm ##MISC +#_maps/RandomRuins/AnywhereRuins/fountain_hall.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_automated_trade_outpost.dmm +#_maps/RandomRuins/LavaRuins/lavaland_surface_cultaltar.dmm +#_maps/RandomRuins/LavaRuins/lavaland_surface_elephant_graveyard.dmm +#_maps/RandomRuins/LavaRuins/lavaland_surface_gaia.dmm +#_maps/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm +#_maps/RandomRuins/LavaRuins/lavaland_surface_hierophant.dmm +#_maps/RandomRuins/LavaRuins/lavaland_surface_library.dmm +#_maps/RandomRuins/LavaRuins/lavaland_surface_mookvillage.dmm +#_maps/RandomRuins/LavaRuins/lavaland_surface_phonebooth.dmm +#_maps/RandomRuins/LavaRuins/lavaland_surface_pizzaparty.dmm +#_maps/RandomRuins/LavaRuins/lavaland_surface_survivalpod.dmm +#_maps/RandomRuins/LavaRuins/lavaland_surface_tomb.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_ww_vault.dmm -#_maps/RandomRuins/LavaRuins/lavaland_surface_automated_trade_outpost.dmm -#_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm -#_maps/RandomRuins/LavaRuins/lavaland_surface_survivalpod.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_wwiioutpost.dmm +<<<<<<< HEAD #_maps/RandomRuins/LavaRuins/lavaland_surface_tomb.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_hierophant.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_pizzaparty.dmm @@ -41,3 +51,6 @@ _maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_library.dmm #_maps/RandomRuins/AnywhereRuins/fountain_hall.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_phonebooth.dmm +======= +#_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm +>>>>>>> 0f5d14e68b1 (Mook village and basic mook refactor (#78789)) diff --git a/icons/mob/simple/jungle/mook.dmi b/icons/mob/simple/jungle/mook.dmi index c9265b22a0ad201b5cfc7f102ff610268157245b..fbc38d29d99deb3349f880a7908a5a38e1e9e0c5 100644 GIT binary patch literal 36875 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�seW3Fn|RluB2b-G9jYJzK}w#VS2PMy8v1k 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 literal 23590 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 ZRB$MC*ufz(2#m#G7mQ2|3-ujw{{fJ{#Cre$ diff --git a/tgstation.dme b/tgstation.dme index d8bc3b0c015..4ce44d82a70 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -898,7 +898,6 @@ #include "code\datums\ai\basic_mobs\generic_controllers.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\basic_attacking.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\climb_tree.dm" -#include "code\datums\ai\basic_mobs\basic_ai_behaviors\find_mineable_wall.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\find_parent.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\nearest_targetting.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\pick_up_item.dm" @@ -919,6 +918,7 @@ #include "code\datums\ai\basic_mobs\basic_subtrees\find_parent.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\flee_target.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\maintain_distance.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\mine_walls.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\move_to_cardinal.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\opportunistic_ventcrawler.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\ranged_skirmish.dm" @@ -4529,6 +4529,10 @@ #include "code\modules\mob\living\basic\lavaland\lobstrosity\lobstrosity.dm" #include "code\modules\mob\living\basic\lavaland\lobstrosity\lobstrosity_ai.dm" #include "code\modules\mob\living\basic\lavaland\lobstrosity\lobstrosity_trophy.dm" +#include "code\modules\mob\living\basic\lavaland\mook\mook.dm" +#include "code\modules\mob\living\basic\lavaland\mook\mook_abilities.dm" +#include "code\modules\mob\living\basic\lavaland\mook\mook_ai.dm" +#include "code\modules\mob\living\basic\lavaland\mook\mook_village.dm" #include "code\modules\mob\living\basic\lavaland\watcher\watcher.dm" #include "code\modules\mob\living\basic\lavaland\watcher\watcher_ai.dm" #include "code\modules\mob\living\basic\lavaland\watcher\watcher_gaze.dm" @@ -4842,7 +4846,6 @@ #include "code\modules\mob\living\simple_animal\hostile\gorilla\visuals_icons.dm" #include "code\modules\mob\living\simple_animal\hostile\jungle\_jungle_mobs.dm" #include "code\modules\mob\living\simple_animal\hostile\jungle\leaper.dm" -#include "code\modules\mob\living\simple_animal\hostile\jungle\mook.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\_megafauna.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\blood_drunk_miner.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\bubblegum.dm" diff --git a/tgui/packages/tgui/interfaces/MaterialStand.tsx b/tgui/packages/tgui/interfaces/MaterialStand.tsx new file mode 100644 index 00000000000..b6e87889cd2 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MaterialStand.tsx @@ -0,0 +1,120 @@ +import { createSearch, toTitleCase } from 'common/string'; +import { useBackend, useLocalState } from '../backend'; +import { Box, Button, Input, Stack, Flex, Section } from '../components'; +import { Window } from '../layouts'; + +type Ores = { + id: string; + name: string; + amount: number; +}; + +type Ore_images = { + name: string; + icon: string; +}; + +type Data = { + ores: Ores[]; + ore_images: Ore_images[]; +}; + +export const MaterialStand = (props, context) => { + const { act, data } = useBackend(context); + const { ores = [] } = data; + const [searchItem, setSearchItem] = useLocalState(context, 'searchItem', ''); + const search = createSearch(searchItem, (ore: Ores) => ore.name); + const ores_filtered = + searchItem.length > 0 ? ores.filter((ore) => search(ore)) : ores; + return ( + + + + +
+ { + setSearchItem(value); + }} + fluid + /> +
+
+ +
+ + {ores_filtered.map((ore) => ( + + + + + + + + + Amount: {ore.amount} + +
+
+
+
+
+ ); +}; + +const RetrieveIcon = (props, context) => { + const { data } = useBackend(context); + const { ore_images = [] } = data; + const { ore } = props; + + let icon_display = ore_images.find((icon) => icon.name === ore.name); + + if (!icon_display) { + return null; + } + + return ( + + ); +}; + +const Orename = (props) => { + const { ore_name } = props; + const return_name = ore_name.split(' '); + if (return_name.length === 0) { + return null; + } + return return_name[0]; +}; From 832c42a12a0d52faea0011810c23c7d0bb1333b8 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:41:20 +0200 Subject: [PATCH 048/100] Galactic Market Hot Fixes [MDB IGNORE] (#24274) * Galactic Market Hot Fixes (#78836) ## About The Pull Request 1. Fixes #78732 The "Order Via Cargo Budget" button no longer appears in the UI if you don't have cargo access in your ID 2. Fixes #78730 Orders made privately & orders made via cargo budget now come in different crates ![Screenshot (315)](https://github.com/tgstation/tgstation/assets/110812394/8dfead42-02ed-46f6-b795-d1ce5a139bfd) So cargo ordered crates no longer require QM cargo budget card and can be opened by anyone as intended wheras privatly ordered crates come with your regular secure access facility. This occurred when assigning the bank account to the order https://github.com/tgstation/tgstation/blob/e41730f6e455c3ece1cd52e3b67aa6c1d11cd953/code/modules/cargo/materials_market.dm#L201 This param is only meant to check if you want an access secured crate(which you should get for private orders) or an normal crate for cargo orders. If null it will send you the regular cargo crate 3. Fixes #78731 Orders made privately vs orders made with cargo budget are now separate and not bundled together ![Screenshot (314)](https://github.com/tgstation/tgstation/assets/110812394/151dfc37-8765-4aa9-88a9-7a41e4f6069d) So if you first make an order privately & them switch to cargo budget or vice versa it will still separate your orders. This way you get what you ordered privately in a separate crate and cargo gets their crate separately for it's purposes 4. New Qol now money will be deducted from cargo budget/your account only after the order is confirmed in the cargo request console & after shuttle is called and arrives with your packages This way you drain the budget only after your orders were successfully delivered and not before hand itself. We don't have to worry about making orders that exceed our budget cause cargo already has bound checking code for that so let it do its thing. Here for example cargo only had 500 credits but i ordered way too much so it gracefully rejected it ![Screenshot (316)](https://github.com/tgstation/tgstation/assets/110812394/0b13946e-13f5-4dbc-aebc-a54ba10df043) 6. This also addresses https://github.com/tgstation/tgstation/pull/78729#pullrequestreview-1654922282 by making the for loop treat the items in the list as paths by using the `as anything in` clause in the for loop. ## Changelog :cl: fix: You cannot order with cargo budget if you don't have cargo access in the Galactic Market fix: Private & Cargo orders no longer get mixed together in the same crate if you order them interchangeably so no more embezzlement in the Galactic Market fix: Orders made with cargo budget come in a regular cargo crate thus allowing you to open them without QM cargo budget card in the Galactic Market qol: Orders made in the Galactic Market will deduct money from your account/cargo budget only after the order has been confirmed in the cargo request console & after the shuttle arrives with your order. This way you drain the budget only after your orders were successfully delivered and not before hand itself /:cl: * Galactic Market Hot Fixes --------- Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> --- code/modules/cargo/materials_market.dm | 63 +++++++++++-------- .../modules/cargo/packs/stock_market_items.dm | 2 +- tgui/packages/tgui/interfaces/MatMarket.tsx | 24 +++---- 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/code/modules/cargo/materials_market.dm b/code/modules/cargo/materials_market.dm index dd56128241d..e2bedd2f19a 100644 --- a/code/modules/cargo/materials_market.dm +++ b/code/modules/cargo/materials_market.dm @@ -11,7 +11,7 @@ base_icon_state = "mat_market" idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION /// What items can be converted into a stock block? Must be a stack subtype based on current implementation. - var/list/exportable_material_items = list( + var/static/list/exportable_material_items = list( /obj/item/stack/sheet/iron, //God why are we like this /obj/item/stack/sheet/glass, //No really, God why are we like this /obj/item/stack/sheet/mineral, @@ -130,12 +130,18 @@ data["canOrderCargo"] = can_buy_via_budget return data -/obj/machinery/materials_market/ui_act(action, params) +/obj/machinery/materials_market/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return - if(!isliving(usr)) + + //You must have an ID to be able to do something + var/mob/living/living_user = ui.user + var/obj/item/card/id/used_id_card = living_user.get_idcard(TRUE) + if(isnull(used_id_card)) + say("No ID Found") return + switch(action) if("buy") var/material_str = params["material"] @@ -149,32 +155,41 @@ break if(!material_bought) CRASH("Invalid material name passed to materials market!") - var/mob/living/living_user = usr - var/datum/bank_account/account_payable = SSeconomy.get_dep_account(ACCOUNT_CAR) - if(ordering_private) - var/obj/item/card/id/used_id_card = living_user.get_idcard(TRUE) + + //if multiple users open the UI some of them may not have the required access so we recheck + var/is_ordering_private = ordering_private + if(!(ACCESS_CARGO in used_id_card.GetAccess())) //no cargo access then force private purchase + is_ordering_private = TRUE + + var/datum/bank_account/account_payable + if(is_ordering_private) account_payable = used_id_card.registered_account else if(can_buy_via_budget) account_payable = SSeconomy.get_dep_account(ACCOUNT_CAR) - - var/cost = SSstock_market.materials_prices[material_bought] * quantity + if(!account_payable) + say("No bank account detected!") + return sheet_to_buy = initial(material_bought.sheet_type) if(!sheet_to_buy) CRASH("Material with no sheet type being sold on materials market!") - if(!account_payable) - say("No bank account detected!") - return + var/cost = SSstock_market.materials_prices[material_bought] * quantity if(cost > account_payable.account_balance) to_chat(living_user, span_warning("You don't have enough money to buy that!")) return + var/list/things_to_order = list() things_to_order += (sheet_to_buy) things_to_order[sheet_to_buy] = quantity // We want to count how many stacks of all sheets we're ordering to make sure they don't exceed the limit of 10 - //If we already have a custom order on SSshuttle, we should add the things to order to that order + // If we already have a custom order on SSshuttle, we should add the things to order to that order for(var/datum/supply_order/order in SSshuttle.shopping_list) - if(order.orderer == living_user && order.orderer_rank == "Galactic Materials Market") + // Must be a Galactic Materials Market order and payed by the null account(if ordered via cargo budget) or by correct user for private purchase + if(order.orderer_rank == "Galactic Materials Market" && ( \ + (!is_ordering_private && order.paying_account == null) || \ + (is_ordering_private && order.paying_account != null && order.orderer == living_user) \ + )) + // Check if this order exceeded its limit var/prior_stacks = 0 for(var/obj/item/stack/sheet/sheet as anything in order.pack.contains) prior_stacks += ROUND_UP(order.pack.contains[sheet] / 50) @@ -182,29 +197,24 @@ to_chat(usr, span_notice("You already have 10 stacks of sheets on order! Please wait for them to arrive before ordering more.")) playsound(usr, 'sound/machines/synth_no.ogg', 35, FALSE) return + // Append to this order order.append_order(things_to_order, cost) - account_payable.adjust_money(-(cost) , "Materials Market Purchase") //Add the extra price to the total return - account_payable.adjust_money(-(CARGO_CRATE_VALUE) , "Materials Market Purchase") //Here is where we factor in the base cost of a crate + //Now we need to add a cargo order for quantity sheets of material_bought.sheet_type var/datum/supply_pack/custom/minerals/mineral_pack = new( - purchaser = living_user, \ - cost = SSstock_market.materials_prices[material_bought] * quantity, \ + purchaser = is_ordering_private ? living_user : "Cargo", \ + cost = cost, \ contains = things_to_order, \ - ) + ) var/datum/supply_order/new_order = new( pack = mineral_pack, orderer = living_user, orderer_rank = "Galactic Materials Market", orderer_ckey = living_user.ckey, - reason = "", - paying_account = account_payable, - department_destination = null, - coupon = null, - charge_on_purchase = FALSE, - manifest_can_fail = FALSE, + paying_account = is_ordering_private ? account_payable : null, cost_type = "credit", - can_be_cancelled = FALSE, + can_be_cancelled = FALSE ) say("Thank you for your purchase! It will arrive on the next cargo shuttle!") SSshuttle.shopping_list += new_order @@ -214,7 +224,6 @@ return ordering_private = !ordering_private - /obj/item/stock_block name = "stock block" desc = "A block of stock. It's worth a certain amount of money, based on a sale on the materials market. Ship it on the cargo shuttle to claim your money." diff --git a/code/modules/cargo/packs/stock_market_items.dm b/code/modules/cargo/packs/stock_market_items.dm index 04b2eac4acf..9744bdf7400 100644 --- a/code/modules/cargo/packs/stock_market_items.dm +++ b/code/modules/cargo/packs/stock_market_items.dm @@ -14,7 +14,7 @@ var/amount /datum/supply_pack/market_materials/get_cost() - for(var/datum/material/mat in SSstock_market.materials_prices) + for(var/datum/material/mat as anything in SSstock_market.materials_prices) if(material == mat) return SSstock_market.materials_prices[mat] * amount diff --git a/tgui/packages/tgui/interfaces/MatMarket.tsx b/tgui/packages/tgui/interfaces/MatMarket.tsx index 86f44462cb1..da9f4535911 100644 --- a/tgui/packages/tgui/interfaces/MatMarket.tsx +++ b/tgui/packages/tgui/interfaces/MatMarket.tsx @@ -38,17 +38,19 @@ export const MatMarket = (props, context) => {
act('toggle_budget')} - /> + !!canOrderCargo && ( +