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 <b> 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.
This commit is contained in:
Cameron Lennox
2025-01-27 07:15:58 +10:00
committed by GitHub
parent af4b4fecd1
commit 09b36a7ff6
85 changed files with 2205 additions and 1348 deletions
+1
View File
@@ -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)
+1 -1
View File
@@ -72,7 +72,7 @@
#define span_filter_combat(str) ("<span class='filter_combat'>" + str + "</span>")
// Filtered under warning messages
#define span_critical(str) ("<span class='critical'>" + str + "</span>")
#define span_critical(str) ("<span class='critical'>" + str + "</span>") //This doesn't seem to work.
#define span_userdanger(str) ("<span class='userdanger'>" + str + "</span>")
#define span_warning(str) ("<span class='warning'>" + str + "</span>")
#define span_warningplain(str) ("<span class='warningplain'>" + str + "</span>")
+50 -16
View File
@@ -1,6 +1,9 @@
/// <summary>
/// These are the defines for the SMALL (can hold in hand) artifacts.
/// </summary>
#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
/// <summary>
/// These are the defines for the DIGSITES (which determine what artifacts will spawn in that cluster of artifact tiles)
/// </summary>
#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
/// <summary>
/// These are the defines for what type of effect the artifact has.
/// </summary>
/// <example>
/// 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)
/// </example>
#define EFFECT_TOUCH 0
#define EFFECT_AURA 1
#define EFFECT_PULSE 2
#define MAX_EFFECT 2
/// <summary>
/// These are the defines for what is required to ACTIVATE the artifact.
/// </summary>
/// 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
/// <summary>
/// These are defines of what TYPE of artifact it is. See code/modules/xenoarcheaology/effects for each artifact.
/// </summary>
#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
#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.
+43
View File
@@ -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
+124 -23
View File
@@ -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
+13
View File
@@ -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
*/
+2 -1
View File
@@ -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"
+3
View File
@@ -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
+4 -1
View File
@@ -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))
@@ -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!"
+8
View File
@@ -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)
+1 -1
View File
@@ -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,
@@ -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
@@ -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"
+5 -5
View File
@@ -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
+11 -6
View File
@@ -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()
+5
View File
@@ -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
+5
View File
@@ -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
+4
View File
@@ -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)
+3
View File
@@ -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
+20 -22
View File
@@ -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
@@ -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),
+2 -2
View File
@@ -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
@@ -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()
..()
@@ -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%
-6
View File
@@ -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)
+82 -33
View File
@@ -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()
. = "<b>"
. = "<br><br>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"
. += "</b> have been detected <b>"
. += ". 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."
. += ""
. += "</b>"
. += "<br>"
switch(trigger)
if(TRIGGER_TOUCH, TRIGGER_WATER, TRIGGER_ACID, TRIGGER_VOLATILE, TRIGGER_TOXIN)
. += " Activation index involves <b>physical interaction</b> with artifact surface."
if(TRIGGER_FORCE, TRIGGER_ENERGY, TRIGGER_HEAT, TRIGGER_COLD)
. += " Activation index involves <b>energetic interaction</b> with artifact surface."
if(TRIGGER_PHORON, TRIGGER_OXY, TRIGGER_CO2, TRIGGER_NITRO)
. += " Activation index involves <b>precise local atmospheric conditions</b>."
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."
+78 -31
View File
@@ -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
@@ -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()
@@ -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))
@@ -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("<font size='[num2text(rand(1,5))]'>[pick(drastic_messages)]") + "</font>"))
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("<font size='[num2text(rand(1,5))]'><b>[pick(drastic_messages)]</b></font>"))
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("<font size='[num2text(rand(1,5))]'><b>[pick(drastic_messages)]</b></font>"))
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
@@ -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())
@@ -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("<font size='[num2text(rand(1,5))]'>[pick(drastic_messages)]") + "</font>"))
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("<font size='[num2text(rand(1,5))]'><b>[pick(drastic_messages)]</b></font>"))
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("<font size='[num2text(rand(1,5))]'><b>[pick(drastic_messages)]</b></font>"))
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
@@ -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
@@ -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)
@@ -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)
@@ -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)
@@ -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)
+6 -2
View File
@@ -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
@@ -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("<font size='[num2text(rand(1,5))]'>[pick(drastic_messages)]") + "</font>"))
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("<font size='[num2text(rand(1,5))]'> " + span_bold("[pick(drastic_messages)]") + " </font>"))
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("<font size='[num2text(rand(1,5))]'> " + span_bold("[pick(drastic_messages)]") + " </font>"))
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
@@ -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())
@@ -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"
+3 -3
View File
@@ -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()
@@ -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()))
@@ -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()))
@@ -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()))
@@ -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()))
@@ -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()))
@@ -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("<font size='[num2text(rand(1,5))]'>[pick(drastic_messages)]") + "</font>"))
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("<font size='[num2text(rand(1,5))]'><b>[pick(drastic_messages)]</b></font>"))
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("<font size='[num2text(rand(1,5))]'><b>[pick(drastic_messages)]</b></font>"))
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
@@ -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)
@@ -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()
@@ -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
@@ -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)
@@ -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()
@@ -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
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
+3 -2
View File
@@ -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))
@@ -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))
@@ -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
@@ -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)
@@ -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
@@ -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()
@@ -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
@@ -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
@@ -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)
+6 -12
View File
@@ -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
@@ -1,41 +1,59 @@
/// This is the big file of various xenoarch spawns (what each digsite spawns), digsite spawn rates, and
/// <summary>
/// This is a list of what the depth_scanner can show, depending on what get_responsive_reagent returns below.
/// </summary>
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)
/// <summary>
/// This is a list of what the depth_scanner shows the user. In order with the above list.
/// </summary>
/// <example>
/// 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"
/// </example>
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
/// <summary>
/// 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!
/// </summary>
/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,
+23 -3
View File
@@ -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!"))
@@ -111,5 +111,5 @@
var/list/listening = viewers(holder_atom)
for(var/mob/M in listening)
to_chat(M, "[icon2html(holder_atom,M.client)] <b>[holder_atom]</b> 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
+1 -1
View File
@@ -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)
@@ -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
@@ -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
@@ -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()
*/
@@ -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
+12 -9
View File
@@ -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"
@@ -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)
@@ -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) => {
<LabeledList.Item label="Anomaly Depth">
{current.depth} cm
</LabeledList.Item>
<LabeledList.Item label="Anomaly Size">
{current.clearance} cm
</LabeledList.Item>
<LabeledList.Item label="Dissonance Spread">
{current.dissonance_spread}
</LabeledList.Item>
<LabeledList.Item label="Anomaly Material">
{current.material}
</LabeledList.Item>
+11 -18
View File
@@ -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"