From 09b36a7ff6e464fd9e6a3de4f76c030ec77339e3 Mon Sep 17 00:00:00 2001 From: Cameron Lennox Date: Sun, 26 Jan 2025 16:15:58 -0500 Subject: [PATCH] Xenoarch Rework [Ready for Review] (#16757) * WIP Xenoarch * Removes the chompedits * Makes field gen not required. Genuinely, it was a relic and NOT fun at all to lug around this giant machinery that all it did was make it so you could actually GET the artifacts. It added nothing to the experience and simply made it feel more clunky. Previously, the field generator REQUIRED you to select what "generator field type" it needed, which was 'used in conjunction with analysis machines to determine correct suspension field type'... Or, if you did what 99% of every xenoarch player did, you learned how to code dive or used the wiki ("Oh, metal composite = this field gen type"). Someone down the line realized this was a dumb idea and proceeded to axe the types. Now, I axe the generator entirely. Still leaving this IN here in case someone DOES want to reenable it, but it just makes the whole xenoarch experience that much more worse in my opinion. Especially when you get to deposits in awkward positions that are sandwiched between two walls, meaning you can't excavate AND use the suspension gen at the same time without choosing one of the tiles to break. Visual example below. X walls, x open space, O artifacts. XXX xOX xOX XXX * Part 1 -Slashes a LOT of RNG from xenoarch spawns. No longer will you get 5 normal, mundane bowls in a row that all look the same. They're GUARANTEED to have coloration and various effects - Adjusts a LOT of the RNG of xenoarch spawns. - Remove shards (was just a glass shard...The most disappointing find you could get) - Removes rods (See above) - Removed Cutlery (See above) - Increases chance for the vampiric statuette to spawn - Makes the 'syringe' archeology find generate random 3 to 6 random chemicals that get stuffed into the syringe. (Using same blacklist as the xenoflora chem blacklist) - Readjust spawned /material weights for items. These are ALIEN artifacts. It's boring to get your 20th 'alien wooden bat' of the day. Now it's COMPLETELY random. You might get a glass bat. Or a supermatter bat. Or a diamond bat. Who knows! (Has a blacklist that includes adminspawn materials or materials that would be too strong/make little sense. No durasteel hull knives here!) - Made things that just spawned "this weapon" spawn a subtype of "this weapon". Things like knives, handcuffs, 'flame' (includes matches now), tanks, and tools will also follow this logic. - Adjust it so you can get an alien tool AND alien clothes - Alien remains aren't just useless bones anymore, they spawn with a randomized plasma vessel and organ! Go ask medical to shove it in ya! (TODO: Test that medical can ACTUALLY shove it in you) - Removes the no fun 'Oops you accidentally dug too far, the artifact inside breaks!' when it comes to rocky debris because the game never tells you to dig 1 at a time. - Expands the list of what the replenishing bowl can spawn with. Uses the xenobio plant chemical blacklist. (TODO: Add a 'blacklist' var on said chemicals, sometime) - Makes it so ARCHAEO_REMAINS_HUMANOID can spawn a random organ. - Makes it so the ARCHAEO_REMAINS_ROBOT spawns a lost drone pod. - Makes it so guns are more randomized in xenoarch. They now tell you what bullet type they require Additionally, they are now a subtype of bullet and can spawn with ANY /bullet. This makes the guns ACTUALLY really weird. - Makes it so your xenoarch guns will always spawn with some bullets. -Expands the alien clothes spawn to include the gluttony psy_crown. - Makes the 'ARCHAEO_UNKNOWN' that was previous broken (and spawned nothing) spawn a rare research sample. (This is generally useless since the circuit printer exists and R&D can be speedran in 10 minutes, but whatever. If your xenoarch finds one in precursor or anomalous you'll be happy.) - The plant fossil notes to give it to xenobotany and extract it. - Gives the instrument spawn logic the same as everything else. Subtypes. - Swaps the 'ARCHAEO_CULTBLADE' cultblade to a new archeology based cultblade. Has SPOOKY effects. (TODO!) - Adds the library tome to the possible spawn pool for temple digsites (Useless unless you're an antag cult but SPOOKY - Gets rid of 'digsite animal' as it was completely irrelevent due to bones not being able to put in the xenobio machine to give you animals. (This was a very VERY old feature. I can't even recall how many years ago)\ - Makes every xenoarch effect have its own individual tag. - Makes it so the artifact analyzer actually gives you an idea of WHAT the artifact will do instead of saying "I dunno boss, go test it and accidentally blow medical up" - Makes it so the artifact analyzer gives you an idea of how the artifact disperses it's effect, other than using weird super sciency-sounding terms and requiring you to code dive - Reworks the vampire artifact spawns to make it so you're rewarded for interacting with it via spawning spooky cult-themed objects. This makes it so there's actually a (small) incentive to experiment with it instead of just proccing it once and going "INTO THE BOX OF THINGS TO NEVER BE TOUCHED AGAIN" - Better formatting for the anomaly analyzer. No longer will it be a MASSIVE wall of text, especially if it has multiple artifacts! * Part 2: Guns and Weight - Adjusts the large artifact find rates. Some things (like the supermatter shard, which could just instakill the xenoarch and the crystal which was useless) were too high, while some (like the construct shell) were too low and would NEVER really be seen. (I've done xenoarch for years now and have only seen ONE construct shell. Previous drop rates: Total Wt In Pool: 1590 5 wt: 0.31% 25 wt: 1.5% 100 wt: 6.2% 150 wt: 9.4% 1000 wt (artifact): 62.8% New wt: // Our total is 560 (As of the time of writing. If ANY of the weights are adjusted above, you have to recalculate. Formula: (thingy_wt/total_wt)*100 = % chance of drop) // Artifact: 53% // 50 wt: 8.9% // 25 wt: 4.4% // 5 wt: 0.89% - Adjusts the archeology gun logic. Makes it actually functional AND makes it so you can't remove the fancy bullets out of it. - Adjusts the archeology calibers to ones that can be obtained. - Adds a note to the archeology gun when examined that it requires ONE bullet at a time. No speedloading these alien guns! - Makes it so the archeology gun has the proper special HUD state depending on what bullet type is loaded. - Fixes a few runtimes pertaining to secondary items - ADDS A DEBUG SPAWN VERB SO I CAN TEST ALL THIS. THIS NEEDS TO BE REMOVED PRIOR TO MERGE. - Fixes an unintentional = vs == in archeo_melee.dm. It's not completed yet and is in an EARLY wip stage but might as well fix it sooner than later. * Added an extra failsafe last second and forgot to tab it * angy * Energy guns - Makes xenoarch laser gun follow the same logic as the xenoarch projectile gun, but SOMEWHAT stricter. (Not using projectile/energy for example. Beams, ion, animate, and floramut rays only!) - Removes the '5% explode on use' chance * Update find_spawning.dm - Fixes a few runtimes with material display names. Some didn't have any and would runtime. - Adjusts and expands the list of the source_material if we don't have a specific material display name. It's supposed to be alien artifacts, so unearthing a ring made of pure meitnerium or a bowl composed of roentgenium is COMPLETELY in the realm of possibility. * More spawn logic - Makes material stuffs spawn properly - Makes the robot pod spawn properly - Makes the cursedform stop spawning (It served its purpose of confirming stuff worked) - Makes rings have different materials (https://i.imgur.com/T9OzU4p.png) - Makes gasmask able to spawn as either a poltergeist or a voice type. - Makes the banned materials a list in the proc only once instead of multiple times. (Cuts down on copy paste errors and makes it easier to add to. Could honestly make it a global list but eh.) - Makes the new_item_mat default to steel correctly. - Allows for secondary items to have different names and desriptions. * More Small Artifact Adjustments - Gives the artifact blade a proper decription - Makes the vampiric statuette no longer RNG. - Makes the occult clothing spawn in sets instead of mix&matched - Makes the research sample (ARCHAEO_UNKNOWN) spawn properly. - Fixes the syringe from having too much volume and not having the sprites. It's limited to 15u now, but spawns with 5 chems now, 3u each. - Fixes the alien clothes from having the same name as the alien tool - Makes it so boats spawn properly. This is ALL the small artifacts taken care of, fixed, and having additional fluff added to them. Next, I need to adjust the large artifacts, add feature to the artifact sword, rework the vampiric statue, and see about touching up the other xenoarch code * Shock Maul Adjustment - Makes the shock maul's description of breaking rocks different. Plays a different sound as well * whoops quotes * More adjustments! - Vampiric statuette has a hint/warning of how to activate it in it's description - Makes shadow wrights NOT sit in nullspace 5ever after activating - Makes shadow wrights give you some fluff text instead of just randomly KOing you. - Makes the vampiric statuette follow the same spawn logic as the vampiric large artifact * More sword stuff - Adds 'ispassive' typecheck helper - Makes the artifact blade's origin tech 6/6/6 because funny - Makes it so the cult sword only starts processing when it's first touched. - Makes cult sword stop processing when the user dies or stops existing. - Adds some more features * More relic sword stuff More artifact blade works. - Various blade fixes - Makes it so it can 'consecrate' SIMULATED turf, SIMULATED walls, and girders. - Also adjusts 0 & 1 for grille destruction & bullet passthrough to false/true while I was in there * Purge is lame get rid of it * mixup * Finishes artifact sword Makes it so if you use it and destroy it, it gets VERY upset Makes it so the artifact sword is a way for archeology to - slowly - exchange health and time in exchange for artifacts * Verifies all artifact effects works, fixes some - Makes the xenoarch anomaly harvester ACTUALLY work - This has a BUNCH of features but I'll have to detail them out better once the PR is ready for review - Fixes a bug where rarely, "datum/artifact_effect/extreme" would get selected and do nothing. - Fixes a server-crashing bug. - Makes all the artifacts compatible with the artifact harvester - Moves 'being_used' from the artifact to /obj - Makes gas artifacts not 100% useless. - Makes some more adjustments to the artifact sword * small rewrite * lightning and culstist check fixes * iscultist * More small adjustments * Organization Organizes all the atmos affecting artifacts into one folder * Condenses artifacts - Condenses a LOT of the artifacts down and gets rid of duplicates. * Updates dme for new artifacts * switch * Type Changes - Adds wrench to xenoarch supply pack - Changes istype to ishuman, isrobot, ismob where applicable screech * Changes to span_bold In applicable places * Adds Power Generator artifact - Adds power generator artifact - Adds some sounds from Goonstation to go along with the new artifact - Makes it so animate_shake is a proc on /obj instead of just /closet - Makes it so you can activate artifacts with gloves on, but you won't accidentally touch them if you have gloves on. * More edits * Procedural gen. Rock adjustment. Drill buffs - Speeds up excavation drill (It made no sense it was a downgrade in speed) - Makes it so when going to change the depth, it defaults to whatever it's currently set to - Makes excavation drill able to go up to 60cm - Makes xenoarch lockers start with excavation drill - Changes loot pile prob2 from excavation pack to excavationdrill - Makes it so mining vendor also sells the excavation kit - Gives miners a basic anomaly scanner (but NOT the anomaly locator) to allow miners to do basic archeology if they stumble across a rock and want to excavate it but can't actively search and locate artifacts that archeology might be going for. - Makes archeologist's anomaly scanner able to do continual artifact searching and generation. No more will you 'run out' of artifacts halfway through a round and have nothing to do anymore. This only occurs when all large (or small) artifacts have been completely depleted on a Z level. - Makes it so boulders no longer randomly spawn when miners are mining, even when no artifact was there. - Makes anomaly scanner do procedural generation to keep giving further ability to mine. - Makes it so strange rocks can be mined with any /pickaxe, as small picks (the excavation pickset) was destroying them * Gets rid of clearance - Gets rid of clearance range. It was confusing and not helpful in the slightest for players. * Gets rid of unused variables * Removes unused vars from the tsx as well Wanted to test to make sure it'd work first * More bugfixes - Fixes excavation drill text - Fixes runtime with responsive reagent - Makes temperature artifact show up properly to the scanner - Fixes a typo with the atmospheric effect name - Adds some spaces to effect.dm to make the artifact analyzer effect show up properly. - Removes a few invisible sprite organs from spawning * Untick * Adds a cooldown and sanity check - Adds a cooldown to the procedural generation of the ano scanner. - Makes the debug ability a proc on /mob so that admins can call it to spawn artifacts. - Adds a sanity check since it's now a proc that can be called. --- code/__defines/is_helpers.dm | 1 + code/__defines/span_vr.dm | 2 +- code/__defines/xenoarcheaology.dm | 66 +- code/_helpers/typelists.dm | 43 ++ code/controllers/subsystems/xenoarch.dm | 147 +++- code/datums/components/_component.dm | 13 + code/datums/supplypacks/science.dm | 3 +- code/game/atoms.dm | 3 + code/game/objects/items.dm | 5 +- .../objects/items/weapons/storage/egg_vr.dm | 6 - code/game/objects/objs.dm | 8 + code/game/objects/random/maintenance.dm | 2 +- .../structures/crates_lockers/__closets.dm | 6 - .../closets/secure/scientist.dm | 3 +- code/game/objects/structures/fitness.dm | 10 +- code/game/objects/structures/grille.dm | 17 +- code/game/turfs/simulated/floor.dm | 5 + code/game/turfs/simulated/walls.dm | 5 + code/game/turfs/turf.dm | 4 + code/game/turfs/unsimulated.dm | 3 + code/modules/mining/mine_turfs.dm | 42 +- .../equipment_vendor.dm | 4 +- code/modules/rogueminer_vr/zonemaster.dm | 4 +- .../xenoarcheaology/artifacts/artifact.dm | 29 +- .../artifacts/artifact_find.dm | 28 +- code/modules/xenoarcheaology/boulder.dm | 6 - code/modules/xenoarcheaology/effect.dm | 115 ++- code/modules/xenoarcheaology/effect_master.dm | 109 ++- .../effects/animate_anomaly.dm | 52 +- .../xenoarcheaology/effects/atmospheric.dm | 27 + .../xenoarcheaology/effects/badfeeling.dm | 74 -- .../xenoarcheaology/effects/berserk.dm | 7 +- .../xenoarcheaology/effects/cannibal.dm | 80 --- code/modules/xenoarcheaology/effects/cell.dm | 69 ++ .../xenoarcheaology/effects/cellcharge.dm | 44 -- .../xenoarcheaology/effects/celldrain.dm | 44 -- code/modules/xenoarcheaology/effects/cold.dm | 27 - .../xenoarcheaology/effects/electric_field.dm | 38 +- code/modules/xenoarcheaology/effects/emp.dm | 8 +- .../xenoarcheaology/effects/feelings.dm | 147 ++++ .../xenoarcheaology/effects/feysight.dm | 7 +- .../xenoarcheaology/effects/forcefield.dm | 5 +- code/modules/xenoarcheaology/effects/gaia.dm | 6 +- .../modules/xenoarcheaology/effects/gasco2.dm | 23 - .../xenoarcheaology/effects/gasnitro.dm | 23 - .../modules/xenoarcheaology/effects/gasoxy.dm | 21 - .../xenoarcheaology/effects/gasphoron.dm | 23 - .../xenoarcheaology/effects/gassleeping.dm | 21 - .../xenoarcheaology/effects/goodfeeling.dm | 72 -- .../effects/gravitational_waves.dm | 32 +- code/modules/xenoarcheaology/effects/heal.dm | 67 -- .../modules/xenoarcheaology/effects/health.dm | 113 +++ code/modules/xenoarcheaology/effects/heat.dm | 26 - code/modules/xenoarcheaology/effects/hurt.dm | 53 -- .../xenoarcheaology/effects/poltergeist.dm | 10 +- .../effects/power_generator.dm | 97 +++ .../xenoarcheaology/effects/radiate.dm | 11 +- .../xenoarcheaology/effects/resurrect.dm | 48 +- .../xenoarcheaology/effects/roboheal.dm | 44 -- .../xenoarcheaology/effects/robohurt.dm | 44 -- .../xenoarcheaology/effects/robothealth.dm | 76 ++ .../modules/xenoarcheaology/effects/sleepy.dm | 6 +- code/modules/xenoarcheaology/effects/stun.dm | 5 +- .../xenoarcheaology/effects/teleport.dm | 11 +- .../xenoarcheaology/effects/temperature.dm | 50 ++ .../xenoarcheaology/effects/vampire.dm | 34 +- .../finds/Weapons/archeo_eguns.dm | 6 + .../archeo_eguns_vr.dm} | 0 .../finds/Weapons/archeo_guns.dm | 49 ++ .../finds/Weapons/archeo_melee.dm | 297 ++++++++ code/modules/xenoarcheaology/finds/eguns.dm | 30 - .../xenoarcheaology/finds/find_spawning.dm | 655 +++++++++++------- code/modules/xenoarcheaology/finds/finds.dm | 18 +- .../xenoarcheaology/finds/finds_defines.dm | 84 +-- code/modules/xenoarcheaology/finds/special.dm | 26 +- code/modules/xenoarcheaology/finds/talking.dm | 2 +- code/modules/xenoarcheaology/sampling.dm | 2 +- .../tools/ano_device_battery.dm | 11 +- .../tools/artifact_analyser.dm | 1 + .../tools/artifact_harvester.dm | 70 +- .../tools/suspension_generator.dm | 2 +- code/modules/xenoarcheaology/tools/tools.dm | 21 +- .../xenoarcheaology/tools/tools_pickaxe.dm | 8 +- .../tgui/interfaces/XenoarchDepthScanner.tsx | 8 - vorestation.dme | 29 +- 85 files changed, 2205 insertions(+), 1348 deletions(-) create mode 100644 code/_helpers/typelists.dm create mode 100644 code/modules/xenoarcheaology/effects/atmospheric.dm delete mode 100644 code/modules/xenoarcheaology/effects/badfeeling.dm delete mode 100644 code/modules/xenoarcheaology/effects/cannibal.dm create mode 100644 code/modules/xenoarcheaology/effects/cell.dm delete mode 100644 code/modules/xenoarcheaology/effects/cellcharge.dm delete mode 100644 code/modules/xenoarcheaology/effects/celldrain.dm delete mode 100644 code/modules/xenoarcheaology/effects/cold.dm create mode 100644 code/modules/xenoarcheaology/effects/feelings.dm delete mode 100644 code/modules/xenoarcheaology/effects/gasco2.dm delete mode 100644 code/modules/xenoarcheaology/effects/gasnitro.dm delete mode 100644 code/modules/xenoarcheaology/effects/gasoxy.dm delete mode 100644 code/modules/xenoarcheaology/effects/gasphoron.dm delete mode 100644 code/modules/xenoarcheaology/effects/gassleeping.dm delete mode 100644 code/modules/xenoarcheaology/effects/goodfeeling.dm delete mode 100644 code/modules/xenoarcheaology/effects/heal.dm create mode 100644 code/modules/xenoarcheaology/effects/health.dm delete mode 100644 code/modules/xenoarcheaology/effects/heat.dm delete mode 100644 code/modules/xenoarcheaology/effects/hurt.dm create mode 100644 code/modules/xenoarcheaology/effects/power_generator.dm delete mode 100644 code/modules/xenoarcheaology/effects/roboheal.dm delete mode 100644 code/modules/xenoarcheaology/effects/robohurt.dm create mode 100644 code/modules/xenoarcheaology/effects/robothealth.dm create mode 100644 code/modules/xenoarcheaology/effects/temperature.dm create mode 100644 code/modules/xenoarcheaology/finds/Weapons/archeo_eguns.dm rename code/modules/xenoarcheaology/finds/{eguns_vr.dm => Weapons/archeo_eguns_vr.dm} (100%) create mode 100644 code/modules/xenoarcheaology/finds/Weapons/archeo_guns.dm create mode 100644 code/modules/xenoarcheaology/finds/Weapons/archeo_melee.dm delete mode 100644 code/modules/xenoarcheaology/finds/eguns.dm diff --git a/code/__defines/is_helpers.dm b/code/__defines/is_helpers.dm index 71b7858571..7a59144f8e 100644 --- a/code/__defines/is_helpers.dm +++ b/code/__defines/is_helpers.dm @@ -38,6 +38,7 @@ #define isnewplayer(A) istype(A, /mob/new_player) #define isanimal(A) istype(A, /mob/living/simple_mob) +#define ispassive(A) istype(A, /mob/living/simple_mob/animal/passive) #define ismouse(A) istype(A, /mob/living/simple_mob/animal/passive/mouse) #define iscorgi(A) istype(A, /mob/living/simple_mob/animal/passive/dog/corgi) #define isslime(A) istype(A, /mob/living/simple_mob/slime) diff --git a/code/__defines/span_vr.dm b/code/__defines/span_vr.dm index c87d062b0e..727f04ad5c 100644 --- a/code/__defines/span_vr.dm +++ b/code/__defines/span_vr.dm @@ -72,7 +72,7 @@ #define span_filter_combat(str) ("" + str + "") // Filtered under warning messages -#define span_critical(str) ("" + str + "") +#define span_critical(str) ("" + str + "") //This doesn't seem to work. #define span_userdanger(str) ("" + str + "") #define span_warning(str) ("" + str + "") #define span_warningplain(str) ("" + str + "") diff --git a/code/__defines/xenoarcheaology.dm b/code/__defines/xenoarcheaology.dm index 20781a8356..b0282b7682 100644 --- a/code/__defines/xenoarcheaology.dm +++ b/code/__defines/xenoarcheaology.dm @@ -1,6 +1,9 @@ +/// +/// These are the defines for the SMALL (can hold in hand) artifacts. +/// #define ARCHAEO_BOWL 1 #define ARCHAEO_URN 2 -#define ARCHAEO_CUTLERY 3 +#define ARCHAEO_SYRINGE 3 #define ARCHAEO_STATUETTE 4 #define ARCHAEO_INSTRUMENT 5 #define ARCHAEO_KNIFE 6 @@ -19,8 +22,8 @@ #define ARCHAEO_CLAYMORE 19 #define ARCHAEO_CULTROBES 20 #define ARCHAEO_SOULSTONE 21 -#define ARCHAEO_SHARD 22 -#define ARCHAEO_RODS 23 +#define ARCHAEO_CLUB 22 +#define ARCHAEO_RING 23 #define ARCHAEO_STOCKPARTS 24 #define ARCHAEO_KATANA 25 #define ARCHAEO_LASER 26 @@ -38,24 +41,36 @@ #define ARCHAEO_IMPERION_CIRCUIT 38 #define ARCHAEO_TELECUBE 39 #define ARCHAEO_BATTERY 40 -#define ARCHAEO_SYRINGE 41 -#define ARCHAEO_RING 42 -#define ARCHAEO_CLUB 43 -#define MAX_ARCHAEO 43 +#define ARCHAEO_TOME 41 +#define MAX_ARCHAEO 41 +/// +/// These are the defines for the DIGSITES (which determine what artifacts will spawn in that cluster of artifact tiles) +/// #define DIGSITE_GARDEN 1 -#define DIGSITE_ANIMAL 2 +#define DIGSITE_MIDDEN 2 #define DIGSITE_HOUSE 3 #define DIGSITE_TECHNICAL 4 #define DIGSITE_TEMPLE 5 #define DIGSITE_WAR 6 -#define DIGSITE_MIDDEN 7 +/// +/// These are the defines for what type of effect the artifact has. +/// +/// +/// Touch requires you to touch it to have effects +/// Aura will require the artifact to be activated (on sprite) and will occasionally effect things in a short range +/// Pulse will require the artifact to be activated, will take a long while to charge, then hit things in a long range (possibly Z wide) +/// #define EFFECT_TOUCH 0 #define EFFECT_AURA 1 #define EFFECT_PULSE 2 #define MAX_EFFECT 2 +/// +/// These are the defines for what is required to ACTIVATE the artifact. +/// +/// TODO: Get rid of TRIGGER_PHORON/OXY/CO2/NITRO. They're unfun and tedious. #define TRIGGER_TOUCH 0 #define TRIGGER_WATER 1 #define TRIGGER_ACID 2 @@ -71,11 +86,30 @@ #define TRIGGER_NITRO 12 #define MAX_TRIGGER 12 +/// +/// These are defines of what TYPE of artifact it is. See code/modules/xenoarcheaology/effects for each artifact. +/// #define EFFECT_UNKNOWN 0 -#define EFFECT_ENERGY 1 -#define EFFECT_PSIONIC 2 -#define EFFECT_ELECTRO 3 -#define EFFECT_PARTICLE 4 -#define EFFECT_ORGANIC 5 -#define EFFECT_BLUESPACE 6 -#define EFFECT_SYNTH 7 \ No newline at end of file +#define EFFECT_ANIMATE 1 +#define EFFECT_BERSERK 2 +#define EFFECT_FEELINGS 3 +#define EFFECT_CELL 4 +#define EFFECT_ELECTIC_FIELD 5 +#define EFFECT_EMP 6 +#define EFFECT_FEYSIGHT 7 +#define EFFECT_FORCEFIELD 8 +#define EFFECT_GAIA 9 +#define EFFECT_GAS 10 +#define EFFECT_GRAVIATIONAL_WAVES 11 +#define EFFECT_TEMPERATURE 12 +#define EFFECT_POLTERGEIST 13 +#define EFFECT_RADIATE 14 +#define EFFECT_RESURRECT 15 +#define EFFECT_ROBOT_HEALTH 16 +#define EFFECT_SLEEPY 17 +#define EFFECT_STUN 18 +#define EFFECT_TELEPORT 19 +#define EFFECT_VAMPIRE 20 +#define EFFECT_HEALTH 21 +#define EFFECT_GENERATOR 22 +//#define EFFECT_DNASWITCH 23 //Not in as of yet. diff --git a/code/_helpers/typelists.dm b/code/_helpers/typelists.dm new file mode 100644 index 0000000000..f271b9204d --- /dev/null +++ b/code/_helpers/typelists.dm @@ -0,0 +1,43 @@ +GLOBAL_LIST_EMPTY(typelists) + +#ifndef TESTING + +/datum/proc/typelist(key, list/values = list()) + var/list/mytypelist = GLOB.typelists[type] || (GLOB.typelists[type] = list()) + return mytypelist[key] || (mytypelist[key] = values.Copy()) + +#else +// mostly the same code as above, just more verbose, slower and has tallying for saved lists +/datum/proc/typelist(key, list/values) + if (!values) + values = list() + GLOB.typelistkeys |= key + if (GLOB.typelists[type]) + if (GLOB.typelists[type][key]) + GLOB.typelists[type]["[key]-saved"]++ + return GLOB.typelists[type][key] + else + GLOB.typelists[type][key] = values.Copy() + else + GLOB.typelists[type] = list() + GLOB.typelists[type][key] = values.Copy() + return GLOB.typelists[type][key] + +GLOBAL_LIST_EMPTY(typelistkeys) + +/proc/tallytypelistsavings() + var/savings = list() + var/saveditems = list() + for (var/key in GLOB.typelistkeys) + savings[key] = 0 + saveditems[key] = 0 + + for (var/type in GLOB.typelists) + for (var/saving in savings) + if (GLOB.typelists[type]["[saving]-saved"]) + savings[saving] += GLOB.typelists[type]["[saving]-saved"] + saveditems[saving] += (GLOB.typelists[type]["[saving]-saved"] * length(GLOB.typelists[type][saving])) + + for (var/saving in savings) + to_chat(world, "Savings for [saving]: [savings[saving]] lists, [saveditems[saving]] items") +#endif \ No newline at end of file diff --git a/code/controllers/subsystems/xenoarch.dm b/code/controllers/subsystems/xenoarch.dm index a0e3991530..59dcda2de5 100644 --- a/code/controllers/subsystems/xenoarch.dm +++ b/code/controllers/subsystems/xenoarch.dm @@ -1,8 +1,13 @@ #define XENOARCH_SPAWN_CHANCE 0.5 #define DIGSITESIZE_LOWER 4 #define DIGSITESIZE_UPPER 12 -#define ARTIFACTSPAWNNUM_LOWER 12 -#define ARTIFACTSPAWNNUM_UPPER 24 +#define ARTIFACTSPAWNNUM_LOWER 18 //This used to be 6-12 when xenoarch was performed on mostly a single Z level: The mining asteroid. +#define ARTIFACTSPAWNNUM_UPPER 36 //Due to the increasing complexity of the game, that number resulted in current-day xenaorcheologists possibly being able to find one or maybe two artifacts a Z level. + //This meant that xenoarch, an already tedious job, would be made even slower and more tedious and find very few large artifacts, which is the 'bulk' of their job. This should help alleviate that. + //Ideally, this should be replaced with Z level specific (i.e. spawn 3-6 artifacts per Z level) spawns, but that is for the future. + //For now, this is functional. +#define PROCEDURAL_LOWER 5 //These are high as the generation of them can could be laggy if spammed. This ONLY happens if the entire Z level has been depleted of large artifacts. +#define PROCEDURAL_UPPER 10 //It's easier to just go 'Here's more artifacts to dig up' and give xenoarch more to do. // // Xenoarch subsystem handles initialization of Xenoarcheaology artifacts and digsites. @@ -27,17 +32,107 @@ SUBSYSTEM_DEF(xenoarch) /datum/controller/subsystem/xenoarch/stat_entry(msg) if (!Debug2) return // Only show up in stat panel if debugging is enabled. - . = ..() + return ..() /datum/controller/subsystem/xenoarch/proc/SetupXenoarch() - for(var/turf/simulated/mineral/M in world) + for(var/turf/simulated/mineral/M in world) //This selects every mineral turf in the world + if(!M.density) //Checks to see if it's a mineral wall + continue + + if((M.z in using_map.xenoarch_exempt_levels) || !prob(XENOARCH_SPAWN_CHANCE)) //Now we roll the dice. Base chance is 1/200 for a mineral turf to spawn a digsite. If it doesn't roll that chance, we skip this rock. + continue + + var/farEnough = 1 + for(var/turf/T as anything in digsite_spawning_turfs) //Did any other digsites within 5 tiles roll lucky on their chance? + if(T in range(5, M)) + farEnough = 0 + break + if(!farEnough) //If they did, let's not crowd the area with digsites. Skip this rock, even if it rolled well. + continue + + digsite_spawning_turfs.Add(M) //This rock was lucky enough to be selected and not near any other sites! + + var/digsite = get_random_digsite_type() //What type of artifact site is this? Dictates what items will spawn. + var/target_digsite_size = rand(DIGSITESIZE_LOWER, DIGSITESIZE_UPPER) //What the minimum size our digsite will be. + + var/list/processed_turfs = list() + var/list/turfs_to_process = list(M) + + var/list/viable_adjacent_turfs = list() + if(target_digsite_size > 1) + for(var/turf/simulated/mineral/T in orange(2, M)) //With the rock being the center, check every rock around us within 2 tiles in each direction. So 5x5 square with our rock as the center. + if(!T.density) //Is it an actual mineral wall? + continue + if(T.finds) //If the rock being checked has an artifact in it already, skip it. + continue + if(T in processed_turfs) //The rock has already been processed...This shouldn't happen since farEnough above ensures digsites can't be next to each other. Presumably, this is a failsafe. + continue + viable_adjacent_turfs.Add(T) //Add to the list of rocks we can select for this site. + + //Below determines how many artifacts containing tiles will actually spawn. + target_digsite_size = min(target_digsite_size, viable_adjacent_turfs.len) //Min((4-12),25) with base settings, if there are tiles all around the deposit. If there are less tiles around the deposit, it'll be smaller than the target_size.effectively. + + for(var/i = 1 to target_digsite_size) //Go through all the selected turfs and let's start processing them! + turfs_to_process += pick_n_take(viable_adjacent_turfs) + + while(turfs_to_process.len) + var/turf/simulated/mineral/archeo_turf = pop(turfs_to_process) + + //Here, we start to see how many artifacts will spawn in the selected rock. 1-3 artifacts per. + processed_turfs.Add(archeo_turf) + if(isnull(archeo_turf.finds)) + archeo_turf.finds = list() + if(prob(50)) + archeo_turf.finds.Add(new /datum/find(digsite, rand(10, 190))) //Dictates how far one has to dig to properly excavate the artifact. From 10-190 + else if(prob(75)) + archeo_turf.finds.Add(new /datum/find(digsite, rand(10, 90))) //High chance of being visible, alerting xenoarch to a digsite location. + archeo_turf.finds.Add(new /datum/find(digsite, rand(110, 190))) + else + archeo_turf.finds.Add(new /datum/find(digsite, rand(10, 50))) + archeo_turf.finds.Add(new /datum/find(digsite, rand(60, 140))) + archeo_turf.finds.Add(new /datum/find(digsite, rand(150, 190))) + + //sometimes a find will be close enough to the surface to show + var/datum/find/F = archeo_turf.finds[1] + if(F.excavation_required <= F.view_range) //view_range is by default 40. + archeo_turf.archaeo_overlay = "overlay_archaeo[rand(1,3)]" + archeo_turf.update_icon() + + //have a chance for an artifact to spawn here, but not in animal or plant digsites + if(isnull(M.artifact_find) && digsite != DIGSITE_GARDEN) + artifact_spawning_turfs.Add(archeo_turf) + + //Larger maps will convince byond this is an infinite loop, so let go for a second + CHECK_TICK + + //create artifact machinery. Colloquially known as large artifacts. + //Any artifact turfs except for garden & animal digsites can be selected. + var/num_artifacts_spawn = rand(ARTIFACTSPAWNNUM_LOWER, ARTIFACTSPAWNNUM_UPPER) + while(artifact_spawning_turfs.len > num_artifacts_spawn) + pick_n_take(artifact_spawning_turfs) + + //Actually adds the large artifacts to the areas, now that we have our selected locations. + var/list/artifacts_spawnturf_temp = artifact_spawning_turfs.Copy() + while(artifacts_spawnturf_temp.len > 0) + var/turf/simulated/mineral/artifact_turf = pop(artifacts_spawnturf_temp) + artifact_turf.artifact_find = new() + +/// This is the proc that is used when a Z level runs out of artifacts. This means you have 'completed' your job and now you get bonus goodies to keep you occupied. +/datum/controller/subsystem/xenoarch/proc/continual_generation(var/mob/living/caller) + + /// So, to preface this, I had to do a lot of testing with this to ensure it wouldn't cause mass lag and that it properly functioned. + /// At first, I tried to make it scan mineral in the user's Z. There's not really any preexisting functionality for this that I could find, so that was a negative. + /// Next, I saw what would happen if it did 'in world' and then went 'if M.z != caller.z continue' and that caused...A lot of lag. For a long time. + /// This range(100) was for me was completely lagless. It gives a good amount of artifacts to keep digging and keep archeo working so they don't 'run out' of things to do. + for(var/turf/simulated/mineral/M in range(100, caller)) + if(!M.density) continue - if(isnull(M.geologic_data)) - M.geologic_data = new /datum/geosample(M) + if(M.artifact_find) + continue - if((M.z in using_map.xenoarch_exempt_levels) || !prob(XENOARCH_SPAWN_CHANCE)) + if(!prob(XENOARCH_SPAWN_CHANCE)) continue var/farEnough = 1 @@ -48,40 +143,42 @@ SUBSYSTEM_DEF(xenoarch) if(!farEnough) continue - digsite_spawning_turfs.Add(M) + digsite_spawning_turfs.Add(M) //This rock was lucky enough to be selected and not near any other sites! - var/digsite = get_random_digsite_type() - var/target_digsite_size = rand(DIGSITESIZE_LOWER, DIGSITESIZE_UPPER) + var/digsite = get_random_digsite_type() //What type of artifact site is this? Dictates what items will spawn. + var/target_digsite_size = rand(DIGSITESIZE_LOWER, DIGSITESIZE_UPPER) //What the minimum size our digsite will be. var/list/processed_turfs = list() var/list/turfs_to_process = list(M) var/list/viable_adjacent_turfs = list() if(target_digsite_size > 1) - for(var/turf/simulated/mineral/T in orange(2, M)) - if(!T.density) + for(var/turf/simulated/mineral/T in orange(2, M)) //With the rock being the center, check every rock around us within 2 tiles in each direction. So 5x5 square with our rock as the center. + if(!T.density) //Is it an actual mineral wall? continue - if(T.finds) + if(T.finds) //If the rock being checked has an artifact in it already, skip it. continue - if(T in processed_turfs) + if(T in processed_turfs) //The rock has already been processed...This shouldn't happen since farEnough above ensures digsites can't be next to each other. Presumably, this is a failsafe. continue - viable_adjacent_turfs.Add(T) + viable_adjacent_turfs.Add(T) //Add to the list of rocks we can select for this site. - target_digsite_size = min(target_digsite_size, viable_adjacent_turfs.len) + //Below determines how many artifacts containing tiles will actually spawn. + target_digsite_size = min(target_digsite_size, viable_adjacent_turfs.len) //Min((4-12),25) with base settings, if there are tiles all around the deposit. If there are less tiles around the deposit, it'll be smaller than the target_size.effectively. - for(var/i = 1 to target_digsite_size) + for(var/i = 1 to target_digsite_size) //Go through all the selected turfs and let's start processing them! turfs_to_process += pick_n_take(viable_adjacent_turfs) while(turfs_to_process.len) var/turf/simulated/mineral/archeo_turf = pop(turfs_to_process) + //Here, we start to see how many artifacts will spawn in the selected rock. 1-3 artifacts per. processed_turfs.Add(archeo_turf) if(isnull(archeo_turf.finds)) archeo_turf.finds = list() if(prob(50)) - archeo_turf.finds.Add(new /datum/find(digsite, rand(10, 190))) + archeo_turf.finds.Add(new /datum/find(digsite, rand(10, 190))) //Dictates how far one has to dig to properly excavate the artifact. From 10-190 else if(prob(75)) - archeo_turf.finds.Add(new /datum/find(digsite, rand(10, 90))) + archeo_turf.finds.Add(new /datum/find(digsite, rand(10, 90))) //High chance of being visible, alerting xenoarch to a digsite location. archeo_turf.finds.Add(new /datum/find(digsite, rand(110, 190))) else archeo_turf.finds.Add(new /datum/find(digsite, rand(10, 50))) @@ -90,22 +187,24 @@ SUBSYSTEM_DEF(xenoarch) //sometimes a find will be close enough to the surface to show var/datum/find/F = archeo_turf.finds[1] - if(F.excavation_required <= F.view_range) + if(F.excavation_required <= F.view_range) //view_range is by default 40. archeo_turf.archaeo_overlay = "overlay_archaeo[rand(1,3)]" archeo_turf.update_icon() //have a chance for an artifact to spawn here, but not in animal or plant digsites - if(isnull(M.artifact_find) && digsite != DIGSITE_GARDEN && digsite != DIGSITE_ANIMAL) + if(isnull(M.artifact_find) && digsite != DIGSITE_GARDEN) artifact_spawning_turfs.Add(archeo_turf) //Larger maps will convince byond this is an infinite loop, so let go for a second CHECK_TICK - //create artifact machinery - var/num_artifacts_spawn = rand(ARTIFACTSPAWNNUM_LOWER, ARTIFACTSPAWNNUM_UPPER) + //create artifact machinery. Colloquially known as large artifacts. + //Any artifact turfs except for garden & animal digsites can be selected. + var/num_artifacts_spawn = rand(PROCEDURAL_LOWER, PROCEDURAL_UPPER) //Our random generation will spawn fewer new large artifacts. Remember, this is for our Z level, not the whole map! while(artifact_spawning_turfs.len > num_artifacts_spawn) pick_n_take(artifact_spawning_turfs) + //Actually adds the large artifacts to the areas, now that we have our selected locations. var/list/artifacts_spawnturf_temp = artifact_spawning_turfs.Copy() while(artifacts_spawnturf_temp.len > 0) var/turf/simulated/mineral/artifact_turf = pop(artifacts_spawnturf_temp) @@ -116,3 +215,5 @@ SUBSYSTEM_DEF(xenoarch) #undef DIGSITESIZE_UPPER #undef ARTIFACTSPAWNNUM_LOWER #undef ARTIFACTSPAWNNUM_UPPER +#undef PROCEDURAL_LOWER +#undef PROCEDURAL_UPPER diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm index 0aa3c9889f..3b4ede5402 100644 --- a/code/datums/components/_component.dm +++ b/code/datums/components/_component.dm @@ -474,6 +474,19 @@ if(!.) return _AddComponent(args) +/** + * Removes the component from parent, ends up with a null parent + * Used as a helper proc by the component transfer proc, does not clean up the component like Destroy does + */ +/datum/component/proc/ClearFromParent() + if(!parent) + return + var/datum/old_parent = parent + PreTransfer() + _RemoveFromParent() + parent = null + SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src) + /** * Removes the component from parent, ends up with a null parent */ diff --git a/code/datums/supplypacks/science.dm b/code/datums/supplypacks/science.dm index ae5c6c6efc..96fbb91879 100644 --- a/code/datums/supplypacks/science.dm +++ b/code/datums/supplypacks/science.dm @@ -79,7 +79,8 @@ /obj/item/clothing/glasses/meson, /obj/item/pickaxe, /obj/item/storage/bag/fossils, - /obj/item/hand_labeler) + /obj/item/hand_labeler, + /obj/item/tool/wrench) cost = 100 containertype = /obj/structure/closet/crate/secure/xion containername = "Xenoarchaeology Tech crate" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index da857b3997..6d383c2040 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -294,6 +294,9 @@ /atom/proc/rcd_act(mob/living/user, obj/item/rcd/the_rcd, passed_mode) return +/atom/proc/occult_act(mob/living/user) + return + /atom/proc/melt() return diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index d3627bd4f7..ca86d620d5 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -113,12 +113,15 @@ var/rock_climbing = FALSE //If true, allows climbing cliffs using click drag for single Z, walls if multiZ var/climbing_delay = 1 //If rock_climbing, lower better. -/obj/item/New() +/obj/item/Initialize(mapload) ..() for(var/path in actions_types) add_item_action(path) + if(islist(origin_tech)) + origin_tech = typelist(NAMEOF(src, origin_tech), origin_tech) + if(embed_chance < 0) if(sharp) embed_chance = max(5, round(force/w_class)) diff --git a/code/game/objects/items/weapons/storage/egg_vr.dm b/code/game/objects/items/weapons/storage/egg_vr.dm index 1669121be7..bbf11883ce 100644 --- a/code/game/objects/items/weapons/storage/egg_vr.dm +++ b/code/game/objects/items/weapons/storage/egg_vr.dm @@ -38,12 +38,6 @@ if(user.transforming) user.transforming = FALSE -/obj/item/storage/vore_egg/proc/animate_shake() - var/init_px = pixel_x - var/shake_dir = pick(-1, 1) - animate(src, transform=turn(matrix(), 8*shake_dir), pixel_x=init_px + 2*shake_dir, time=1) - animate(transform=null, pixel_x=init_px, time=6, easing=ELASTIC_EASING) - /obj/item/storage/vore_egg/unathi name = "unathi egg" desc = "Some species of Unathi apparently lay soft-shelled eggs!" diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 9df1f75be1..693a8f3496 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -22,6 +22,7 @@ var/show_examine = TRUE // Does this pop up on a mob when the mob is examined? var/redgate_allowed = TRUE //can we be taken through the redgate, in either direction? + var/being_used = 0 /obj/Destroy() STOP_PROCESSING(SSobj, src) @@ -216,3 +217,10 @@ if(src) step(src, pick(NORTH,SOUTH,EAST,WEST)) sleep(rand(2,4)) + +// Gives the object a shake animation. +/obj/proc/animate_shake() + var/init_px = pixel_x + var/shake_dir = pick(-1, 1) + animate(src, transform=turn(matrix(), 8*shake_dir), pixel_x=init_px + 2*shake_dir, time=1) + animate(transform=null, pixel_x=init_px, time=6, easing=ELASTIC_EASING) diff --git a/code/game/objects/random/maintenance.dm b/code/game/objects/random/maintenance.dm index 268cf07f7c..9489fd1cb1 100644 --- a/code/game/objects/random/maintenance.dm +++ b/code/game/objects/random/maintenance.dm @@ -269,7 +269,7 @@ something, make sure it's not in one of the other lists.*/ prob(5);/obj/item/storage/backpack/toxins, prob(5);/obj/item/storage/backpack/satchel/tox, prob(5);/obj/item/storage/backpack/messenger/tox, - prob(2);/obj/item/storage/excavation, + prob(2);/obj/item/pickaxe/excavationdrill, prob(1);/obj/item/storage/backpack/holding, prob(3);/obj/item/storage/box/beakers, prob(3);/obj/item/storage/box/syringes, diff --git a/code/game/objects/structures/crates_lockers/__closets.dm b/code/game/objects/structures/crates_lockers/__closets.dm index 3bfa5ff727..accac2331c 100644 --- a/code/game/objects/structures/crates_lockers/__closets.dm +++ b/code/game/objects/structures/crates_lockers/__closets.dm @@ -475,12 +475,6 @@ BD.unwrap() open() -/obj/structure/closet/proc/animate_shake() - var/init_px = pixel_x - var/shake_dir = pick(-1, 1) - animate(src, transform=turn(matrix(), 8*shake_dir), pixel_x=init_px + 2*shake_dir, time=1) - animate(transform=null, pixel_x=init_px, time=6, easing=ELASTIC_EASING) - /obj/structure/closet/onDropInto(var/atom/movable/AM) return diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm index 25310147df..34bab3dcd7 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm @@ -70,7 +70,8 @@ /obj/item/clothing/glasses/science, /obj/item/radio/headset/headset_sci, /obj/item/storage/belt/archaeology, - /obj/item/storage/excavation) + /obj/item/storage/excavation, + /obj/item/pickaxe/excavationdrill) /obj/structure/closet/excavation name = "Excavation tools" diff --git a/code/game/objects/structures/fitness.dm b/code/game/objects/structures/fitness.dm index 1e754ed8de..0a059c8a64 100644 --- a/code/game/objects/structures/fitness.dm +++ b/code/game/objects/structures/fitness.dm @@ -1,7 +1,7 @@ /obj/structure/fitness icon = 'icons/obj/stationobjs.dmi' anchored = TRUE - var/being_used = 0 + var/fitness_being_used = 0 var/weightloss_power = 1 /obj/structure/fitness/punchingbag @@ -50,11 +50,11 @@ if(user.nutrition < 50) to_chat(user, span_warning("You need more energy to lift weights. Go eat something.")) return - if(being_used) + if(fitness_being_used) to_chat(user, span_warning("The weight machine is already in use by somebody else.")) return else - being_used = 1 + fitness_being_used = 1 playsound(src, 'sound/effects/weightlifter.ogg', 50, 1) user.set_dir(SOUTH) flick("[icon_state]_[weight]", src) @@ -64,7 +64,7 @@ var/weightloss_enhanced = weightloss_power * (weight * 0.5) user.weight -= 0.25 * weightloss_enhanced * (0.01 * user.weight_loss) to_chat(user, span_notice("You lift the weights [qualifiers[weight]].")) - being_used = 0 + fitness_being_used = 0 else to_chat(user, span_notice("Against your previous judgement, perhaps working out is not for you.")) - being_used = 0 + fitness_being_used = 0 diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 93098250c2..0821318e2d 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -9,7 +9,7 @@ layer = TABLE_LAYER explosion_resistance = 1 var/health = 10 - var/destroyed = 0 + var/destroyed = FALSE /obj/structure/grille/ex_act(severity) @@ -60,7 +60,7 @@ //Flimsy grilles aren't so great at stopping projectiles. However they can absorb some of the impact var/damage = Proj.get_structure_damage() - var/passthrough = 0 + var/passthrough = FALSE if(!damage) return @@ -72,15 +72,15 @@ if(Proj.original == src || prob(20)) Proj.damage *= between(0, Proj.damage/60, 0.5) if(prob(max((damage-10)/25, 0))*100) - passthrough = 1 + passthrough = TRUE else Proj.damage *= between(0, Proj.damage/60, 1) - passthrough = 1 + passthrough = TRUE if(BURN) //beams and other projectiles are either blocked completely by grilles or stop half the damage. if(!(Proj.original == src || prob(20))) Proj.damage *= 0.5 - passthrough = 1 + passthrough = TRUE if(passthrough) . = PROJECTILE_CONTINUE @@ -221,7 +221,7 @@ // Used in mapping to avoid /obj/structure/grille/broken - destroyed = 1 + destroyed = TRUE icon_state = "grille-b" density = FALSE @@ -282,6 +282,11 @@ return TRUE return FALSE +/obj/structure/grille/occult_act(mob/living/user) + new /obj/structure/grille/cult(get_turf(src)) + qdel(src) + return TRUE + /obj/structure/grille/take_damage(var/damage) health -= damage spawn(1) healthcheck() diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index ee86344966..eec0bede4b 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -177,6 +177,11 @@ ChangeTurf(get_base_turf_by_area(src), preserve_outdoors = TRUE) return TRUE +/turf/simulated/floor/occult_act(mob/living/user) + to_chat(user, span_cult("You consecrate the floor.")) + ChangeTurf(/turf/simulated/floor/cult, preserve_outdoors = TRUE) + return TRUE + /turf/simulated/floor/AltClick(mob/user) if(isliving(user)) var/mob/living/livingUser = user diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 2494e10574..385c7b2ba4 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -334,6 +334,11 @@ return TRUE return FALSE +/turf/simulated/wall/occult_act(mob/living/user) + to_chat(user, span_cult("You consecrate the wall.")) + ChangeTurf(/turf/simulated/wall/cult, preserve_outdoors = TRUE) + return TRUE + /turf/simulated/wall/AltClick(mob/user) if(isliving(user)) var/mob/living/livingUser = user diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 3cfc4585fc..4f0d6be739 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -399,6 +399,10 @@ return TRUE return FALSE +/turf/occult_act(mob/living/user) + to_chat(user, span_cult("You consecrate the floor.")) + ChangeTurf(/turf/simulated/floor/cult, preserve_outdoors = TRUE) + return TRUE // We're about to be the A-side in a turf translation /turf/proc/pre_translate_A(var/turf/B) diff --git a/code/game/turfs/unsimulated.dm b/code/game/turfs/unsimulated.dm index 06cb988fdf..5f249e354e 100644 --- a/code/game/turfs/unsimulated.dm +++ b/code/game/turfs/unsimulated.dm @@ -29,3 +29,6 @@ /turf/unsimulated/rcd_act(mob/living/user, obj/item/rcd/the_rcd, passed_mode) return FALSE + +/turf/unsimulated/occult_act(mob/living/user) + return FALSE diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index 47f89d9ed7..05a9856595 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -413,6 +413,7 @@ var/list/mining_overlay_cache = list() else + //This lets us get a sample of the artifact core...This is JUST used for fluff. if (istype(W, /obj/item/core_sampler)) geologic_data.UpdateNearbyArtifactInfo(src) var/obj/item/core_sampler/C = W @@ -446,8 +447,8 @@ var/list/mining_overlay_cache = list() return var/obj/item/melee/shock_maul/S = W - if(!S.wielded || !S.status) //if we're not wielded OR not powered up, do nothing - to_chat(user, span_warning("\The [src] must be wielded in two hands and powered on to be used for mining!")) + if(!S.wielded) + to_chat(user, span_warning("\The [W] must be wielded in two hands to be used for mining!")) return var/newDepth = excavation_level + S.excavation_amount // Used commonly below @@ -461,6 +462,12 @@ var/list/mining_overlay_cache = list() wreckfinds(S.destroy_artefacts) to_chat(user, span_notice("You smash through \the [src][fail_message].")) + if(S.status != 0) //We're on. This isn't just a == 1 in case someone adds some weird functionality in the future to give it multiple states. + user.visible_message(span_warning("\The [src] discharges with a thunderous, hair-raising crackle!")) + playsound(src, 'sound/weapons/resonator_blast.ogg', 100, 1, -1) + else + user.visible_message(span_warning("\The [src] plows into the rock with a thunk, smashing it to pieces.")) + playsound(src, get_sfx("pickaxe"), 35, 1, -1) //Weak. Not on. Just as good as a normal pick. if(newDepth >= 200) // This means the rock is mined out fully if(S.destroy_artefacts) @@ -471,7 +478,7 @@ var/list/mining_overlay_cache = list() excavation_level += S.excavation_amount update_archeo_overlays(S.excavation_amount) - + geologic_data = new /datum/geosample(src) //drop some rocks next_rock += S.excavation_amount while(next_rock > 50) @@ -480,12 +487,6 @@ var/list/mining_overlay_cache = list() geologic_data.UpdateNearbyArtifactInfo(src) O.geologic_data = geologic_data - user.visible_message(span_warning("\The [src] discharges with a thunderous, hair-raising crackle!")) - playsound(src, 'sound/weapons/resonator_blast.ogg', 100, 1, -1) - S.deductcharge() - S.status = 0 - S.update_held_icon() - if (istype(W, /obj/item/pickaxe)) if(!istype(user.loc, /turf)) return @@ -513,8 +514,8 @@ var/list/mining_overlay_cache = list() var/datum/find/F = finds[1] if(newDepth == F.excavation_required) // When the pick hits that edge just right, you extract your find perfectly, it's never confined in a rock excavate_find(1, F) - else if(newDepth > F.excavation_required - F.clearance_range) // Not quite right but you still extract your find, the closer to the bottom the better, but not above 80% - excavate_find(prob(80 * (F.excavation_required - newDepth) / F.clearance_range), F) + else if(newDepth > F.excavation_required) + excavate_find(prob(10), F) //A 1 in 10 chance to get it out perfectly seems fine if you're not being careful. to_chat(user, span_notice("You finish [P.drill_verb] \the [src].")) @@ -527,7 +528,7 @@ var/list/mining_overlay_cache = list() excavation_level += P.excavation_amount update_archeo_overlays(P.excavation_amount) - + geologic_data = new /datum/geosample(src) //drop some rocks next_rock += P.excavation_amount while(next_rock > 50) @@ -595,6 +596,7 @@ var/list/mining_overlay_cache = list() if(!mineral) return clear_ore_effects() + geologic_data = new /datum/geosample(src) var/obj/item/ore/O = new mineral.ore (src) if(istype(O)) geologic_data.UpdateNearbyArtifactInfo(src) @@ -604,16 +606,9 @@ var/list/mining_overlay_cache = list() /turf/simulated/mineral/proc/excavate_turf() var/obj/structure/boulder/B if(artifact_find) - if( excavation_level > 0 || prob(15) ) - //boulder with an artifact inside - B = new(src) - if(artifact_find) - B.artifact_find = artifact_find - else - artifact_debris(1) - else if(prob(5)) - //empty boulder + //boulder with an artifact inside B = new(src) + B.artifact_find = artifact_find if(B) GetDrilled(0) @@ -668,9 +663,10 @@ var/list/mining_overlay_cache = list() /turf/simulated/mineral/proc/excavate_find(var/is_clean = 0, var/datum/find/F) //with skill and luck, players can cleanly extract finds //otherwise, they come out inside a chunk of rock + geologic_data = new /datum/geosample(src) var/obj/item/X if(is_clean) - X = new /obj/item/archaeological_find(src, new_item_type = F.find_type) + X = new /obj/item/archaeological_find(src, F.find_type) else X = new /obj/item/strangerock(src, inside_item_type = F.find_type) geologic_data.UpdateNearbyArtifactInfo(src) @@ -685,6 +681,8 @@ var/list/mining_overlay_cache = list() if(X) display_name = X.name + //This is affected by 'prob_delicate' in finds.dm. As of writing, this has been set to 0 because the suspension field is just one extra piece that makes + //Xenoarch that much more confusing, and the intent of this PR is to make it more friendly to get into. //many finds are ancient and thus very delicate - luckily there is a specialised energy suspension field which protects them when they're being extracted if(prob(F.prob_delicate)) var/obj/effect/suspension_field/S = locate() in src diff --git a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm index a31d6ba190..d617f039a8 100644 --- a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm +++ b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm @@ -133,9 +133,9 @@ EQUIPMENT("Resonator", /obj/item/resonator, 900), EQUIPMENT("Silver Pickaxe", /obj/item/pickaxe/silver, 1200), EQUIPMENT("Super Resonator", /obj/item/resonator/upgraded, 2500), - EQUIPMENT("Fine Excavation Kit - Chisels", /obj/item/storage/excavation, 500), + EQUIPMENT("Archeology Equipment - Chisels", /obj/item/storage/excavation, 500), + EQUIPMENT("Archeology Equipment - Scanner", /obj/item/depth_scanner, 1000), // They can get a basic scanner for archeology, but not the anomaly scanner. Keeps job stealing at a minimum while also allowing miners to excavate any cool rocks they come across. EQUIPMENT("Fine Excavation Kit - Measuring Tape", /obj/item/measuring_tape, 125), - EQUIPMENT("Fine Excavation Kit - Hand Pick", /obj/item/pickaxe/hand, 375), EQUIPMENT("Explosive Excavation Kit - Plastic Charge",/obj/item/plastique/seismic/locked, 1500), EQUIPMENT("Industrial Equipment - Phoron Bore", /obj/item/gun/magnetic/matfed/phoronbore/loaded, 3000), EQUIPMENT("Industrial Equipment - Inducer", /obj/item/inducer, 3500), diff --git a/code/modules/rogueminer_vr/zonemaster.dm b/code/modules/rogueminer_vr/zonemaster.dm index 0ea46135fd..71090a9a7f 100644 --- a/code/modules/rogueminer_vr/zonemaster.dm +++ b/code/modules/rogueminer_vr/zonemaster.dm @@ -244,8 +244,8 @@ archeo_turf.archaeo_overlay = "overlay_archaeo[rand(1,3)]" archeo_turf.update_icon() - //have a chance for an artifact to spawn here, but not in animal or plant digsites - if(isnull(M.artifact_find) && digsite != DIGSITE_GARDEN && digsite != DIGSITE_ANIMAL) + //have a chance for an artifact to spawn here, but not in plant digsites + if(isnull(M.artifact_find) && digsite != DIGSITE_GARDEN) SSxenoarch.artifact_spawning_turfs.Add(archeo_turf) //create artifact machinery diff --git a/code/modules/xenoarcheaology/artifacts/artifact.dm b/code/modules/xenoarcheaology/artifacts/artifact.dm index 52c871a7b9..a1ea8e37ea 100644 --- a/code/modules/xenoarcheaology/artifacts/artifact.dm +++ b/code/modules/xenoarcheaology/artifacts/artifact.dm @@ -1,3 +1,9 @@ +//Xenoarch machinery spawning code! +//These are colloquially refered to 'large' artifacts. +//The below dictates the icon, description, and the activation requirement. +//Additionally, it updates the icon based on if it's active or not. +//What the artifact does itself is dictated by effect.dm. + /obj/machinery/artifact name = "alien artifact" desc = "A large alien device." @@ -5,18 +11,16 @@ icon_state = "ano00" var/icon_num = 0 density = TRUE + //Note: If you adminspawn this, it will NOT have an assosciated artifact_id. You have to manually set it! var/predefined_icon_num var/datum/component/artifact_master/artifact_master = /datum/component/artifact_master - var/being_used = 0 - - /obj/machinery/artifact/Destroy() if(artifact_master) var/datum/component/artifact_master/arti_mstr = artifact_master - arti_mstr.RemoveComponent() + arti_mstr.ClearFromParent() artifact_master = null if(!QDELETED(arti_mstr)) qdel(arti_mstr) @@ -33,7 +37,7 @@ if(!istype(artifact_master)) return - var/datum/artifact_effect/my_effect = artifact_master.get_primary() + var/datum/artifact_effect/my_effect = artifact_master.get_primary() //Gets the primary effect of the artifact. if(!isnull(predefined_icon_num)) icon_num = predefined_icon_num @@ -48,27 +52,22 @@ "It seems to draw you inward as you look it at.", "Something twinkles faintly as you look at it.", "It's mesmerizing to behold.") - if(prob(50)) - my_effect.trigger = TRIGGER_ENERGY + my_effect.trigger = pick(TRIGGER_ENERGY, TRIGGER_TOUCH) else if(icon_num == 9 || icon_num == 17 || icon_num == 19) name = "alien computer" desc = "It is covered in strange markings." - if(prob(75)) - my_effect.trigger = TRIGGER_TOUCH + my_effect.trigger = TRIGGER_TOUCH else if(icon_num == 10) desc = "A large alien device, there appear to be some kind of vents in the side." - if(prob(50)) - my_effect.trigger = pick(TRIGGER_ENERGY, TRIGGER_HEAT, TRIGGER_COLD, TRIGGER_PHORON, TRIGGER_OXY, TRIGGER_CO2, TRIGGER_NITRO) + my_effect.trigger = pick(TRIGGER_ENERGY, TRIGGER_HEAT, TRIGGER_COLD, TRIGGER_PHORON, TRIGGER_OXY, TRIGGER_CO2, TRIGGER_NITRO) else if(icon_num == 11) name = "sealed alien pod" desc = "A strange alien device." - if(prob(25)) - my_effect.trigger = pick(TRIGGER_WATER, TRIGGER_ACID, TRIGGER_VOLATILE, TRIGGER_TOXIN) + my_effect.trigger = pick(TRIGGER_WATER, TRIGGER_ACID, TRIGGER_VOLATILE, TRIGGER_TOXIN) else if(icon_num == 12 || icon_num == 14) name = "intricately carved statue" desc = "A strange statue." - if(prob(60)) - my_effect.trigger = pick(TRIGGER_TOUCH, TRIGGER_HEAT, TRIGGER_COLD, TRIGGER_PHORON, TRIGGER_OXY, TRIGGER_CO2, TRIGGER_NITRO) + my_effect.trigger = pick(TRIGGER_TOUCH, TRIGGER_HEAT, TRIGGER_COLD, TRIGGER_PHORON, TRIGGER_OXY, TRIGGER_CO2, TRIGGER_NITRO) /obj/machinery/artifact/update_icon() ..() diff --git a/code/modules/xenoarcheaology/artifacts/artifact_find.dm b/code/modules/xenoarcheaology/artifacts/artifact_find.dm index dcbe6bea84..49369d861c 100644 --- a/code/modules/xenoarcheaology/artifacts/artifact_find.dm +++ b/code/modules/xenoarcheaology/artifacts/artifact_find.dm @@ -2,18 +2,26 @@ var/artifact_id var/artifact_find_type +/// These are the LARGE artifacts that can spawn (Have density, have to be pulled, etc etc.) Not the HANDHELD or MUNDANE artifacts. For those, see find_spawning.dm. /datum/artifact_find/New() artifact_id = "[pick("kappa","sigma","antaeres","beta","omicron","iota","epsilon","omega","gamma","delta","tau","alpha")]-[rand(100,999)]" artifact_find_type = pick( - 5;/obj/machinery/power/supermatter, - 5;/obj/structure/constructshell, - 5;/obj/machinery/syndicate_beacon/virgo, // VOREStation Edit: use virgo-specific subtype that doesn't create 'real' antags, - 25;/obj/machinery/power/supermatter/shard, - 100;/obj/machinery/auto_cloner, - 100;/obj/machinery/giga_drill, - 100;/obj/machinery/replicator/clothing, //VOREStation Edit: use virgo-specific subtype that allows TF into items. - 100;/obj/machinery/replicator/vore, //VOREStation Edit: use virgo-specific subtype that allows TF into mobs. - 150;/obj/structure/crystal, - 1000;/obj/machinery/artifact) + 300;/obj/machinery/artifact, + 50;/obj/machinery/syndicate_beacon/virgo, // VOREStation Edit: use virgo-specific subtype that doesn't create 'real' antags, + 50;/obj/machinery/auto_cloner, + 50;/obj/machinery/replicator/vore, + 25;/obj/structure/constructshell, + 25;/obj/machinery/giga_drill, + 25;/obj/machinery/replicator/clothing, //VOREStation Edit: use virgo-specific subtype that allows TF into items. //VOREStation Edit: use virgo-specific subtype that allows TF into mobs. + 25;/obj/structure/crystal, + 5;/obj/machinery/power/supermatter/shard, + 5;/obj/machinery/power/supermatter,) + + // Calculations: + // Our total is 560 (As of the time of writing. If ANY of the weights are adjusted above, you have to recalculate. Formula: (thingy_wt/total_wt)*100 = % chance of drop) + // Artifact: 53% + // 50 wt: 8.9% + // 25 wt: 4.4% + // 5 wt: 0.89% diff --git a/code/modules/xenoarcheaology/boulder.dm b/code/modules/xenoarcheaology/boulder.dm index 18cfe19fbd..4d32427e76 100644 --- a/code/modules/xenoarcheaology/boulder.dm +++ b/code/modules/xenoarcheaology/boulder.dm @@ -63,12 +63,6 @@ to_chat(user, span_notice("You finish [P.drill_verb] [src].")) excavation_level += P.excavation_amount - if(excavation_level > 100) - //failure - user.visible_message(span_warning("\The [src] suddenly crumbles away."), span_warning("\The [src] has disintegrated under your onslaught, any secrets it was holding are long gone.")) - qdel(src) - return - if(prob(excavation_level)) //success if(artifact_find) diff --git a/code/modules/xenoarcheaology/effect.dm b/code/modules/xenoarcheaology/effect.dm index c19c0592d4..a737196627 100644 --- a/code/modules/xenoarcheaology/effect.dm +++ b/code/modules/xenoarcheaology/effect.dm @@ -1,14 +1,15 @@ /datum/artifact_effect var/name = "unknown" - var/effect = EFFECT_TOUCH - var/effectrange = 4 - var/trigger = TRIGGER_TOUCH - var/datum/component/artifact_master/master + var/effect = EFFECT_TOUCH //This is simply if the effect occurs on touch, in an aura, or a pulse AOE. Horribly named variable. + var/effectrange = 4 //How far the effect will hit something. + var/trigger = TRIGGER_TOUCH //This decides how the artifact is actually activated. Ex: Splashing water on it. + var/datum/component/artifact_master/master //This code is handled in effect_master.dm var/activated = 0 var/chargelevel = 1 var/chargelevelmax = 10 var/artifact_id = "" - var/effect_type = 0 + var/effect_type = 0 //This is what the artifact does. This is used to generating a description when inspected. + var/harvestable = 1 //If we can be harvested or not var/req_type = /atom/movable @@ -111,46 +112,94 @@ DoEffectPulse() /datum/artifact_effect/proc/getDescription() - . = "" + . = "

This object has been detected to: " switch(effect_type) - if(EFFECT_ENERGY) - . += "Concentrated energy emissions" - if(EFFECT_PSIONIC) - . += "Intermittent psionic wavefront" - if(EFFECT_ELECTRO) - . += "Electromagnetic energy" - if(EFFECT_PARTICLE) - . += "High frequency particles" - if(EFFECT_ORGANIC) - . += "Organically reactive exotic particles" - if(EFFECT_BLUESPACE) - . += "Interdimensional/bluespace? phasing" - if(EFFECT_SYNTH) - . += "Atomic synthesis" + if(EFFECT_UNKNOWN) + . += span_bold("have an unknown effect") //Should never happen but you know, whatever. Failsafe. + if(EFFECT_ANIMATE) + . += span_bold("have intermittent movement either towards or away from an individual") + if(EFFECT_FEELINGS) + . += span_bold("cause subjects to feel a certain way") + if(EFFECT_CELL) + . += span_bold("charges or drains electronic devices in range") + if(EFFECT_TEMPERATURE) + . += span_bold("adjust the thermal energy in an area") + /* //Not Yet Implemented + if(EFFECT_DNASWITCH) + . += "scramble the DNA of a subject, resulting in rampant genetic mutation" + */ + if(EFFECT_ELECTIC_FIELD) + . += "discharge concentrated electrical energy" + if(EFFECT_EMP) + . += "discharge electromagnetic energy" + if(EFFECT_FEYSIGHT) + . += "invoke visions in subjects" //spooky. + if(EFFECT_FORCEFIELD) + . += "create a forcefield within a short range" + if(EFFECT_GAIA) + . += "transfer healing energies to nearby flora" + if(EFFECT_GAS) + . += "emits gas of some type" + if(EFFECT_GRAVIATIONAL_WAVES) + . += "create local gravitational distortions" + if(EFFECT_HEALTH) + . += "transfer energies into subjects, harming or healing them" + if(EFFECT_POLTERGEIST) + . += "cause local movement phenomena" + if(EFFECT_RADIATE) + . += "transfer high energy gamma rays into subjects" + if(EFFECT_RESURRECT) + . += "transfer the lifeforce from one entity to another, potentially allowing the ressurection of deceased entities" + if(EFFECT_ROBOT_HEALTH) + . += "transfer energies into synthetic lifeforms, harming or healing them" + if(EFFECT_SLEEPY) + . += "invoke drowsiness in subjects" + if(EFFECT_STUN) + . += "discharge non-lethal amounts of energy into subjects" + if(EFFECT_TELEPORT) + . += "displace subjects using bluespace phenomena" + if(EFFECT_VAMPIRE) + . += "drain the blood of subjects, creating creatures or anomalous artifacts in the process" else - . += "Low level energy emissions" + . += "have no previously-known anomalous properties" - . += "
have been detected " + . += ". The method of the dispersion of the object's effect seems to be through " switch(effect) if(EFFECT_TOUCH) - . += "interspersed throughout substructure and shell." + . += span_bold(" contact with the object.") if(EFFECT_AURA) - . += "emitting in an ambient energy field." + . += span_bold(" occasional, short ranged pulses of energy.") if(EFFECT_PULSE) - . += "emitting in periodic bursts." + . += span_bold(" occasional, long ranged pulses of energy.") else - . += "emitting in an unknown way." + . += "" - . += "" + . += "
" switch(trigger) - if(TRIGGER_TOUCH, TRIGGER_WATER, TRIGGER_ACID, TRIGGER_VOLATILE, TRIGGER_TOXIN) - . += " Activation index involves physical interaction with artifact surface." - if(TRIGGER_FORCE, TRIGGER_ENERGY, TRIGGER_HEAT, TRIGGER_COLD) - . += " Activation index involves energetic interaction with artifact surface." - if(TRIGGER_PHORON, TRIGGER_OXY, TRIGGER_CO2, TRIGGER_NITRO) - . += " Activation index involves precise local atmospheric conditions." + if(TRIGGER_TOUCH) //This one should be self explanatory. + . += "Activation index involves " + span_bold("physical interaction") + " with artifact surface." + if(TRIGGER_WATER, TRIGGER_ACID, TRIGGER_VOLATILE, TRIGGER_TOXIN) //No xenoarch would know how to activate these without code digging. + . += " Activation index involves " + span_bold("chemical interaction with artifact surface.") + " Water/Hydrogen, sulfuric acid, Thermite/Phoron, and toxin/toxic substances are potential triggers." + + if(TRIGGER_FORCE, TRIGGER_ENERGY) //Did you know multitools can activate energy artifacts? + . += " Activation index involves " + span_bold("forceful or energetic interaction with artifact surface.") + " Potential triggers are a pulse from a multitool or battering the artifact with a strong object." + + if(TRIGGER_HEAT, TRIGGER_COLD) //Heat is easy to activate. Smack it with a welder. Cold? Have to cool the area. + . += " Activation index involves " + span_bold("precise temperature conditions.") + " Heating/Cooling the atmosphere (>375K or <225K) or using a welder are potential triggers." + + //Gases are separate since they are a pain in the rear to get activated and might as well let you know exactly what to do. + //I've been playing this game since the dawn of man and I've never seen someone bother to actually TRY to set up atmos to get these activated. + //Honestly, I'm slating these for removal. + if(TRIGGER_PHORON) + . += " Activation index involves "+ span_bold("precise local atmospheric conditions.") + " Phoron is a potential trigger. (Atmosphere must be >10% of gas to activate device)" + if(TRIGGER_OXY) + . += " Activation index involves "+ span_bold("precise local atmospheric conditions.") + " Oxygen is a potential trigger. (Atmosphere must be >10% of gas to activate device)" + if(TRIGGER_CO2) + . += " Activation index involves "+ span_bold("precise local atmospheric conditions.") + " Carbon Dioxide, is a potential trigger. (Atmosphere must be >10% of gas to activate device)" + if(TRIGGER_NITRO) + . += " Activation index involves "+ span_bold("precise local atmospheric conditions.") + " Nitrous Oxide is a potential trigger. (Atmosphere must be >10% of gas to activate device)" else . += " Unable to determine any data about activation trigger." diff --git a/code/modules/xenoarcheaology/effect_master.dm b/code/modules/xenoarcheaology/effect_master.dm index f6954f4090..1416cf77e9 100644 --- a/code/modules/xenoarcheaology/effect_master.dm +++ b/code/modules/xenoarcheaology/effect_master.dm @@ -3,6 +3,23 @@ * Here there be the base component for artifacts. */ +//The reagents used to be a very small list of only certain reagent IDs previously. +//Now, we use modifiable lists that allows /types/ of reagents to be used. Nifty, right? +//Now if you dump reagent/toxin/really_bad_deadly_stuff it'll activate it just like reagent/toxin will. +#define HYDROGEN_PATH /datum/reagent/hydrogen +#define WATER_PATH /datum/reagent/water +#define ACID_PATH /datum/reagent/acid +#define DIETHYLAMINE_PATH /datum/reagent/diethylamine +#define PHORON_PATH /datum/reagent/toxin/phoron +#define HYDROPHORON_PATH /datum/reagent/toxin/hydrophoron +#define THERMITE_PATH /datum/reagent/thermite +#define TOXIN_PATH /datum/reagent/toxin + +var/list/water_reagents = list(HYDROGEN_PATH, WATER_PATH) +var/list/acid_reagents = list(ACID_PATH, DIETHYLAMINE_PATH) +var/list/volatile_reagents = list(PHORON_PATH, HYDROPHORON_PATH, THERMITE_PATH) +var/list/toxic_reagents = list(TOXIN_PATH) + /atom/proc/is_anomalous() return (GetComponent(/datum/component/artifact_master)) @@ -100,6 +117,13 @@ return active_effects +/datum/component/artifact_master/proc/get_all_effects() + var/list/effects = list() + for(var/datum/artifact_effect/my_effect in my_effects) + effects |= my_effect + + return effects + /datum/component/artifact_master/proc/add_effect() var/effect_type = input(usr, "What type do you want?", "Effect Type") as null|anything in subtypesof(/datum/artifact_effect) if(effect_type) @@ -144,7 +168,7 @@ /datum/component/artifact_master/proc/generate_effects() while(effect_generation_chance > 0) - var/chosen_path = pick(subtypesof(/datum/artifact_effect)) + var/chosen_path = pick(subtypesof(/datum/artifact_effect) - /datum/artifact_effect/extreme) if(effect_generation_chance >= 100) // If we're above 100 percent, just cut a flat amount and add an effect. var/datum/artifact_effect/AE = new chosen_path(src) if(istype(holder, AE.req_type)) @@ -228,11 +252,11 @@ my_effect.ToggleActivate() else if(ishuman(bumped) && GetAnomalySusceptibility(bumped) >= 0.5) - if (my_effect.trigger == TRIGGER_TOUCH && prob(50)) + if (my_effect.trigger == TRIGGER_TOUCH) my_effect.ToggleActivate() warn = 1 - if (my_effect.effect == EFFECT_TOUCH && prob(50)) + if (my_effect.effect == EFFECT_TOUCH) my_effect.DoEffectTouch(bumped) warn = 1 @@ -249,11 +273,11 @@ my_effect.ToggleActivate() else if(ishuman(M) && !istype(M:gloves,/obj/item/clothing/gloves)) - if (my_effect.trigger == TRIGGER_TOUCH && prob(50)) + if (my_effect.trigger == TRIGGER_TOUCH) my_effect.ToggleActivate() warn = 1 - if (my_effect.effect == EFFECT_TOUCH && prob(50)) + if (my_effect.effect == EFFECT_TOUCH) my_effect.DoEffectTouch(M) warn = 1 @@ -268,9 +292,6 @@ if (get_dist(user, holder) > 1) to_chat(user, span_filter_notice("[span_red("You can't reach [holder] from here.")]")) return - if(ishuman(user) && user:gloves) - to_chat(user, span_filter_notice(span_bold("You touch [holder]") + " with your gloved hands, [pick("but nothing of note happens","but nothing happens","but nothing interesting happens","but you notice nothing different","but nothing seems to have happened")].")) - return var/triggered = FALSE @@ -293,56 +314,73 @@ /datum/component/artifact_master/proc/on_attackby() var/obj/item/W = args[2] - for(var/datum/artifact_effect/my_effect in my_effects) + for(var/datum/artifact_effect/my_effect in my_effects) + //If we were splashed by a reagent, let's check to see if we have a trigger for that. if (istype(W, /obj/item/reagent_containers)) - if(W.reagents.has_reagent(REAGENT_ID_HYDROGEN, 1) || W.reagents.has_reagent(REAGENT_ID_WATER, 1)) - if(my_effect.trigger == TRIGGER_WATER) - my_effect.ToggleActivate() - else if(W.reagents.has_reagent(REAGENT_ID_SACID, 1) || W.reagents.has_reagent(REAGENT_ID_PACID, 1) || W.reagents.has_reagent(REAGENT_ID_DIETHYLAMINE, 1)) - if(my_effect.trigger == TRIGGER_ACID) - my_effect.ToggleActivate() - else if(W.reagents.has_reagent(REAGENT_ID_PHORON, 1) || W.reagents.has_reagent(REAGENT_ID_THERMITE, 1)) - if(my_effect.trigger == TRIGGER_VOLATILE) - my_effect.ToggleActivate() - else if(W.reagents.has_reagent(REAGENT_ID_TOXIN, 1) || W.reagents.has_reagent(REAGENT_ID_CYANIDE, 1) || W.reagents.has_reagent(REAGENT_ID_AMATOXIN, 1) || W.reagents.has_reagent(REAGENT_ID_NEUROTOXIN, 1)) - if(my_effect.trigger == TRIGGER_TOXIN) - my_effect.ToggleActivate() + if(my_effect.trigger == TRIGGER_WATER) + for(var/datum/reagent/R in W.reagents.reagent_list) //What chems are in the beaker? + var/T = R.type + if(is_path_in_list(T,water_reagents)) //Check the reagent and activate! + my_effect.ToggleActivate() + + else if(my_effect.trigger == TRIGGER_ACID) + for(var/datum/reagent/R in W.reagents.reagent_list) + var/T = R.type + if(is_path_in_list(T,acid_reagents)) + my_effect.ToggleActivate() + + else if(my_effect.trigger == TRIGGER_VOLATILE) + for(var/datum/reagent/R in W.reagents.reagent_list) + var/T = R.type + if(is_path_in_list(T,volatile_reagents)) + my_effect.ToggleActivate() + + else if(my_effect.trigger == TRIGGER_TOXIN) + for(var/datum/reagent/R in W.reagents.reagent_list) + var/T = R.type + if(is_path_in_list(T,toxic_reagents)) + my_effect.ToggleActivate() + //If we weren't splashed, let's see if we were hit by a energy item and if we're energy activation. else if(istype(W,/obj/item/melee/baton) && W:status ||\ istype(W,/obj/item/melee/energy) ||\ istype(W,/obj/item/melee/cultblade) ||\ istype(W,/obj/item/card/emag) ||\ istype(W,/obj/item/multitool)) + if (my_effect.trigger == TRIGGER_ENERGY) my_effect.ToggleActivate() + //If we weren't hit by energy, let's see if we were hit by a lighter or welding tool and if we are heat. else if (istype(W,/obj/item/flame) && W:lit ||\ istype(W,/obj/item/weldingtool) && W:welding) if(my_effect.trigger == TRIGGER_HEAT) my_effect.ToggleActivate() + + //Otherwise, let's see if we were hit with something with enough force to activate us. else if (my_effect.trigger == TRIGGER_FORCE && W.force >= 10) my_effect.ToggleActivate() /datum/component/artifact_master/proc/on_reagent() - var/datum/reagent/Touching = args[2] - - var/list/water = list(REAGENT_ID_HYDROGEN, REAGENT_ID_WATER) - var/list/acid = list(REAGENT_ID_SACID, REAGENT_ID_PACID, REAGENT_ID_DIETHYLAMINE) - var/list/volatile = list(REAGENT_ID_PHORON,REAGENT_ID_THERMITE) - var/list/toxic = list(REAGENT_ID_TOXIN,REAGENT_ID_CYANIDE,REAGENT_ID_AMATOXIN,REAGENT_ID_NEUROTOXIN) + //A strange bug here is that, when a reagent is splashed on an artifact, it calls this proc twice. + //Why? I have no clue. I only accidentally stumbled upon it during debugging! + //I left one of the debug logs commented out so others can confirm this. + var/datum/reagent/touching = args[2] + var/T = touching.type //What type of reagent is being splashed on it? for(var/datum/artifact_effect/my_effect in my_effects) - if(Touching.id in water) + if(is_path_in_list(T,water_reagents)) + //log_debug("ON REAGENT T in path = [is_path_in_list(T,water_reagents)]!") if(my_effect.trigger == TRIGGER_WATER) my_effect.ToggleActivate() - else if(Touching.id in acid) + else if(is_path_in_list(T,acid_reagents)) if(my_effect.trigger == TRIGGER_ACID) my_effect.ToggleActivate() - else if(Touching.id in volatile) + else if(is_path_in_list(T,volatile_reagents)) if(my_effect.trigger == TRIGGER_VOLATILE) my_effect.ToggleActivate() - else if(Touching.id in toxic) + else if(is_path_in_list(T,toxic_reagents)) if(my_effect.trigger == TRIGGER_TOXIN) my_effect.ToggleActivate() @@ -424,3 +462,12 @@ //NITROGEN GAS ACTIVATION if(my_effect.trigger == TRIGGER_NITRO && (trigger_nitro ^ my_effect.activated)) my_effect.ToggleActivate() + +#undef HYDROGEN_PATH +#undef WATER_PATH +#undef ACID_PATH +#undef DIETHYLAMINE_PATH +#undef PHORON_PATH +#undef HYDROPHORON_PATH +#undef THERMITE_PATH +#undef TOXIN_PATH diff --git a/code/modules/xenoarcheaology/effects/animate_anomaly.dm b/code/modules/xenoarcheaology/effects/animate_anomaly.dm index 52ab0cf495..49bb4613da 100644 --- a/code/modules/xenoarcheaology/effects/animate_anomaly.dm +++ b/code/modules/xenoarcheaology/effects/animate_anomaly.dm @@ -1,7 +1,7 @@ - +/// Modified to work with the Artifact Harvester /datum/artifact_effect/animate_anomaly - name = "animate anomaly" - effect_type = EFFECT_PSIONIC + name = "Animation" + effect_type = EFFECT_ANIMATE var/mob/living/target = null effect_state = "pulsing" @@ -15,8 +15,12 @@ ..() effectrange = max(3, effectrange) -/datum/artifact_effect/animate_anomaly/proc/find_target() +/datum/artifact_effect/animate_anomaly/proc/find_target(var/obj/item/anodevice/utilizer) var/atom/masterholder = get_master_holder() + if(utilizer) //We are in an artifact utilizer! Just run from whoever touched us last! + masterholder = utilizer + target = utilizer.last_user_touched + return if(!target || target.z != masterholder.z || get_dist(target, masterholder) > effectrange) var/mob/living/ClosestMob = null @@ -36,14 +40,42 @@ var/atom/holder = get_master_holder() var/obj/O = holder var/turf/T = get_step_away(O, user) - - if(target && istype(T) && istype(O.loc, /turf)) + if(!user) //Sanity. + return + /// This controls the NORMAL functionality! + if(target && istype(T) && isturf(O.loc)) O.Move(T) O.visible_message(span_alien("\The [holder] lurches away from [user]")) + /// This does the 'we are in an artifact utilizer' functionality + if(istype(holder, /obj/item/anobattery)) + var/obj/item/anodevice/utilizer = O.loc + user = utilizer.last_user_touched + T = get_step_away(utilizer, user) + if(istype(utilizer.loc, /turf)) + utilizer.Move(T) + utilizer.visible_message(span_alien("\The [holder] lurches away from [user]")) + else if(istype(utilizer.loc, /mob)) //It's in your hands and running away! + user.drop_from_inventory(utilizer, user.loc) + utilizer.visible_message(span_alien("\The [holder] squirms out of [user]'s hand!")) + T = get_step_away(utilizer, user) + utilizer.Move(T) + /datum/artifact_effect/animate_anomaly/DoEffectAura() - var/obj/O = get_master_holder() - find_target() + var/atom/holder = get_master_holder() + var/obj/O = holder + var/mob/user + if(istype(holder, /obj/item/anobattery)) + var/obj/item/anodevice/utilizer = O.loc + O = O.loc //Yes, this seems weird, but it's needed for below. + user = utilizer.last_user_touched + if(istype(utilizer.loc, /mob)) //It's in your hands and running away! + user = utilizer.loc + user.drop_from_inventory(utilizer, user.loc) + utilizer.visible_message(span_alien("\The [utilizer] squirms out of [user]'s hand!")) + find_target(utilizer) + else + find_target() if(!target || !istype(O)) return @@ -55,10 +87,12 @@ O.dir = get_dir(O, target) - if(istype(O.loc, /turf)) + if(isturf(O.loc)) if(get_dist(O.loc, target.loc) > 1) O.Move(get_step_to(O, target)) O.visible_message(span_alien("\The [O] lurches toward [target]")) + + /datum/artifact_effect/animate_anomaly/DoEffectPulse() DoEffectAura() diff --git a/code/modules/xenoarcheaology/effects/atmospheric.dm b/code/modules/xenoarcheaology/effects/atmospheric.dm new file mode 100644 index 0000000000..3ae06d13c7 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/atmospheric.dm @@ -0,0 +1,27 @@ +/// Verified to work with the Artifact Harvester +/datum/artifact_effect/gas + name = "Gas creation" + var/GAS_TYPE = GAS_O2 //O2 by default. Changed in /New(). Do NOT MODIFY THIS TO SOMETHING + effect_type = EFFECT_GAS + + effect_color = "#a5a5a5" + + +/datum/artifact_effect/gas/New() + ..() + effect = pick(EFFECT_TOUCH, EFFECT_AURA) + GAS_TYPE = pick(GAS_CO2, GAS_N2, GAS_N2O, GAS_O2, GAS_PHORON, GAS_VOLATILE_FUEL) //the only way you will EVER see volatile fuel. + +/datum/artifact_effect/gas/DoEffectTouch(var/mob/user) + var/atom/holder = get_master_holder() + if(holder) + var/turf/holder_loc = holder.loc + if(isturf(holder_loc)) + holder_loc.assume_gas(GAS_TYPE, rand(2, 15)) //You can spam touch this, so it's lesser. + +/datum/artifact_effect/gas/DoEffectAura() + var/atom/holder = get_master_holder() + if(holder) + var/turf/holder_loc = holder.loc + if(isturf(holder_loc)) + holder_loc.assume_gas(GAS_TYPE, rand(25, 50)) diff --git a/code/modules/xenoarcheaology/effects/badfeeling.dm b/code/modules/xenoarcheaology/effects/badfeeling.dm deleted file mode 100644 index df6383137c..0000000000 --- a/code/modules/xenoarcheaology/effects/badfeeling.dm +++ /dev/null @@ -1,74 +0,0 @@ -/datum/artifact_effect/badfeeling - name = "badfeeling" - effect_type = EFFECT_PSIONIC - var/list/messages = list("You feel worried.", - "Something doesn't feel right.", - "You get a strange feeling in your gut.", - "Your instincts are trying to warn you about something.", - "Someone just walked over your grave.", - "There's a strange feeling in the air.", - "There's a strange smell in the air.", - "The tips of your fingers feel tingly.", - "You feel witchy.", - "You have a terrible sense of foreboding.", - "You've got a bad feeling about this.", - "Your scalp prickles.", - "The light seems to flicker.", - "The shadows seem to lengthen.", - "The walls are getting closer.", - "Something is wrong") - - var/list/drastic_messages = list("You've got to get out of here!", - "Someone's trying to kill you!", - "There's something out there!", - "What's happening to you?", - "OH GOD!", - "HELP ME!") - - effect_state = "summoning" - effect_color = "#643232" - -/datum/artifact_effect/badfeeling/DoEffectTouch(var/mob/user) - if(user) - if (ishuman(user)) - var/mob/living/carbon/human/H = user - if(prob(50)) - if(prob(75)) - to_chat(H, span_red(span_bold("[pick(drastic_messages)]") + "")) - else - to_chat(H, span_red("[pick(messages)]")) - - if(prob(50)) - H.dizziness += rand(3,5) - -/datum/artifact_effect/badfeeling/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/carbon/human/H in range(src.effectrange,T)) - if(prob(5)) - if(prob(75)) - to_chat(H, span_red("[pick(messages)]")) - else - to_chat(H, span_red("[pick(drastic_messages)]")) - - if(prob(10)) - H.dizziness += rand(3,5) - return 1 - -/datum/artifact_effect/badfeeling/DoEffectPulse() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/carbon/human/H in range(src.effectrange,T)) - if(prob(50)) - if(prob(95)) - to_chat(H, span_red("[pick(drastic_messages)]")) - else - to_chat(H, span_red("[pick(messages)]")) - - if(prob(50)) - H.dizziness += rand(3,5) - else if(prob(25)) - H.dizziness += rand(5,15) - return 1 diff --git a/code/modules/xenoarcheaology/effects/berserk.dm b/code/modules/xenoarcheaology/effects/berserk.dm index 14015b13ba..23ba3e415e 100644 --- a/code/modules/xenoarcheaology/effects/berserk.dm +++ b/code/modules/xenoarcheaology/effects/berserk.dm @@ -1,12 +1,13 @@ +/// Verified to work with the Artifact Harvester /datum/artifact_effect/berserk - name = "berserk" - effect_type = EFFECT_PSIONIC + name = "Berserk" + effect_type = EFFECT_BERSERK effect_state = "summoning" effect_color = "#5f0000" /datum/artifact_effect/berserk/proc/apply_berserk(var/mob/living/L) - if(!istype(L)) + if(!isliving(L)) return FALSE if(!L.is_sentient()) diff --git a/code/modules/xenoarcheaology/effects/cannibal.dm b/code/modules/xenoarcheaology/effects/cannibal.dm deleted file mode 100644 index fb2a33380f..0000000000 --- a/code/modules/xenoarcheaology/effects/cannibal.dm +++ /dev/null @@ -1,80 +0,0 @@ -/datum/artifact_effect/cannibalfeeling - name = "cannibalfeeling" - effect_type = EFFECT_PSIONIC - var/list/messages = list("You feel peckish.", - "Something doesn't feel right.", - "You get a strange feeling in your gut.", - "You feel particularly hungry.", - "You taste blood.", - "There's a strange feeling in the air.", - "There's a strange smell in the air.", - "The tips of your fingers feel tingly.", - "You feel twitchy.", - "You feel empty.", - "You've got a good feeling about this.", - "Your tongue prickles.", - "Are they clean?", - "You feel weak.", - "The ground is getting closer.", - "Something is missing.") - - var/list/drastic_messages = list("They look delicious.", - "They'll take what's yours!", - "They're full of meat.", - "What's happening to you?", - "Butcher them!", - "Feast!") - - effect_state = "summoning" - effect_color = "#c50303" - -/datum/artifact_effect/cannibalfeeling/DoEffectTouch(var/mob/user) - if(user) - if (ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.is_sentient()) - if(prob(50)) - if(prob(75)) - to_chat(H, span_red(span_bold("[pick(drastic_messages)]") + "")) - else - to_chat(H, span_red("[pick(messages)]")) - - if(prob(50)) - H.dizziness += rand(3,5) - H.nutrition = H.nutrition / 1.5 - -/datum/artifact_effect/cannibalfeeling/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/carbon/human/H in range(src.effectrange,T)) - if(H.is_sentient()) - if(prob(5)) - if(prob(75)) - to_chat(H, span_red("[pick(messages)]")) - else - to_chat(H, span_red("[pick(drastic_messages)]")) - - if(prob(10)) - H.dizziness += rand(3,5) - H.nutrition = H.nutrition / 2 - return 1 - -/datum/artifact_effect/cannibalfeeling/DoEffectPulse() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/carbon/human/H in range(src.effectrange,T)) - if(H.is_sentient()) - if(prob(50)) - if(prob(95)) - to_chat(H, span_red("[pick(drastic_messages)]")) - else - to_chat(H, span_red("[pick(messages)]")) - - if(prob(50)) - H.dizziness += rand(3,5) - else if(prob(25)) - H.dizziness += rand(5,15) - H.nutrition = H.nutrition / 4 - return 1 diff --git a/code/modules/xenoarcheaology/effects/cell.dm b/code/modules/xenoarcheaology/effects/cell.dm new file mode 100644 index 0000000000..29ca4c88a9 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/cell.dm @@ -0,0 +1,69 @@ +/// Verified to work with the Artifact Harvester +#define CELL_DRAIN 1 +#define CELL_CHARGE 2 + +/datum/artifact_effect/cell + name = "Cell Power Effect" + effect_type = EFFECT_CELL + effect_color = "#ffee06" + var/last_message + var/charge_type = CELL_CHARGE + +/datum/artifact_effect/cell/New() + ..() + charge_type = pick(CELL_DRAIN, CELL_CHARGE) + + +/datum/artifact_effect/cell/proc/effect_cells(var/amount = 25, var/effect) + var/atom/holder = get_master_holder() + if(!holder) + return + var/turf/turf = get_turf(holder) + if(!turf) + return + + var/messaged_robots + for(var/atom/movable/AM in range(effectrange, turf)) + if(isliving(AM)) + var/mob/living/L = AM + var/obj/item/cell/C = L.get_cell() + + if(C) + if(issilicon(L) && ((last_message + (1 MINUTE)) < world.time)) + messaged_robots = TRUE + switch(effect) + if(CELL_CHARGE) + to_chat(L, span_notice("SYSTEM ALERT: Energy boost detected!")) + C.charge = min(C.maxcharge, C.charge + amount) + else + to_chat(L, span_warning("SYSTEM ALERT: Energy drain detected!")) + C.charge = min(C.maxcharge, C.charge - amount) + continue + + var/obj/item/cell/C = AM.get_cell() + if(C) + C.charge = min(C.maxcharge, C.charge + amount) + + if(messaged_robots) + last_message = world.time + +/datum/artifact_effect/cell/DoEffectTouch(mob/living/user) + if(!user) + return + if(type == CELL_DRAIN) + effect_cells(100, CELL_DRAIN) + else + effect_cells(100, CELL_CHARGE) +/datum/artifact_effect/cell/DoEffectAura() + if(charge_type == CELL_DRAIN) + effect_cells(25, CELL_DRAIN) + else + effect_cells(25, CELL_CHARGE) + +/datum/artifact_effect/cell/DoEffectPulse() + if(charge_type == CELL_DRAIN) + effect_cells(50, CELL_DRAIN) + else + effect_cells(50, CELL_CHARGE) +#undef CELL_DRAIN +#undef CELL_CHARGE diff --git a/code/modules/xenoarcheaology/effects/cellcharge.dm b/code/modules/xenoarcheaology/effects/cellcharge.dm deleted file mode 100644 index 1590abeb3f..0000000000 --- a/code/modules/xenoarcheaology/effects/cellcharge.dm +++ /dev/null @@ -1,44 +0,0 @@ -/datum/artifact_effect/cellcharge - name = "cell charge" - effect_type = EFFECT_ELECTRO - effect_color = "#ffee06" - var/last_message - -/datum/artifact_effect/cellcharge/proc/charge_cells(var/amount = 25) - var/atom/holder = get_master_holder() - if(!holder) - return - var/turf/turf = get_turf(holder) - if(!turf) - return - - var/messaged_robots - for(var/atom/movable/AM in range(effectrange, turf)) - if(isliving(AM)) - var/mob/living/L = AM - var/obj/item/cell/C = L.get_cell() - - if(C) - if(issilicon(L) && ((last_message + (1 MINUTE)) < world.time)) - messaged_robots = TRUE - to_chat(L, span_notice("SYSTEM ALERT: Energy boost detected!")) - C.charge = min(C.maxcharge, C.charge + amount) - continue - - var/obj/item/cell/C = AM.get_cell() - if(C) - C.charge = min(C.maxcharge, C.charge + amount) - - if(messaged_robots) - last_message = world.time - -/datum/artifact_effect/cellcharge/DoEffectTouch(mob/living/user) - if(!user) - return - charge_cells(100) - -/datum/artifact_effect/cellcharge/DoEffectAura() - charge_cells() - -/datum/artifact_effect/cellcharge/DoEffectPulse() - charge_cells(50) diff --git a/code/modules/xenoarcheaology/effects/celldrain.dm b/code/modules/xenoarcheaology/effects/celldrain.dm deleted file mode 100644 index 4831fb5797..0000000000 --- a/code/modules/xenoarcheaology/effects/celldrain.dm +++ /dev/null @@ -1,44 +0,0 @@ -//todo -/datum/artifact_effect/celldrain - name = "cell drain" - effect_type = EFFECT_ELECTRO - var/last_message - -/datum/artifact_effect/celldrain/proc/drain_cells(var/amount = 25) - var/atom/holder = get_master_holder() - if (!holder) - return - var/turf/turf = get_turf(holder) - if (!turf) - return - - var/messaged_robots - for(var/atom/movable/AM in range(effectrange, turf)) - if(isliving(AM)) - var/mob/living/L = AM - var/obj/item/cell/C = L.get_cell() - - if(C) - if(issilicon(L) && ((last_message + (1 MINUTE)) < world.time)) - messaged_robots = TRUE - to_chat(L, span_warning("SYSTEM ALERT: Energy drain detected!")) - C.charge = min(C.maxcharge, C.charge - amount) - continue - - var/obj/item/cell/C = AM.get_cell() - if(C) - C.charge = min(C.maxcharge, C.charge - amount) - - if(messaged_robots) - last_message = world.time - -/datum/artifact_effect/celldrain/DoEffectTouch(mob/living/user) - if(!user) - return - drain_cells(100) - -/datum/artifact_effect/celldrain/DoEffectAura() - drain_cells() - -/datum/artifact_effect/celldrain/DoEffectPulse() - drain_cells(50) diff --git a/code/modules/xenoarcheaology/effects/cold.dm b/code/modules/xenoarcheaology/effects/cold.dm deleted file mode 100644 index 1b922f9132..0000000000 --- a/code/modules/xenoarcheaology/effects/cold.dm +++ /dev/null @@ -1,27 +0,0 @@ -//inverse of /datum/artifact_effect/heat, the two effects split up for neatness' sake -/datum/artifact_effect/cold - name = "cold" - var/target_temp - - effect_color = "#b3f6ff" - -/datum/artifact_effect/cold/New() - ..() - target_temp = rand(0, 250) - effect = pick(EFFECT_TOUCH, EFFECT_AURA) - effect_type = pick(EFFECT_ORGANIC, EFFECT_BLUESPACE, EFFECT_SYNTH) - -/datum/artifact_effect/cold/DoEffectTouch(var/mob/user) - var/atom/holder = get_master_holder() - if(holder) - to_chat(user, span_blue("A chill passes up your spine!")) - var/datum/gas_mixture/env = holder.loc.return_air() - if(env) - env.temperature = max(env.temperature - rand(5,50), 0) - -/datum/artifact_effect/cold/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/datum/gas_mixture/env = holder.loc.return_air() - if(env && env.temperature > target_temp) - env.temperature -= pick(0, 0, 1) diff --git a/code/modules/xenoarcheaology/effects/electric_field.dm b/code/modules/xenoarcheaology/effects/electric_field.dm index 706daf4664..b1173a8126 100644 --- a/code/modules/xenoarcheaology/effects/electric_field.dm +++ b/code/modules/xenoarcheaology/effects/electric_field.dm @@ -1,15 +1,21 @@ - +/// Modified to work with the Artifact Harvester /datum/artifact_effect/electric_field - name = "electric field" - effect_type = EFFECT_ENERGY + name = "Electric Field" + effect_type = EFFECT_ELECTIC_FIELD effect_color = "#ffff00" /datum/artifact_effect/electric_field/DoEffectTouch(var/mob/user) var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + var/obj/item/anobattery/battery = holder + var/obj/item/anodevice/utilizer = holder.loc + battery.stored_charge = 0 //You only get ONE use of this. This is WAY too strong. + holder = utilizer + user = utilizer.last_user_touched var/list/nearby_mobs = list() for(var/mob/living/L in oview(effectrange, get_turf(holder))) - if(L == user) // You're "grounded" when you contact the artifact. + if(user && L == user) // You're "grounded" when you contact the artifact... continue if(!L.stat) nearby_mobs |= L @@ -26,13 +32,24 @@ var/mob/living/carbon/human/H = L var/obj/item/organ/external/affected = H.get_organ(check_zone(BP_TORSO)) H.electrocute_act(rand(25, 40), holder, H.get_siemens_coefficient_organ(affected), affected) + lightning_strike(H.loc, TRUE) else L.electrocute_act(rand(25, 40), holder, 0.75, BP_TORSO) + lightning_strike(L.loc, TRUE) /datum/artifact_effect/electric_field/DoEffectAura() var/atom/holder = get_master_holder() + var/mob/living/user + if(istype(holder, /obj/item/anobattery)) + var/obj/item/anobattery/battery = holder + var/obj/item/anodevice/utilizer = holder.loc + battery.stored_charge = max(0, battery.stored_charge-100) //This one isn't TOO terrible. It doesn't stun, so lets just have it do extra drain. + holder = utilizer + user = utilizer.last_user_touched var/list/nearby_mobs = list() for(var/mob/living/L in oview(effectrange, get_turf(holder))) + if(L == user) // You're "grounded" when you contact the artifact... + continue if(!L.stat) nearby_mobs |= L @@ -48,13 +65,24 @@ var/mob/living/carbon/human/H = L var/obj/item/organ/external/affected = H.get_organ(check_zone(BP_TORSO)) H.electrocute_act(rand(1, 10), holder, H.get_siemens_coefficient_organ(affected), affected) + lightning_strike(H.loc, TRUE) else L.electrocute_act(rand(1, 10), holder, 0.75, BP_TORSO) + lightning_strike(L.loc, TRUE) /datum/artifact_effect/electric_field/DoEffectPulse() var/atom/holder = get_master_holder() + var/mob/living/user + if(istype(holder, /obj/item/anobattery)) + var/obj/item/anodevice/utilizer = holder.loc + var/obj/item/anobattery/battery = holder + holder = utilizer + user = utilizer.last_user_touched + battery.stored_charge = 0 var/list/nearby_mobs = list() for(var/mob/living/L in oview(effectrange, get_turf(holder))) + if(user && L == user) // You're "grounded" when you contact the artifact... + continue if(!L.stat) nearby_mobs |= L @@ -70,5 +98,7 @@ var/mob/living/carbon/human/H = L var/obj/item/organ/external/affected = H.get_organ(check_zone(BP_TORSO)) H.electrocute_act(rand(10, 30), holder, H.get_siemens_coefficient_organ(affected), affected) + lightning_strike(H.loc, TRUE) else L.electrocute_act(rand(10, 30), holder, 0.75, BP_TORSO) + lightning_strike(L.loc, TRUE) diff --git a/code/modules/xenoarcheaology/effects/emp.dm b/code/modules/xenoarcheaology/effects/emp.dm index 8b9d969a3e..b94ba63cfa 100644 --- a/code/modules/xenoarcheaology/effects/emp.dm +++ b/code/modules/xenoarcheaology/effects/emp.dm @@ -1,6 +1,7 @@ +/// Verified to work with the Artifact Harvester /datum/artifact_effect/emp - name = "emp" - effect_type = EFFECT_ELECTRO + name = "Electromagnetic Pulse" + effect_type = EFFECT_EMP effect_state = "empdisable" @@ -13,4 +14,7 @@ if(holder) var/turf/T = get_turf(holder) empulse(T, effectrange/4, effectrange/3, effectrange/2, effectrange) + if(istype(holder, /obj/item/anobattery)) + var/obj/item/anobattery/battery = holder + battery.stored_charge = max(0, battery.stored_charge-250) //You only get TWO uses of this. This is VERY strong. return 1 diff --git a/code/modules/xenoarcheaology/effects/feelings.dm b/code/modules/xenoarcheaology/effects/feelings.dm new file mode 100644 index 0000000000..86a7fdd12b --- /dev/null +++ b/code/modules/xenoarcheaology/effects/feelings.dm @@ -0,0 +1,147 @@ +/// Verified to work with the Artifact Harvester +#define GOOD_FEELING 1 +#define BAD_FEELING 2 +#define CANNIBAL_FEELING 3 +/datum/artifact_effect/feelings + name = "Feelings" + effect_type = EFFECT_FEELINGS + var/feeling_type = 1 //If we're good, bad, or cannibalistic feelings. Defaults to good. Changed in init. + var/list/messages = list() + + var/list/drastic_messages = list() + + effect_state = "summoning" + effect_color = "#69008f" + +/datum/artifact_effect/feelings/New() + ..() + feeling_type = pick(GOOD_FEELING, BAD_FEELING, CANNIBAL_FEELING) + effect = pick(EFFECT_TOUCH, EFFECT_AURA, EFFECT_PULSE) + switch(feeling_type) + if(GOOD_FEELING) + messages = list("You feel good.", + "Everything seems to be going alright", + "You've got a good feeling about this", + "Your instincts tell you everything is going to be getting better.", + "There's a good feeling in the air.", + "Something smells... good.", + "The tips of your fingers feel tingly.", + "You've got a good feeling about this.", + "You feel happy.", + "You fight the urge to smile.", + "Your scalp prickles.", + "All the colours seem a bit more vibrant.", + "Everything seems a little lighter.", + "The troubles of the world seem to fade away.") + + drastic_messages = list("You want to hug everyone you meet!", + "Everything is going so well!", + "You feel euphoric.", + "You feel giddy.", + "You're so happy suddenly, you almost want to dance and sing.", + "You feel like the world is out to help you.") + if(BAD_FEELING) + messages = list("You feel worried.", + "Something doesn't feel right.", + "You get a strange feeling in your gut.", + "Your instincts are trying to warn you about something.", + "Someone just walked over your grave.", + "There's a strange feeling in the air.", + "There's a strange smell in the air.", + "The tips of your fingers feel tingly.", + "You feel witchy.", + "You have a terrible sense of foreboding.", + "You've got a bad feeling about this.", + "Your scalp prickles.", + "The light seems to flicker.", + "The shadows seem to lengthen.", + "The walls are getting closer.", + "Something is wrong") + + drastic_messages = list("You've got to get out of here!", + "Someone's trying to kill you!", + "There's something out there!", + "What's happening to you?", + "OH GOD!", + "HELP ME!") + else + messages = list("You feel peckish.", + "Something doesn't feel right.", + "You get a strange feeling in your gut.", + "You feel particularly hungry.", + "You taste blood.", + "There's a strange feeling in the air.", + "There's a strange smell in the air.", + "The tips of your fingers feel tingly.", + "You feel twitchy.", + "You feel empty.", + "You've got a good feeling about this.", + "Your tongue prickles.", + "Are they clean?", + "You feel weak.", + "The ground is getting closer.", + "Something is missing.") + + drastic_messages = list("They look delicious.", + "They'll take what's yours!", + "They're full of meat.", + "What's happening to you?", + "Butcher them!", + "Feast!") + + + +/datum/artifact_effect/feelings/DoEffectTouch(var/mob/user) + if(user) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(prob(50)) + if(prob(75)) + to_chat(H, span_red(span_bold("[pick(drastic_messages)]") + "")) + else + to_chat(H, span_red("[pick(messages)]")) + + if(prob(50)) + H.dizziness += rand(3,5) + if(feeling_type == CANNIBAL_FEELING) + H.nutrition = H.nutrition / 1.5 + +/datum/artifact_effect/feelings/DoEffectAura() + var/atom/holder = get_master_holder() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) + if(prob(5)) + if(prob(75)) + to_chat(H, span_red("[pick(messages)]")) + else + to_chat(H, span_red(" " + span_bold("[pick(drastic_messages)]") + " ")) + + if(prob(10)) + H.dizziness += rand(3,5) + if(feeling_type == CANNIBAL_FEELING) + H.nutrition = H.nutrition / 2 + return 1 + +/datum/artifact_effect/feelings/DoEffectPulse() + var/atom/holder = get_master_holder() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) + if(prob(50)) + if(prob(95)) + to_chat(H, span_red(" " + span_bold("[pick(drastic_messages)]") + " ")) + else + to_chat(H, span_red("[pick(messages)]")) + + if(prob(50)) + H.dizziness += rand(3,5) + else if(prob(25)) + H.dizziness += rand(5,15) + if(feeling_type == CANNIBAL_FEELING) + H.nutrition = H.nutrition / 4 + return 1 + +#undef GOOD_FEELING +#undef BAD_FEELING +#undef CANNIBAL_FEELING diff --git a/code/modules/xenoarcheaology/effects/feysight.dm b/code/modules/xenoarcheaology/effects/feysight.dm index f966ac7f70..a24f99f52c 100644 --- a/code/modules/xenoarcheaology/effects/feysight.dm +++ b/code/modules/xenoarcheaology/effects/feysight.dm @@ -1,12 +1,13 @@ +/// Verified to work with the Artifact Harvester /datum/artifact_effect/feysight - name = "feysight" - effect_type = EFFECT_PSIONIC + name = "Fey Sight" + effect_type = EFFECT_FEYSIGHT effect_state = "pulsing" effect_color = "#00c763" /datum/artifact_effect/feysight/proc/apply_modifier(var/mob/living/L) - if(!istype(L)) + if(!isliving(L)) return FALSE if(!L.is_sentient()) diff --git a/code/modules/xenoarcheaology/effects/forcefield.dm b/code/modules/xenoarcheaology/effects/forcefield.dm index 661563ccc7..7a27c34da9 100644 --- a/code/modules/xenoarcheaology/effects/forcefield.dm +++ b/code/modules/xenoarcheaology/effects/forcefield.dm @@ -1,7 +1,8 @@ +/// Verified to work with the Artifact Harvester /datum/artifact_effect/forcefield - name = "force field" + name = "Forcefield" var/list/created_field = list() - effect_type = EFFECT_PARTICLE + effect_type = EFFECT_FORCEFIELD effect_state = "shield-old" effect_color = "#00b7ff" diff --git a/code/modules/xenoarcheaology/effects/gaia.dm b/code/modules/xenoarcheaology/effects/gaia.dm index 75d184016d..e8c084c70c 100644 --- a/code/modules/xenoarcheaology/effects/gaia.dm +++ b/code/modules/xenoarcheaology/effects/gaia.dm @@ -1,7 +1,7 @@ - +/// Verified to work with the Artifact Harvester /datum/artifact_effect/gaia - name = "gaia" - effect_type = EFFECT_ORGANIC + name = "Plant Rejuvenation" + effect_type = EFFECT_GAIA var/list/my_glitterflies = list() diff --git a/code/modules/xenoarcheaology/effects/gasco2.dm b/code/modules/xenoarcheaology/effects/gasco2.dm deleted file mode 100644 index a99ce0af03..0000000000 --- a/code/modules/xenoarcheaology/effects/gasco2.dm +++ /dev/null @@ -1,23 +0,0 @@ -/datum/artifact_effect/gasco2 - name = "CO2 creation" - - effect_color = "#a5a5a5" - -/datum/artifact_effect/gasco2/New() - ..() - effect = pick(EFFECT_TOUCH, EFFECT_AURA) - effect_type = pick(EFFECT_BLUESPACE, EFFECT_SYNTH) - -/datum/artifact_effect/gasco2/DoEffectTouch(var/mob/user) - var/atom/holder = get_master_holder() - if(holder) - var/turf/holder_loc = holder.loc - if(istype(holder_loc)) - holder_loc.assume_gas(GAS_CO2, rand(2, 15)) - -/datum/artifact_effect/gasco2/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/turf/holder_loc = holder.loc - if(istype(holder_loc)) - holder_loc.assume_gas(GAS_CO2, pick(0, 0, 0.1, rand())) diff --git a/code/modules/xenoarcheaology/effects/gasnitro.dm b/code/modules/xenoarcheaology/effects/gasnitro.dm deleted file mode 100644 index 66fd4452b6..0000000000 --- a/code/modules/xenoarcheaology/effects/gasnitro.dm +++ /dev/null @@ -1,23 +0,0 @@ -/datum/artifact_effect/gasnitro - name = "N2 creation" - - effect_color = "#c2d3d8" - -/datum/artifact_effect/gasnitro/New() - ..() - effect = pick(EFFECT_TOUCH, EFFECT_AURA) - effect_type = pick(EFFECT_BLUESPACE, EFFECT_SYNTH) - -/datum/artifact_effect/gasnitro/DoEffectTouch(var/mob/user) - var/atom/holder = get_master_holder() - if(holder) - var/turf/holder_loc = holder.loc - if(istype(holder_loc)) - holder_loc.assume_gas(GAS_N2, rand(2, 15)) - -/datum/artifact_effect/gasnitro/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/turf/holder_loc = holder.loc - if(istype(holder_loc)) - holder_loc.assume_gas(GAS_N2, pick(0, 0, 0.1, rand())) diff --git a/code/modules/xenoarcheaology/effects/gasoxy.dm b/code/modules/xenoarcheaology/effects/gasoxy.dm deleted file mode 100644 index f18447dfe1..0000000000 --- a/code/modules/xenoarcheaology/effects/gasoxy.dm +++ /dev/null @@ -1,21 +0,0 @@ -/datum/artifact_effect/gasoxy - name = "O2 creation" - -/datum/artifact_effect/gasoxy/New() - ..() - effect = pick(EFFECT_TOUCH, EFFECT_AURA) - effect_type = pick(EFFECT_BLUESPACE, EFFECT_SYNTH) - -/datum/artifact_effect/gasoxy/DoEffectTouch(var/mob/user) - var/atom/holder = get_master_holder() - if(holder) - var/turf/holder_loc = holder.loc - if(istype(holder_loc)) - holder_loc.assume_gas(GAS_O2, rand(2, 15)) - -/datum/artifact_effect/gasoxy/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/turf/holder_loc = holder.loc - if(istype(holder_loc)) - holder_loc.assume_gas(GAS_O2, pick(0, 0, 0.1, rand())) diff --git a/code/modules/xenoarcheaology/effects/gasphoron.dm b/code/modules/xenoarcheaology/effects/gasphoron.dm deleted file mode 100644 index be6eca75be..0000000000 --- a/code/modules/xenoarcheaology/effects/gasphoron.dm +++ /dev/null @@ -1,23 +0,0 @@ -/datum/artifact_effect/gasphoron - name = "phoron creation" - - effect_color = "#c408ba" - -/datum/artifact_effect/gasphoron/New() - ..() - effect = pick(EFFECT_TOUCH, EFFECT_AURA) - effect_type = pick(EFFECT_BLUESPACE, EFFECT_SYNTH) - -/datum/artifact_effect/gasphoron/DoEffectTouch(var/mob/user) - var/atom/holder = get_master_holder() - if(holder) - var/turf/holder_loc = holder.loc - if(istype(holder_loc)) - holder_loc.assume_gas(GAS_PHORON, rand(2, 15)) - -/datum/artifact_effect/gasphoron/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/turf/holder_loc = holder.loc - if(istype(holder_loc)) - holder_loc.assume_gas(GAS_PHORON, pick(0, 0, 0.1, rand())) diff --git a/code/modules/xenoarcheaology/effects/gassleeping.dm b/code/modules/xenoarcheaology/effects/gassleeping.dm deleted file mode 100644 index f5a7ff7c33..0000000000 --- a/code/modules/xenoarcheaology/effects/gassleeping.dm +++ /dev/null @@ -1,21 +0,0 @@ -/datum/artifact_effect/gassleeping - name = "N2O creation" - -/datum/artifact_effect/gassleeping/New() - ..() - effect = pick(EFFECT_TOUCH, EFFECT_AURA) - effect_type = pick(EFFECT_BLUESPACE, EFFECT_SYNTH) - -/datum/artifact_effect/gassleeping/DoEffectTouch(var/mob/user) - var/atom/holder = get_master_holder() - if(holder) - var/turf/holder_loc = holder.loc - if(istype(holder_loc)) - holder_loc.assume_gas(GAS_N2O, rand(2, 15)) - -/datum/artifact_effect/gassleeping/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/turf/holder_loc = holder.loc - if(istype(holder_loc)) - holder_loc.assume_gas(GAS_N2O, pick(0, 0, 0.1, rand())) diff --git a/code/modules/xenoarcheaology/effects/goodfeeling.dm b/code/modules/xenoarcheaology/effects/goodfeeling.dm deleted file mode 100644 index ed03f4bd0b..0000000000 --- a/code/modules/xenoarcheaology/effects/goodfeeling.dm +++ /dev/null @@ -1,72 +0,0 @@ -/datum/artifact_effect/goodfeeling - name = "good feeling" - effect_type = EFFECT_PSIONIC - var/list/messages = list("You feel good.", - "Everything seems to be going alright", - "You've got a good feeling about this", - "Your instincts tell you everything is going to be getting better.", - "There's a good feeling in the air.", - "Something smells... good.", - "The tips of your fingers feel tingly.", - "You've got a good feeling about this.", - "You feel happy.", - "You fight the urge to smile.", - "Your scalp prickles.", - "All the colours seem a bit more vibrant.", - "Everything seems a little lighter.", - "The troubles of the world seem to fade away.") - - var/list/drastic_messages = list("You want to hug everyone you meet!", - "Everything is going so well!", - "You feel euphoric.", - "You feel giddy.", - "You're so happy suddenly, you almost want to dance and sing.", - "You feel like the world is out to help you.") - - effect_state = "summoning" - effect_color = "#009118" - -/datum/artifact_effect/goodfeeling/DoEffectTouch(var/mob/user) - if(user) - if (ishuman(user)) - var/mob/living/carbon/human/H = user - if(prob(50)) - if(prob(75)) - to_chat(H, span_blue(span_bold("[pick(drastic_messages)]") + "")) - else - to_chat(H, span_blue("[pick(messages)]")) - - if(prob(50)) - H.dizziness += rand(3,5) - -/datum/artifact_effect/goodfeeling/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/carbon/human/H in range(src.effectrange,T)) - if(prob(5)) - if(prob(75)) - to_chat(H, span_blue("[pick(messages)]")) - else - to_chat(H, span_blue("[pick(drastic_messages)]")) - - if(prob(5)) - H.dizziness += rand(3,5) - return 1 - -/datum/artifact_effect/goodfeeling/DoEffectPulse() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/carbon/human/H in range(src.effectrange,T)) - if(prob(50)) - if(prob(95)) - to_chat(H, span_blue("[pick(drastic_messages)]")) - else - to_chat(H, span_blue("[pick(messages)]")) - - if(prob(50)) - H.dizziness += rand(3,5) - else if(prob(25)) - H.dizziness += rand(5,15) - return 1 diff --git a/code/modules/xenoarcheaology/effects/gravitational_waves.dm b/code/modules/xenoarcheaology/effects/gravitational_waves.dm index b9541fe766..c665dfb038 100644 --- a/code/modules/xenoarcheaology/effects/gravitational_waves.dm +++ b/code/modules/xenoarcheaology/effects/gravitational_waves.dm @@ -1,6 +1,13 @@ +/// Modified to work with the Artifact Harvester +/// BEWARE THOSE WHO TOUCH THIS FILE. +/// IF YOU ARE NOT CAREFUL, YOU CAN CAUSE AN INFINITE LOOP WITH THIS IF EFFECT = 0 TRIGGER = 0 +/// AS IT WILL PULL THE USER INTO IT, TRIGGERING IT, WHICH PULLS THE USER INTO IT, TRIGGERING IT, WHICH PULLS THE... YEAH. +/// IT DOES THAT FOREVER. OR MORE APPROPRIATELY, IT DOES IT FOR 1 SECOND BEFORE THE ENTIRE SERVER CROAKS +/// THIS HAS BEEN RESOLVED BY OUR ' if(world.time >= last_wave_pull+10) last_wave_pull = world.time' LINE DOWN THERE + /datum/artifact_effect/extreme/gravity_wave - name = "gravity wave" - effect_type = EFFECT_ENERGY + name = "Gravitational Waves" + effect_type = EFFECT_GRAVIATIONAL_WAVES var/last_wave_pull = 0 var/pull_power @@ -10,7 +17,7 @@ /datum/artifact_effect/extreme/gravity_wave/New() ..() - effect_type = pick(EFFECT_ENERGY, EFFECT_BLUESPACE, EFFECT_PSIONIC) + effect_type = EFFECT_GRAVIATIONAL_WAVES switch(pick(100;1, 50;2, 25;3)) if(1) //short range effectrange = rand(2, 4) @@ -20,13 +27,20 @@ effectrange = rand(9, 14) pull_power = rand(STAGE_ONE, STAGE_FOUR) +/// BEWARE THOSE WHO TOUCH THIS FILE. /datum/artifact_effect/extreme/gravity_wave/DoEffectTouch(var/mob/user) - gravwave(user, effectrange, pull_power) + var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + var/obj/item/anodevice/utilizer = holder.loc + gravwave(utilizer, effectrange, pull_power) + else + gravwave(user, effectrange, pull_power) /datum/artifact_effect/extreme/gravity_wave/DoEffectAura() var/atom/holder = get_master_holder() var/seconds_since_last_pull = max(0, round((last_wave_pull - world.time) / 10)) - + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc if(prob(10 + seconds_since_last_pull)) holder.visible_message(span_alien("\The [holder] distorts as local gravity intensifies, and shifts toward it.")) last_wave_pull = world.time @@ -34,9 +48,13 @@ /datum/artifact_effect/extreme/gravity_wave/DoEffectPulse() var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) //In case we're being used by a harvester. + holder = holder.loc holder.visible_message(span_alien("\The [holder] distorts as local gravity intensifies, and shifts toward it.")) gravwave(get_turf(holder), effectrange, pull_power) /datum/artifact_effect/extreme/gravity_wave/proc/gravwave(var/atom/target, var/pull_range = 7, var/pull_power = STAGE_TWO) - for(var/atom/A in oview(pull_range, target)) - A.singularity_pull(target, pull_power) + if(world.time >= last_wave_pull+10) //NO INFINITE LOOPS. do not touch this line or you WILL crash the server. I am not kidding. Go ahead, remove it on a test server and see what happens. + last_wave_pull = world.time + for(var/atom/A in oview(pull_range, target)) + A.singularity_pull(target, pull_power) diff --git a/code/modules/xenoarcheaology/effects/heal.dm b/code/modules/xenoarcheaology/effects/heal.dm deleted file mode 100644 index 6b6ea9b259..0000000000 --- a/code/modules/xenoarcheaology/effects/heal.dm +++ /dev/null @@ -1,67 +0,0 @@ -/datum/artifact_effect/heal - name = XENO_CHEM_HEAL - effect_type = EFFECT_ORGANIC - effect_color = "#4649ff" - -/datum/artifact_effect/heal/DoEffectTouch(var/mob/toucher) - //todo: check over this properly - if(toucher && iscarbon(toucher)) - var/weakness = GetAnomalySusceptibility(toucher) - if(prob(weakness * 100)) - var/mob/living/carbon/C = toucher - to_chat(C, span_blue("You feel a soothing energy invigorate you.")) - - if(ishuman(toucher)) - var/mob/living/carbon/human/H = toucher - for(var/obj/item/organ/external/affecting in H.organs) - if(affecting && istype(affecting)) - affecting.heal_damage(25 * weakness, 25 * weakness) - //H:heal_organ_damage(25, 25) - H.vessel.add_reagent(REAGENT_ID_BLOOD,5) - H.adjust_nutrition(50 * weakness) - H.adjustBrainLoss(-25 * weakness) - H.radiation -= min(H.radiation, 25 * weakness) - H.bodytemperature = initial(H.bodytemperature) - spawn(1) - H.fixblood() - // - C.adjustOxyLoss(-25 * weakness) - C.adjustToxLoss(-25 * weakness) - C.adjustBruteLoss(-25 * weakness) - C.adjustFireLoss(-25 * weakness) - // - C.regenerate_icons() - return 1 - -/datum/artifact_effect/heal/DoEffectAura() - var/atom/holder = get_master_holder() - //todo: check over this properly - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/carbon/C in range(src.effectrange,T)) - var/weakness = GetAnomalySusceptibility(C) - if(prob(weakness * 100)) - if(prob(10)) - to_chat(C, span_blue("You feel a soothing energy radiating from something nearby.")) - C.adjustBruteLoss(-1 * weakness) - C.adjustFireLoss(-1 * weakness) - C.adjustToxLoss(-1 * weakness) - C.adjustOxyLoss(-1 * weakness) - C.adjustBrainLoss(-1 * weakness) - C.updatehealth() - -/datum/artifact_effect/heal/DoEffectPulse() - var/atom/holder = get_master_holder() - //todo: check over this properly - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/carbon/C in range(src.effectrange,T)) - var/weakness = GetAnomalySusceptibility(C) - if(prob(weakness * 100)) - to_chat(C, span_blue("A wave of energy invigorates you.")) - C.adjustBruteLoss(-5 * weakness) - C.adjustFireLoss(-5 * weakness) - C.adjustToxLoss(-5 * weakness) - C.adjustOxyLoss(-5 * weakness) - C.adjustBrainLoss(-5 * weakness) - C.updatehealth() diff --git a/code/modules/xenoarcheaology/effects/health.dm b/code/modules/xenoarcheaology/effects/health.dm new file mode 100644 index 0000000000..fda8387301 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/health.dm @@ -0,0 +1,113 @@ +/// Modified to work with the Artifact Harvester +#define EFFECT_HEAL 1 +#define EFFECT_HARM 2 +/datum/artifact_effect/health + name = "Health" + effect_type = EFFECT_HEALTH + effect_color = "#4649ff" + var/health_type = EFFECT_HEAL + +/datum/artifact_effect/health/New() + ..() + health_type = pick(EFFECT_HEAL, EFFECT_HARM) + if(health_type == EFFECT_HEAL) + effect_color = "#4649ff" + else + effect_color = "#6d1212" + +/datum/artifact_effect/health/DoEffectTouch(var/mob/toucher) + var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + var/obj/item/anobattery/battery = holder + battery.stored_charge = max(0, battery.stored_charge-50) //This artifact uses charge at an accelrated rate. It makes you nigh invincvible while it's up OR kills you extremely quickly while it's up. + if(toucher && iscarbon(toucher)) + var/weakness = GetAnomalySusceptibility(toucher) + if(prob(weakness * 100)) + var/mob/living/carbon/C = toucher + if(health_type == EFFECT_HEAL) + to_chat(C, span_blue("You feel a soothing energy invigorate you.")) + if(ishuman(toucher)) + var/mob/living/carbon/human/H = toucher + for(var/obj/item/organ/external/affecting in H.organs) + if(affecting && istype(affecting)) + affecting.heal_damage(25 * weakness, 25 * weakness) + H.vessel.add_reagent(REAGENT_ID_BLOOD,5) + H.adjust_nutrition(50 * weakness) + H.adjustBrainLoss(-25 * weakness) + H.radiation -= min(H.radiation, 25 * weakness) + H.bodytemperature = initial(H.bodytemperature) + H.fixblood() + C.adjustOxyLoss(-25 * weakness) + C.adjustToxLoss(-25 * weakness) + C.adjustBruteLoss(-25 * weakness) + C.adjustFireLoss(-25 * weakness) + C.regenerate_icons() + else + to_chat(C, span_danger("A painful discharge of energy strikes you!")) + C.adjustOxyLoss(rand(5,25) * weakness) + C.adjustToxLoss(rand(5,25) * weakness) + C.adjustBruteLoss(rand(5,25) * weakness) + C.adjustFireLoss(rand(5,25) * weakness) + C.adjustBrainLoss(rand(1,5) * weakness) + C.apply_effect(25 * weakness, IRRADIATE) + C.adjust_nutrition(-50 * weakness) + C.nutrition -= min(50 * weakness, C.nutrition) + C.make_dizzy(6 * weakness) + C.weakened += 6 * weakness + return 1 + +/datum/artifact_effect/health/DoEffectAura() + var/atom/holder = get_master_holder() + //This is where I would make it drain charge at an accelerated rate, but...A passive 1 heal per 2 seconds is weak and fine. + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) + var/weakness = GetAnomalySusceptibility(C) + if(prob(weakness * 100)) + if(health_type == EFFECT_HEAL) + if(prob(10)) + to_chat(C, span_blue("You feel a soothing energy radiating from something nearby.")) + C.adjustBruteLoss(-1 * weakness) + C.adjustFireLoss(-1 * weakness) + C.adjustToxLoss(-1 * weakness) + C.adjustOxyLoss(-1 * weakness) + C.adjustBrainLoss(-1 * weakness) + C.updatehealth() + else + if(prob(10)) + to_chat(C, span_danger("You feel a painful force radiating from something nearby.")) + C.adjustBruteLoss(1 * weakness) + C.adjustFireLoss(1 * weakness) + C.adjustToxLoss(1 * weakness) + C.adjustOxyLoss(1 * weakness) + C.adjustBrainLoss(0.1 * weakness) + C.updatehealth() + +/datum/artifact_effect/health/DoEffectPulse() + var/atom/holder = get_master_holder() //I'm not touching the below line because it's FUNNY that a 'todo:' has been sitting there for 12 years. + //todo: check over this properly + //Anyways, this is where you'd put accelerated drain code, but it already drains at 200 a tick, meaning you get 2-3 uses at most before having to recharge. + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) + var/weakness = GetAnomalySusceptibility(C) + if(prob(weakness * 100)) + if(health_type == EFFECT_HEAL) + to_chat(C, span_blue("A wave of energy invigorates you.")) + C.adjustBruteLoss(-25 * weakness) + C.adjustFireLoss(-25 * weakness) + C.adjustToxLoss(-25 * weakness) + C.adjustOxyLoss(-25 * weakness) + C.adjustBrainLoss(-25 * weakness) + C.updatehealth() + else + to_chat(C, span_danger("A wave of painful energy strikes you!")) + C.adjustBruteLoss(3 * weakness) + C.adjustFireLoss(3 * weakness) + C.adjustToxLoss(3 * weakness) + C.adjustOxyLoss(3 * weakness) + C.adjustBrainLoss(0.1 * weakness) + C.updatehealth() + +#undef EFFECT_HEAL +#undef EFFECT_HARM diff --git a/code/modules/xenoarcheaology/effects/heat.dm b/code/modules/xenoarcheaology/effects/heat.dm deleted file mode 100644 index 1dbab3eecf..0000000000 --- a/code/modules/xenoarcheaology/effects/heat.dm +++ /dev/null @@ -1,26 +0,0 @@ -//inverse of /datum/artifact_effect/cold, the two effects split up for neatness' sake -/datum/artifact_effect/heat - name = "heat" - var/target_temp - effect_color = "#ff6600" - -/datum/artifact_effect/heat/New() - ..() - effect = pick(EFFECT_TOUCH, EFFECT_AURA) - effect_type = pick(EFFECT_ORGANIC, EFFECT_BLUESPACE, EFFECT_SYNTH) - target_temp = rand(300, 600) - -/datum/artifact_effect/heat/DoEffectTouch(var/mob/user) - var/atom/holder = get_master_holder() - if(holder) - to_chat(user, span_red("You feel a wave of heat travel up your spine!")) - var/datum/gas_mixture/env = holder.loc.return_air() - if(env) - env.temperature += rand(5,50) - -/datum/artifact_effect/heat/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/datum/gas_mixture/env = holder.loc.return_air() - if(env && env.temperature < target_temp) - env.temperature += pick(0, 0, 1) diff --git a/code/modules/xenoarcheaology/effects/hurt.dm b/code/modules/xenoarcheaology/effects/hurt.dm deleted file mode 100644 index 52ef861231..0000000000 --- a/code/modules/xenoarcheaology/effects/hurt.dm +++ /dev/null @@ -1,53 +0,0 @@ -/datum/artifact_effect/hurt - name = "hurt" - effect_type = EFFECT_ORGANIC - - effect_color = "#6d1212" - -/datum/artifact_effect/hurt/DoEffectTouch(var/mob/toucher) - if(toucher) - var/weakness = GetAnomalySusceptibility(toucher) - if(iscarbon(toucher) && prob(weakness * 100)) - var/mob/living/carbon/C = toucher - to_chat(C, span_danger("A painful discharge of energy strikes you!")) - C.adjustOxyLoss(rand(5,25) * weakness) - C.adjustToxLoss(rand(5,25) * weakness) - C.adjustBruteLoss(rand(5,25) * weakness) - C.adjustFireLoss(rand(5,25) * weakness) - C.adjustBrainLoss(rand(1,5) * weakness) - C.apply_effect(25 * weakness, IRRADIATE) - C.adjust_nutrition(-50 * weakness) - C.nutrition -= min(50 * weakness, C.nutrition) - C.make_dizzy(6 * weakness) - C.weakened += 6 * weakness - -/datum/artifact_effect/hurt/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/carbon/C in range(src.effectrange,T)) - var/weakness = GetAnomalySusceptibility(C) - if(prob(weakness * 100)) - if(prob(10)) - to_chat(C, span_danger("You feel a painful force radiating from something nearby.")) - C.adjustBruteLoss(1 * weakness) - C.adjustFireLoss(1 * weakness) - C.adjustToxLoss(1 * weakness) - C.adjustOxyLoss(1 * weakness) - C.adjustBrainLoss(0.1 * weakness) - C.updatehealth() - -/datum/artifact_effect/hurt/DoEffectPulse() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/carbon/C in range(effectrange, T)) - var/weakness = GetAnomalySusceptibility(C) - if(prob(weakness * 100)) - to_chat(C, span_danger("A wave of painful energy strikes you!")) - C.adjustBruteLoss(3 * weakness) - C.adjustFireLoss(3 * weakness) - C.adjustToxLoss(3 * weakness) - C.adjustOxyLoss(3 * weakness) - C.adjustBrainLoss(0.1 * weakness) - C.updatehealth() diff --git a/code/modules/xenoarcheaology/effects/poltergeist.dm b/code/modules/xenoarcheaology/effects/poltergeist.dm index 7cf80bfd3d..65208c7ca1 100644 --- a/code/modules/xenoarcheaology/effects/poltergeist.dm +++ b/code/modules/xenoarcheaology/effects/poltergeist.dm @@ -1,7 +1,7 @@ - +/// Verified to work with the Artifact Harvester /datum/artifact_effect/poltergeist - name = "poltergeist" - effect_type = EFFECT_ENERGY + name = "Poltergeist" + effect_type = EFFECT_POLTERGEIST effect_state = "shield2" effect_color = "#a824c9" @@ -23,6 +23,8 @@ /datum/artifact_effect/poltergeist/DoEffectAura() var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc //We are inside of an artifact harvester. Make that the holder. var/mob/living/target = null for(var/mob/living/L in oview(get_turf(holder), effectrange)) if(L.stat || !L.mind) @@ -39,6 +41,8 @@ /datum/artifact_effect/poltergeist/DoEffectPulse() var/atom/holder = get_master_holder() var/mob/living/target = null + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc //We are inside of an artifact harvester. Make that the holder. for(var/mob/living/L in oview(get_turf(holder), effectrange)) if(L.stat || !L.mind) continue diff --git a/code/modules/xenoarcheaology/effects/power_generator.dm b/code/modules/xenoarcheaology/effects/power_generator.dm new file mode 100644 index 0000000000..781f63247a --- /dev/null +++ b/code/modules/xenoarcheaology/effects/power_generator.dm @@ -0,0 +1,97 @@ +// Unticking this from the .dme until it has some custom sounds and is modified. +// This works as is, but is EXTREMELY dangerous and I want it to only show up on LARGE artifacts, not small ones. +/datum/artifact_effect/generator + name = "Power Generation" + effect_type = EFFECT_GENERATOR + effect_color = "#fff134" + activated = 0 + var/gen_rate = 0 + var/gen_level = 0 + var/mode = 0 + var/obj/structure/cable/attached + var/list/spark_sounds = list('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks4.ogg','sound/effects/sparks5.ogg','sound/effects/sparks6.ogg') + harvestable = 0 + +/datum/artifact_effect/generator/New() + ..() + gen_level = rand(1,10) // levels from 1-10 + gen_rate = 500000 * 1.0715 ** ((gen_level-1)*10 + rand(0,10)) + trigger = TRIGGER_TOUCH + effect = EFFECT_TOUCH + activated = TRUE //We are ALWAYS on. + START_PROCESSING(SSprocessing, src) + + +/datum/artifact_effect/generator/ToggleActivate() + return //We can not be turned off. + +/datum/artifact_effect/generator/DoEffectTouch(var/mob/living/carbon/human/user) + var/obj/holder = get_master_holder() + if (..()) + return + var/obj/item/organ/external/affected = user.get_organ(check_zone(BP_L_HAND)) + user.electrocute_act(gen_level*9, src, user.get_siemens_coefficient_organ(affected), affected) //In case you touch it without insuls. + if(mode == 0) + var/turf/T = get_turf(holder) + if(isturf(T)) + attached = locate() in T + if(!attached) + to_chat(user, "No exposed cable here to attach to.") + else + holder.anchored = TRUE + mode = 2 + holder.visible_message("[holder] connects itself to the cable. Weird.") + // playsound(holder, 'x', 75, TRUE) //TODO: Get sounds here + holder.set_light(gen_level, 25, effect_color) + else + to_chat(user, "[holder] must be placed over a cable to attach to it.") + else + holder.anchored = FALSE + mode = 0 + attached = 0 + to_chat(user, "[holder] disconnects itself from the cable.") + // playsound(holder, 'X', 75, TRUE, 0, 2) //TODO: Get sounds here + holder.set_light(FALSE) + +/datum/artifact_effect/generator/process(var/obj/holder) + holder = get_master_holder() + if(attached) + var/datum/powernet/PN = attached.powernet + if(PN) + PN.newavail += gen_rate + var/turf/T = get_turf(holder) + // playsound(holder, 'X', 75, TRUE, 0, 1) //TODO: Get sounds here + if (prob(5)) + // playsound(holder, 'X', 75, TRUE) //TODO: Get sounds here + var/turf/location = holder.loc + if(isturf(location)) + var/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel/fuel_spill = new /obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(location) + fuel_spill.amount = 15 + fuel_spill.Spread() + location.hotspot_expose(1000,500,1) + holder.visible_message(span_alert("[holder] erupts in flame!")) + if (prob(3)) + // playsound(holder, 'X', 75, TRUE) //TODO: Get sounds here + holder.visible_message(span_alert("[holder] rumbles!")) + for (var/mob/M in range(min(5,gen_level),T)) + shake_camera(M, 5, 8) + M.weakened += 1 + for (var/turf/TF in range(min(5,gen_level),T)) + holder.animate_shake() + if (gen_level >= 5) + for (var/obj/structure/window/W in range(min(5,gen_level), T)) + W.health = 0 + W.shatter() + if (prob(5)) + // playsound(holder, 'X', 75, TRUE) //TODO: Get sounds here + holder.visible_message(span_alert("[holder] sparks violently!")) + for (var/mob/living/M in view(min(5,gen_level),T)) + if(ishuman(M)) + var/mob/living/carbon/human/target = M + var/obj/item/organ/external/affected = target.get_organ(check_zone(BP_TORSO)) + target.electrocute_act(gen_level*9, src, target.get_siemens_coefficient_organ(affected), affected) + else + M.electrocute_act(gen_level*9, src) + else + if(prob(5)) + playsound(holder, pick(spark_sounds), 75, 1) diff --git a/code/modules/xenoarcheaology/effects/radiate.dm b/code/modules/xenoarcheaology/effects/radiate.dm index 88a37b3e06..2080b46530 100644 --- a/code/modules/xenoarcheaology/effects/radiate.dm +++ b/code/modules/xenoarcheaology/effects/radiate.dm @@ -1,5 +1,6 @@ +/// Modified to work with the Artifact Harvester /datum/artifact_effect/radiate - name = "radiation" + name = "Radiation" var/radiation_amount effect_color = "#007006" @@ -7,7 +8,7 @@ /datum/artifact_effect/radiate/New() ..() radiation_amount = rand(1, 10) - effect_type = pick(EFFECT_PARTICLE, EFFECT_ORGANIC) + effect_type = EFFECT_RADIATE /datum/artifact_effect/radiate/DoEffectTouch(var/mob/living/user) if(user) @@ -17,12 +18,16 @@ /datum/artifact_effect/radiate/DoEffectAura() var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc if(holder) SSradiation.flat_radiate(holder, radiation_amount, src.effectrange) return 1 /datum/artifact_effect/radiate/DoEffectPulse() var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc if(holder) - SSradiation.radiate(holder, ((radiation_amount * 3) * (sqrt(src.effectrange)))) //Need to get feedback on this //VOREStation Edit - Was too crazy-strong. + SSradiation.radiate(holder, ((radiation_amount * 3) * (sqrt(src.effectrange)))) return 1 diff --git a/code/modules/xenoarcheaology/effects/resurrect.dm b/code/modules/xenoarcheaology/effects/resurrect.dm index ceea8871a1..d7d211df56 100644 --- a/code/modules/xenoarcheaology/effects/resurrect.dm +++ b/code/modules/xenoarcheaology/effects/resurrect.dm @@ -1,6 +1,7 @@ +/// Modified to work with the Artifact Harvester /datum/artifact_effect/resurrect - name = "resurrect" - effect_type = EFFECT_ORGANIC + name = "Resurrection Vitality Swap" //Lets give whoever's using this a hint of just what it does. + effect_type = EFFECT_RESURRECT var/stored_life = 0 @@ -9,6 +10,10 @@ /datum/artifact_effect/resurrect/proc/steal_life(var/mob/living/target = null) var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc + if(isliving(holder.loc)) //We are being held by someone. + holder = holder.loc if(!istype(target)) return 0 @@ -21,7 +26,20 @@ /datum/artifact_effect/resurrect/proc/give_life(var/mob/living/target = null) var/atom/holder = get_master_holder() - if(!istype(target)) + + /// ALRIGHT, LET ME EXPLAIN THIS ABOMINATION. + /// First, we got holder = get_master_holder() that gives us either the artifact (and we skip all this nonsense) + /// OR it returns anobattery. We then check to see if it is (it is) and then go 'alright, that's our holder now' + /// If it's on the ground, it stops there and creates the beams and all the cool stuff. + /// But if someone is holding us, it goes one further and sets the mob holding us as the holder + /// To allow for proper generation of beams and whatnot. + /// A lot of the xenoarch code does this because the harvester was never properly implemented in the 12ish years it's been here. + /// So while this LOOKS weird, it's efficent. + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc + if(isliving(holder.loc)) //We are being held by someone. + holder = holder.loc + if(!isliving(target)) return if(target.stat == DEAD && stored_life) @@ -65,6 +83,7 @@ H.adjustBruteLoss(-40) H.adjustFireLoss(-40) + holder.visible_message(span_alien("\The [H]'s body begins to shift and stir, loud, wet cracks emitting from within!")) sleep(10 SECONDS) if(H.client) @@ -74,36 +93,47 @@ H.timeofdeath = null holder.visible_message(span_alien("\The [H]'s eyes open in a flash of light!")) + else + holder.visible_message(span_alien("\The [H]'s body stays still...Perhaps their mind was not ready to rejoin their body.")) /datum/artifact_effect/resurrect/DoEffectTouch(var/mob/user) var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc + if(isliving(holder.loc)) //We are being held by someone. + holder = holder.loc for(var/mob/living/L in oview(effectrange, get_turf(holder))) stored_life += 4 * steal_life(L) - var/turf/T = get_turf(holder) - for(var/mob/living/L in T) + for(var/mob/living/L in oview(effectrange, get_turf(holder))) if(L.stat == DEAD) give_life(L) break /datum/artifact_effect/resurrect/DoEffectAura() var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc + if(isliving(holder.loc)) //We are being held by someone. + holder = holder.loc for(var/mob/living/L in oview(effectrange, get_turf(holder))) stored_life += steal_life(L) - var/turf/T = get_turf(holder) - for(var/mob/living/L in T) + for(var/mob/living/L in oview(effectrange, get_turf(holder))) if(L.stat == DEAD) give_life(L) break /datum/artifact_effect/resurrect/DoEffectPulse() var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc + if(isliving(holder.loc)) //We are being held by someone. + holder = holder.loc for(var/mob/living/L in oview(effectrange, get_turf(holder))) stored_life += 2 * steal_life(L) - var/turf/T = get_turf(holder) - for(var/mob/living/L in T) + for(var/mob/living/L in oview(effectrange, get_turf(holder))) if(L.stat == DEAD) give_life(L) break diff --git a/code/modules/xenoarcheaology/effects/roboheal.dm b/code/modules/xenoarcheaology/effects/roboheal.dm deleted file mode 100644 index a88bc207e6..0000000000 --- a/code/modules/xenoarcheaology/effects/roboheal.dm +++ /dev/null @@ -1,44 +0,0 @@ -/datum/artifact_effect/roboheal - name = "robotic healing" - var/last_message - - effect_color = "#3879ad" - -/datum/artifact_effect/roboheal/New() - ..() - effect_type = pick(EFFECT_ELECTRO, EFFECT_PARTICLE) - -/datum/artifact_effect/roboheal/DoEffectTouch(var/mob/user) - if(user) - if (isrobot(user)) - var/mob/living/silicon/robot/R = user - to_chat(R, span_blue("Your systems report damaged components mending by themselves!")) - R.adjustBruteLoss(rand(-10,-30)) - R.adjustFireLoss(rand(-10,-30)) - return 1 - -/datum/artifact_effect/roboheal/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) - if(world.time - last_message > 200) - to_chat(M, span_blue("SYSTEM ALERT: Beneficial energy field detected!")) - last_message = world.time - M.adjustBruteLoss(-1) - M.adjustFireLoss(-1) - M.updatehealth() - return 1 - -/datum/artifact_effect/roboheal/DoEffectPulse() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) - if(world.time - last_message > 200) - to_chat(M, span_blue("SYSTEM ALERT: Structural damage has been repaired by energy pulse!")) - last_message = world.time - M.adjustBruteLoss(-10) - M.adjustFireLoss(-10) - M.updatehealth() - return 1 diff --git a/code/modules/xenoarcheaology/effects/robohurt.dm b/code/modules/xenoarcheaology/effects/robohurt.dm deleted file mode 100644 index 67c031049c..0000000000 --- a/code/modules/xenoarcheaology/effects/robohurt.dm +++ /dev/null @@ -1,44 +0,0 @@ -/datum/artifact_effect/robohurt - name = "robotic harm" - var/last_message - - effect_color = "#5432cf" - -/datum/artifact_effect/robohurt/New() - ..() - effect_type = pick(EFFECT_ELECTRO, EFFECT_PARTICLE) - -/datum/artifact_effect/robohurt/DoEffectTouch(var/mob/user) - if(user) - if (isrobot(user)) - var/mob/living/silicon/robot/R = user - to_chat(R, span_red("Your systems report severe damage has been inflicted!")) - R.adjustBruteLoss(rand(10,50)) - R.adjustFireLoss(rand(10,50)) - return 1 - -/datum/artifact_effect/robohurt/DoEffectAura() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) - if(world.time - last_message > 200) - to_chat(M, span_red("SYSTEM ALERT: Harmful energy field detected!")) - last_message = world.time - M.adjustBruteLoss(1) - M.adjustFireLoss(1) - M.updatehealth() - return 1 - -/datum/artifact_effect/robohurt/DoEffectPulse() - var/atom/holder = get_master_holder() - if(holder) - var/turf/T = get_turf(holder) - for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) - if(world.time - last_message > 200) - to_chat(M, span_red("SYSTEM ALERT: Structural damage inflicted by energy pulse!")) - last_message = world.time - M.adjustBruteLoss(10) - M.adjustFireLoss(10) - M.updatehealth() - return 1 diff --git a/code/modules/xenoarcheaology/effects/robothealth.dm b/code/modules/xenoarcheaology/effects/robothealth.dm new file mode 100644 index 0000000000..a280cb5ffd --- /dev/null +++ b/code/modules/xenoarcheaology/effects/robothealth.dm @@ -0,0 +1,76 @@ +/// Verified to work with the Artifact Harvester +#define ROBO_HEAL 1 +#define ROBO_HARM 2 +/datum/artifact_effect/robohealth + name = "Robotic Healing" + var/last_message + effect_type = EFFECT_ROBOT_HEALTH + effect_color = "#3879ad" + var/health_type = ROBO_HEAL + +/datum/artifact_effect/robohealth/New() + ..() + health_type = pick(ROBO_HEAL, ROBO_HARM) + if(health_type == ROBO_HARM) + effect_color = "#5432cf" + else + effect_color = "#3879ad" + +/datum/artifact_effect/robohealth/DoEffectTouch(var/mob/user) + if(user) + if(isrobot(user)) + var/mob/living/silicon/robot/R = user + if(health_type == ROBO_HEAL) + to_chat(R, span_blue("Your systems report damaged components mending by themselves!")) + R.adjustBruteLoss(rand(-10,-30)) + R.adjustFireLoss(rand(-10,-30)) + else + to_chat(R, span_red("Your systems report severe damage has been inflicted!")) + R.adjustBruteLoss(rand(10,50)) + R.adjustFireLoss(rand(10,50)) + return 1 + +/datum/artifact_effect/robohealth/DoEffectAura() + var/atom/holder = get_master_holder() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) + if(health_type == ROBO_HEAL) + if(world.time - last_message > 200) + to_chat(M, span_blue("SYSTEM ALERT: Beneficial energy field detected!")) + last_message = world.time + M.adjustBruteLoss(-1) + M.adjustFireLoss(-1) + M.updatehealth() + else + if(world.time - last_message > 200) + to_chat(M, span_red("SYSTEM ALERT: Harmful energy field detected!")) + last_message = world.time + M.adjustBruteLoss(1) + M.adjustFireLoss(1) + M.updatehealth() + return 1 + +/datum/artifact_effect/robohealth/DoEffectPulse() + var/atom/holder = get_master_holder() + if(holder) + var/turf/T = get_turf(holder) + for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) + if(health_type == ROBO_HEAL) + if(world.time - last_message > 200) + to_chat(M, span_blue("SYSTEM ALERT: Structural damage has been repaired by energy pulse!")) + last_message = world.time + M.adjustBruteLoss(-10) + M.adjustFireLoss(-10) + M.updatehealth() + else + if(world.time - last_message > 200) + to_chat(M, span_red("SYSTEM ALERT: Structural damage inflicted by energy pulse!")) + last_message = world.time + M.adjustBruteLoss(10) + M.adjustFireLoss(10) + M.updatehealth() + return 1 + +#undef ROBO_HEAL +#undef ROBO_HARM diff --git a/code/modules/xenoarcheaology/effects/sleepy.dm b/code/modules/xenoarcheaology/effects/sleepy.dm index a13c1dcbb4..63978c2e3d 100644 --- a/code/modules/xenoarcheaology/effects/sleepy.dm +++ b/code/modules/xenoarcheaology/effects/sleepy.dm @@ -1,11 +1,11 @@ -//todo +/// Verified to work with the Artifact Harvester /datum/artifact_effect/sleepy - name = "sleepy" + name = "Drowsiness" effect_color = "#a36fa1" /datum/artifact_effect/sleepy/New() ..() - effect_type = pick(EFFECT_PSIONIC, EFFECT_ORGANIC) + effect_type = EFFECT_SLEEPY /datum/artifact_effect/sleepy/DoEffectTouch(var/mob/toucher) if(toucher) diff --git a/code/modules/xenoarcheaology/effects/stun.dm b/code/modules/xenoarcheaology/effects/stun.dm index 82b0ff534c..d74bfdefbf 100644 --- a/code/modules/xenoarcheaology/effects/stun.dm +++ b/code/modules/xenoarcheaology/effects/stun.dm @@ -1,10 +1,11 @@ +/// Verified to work with the Artifact Harvester /datum/artifact_effect/stun - name = "stun" + name = "Stun" effect_color = "#00eeff" /datum/artifact_effect/stun/New() ..() - effect_type = pick(EFFECT_PSIONIC, EFFECT_ORGANIC) + effect_type = EFFECT_STUN /datum/artifact_effect/stun/DoEffectTouch(var/mob/toucher) if(toucher && iscarbon(toucher)) diff --git a/code/modules/xenoarcheaology/effects/teleport.dm b/code/modules/xenoarcheaology/effects/teleport.dm index 31a0dd6e67..0092e6defd 100644 --- a/code/modules/xenoarcheaology/effects/teleport.dm +++ b/code/modules/xenoarcheaology/effects/teleport.dm @@ -1,6 +1,7 @@ +/// Modified to work with the Artifact Harvester /datum/artifact_effect/teleport - name = "teleport" - effect_type = EFFECT_BLUESPACE + name = "Teleportation" + effect_type = EFFECT_TELEPORT effect_state = "pulsing" effect_color = "#88ffdb" @@ -24,6 +25,9 @@ /datum/artifact_effect/teleport/DoEffectAura() var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + var/obj/item/anobattery/battery = holder + battery.stored_charge = max(0, battery.stored_charge-250) //Slow your roll. This takes a LOT of energy. if(holder) var/turf/T = get_turf(holder) for (var/mob/living/M in range(src.effectrange,T)) @@ -44,6 +48,9 @@ /datum/artifact_effect/teleport/DoEffectPulse() var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + var/obj/item/anobattery/battery = holder + battery.stored_charge = max(0, battery.stored_charge-500) //Slow your roll. This takes a LOT of energy. if(holder) var/turf/T = get_turf(holder) for (var/mob/living/M in range(src.effectrange, T)) diff --git a/code/modules/xenoarcheaology/effects/temperature.dm b/code/modules/xenoarcheaology/effects/temperature.dm new file mode 100644 index 0000000000..1d45848028 --- /dev/null +++ b/code/modules/xenoarcheaology/effects/temperature.dm @@ -0,0 +1,50 @@ +/// Verified to work with the Artifact Harvester +//inverse of /datum/artifact_effect/heat, the two effects split up for neatness' sake +#define COLD 1 +#define HOT 2 +/datum/artifact_effect/temperature + name = "Atmospheric Temperature Change" + var/target_temp + var/temp_change = COLD + + effect_color = "#b3f6ff" + +/datum/artifact_effect/temperature/New() + ..() + effect = pick(EFFECT_TOUCH, EFFECT_AURA) + temp_change = pick(COLD, HOT) + if(temp_change == HOT) + target_temp = rand(300, 3000) + else + target_temp = rand (0, 150) + effect_type = EFFECT_TEMPERATURE + +/datum/artifact_effect/temperature/DoEffectTouch(var/mob/user) + var/atom/holder = get_master_holder() + if(holder) + to_chat(user, span_blue("A chill passes up your spine!")) + var/datum/gas_mixture/env = holder.loc.return_air() + if(env) + var/temp_coef = 1 //The closer they are, the harder it is to cause a change. + if(temp_change == HOT && env.temperature < target_temp) + temp_coef = ((target_temp)/(env.temperature+1)) //TT = 300. ET = 250. TC = ~1 || TT = 3000. ET = 300 TT = 10. We multiply by 10 below to speed it up. + env.temperature = max(env.temperature + temp_coef*10, 0) + else if(temp_change == COLD && env.temperature > target_temp) + temp_coef = (env.temperature/(target_temp+1)) //ET = 300, TT = 25. TC = 12. Next: ET=288 TT = 25, TC = 11.52. ETC. + env.temperature = max(env.temperature - temp_coef, 0) + +/datum/artifact_effect/temperature/DoEffectAura() + var/atom/holder = get_master_holder() + if(holder) + var/datum/gas_mixture/env = holder.loc.return_air() + if(env) + var/temp_coef = 1 //The closer they are, the harder it is to cause a change. + if(temp_change == HOT && env.temperature < target_temp) + temp_coef = ((target_temp)/(env.temperature+1)) //TT = 300. ET = 250. TC = ~1 || TT = 3000. ET = 300 TT = 10. We multiply by 10 below to speed it up. + env.temperature = max(env.temperature + temp_coef*10, 0) + else if(temp_change == COLD && env.temperature > target_temp) + temp_coef = (env.temperature/(target_temp+1)) //ET = 300, TT = 25. TC = 12. Next: ET=288 TT = 25, TC = 11.52. ETC. + env.temperature = max(env.temperature - temp_coef, 0) + +#undef COLD +#undef HOT diff --git a/code/modules/xenoarcheaology/effects/vampire.dm b/code/modules/xenoarcheaology/effects/vampire.dm index f46aec3388..ea219510ed 100644 --- a/code/modules/xenoarcheaology/effects/vampire.dm +++ b/code/modules/xenoarcheaology/effects/vampire.dm @@ -1,21 +1,28 @@ - +/// Modified to work with the Artifact Harvester /datum/artifact_effect/vampire - name = "vampire" - effect_type = EFFECT_ORGANIC + name = "Cultic Vampirism" + effect_type = EFFECT_VAMPIRE var/last_bloodcall = 0 var/bloodcall_interval = 50 var/last_eat = 0 var/eat_interval = 100 var/charges = 0 var/list/nearby_mobs = list() + var/harvested = FALSE effect_state = "gravisphere" effect_color = "#ff0000" /datum/artifact_effect/vampire/proc/bloodcall(var/mob/living/carbon/human/M) var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc + eat_interval = 10 //If we're in an artifact just CRUNCH through those blood piles! + harvested = 1 //We're in a harvester. We need special handling for this. + if(isliving(holder.loc)) + holder = holder.loc last_bloodcall = world.time - if(istype(M)) + if(ishuman(M)) playsound(holder, pick('sound/hallucinations/wail.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/far_noise.ogg'), 50, 1, -3) var/target = pick(M.organs_by_name) @@ -27,14 +34,25 @@ B.target_turf = pick(RANGE_TURFS(1, holder)) B.blood_DNA = list() B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - M.remove_blood(rand(10,30)) + var/blood_to_remove = (rand(10,30)) + M.remove_blood(blood_to_remove) + if(harvested) + charges += blood_to_remove/10 //Anywhere from 1 to 3 charges based on how much it sucks, plus the extra blood puddle.. This means you can reasonably get things from the harvested variant. + /// In testing, (with it set to effect = 1 aka AURA, it got ~18 charges with 300 anobattery usage, 22% blood loss from the person being drained, and 41 damage to them (plus the resulting 20 oxyloss from low blood) + /// I feel like 22% blood loss and 41 damage is a good exchange for 18 charges. If this seems to be too strong later down the line, just change that /10 above to a /15 (33% less per blood) or /20 (50% less per blood) /datum/artifact_effect/vampire/DoEffectTouch(var/mob/user) - bloodcall(user) + if(world.time - bloodcall_interval*2 > last_bloodcall) //The artifact harvester works by having you massively targeted if you use it as a 'on touch' artifact. + bloodcall(user) // Due to such, things like the 'harm artifact' will just annihilate you if you set it high enough. This will also annihilate you, but it feels really cheesey, so let's not do that, as DoEffectTouch calls DoEffectAura already. + // Additionally, it requires the *2 or it will ALWAYS target the person who activated it DoEffectAura() /datum/artifact_effect/vampire/DoEffectAura() var/atom/holder = get_master_holder() + if(istype(holder, /obj/item/anobattery)) + holder = holder.loc + if(isliving(holder.loc)) + holder = holder.loc if(nearby_mobs.len) nearby_mobs.Cut() var/turf/T = get_turf(holder) @@ -62,9 +80,9 @@ qdel(B) - if(charges >= 10) + if(charges >= 10) //Listen, if you have INTENTIONALLY FED THE SPOOKY, SCARY ARTIFACT THAT IS DRAINING YOUR BLOOD, then go ahead and have your spooky reward. charges -= 10 - var/manifestation = pick(/obj/item/soulstone, /mob/living/simple_mob/faithless/cult/strong, /mob/living/simple_mob/creature/cult/strong, /mob/living/simple_mob/animal/space/bats/cult/strong) + var/manifestation = pick(/obj/item/soulstone, /obj/item/melee/artifact_blade, /obj/item/book/tome, /obj/item/clothing/head/helmet/space/cult, /obj/item/clothing/suit/space/cult, /obj/structure/constructshell) new manifestation(pick(RANGE_TURFS(1,T))) if(charges >= 3) diff --git a/code/modules/xenoarcheaology/finds/Weapons/archeo_eguns.dm b/code/modules/xenoarcheaology/finds/Weapons/archeo_eguns.dm new file mode 100644 index 0000000000..ac02b99846 --- /dev/null +++ b/code/modules/xenoarcheaology/finds/Weapons/archeo_eguns.dm @@ -0,0 +1,6 @@ +//snowflake guns for xenoarch because you can't override the update_icon() proc inside the giant mess that is find creation +/obj/item/gun/energy/laser/xenoarch + icon = 'icons/obj/xenoarchaeology.dmi' + +/obj/item/gun/energy/laser/xenoarch/update_icon() + return diff --git a/code/modules/xenoarcheaology/finds/eguns_vr.dm b/code/modules/xenoarcheaology/finds/Weapons/archeo_eguns_vr.dm similarity index 100% rename from code/modules/xenoarcheaology/finds/eguns_vr.dm rename to code/modules/xenoarcheaology/finds/Weapons/archeo_eguns_vr.dm diff --git a/code/modules/xenoarcheaology/finds/Weapons/archeo_guns.dm b/code/modules/xenoarcheaology/finds/Weapons/archeo_guns.dm new file mode 100644 index 0000000000..93bc69c121 --- /dev/null +++ b/code/modules/xenoarcheaology/finds/Weapons/archeo_guns.dm @@ -0,0 +1,49 @@ +//snowflake guns for xenoarch because you can't override the update_icon() proc inside the giant mess that is find creation +/obj/item/gun/projectile/artifact + name = "artifact gun" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "gun1" + caliber = ".357" + max_shells = 12 + ammo_type = /obj/item/ammo_casing/artifact + load_method = SINGLE_CASING //One. At. A. Time. + auto_eject = 0 + +/obj/item/gun/projectile/artifact/get_ammo_type() //Handles the HUD overlay. + var/obj/item/projectile/P = src.projectile_type + return list(initial(P.hud_state), initial(P.hud_state_empty)) + +/obj/item/gun/projectile/artifact/unload_ammo(mob/user, allow_dump=0) //No taking the bullets out! + if(loaded.len) + var/obj/item/ammo_casing/C = loaded[loaded.len] + loaded.len-- + user.visible_message("[user] removes \a casing from [src], the casing fizzling in the air before evaporating into dust.", span_notice("You remove \a casing from [src], the casing fizzling in the air before evaporating into dust")) + C.loc = null //Into the void! + qdel(C) //And begone! + playsound(src, 'sound/weapons/empty.ogg', 50, 1) + new /obj/effect/effect/sparks(src) + user.hud_used.update_ammo_hud(user, src) + else + to_chat(user, span_warning("[src] is empty.")) + update_icon() + user.hud_used.update_ammo_hud(user, src) + +/obj/item/ammo_casing/artifact + name = "artifact bullet casing" + desc = "A MYSTERIOUS bullet casing!!! (You should not see this. If you do, blame adminbus or contact your nearest coder.)" + drop_sound = 'sound/items/drop/ring.ogg' + pickup_sound = 'sound/items/pickup/ring.ogg' + projectile_type = /obj/item/projectile/bullet/cap //Just a placeholder. Doesn't actually matter what this is. All that matters is what the projecttile_type of our BB is. + +/obj/item/ammo_casing/artifact/New() //These should ONLY ever be in artifact weapons. If you spawn outside of artifact weapons, it'll have a riot foam dart inside of it as the bullet. + ..() + BB = null + if(istype(loc, /obj/item/gun/projectile/artifact)) //If we are IN an artifact gun + var/obj/item/gun/projectile/artifact/our_gun = loc + if(ispath(our_gun.projectile_type)) + BB = new our_gun.projectile_type(src) //Then we create the bullet inside of us that is the projectile_type that the gun shoots! + else + BB = new /obj/item/ammo_casing/afoam_dart/riot(src) //Something went wrong. Should never happen. + else //The bullet was adminspawned in outside of an artifact gun. + BB = new /obj/item/ammo_casing/afoam_dart/riot(src) + randpixel_xy() diff --git a/code/modules/xenoarcheaology/finds/Weapons/archeo_melee.dm b/code/modules/xenoarcheaology/finds/Weapons/archeo_melee.dm new file mode 100644 index 0000000000..4b9664c28e --- /dev/null +++ b/code/modules/xenoarcheaology/finds/Weapons/archeo_melee.dm @@ -0,0 +1,297 @@ +/// Our summonables +#define SOULSTONE /obj/item/soulstone +#define SHELL /obj/structure/constructshell +#define ARTIFACT /obj/machinery/artifact + +/// Modified version of the cultblade that xenoarch spawned. +/// This is a usuable version that isn't just a trap if you find it and try to use it on a mob. +/// Has some spooky effects, damages you as you use it (which fuels the sword) and can really hurt if overused. +/// And if you feed it enough, it allows the sword to do some special spawns. +/// Melee has always been a VERY underused thing and guns are EXTREMELY strong comparitively. +/// Thus, this gives the xenoarch a few choices when finding this: +/// Give it to R&D to deconstruct, use it to fight mobs off near artifact sites, give it to people exploring space, or keep it to summon more artifacts. +/// If you DO decide to use it and then give it to R&D...Well...Either you or whoever puts it into the deconstructor is going to have a BAD time. +/obj/item/melee/artifact_blade + name = "artifact blade" + desc = "A mysterious blade that emanates terrifying power" + icon_state = "cultblade" + origin_tech = list(TECH_COMBAT = 6, TECH_ARCANE = 6, TECH_BIO = 6) + w_class = ITEMSIZE_LARGE + force = 30 + throwforce = 10 + toolspeed = 5 //Syncs perfectly with the animation time. + hitsound = 'sound/weapons/bladeslice.ogg' + drop_sound = 'sound/items/drop/sword.ogg' + pickup_sound = 'sound/items/pickup/sword.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + edge = TRUE + sharp = TRUE + embed_chance = 0 + var/mob/living/carbon/human/last_touched //The last human that touched us + var/stored_blood = 0 //How much energy we have! + var/last_special = 0 //How recently our powers were used! Can be admin-set to a high number to keep from having the mode able to be changed. + var/list/abilities = list("Consecrate", "Summon") + var/list/summonables = list("Soulstone" = SOULSTONE, "Shell" = SHELL, "Cultic Artifact" = ARTIFACT) + var/consecrating = FALSE //If we are consecrating or not! + var/consecration_cost = 10 //Ten stored_blood per use! + var/empowered = FALSE //If our next atack is empowered (2x damage) + +/obj/item/melee/artifact_blade/Initialize() //We will never spawn without xenoarch or SOMEONE unearthing us. + . = ..() + //START_PROCESSING(SSobj, src) //We could start processing here, but let's wait until someone touches us. Uncomment this if more stuff is added and you want it to do spooky passive things. + +/obj/item/melee/artifact_blade/examine(mob/user) + . = ..() + if(stored_blood && user == last_touched) + . += span_cult("You can sense the blade has about " + span_bold("[stored_blood]") + " lifeforce contained within it.") + +/obj/item/melee/artifact_blade/process() + if(!last_touched || !stored_blood) //Nobody has touched us yet or we have no energy...For now. + return + if(!last_touched || last_touched.stat == DEAD) //If our user doesn't exist or is dead, stop processing until the next unlucky sod touches us. + STOP_PROCESSING(SSobj, src) + last_touched = null + return + if(loc == last_touched && (last_touched.life_tick % 30 == 0)) //We are currently being wielded by our owner. One proc every minute. + /// First and foremost, the sword passively takes some blood from you when you hold it. + /// This doesn't INJURE you like using it but does take blood. And a LOT of it. If you just carry the sword around, it's going to drain you. + to_chat(last_touched, span_cult("You feel weaker as the sword drains your lifeforce, imbuing itself with power.")) + var/blood_to_remove = rand(10,30) + if(last_touched.remove_blood(blood_to_remove)) + stored_blood += blood_to_remove*3 + empowered = 1 + return //We are done with our effects. + else + return + +/obj/item/melee/artifact_blade/Destroy() + if(stored_blood && last_touched && last_touched.stat != DEAD) //We have been activated (have some energy), an owner and they are alive. They are going to feel pain. + to_chat(last_touched, span_cult("You feel as though your mind is suddenly being torn apart at the seams as the [src] is destroyed!")) + last_touched.Paralyse(10) + last_touched.make_jittery(1000) + last_touched.eye_blurry += 10 + last_touched.add_modifier(/datum/modifier/agonize, 30 SECONDS) + blood_splatter(last_touched, last_touched, 1) + if(last_touched.loc) + conjure_animation(last_touched.loc) + visible_message(span_cult("\The [src] screeches as it's destroyed")) + lightning_strike(last_touched.loc, TRUE) + playsound(src, 'sound/goonstation/spooky/creepyshriek.ogg', 100, 1, 75) //It plays VERY far. + last_touched = null //Get rid of the reference to our owner. + ..() + + +/obj/item/melee/artifact_blade/cultify() + return + +/obj/item/melee/artifact_blade/attack(mob/living/M, mob/living/user, var/target_zone) + var/zone = (user.hand ? "l_arm":"r_arm") //Which arm we're in! + var/prior_force = force + if(empowered) + force = force*2 + empowered = 0 + /// First, we check a few things. + /// Check 1: We aren't a cultist and they're a human AND they're not AI controlled + /// OR + /// Check 2: (We're a cultist AND they're a cultist) OR (Our factions align) + /// If these are true, we get hurt. + if((!iscultist(user) && (ishuman(M) && !istype(M, /mob/living/carbon/human/ai_controlled)) || ((iscultist(user) && iscultist(M)) || M.faction == user.faction))) + user.visible_message(span_cult("[user]'s arm is engulfed in dark flames!")) + to_chat(user, span_cult("An inexplicable force rips through your arm as it's engulfed in flames, tearing the sword from your grasp!")) + user.drop_from_inventory(src, user.loc) + user.Weaken(5) + throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,10),5) + user.apply_damage(rand(force/2, force), BURN, zone, FALSE) + return + + ..() //We hit them! + + if(ishuman(user)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/affecting = H.get_organ(zone) + + to_chat(user, span_cult("You feel your [affecting.name] tearing from the inside out as the sword takes its blood price!")) + + var/damage_to_apply = rand(1,3) + affecting.take_damage(damage_to_apply, sharp = FALSE, edge = FALSE) //Careful...Too much use and you might break your arm! This doesn't make you bleed because the sword is slurping that up. + if(((affecting.brute_dam + affecting.burn_dam) >= affecting.max_damage) && prob((affecting.brute_dam + affecting.burn_dam))) //Don't just splint your arm and keep using it, because you'll lose it! + user.visible_message(span_cult("[H]'s arm is engulfed in dark flames!")) + affecting.droplimb(TRUE, DROPLIMB_BURN) //And by hacked off, we mean melted into ashes... It's fire, so it's a clean loss. + + var/blood_loss = damage_to_apply*3 + if(H.remove_blood(blood_loss)) //Non insignificant amount if we keep using it. 3 to 15 blood lost per swing. Blood volume base is 560. Anything above 476 is safe. This means we get 28 to 5 swings. Average being 9 swings. + stored_blood += blood_loss //We add the damage dealt to our owner to our stored blood. + + /// If the thing we're hitting is dead, our faction, friendly, or synthetic, we get no blood. + if(M.stat < DEAD && M.faction != user.faction && !ispassive(M) && !issilicon(M) && !isbot(M) && isslime(M)) + stored_blood += force + + //If the user isn't 'worthy' they get a single swing before the sword THROWS itself away from them. Possibly even off-screen! + else if(istype(user, /mob/living/simple_mob/construct)) + to_chat(user, span_cult("An inexplicable force rips through you, tearing the sword from your grasp!")) + user.drop_from_inventory(src, user.loc) + throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,10),5) + + else + to_chat(user, span_cult("The blade hisses, forcing itself from your manipulators. \The [src] will only allow mortals to wield it against foes, not kin.")) + user.drop_from_inventory(src, user.loc) + throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,10),5) + + if(prob(10)) //During testing, this was set to 100% of the time to make sure it works... It went from spooky to 'dear god make it stop' + var/spooky = pick('sound/effects/ghost.ogg', 'sound/effects/ghost2.ogg', 'sound/effects/Heart Beat.ogg', 'sound/effects/screech.ogg',\ + 'sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', 'sound/hallucinations/far_noise.ogg', 'sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg',\ + 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\ + 'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\ + 'sound/hallucinations/wail.ogg') //It's just a cursed, talking sword. Nothing to fear! + playsound(src, spooky, 50, 1) + + force = prior_force //Return our force back. + return 1 + +/obj/item/melee/artifact_blade/pickup(mob/living/user as mob) + // We check to see if the person picking us up isn't our owner, not a cultist, and they're human. + // Yes. This means you can hand off the sword to someone else to make them the newfound owner of the cursed sword. + if((user != last_touched) && !iscultist(user) && ishuman(user)) + to_chat(user, span_cult("An overwhelming feeling of dread comes over you as you pick up the sword. You feel as though it has become attached to you.")) + last_touched = user + START_PROCESSING(SSobj, src) + +/obj/item/melee/artifact_blade/attack_self(mob/user as mob) + if(last_special > world.time - 120) + to_chat(user, span_cult("The blade does not respond to your attempts, having recently performed an action!")) + return + last_special = world.time + if(stored_blood < 20) + to_chat(user, span_cult("The blade does not respond to your attempts, seeming to have not enough blood to perform any actions!")) + return + if(stored_blood > 100) + var/choice = tgui_input_list(user, "What action do you wish to have the blade perform?", "Download", abilities) + if(choice && loc == user) + switch(choice) + if("Consecrate") + var/decision2 = tgui_alert(user, "Do you wish to toggle the sword's 'consecrate' mode? If enabled, this will allow the sword to turn floors and walls into a more cult-like appearance! It requires [consecration_cost] per use!", "Consecrate!", list("Toggle on", "Toggle off")) + consecrate_toggle(user, decision2) + return + /// Spawning logic. Checks the 'summonables' list. + if("Summon") + var/summoned_item = tgui_input_list(user, "What do you wish to summon?", "Summon", summonables) + summon_item(user, summoned_item) + return + +/obj/item/melee/artifact_blade/proc/consecrate_toggle(mob/user as mob, var/toggle) + switch(toggle) + if("Toggle on") + consecrating = TRUE + to_chat(user, span_cult("The blade will now transform walls and tiles!")) + return + if("Toggle off") + consecrating = FALSE + to_chat(user, span_cult("The blade will " + span_bold("NOT") +" transform walls and tiles!")) + return + else + return + +/// It lets them select it, gives them a small blurb on it (w/ cost), then checks to see if they have enough blood. +/// The summonables list can be VV'd by admins to allow for adminbus. +/// To add to the list: Add-Item, Multi-line text (Front-facing name), Associated value = yes, Atom Typepath = whatever you want. +/// This should appear something like " Paper = /obj/item/paper " if you did it right, and will let them summon paper! +/obj/item/melee/artifact_blade/proc/summon_item(mob/user as mob, var/selected_item) + if(selected_item) + if(selected_item == "Soulstone") + var/decision2 = tgui_alert(user, "Do you wish to create a redspace gem? This will take 200 lifeforce from the sword.", "Generate Gem", list("YES", "NO")) + if(stored_blood < 200) + to_chat(user, span_cult("The blade does not have enough lifeforce!")) + return + if(decision2 == "YES") + var/obj/item/soulstone/our_stone = new SOULSTONE(user.loc) + our_stone.desc = "A glowing stone made of what appears to be a pure chunk of redspace. It seems to have the power to transfer the consciousness of dead or nearly-dead humanoids into it." + our_stone.name = "Redspace Gem" + stored_blood -= 200 + to_chat(user, span_cult("You have summoned a redspace gem!")) + return + else + return + if(selected_item == "Shell") + var/decision2 = tgui_alert(user, "Do you wish to create a shell? This will take 500 lifeforce from the sword.", "Generate Shell", list("YES", "NO")) + if(stored_blood < 500) + to_chat(user, span_cult("The blade does not have enough lifeforce!")) + return + if(decision2 == "YES") + var/obj/structure/constructshell/shell = new SHELL(user.loc) + shell.desc = "A strange collection of stone carved out in a vague, humanoid shape. Red, pulsing lines travel down its entirety." + stored_blood -= 500 //This is VERY costly. + return + + /// This is one of the ways for xenoarch to obtain more artifacts in case you have depleted all the large artifacts in the available world. + /// While the artifact cap is relatively high, the more Z-levels that spawn any mineral turf, the less artifacts xenoarch can reliably find. + /// In some cases, if a xenoarch was REALLY unlucky, they could only find 3-4 large artifacts in the (readily) available Z levels without scouring the entire universe. + /// So this acts as a "You sacrifice a LOT to get a random artifact" + if(selected_item == "Cultic Artifact") + var/decision2 = tgui_alert(user, "Do you wish to create an artifact? This will take 1000 lifeforce from the sword.", "Generate Artifact", list("YES", "NO")) + if(stored_blood < 1000) + to_chat(user, span_cult("The blade does not have enough lifeforce!")) + return + if(decision2 == "YES") + var/obj/machinery/artifact/artifact = new ARTIFACT(user.loc) + artifact.desc = "A strange artifact. Red, pulsing lines travel down its entirety. It appears as though it has been brought into this reality through abnormal means." + stored_blood -= 500 //This is VERY costly. + return + else + return + + if(selected_item in summonables) //If admins modify the list, let's spawn it! + //This one doesn't have a blood requirement, barring the 100 required to GET to this menu. If an admin VV'd the list, there's a reason! + var/thing_to_spawn = summonables[selected_item] + new thing_to_spawn(user.loc) + stored_blood = max(0,stored_blood-250) //Subtract 250 stored blood, down to a minimum of 0. No negative numbers here! + return + else // You're trying to href hack it! (Or an admin put in the wrong thing). I'm going to assume if you know how to href hack, you're looking at this beforehand. + message_admins("[key_name_admin(user)] attempted to spawn an object not in the artifact blade's spawnlist! This is either a HREF hack, the list was improperly VV'd by an admin, or something went wrong!") + log_game("[key_name_admin(user)] attempted to spawn an object not in the artifact blade's spawnlist!") + return + else + return + + +/// While this COULD just use the cultify() proc ultimately, I decided against that as this isn't meant to be +/// Some sort of weapon of mass destruction. It's supposed to be a funny, spooky artifact that you find. +/// Thus, it uses the 'occult_act' proc, which does a HEAVILY watered down version of the cultify() proc. +/// Only affects simulated turf, simulated walls, and girders. Nothing else. This shouldn't be desturctive, simply gimmicky. +/obj/item/melee/artifact_blade/afterattack(atom/A, mob/living/user, proximity) + if(consecrating && proximity && !ismob(A)) + convert_turf(A, user) + else + ..() + + +/// The fancy animation it plays when you hit something to convert it! +/obj/item/melee/artifact_blade/proc/conjure_animation(var/turf/target) //Taken from occult wizard code. + var/atom/movable/overlay/animation = new /atom/movable/overlay(target) + animation.name = "conjure" + animation.icon = 'icons/effects/effects.dmi' + animation.plane = OBJ_PLANE + animation.layer = ABOVE_JUNK_LAYER + animation.icon_state = "cultwall" + flick("cultwall",animation) + spawn(10) + qdel(animation) + +/// When it actually, properly converts the turf. +/obj/item/melee/artifact_blade/proc/convert_turf(atom/A, mob/living/user) //Shamelessly taken from RCD code. + if(stored_blood < consecration_cost) + to_chat(user, span_cult("\The [src] lacks enough lifeforce to convert.")) + return FALSE + conjure_animation(A, toolspeed) + if(do_after(user, toolspeed, target = A)) + if(stored_blood < consecration_cost) + to_chat(user, span_cult("\The [src] lacks enough lifeforce to convert.")) + return FALSE + if(A.occult_act(user)) + stored_blood -= consecration_cost + return TRUE + + //Moving = stop + return FALSE +#undef SOULSTONE +#undef SHELL +#undef ARTIFACT diff --git a/code/modules/xenoarcheaology/finds/eguns.dm b/code/modules/xenoarcheaology/finds/eguns.dm deleted file mode 100644 index 0365ca2c73..0000000000 --- a/code/modules/xenoarcheaology/finds/eguns.dm +++ /dev/null @@ -1,30 +0,0 @@ -//snowflake guns for xenoarch because you can't override the update_icon() proc inside the giant mess that is find creation -/obj/item/gun/energy/laser/xenoarch - icon = 'icons/obj/xenoarchaeology.dmi' - -/obj/item/gun/energy/laser/xenoarch/update_icon() - return - -/obj/item/gun/energy/laser/practice/xenoarch - icon = 'icons/obj/xenoarchaeology.dmi' - -/obj/item/gun/energy/laser/practice/xenoarch/update_icon() - return - -/obj/item/gun/energy/laser/practice/xenoarch - icon = 'icons/obj/xenoarchaeology.dmi' - -/obj/item/gun/energy/laser/practice/xenoarch/update_icon() - return - -/obj/item/gun/energy/xray/xenoarch - icon = 'icons/obj/xenoarchaeology.dmi' - -/obj/item/gun/energy/xray/xenoarch/update_icon() - return - -/obj/item/gun/energy/captain/xenoarch - icon = 'icons/obj/xenoarchaeology.dmi' - -/obj/item/gun/energy/captain/xenoarch/update_icon() - return diff --git a/code/modules/xenoarcheaology/finds/find_spawning.dm b/code/modules/xenoarcheaology/finds/find_spawning.dm index af11c748e7..8b93844b90 100644 --- a/code/modules/xenoarcheaology/finds/find_spawning.dm +++ b/code/modules/xenoarcheaology/finds/find_spawning.dm @@ -4,23 +4,61 @@ icon_state = "ano01" var/find_type = 0 -/obj/item/archaeological_find/New(loc, var/new_item_type) +/// Find spawning debug tool. Can be called on any /mob to spawn it at their location. +/mob/proc/artifact_spawn_debug_tool() + set name = "Artifact Debug" + set desc = "Spawn an artifact." + set category = "Debug" + if(!src.loc) + to_chat(usr, "You need to select a mob with a proper LOC to spawn a minor artifact!") + return + + var/type_to_spawn = tgui_input_number(usr, "Desired type to spawn. Consult xenoarcheaology.dm for the spawn list", "Spawn Artifact", 0) + new /obj/item/archaeological_find(src.loc, type_to_spawn) + +/obj/item/archaeological_find/Initialize(mapload, var/new_item_type) + . = ..() if(new_item_type) find_type = new_item_type else find_type = rand(1, MAX_ARCHAEO) var/item_type = "object" + var/secondary_item_type = "object" icon_state = "unknown[rand(1,4)]" - var/additional_desc = "" - var/obj/item/new_item + var/additional_desc = "" //Description for the item we find! + var/secondary_item_desc = "" //Description for the secondary item that can be found + var/obj/item/new_item //The item we're finding! + var/obj/item/secondary_item //Allows for more than one item to be found at a time. var/source_material = "" var/apply_material_decorations = TRUE var/apply_image_decorations = FALSE var/material_descriptor = "" var/apply_prefix = TRUE - var/become_anomalous = FALSE + var/become_anomalous = FALSE //This, simply put, gives the item either precursor or an arcane tech level, along with setting a random tech level to 4-7. + + /// Used for the below material type generation code. + var/list/banned_materials = list( + /datum/material/flesh, + /datum/material/fluff, + /datum/material/darkglass, + /datum/material/fancyblack, + /datum/material/steel/hull, + /datum/material/plasteel/hull, + /datum/material/durasteel/hull, + /datum/material/titanium/hull, + /datum/material/morphium/hull, + /datum/material/steel/holographic, + /datum/material/plastic/holographic, + /datum/material/wood/holographic, + /datum/material/alienalloy, + /datum/material/alienalloy/elevatorium, + /datum/material/alienalloy/dungeonium, + /datum/material/alienalloy/bedrock, + /datum/material/alienalloy/alium + ///datum/material/debug //Enable if ticked in the .dme + ) if(prob(40)) material_descriptor = pick("rusted ","dusty ","archaic ","fragile ", "damaged", "pristine") @@ -36,43 +74,24 @@ switch(find_type) if(ARCHAEO_BOWL) item_type = "bowl" + new_item = new /obj/item/reagent_containers/glass/replenishing(src.loc) if(prob(33)) - new_item = new /obj/item/reagent_containers/glass/replenishing(src.loc) LAZYSET(new_item.origin_tech, TECH_ARCANE, 1) - else - new_item = new /obj/item/reagent_containers/glass/beaker(src.loc) new_item.icon = 'icons/obj/xenoarchaeology.dmi' new_item.icon_state = "bowl" apply_image_decorations = TRUE - if(prob(40)) - new_item.color = rgb(rand(0,255),rand(0,255),rand(0,255)) - if(prob(20)) - additional_desc = "There appear to be [pick("dark","faintly glowing","pungent","bright")] [pick("red","purple","green","blue")] stains inside." + new_item.color = rgb(rand(0,255),rand(0,255),rand(0,255)) + additional_desc = "There appear to be [pick("dark","faintly glowing","pungent","bright")] [pick("red","purple","green","blue")] stains inside." if(ARCHAEO_URN) item_type = "urn" + new_item = new /obj/item/reagent_containers/glass/replenishing(src.loc) if(prob(33)) - new_item = new /obj/item/reagent_containers/glass/replenishing(src.loc) LAZYSET(new_item.origin_tech, TECH_ARCANE, 1) - else - new_item = new /obj/item/reagent_containers/glass/beaker(src.loc) + new_item = new /obj/item/reagent_containers/glass/beaker(src.loc) new_item.icon = 'icons/obj/xenoarchaeology.dmi' new_item.icon_state = "urn[rand(1,2)]" apply_image_decorations = TRUE - if(prob(20)) - additional_desc = "It [pick("whispers faintly","makes a quiet roaring sound","whistles softly","thrums quietly","throbs")] if you put it to your ear." - if(ARCHAEO_CUTLERY) - item_type = "[pick("fork","spoon","knife")]" - if(prob(25)) - new_item = new /obj/item/material/kitchen/utensil/fork(src.loc) - else if(prob(50)) - new_item = new /obj/item/material/knife(src.loc) - else - new_item = new /obj/item/material/kitchen/utensil/spoon(src.loc) - if(prob(60)) - LAZYSET(new_item.origin_tech, TECH_ARCANE, 1) - additional_desc = "[pick("It's like no [item_type] you've ever seen before",\ - "It's a mystery how anyone is supposed to eat with this",\ - "You wonder what the creator's mouth was shaped like")]." + additional_desc = "It [pick("whispers faintly","makes a quiet roaring sound","whistles softly","thrums quietly","throbs")] if you put it to your ear." if(ARCHAEO_STATUETTE) name = "statuette" icon = 'icons/obj/xenoarchaeology.dmi' @@ -80,26 +99,32 @@ icon_state = "statuette[rand(1,3)]" additional_desc = "It depicts a [pick("small","ferocious","wild","pleasing","hulking")] \ [pick("alien figure","rodent-like creature","reptilian alien","primate","unidentifiable object")] \ - [pick("performing unspeakable acts","posing heroically","in a fetal position","cheering","sobbing","making a plaintive gesture","making a rude gesture")]." - if(prob(25)) - new_item = new /obj/item/vampiric(src.loc) - LAZYSET(new_item.origin_tech, TECH_ARCANE, 1) + [pick("performing unspeakable acts","posing heroically","in a fetal position","cheering","sobbing","making a plaintive gesture","making a rude gesture")]. \ + [pick("It glares at anything that makes sound", "Any nearby sounds attract it's gaze", "Its eyes glow crimson when noises are made nearby")]]." + new_item = new /obj/item/vampiric(src.loc) //Possibly make multiple subtypes of this? + LAZYSET(new_item.origin_tech, TECH_ARCANE, 1) if(ARCHAEO_INSTRUMENT) name = "instrument" icon = 'icons/obj/xenoarchaeology.dmi' item_type = "instrument" icon_state = "instrument" + var/possible_object_paths = list() + possible_object_paths |= subtypesof(/obj/item/instrument) + var/new_instrument = pick(possible_object_paths) + new_item = new new_instrument(src.loc) if(prob(30)) become_anomalous = TRUE - if(prob(30)) - apply_image_decorations = TRUE - additional_desc = "[pick("You're not sure how anyone could have played this",\ - "You wonder how many mouths the creator had",\ - "You wonder what it sounds like",\ - "You wonder what kind of music was made with it")]." + apply_image_decorations = TRUE + additional_desc = "[pick("You're not sure how anyone could have played this",\ + "You wonder how many mouths the creator had",\ + "You wonder what it sounds like",\ + "You wonder what kind of music was made with it")]." if(ARCHAEO_KNIFE) item_type = "[pick("bladed knife","serrated blade","sharp cutting implement")]" - new_item = new /obj/item/material/knife(src.loc) + var/possible_object_paths = list(/obj/item/material/knife) //As far as I can tell, this is more 'random' than using typesof, as it just picks a random one vs going down the list with a prob (as seen below) + possible_object_paths |= subtypesof(/obj/item/material/knife) + var/obj/item/material/knife/new_knife = pick(possible_object_paths) + new_item = new new_knife(src.loc) additional_desc = "[pick("It doesn't look safe.",\ "It looks wickedly jagged",\ "There appear to be [pick("dark red","dark purple","dark green","dark blue")] stains along the edges")]." @@ -118,23 +143,31 @@ apply_image_decorations = TRUE if(ARCHAEO_HANDCUFFS) item_type = "handcuffs" - new_item = new /obj/item/handcuffs(src.loc) + var/possible_object_paths = list(/obj/item/handcuffs) + possible_object_paths |= subtypesof(/obj/item/handcuffs) + var/new_cuffs = pick(possible_object_paths) + new_item = new new_cuffs(src.loc) additional_desc = "[pick("They appear to be for securing two things together","Looks kinky","Doesn't seem like a children's toy")]." if(ARCHAEO_BEARTRAP) item_type = "[pick("wicked","evil","byzantine","dangerous")] looking [pick("device","contraption","thing","trap")]" apply_prefix = FALSE - new_item = new /obj/item/beartrap(src.loc) - if(prob(40)) - new_item.color = rgb(rand(0,255),rand(0,255),rand(0,255)) + var/list/possible_trap = list(/obj/item/beartrap, + /obj/item/beartrap/hunting) + + var/new_trap = pick(possible_trap) + new_item = new new_trap(src.loc) + new_item.color = rgb(rand(0,255),rand(0,255),rand(0,255)) additional_desc = "[pick("It looks like it could take a limb off",\ "Could be some kind of animal trap",\ "There appear to be [pick("dark red","dark purple","dark green","dark blue")] stains along part of it")]." if(ARCHAEO_LIGHTER) item_type = "[pick("cylinder","tank","chamber")]" - new_item = new /obj/item/flame/lighter(src.loc) + var/possible_object_paths = list() + possible_object_paths |= subtypesof(/obj/item/flame) + var/new_lighter = pick(possible_object_paths) + new_item = new new_lighter(src.loc) additional_desc = "There is a tiny device attached." - if(prob(30)) - apply_image_decorations = TRUE + apply_image_decorations = TRUE if(ARCHAEO_BOX) item_type = "box" new_item = new /obj/item/storage/box(src.loc) @@ -149,50 +182,48 @@ apply_image_decorations = TRUE if(ARCHAEO_GASTANK) item_type = "[pick("cylinder","tank","chamber")]" - if(prob(25)) - new_item = new /obj/item/tank/air(src.loc) - else if(prob(50)) - new_item = new /obj/item/tank/anesthetic(src.loc) - else - new_item = new /obj/item/tank/phoron(src.loc) + var/possible_object_paths = list() + possible_object_paths |= subtypesof(/obj/item/tank) + var/new_tank = pick(possible_object_paths) + new_item = new new_tank(src.loc) icon_state = pick("oxygen","oxygen_fr","oxygen_f","phoron","anesthetic") additional_desc = "It [pick("gloops","sloshes")] slightly when you shake it." if(ARCHAEO_TOOL) item_type = "tool" - if(prob(25)) - new_item = new /obj/item/tool/wrench(src.loc) - else if(prob(25)) - new_item = new /obj/item/tool/crowbar(src.loc) - else - new_item = new /obj/item/tool/screwdriver(src.loc) - if(prob(40)) - new_item.color = rgb(rand(0,255),rand(0,255),rand(0,255)) - apply_image_decorations = TRUE + var/possible_object_paths = list() + possible_object_paths |= subtypesof(/obj/item/tool) + var/new_tool = pick(possible_object_paths) + new_item = new new_tool(src.loc) + new_item.color = rgb(rand(0,255),rand(0,255),rand(0,255)) + apply_image_decorations = TRUE additional_desc = "[pick("It doesn't look safe.",\ "You wonder what it was used for",\ "There appear to be [pick("dark red","dark purple","dark green","dark blue")] stains on it")]." if(ARCHAEO_METAL) apply_material_decorations = FALSE - var/list/possible_spawns = list() - possible_spawns += /obj/item/stack/material/steel - possible_spawns += /obj/item/stack/material/plasteel - possible_spawns += /obj/item/stack/material/glass - possible_spawns += /obj/item/stack/material/glass/reinforced - possible_spawns += /obj/item/stack/material/phoron - possible_spawns += /obj/item/stack/material/gold - possible_spawns += /obj/item/stack/material/silver - possible_spawns += /obj/item/stack/material/uranium - possible_spawns += /obj/item/stack/material/sandstone - possible_spawns += /obj/item/stack/material/silver - - var/new_type = pick(possible_spawns) - new_item = new new_type(src.loc) + var/possible_object_paths = list() + possible_object_paths |= subtypesof(/obj/item/stack/material) + //I looked through the code for any materials that should be banned...Most of the "DO NOT EVER GIVE THESE TO ANYONE EVER" materials are only in their /datum form and the ones that have sheets spawn in as normal sheets (ex: hull datums) so...This is here in case it's needed in the future. + var/list/banned_sheet_materials = list( + // Include if you enable in the .dme /obj/item/stack/material/debug + ) + var/new_metal = /obj/item/stack/material/supermatter + for(var/x=1;x<=10;x++) //You got 10 chances to hit a metal that is NOT banned. + var/picked_metal = pick(possible_object_paths) //We select + if(picked_metal in banned_sheet_materials) + continue + else + new_metal = picked_metal + break + new_item = new new_metal(src.loc) new_item:amount = rand(5,45) if(ARCHAEO_PEN) - if(prob(75)) - new_item = new /obj/item/pen(src.loc) - else - new_item = new /obj/item/pen/reagent/sleepy(src.loc) + var/new_pen = pick(/obj/item/pen, /obj/item/pen/blade/fountain, /obj/item/pen/reagent/sleepy) //There are WAY too many pen blade variants that it'd drown out the others in this list. + new_item = new new_pen(src.loc) + if(istype(new_item, /obj/item/pen/blade)) + additional_desc = "There seems to be a needle inside of the pen tip." + if(istype(new_item, /obj/item/pen/reagent/sleepy)) + additional_desc = "It sloshes when you move it around." if(prob(30)) icon = 'icons/obj/xenoarchaeology.dmi' icon_state = "pen1" @@ -215,7 +246,6 @@ item_type = "rough red crystal" icon_state = "changerock" additional_desc = pick("It shines faintly as it catches the light.","It appears to have a faint inner glow.","It seems to draw you inward as you look it at.","Something twinkles faintly as you look at it.","It's mesmerizing to behold.") - apply_material_decorations = FALSE if(prob(10)) apply_image_decorations = TRUE @@ -223,11 +253,19 @@ new_item = new /obj/item/soulstone(src.loc) new_item.icon = 'icons/obj/xenoarchaeology.dmi' new_item.icon_state = icon_state + new_item.name = "Redspace Gem" + new_item.desc = "A glowing stone made of what appears to be a pure chunk of redspace. It seems to have the power to transfer the consciousness of dead or nearly-dead humanoids into it." LAZYSET(new_item.origin_tech, TECH_ARCANE, 2) if(ARCHAEO_CULTBLADE) //cultblade apply_prefix = FALSE - new_item = new /obj/item/melee/cultblade(src.loc) + new_item = new /obj/item/melee/artifact_blade(src.loc) //Changed to an artifact one. + additional_desc = "This sword emanates terrifying power" + apply_material_decorations = FALSE + apply_image_decorations = FALSE + if(ARCHAEO_TOME) + apply_prefix = FALSE + new_item = new /obj/item/book/tome(src.loc) //Also obtainable via library. Useless unless you're an ACTUAL cultist antag, but it looks SPOOOKY. apply_material_decorations = FALSE apply_image_decorations = FALSE if(ARCHAEO_TELEBEACON) @@ -247,15 +285,29 @@ new_item.icon_state = "blade1" if(ARCHAEO_CULTROBES) //arcane clothing + //Funnily enough, this was just helmets before I edited it, with no robes. apply_prefix = FALSE - var/list/possible_spawns = list(/obj/item/clothing/head/culthood, + var/list/possible_headwear = list(/obj/item/clothing/head/culthood, /obj/item/clothing/head/culthood/magus, /obj/item/clothing/head/culthood/alt, /obj/item/clothing/head/helmet/space/cult) - var/new_type = pick(possible_spawns) - new_item = new new_type(src.loc) + var/new_helmet = pick(possible_headwear) + var/new_robes + ///Makes sets spawn. Quick, dirty, easy. Simplest thing I could think of without reinventing the wheel. + if(new_helmet == /obj/item/clothing/head/culthood) + new_robes = /obj/item/clothing/suit/cultrobes + else if(new_helmet == /obj/item/clothing/head/culthood/magus) + new_robes = /obj/item/clothing/suit/cultrobes/magusred + else if(new_helmet == /obj/item/clothing/head/culthood/alt) + new_robes = /obj/item/clothing/suit/cultrobes/alt + else if(new_helmet == /obj/item/clothing/head/helmet/space/cult) + new_robes = /obj/item/clothing/suit/space/cult + + new_item = new new_helmet(src.loc) + secondary_item = new new_robes(src.loc) LAZYSET(new_item.origin_tech, TECH_ARCANE, 1) + LAZYSET(secondary_item.origin_tech, TECH_ARCANE, 1) if(ARCHAEO_SOULSTONE) //soulstone become_anomalous = TRUE @@ -264,19 +316,6 @@ item_type = new_item.name apply_material_decorations = FALSE LAZYSET(new_item.origin_tech, TECH_ARCANE, 2) - if(ARCHAEO_SHARD) - if(prob(50)) - new_item = new /obj/item/material/shard(src.loc) - else - new_item = new /obj/item/material/shard/phoron(src.loc) - apply_prefix = FALSE - apply_image_decorations = FALSE - apply_material_decorations = FALSE - if(ARCHAEO_RODS) - apply_prefix = FALSE - new_item = new /obj/item/stack/rods(src.loc) - apply_image_decorations = FALSE - apply_material_decorations = FALSE if(ARCHAEO_STOCKPARTS) if(prob(30)) become_anomalous = TRUE @@ -296,73 +335,63 @@ item_type = new_item.name if(ARCHAEO_LASER) //energy gun - var/spawn_type = pick(\ - /obj/item/gun/energy/laser/practice/xenoarch,\ - /obj/item/gun/energy/laser/xenoarch,\ - /obj/item/gun/energy/xray/xenoarch,\ - /obj/item/gun/energy/captain/xenoarch) - if(spawn_type) - var/obj/item/gun/energy/new_gun = new spawn_type(src.loc) - new_item = new_gun - new_item.icon_state = "egun[rand(1,6)]" //VOREStation Edit: max value is 6 since xenoarcheoloy_vr only has 6 egun variants - new_gun.desc = "This is an antique energy weapon, you're not sure if it will fire or not." - - //5% chance to explode when first fired - //10% chance to have an unchargeable cell - //15% chance to gain a random amount of starting energy, otherwise start with an empty cell - if(prob(5)) - new_gun.power_supply.rigged = 1 - if(prob(10)) - new_gun.power_supply.maxcharge = 0 - LAZYSET(new_gun.origin_tech, TECH_ARCANE, rand(0, 1)) - if(prob(15)) - new_gun.power_supply.charge = rand(0, new_gun.power_supply.maxcharge) - LAZYSET(new_gun.origin_tech, TECH_ARCANE, 1) - else - new_gun.power_supply.charge = 0 + var/obj/item/gun/energy/new_gun = new /obj/item/gun/energy/laser/xenoarch(src.loc) + var/possible_laser_paths = list() + possible_laser_paths |= subtypesof(/obj/item/projectile/beam) + // possible_laser_paths |= /obj/item/projectile/animate //Funny 'turns object into mimic' beam. Currently unticked in the .dme, but here in case it gets toggled! + possible_laser_paths |= /obj/item/projectile/ion + possible_laser_paths |= subtypesof(/obj/item/projectile/energy/floramut) + var/new_laser = pick(possible_laser_paths) + new_gun.projectile_type = new_laser + new_item = new_gun + new_item.icon_state = "egun[rand(1,6)]" + new_gun.desc = "This is an antique energy weapon, you're not sure if it will fire or not." + //10% chance to have an unchargeable cell + //15% chance to gain a random amount of starting energy, otherwise start with an empty cell + if(prob(10)) + new_gun.power_supply.maxcharge = 0 + LAZYSET(new_gun.origin_tech, TECH_ARCANE, rand(0, 1)) + if(prob(15)) + new_gun.power_supply.charge = rand(0, new_gun.power_supply.maxcharge) + LAZYSET(new_gun.origin_tech, TECH_ARCANE, 1) + else + new_gun.power_supply.charge = 0 item_type = "gun" + + + /// Artifact type gun that requires a random caliber and selects a random bullet type it shoots out!. if(ARCHAEO_GUN) - //revolver - var/obj/item/gun/projectile/new_gun = new /obj/item/gun/projectile/revolver(src.loc) + var/obj/item/gun/projectile/artifact/new_gun = new /obj/item/gun/projectile/artifact(src.loc) new_item = new_gun new_item.icon_state = "gun[rand(1,7)]" - new_item.icon = 'icons/obj/xenoarchaeology.dmi' - - //33% chance to be able to reload the gun with human ammunition - if(prob(66)) - new_gun.caliber = "999" - - //33% chance to fill it with a random amount of bullets - new_gun.max_shells = rand(1,12) - if(prob(33)) - var/num_bullets = rand(1,new_gun.max_shells) - if(num_bullets < new_gun.loaded.len) - new_gun.loaded.Cut() - for(var/i = 1, i <= num_bullets, i++) - var/A = new_gun.ammo_type - new_gun.loaded += new A(new_gun) - else - for(var/obj/item/I in new_gun) - if(new_gun.loaded.len > num_bullets) - if(I in new_gun.loaded) - new_gun.loaded.Remove(I) - I.loc = null - else - break - else - for(var/obj/item/I in new_gun) - if(I in new_gun.loaded) - new_gun.loaded.Remove(I) - I.loc = null - item_type = "gun" - if(ARCHAEO_UNKNOWN) - if(prob(20)) - become_anomalous = TRUE - //completely unknown alien device - if(prob(50)) - apply_image_decorations = FALSE + //There is no 'global list of all the gun caliber types' so...Whatever. This will have to do. (Side note: After further review, making it a global list would result in the gun requiring unobtainable calibers, so this is ideal.) + //When someone does make a global list of all the calibers, replace the below with it. + new_gun.caliber = "[pick(".357", "12g", ".38", "7.62mm", ".38", "9mm", "10mm", ".45", "5.45mm", "7.62mm")]" //A list of gun calibers that are obtainable. + additional_desc = "[pick("A dusty engraving on the side says" + span_bold("[new_gun.caliber]") + " The ammo slot seems like it'd only fit single shells at a time.",\ + "The gun's barrel has " + span_bold("[new_gun.caliber]") + " barely visible on it. The ammo slot seems like it'd only fit single shells at a time.")]" + var/possible_bullet_paths = list() + possible_bullet_paths |= subtypesof(/obj/item/projectile/bullet) //As funny as it would be to have your pistol shoot pulse rifle rounds, sorry. + //You COULD add a bullet blacklist here. Look at the material code below if you want an example of how to do so. + //During testing I found nothing EXTRAORDINARILY gamebreaking (although supermatter fuel rod gun rounds were VERY comical, but still obtainable in game) + //But maybe someone will add in a projectile/bullet/admin_instakills_you that needs to be blacklisted! + var/new_bullet = pick(possible_bullet_paths) + new_gun.projectile_type = new_bullet //Instead, you can get anything from chem darts to rifle rounds to everything in between. + + new_gun.max_shells = rand(1,12) + var/num_bullets = rand(1,new_gun.max_shells) + new_gun.loaded.Cut() //Remove all the bullets we spawned with. + new_gun.contents.Cut() + for(var/i = 1, i <= num_bullets, i++)//Load our gun with the special artifact ammo. + new_gun.loaded += new /obj/item/ammo_casing/artifact(new_gun) + + if(ARCHAEO_UNKNOWN) //This previously spawned NOTHING...Are you kidding me? + var/new_sample = new /obj/item/research_sample/rare(src.loc) //So instead, you get a really good research sample. Eat your heart out, science. + become_anomalous = TRUE + new_item = new_sample + item_type = new_item.name + if(ARCHAEO_FOSSIL) //fossil bone/skull //new_item = new /obj/item/fossil/base(src.loc) @@ -377,6 +406,7 @@ additional_desc = "A fossilised part of an alien, long dead." apply_image_decorations = FALSE apply_material_decorations = FALSE + if(ARCHAEO_SHELL) //fossil shell new_item = new /obj/item/fossil/shell(src.loc) @@ -386,67 +416,70 @@ apply_material_decorations = FALSE if(prob(10)) apply_image_decorations = TRUE + if(ARCHAEO_PLANT) //fossil plant new_item = new /obj/item/fossil/plant(src.loc) item_type = new_item.name - additional_desc = "A fossilised shred of alien plant matter." + additional_desc = "A fossilised shred of alien plant matter. " + span_bold("The genetic material inside would allow for seed extraction.") //A hint to give this to xenobotany. apply_image_decorations = FALSE apply_material_decorations = FALSE apply_prefix = FALSE if(ARCHAEO_REMAINS_HUMANOID) //humanoid remains apply_prefix = FALSE - item_type = "humanoid [pick("remains","skeleton")]" + item_type = "humanoid organ]" icon = 'icons/effects/blood.dmi' icon_state = "remains" - additional_desc = pick("They appear almost human.",\ - "They are contorted in a most gruesome way.",\ - "They look almost peaceful.",\ - "The bones are yellowing and old, but remarkably well preserved.",\ - "The bones are scored by numerous burns and partially melted.",\ - "The are battered and broken, in some cases less than splinters are left.",\ - "The mouth is wide open in a death rictus, the victim would appear to have died screaming.") apply_image_decorations = FALSE apply_material_decorations = FALSE + + //We get a list of random internal organs and spawn it. Yes. You can get a still beating heart. Xenoarch is spooky. + var/possible_object_paths = list() + possible_object_paths |= subtypesof(/obj/item/organ/internal) + possible_object_paths |= list(/obj/item/organ/internal/mmi_holder, /obj/item/organ/internal/stack/vox) + var/new_organ = pick(possible_object_paths) + new_item = new new_organ(src.loc) + if(ARCHAEO_REMAINS_ROBOT) //robot remains apply_prefix = FALSE - item_type = "[pick("mechanical","robotic","cyborg")] [pick("remains","chassis","debris")]" + item_type = "Alien cybernetic pod" icon = 'icons/mob/robots.dmi' icon_state = "remainsrobot" - additional_desc = pick("Almost mistakeable for the remains of a modern cyborg.",\ - "They are barely recognisable as anything other than a pile of waste metals.",\ - "It looks like the battered remains of an ancient robot chassis.",\ - "The chassis is rusting and old, but remarkably well preserved.",\ - "The chassis is scored by numerous burns and partially melted.",\ - "The chassis is battered and broken, in some cases only chunks of metal are left.",\ - "A pile of wires and crap metal that looks vaguely robotic.") apply_image_decorations = FALSE apply_material_decorations = FALSE + new_item = new /obj/structure/ghost_pod/manual/lost_drone/dogborg(src.loc) //We find a lost drone pod! if(ARCHAEO_REMAINS_XENO) //xenos remains apply_prefix = FALSE - item_type = "alien [pick("remains","skeleton")]" - icon = 'icons/effects/blood.dmi' - icon_state = "remainsxeno" - additional_desc = pick("It looks vaguely reptilian, but with more teeth.",\ - "They are faintly unsettling.",\ + item_type = "alien plasma organ" + secondary_item_type = "alien gland" + additional_desc = pick("The organ pulses and writhes.",\ + "The mass of flesh is unsettling.",\ "There is a faint aura of unease about them.",\ - "The bones are yellowing and old, but remarkably well preserved.",\ - "The bones are scored by numerous burns and partially melted.",\ - "The are battered and broken, in some cases less than splinters are left.",\ - "This creature would have been twisted and monstrous when it was alive.",\ "It doesn't look human.") apply_image_decorations = FALSE apply_material_decorations = FALSE + var/list/possible_plasma_vessel = list(/obj/item/organ/internal/xenos/plasmavessel, + /obj/item/organ/internal/xenos/plasmavessel/queen, + /obj/item/organ/internal/xenos/plasmavessel/sentinel, + /obj/item/organ/internal/xenos/plasmavessel/hunter) + var/list/possible_organ = list(/obj/item/organ/internal/xenos/acidgland, + /obj/item/organ/internal/xenos/hivenode, + /obj/item/organ/internal/xenos/resinspinner) + + var/new_vessel = pick(possible_plasma_vessel) + var/new_organ = pick(possible_organ) + new_item = new new_vessel(src.loc) + secondary_item = new new_organ(src.loc) if(ARCHAEO_GASMASK) //gas mask - if(prob(25)) + if(prob(50)) new_item = new /obj/item/clothing/mask/gas/poltergeist(src.loc) LAZYSET(new_item.origin_tech, TECH_ARCANE, 1) else - new_item = new /obj/item/clothing/mask/gas(src.loc) + new_item = new /obj/item/clothing/mask/gas/voice(src.loc) if(prob(40)) new_item.color = rgb(rand(0,255),rand(0,255),rand(0,255)) if(ARCHAEO_ALIEN_ITEM) @@ -454,7 +487,7 @@ apply_prefix = FALSE apply_material_decorations = FALSE - var/list/alien_stuff = list( + var/list/alien_tool = list( /obj/item/multitool/alien, /obj/item/stack/cable_coil/alien, /obj/item/tool/crowbar/alien, @@ -471,46 +504,44 @@ /obj/item/surgical/scalpel/alien, /obj/item/surgical/surgicaldrill/alien, /obj/item/cell/device/weapon/recharge/alien, + ) + var/list/alien_clothes = list( /obj/item/clothing/suit/armor/alien, /obj/item/clothing/head/helmet/alien, - /obj/item/clothing/head/psy_crown/wrath - ) + /obj/item/clothing/head/psy_crown/wrath, + /obj/item/clothing/head/psy_crown/gluttony, - var/new_type = pick(alien_stuff) - new_item = new new_type(src.loc) + ) + var/new_tool = pick(alien_tool) + var/new_clothes = pick(alien_clothes) + new_item = new new_tool(src.loc) + secondary_item = new new_clothes(src.loc) + item_type = new_item.name + secondary_item_type = secondary_item.name + secondary_item_desc = "" LAZYSET(new_item.origin_tech, TECH_ARCANE, 2) LAZYSET(new_item.origin_tech, TECH_PRECURSOR, 1) - item_type = new_item.name if(ARCHAEO_ALIEN_BOAT) // Alien boats. - apply_prefix = FALSE - var/new_boat_mat = pickweight(list( - MAT_WOOD = 100, - MAT_SIFWOOD = 200, - MAT_STEEL = 60, - MAT_URANIUM = 14, - MAT_MARBLE = 16, - MAT_GOLD = 20, - MAT_SILVER = 24, - MAT_PLASTEEL = 10, - MAT_TITANIUM = 6, - MAT_IRON = 30, - MAT_PHORON = 4, - MAT_VERDANTIUM = 2, - MAT_DIAMOND = 4, - MAT_DURASTEEL = 2, - MAT_MORPHIUM = 2, - MAT_SUPERMATTER = 1 - )) - var/list/alien_stuff = list( + var/list/boat_types = list( /obj/vehicle/boat, /obj/vehicle/boat/dragon ) - if(prob(30)) - new /obj/item/oar(src.loc, new_boat_mat) - var/new_type = pick(alien_stuff) - new_item = new new_type(src.loc, new_boat_mat) + apply_prefix = FALSE + var/possible_object_paths = list() + possible_object_paths |= subtypesof(/datum/material) + var/new_boat_mat = "MAT_STEEL" + for(var/x=1;x<=5;x++) //You got 5 chances to hit a metal that is NOT banned. + var/datum/material/picked_metal = pick(possible_object_paths) //We select + if(picked_metal in banned_materials) + continue + else + new_boat_mat = "[picked_metal.name]" //set_material requires NAME. + break + new /obj/item/oar(src.loc, new_boat_mat) + var/obj/vehicle/boat/new_boat = pick(boat_types) + new_item = new new_boat(src.loc, new_boat_mat) item_type = new_item.name if(ARCHAEO_IMPERION_CIRCUIT) @@ -532,7 +563,7 @@ apply_image_decorations = TRUE if(prob(25)) apply_material_decorations = FALSE - new_item = new /obj/item/telecube/randomized(src.loc) + new_item = new /obj/item/telecube/randomized/mated(src.loc) item_type = new_item.name if(ARCHAEO_BATTERY) @@ -561,21 +592,33 @@ new_item = new /obj/item/reagent_containers/syringe(src.loc) var/obj/item/reagent_containers/syringe/S = new_item - S.volume = 30 + S.volume = 15 //If S hasn't initialized yet, S.reagents will be null. //However, in that case Initialize will set the maximum volume to the volume for us, so we don't need to do anything. - S.reagents?.maximum_volume = 30 - + S.reagents?.maximum_volume = 15 item_type = new_item.name + //Taken from hydroponics/seed.dm...This should be a global list at some point and reworked in both places. + var/list/banned_chems = list( + REAGENT_ID_ADMINORDRAZINE, + REAGENT_ID_NUTRIMENT, + REAGENT_ID_MACROCILLIN, + REAGENT_ID_MICROCILLIN, + REAGENT_ID_NORMALCILLIN, + REAGENT_ID_MAGICDUST + ) + var/additional_chems = 5 //5 random chems added to the syringe! 15u of RANDOM stuff! (I tried to keep this 30, but this was...Horribly bugged. There is no icon_state for 16-30, so the icon was invisible when filled.) + for(var/x=1;x<=additional_chems;x++) + var/new_chem = pick(SSchemistry.chemical_reagents) + if(new_chem in banned_chems) + continue + banned_chems += new_chem + S.reagents.add_reagent(new_chem, 3) if(ARCHAEO_RING) // Ring. if(prob(15)) apply_prefix = FALSE - if(prob(40)) - apply_image_decorations = TRUE - if(prob(25)) - apply_material_decorations = FALSE + apply_image_decorations = TRUE //It's a ring. Let's just allow you to have fancy decorations on it. new_item = new /obj/item/clothing/accessory/ring/material(src.loc) item_type = new_item.name @@ -592,25 +635,18 @@ new_item.name = pick("great-club","club","billyclub","mace","tenderizer","maul","bat") item_type = new_item.name + if(istype(new_item, /obj/item/material)) - var/new_item_mat = pickweight(list( - MAT_STEEL = 80, - MAT_WOOD = 20, - MAT_SIFWOOD = 40, - MAT_URANIUM = 14, - MAT_MARBLE = 16, - MAT_GOLD = 20, - MAT_SILVER = 24, - MAT_PLASTEEL = 10, - MAT_TITANIUM = 6, - MAT_IRON = 30, - MAT_PHORON = 4, - MAT_VERDANTIUM = 2, - MAT_DIAMOND = 4, - MAT_DURASTEEL = 2, - MAT_MORPHIUM = 2, - MAT_SUPERMATTER = 1 - )) + var/possible_object_paths = list() + possible_object_paths |= subtypesof(/datum/material) + var/new_item_mat = "MAT_STEEL" + for(var/x=1;x<=5;x++) //You got 5 chances to hit a metal that is NOT banned. + var/datum/material/picked_metal = pick(possible_object_paths) //We select + if(picked_metal in banned_materials) + continue + else + new_item_mat = "[picked_metal.name]" //set_material requires NAME. + break var/obj/item/material/MW = new_item MW.applies_material_colour = TRUE MW.set_material(new_item_mat) @@ -621,17 +657,97 @@ else MW.force *= 0.3 - var/decorations = "" - if(apply_material_decorations) - source_material = pick("cordite","quadrinium","steel","titanium","aluminium","ferritic-alloy","plasteel","duranium") + if(istype(secondary_item, /obj/item/material)) + var/possible_object_paths = list() + possible_object_paths |= subtypesof(/datum/material) + var/new_item_mat = "MAT_STEEL" + for(var/x=1;x<=5;x++) + var/datum/material/picked_metal = pick(possible_object_paths) + if(picked_metal in banned_materials) + continue + else + new_item_mat = "[picked_metal.name]" + break + var/obj/item/material/MW = secondary_item + MW.applies_material_colour = TRUE + MW.set_material(new_item_mat) + if(istype(MW, /obj/item/material/twohanded)) + var/obj/item/material/twohanded/TH = MW + TH.force_unwielded *= 0.7 + TH.force_wielded *= 0.5 + else + MW.force *= 0.3 + //Why is ring/material and item/material two different things (and have the same /datum/material var) instead of datum/material being on /obj ? Hell if I know. Someone should fix that eventually. Outside of the scope of this PR. + if(istype(new_item, /obj/item/clothing/accessory/ring/material)) + var/possible_object_paths = list() + possible_object_paths |= subtypesof(/datum/material) + var/new_item_mat = "MAT_STEEL" + for(var/x=1;x<=5;x++) //You got 5 chances to hit a metal that is NOT banned. + var/datum/material/picked_metal = pick(possible_object_paths) //We select + if(picked_metal in banned_materials) + continue + else + new_item_mat = "[picked_metal.name]" //set_material requires NAME. + break + var/obj/item/clothing/accessory/ring/material/MW = new_item + MW.set_material(new_item_mat) + + if(istype(secondary_item, /obj/item/clothing/accessory/ring/material)) + var/possible_object_paths = list() + possible_object_paths |= subtypesof(/datum/material) + var/new_item_mat = "MAT_STEEL" + for(var/x=1;x<=5;x++) + var/datum/material/picked_metal = pick(possible_object_paths) + if(picked_metal in banned_materials) + continue + else + new_item_mat = "[picked_metal.name]" + break + var/obj/item/clothing/accessory/ring/material/MW = secondary_item + MW.set_material(new_item_mat) + + var/decorations = "" + var/secondary_item_decorations = "" + if(apply_material_decorations) + source_material = pick("cordite","quadrinium","chromium","roentgenium","aluminium","ferritic-alloy","meitnerium","tin","hafnium","zirconium","duranium","an unidentifiable alloy","palladium","copper") + + //If we have a material that has a display_name, let's use that! If not, we'll use the random fancy sounding one above. if(istype(new_item, /obj/item/material)) var/obj/item/material/MW = new_item - source_material = MW.material.display_name + if(MW.material && MW.material.display_name) + source_material = MW.material.display_name + + if(istype(new_item, /obj/item/clothing/accessory/ring/material)) + var/obj/item/clothing/accessory/ring/material/MW = new_item + if(MW.material && MW.material.display_name) + source_material = MW.material.display_name + if(istype(new_item, /obj/vehicle/boat)) var/obj/vehicle/boat/B = new_item - source_material = B.material.display_name + if(B.material && B.material.display_name) + source_material = B.material.display_name + + //I split these apart. Above here is the primary item. Below here is the secondary item. + if(secondary_item) + if(istype(secondary_item, /obj/item/material)) + var/obj/item/material/SMW = secondary_item + if(SMW.material && SMW.material.display_name) + source_material = SMW.material.display_name + + if(istype(secondary_item, /obj/item/clothing/accessory/ring/material)) + var/obj/item/clothing/accessory/ring/material/SMW = secondary_item + if(SMW.material && SMW.material.display_name) + source_material = SMW.material.display_name + + if(istype(secondary_item, /obj/vehicle/boat)) + var/obj/vehicle/boat/SB = secondary_item + if(SB.material && SB.material.display_name) + source_material = SB.material.display_name + desc = "A [material_descriptor ? "[material_descriptor] " : ""][item_type] made of [source_material], all craftsmanship is of [pick("the lowest","low","average","high","the highest")] quality." + if(secondary_item) + secondary_item.desc = "A [material_descriptor ? "[material_descriptor] " : ""][secondary_item_type] made of [source_material], all craftsmanship is of [pick("the lowest","low","average","high","the highest")] quality." var/list/descriptors = list() if(prob(30)) @@ -654,8 +770,11 @@ decorations += "." if(decorations) desc += " " + decorations + if(secondary_item && secondary_item_decorations) + secondary_item.desc += " " + decorations var/engravings = "" + var/secondary_item_engravings = "" if(apply_image_decorations) engravings = "[pick("Engraved","Carved","Etched")] on the item is [pick("an image of","a frieze of","a depiction of")] \ [pick("an alien humanoid","an amorphic blob","a short, hairy being","a rodent-like creature","a robot","a primate","a reptilian alien","an unidentifiable object","a statue","a starship","unusual devices","a structure")] \ @@ -664,19 +783,30 @@ if(prob(50)) engravings += ", [pick("they seem to be enjoying themselves","they seem extremely angry","they look pensive","they are making gestures of supplication","the scene is one of subtle horror","the scene conveys a sense of desperation","the scene is completely bizarre")]" engravings += "." + if(secondary_item) + secondary_item_engravings += "." if(desc) desc += " " desc += engravings + if(secondary_item && secondary_item.desc) + desc += " " + secondary_item.desc += secondary_item_engravings if(apply_prefix) name = "[pick("Strange","Ancient","Alien","")] [item_type]" + if(secondary_item) + secondary_item.name = "[pick("Strange","Ancient","Alien","")] [secondary_item_type]" else name = item_type + if(secondary_item) + secondary_item.name = secondary_item_type if(desc) desc += " " desc += additional_desc + if(secondary_item && secondary_item.desc) + secondary_item.desc += secondary_item_desc if(!desc) desc = "This item is completely [pick("alien","bizarre")]." @@ -687,14 +817,15 @@ if(talkative) new_item.talking_atom = new(new_item) - var/list/new_tech - if(new_item.origin_tech) - new_tech = new_item.origin_tech.Copy() - else - new_tech = list() - new_tech[TECH_ARCANE] += 1 - new_tech[TECH_PRECURSOR] += 1 - new_item.origin_tech = new_tech + if("origin_tech" in new_item.vars) + var/list/new_tech + if(new_item.origin_tech) + new_tech = new_item.origin_tech.Copy() + else + new_tech = list() + new_tech[TECH_ARCANE] += 1 + new_tech[TECH_PRECURSOR] += 1 + new_item.origin_tech = new_tech if(become_anomalous) new_item.become_anomalous() @@ -702,8 +833,18 @@ var/turf/simulated/mineral/T = get_turf(new_item) if(istype(T)) T.last_find = new_item + if(secondary_item) //Is this part of a set? + if(talkative) + secondary_item.talking_atom = new(secondary_item) + LAZYINITLIST(secondary_item.origin_tech) + secondary_item.origin_tech[TECH_ARCANE] += 1 + secondary_item.origin_tech[TECH_PRECURSOR] += 1 + + if(become_anomalous) + secondary_item.become_anomalous() qdel(src) + return else if(talkative) src.talking_atom = new(src) @@ -723,7 +864,7 @@ /obj/item/archaeological_find/Destroy() if(src.is_anomalous()) var/datum/component/artifact_master/arti_mstr = GetComponent(/datum/component/artifact_master) - arti_mstr.RemoveComponent() + arti_mstr.ClearFromParent() if(!QDELETED(arti_mstr)) qdel(arti_mstr) diff --git a/code/modules/xenoarcheaology/finds/finds.dm b/code/modules/xenoarcheaology/finds/finds.dm index 8f30b0cb15..1249785e40 100644 --- a/code/modules/xenoarcheaology/finds/finds.dm +++ b/code/modules/xenoarcheaology/finds/finds.dm @@ -2,17 +2,11 @@ var/find_type = 0 //random according to the digsite type var/excavation_required = 0 //random 10 - 190 var/view_range = 40 //how close excavation has to come to show an overlay on the turf - var/clearance_range = 3 //how close excavation has to come to extract the item - //if excavation hits var/excavation_required exactly, it's contained find is extracted cleanly without the ore - var/prob_delicate = 90 //probability it requires an active suspension field to not insta-crumble - var/dissonance_spread = 1 //proportion of the tile that is affected by this find - //used in conjunction with analysis machines to determine correct suspension field type + var/prob_delicate = 0 //probability it requires an active suspension field to not insta-crumble. Set to 0 to nullify the need for suspension field. /datum/find/New(var/digsite, var/exc_req) excavation_required = exc_req find_type = get_random_find_type(digsite) - clearance_range = rand(4, 12) - dissonance_spread = rand(1500, 2500) / 100 /obj/item/strangerock name = "Strange rock" @@ -31,7 +25,7 @@ if(inside_item_type) switch(d100) if(51 to 100) //standard spawn logic 50% of the time - new /obj/item/archaeological_find(src, new_item_type = inside_item_type) + new /obj/item/archaeological_find(src, inside_item_type) if(21 to 50) // 30% chance new /obj/item/research_sample/common(src) if(6 to 20) // 15% chance @@ -39,7 +33,7 @@ if(1 to 5) // 5% chance new /obj/item/research_sample/rare(src) else //if something went wrong, somehow, generate the usual find - new /obj/item/archaeological_find(src, new_item_type = inside_item_type) + new /obj/item/archaeological_find(src, inside_item_type) else //if this strange rock isn't set to generate a find for whatever reason, create a sample 75% of the time (this shouldn't happen unless the rock is mapped in or adminspawned) switch(d100) if(76 to 100) @@ -54,13 +48,13 @@ return //do nothing /obj/item/strangerock/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/pickaxe/brush)) + if(istype(I, /obj/item/pickaxe)) //Whatever, if you use a hand pick it should work just like a brush. No reason for otherwise. var/obj/item/inside = locate() in src if(inside) inside.loc = get_turf(src) - visible_message(span_info("\The [src] is brushed away, revealing \the [inside].")) + visible_message(span_info("\The [src] is mined away, revealing \the [inside].")) else - visible_message(span_info("\The [src] is brushed away into nothing.")) + visible_message(span_info("\The [src] is mined away into nothing.")) qdel(src) return diff --git a/code/modules/xenoarcheaology/finds/finds_defines.dm b/code/modules/xenoarcheaology/finds/finds_defines.dm index d02022eb7e..d5f031022f 100644 --- a/code/modules/xenoarcheaology/finds/finds_defines.dm +++ b/code/modules/xenoarcheaology/finds/finds_defines.dm @@ -1,41 +1,59 @@ +/// This is the big file of various xenoarch spawns (what each digsite spawns), digsite spawn rates, and + +/// +/// This is a list of what the depth_scanner can show, depending on what get_responsive_reagent returns below. +/// var/global/list/responsive_carriers = list( REAGENT_ID_CARBON, REAGENT_ID_POTASSIUM, REAGENT_ID_HYDROGEN, REAGENT_ID_NITROGEN, + REAGENT_BLOOD, REAGENT_ID_MERCURY, REAGENT_ID_IRON, - REAGENT_ID_CHLORINE, - REAGENT_ID_PHOSPHORUS, REAGENT_ID_PHORON) +/// +/// This is a list of what the depth_scanner shows the user. In order with the above list. +/// +/// +/// If the get_responsive_reagent returns 'REAGENT_ID_CARBON' it will show up to the user as "Trace organic cells" +/// If the get_responsive_reagent returns "REAGENT_ID_CHLORINE" it will show up to the user as "Metamorphic/igneous rock composite" +/// var/global/list/finds_as_strings = list( - "Trace organic cells", - "Long exposure particles", - "Trace water particles", - "Crystalline structures", - "Metallic derivative", - "Metallic composite", - "Metamorphic/igneous rock composite", - "Metamorphic/sedimentary rock composite", - "Anomalous material") + "Trace organic cells", //Carbon + "Long exposure particles", //Potassium + "Trace water particles", //Hydrogen + "Crystalline structures", //Nitrogen + "Abnormal energy signatures", //Occult + "Metallic derivative", //Mercury + "Metallic composite", //Iron + "Anomalous material") //Phoron +/// +/// This is called when using the depth_scanner on an artifact tile. It tells you what artifact group type is contained inside. +/// Previously, we only used MERCURY, IRON, NITROGEN, POTASSIUM, CARBON, PHORON. Now, we expanded! +/// /proc/get_responsive_reagent(var/find_type) switch(find_type) - if(ARCHAEO_BOWL, ARCHAEO_URN, ARCHAEO_CUTLERY, ARCHAEO_STATUETTE, ARCHAEO_INSTRUMENT, ARCHAEO_HANDCUFFS, ARCHAEO_BEARTRAP, ARCHAEO_LIGHTER, ARCHAEO_BOX, ARCHAEO_GASTANK, ARCHAEO_PEN, ARCHAEO_UNKNOWN) + if(ARCHAEO_STATUETTE, ARCHAEO_INSTRUMENT, ARCHAEO_HANDCUFFS, ARCHAEO_BEARTRAP, ARCHAEO_LIGHTER, ARCHAEO_BOX, ARCHAEO_PEN, ARCHAEO_COIN, ARCHAEO_STOCKPARTS) return REAGENT_ID_MERCURY - if(ARCHAEO_COIN, ARCHAEO_KNIFE, ARCHAEO_TOOL, ARCHAEO_METAL, ARCHAEO_CLAYMORE, ARCHAEO_RODS, ARCHAEO_KATANA, ARCHAEO_LASER, ARCHAEO_GUN) + if(ARCHAEO_KNIFE, ARCHAEO_TOOL, ARCHAEO_METAL, ARCHAEO_CLAYMORE, ARCHAEO_KATANA, ARCHAEO_LASER, ARCHAEO_GUN, ARCHAEO_REMAINS_ROBOT) return REAGENT_ID_IRON - if(ARCHAEO_CRYSTAL, ARCHAEO_SHARD, ARCHAEO_SOULSTONE) + if(ARCHAEO_CRYSTAL) return REAGENT_ID_NITROGEN - if(ARCHAEO_CULTBLADE, ARCHAEO_TELEBEACON, ARCHAEO_CULTROBES, ARCHAEO_STOCKPARTS) + if(ARCHAEO_CULTBLADE, ARCHAEO_SOULSTONE, ARCHAEO_TOME) + return REAGENT_BLOOD + if(ARCHAEO_CULTBLADE, ARCHAEO_TELEBEACON, ARCHAEO_CULTROBES) return REAGENT_ID_POTASSIUM - if(ARCHAEO_FOSSIL, ARCHAEO_SHELL, ARCHAEO_PLANT, ARCHAEO_REMAINS_HUMANOID, ARCHAEO_REMAINS_ROBOT, ARCHAEO_REMAINS_XENO, ARCHAEO_GASMASK) + if(ARCHAEO_BOWL, ARCHAEO_URN, ARCHAEO_GASTANK, ARCHAEO_GASMASK) //Moisture or humidity in some way. + return REAGENT_ID_HYDROGEN + if(ARCHAEO_FOSSIL, ARCHAEO_SHELL, ARCHAEO_PLANT, ARCHAEO_REMAINS_HUMANOID, ARCHAEO_REMAINS_XENO) return REAGENT_ID_CARBON return REAGENT_ID_PHORON /proc/get_random_digsite_type() - return pick(100;DIGSITE_GARDEN, 95;DIGSITE_ANIMAL, 90;DIGSITE_HOUSE, 85;DIGSITE_TECHNICAL, 85;DIGSITE_MIDDEN, 80;DIGSITE_TEMPLE, 75;DIGSITE_WAR) + return pick(100;DIGSITE_GARDEN, 90;DIGSITE_HOUSE, 85;DIGSITE_TECHNICAL, 85;DIGSITE_MIDDEN, 80;DIGSITE_TEMPLE, 75;DIGSITE_WAR) /proc/get_random_find_type(var/digsite) . = 0 @@ -46,17 +64,10 @@ var/global/list/finds_as_strings = list( 25;ARCHAEO_SHELL, 25;ARCHAEO_FOSSIL, 5;ARCHAEO_BEARTRAP) - if(DIGSITE_ANIMAL) - . = pick( - 100;ARCHAEO_FOSSIL, - 50;ARCHAEO_SHELL, - 50;ARCHAEO_PLANT, - 25;ARCHAEO_BEARTRAP) if(DIGSITE_HOUSE) . = pick( 100;ARCHAEO_BOWL, 100;ARCHAEO_URN, - 100;ARCHAEO_CUTLERY, 100;ARCHAEO_STATUETTE, 100;ARCHAEO_INSTRUMENT, 100;ARCHAEO_PEN, @@ -66,8 +77,6 @@ var/global/list/finds_as_strings = list( 75;ARCHAEO_GASMASK, 75;ARCHAEO_COIN, 75;ARCHAEO_UNKNOWN, - 50;ARCHAEO_SHARD, - 50;ARCHAEO_RODS, 25;ARCHAEO_METAL, 5;ARCHAEO_ALIEN_BOAT) if(DIGSITE_TECHNICAL) @@ -79,33 +88,26 @@ var/global/list/finds_as_strings = list( 100;ARCHAEO_TOOL, 100;ARCHAEO_STOCKPARTS, 100;ARCHAEO_ALIEN_ITEM, - 75;ARCHAEO_SHARD, - 75;ARCHAEO_RODS, 75;ARCHAEO_UNKNOWN, 50;ARCHAEO_HANDCUFFS, 50;ARCHAEO_BEARTRAP, - 1;ARCHAEO_IMPERION_CIRCUIT) + 50;ARCHAEO_IMPERION_CIRCUIT) //They're not even that USEFUL. Why was it a 1 in 1000 chance? if(DIGSITE_TEMPLE) . = pick( 200;ARCHAEO_CULTROBES, 200;ARCHAEO_STATUETTE, - 100;ARCHAEO_URN, - 100;ARCHAEO_BOWL, - 100;ARCHAEO_KNIFE, - 100;ARCHAEO_CRYSTAL, + 75;ARCHAEO_SOULSTONE, 75;ARCHAEO_CULTBLADE, + 75;ARCHAEO_TOME, + 50;ARCHAEO_URN, + 50;ARCHAEO_BOWL, + 50;ARCHAEO_KNIFE, + 50;ARCHAEO_CRYSTAL, 50;ARCHAEO_RING, - 50;ARCHAEO_SOULSTONE, 50;ARCHAEO_UNKNOWN, 25;ARCHAEO_HANDCUFFS, - 25;ARCHAEO_BEARTRAP, 10;ARCHAEO_KATANA, - 10;ARCHAEO_CLAYMORE, - 10;ARCHAEO_CLUB, - 10;ARCHAEO_SHARD, - 10;ARCHAEO_RODS, - 10;ARCHAEO_METAL, - 10;ARCHAEO_GASMASK) + 10;ARCHAEO_METAL) if(DIGSITE_WAR) . = pick( 100;ARCHAEO_GUN, diff --git a/code/modules/xenoarcheaology/finds/special.dm b/code/modules/xenoarcheaology/finds/special.dm index 8eac756fa0..5c5a06c420 100644 --- a/code/modules/xenoarcheaology/finds/special.dm +++ b/code/modules/xenoarcheaology/finds/special.dm @@ -8,8 +8,22 @@ /obj/item/reagent_containers/glass/replenishing/Initialize() . = ..() START_PROCESSING(SSobj, src) - spawning_id = pick(REAGENT_ID_BLOOD,REAGENT_ID_HOLYWATER,REAGENT_ID_LUBE,REAGENT_ID_STOXIN,REAGENT_ID_ETHANOL,REAGENT_ID_ICE,REAGENT_ID_GLYCEROL,REAGENT_ID_FUEL,REAGENT_ID_CLEANER) - + //Taken from hydroponics/seed.dm...This should be a global list at some point and reworked in both places. + var/list/banned_chems = list( + REAGENT_ID_ADMINORDRAZINE, + REAGENT_ID_NUTRIMENT, + REAGENT_ID_MACROCILLIN, + REAGENT_ID_MICROCILLIN, + REAGENT_ID_NORMALCILLIN, + REAGENT_ID_MAGICDUST + ) + for(var/x=1;x<=10;x++) //You got 10 chances to hit a reagent that is NOT banned. + var/new_chem = pick(SSchemistry.chemical_reagents) + if(new_chem in banned_chems) + continue + else + spawning_id = new_chem + break /obj/item/reagent_containers/glass/replenishing/process() reagents.add_reagent(spawning_id, 0.3) @@ -82,7 +96,9 @@ //use up stored charges if(charges >= 10) charges -= 10 - new /obj/effect/spider/eggcluster(pick(RANGE_TURFS(1,src))) + var/new_object = pick(/obj/item/soulstone, /obj/item/melee/artifact_blade, /obj/item/book/tome, /obj/item/clothing/head/helmet/space/cult, /obj/item/clothing/suit/space/cult, /obj/structure/constructshell) + new new_object(pick(RANGE_TURFS(1,src))) + playsound(src, 'sound/effects/ghost.ogg', 50, 1, -3) if(charges >= 3) if(prob(5)) @@ -194,10 +210,14 @@ 'sound/hallucinations/turn_around1.ogg',\ 'sound/hallucinations/turn_around2.ogg',\ ), 50, 1, -3) + to_chat(M, span_cult("The [src] phases right into your body, your entire form feeling cold and numb!")) //You just had a ghost possess / take residence you...YEAH, it's going to be alarming! + M.visible_message(span_cult("[M]'s body glows bright red for a moment as glyphs spread across their form!")) //Let's try something fancy. M.Sleeping(rand(5, 10)) + src.loc = null else STOP_PROCESSING(SSobj, src) + qdel(src) //Let's not just sit in nullspace forever, yeah? /obj/effect/shadow_wight/Bump(var/atom/obstacle) to_chat(obstacle, span_red("You feel a chill run down your spine!")) diff --git a/code/modules/xenoarcheaology/finds/talking.dm b/code/modules/xenoarcheaology/finds/talking.dm index c2b13cf933..4c4f809735 100644 --- a/code/modules/xenoarcheaology/finds/talking.dm +++ b/code/modules/xenoarcheaology/finds/talking.dm @@ -111,5 +111,5 @@ var/list/listening = viewers(holder_atom) for(var/mob/M in listening) - to_chat(M, "[icon2html(holder_atom,M.client)] [holder_atom] reverberates, \"[span_blue(msg)]\"") + to_chat(M, "[icon2html(holder_atom,M.client)] " + span_bold("[holder_atom] reverberates") +" , \"[span_blue(msg)]\"") last_talk_time = world.time diff --git a/code/modules/xenoarcheaology/sampling.dm b/code/modules/xenoarcheaology/sampling.dm index ff3e1df5c0..75e7378aa2 100644 --- a/code/modules/xenoarcheaology/sampling.dm +++ b/code/modules/xenoarcheaology/sampling.dm @@ -55,7 +55,7 @@ for(var/datum/find/F in container.finds) var/responsive_reagent = get_responsive_reagent(F.find_type) - find_presence[responsive_reagent] = F.dissonance_spread + find_presence[responsive_reagent] = 25 //Just making this phoron because this this feature was axed 8 years ago. var/total_presence = 0 for(var/carrier in find_presence) diff --git a/code/modules/xenoarcheaology/tools/ano_device_battery.dm b/code/modules/xenoarcheaology/tools/ano_device_battery.dm index 5f40d9deb5..475bda21ce 100644 --- a/code/modules/xenoarcheaology/tools/ano_device_battery.dm +++ b/code/modules/xenoarcheaology/tools/ano_device_battery.dm @@ -1,3 +1,7 @@ +/// NOTE: +/// If you are adding an artifact, I would highly recommend thinking of HOW it can be utilized by the harvester first and foremost. +/// If you need assistance in getting it to work with the harvester, I suggest looking at animate_anomaly.dm (for a full incorporation) and electric_field (for a partial incoporation) + /obj/item/anobattery name = "Anomaly power battery" icon = 'icons/obj/xenoarchaeology.dmi' @@ -37,11 +41,16 @@ var/obj/item/anobattery/inserted_battery var/turf/archived_loc var/energy_consumed_on_touch = 100 + var/mob/last_user_touched /obj/item/anodevice/New() ..() START_PROCESSING(SSobj, src) +/obj/item/anodevice/equipped(var/mob/user, var/slot) + last_user_touched = user + ..() + /obj/item/anodevice/attackby(var/obj/I as obj, var/mob/user as mob) if(istype(I, /obj/item/anobattery)) if(!inserted_battery) @@ -156,7 +165,7 @@ //consume power equal to time passed inserted_battery.use_power(world.time - last_process) - inserted_battery.battery_effect.DoEffectTouch(holder) + inserted_battery.battery_effect.DoEffectTouch(last_user_touched) //Yes. This means if you give it something REALLY bad, it'll keep hitting you as if you're touching it. Be responsible with eldritch magic. else if(inserted_battery.battery_effect.effect == EFFECT_PULSE) inserted_battery.battery_effect.chargelevel = inserted_battery.battery_effect.chargelevelmax diff --git a/code/modules/xenoarcheaology/tools/artifact_analyser.dm b/code/modules/xenoarcheaology/tools/artifact_analyser.dm index db713bb57a..5515f775fa 100644 --- a/code/modules/xenoarcheaology/tools/artifact_analyser.dm +++ b/code/modules/xenoarcheaology/tools/artifact_analyser.dm @@ -5,6 +5,7 @@ icon_state = "isolator" anchored = TRUE density = TRUE + bubble_icon = "science" var/scan_in_progress = 0 var/scan_num = 0 var/obj/scanned_obj diff --git a/code/modules/xenoarcheaology/tools/artifact_harvester.dm b/code/modules/xenoarcheaology/tools/artifact_harvester.dm index 2c4debe9f4..3b4ce36fdc 100644 --- a/code/modules/xenoarcheaology/tools/artifact_harvester.dm +++ b/code/modules/xenoarcheaology/tools/artifact_harvester.dm @@ -1,6 +1,6 @@ /obj/machinery/artifact_harvester name = "Exotic Particle Harvester" - icon = 'icons/obj/virology_vr.dmi' //VOREStation Edit + icon = 'icons/obj/virology_vr.dmi' icon_state = "incubator" //incubator_on anchored = TRUE density = TRUE @@ -9,10 +9,12 @@ use_power = USE_POWER_IDLE var/harvesting = 0 var/obj/item/anobattery/inserted_battery - var/obj/machinery/artifact/cur_artifact + var/obj/cur_artifact var/obj/machinery/artifact_scanpad/owned_scanner = null var/last_process = 0 + bubble_icon = "science" +/// If you want it to load smoothly, set it's dir to wherever the scanpad is! /obj/machinery/artifact_harvester/Initialize() . = ..() owned_scanner = locate(/obj/machinery/artifact_scanpad) in get_step(src, dir) @@ -77,7 +79,7 @@ switch(action) if("harvest") - harvest() + harvest(ui.user) return TRUE if("stopharvest") @@ -116,7 +118,7 @@ return TRUE -/obj/machinery/artifact_harvester/proc/harvest() +/obj/machinery/artifact_harvester/proc/harvest(mob/user) if(!inserted_battery) atom_say("Cannot harvest. No battery inserted.") return @@ -127,10 +129,11 @@ //locate artifact on analysis pad cur_artifact = null var/articount = 0 - var/obj/machinery/artifact/analysed - for(var/obj/machinery/artifact/A in get_turf(owned_scanner)) + var/obj/analysed + for(var/obj/A in get_turf(owned_scanner)) analysed = A - articount++ + if(A.is_anomalous()) + articount++ if(articount <= 0) atom_say("Cannot harvest. No noteworthy energy signature isolated.") @@ -147,15 +150,30 @@ if(analysed) cur_artifact = analysed - //if both effects are active, we can't harvest either - var/list/active_effects = cur_artifact.artifact_master.get_active_effects() + var/list/active_effects //This will be populated when we see if it has the artifact component or the artifact_master var - if(active_effects.len > 1) - atom_say("Cannot harvest. Source is emitting conflicting energy signatures.") - return - else if(!active_effects.len) + var/datum/component/artifact_master/ScannedMaster = analysed.GetComponent(/datum/component/artifact_master) + if(istype(ScannedMaster)) + active_effects = ScannedMaster.get_all_effects() + else atom_say("Cannot harvest. No energy emitting from source.") return + var/effects_to_show = active_effects + for(var/datum/artifact_effect/selected_effect in effects_to_show) //We check to see if we're harvestable. If not, remove it from the list. + if(selected_effect.harvestable == FALSE) + effects_to_show -= selected_effect + + if(!active_effects.len) + atom_say("Cannot harvest. No harvestable energy emitting from source.") + return + + var/artifact_selection = tgui_input_list(user, "Which effect do you wish to harvest?", "Effect Selection", effects_to_show) + var/datum/artifact_effect/selected_effect + if(artifact_selection && (artifact_selection in effects_to_show)) + selected_effect = artifact_selection + else + atom_say("No selection made. Shutting down harvester.") + return //see if we can clear out an old effect //delete it when the ids match to account for duplicate ids having different effects @@ -165,25 +183,21 @@ // var/datum/artifact_effect/source_effect - var/datum/artifact_effect/active_effect = active_effects[1] //if we already have charge in the battery, we can only recharge it from the source artifact if(inserted_battery.stored_charge > 0) + to_world("Line 185") var/battery_matches_primary_id = 0 - if(inserted_battery.battery_effect && inserted_battery.battery_effect.artifact_id == cur_artifact.artifact_master.artifact_id) + if(inserted_battery.battery_effect && inserted_battery.battery_effect.artifact_id == ScannedMaster.artifact_id) battery_matches_primary_id = 1 - if(battery_matches_primary_id && active_effect.activated) + if(battery_matches_primary_id && selected_effect) //we're good to recharge the primary effect! - source_effect = active_effect + source_effect = selected_effect if(!source_effect) atom_say("Cannot harvest. Battery is charged with a different energy signature.") else - //we're good to charge either - if(active_effect.activated) - //charge the primary effect - source_effect = active_effect - + source_effect = selected_effect if(source_effect) harvesting = 1 @@ -208,6 +222,8 @@ inserted_battery.stored_charge = 0 /obj/machinery/artifact_harvester/process() + if(harvesting == 0) + return if(stat & (NOPOWER|BROKEN)) return @@ -250,7 +266,7 @@ inserted_battery.battery_effect.ToggleActivate() src.visible_message(span_bold("[name]") + " states, \"Battery dump completed.\"") icon_state = "incubator" - +/* //This is old and unused. /obj/machinery/artifact_harvester/Topic(href, href_list) if (href_list["harvest"]) @@ -266,7 +282,7 @@ cur_artifact = null var/articount = 0 var/obj/machinery/artifact/analysed - for(var/obj/machinery/artifact/A in get_turf(owned_scanner)) + for(var/obj/A in get_turf(owned_scanner)) analysed = A articount++ @@ -284,7 +300,10 @@ cur_artifact = analysed //if both effects are active, we can't harvest either - var/list/active_effects = cur_artifact.artifact_master.get_active_effects() + var/datum/component/artifact_master/ScannedMaster = analysed.GetComponent(/datum/component/artifact_master) + if(ScannedMaster && istype(ScannedMaster)) + active_effects = ScannedMaster.get_all_effects() + var/list/active_effects = ScannedMaster.artifact_id.get_active_effects() if(active_effects.len > 1) src.visible_message(span_bold("[src]") + " states, \"Cannot harvest. Source is emitting conflicting energy signatures.\"") @@ -381,3 +400,4 @@ usr.unset_machine(src) updateDialog() +*/ diff --git a/code/modules/xenoarcheaology/tools/suspension_generator.dm b/code/modules/xenoarcheaology/tools/suspension_generator.dm index ed19f72e26..0ee13036bc 100644 --- a/code/modules/xenoarcheaology/tools/suspension_generator.dm +++ b/code/modules/xenoarcheaology/tools/suspension_generator.dm @@ -1,6 +1,6 @@ /obj/machinery/suspension_gen name = "suspension field generator" - desc = "It has stubby bolts up against it's treads for stabilising." + desc = "It has stubby bolts up against it's treads for stabilising. Used to be required for artifact removal but now merely works as a monster deterrant." icon = 'icons/obj/xenoarchaeology.dmi' icon_state = "suspension" density = 1 diff --git a/code/modules/xenoarcheaology/tools/tools.dm b/code/modules/xenoarcheaology/tools/tools.dm index 1e56399def..50256b00a2 100644 --- a/code/modules/xenoarcheaology/tools/tools.dm +++ b/code/modules/xenoarcheaology/tools/tools.dm @@ -43,6 +43,8 @@ var/last_scan_time = 0 var/scan_delay = 25 + var/last_repopulation_time = 0 + var/repopulation_delay = 600 //Anti spam. /obj/item/ano_scanner/attack_self(var/mob/living/user) interact(user) @@ -77,8 +79,16 @@ else SSxenoarch.digsite_spawning_turfs.Remove(T) + if(SSxenoarch && ((nearestTargetDist == -1) || (nearestSimpleTargetDist == -1)) && user.z && (world.time - last_repopulation_time >= repopulation_delay)) + if(user.z in using_map.xenoarch_exempt_levels) //We found no artifacts and our Z level is not spawn exempt. Time for random generation. + //Yeah we do nothing here. I tried to make the above a !user.z ... but VSC compiler screeched at me. + else + last_repopulation_time = world.time + to_chat(user, "The [src] beeps and buzzes, a warning popping up on screen stating 'No artifacts detected on current wavelength. Swapping to different wavelength. Please try scanning momentarily.'") + SSxenoarch.continual_generation(user) + if(nearestTargetDist >= 0) - to_chat(user, "Exotic energy detected on wavelength '[nearestTargetId]' in a radius of [nearestTargetDist]m[nearestSimpleTargetDist > 0 ? "; small anomaly detected in a radius of [nearestSimpleTargetDist]m" : ""]") + to_chat(user, "Large artifact energy signature detected on wavelength '[nearestTargetId]' in a radius of [nearestTargetDist]m[nearestSimpleTargetDist > 0 ? "; small anomaly detected in a radius of [nearestSimpleTargetDist]m" : ""]") else if(nearestSimpleTargetDist >= 0) to_chat(user, "Small anomaly detected in a radius of [nearestSimpleTargetDist]m.") else @@ -103,9 +113,7 @@ var/time = "" var/coords = "" var/depth = "" - var/clearance = 0 var/record_index = 1 - var/dissonance_spread = 1 var/material = "unknown" /obj/item/depth_scanner/proc/scan_atom(var/mob/user, var/atom/A) @@ -125,8 +133,7 @@ //find the first artifact and store it if(M.finds.len) var/datum/find/F = M.finds[1] - D.depth = "[F.excavation_required - F.clearance_range] - [F.excavation_required]" - D.clearance = F.clearance_range + D.depth = "[F.excavation_required]" D.material = get_responsive_reagent(F.find_type) positive_locations.Add(D) @@ -144,8 +151,6 @@ //these values are arbitrary D.depth = rand(150, 200) - D.clearance = rand(10, 50) - D.dissonance_spread = rand(750, 2500) / 100 positive_locations.Add(D) @@ -172,8 +177,6 @@ "time" = current.time, "coords" = current.coords, "depth" = current.depth, - "clearance" = current.clearance, - "dissonance_spread" = current.dissonance_spread, "index" = current.record_index, ) data["current"]["material"] = "Unknown" diff --git a/code/modules/xenoarcheaology/tools/tools_pickaxe.dm b/code/modules/xenoarcheaology/tools/tools_pickaxe.dm index caffe30682..54beff3086 100644 --- a/code/modules/xenoarcheaology/tools/tools_pickaxe.dm +++ b/code/modules/xenoarcheaology/tools/tools_pickaxe.dm @@ -165,7 +165,7 @@ icon_state = "excavationdrill2" item_state = "syringe_0" excavation_amount = 15 - digspeed = 30 + digspeed = 10 desc = "Advanced archaeological drill combining ultrasonic excitation and bluespace manipulation to provide extreme precision. The tip is adjustable from 1 to 30 cm." drill_sound = 'sound/weapons/thudswoosh.ogg' drill_verb = "drilling" @@ -174,8 +174,8 @@ attack_verb = list("drilled") /obj/item/pickaxe/excavationdrill/attack_self(mob/user as mob) - var/depth = tgui_input_number(usr, "Put the desired depth (1-30 centimeters).", "Set Depth", 30, 30, 1) - if(depth>30 || depth<1) + var/depth = tgui_input_number(usr, "Put the desired depth (1-60 centimeters).", "Set Depth", excavation_amount, 60, 1) + if(depth>60 || depth<1) to_chat(user, span_notice("Invalid depth.")) return excavation_amount = depth @@ -191,7 +191,7 @@ icon_state = "excavationdrill3" if(21 to 25) icon_state = "excavationdrill4" - if(25 to 30) + if(26 to 60) icon_state = "excavationdrill5" //The other 2 sprites are comically long. Let's just cut it at 5. /obj/item/pickaxe/excavationdrill/examine(mob/user) diff --git a/tgui/packages/tgui/interfaces/XenoarchDepthScanner.tsx b/tgui/packages/tgui/interfaces/XenoarchDepthScanner.tsx index 186c05f7e2..d0d94ea1b4 100644 --- a/tgui/packages/tgui/interfaces/XenoarchDepthScanner.tsx +++ b/tgui/packages/tgui/interfaces/XenoarchDepthScanner.tsx @@ -8,8 +8,6 @@ type Data = { time: string; coords: string; depth: number; - clearance: number; - dissonance_spread: number; material: string; }; positive_locations: { index: string; time: string; coords: string }[]; @@ -45,12 +43,6 @@ export const XenoarchDepthScanner = (props) => { {current.depth} cm - - {current.clearance} cm - - - {current.dissonance_spread} - {current.material} diff --git a/vorestation.dme b/vorestation.dme index 761de2a81b..895acf1a84 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -212,6 +212,7 @@ #include "code\_helpers\traits.dm" #include "code\_helpers\turfs.dm" #include "code\_helpers\type2type.dm" +#include "code\_helpers\typelists.dm" #include "code\_helpers\unsorted.dm" #include "code\_helpers\unsorted_vr.dm" #include "code\_helpers\verbs.dm" @@ -4357,38 +4358,26 @@ #include "code\modules\xenoarcheaology\artifacts\predefined\_predefined.dm" #include "code\modules\xenoarcheaology\artifacts\predefined\hungry_statue.dm" #include "code\modules\xenoarcheaology\effects\animate_anomaly.dm" -#include "code\modules\xenoarcheaology\effects\badfeeling.dm" +#include "code\modules\xenoarcheaology\effects\atmospheric.dm" #include "code\modules\xenoarcheaology\effects\berserk.dm" -#include "code\modules\xenoarcheaology\effects\cannibal.dm" -#include "code\modules\xenoarcheaology\effects\cellcharge.dm" -#include "code\modules\xenoarcheaology\effects\celldrain.dm" -#include "code\modules\xenoarcheaology\effects\cold.dm" +#include "code\modules\xenoarcheaology\effects\cell.dm" #include "code\modules\xenoarcheaology\effects\electric_field.dm" #include "code\modules\xenoarcheaology\effects\emp.dm" +#include "code\modules\xenoarcheaology\effects\feelings.dm" #include "code\modules\xenoarcheaology\effects\feysight.dm" #include "code\modules\xenoarcheaology\effects\forcefield.dm" #include "code\modules\xenoarcheaology\effects\gaia.dm" -#include "code\modules\xenoarcheaology\effects\gasco2.dm" -#include "code\modules\xenoarcheaology\effects\gasnitro.dm" -#include "code\modules\xenoarcheaology\effects\gasoxy.dm" -#include "code\modules\xenoarcheaology\effects\gasphoron.dm" -#include "code\modules\xenoarcheaology\effects\gassleeping.dm" -#include "code\modules\xenoarcheaology\effects\goodfeeling.dm" #include "code\modules\xenoarcheaology\effects\gravitational_waves.dm" -#include "code\modules\xenoarcheaology\effects\heal.dm" -#include "code\modules\xenoarcheaology\effects\heat.dm" -#include "code\modules\xenoarcheaology\effects\hurt.dm" +#include "code\modules\xenoarcheaology\effects\health.dm" #include "code\modules\xenoarcheaology\effects\poltergeist.dm" #include "code\modules\xenoarcheaology\effects\radiate.dm" #include "code\modules\xenoarcheaology\effects\resurrect.dm" -#include "code\modules\xenoarcheaology\effects\roboheal.dm" -#include "code\modules\xenoarcheaology\effects\robohurt.dm" +#include "code\modules\xenoarcheaology\effects\robothealth.dm" #include "code\modules\xenoarcheaology\effects\sleepy.dm" #include "code\modules\xenoarcheaology\effects\stun.dm" #include "code\modules\xenoarcheaology\effects\teleport.dm" +#include "code\modules\xenoarcheaology\effects\temperature.dm" #include "code\modules\xenoarcheaology\effects\vampire.dm" -#include "code\modules\xenoarcheaology\finds\eguns.dm" -#include "code\modules\xenoarcheaology\finds\eguns_vr.dm" #include "code\modules\xenoarcheaology\finds\find_spawning.dm" #include "code\modules\xenoarcheaology\finds\finds.dm" #include "code\modules\xenoarcheaology\finds\finds_defines.dm" @@ -4396,6 +4385,10 @@ #include "code\modules\xenoarcheaology\finds\misc.dm" #include "code\modules\xenoarcheaology\finds\special.dm" #include "code\modules\xenoarcheaology\finds\talking.dm" +#include "code\modules\xenoarcheaology\finds\Weapons\archeo_eguns.dm" +#include "code\modules\xenoarcheaology\finds\Weapons\archeo_eguns_vr.dm" +#include "code\modules\xenoarcheaology\finds\Weapons\archeo_guns.dm" +#include "code\modules\xenoarcheaology\finds\Weapons\archeo_melee.dm" #include "code\modules\xenoarcheaology\tools\ano_device_battery.dm" #include "code\modules\xenoarcheaology\tools\artifact_analyser.dm" #include "code\modules\xenoarcheaology\tools\artifact_harvester.dm"