Merge pull request #3839 from caelaislinn/xenoarchaeology

Xenoarchaeology updates
This commit is contained in:
DJSnapshot
2013-10-28 22:36:08 -07:00
40 changed files with 1223 additions and 2270 deletions

View File

@@ -145,14 +145,14 @@ datum/fusion_reaction/pergium_tritium
energy_production = 0
radiation = 5
datum/fusion_reaction/pergium_deuterium
datum/fusion_reaction/pergium_obdurium
primary_reactant = "Pergium"
secondary_reactant = "Obdurium"
energy_consumption = 5
energy_production = 0
radiation = 5
datum/fusion_reaction/pergium_tritium
datum/fusion_reaction/pergium_solonium
primary_reactant = "Pergium"
secondary_reactant = "Solonium"
energy_consumption = 5

View File

@@ -456,6 +456,14 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containername = "fuel tank crate"
group = "Engineering"
/datum/supply_packs/coolanttank
name = "Coolant tank crate"
contains = list(/obj/structure/reagent_dispensers/coolanttank)
cost = 16
containertype = /obj/structure/largecrate
containername = "coolant tank crate"
group = "Medical / Science"
/datum/supply_packs/solar
name = "Solar Pack crate"
contains = list(/obj/item/solar_assembly,

View File

@@ -152,7 +152,7 @@
carddesc += "<input type='hidden' name='src' value='\ref[src]'>"
carddesc += "<input type='hidden' name='choice' value='account'>"
carddesc += "<b>Stored account number:</b> <input type='text' id='accountfield' name='account' value='[modify.associated_account_number]' style='width:250px; background-color:white;' onchange='markAccountRed()'>"
carddesc += "<input type='submit' value='Rename' onclick='markAccountGreen()'>"
carddesc += "<input type='submit' value='Modify' onclick='markAccountGreen()'>"
carddesc += "</form>"
carddesc += "<b>Assignment:</b> "

View File

@@ -99,6 +99,16 @@ obj/structure/ex_act(severity)
/obj/structure/transit_tube/Bumped(mob/AM as mob|obj)
var/obj/structure/transit_tube/T = locate() in AM.loc
if(T)
AM << "<span class='warning'>The tube's support pylons block your way.</span>"
return ..()
else
AM.loc = src.loc
AM << "<span class='info'>You slip under the tube.</span>"
/obj/structure/transit_tube/station/New(loc)
..(loc)

View File

@@ -251,6 +251,7 @@
'nano/css/icons.css',
'nano/templates/chem_dispenser.tmpl',
'nano/templates/cryo.tmpl',
'nano/templates/geoscanner.tmpl',
'nano/templates/dna_modifier.tmpl',
'nano/images/uiBackground.png',
'nano/images/uiIcons16.png',
@@ -298,9 +299,5 @@
'icons/spideros_icons/sos_11.png',
'icons/spideros_icons/sos_12.png',
'icons/spideros_icons/sos_13.png',
'icons/spideros_icons/sos_14.png',
'icons/xenoarch_icons/chart1.jpg',
'icons/xenoarch_icons/chart2.jpg',
'icons/xenoarch_icons/chart3.jpg',
'icons/xenoarch_icons/chart4.jpg'
'icons/spideros_icons/sos_14.png'
)

View File

@@ -4,6 +4,8 @@
#define XENOARCH_SPREAD_CHANCE 15
#define ARTIFACT_SPAWN_CHANCE 20
var/list/artifact_spawning_turfs = list()
/turf/simulated/mineral //wall piece
name = "Rock"
icon = 'icons/turf/walls.dmi'
@@ -369,29 +371,25 @@ commented out in r5061, I left it because of the shroom thingies
//just pull the surrounding rock out
excavate_find(0, F)
if( src.excavation_level + P.excavation_amount >= 100 || (!finds.len && !excavation_minerals.len) )
//if players have been excavating this turf, have a chance to leave some rocky debris behind
var/boulder_prob = 0
if( src.excavation_level + P.excavation_amount >= 100 )
//if players have been excavating this turf, leave some rocky debris behind
var/obj/structure/boulder/B
if(src.excavation_level > 15)
boulder_prob = 10
if(artifact_find)
boulder_prob += 25
if(src.excavation_level >= 100)
boulder_prob += 40
else if(src.excavation_level > 95)
boulder_prob += 25
else if(src.excavation_level > 90)
boulder_prob += 10
if(prob(boulder_prob))
if( src.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(15))
//empty boulder
B = new(src)
if(artifact_find)
B.artifact_find = artifact_find
else if(artifact_find && src.excavation_level + P.excavation_amount >= 100)
artifact_debris(1)
gets_drilled(B ? 0 : 1)
if(B)
gets_drilled(0)
else
gets_drilled(1)
return
else
src.excavation_level += P.excavation_amount
@@ -475,7 +473,7 @@ commented out in r5061, I left it because of the shroom thingies
if(prob(50))
pain = 1
for(var/mob/living/M in range(src, 200))
M << "<font color='red'><b>[pick("A high pitched [pick("keening","wailing","whistle")]","A rumbling noise like [pick("thunder","heavy machinery")]")] somehow penetrates your mind before fadaing away!</b></font>"
M << "<font color='red'><b>[pick("A high pitched [pick("keening","wailing","whistle")]","A rumbling noise like [pick("thunder","heavy machinery")]")] somehow penetrates your mind before fading away!</b></font>"
if(pain)
flick("pain",M.pain)
if(prob(50))

View File

@@ -19,6 +19,8 @@
var/list/dispensable_reagents = list("hydrogen","lithium","carbon","nitrogen","oxygen","fluorine",
"sodium","aluminum","silicon","phosphorus","sulfur","chlorine","potassium","iron",
"copper","mercury","radium","water","ethanol","sugar","sacid","tungsten")
var/list/broken_requirements = list()
var/broken_on_spawn = 0
/obj/machinery/chem_dispenser/proc/recharge()
if(stat & (BROKEN|NOPOWER)) return
@@ -50,6 +52,28 @@
recharge()
dispensable_reagents = sortList(dispensable_reagents)
if(broken_on_spawn)
var/amount = pick(1,2,2,3,4)
var/list/options = list()
options[/obj/item/weapon/stock_parts/capacitor/adv] = "Add an advanced capacitor to fix it."
options[/obj/item/weapon/stock_parts/console_screen] = "Replace the console screen to fix it."
options[/obj/item/weapon/stock_parts/manipulator/pico] = "Upgrade to a pico manipulator to fix it."
options[/obj/item/weapon/stock_parts/matter_bin/adv] = "Give it an advanced matter bin to fix it."
options[/obj/item/stack/sheet/mineral/diamond] = "Line up a cut diamond with the nozzle to fix it."
options[/obj/item/stack/sheet/mineral/uranium] = "Position a uranium sheet inside to fix it."
options[/obj/item/stack/sheet/mineral/plasma] = "Enter a block of plasma to fix it."
options[/obj/item/stack/sheet/mineral/silver] = "Cover the internals with a silver lining to fix it."
options[/obj/item/stack/sheet/mineral/gold] = "Wire a golden filament to fix it."
options[/obj/item/stack/sheet/plasteel] = "Surround the outside with a plasteel cover to fix it."
options[/obj/item/stack/sheet/rglass] = "Insert a pane of reinforced glass to fix it."
while(amount > 0)
amount -= 1
var/index = pick(options)
broken_requirements[index] = options[index]
options -= index
/obj/machinery/chem_dispenser/ex_act(severity)
switch(severity)
if(1.0)
@@ -82,6 +106,10 @@
if(stat & (BROKEN|NOPOWER)) return
if(user.stat || user.restrained()) return
if(broken_requirements.len)
user << "<span class='warning'>[src] is broken. [broken_requirements[broken_requirements[1]]]</span>"
return
// this is the data which will be sent to the ui
var/data[0]
data["amount"] = amount
@@ -156,6 +184,19 @@
if(isrobot(user))
return
if(broken_requirements.len && B.type == broken_requirements[1])
broken_requirements -= broken_requirements[1]
user << "<span class='notice'>You fix [src].</span>"
if(istype(B,/obj/item/stack))
var/obj/item/stack/S = B
S.use(1)
else
user.drop_item()
del(B)
return
if(!istype(B, /obj/item/weapon/reagent_containers/glass))
return
if(src.beaker)
user << "Something is already loaded into the machine."
return

View File

@@ -122,7 +122,7 @@
else if(istype(target, /obj/machinery/bunsen_burner))
return
else if(istype(target, /obj/machinery/anomaly))
else if(istype(target, /obj/machinery/radiocarbon_spectrometer))
return
else if(reagents.total_volume)
@@ -223,6 +223,7 @@
possible_transfer_amounts = list(5,10,15,25,30,50,100,300)
flags = FPRINT | TABLEPASS | OPENCONTAINER
/obj/item/weapon/reagent_containers/glass/beaker/vial
name = "vial"
desc = "A small glass vial. Can hold up to 25 units."

View File

@@ -211,6 +211,10 @@
// attack with hand, switch position
/obj/machinery/conveyor_switch/attack_hand(mob/user)
if(!allowed(user))
user << "<span class='warning'>Access denied.</span>"
return
if(position == 0)
if(last_pos < 0)
position = 1

View File

@@ -35,6 +35,7 @@
icon_state = "boulder1"
density = 1
opacity = 1
anchored = 1
var/excavation_level = 0
var/datum/geosample/geological_data
var/datum/artifact_find/artifact_find
@@ -75,17 +76,14 @@
user << "\blue You finish [P.drill_verb] [src]."
excavation_level += P.excavation_amount
var/reveal_prob = 1
if(excavation_level >= 95)
reveal_prob = 50 + (excavation_level - 90) * (excavation_level - 90)
else if(excavation_level >= 90)
reveal_prob = 5
if(excavation_level >= 100)
if(excavation_level > 100)
//failure
user.visible_message("<font color='red'><b>[src] suddenly crumbles away.</b></font>",\
"\red [src] has disintegrated under your onslaught, any secrets it was holding long gone.")
"\red [src] has disintegrated under your onslaught, any secrets it was holding are long gone.")
del(src)
else if(prob(reveal_prob))
return
if(prob(excavation_level))
//success
if(artifact_find)
var/spawn_type = artifact_find.artifact_find_type

View File

@@ -1,242 +0,0 @@
//Part of ISaidNo's public release around July 2011(ish), multiple changes
//many thanks
#define PLASMA_SPAWN 1
#define N2_SPAWN 2
#define CO2_SPAWN 3
#define RADIATE 4
#define VIRUS 5
#define HEAT 6
#define COLD 7
/obj/machinery/artifact
name = "alien artifact"
desc = "A large alien device."
icon = 'icons/obj/xenoarchaeology.dmi'
icon_state = "ano00"
var/icon_num = 0
anchored = 0
density = 1
var/origin = null // Used in the randomisation/research of the artifact.
var/activated = 0 // Whether or not the artifact has been unlocked.
var/charged = 1 // Whether the artifact is ready to have it's effect.
var/chargetime = 0 // How much time until the artifact is charged.
var/recharge = 5 // How long does it take this artifact to recharge?
var/display_id = "" // Artifact ID to display once successfully scanned
var/datum/artifact_effect/my_effect = null
var/being_used = 0
/obj/machinery/artifact/New()
..()
// Origin and appearance randomisation
my_effect = new()
icon_num = rand(0,5)
icon_state = "ano[icon_num]0"
// Power randomisation
my_effect.trigger = pick("force","energy","chemical","heat","touch","presence")
if (my_effect.trigger == "chemical")
my_effect.triggerX = pick("hydrogen","corrosive","volatile","toxic")
my_effect.effecttype = pick("healing","injure","stun","roboheal","robohurt","cellcharge","celldrain","planthelper","forcefield","teleport","dnaswitch","emp","sleepy")
// Select range based on the power
var/canworldpulse = 1
switch(my_effect.effecttype)
if("healing")
my_effect.effectmode = pick("aura","pulse","contact")
if("injure")
my_effect.effectmode = pick("aura","pulse","contact")
if("stun")
my_effect.effectmode = pick("aura","pulse","contact")
if("roboheal")
my_effect.effectmode = pick("aura","pulse","contact")
if("robohurt")
my_effect.effectmode = pick("aura","pulse","contact")
if("sleepy")
my_effect.effectmode = pick("aura","pulse","contact")
if("cellcharge")
my_effect.effectmode = pick("aura","pulse")
if("celldrain")
my_effect.effectmode = pick("aura","pulse")
if("planthelper")
my_effect.effectmode = pick("aura","pulse")
canworldpulse = 0
if("forcefield")
my_effect.effectmode = "contact"
canworldpulse = 0
if("teleport")
my_effect.effectmode = pick("pulse","contact")
if("genderswitch")
my_effect.effectmode = pick("pulse","contact")
if("emp")
my_effect.effectmode = pick("pulse","contact")
// Recharge timer & range setup
if (my_effect.effectmode == "aura")
my_effect.aurarange = rand(1,4)
if (my_effect.effectmode == "contact")
src.recharge = rand(5,15)
if (my_effect.effectmode == "pulse")
my_effect.aurarange = rand(2,14)
src.recharge = rand(5,20)
if (canworldpulse == 1 && prob(1))
my_effect.effectmode = "worldpulse"
src.recharge = rand(40,120)
/*
display_id += pick("kappa","sigma","antaeres","beta","lorard","omicron","iota","upsilon","omega","gamma","delta")
display_id += "-"
display_id += num2text(rand(100,999))
*/
/obj/machinery/artifact/Del()
..()
my_effect.HaltEffect()
/obj/machinery/artifact/attack_hand(var/mob/user as mob)
if (istype(user, /mob/living/silicon/ai) || istype(user, /mob/dead/)) return
if (istype(user, /mob/living/silicon/robot))
if (get_dist(user, src) > 1)
user << "\red You can't reach [src] from here."
return
if(ishuman(user) && istype(user:gloves,/obj/item/clothing/gloves))
return ..()
for(var/mob/O in viewers(src, null))
O.show_message(text("<b>[]</b> touches [].", user, src), 1)
src.add_fingerprint(user)
src.Artifact_Contact(user)
/obj/machinery/artifact/attackby(obj/item/weapon/W as obj, mob/living/user as mob)
/*if (istype(W, /obj/item/weapon/cargotele))
W:cargoteleport(src, user)
return*/
if (my_effect.trigger == "chemical" && istype(W, /obj/item/weapon/reagent_containers/))
switch(my_effect.triggerX)
if("hydrogen")
if (W.reagents.has_reagent("hydrogen", 1) || W.reagents.has_reagent("water", 1))
src.Artifact_Activate()
return
if("corrosive")
if (W.reagents.has_reagent("acid", 1) || W.reagents.has_reagent("pacid", 1) || W.reagents.has_reagent("diethylamine", 1))
src.Artifact_Activate()
return
if("volatile")
if (W.reagents.has_reagent("plasma", 1) || W.reagents.has_reagent("thermite", 1))
src.Artifact_Activate()
return
if("toxic")
if (W.reagents.has_reagent("toxin", 1) || W.reagents.has_reagent("cyanide", 1) || W.reagents.has_reagent("amanitin", 1) || W.reagents.has_reagent("neurotoxin", 1))
src.Artifact_Activate()
return
..()
if (my_effect.trigger == "force" && W.force >= 10 && !src.activated) src.Artifact_Activate()
if (my_effect.trigger == "energy")
if (istype(W,/obj/item/weapon/melee/baton) && W:status) src.Artifact_Activate()
if (istype(W,/obj/item/weapon/melee/energy)) src.Artifact_Activate()
if (istype(W,/obj/item/weapon/melee/cultblade)) src.Artifact_Activate()
if (istype(W,/obj/item/weapon/gun/energy/)) src.Artifact_Activate()
if (istype(W,/obj/item/device/multitool)) src.Artifact_Activate()
if (istype(W,/obj/item/weapon/card/emag)) src.Artifact_Activate()
if (my_effect.trigger == "heat")
if (istype(W,/obj/item/weapon/match) && W:lit) src.Artifact_Activate()
if (istype(W, /obj/item/weapon/weldingtool) && W:welding) src.Artifact_Activate()
if (istype(W, /obj/item/weapon/lighter) && W:lit) src.Artifact_Activate()
//Bump(atom/A)
/obj/machinery/artifact/Bumped(M as mob|obj)
if (istype(M,/obj/item/weapon/) && my_effect.trigger == "force" && M:throwforce >= 10) src.Artifact_Activate()
/obj/machinery/artifact/bullet_act(var/obj/item/projectile/P)
if (my_effect.trigger == "force")
if(istype(P,/obj/item/projectile/bullet)) src.Artifact_Activate()
else if(istype(P,/obj/item/projectile/hivebotbullet)) src.Artifact_Activate()
if (my_effect.trigger == "energy")
if(istype(P,/obj/item/projectile/beam)) src.Artifact_Activate()
else if(istype(P,/obj/item/projectile/ion)) src.Artifact_Activate()
else if(istype(P,/obj/item/projectile/energy)) src.Artifact_Activate()
if (my_effect.trigger == "heat")
if(istype(P,/obj/item/projectile/temp)) src.Artifact_Activate()
/obj/machinery/artifact/ex_act(severity)
switch(severity)
if(1.0) del src
if(2.0)
if (prob(50)) del src
if (my_effect.trigger == "force") src.Artifact_Activate()
if (my_effect.trigger == "heat") src.Artifact_Activate()
if(3.0)
if (my_effect.trigger == "force") src.Artifact_Activate()
if (my_effect.trigger == "heat") src.Artifact_Activate()
return
/obj/machinery/artifact/temperature_expose(null, temp, volume)
if (my_effect.trigger == "heat") src.Artifact_Activate()
/obj/machinery/artifact/process()
if (!src.activated)
return
if (chargetime > 0)
chargetime -= 1
else
src.charged = 1
my_effect.UpdateEffect(src.loc)
//activate
if( (my_effect.effectmode == "pulse" || my_effect.effecttype == "worldpulse") && activated)
if(src.charged && my_effect.DoEffect(src))
src.charged = 0
src.chargetime = src.recharge
/obj/machinery/artifact/proc/Artifact_Activate()
src.activated = !src.activated
var/display_msg = ""
if(activated)
if(prob(30))
switch(rand(4))
if(0)
display_msg = "momentarily glows brightly!"
if(1)
display_msg = "distorts slightly for a moment!"
if(2)
display_msg = "makes a slightly clicking noise!"
if(3)
display_msg = "flickers slightly!"
if(4)
display_msg = "vibrates!"
else
my_effect.HaltEffect()
if(prob(30))
switch(rand(2))
if(0)
display_msg = "grows dull!"
if(1)
display_msg = "fades in intensity!"
if(2)
display_msg = "suddenly becomes very quiet!"
icon_state = "ano[icon_num][activated]"
for(var/mob/O in viewers(src, null))
O.show_message(text("<b>[]</b> [display_msg]", src), 1)
/obj/machinery/artifact/proc/Artifact_Contact(var/mob/user as mob)
// Trigger Code
if (istype (user,/mob/living/carbon/) && my_effect.trigger == "touch" && !src.activated) src.Artifact_Activate()
else if (my_effect.trigger != "touch" && !src.activated) user << "Nothing happens."
if (my_effect.effectmode == "contact" && src.activated && src.charged)
my_effect.DoEffect(user)
src.charged = 0
src.chargetime = src.recharge
// this was used in QM for a time but it fell into disuse and wasn't removed, the purpose being to check if an artifact
// was benevolent or malicious, to determine whether QMs would be paid or punished for shipping it
/obj/machinery/artifact/Move()
..()
my_effect.update_move(src, src.loc)

View File

@@ -1,542 +0,0 @@
//
/datum/artifact_effect
var/artifact_id = "" // Display ID of the spawning artifact
var/trigger = "touch" // What activates it?
var/triggerX = "none" // Used for more varied triggers
var/effecttype = "healing" // What does it do?
var/effectmode = "aura" // How does it carry out the effect?
var/aurarange = 4 // How far the artifact will extend an aura effect.
var/list/created_field
var/archived_loc
/datum/artifact_effect/New()
//
created_field = new()
/datum/artifact_effect/proc/GetOriginString(var/origin)
/datum/artifact_effect/proc/GetEffectString(var/effect)
/datum/artifact_effect/proc/GetTriggerString(var/trigger)
/datum/artifact_effect/proc/GetRangeString(var/range)
switch(effectmode)
if("aura") return "Constant Short-Range Energy Field"
if("pulse")
if(aurarange > 7) return "Long Range Energy Pulses"
else return "Medium Range Energy Pulses"
if("worldpulse") return "Extreme Range Energy Pulses"
if("contact") return "Requires contact with subject"
else return "Unknown Range"
/datum/artifact_effect/proc/HaltEffect()
for(var/obj/effect/energy_field/F in created_field)
created_field.Remove(F)
del F
/datum/artifact_effect/proc/UpdateEffect(var/atom/originator)
/*for(var/obj/effect/energy_field/F in created_field)
created_field.Remove(F)
del F*/
if(originator.loc != archived_loc)
archived_loc = originator.loc
update_move(originator)
for(var/obj/effect/energy_field/E in created_field)
if(E.strength < 5)
E.Strengthen(0.2)
/datum/artifact_effect/proc/DoEffect(var/atom/originator)
archived_loc = originator.loc
if (src.effectmode == "contact")
var/mob/living/user = originator
if(!user)
return
switch(src.effecttype)
if("healing")
//caeltodo
if (istype(user, /mob/living/carbon/human/))
user << "\blue You feel a soothing energy invigorate you."
var/mob/living/carbon/human/H = user
for(var/datum/organ/external/affecting in H.organs)
if(!affecting) continue
if(!istype(affecting, /datum/organ/external)) continue
affecting.heal_damage(25, 25) //fixes getting hit after ingestion, killing you when game updates organ health
//user:heal_organ_damage(25, 25)
//
user.adjustOxyLoss(-25)
user.adjustToxLoss(-25)
user.adjustBruteLoss(-25)
user.adjustFireLoss(-25)
user.adjustBrainLoss(-25)
user.radiation -= min(user.radiation, 25)
user.nutrition += 50
H.bodytemperature = initial(H.bodytemperature)
//
H.vessel.add_reagent("blood",50)
spawn(1)
H.fixblood()
H.regenerate_icons()
return 1
//
if (istype(user, /mob/living/carbon/monkey/))
user << "\blue You feel a soothing energy invigorate you."
user.adjustOxyLoss(-25)
user.adjustToxLoss(-25)
user.adjustBruteLoss(-25)
user.adjustFireLoss(-25)
user.adjustBrainLoss(-25)
return 1
else user << "Nothing happens."
if("injure")
if (istype(user, /mob/living/carbon/))
user << "\red A painful discharge of energy strikes you!"
user.adjustOxyLoss(rand(5,25))
user.adjustToxLoss(rand(5,25))
user.adjustBruteLoss(rand(5,25))
user.adjustFireLoss(rand(5,25))
user.adjustBrainLoss(rand(5,25))
user.radiation += 25
user.nutrition -= min(50, user.nutrition)
user.make_dizzy(6)
user.weakened += 6
return 1
else user << "Nothing happens."
if("stun")
if (istype(user, /mob/living/carbon/))
user << "\red A powerful force overwhelms your consciousness."
user.weakened += 45
user.stuttering += 45
if(prob(50))
user.stunned += rand(1,10)
return 1
else user << "Nothing happens."
if("roboheal")
if (istype(user, /mob/living/silicon/robot))
user << "\blue Your systems report damaged components mending by themselves!"
user.adjustBruteLoss(rand(-10,-30))
user.adjustFireLoss(rand(-10,-30))
return 1
else user << "Nothing happens."
if("robohurt")
if (istype(user, /mob/living/silicon/robot))
user << "\red Your systems report severe damage has been inflicted!"
user.adjustBruteLoss(rand(10,50))
user.adjustFireLoss(rand(10,50))
return 1
else user << "Nothing happens."
if("forcefield")
while(created_field.len < 16)
var/obj/effect/energy_field/E = new (locate(user.x,user.y,user.z))
created_field.Add(E)
E.strength = 1
E.density = 1
E.anchored = 1
E.invisibility = 0
return 1
if("teleport")
var/list/randomturfs = new/list()
for(var/turf/T in orange(user, 50))
if(!istype(T, /turf/simulated/floor) || T.density)
continue
randomturfs.Add(T)
if(randomturfs.len > 0)
user << "\red You are suddenly zapped away elsewhere!"
if (user.buckled)
user.buckled.unbuckle()
user.loc = pick(randomturfs)
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(3, 0, get_turf(originator)) //no idea what the 0 is
sparks.start()
return 1
if("sleepy")
user << pick("\blue You feel like taking a nap.","\blue You feel a yawn coming on.","\blue You feel a little tired.")
user.drowsyness = min(user.drowsyness + rand(5,25), 50)
user.eye_blurry = min(user.eye_blurry + rand(1,3), 50)
return 1
else if (src.effectmode == "aura")
switch(src.effecttype)
//caeltodo
if("healing")
for (var/mob/living/carbon/M in range(src.aurarange,originator))
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
if(prob(10)) M << "\blue You feel a soothing energy radiating from something nearby."
M.adjustBruteLoss(-1)
M.adjustFireLoss(-1)
M.adjustToxLoss(-1)
M.adjustOxyLoss(-1)
M.adjustBrainLoss(-1)
M.updatehealth()
return 1
if("injure")
for (var/mob/living/carbon/M in range(src.aurarange,originator))
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
if(prob(10)) M << "\red You feel a painful force radiating from something nearby."
M.adjustBruteLoss(1)
M.adjustFireLoss(1)
M.adjustToxLoss(1)
M.adjustOxyLoss(1)
M.adjustBrainLoss(1)
M.updatehealth()
return 1
if("stun")
for (var/mob/living/carbon/M in range(src.aurarange,originator))
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
if(prob(10)) M << "\red Energy radiating from the [originator] is making you feel numb."
if(prob(20))
M << "\red Your body goes numb for a moment."
M.stunned += 2
M.weakened += 2
M.stuttering += 2
return 1
if("roboheal")
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
if(prob(10)) M << "\blue SYSTEM ALERT: Beneficial energy field detected!"
M.adjustBruteLoss(-1)
M.adjustFireLoss(-1)
M.updatehealth()
return 1
if("robohurt")
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
if(prob(10)) M << "\red SYSTEM ALERT: Harmful energy field detected!"
M.adjustBruteLoss(1)
M.adjustFireLoss(1)
M.updatehealth()
return 1
if("cellcharge")
for (var/obj/machinery/power/apc/C in range(src.aurarange,originator))
for (var/obj/item/weapon/cell/B in C.contents)
B.charge += 10
for (var/obj/machinery/power/smes/S in range (src.aurarange,originator)) S.charge += 20
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
for (var/obj/item/weapon/cell/D in M.contents)
D.charge += 10
if(prob(10)) M << "\blue SYSTEM ALERT: Energy boosting field detected!"
return 1
if("celldrain")
for (var/obj/machinery/power/apc/C in range(src.aurarange,originator))
for (var/obj/item/weapon/cell/B in C.contents)
B.charge = max(B.charge-10,0)
for (var/obj/machinery/power/smes/S in range (src.aurarange,originator))
S.charge = max(S.charge-20,0)
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
for (var/obj/item/weapon/cell/D in M.contents)
D.charge = max(D.charge-10,0)
if(prob(10)) M << "\red SYSTEM ALERT: Energy draining field detected!"
return 1
if("planthelper")
for (var/obj/machinery/hydroponics/H in range(src.aurarange,originator))
//makes weeds and shrooms and stuff more potent too
if(H.planted)
H.waterlevel += 2
H.nutrilevel += 2
if(H.toxic > 0)
H.toxic -= 1
H.health += 1
if(H.pestlevel > 0)
H.pestlevel -= 1
if(H.weedlevel > 0)
H.weedlevel -= 1
H.lastcycle += 5
return 1
if("sleepy")
for (var/mob/living/carbon/M in range(src.aurarange,originator))
if(prob(10))
M << pick("\blue You feel like taking a nap.","\blue You feel a yawn coming on.","\blue You feel a little tired.")
M.drowsyness = min(M.drowsyness + 1, 25)
M.eye_blurry = min(M.eye_blurry + 1, 25)
return 1
else if (src.effectmode == "pulse")
for(var/mob/O in viewers(originator, null))
O.show_message(text("<b>[]</b> emits a pulse of energy!", originator), 1)
switch(src.effecttype)
//caeltodo
if("healing")
for (var/mob/living/carbon/M in range(src.aurarange,originator))
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
M << "\blue A wave of energy invigorates you."
M.adjustBruteLoss(-5)
M.adjustFireLoss(-5)
M.adjustToxLoss(-5)
M.adjustOxyLoss(-5)
M.adjustBrainLoss(-5)
M.updatehealth()
return 1
if("injure")
for (var/mob/living/carbon/M in range(src.aurarange,originator))
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
M << "\red A wave of energy causes you great pain!"
M.adjustBruteLoss(5)
M.adjustFireLoss(5)
M.adjustToxLoss(5)
M.adjustOxyLoss(5)
M.adjustBrainLoss(5)
M.make_dizzy(6)
M.weakened += 3
M.updatehealth()
return 1
if("stun")
for (var/mob/living/carbon/M in range(src.aurarange,originator))
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
M << "\red A wave of energy overwhelms your senses!"
M.paralysis += 3
M.weakened += 4
M.stuttering += 4
return 1
if("roboheal")
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
M << "\blue SYSTEM ALERT: Structural damage has been repaired by energy pulse!"
M.adjustBruteLoss(-10)
M.adjustFireLoss(-10)
M.updatehealth()
return 1
if("robohurt")
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
M << "\red SYSTEM ALERT: Structural damage inflicted by energy pulse!"
M.adjustBruteLoss(10)
M.adjustFireLoss(10)
M.updatehealth()
return 1
if("cellcharge")
for (var/obj/machinery/power/apc/C in range(src.aurarange,originator))
for (var/obj/item/weapon/cell/B in C.contents)
B.charge += 250
for (var/obj/machinery/power/smes/S in range (src.aurarange,originator)) S.charge += 400
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
for (var/obj/item/weapon/cell/D in M.contents)
D.charge += 250
M << "\blue SYSTEM ALERT: Large energy boost detected!"
return 1
if("celldrain")
for (var/obj/machinery/power/apc/C in range(src.aurarange,originator))
for (var/obj/item/weapon/cell/B in C.contents)
B.charge = max(B.charge-500,0)
for (var/obj/machinery/power/smes/S in range (src.aurarange,originator))
S.charge = max(S.charge-400,0)
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
for (var/obj/item/weapon/cell/D in M.contents)
D.charge = max(D.charge-500,0)
M << "\red SYSTEM ALERT: Severe energy drain detected!"
return 1
if("planthelper")
//makes weeds and shrooms and stuff more potent too
for (var/obj/machinery/hydroponics/H in range(src.aurarange,originator))
if(H.planted)
H.dead = 0
H.waterlevel = 200
H.nutrilevel = 200
H.toxic = 0
H.health = 100
H.pestlevel = 0
H.weedlevel = 0
H.lastcycle = H.cycledelay
return 1
if("teleport")
for (var/mob/living/M in range(src.aurarange,originator))
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
var/list/randomturfs = new/list()
for(var/turf/T in orange(M, 30))
if(!istype(T, /turf/simulated/floor) || T.density)
continue
randomturfs.Add(T)
if(randomturfs.len > 0)
M << "\red You are displaced by a strange force!"
if(M.buckled)
M.buckled.unbuckle()
M.loc = pick(randomturfs)
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(3, 0, get_turf(originator)) //no idea what the 0 is
sparks.start()
return 1
if("dnaswitch")
for(var/mob/living/H in range(src.aurarange,originator))
if(ishuman(H) && istype(H:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(H:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
if(prob(30))
H << pick("\green You feel a little different.","\green You feel strange.","\green You feel different.")
//todo
if (H.gender == FEMALE)
H.gender = MALE
else
H.gender = FEMALE
/*H.dna.ready_dna(H)
H.update_body()
H.update_face()*/
return 1
if("emp")
empulse(get_turf(originator), aurarange/2, aurarange)
return 1
if("sleepy")
for (var/mob/living/carbon/M in range(src.aurarange,originator))
if(prob(30))
M << pick("\blue You feel like taking a nap.","\blue You feel a yawn coming on.","\blue You feel a little tired.")
if(prob(50))
M.drowsyness = min(M.drowsyness + rand(1,5), 25)
if(prob(50))
M.eye_blurry = min(M.eye_blurry + rand(1,5), 25)
return 1
else if (src.effectmode == "worldpulse")
for(var/mob/O in viewers(originator, null))
O.show_message(text("<b>[]</b> emits a powerful burst of energy!", originator), 1)
switch(src.effecttype)
if("healing")
for (var/mob/living/carbon/M in range(200, originator))
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
M << "\blue Waves of soothing energy wash over you."
M.adjustBruteLoss(-3)
M.adjustFireLoss(-3)
M.adjustToxLoss(-3)
M.adjustOxyLoss(-3)
M.adjustBrainLoss(-3)
M.updatehealth()
return 1
if("injure")
for (var/mob/living/carbon/human/M in range(200, originator))
M << "\red A wave of painful energy strikes you!"
M.adjustBruteLoss(3)
M.adjustFireLoss(3)
M.adjustToxLoss(3)
M.adjustOxyLoss(3)
M.adjustBrainLoss(3)
M.updatehealth()
return 1
if("stun")
for (var/mob/living/carbon/M in range(200, originator))
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
M << "\red A powerful force causes you to black out momentarily."
M.paralysis += 5
M.weakened += 8
M.stuttering += 8
return 1
if("roboheal")
for (var/mob/living/silicon/robot/M in range(200, originator))
M << "\blue SYSTEM ALERT: Structural damage has been repaired by energy pulse!"
M.adjustBruteLoss(-5)
M.adjustFireLoss(-5)
M.updatehealth()
return 1
if("robohurt")
for (var/mob/living/silicon/robot/M in range(200, originator))
M << "\red SYSTEM ALERT: Structural damage inflicted by energy pulse!"
M.adjustBruteLoss(5)
M.adjustFireLoss(5)
M.updatehealth()
return 1
if("cellcharge")
for (var/obj/machinery/power/apc/C in range(200, originator))
for (var/obj/item/weapon/cell/B in C.contents)
B.charge += 100
for (var/obj/machinery/power/smes/S in range (src.aurarange,src)) S.charge += 250
for (var/mob/living/silicon/robot/M in world)
for (var/obj/item/weapon/cell/D in M.contents)
D.charge += 100
M << "\blue SYSTEM ALERT: Energy boost detected!"
return 1
if("celldrain")
for (var/obj/machinery/power/apc/C in range(200, originator))
for (var/obj/item/weapon/cell/B in C.contents)
B.charge = max(B.charge-250,0)
for (var/obj/machinery/power/smes/S in range (src.aurarange,src))
S.charge = max(S.charge-250,0)
for (var/mob/living/silicon/robot/M in world)
for (var/obj/item/weapon/cell/D in M.contents)
D.charge = max(D.charge-250,0)
M << "\red SYSTEM ALERT: Energy drain detected!"
return 1
if("teleport")
for (var/mob/living/M in range(200, originator))
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
var/list/randomturfs = new/list()
for(var/turf/T in orange(M, 15))
if(!istype(T, /turf/simulated/floor) || T.density)
continue
randomturfs.Add(T)
if(randomturfs.len > 0)
M << "\red You are displaced by a strange force!"
if(M.buckled)
M.buckled.unbuckle()
M.loc = pick(randomturfs)
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(3, 0, get_turf(originator)) //no idea what the 0 is
sparks.start()
return 1
if("dnaswitch")
for(var/mob/living/H in range(200, originator))
if(ishuman(H) && istype(H:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(H:head,/obj/item/clothing/head/bio_hood/anomaly))
continue
if(prob(30))
H << pick("\green You feel a little different.","\green You feel strange.","\green You feel different.")
//todo
if (H.gender == FEMALE)
H.gender = MALE
else
H.gender = FEMALE
/*H.dna.ready_dna(H)
H.update_body()
H.update_face()*/
return 1
if("sleepy")
for(var/mob/living/H in range(200, originator))
H.drowsyness = min(H.drowsyness + rand(5,15), 50)
H.eye_blurry = min(H.eye_blurry + rand(5,15), 50)
return 1
//initially for the force field artifact
/datum/artifact_effect/proc/update_move(var/atom/originator)
switch(effecttype)
if("forcefield")
while(created_field.len < 16)
//for now, just instantly respawn the fields when they get destroyed
var/obj/effect/energy_field/E = new (locate(originator.x,originator.y,originator))
created_field.Add(E)
E.strength = 1
E.density = 1
E.anchored = 1
E.invisibility = 0
var/obj/effect/energy_field/E = created_field[1]
E.loc = locate(originator.x + 2,originator.y + 2,originator.z)
E = created_field[2]
E.loc = locate(originator.x + 2,originator.y + 1,originator.z)
E = created_field[3]
E.loc = locate(originator.x + 2,originator.y,originator.z)
E = created_field[4]
E.loc = locate(originator.x + 2,originator.y - 1,originator.z)
E = created_field[5]
E.loc = locate(originator.x + 2,originator.y - 2,originator.z)
E = created_field[6]
E.loc = locate(originator.x + 1,originator.y + 2,originator.z)
E = created_field[7]
E.loc = locate(originator.x + 1,originator.y - 2,originator.z)
E = created_field[8]
E.loc = locate(originator.x,originator.y + 2,originator.z)
E = created_field[9]
E.loc = locate(originator.x,originator.y - 2,originator.z)
E = created_field[10]
E.loc = locate(originator.x - 1,originator.y + 2,originator.z)
E = created_field[11]
E.loc = locate(originator.x - 1,originator.y - 2,originator.z)
E = created_field[12]
E.loc = locate(originator.x - 2,originator.y + 2,originator.z)
E = created_field[13]
E.loc = locate(originator.x - 2,originator.y + 1,originator.z)
E = created_field[14]
E.loc = locate(originator.x - 2,originator.y,originator.z)
E = created_field[15]
E.loc = locate(originator.x - 2,originator.y - 1,originator.z)
E = created_field[16]
E.loc = locate(originator.x - 2,originator.y - 2,originator.z)

View File

@@ -324,26 +324,27 @@
if(26)
//energy gun
var/spawn_type = pick(\
/obj/item/weapon/gun/energy/laser/practice;100,\
/obj/item/weapon/gun/energy/laser;75,\
/obj/item/weapon/gun/energy/xray;50,\
/obj/item/weapon/gun/energy/laser/captain;25,\
)
var/obj/item/weapon/gun/energy/new_gun = new spawn_type(src.loc)
new_item = new_gun
new_item.icon_state = "egun[rand(1,6)]"
/obj/item/weapon/gun/energy/laser/practice,\
/obj/item/weapon/gun/energy/laser,\
/obj/item/weapon/gun/energy/xray,\
/obj/item/weapon/gun/energy/laser/captain)
if(spawn_type)
var/obj/item/weapon/gun/energy/new_gun = new spawn_type(src.loc)
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."
//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
if(prob(15))
new_gun.power_supply.charge = rand(0, new_gun.power_supply.maxcharge)
else
new_gun.power_supply.charge = 0
//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
if(prob(15))
new_gun.power_supply.charge = rand(0, new_gun.power_supply.maxcharge)
else
new_gun.power_supply.charge = 0
item_type = "gun"
if(27)

View File

@@ -206,6 +206,28 @@
)
return find_type
var/list/responsive_carriers = list( \
"carbon", \
"potassium", \
"hydrogen", \
"nitrogen", \
"mercury", \
"iron", \
"chlorine", \
"phosphorus", \
"plasma")
var/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" )
#undef ARCHAEO_BOWL
#undef ARCHAEO_URN
#undef ARCHAEO_CUTLERY

View File

@@ -29,30 +29,6 @@
pixel_x = rand(0,16)-8
pixel_y = rand(0,8)-8
var/list/responsive_carriers = list( \
"carbon", \
"potassium", \
"hydrogen", \
"nitrogen", \
"mercury", \
"iron", \
"chlorine", \
"phosphorus", \
"plasma")
var/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" )
var/list/artifact_spawning_turfs = list()
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Geosample datum
@@ -64,7 +40,6 @@ var/list/artifact_spawning_turfs = list()
var/artifact_id = "" //id of a nearby artifact, if there is one
var/artifact_distance = -1 //proportional to distance
var/source_mineral = "chlorine" //machines will pop up a warning telling players that the sample may be confused
var/total_spread = 0
//
//var/source_mineral
//all potential finds are initialised to null, so nullcheck before you access them
@@ -76,11 +51,11 @@ var/list/artifact_spawning_turfs = list()
//this should only need to be called once
/datum/geosample/proc/UpdateTurf(var/turf/simulated/mineral/container)
set background = 1
if(!container || !istype(container))
return
age = rand(1,999)
total_spread = 0
switch(container.mineralName)
if("Uranium")
@@ -132,8 +107,15 @@ var/list/artifact_spawning_turfs = list()
var/responsive_reagent = get_responsive_reagent(F.find_type)
find_presence[responsive_reagent] = F.dissonance_spread
for(var/entry in find_presence)
total_spread += find_presence[entry]
//loop over again to reset values to percentages
var/total_presence = 0
for(var/carrier in find_presence)
total_presence += find_presence[carrier]
for(var/carrier in find_presence)
find_presence[carrier] = find_presence[carrier] / total_presence
/*for(var/entry in find_presence)
total_spread += find_presence[entry]*/
//have this separate from UpdateTurf() so that we dont have a billion turfs being updated (redundantly) every time an artifact spawns
/datum/geosample/proc/UpdateNearbyArtifactInfo(var/turf/simulated/mineral/container)
@@ -146,7 +128,7 @@ var/list/artifact_spawning_turfs = list()
else
for(var/turf/simulated/mineral/holder in artifact_spawning_turfs)
if(holder.artifact_find)
var/dist = get_dist(container, holder)
var/dist = get_dist(container, holder) * 2
if(dist < holder.artifact_find.artifact_detect_range && dist < src.artifact_distance)
src.artifact_distance = dist
src.artifact_id = holder.artifact_find.artifact_id

View File

@@ -1,44 +0,0 @@
// This machine shows the age for extremely old finds
obj/machinery/anomaly/accelerator
name = "Accelerator spectrometer"
obj/machinery/anomaly/accelerator/ScanResults()
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
var/datum/geosample/scanned_sample
var/carrier_name
var/num_reagents = 0
for(var/datum/reagent/A in held_container.reagents.reagent_list)
var/datum/reagent/R = A
if(istype(R, /datum/reagent/analysis_sample))
scanned_sample = R.data
else
carrier_name = R.id
num_reagents++
if(num_reagents == 2 && scanned_sample && carrier_name)
var/specifity = GetResultSpecifity(scanned_sample, carrier_name)
results = "Kinetic acceleration of carrier ([carrier_name]) indicates age ([100 * specifity]% accuracy): <br><br>"
if(scanned_sample.age_billion)
var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - specifity) * (2 * rand() - 1)), 0)
var/displayed_age_billions = scanned_sample.age_billion + max(scanned_sample.age_billion * ((1 - specifity) * (2 * rand() - 1)), 0)
results += "[displayed_age_billions + displayed_age_millions / 1000] billion years.<br>"
else if(scanned_sample.age_million)
var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - specifity) * (4 * rand() - 2)), 0)
var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - specifity) * (2 * rand() - 1)), 0)
results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.<br>"
else if(scanned_sample.age_thousand)
var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - specifity) * (8 * rand() - 4)), 0)
var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age * ((1 - specifity) * (4 * rand() - 2)), 0)
results += "[displayed_age_thousands + displayed_age / 1000] thousand years.<br>"
else
var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - specifity) * (8 * rand() - 4)), 0)
results += "[displayed_age] years.<br>"
results += "<br>Warning, results only valid for ages on the scale of billions of years."
return results

View File

@@ -1,203 +0,0 @@
//Handles how much the temperature changes on power use. (Joules/Kelvin)
//Equates to as much heat energy per kelvin as a quarter tile of air.
#define XENOARCH_HEAT_CAPACITY 5000
//Handles heat transfer to the air. (In watts)
//Can heat a single tile 2 degrees per tick.
#define XENOARCH_MAX_ENERGY_TRANSFER 4000
//How many joules of electrical energy produce how many joules of heat energy?
#define XENOARCH_HEAT_COEFFICIENT 3
/obj/machinery/anomaly
name = "Analysis machine"
desc = "A specialised, complex analysis machine."
anchored = 1
density = 1
icon = 'icons/obj/virology.dmi'
icon_state = "analyser"
idle_power_usage = 20 //watts
active_power_usage = 300 //Because I need to make up numbers~
var/obj/item/weapon/reagent_containers/glass/held_container
var/obj/item/weapon/tank/fuel_container
var/target_scan_ticks = 30
var/report_num = 0
var/scan_process = 0
var/temperature = 273 //measured in kelvin, if this exceeds 1200, the machine is damaged and requires repairs
//if this exceeds 600 and safety is enabled it will shutdown
//temp greater than 600 also requires a safety prompt to initiate scanning
var/max_temp = 450
/obj/machinery/anomaly/New()
..()
//for analysis debugging
/*var/obj/item/weapon/reagent_containers/glass/solution_tray/S = new(src.loc)
var/turf/simulated/mineral/diamond/D
for(var/turf/simulated/mineral/diamond/M in world)
D = M
break
S.reagents.add_reagent("analysis_sample", 1, D.geological_data)
S.reagents.add_reagent("chlorine", 1, null)*/
/obj/machinery/anomaly/process()
//not sure if everything needs to heat up, or just the GLPC
var/datum/gas_mixture/env = loc.return_air()
var/environmental_temp = env.temperature
if(scan_process)
if(scan_process++ > target_scan_ticks)
FinishScan()
else if(temperature > 400)
src.visible_message("\blue \icon[src] shuts down from the heat!", 2)
scan_process = 0
else if(temperature > 350 && prob(10))
src.visible_message("\blue \icon[src] bleets plaintively.", 2)
if(temperature > 400)
scan_process = 0
//show we're busy
if(prob(5))
src.visible_message("\blue \icon[src] [pick("whirrs","chuffs","clicks")][pick(" quietly"," softly"," sadly"," excitedly"," energetically"," angrily"," plaintively")].", 2)
use_power = 2
else
use_power = 1
auto_use_power()
//Add 3000 joules when active. This is about 0.6 degrees per tick.
//May need adjustment
if(use_power == 1)
var/heat_added = active_power_usage *XENOARCH_HEAT_COEFFICIENT
if(temperature < max_temp)
temperature += heat_added/XENOARCH_HEAT_CAPACITY
var/temperature_difference = abs(environmental_temp-temperature)
var/datum/gas_mixture/removed = loc.remove_air(env.total_moles*0.25)
var/heat_capacity = removed.heat_capacity()
heat_added = max(temperature_difference*heat_capacity, XENOARCH_MAX_ENERGY_TRANSFER)
if(temperature > environmental_temp)
//cool down to match the air
temperature = max(TCMB, temperature - heat_added/XENOARCH_HEAT_CAPACITY)
removed.temperature = max(TCMB, removed.temperature + heat_added/heat_capacity)
if(temperature_difference > 10 && prob(5))
src.visible_message("\blue \icon[src] hisses softly.", 2)
else
//heat up to match the air
temperature = max(TCMB, temperature + heat_added/XENOARCH_HEAT_CAPACITY)
removed.temperature = max(TCMB, removed.temperature - heat_added/heat_capacity)
if(temperature_difference > 10 && prob(5))
src.visible_message("\blue \icon[src] plinks quietly.", 2)
env.merge(removed)
//this proc should be overriden by each individual machine
/obj/machinery/anomaly/attack_hand(var/mob/user as mob)
if(stat & (NOPOWER|BROKEN))
return
user.machine = src
var/dat = "<B>[src.name]</B><BR>"
dat += "Module heat level: [temperature] kelvin<br>"
dat += "Safeties set at 350k, shielding failure at 400k. Failure to maintain safe heat levels may result in equipment damage.<br>"
dat += "<hr>"
if(scan_process)
dat += "Scan in progress<br><br><br>"
else
dat += "[held_container ? "<A href='?src=\ref[src];eject_beaker=1'>Eject beaker</a>" : "No beaker inserted."]<br>"
//dat += "[fuel_container ? "<A href='?src=\ref[src];eject_fuel=1'>Eject fuel tank</a>" : "No fuel tank inserted."]<br>"
dat += "[held_container ? "<A href='?src=\ref[src];begin=1'>Begin scanning</a>" : ""]"
dat += "<hr>"
dat += "<A href='?src=\ref[src];refresh=1'>Refresh</a><BR>"
dat += "<A href='?src=\ref[src];close=1'>Close</a><BR>"
user << browse(dat, "window=anomaly;size=450x500")
onclose(user, "anomaly")
obj/machinery/anomaly/attackby(obj/item/weapon/W as obj, mob/living/user as mob)
if(istype(W, /obj/item/weapon/reagent_containers/glass))
//var/obj/item/weapon/reagent_containers/glass/G = W
if(held_container)
user << "\red You must remove the [held_container] first."
else
user << "\blue You put the [W] into the [src]."
user.drop_item(W)
held_container = W
held_container.loc = src
updateDialog()
/*else if(istype(W, /obj/item/weapon/tank))
//var/obj/item/weapon/reagent_containers/glass/G = W
if(fuel_container)
user << "\red You must remove the [fuel_container] first."
else
user << "\blue You put the [fuel_container] into the [src]."
user.drop_item(W)
fuel_container.loc = src
fuel_container = W
updateDialog()*/
else
return ..()
obj/machinery/anomaly/proc/ScanResults()
//instantiate in children to produce unique scan behaviour
return "\red Error initialising scanning components."
obj/machinery/anomaly/proc/FinishScan()
scan_process = 0
updateDialog()
//determine the results and print a report
if(held_container)
src.visible_message("\blue \icon[src] makes an insistent chime.", 2)
var/obj/item/weapon/paper/P = new(src.loc)
P.name = "[src] report #[++report_num]"
P.info = "<b>[src] analysis report #[report_num]</b><br><br>" + ScanResults()
P.stamped = list(/obj/item/weapon/stamp)
P.overlays = list("paper_stamped")
else
src.visible_message("\blue \icon[src] makes a low buzzing noise.", 2)
obj/machinery/anomaly/Topic(href, href_list)
..()
usr.set_machine(src)
if(href_list["close"])
usr << browse(null, "window=anomaly")
usr.machine = null
if(href_list["eject_beaker"])
held_container.loc = src.loc
held_container = null
if(href_list["eject_fuel"])
fuel_container.loc = src.loc
fuel_container = null
if(href_list["begin"])
if(temperature >= 350)
var/proceed = input("Unsafe internal temperature detected, enter YES below to continue.","Warning")
if(proceed == "YES" && get_dist(src, usr) <= 1)
scan_process = 1
else
scan_process = 1
updateUsrDialog()
//whether the carrier sample matches the possible finds
//results greater than a threshold of 0.6 means a positive result
obj/machinery/anomaly/proc/GetResultSpecifity(var/datum/geosample/scanned_sample, var/carrier_name)
var/specifity = 0
if(scanned_sample && carrier_name)
if(scanned_sample.find_presence.Find(carrier_name))
specifity = 0.75 * (scanned_sample.find_presence[carrier_name] / scanned_sample.total_spread) + 0.25
else
specifity = rand(0, 0.5)
return specifity

View File

@@ -1,34 +0,0 @@
// This machine tells the distance to a nearby artifact, if there is one
obj/machinery/anomaly/fourier_transform
name = "Fourier Transform spectroscope"
obj/machinery/anomaly/fourier_transform/ScanResults()
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
var/datum/geosample/scanned_sample
var/carrier
var/num_reagents = 0
for(var/datum/reagent/A in held_container.reagents.reagent_list)
var/datum/reagent/R = A
if(istype(R, /datum/reagent/analysis_sample))
scanned_sample = R.data
else
carrier = R.id
num_reagents++
if(num_reagents == 2 && scanned_sample && carrier)
//all necessary components are present
var/specifity = GetResultSpecifity(scanned_sample, carrier)
var/distance = scanned_sample.artifact_distance
if(distance > 0)
distance += (2 * rand() - 1) * distance * 0.05
results = "Fourier transform analysis on anomalous energy absorption through carrier ([carrier]) indicates source located inside emission radius ([95 * specifity]% accuracy): [distance]."
else
results = "Energy dispersion detected throughout sample consistent with background readings.<br>"
if(carrier == scanned_sample.source_mineral)
results += "Warning, analysis may be contaminated by high quantities of molecular carrier present throughout sample."
return results

View File

@@ -1,39 +0,0 @@
// This machine shows the materials that are present
obj/machinery/anomaly/gas_chromatography
name = "Gas Chromatography spectrometer"
obj/machinery/anomaly/gas_chromatography/ScanResults()
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
var/datum/geosample/scanned_sample
var/carrier
var/num_reagents = 0
for(var/datum/reagent/A in held_container.reagents.reagent_list)
var/datum/reagent/R = A
if(istype(R, /datum/reagent/analysis_sample))
scanned_sample = R.data
else
carrier = R.id
num_reagents++
if(num_reagents == 2 && scanned_sample)
var/specifity = GetResultSpecifity(scanned_sample, carrier)
results = "Chromatography partitioning analysis over carrier ([carrier]) indicates the following elements present ([100 * specifity]% accuracy):<br><br>"
var/num_found = 0
for(var/index=1,index <= scanned_sample.find_presence.len, index++)
var/find = scanned_sample.find_presence[index]
if(find && prob(100 * specifity))
results += " - " + finds_as_strings[index] + "<br>"
num_found++
if(!num_found)
results = "Chromatography partitioning results over carrier ([carrier]) to determine elemental makeup were inconclusive.<br>"
if(!carrier)
results += "<br>No carrier detected, scan accuracy affected.<br>"
return results

View File

@@ -1,55 +0,0 @@
obj/machinery/anomaly/hyperspectral
name = "Hyperspectral Imager"
icon = 'icons/obj/xenoarchaeology.dmi'
icon_state = "scanner"
obj/machinery/anomaly/hyperspectral/process()
..()
if(scan_process)
icon_state = "scanner_active"
else if(prob(10))
icon_state = "scanner"
flick(src, "scanner_active")
obj/machinery/anomaly/hyperspectral/ScanResults()
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
var/datum/geosample/scanned_sample
var/carrier
var/num_reagents = 0
for(var/datum/reagent/A in held_container.reagents.reagent_list)
var/datum/reagent/R = A
if(istype(R, /datum/reagent/analysis_sample))
scanned_sample = R.data
else
carrier = R.id
num_reagents++
if(num_reagents == 2 && scanned_sample && carrier)
//all necessary components are present
var/specifity = GetResultSpecifity(scanned_sample, carrier)
results = "Spectral signature over carrier ([carrier]):<br>"
if(specifity <= 0.25)
//results += "<img src=\"http://i.imgur.com/TAQHn.jpg\"></img><br>"
results += "<img src=chart1.jpg>"
else if(specifity <= 0.5)
//results += "<img src=\"http://i.imgur.com/EwOZ7.jpg\"></img><br>"
results += "<img src=chart2.jpg>"
else if(specifity <= 0.75)
//results += "<img src=\"http://i.imgur.com/1qCae.jpg\"></img><br>"
results += "<img src=chart3.jpg>"
else
//results += "<img src=\"http://i.imgur.com/9T9nc.jpg\"></img><br>"
results += "<img src=chart4.jpg>"
results += "<br>"
if(scanned_sample.artifact_id)
results += "Detected energy signatures [100 * (1 - specifity)]% consistent with standard background readings.<br>"
if(prob( (specifity + 0.5 * (1 - specifity)) * 100))
results += "Anomalous exotic energy signature isolated: <font color='red'><b>[scanned_sample.artifact_id].</b></font>"
else
results += "Detected energy signatures [95 + 5 * (2 * rand() - 1) * (1 - specifity)]% consistent with standard background readings."
return results

View File

@@ -1,47 +0,0 @@
// This machine shows the amount of a certain material that is present
obj/machinery/anomaly/ion_mobility
name = "Ion Mobility Spectrometer"
desc = "A specialised, complex analysis machine."
icon = 'icons/obj/virology.dmi'
icon_state = "analyser"
obj/machinery/anomaly/ion_mobility/ScanResults()
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
var/datum/geosample/scanned_sample
var/carrier
var/num_reagents = 0
for(var/datum/reagent/A in held_container.reagents.reagent_list)
var/datum/reagent/R = A
if(istype(R, /datum/reagent/analysis_sample))
scanned_sample = R.data
else
carrier = R.id
num_reagents++
if(num_reagents == 2 && scanned_sample && carrier)
//all necessary components are present
results = "Kinetic analysis on sample's ionic residue in carrier ([carrier]) indicates the dissonance spread:<br><br>"
var/found = 0
if(scanned_sample.find_presence.Find(carrier))
var/dis_ratio = scanned_sample.find_presence[carrier]
var/desc_index = responsive_carriers.Find(carrier)
results += " - [finds_as_strings[desc_index]]: [dis_ratio]<br>"
found++
/*
for(var/index=1,index <= scanned_sample.find_presence.len, index++)
var/find = scanned_sample.find_presence[index]
//world << "index: [index], find: [find], response: [responsive_carriers[index]], carrier: [carrier]"
if(find && responsive_carriers[index] == carrier)
results += " - [finds_as_strings[index]] [find * 100]%<br>"
found++
*/
if(!found)
results = "Kinetic analysis on sample's ionic residue in carrier ([carrier]) to determine composition were inconclusive.<br>"
if(carrier == scanned_sample.source_mineral)
results += "Warning, analysis may be contaminated by high quantities of molecular carrier present throughout sample."
return results

View File

@@ -1,51 +0,0 @@
// This machine shows the age for newer finds
obj/machinery/anomaly/isotope_ratio
name = "Isotope ratio spectrometer"
desc = "A specialised, complex analysis machine."
icon = 'icons/obj/virology.dmi'
icon_state = "analyser"
obj/machinery/anomaly/isotope_ratio/ScanResults()
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
var/datum/geosample/scanned_sample
var/carrier_name
var/num_reagents = 0
for(var/datum/reagent/A in held_container.reagents.reagent_list)
var/datum/reagent/R = A
if(istype(R, /datum/reagent/analysis_sample))
scanned_sample = R.data
else
carrier_name = R.id
num_reagents++
if(num_reagents == 2 && scanned_sample && carrier_name)
var/accuracy = GetResultSpecifity(scanned_sample, carrier_name)
accuracy += 0.5 * (1 - accuracy) / scanned_sample.total_spread
if(!accuracy)
accuracy = rand(0.01, 0.5)
results = "Isotope decay analysis in carrier ([carrier_name]) indicates age ([100 * accuracy]% accuracy): <br><br>"
if(scanned_sample.age_billion)
//scramble the results
var/displayed_age_thousands = rand(0, 999)
var/displayed_age_millions = rand(0, 999)
results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.<br>"
else if(scanned_sample.age_million)
var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - accuracy) * (2 * rand() - 1)), 0)
var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - accuracy) * (4 * rand() - 2)), 0)
results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.<br>"
else if(scanned_sample.age_thousand)
var/displayed_age = scanned_sample.age + scanned_sample.age * ((1 - accuracy) * (2 * rand() - 1))
var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - accuracy) * (2 * rand() - 1)), 0)
results += "[displayed_age_thousands + displayed_age / 1000] thousand years.<br>"
else
var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - accuracy) * (2 * rand() - 1)), 0)
results += "[displayed_age] years.<br>"
results += "<br>Warning, results only valid up to ages of one billion years."
return results

View File

@@ -1,318 +0,0 @@
//cael - some changes here. the analysis pad is entirely new
/obj/machinery/artifact_analyser
name = "Artifact Analyser"
desc = "Studies the structure of artifacts to discover their uses."
icon = 'icons/obj/virology.dmi'
icon_state = "analyser"
anchored = 1
density = 1
var/working = 0
var/accuO = 0
var/accuT = 0
var/accuE1 = 0
var/accuE2 = 0
var/aorigin = "None"
var/atrigger = "None"
var/aeffect1 = "None"
var/aeffect2 = "None"
var/list/origin_bonuses
var/list/trigger_bonuses
var/list/function_bonuses
var/list/range_bonuses
var/cur_id = ""
var/scan_num = 0
var/obj/machinery/artifact/cur_artifact = null
var/obj/machinery/analyser_pad/owned_pad = null
var/list/allorigins = list("Ancient Robots","Martian","Wizard Federation","Extradimensional","Precursor")
var/list/alltriggers = list("Contact with Living Organism","Heavy Impact","Contact with Energy Source","Contact with Hydrogen","Contact with Corrosive Substance","Contact with Volatile Substance","Contact with Toxins","Exposure to Heat")
var/list/alleffects = list("Healing Device","Anti-biological Weapon","Non-lethal Stunning Trap","Mechanoid Repair Module","Mechanoid Deconstruction Device","Power Generator","Power Drain","Stellar Mineral Attractor","Agriculture Regulator","Shield Generator","Space-Time Displacer")
var/list/allranges = list("Constant Short-Range Energy Field","Medium Range Energy Pulses","Long Range Energy Pulses","Extreme Range Energy Pulses","Requires contact with subject")
/obj/machinery/artifact_analyser/New()
..()
origin_bonuses = new/list()
origin_bonuses["ancient"] = 0
origin_bonuses["martian"] = 0
origin_bonuses["wizard"] = 0
origin_bonuses["eldritch"] = 0
origin_bonuses["precursor"] = 0
trigger_bonuses = new/list()
trigger_bonuses["ancient"] = 0
trigger_bonuses["martian"] = 0
trigger_bonuses["wizard"] = 0
trigger_bonuses["eldritch"] = 0
trigger_bonuses["precursor"] = 0
function_bonuses = new/list()
function_bonuses["ancient"] = 0
function_bonuses["martian"] = 0
function_bonuses["wizard"] = 0
function_bonuses["eldritch"] = 0
function_bonuses["precursor"] = 0
range_bonuses = new/list()
range_bonuses["ancient"] = 0
range_bonuses["martian"] = 0
range_bonuses["wizard"] = 0
range_bonuses["eldritch"] = 0
range_bonuses["precursor"] = 0
//
spawn(10)
owned_pad = locate() in orange(1, src)
/obj/machinery/artifact_analyser/attack_hand(var/mob/user as mob)
if(stat & (NOPOWER|BROKEN))
return
user.machine = src
var/dat = "<B>Artifact Analyser</B><BR>"
dat += "<HR><BR>"
if(!owned_pad)
dat += "<B><font color=red>Unable to locate analysis pad.</font><BR></b>"
dat += "<HR><BR>"
else if (!src.working)
dat += "<B>Artifact ID:</B> [cur_id]<BR>"
dat += "<B>Artifact Origin:</B> [aorigin] ([accuO]%)<BR>"
dat += "<B>Activation Trigger:</B> [atrigger] ([accuT]%)<BR>"
dat += "<B>Artifact Function:</B> [aeffect1] ([accuE1]%)<BR>"
dat += "<B>Artifact Range:</B> [aeffect2] ([accuE2]%)<BR><BR>"
dat += "<HR><BR>"
dat += "Artifact ID is determined from unique energy emission signatures.<br>"
dat += "<A href='?src=\ref[src];analyse=1'>Analyse Artifact (Scan number #[scan_num+1])</a><BR>"
dat += "<A href='?src=\ref[src];upload=1'>Upload/update artifact scan</a><BR>"
dat += "<A href='?src=\ref[src];print=1'>Print Page</a><BR>"
else
dat += "<B>Please wait. Analysis in progress.</B><BR>"
dat += "<HR><BR>"
//
dat += "<A href='?src=\ref[src];close=1'>Close<BR>"
user << browse(dat, "window=artanalyser;size=450x500")
onclose(user, "artanalyser")
/obj/machinery/artifact_analyser/process()
if(stat & (NOPOWER|BROKEN))
return
use_power(350)
//
if(!owned_pad)
for(var/obj/machinery/analyser_pad/pad in range(1))
owned_pad = pad
break
/obj/machinery/artifact_analyser/proc/AA_FailedAnalysis(var/failtype)
switch(failtype)
if(1)
src.aorigin = "Failed to Identify"
if (prob(20)) src.aorigin = pick(src.allorigins)
if(2)
src.atrigger = "Failed to Identify"
if (prob(20)) src.atrigger = pick(src.alltriggers)
if(3)
src.aeffect1 = "Failed to Identify"
if (prob(20)) src.aeffect1 = pick(src.alleffects)
if(4)
src.aeffect2 = "Failed to Identify"
if (prob(20)) src.aeffect2 = pick(src.allranges)
/obj/machinery/artifact_analyser/proc/AA_Analyse()
if(!cur_artifact)
return
src.accuO = 5 + rand(0,10) + origin_bonuses[cur_artifact.origin] + cur_artifact.activated * 50
src.accuT = 5 + rand(0,10) + trigger_bonuses[cur_artifact.origin] + cur_artifact.activated * 50
src.accuE1 = 5 + rand(0,10) + function_bonuses[cur_artifact.origin] + cur_artifact.activated * 50
src.accuE2 = 5 + rand(0,10) + range_bonuses[cur_artifact.origin] + cur_artifact.activated * 50
//keep any correctly determined properties the same
var/origin_correct = 0
var/trigger_correct = 0
var/function_correct = 0
var/range_correct = 0
if(cur_id == cur_artifact.display_id)
if(src.aorigin == cur_artifact.origin)
origin_correct = 1
if(src.atrigger == cur_artifact.my_effect.trigger)
trigger_correct = 1
else if(src.atrigger == cur_artifact.my_effect.triggerX)
trigger_correct = 1
if(src.aeffect1 == cur_artifact.my_effect.effecttype)
function_correct = 1
if(src.aeffect2 == cur_artifact.my_effect.effectmode)
range_correct = 1
if (src.accuO > 100) src.accuO = 100
if (src.accuT > 100) src.accuT = 100
if (src.accuE1 > 100) src.accuE1 = 100
if (src.accuE2 > 100) src.accuE2 = 100
// Roll to generate report
if (prob(accuO) || origin_correct)
switch(cur_artifact.origin)
if("ancient") src.aorigin = "Ancient Robots"
if("martian") src.aorigin = "Martian"
if("wizard") src.aorigin = "Wizard Federation"
if("eldritch") src.aorigin = "Extradimensional"
if("precursor") src.aorigin = "Precursor"
else src.aorigin = "Unknown Origin"
origin_bonuses[cur_artifact.origin] += 10
else
AA_FailedAnalysis(1)
origin_bonuses[cur_artifact.origin] += 5
if (prob(accuT) || trigger_correct)
switch(cur_artifact.my_effect.trigger)
if("touch") src.atrigger = "Contact with Living Organism"
if("force") src.atrigger = "Heavy Impact"
if("energy") src.atrigger = "Contact with Energy Source"
if("chemical")
switch(cur_artifact.my_effect.triggerX)
if("hydrogen") src.atrigger = "Contact with Hydrogen"
if("corrosive") src.atrigger = "Contact with Corrosive Substance"
if("volatile") src.atrigger = "Contact with Volatile Substance"
if("toxin") src.atrigger = "Contact with Toxins"
if("heat") src.atrigger = "Exposure to Heat"
else src.atrigger = "Unknown Trigger"
trigger_bonuses[cur_artifact.origin] += 5
else
AA_FailedAnalysis(2)
trigger_bonuses[cur_artifact.origin] += 1
if (prob(accuE1) || function_correct)
switch(cur_artifact.my_effect.effecttype)
if("healing") src.aeffect1 = "Healing Device"
if("injure") src.aeffect1 = "Anti-biological Weapon"
// if("stun") src.aeffect1 = "Non-lethal Stunning Trap"
if("roboheal") src.aeffect1 = "Mechanoid Repair Module"
if("robohurt") src.aeffect1 = "Mechanoid Deconstruction Device"
if("cellcharge") src.aeffect1 = "Power Generator"
if("celldrain") src.aeffect1 = "Power Drain"
if("planthelper") src.aeffect1 = "Agriculture Regulator"
if("forcefield") src.aeffect1 = "Shield Generator"
if("teleport") src.aeffect1 = "Space-Time Displacer"
else src.aeffect1 = "Unknown Effect"
function_bonuses[cur_artifact.origin] += 5
else
AA_FailedAnalysis(3)
function_bonuses[cur_artifact.origin] += 1
if (prob(accuE2) || range_correct)
switch(cur_artifact.my_effect.effectmode)
if("aura") src.aeffect2 = "Constant Short-Range Energy Field"
if("pulse")
if(cur_artifact.my_effect.aurarange > 7) src.aeffect2 = "Long Range Energy Pulses"
else src.aeffect2 = "Medium Range Energy Pulses"
if("worldpulse") src.aeffect2 = "Extreme Range Energy Pulses"
if("contact") src.aeffect2 = "Requires contact with subject"
else src.aeffect2 = "Unknown Range"
range_bonuses[cur_artifact.origin] += 5
else
AA_FailedAnalysis(4)
range_bonuses[cur_artifact.origin] += 1
cur_artifact.name = "alien artifact ([cur_artifact.display_id])"
cur_artifact.desc = "A large alien device. It has a small tag near the bottom that reads \"[cur_artifact.display_id]\"."
cur_id = cur_artifact.display_id
cur_artifact.my_effect.artifact_id = cur_artifact.display_id
/obj/machinery/artifact_analyser/Topic(href, href_list)
if(href_list["analyse"])
if(owned_pad)
var/turf/pad_turf = get_turf(owned_pad)
var/findarti = 0
for(var/obj/machinery/artifact/A in pad_turf.contents)
findarti++
cur_artifact = A
if (findarti == 1)
if(cur_artifact && cur_artifact.being_used)
var/message = "<b>[src]</b> states, \"Cannot analyse. Excess energy drain is disrupting signal.\""
src.visible_message(message, message)
else
cur_artifact.anchored = 1
cur_artifact.being_used = 1
src.working = 1
src.icon_state = "analyser_processing"
var/time = rand(30,50) + max(0, 300 - scan_num * 10)
/*for(var/i = artifact_research.starting_tier, i <= artifact_research.max_tiers, i++)
for(var/datum/artiresearch/R in artifact_research.researched_items[i])
if (R.bonustype == "analyser") time -= R.bonusTime*/
time *= 10
var/message = "<b>[src]</b> states, \"Commencing analysis.\""
src.visible_message(message, message)
use_power(500)
spawn(time)
src.working = 0
icon_state = "analyser"
cur_artifact.anchored = 0
cur_artifact.being_used = 0
if(cur_artifact.loc == pad_turf)
AA_Analyse()
scan_num++
message = "<b>[src]</b> states, \"Analysis complete.\""
src.visible_message(message, message)
use_power(500)
else if (findarti > 1)
var/message = "<b>[src]</b> states, \"Cannot analyse. Error isolating energy signature.\""
src.visible_message(message, message)
else
var/message = "<b>[src]</b> states, \"Cannot analyse. No noteworthy energy signature isolated.\""
src.visible_message(message, message)
if(href_list["upload"] && cur_id != "")
//add new datum to every DB in the world
for(var/obj/machinery/computer/artifact_database/DB in world)
var/update = 0
for(var/datum/catalogued_artifact/CA in DB.catalogued_artifacts)
if(CA.display_id == cur_id)
//already there, so update it
update = 1
CA.origin = aorigin + " ([accuO]%)"
CA.trigger = atrigger + " ([accuT]%)"
CA.effecttype = aeffect1 + " ([accuE1]%)"
CA.effectmode = aeffect2 + " ([accuE2]%)"
if(!update)
//not there, so add it
var/datum/catalogued_artifact/CA = new()
CA.display_id = cur_id
CA.origin = aorigin + " ([accuO]%)"
CA.trigger = atrigger + " ([accuT]%)"
CA.effecttype = aeffect1 + " ([accuE1]%)"
CA.effectmode = aeffect2 + " ([accuE2]%)"
DB.catalogued_artifacts.Add(CA)
use_power(100)
if(href_list["print"])
var/r = "Artifact Analysis Report (Scan #[scan_num])<hr>"
r += "<B>Artifact ID:</B> [cur_id] (determined from unique energy emission signatures)<BR>"
r += "<B>Artifact Origin:</B> [aorigin] ([accuO]%)<BR>"
r += "<B>Activation Trigger:</B> [atrigger] ([accuT]%)<BR>"
r += "<B>Artifact Function:</B> [aeffect1] ([accuE1]%)<BR>"
r += "<B>Artifact Range:</B> [aeffect2] ([accuE2]%)<BR><BR>"
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(src.loc)
P.name = "Artifact Analysis Report #[scan_num]"
P.info = r
for(var/mob/O in hearers(src, null))
O.show_message("\icon[src] \blue The [src.name] prints a sheet of paper", 3)
use_power(10)
if(href_list["close"])
usr << browse(null, "window=artanalyser")
usr.machine = null
src.updateDialog()
//stick artifacts onto this then switch the analyser on
/obj/machinery/analyser_pad
name = "artifact analysis pad"
desc = "Studies the structure of artifacts to discover their uses."
icon = 'icons/obj/stationobjs.dmi'
icon_state = "tele0"
anchored = 1
density = 0
/obj/machinery/analyser_pad/New()
..()
/*spawn(10)
for(var/obj/machinery/artifact_analyser/analyser in orange(1))
world << "pad found analyser"
if(!analyser.owned_pad)
analyser.owned_pad = src
world << "pad set analyser to self"
break*/

View File

@@ -1,58 +0,0 @@
/datum/catalogued_artifact
var/trigger = "touch" // What activates it?
var/effecttype = "healing" // What does it do?
var/effectmode = "aura" // How does it carry out the effect?
var/display_id = "" // Artifact ID to display once successfully scanned
var/origin = ""
/obj/machinery/computer/artifact_database
name = "Artifact Database"
icon_state = "rdcomp"
var/list/catalogued_artifacts
/obj/machinery/computer/artifact_database/New()
..()
catalogued_artifacts = new/list
/obj/machinery/computer/artifact_database/Topic(href, href_list)
..()
if( href_list["close"] )
usr << browse(null, "window=artifact_db")
usr.machine = null
updateDialog()
/obj/machinery/computer/artifact_database/process()
..()
updateDialog()
/obj/machinery/computer/artifact_database/interact(mob/user)
if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) )
if (!istype(user, /mob/living/silicon))
user.machine = null
user << browse(null, "window=artifact_db")
return
var/t = "<B>Artifact Database</B><BR>"
t += "<hr>"
for(var/datum/catalogued_artifact/CA in catalogued_artifacts)
t += "<B>Artifact ID:</B> [CA.display_id] (determined from unique energy emission signatures)<BR>"
t += "<B>Artifact Origin:</B> [CA.origin]<BR>"
t += "<B>Activation Trigger:</B> [CA.trigger]<BR>"
t += "<B>Artifact Function:</B> [CA.effecttype]<BR>"
t += "<B>Artifact Range:</B> [CA.effectmode]<BR><BR>"
t += "<hr>"
t += "<A href='?src=\ref[src];refresh=1'>Refresh</A> <A href='?src=\ref[src];close=1'>Close</A><BR>"
user << browse(t, "window=artifact_db;size=500x800")
user.machine = src
/*
/datum/artifact_effect
var/origin = null // Used in the randomisation/research of the artifact.
var/trigger = "touch" // What activates it?
var/triggerX = "none" // Used for more varied triggers
var/effecttype = "healing" // What does it do?
var/effectmode = "aura" // How does it carry out the effect?
var/aurarange = 4 // How far the artifact will extend an aura effect.
var/display_id = "" // Artifact ID to display once successfully scanned
var/list/created_field
*/

View File

@@ -0,0 +1,59 @@
datum/reagent/coolant
name = "Coolant"
id = "coolant"
description = "Industrial cooling substance."
reagent_state = LIQUID
color = "#C8A5DC" // rgb: 200, 165, 220
datum/chemical_reaction/coolant
name = "Coolant"
id = "coolant"
result = "coolant"
required_reagents = list("tungsten" = 1, "oxygen" = 1, "water" = 1)
result_amount = 3
/obj/structure/reagent_dispensers/coolanttank
name = "coolant tank"
desc = "A tank of industrial coolant"
icon = 'icons/obj/objects.dmi'
icon_state = "coolanttank"
amount_per_transfer_from_this = 10
New()
..()
reagents.add_reagent("coolant",1000)
/obj/structure/reagent_dispensers/coolanttank/bullet_act(var/obj/item/projectile/Proj)
if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
if(!istype(Proj ,/obj/item/projectile/beam/lastertag) && !istype(Proj ,/obj/item/projectile/beam/practice) )
explode()
/obj/structure/reagent_dispensers/coolanttank/blob_act()
explode()
/obj/structure/reagent_dispensers/coolanttank/ex_act()
explode()
/obj/structure/reagent_dispensers/coolanttank/proc/explode()
var/datum/effect/effect/system/harmless_smoke_spread/S = new /datum/effect/effect/system/harmless_smoke_spread
//S.attach(src)
S.set_up(5, 0, src.loc)
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
spawn(0)
S.start()
var/datum/gas_mixture/env = src.loc.return_air()
if(env)
if (reagents.total_volume > 750)
env.temperature = 0
else if (reagents.total_volume > 500)
env.temperature -= 100
else
env.temperature -= 50
sleep(10)
if(src)
del(src)

View File

@@ -0,0 +1,355 @@
/obj/machinery/radiocarbon_spectrometer
name = "Radiocarbon spectrometer"
desc = "A specialised, complex scanner for gleaning information on all manner of small things."
anchored = 1
density = 1
icon = 'icons/obj/virology.dmi'
icon_state = "analyser"
use_power = 1 //1 = idle, 2 = active
idle_power_usage = 20
active_power_usage = 300
//var/obj/item/weapon/reagent_containers/glass/coolant_container
var/scanning = 0
var/report_num = 0
//
var/obj/item/scanned_item
var/last_scan_data = "No scans on record."
//
var/last_process_worldtime = 0
//
var/scanner_progress = 0
var/scanner_rate = 1.25 //80 seconds per scan
var/scanner_rpm = 0
var/scanner_rpm_dir = 1
var/scanner_temperature = 0
var/scanner_seal_integrity = 100
//
var/coolant_usage_rate = 0 //measured in u/microsec
var/fresh_coolant = 0
var/coolant_purity = 0
var/datum/reagents/coolant_reagents
var/used_coolant = 0
var/list/coolant_reagents_purity = list()
//
var/maser_wavelength = 0
var/optimal_wavelength = 0
var/optimal_wavelength_target = 0
var/tleft_retarget_optimal_wavelength = 0
var/maser_efficiency = 0
//
var/radiation = 0 //0-100 mSv
var/t_left_radspike = 0
var/rad_shield = 0
/obj/machinery/radiocarbon_spectrometer/New()
..()
create_reagents(500)
coolant_reagents_purity["water"] = 0.5
coolant_reagents_purity["icecoffee"] = 0.6
coolant_reagents_purity["icetea"] = 0.6
coolant_reagents_purity["milkshake"] = 0.6
coolant_reagents_purity["leporazine"] = 0.7
coolant_reagents_purity["kelotane"] = 0.7
coolant_reagents_purity["sterilizine"] = 0.7
coolant_reagents_purity["dermaline"] = 0.7
coolant_reagents_purity["hyperzine"] = 0.8
coolant_reagents_purity["cryoxadone"] = 0.9
coolant_reagents_purity["coolant"] = 1
coolant_reagents_purity["adminordrazine"] = 2
/obj/machinery/radiocarbon_spectrometer/attack_hand(var/mob/user as mob)
ui_interact(user)
/obj/machinery/radiocarbon_spectrometer/attackby(var/obj/I as obj, var/mob/user as mob)
if(scanning)
user << "<span class='warning'>You can't do that while [src] is scanning!</span>"
else
if(istype(I, /obj/item/stack/nanopaste))
var/choice = alert("What do you want to do with the nanopaste?","Radiometric Scanner","Add nanopaste","Fix seal integrity")
if(choice == "Fix seal integrity")
var/obj/item/stack/nanopaste/N = I
var/amount_used = min(N.amount, 10 - scanner_seal_integrity / 10)
N.use(amount_used)
scanner_seal_integrity = round(scanner_seal_integrity + amount_used * 10)
return
if(istype(I, /obj/item/weapon/reagent_containers/glass))
var/choice = alert("What do you want to do with the container?","Radiometric Scanner","Add coolant","Empty coolant","Scan container")
if(choice == "Add coolant")
var/obj/item/weapon/reagent_containers/glass/G = I
G.reagents.trans_to(src, min(src.reagents.maximum_volume - src.reagents.total_volume, G.reagents.total_volume))
update_coolant()
return
else if(choice == "Empty coolant")
var/obj/item/weapon/reagent_containers/glass/G = I
src.reagents.trans_to(G, min(G.reagents.maximum_volume - G.reagents.total_volume, src.reagents.total_volume))
update_coolant()
return
user.drop_item()
I.loc = src
scanned_item = I
/obj/machinery/radiocarbon_spectrometer/proc/update_coolant()
var/total_purity = 0
fresh_coolant = 0
coolant_purity = 0
for (var/datum/reagent/current_reagent in src.reagents.reagent_list)
if (!current_reagent)
continue
var/cur_purity = coolant_reagents_purity[current_reagent.id]
if(!cur_purity)
cur_purity = 0.1
total_purity += cur_purity
fresh_coolant += current_reagent.volume
if(total_purity && fresh_coolant)
coolant_purity = total_purity / fresh_coolant
/obj/machinery/radiocarbon_spectrometer/ui_interact(mob/user, ui_key = "radio_spectro")
if(user.stat)
return
// this is the data which will be sent to the ui
var/data[0]
data["scanned_item"] = (scanned_item ? scanned_item.name : "")
data["scanned_item_desc"] = (scanned_item ? (scanned_item.desc ? scanned_item.desc : "No information on record.") : "")
data["last_scan_data"] = last_scan_data
//
data["scan_progress"] = round(scanner_progress)
data["scanning"] = scanning
//
data["scanner_seal_integrity"] = round(scanner_seal_integrity)
data["scanner_rpm"] = round(scanner_rpm)
data["scanner_temperature"] = round(scanner_temperature)
//
data["coolant_usage_rate"] = "[coolant_usage_rate]"
data["unused_coolant_abs"] = round(fresh_coolant)
data["unused_coolant_per"] = round(fresh_coolant / reagents.maximum_volume * 100)
data["coolant_purity"] = "[coolant_purity * 100]"
//
data["optimal_wavelength"] = round(optimal_wavelength)
data["maser_wavelength"] = round(maser_wavelength)
data["maser_efficiency"] = round(maser_efficiency * 100)
//
data["radiation"] = round(radiation)
data["t_left_radspike"] = round(t_left_radspike)
data["rad_shield_on"] = rad_shield
var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key)
if (!ui)
// the ui does not exist, so we'll create a new one
ui = new(user, src, ui_key, "geoscanner.tmpl", "High Res Radiocarbon Spectrometer", 900, 825)
// When the UI is first opened this is the data it will use
ui.set_initial_data(data)
ui.open()
// Auto update every Master Controller tick
ui.set_auto_update(1)
else
// The UI is already open so push the new data to it
ui.push_data(data)
return
/obj/machinery/radiocarbon_spectrometer/process()
if(scanning)
if(!scanned_item || scanned_item.loc != src)
scanned_item = null
stop_scanning()
else if(scanner_progress >= 100)
complete_scan()
else
//calculate time difference
var/deltaT = (world.time - last_process_worldtime) * 0.1
//modify the RPM over time
//i want 1u to last for 10 sec at 500 RPM, scaling linearly
scanner_rpm += scanner_rpm_dir * 50 * deltaT
if(scanner_rpm > 1000)
scanner_rpm = 1000
scanner_rpm_dir = -1 * pick(0.5, 2.5, 5.5)
else if(scanner_rpm < 1)
scanner_rpm = 1
scanner_rpm_dir = 1 * pick(0.5, 2.5, 5.5)
//heat up according to RPM
//each unit of coolant
scanner_temperature += scanner_rpm * deltaT * 0.05
//radiation
t_left_radspike -= deltaT
if(t_left_radspike > 0)
//ordinary radiation
radiation = rand() * 15
else
//radspike
if(t_left_radspike > -5)
radiation = rand() * 15 + 85
if(!rad_shield)
//irradiate nearby mobs
for(var/mob/living/M in view(7,src))
M.apply_effect(radiation / 25, IRRADIATE, 0)
else
t_left_radspike = pick(10,15,25)
//use some coolant to cool down
if(coolant_usage_rate > 0)
var/coolant_used = min(fresh_coolant, coolant_usage_rate * deltaT)
if(coolant_used > 0)
fresh_coolant -= coolant_used
used_coolant += coolant_used
scanner_temperature = max(scanner_temperature - coolant_used * coolant_purity * 20, 0)
//modify the optimal wavelength
tleft_retarget_optimal_wavelength -= deltaT
if(tleft_retarget_optimal_wavelength <= 0)
tleft_retarget_optimal_wavelength = pick(4,8,15)
optimal_wavelength_target = rand() * 9900 + 100
//
if(optimal_wavelength < optimal_wavelength_target)
optimal_wavelength = min(optimal_wavelength + 700 * deltaT, optimal_wavelength_target)
else if(optimal_wavelength > optimal_wavelength_target)
optimal_wavelength = max(optimal_wavelength - 700 * deltaT, optimal_wavelength_target)
//
maser_efficiency = 1 - max(min(10000, abs(optimal_wavelength - maser_wavelength) * 3), 1) / 10000
//make some scan progress
if(!rad_shield)
scanner_progress = min(100, scanner_progress + scanner_rate * maser_efficiency * deltaT)
//degrade the seal over time according to temperature
//i want temperature of 50K to degrade at 1%/sec
scanner_seal_integrity -= (max(scanner_temperature, 1) / 1000) * deltaT
//emergency stop if seal integrity reaches 0
if(scanner_seal_integrity <= 0 || (scanner_temperature >= 1273 && !rad_shield))
stop_scanning()
src.visible_message("\blue \icon[src] buzzes unhappily. It has failed mid-scan!", 2)
if(prob(5))
src.visible_message("\blue \icon[src] [pick("whirrs","chuffs","clicks")][pick(" excitedly"," energetically"," busily")].", 2)
else
//gradually cool down over time
if(scanner_temperature > 0)
scanner_temperature = max(scanner_temperature - 5 - 10 * rand(), 0)
if(prob(0.75))
src.visible_message("\blue \icon[src] [pick("plinks","hisses")][pick(" quietly"," softly"," sadly"," plaintively")].", 2)
last_process_worldtime = world.time
/obj/machinery/radiocarbon_spectrometer/proc/stop_scanning()
scanning = 0
scanner_rpm_dir = 1
scanner_rpm = 0
optimal_wavelength = 0
maser_efficiency = 0
maser_wavelength = 0
coolant_usage_rate = 0
radiation = 0
t_left_radspike = 0
if(used_coolant)
src.reagents.remove_any(used_coolant)
used_coolant = 0
/obj/machinery/radiocarbon_spectrometer/proc/complete_scan()
src.visible_message("\blue \icon[src] makes an insistent chime.", 2)
if(scanned_item)
//create report
var/obj/item/weapon/paper/P = new(src)
P.name = "[src] report #[++report_num]: [scanned_item.name]"
P.stamped = list(/obj/item/weapon/stamp)
P.overlays = list("paper_stamped")
//work out data
var/data = " - Mundane object: [scanned_item.desc ? scanned_item.desc : "No information on record."]<br>"
var/datum/geosample/G
switch(scanned_item.type)
if(/obj/item/weapon/ore)
var/obj/item/weapon/ore/O = scanned_item
if(O.geological_data)
G = O.geological_data
if(/obj/item/weapon/rocksliver)
var/obj/item/weapon/rocksliver/O = scanned_item
if(O.geological_data)
G = O.geological_data
if(/obj/item/weapon/archaeological_find)
data = " - Mundane object (archaic xenos origins)<br>"
var/obj/item/weapon/archaeological_find/A = scanned_item
if(A.speaking_to_players)
data = " - Exhibits properties consistent with sonic reproduction.<br>"
if(A.listening_to_players)
data = " - Exhibits properties similar to audio capture technology.<br>"
var/anom_found = 0
if(G)
data = " - Spectometric analysis on mineral sample has determined type [finds_as_strings[responsive_carriers.Find(G.source_mineral)]]<br>"
if(G.age_billion > 0)
data += " - Radiometric dating shows age of [G.age_billion].[G.age_million] billion years<br>"
else if(G.age_million > 0)
data += " - Radiometric dating shows age of [G.age_million].[G.age_thousand] million years<br>"
else
data += " - Radiometric dating shows age of [G.age_thousand * 1000 + G.age] years<br>"
data += " - Chromatographic analysis shows the following materials present:<br>"
for(var/carrier in G.find_presence)
if(G.find_presence[carrier])
var/index = responsive_carriers.Find(carrier)
if(index > 0 && index <= finds_as_strings.len)
data += " > [100 * G.find_presence[carrier]]% [finds_as_strings[index]]<br>"
if(G.artifact_id && G.artifact_distance >= 0)
anom_found = 1
data += " - Hyperspectral imaging reveals exotic energy wavelength detected with ID: [G.artifact_id]<br>"
data += " - Fourier transform analysis on anomalous energy absorption indicates energy source located inside emission radius of [G.artifact_distance]m<br>"
if(!anom_found)
data += " - No anomalous data<br>"
P.info = "<b>[src] analysis report #[report_num]</b><br>"
P.info += "<b>Scanned item:</b> [scanned_item.name]<br><br>" + data
last_scan_data = P.info
P.loc = src.loc
scanned_item.loc = src.loc
scanned_item = null
/obj/machinery/radiocarbon_spectrometer/Topic(href, href_list)
if(stat & (NOPOWER|BROKEN))
return 0 // don't update UIs attached to this object
if(href_list["scanItem"])
if(scanning)
stop_scanning()
else
if(scanned_item)
if(scanner_seal_integrity > 0)
scanner_progress = 0
scanning = 1
t_left_radspike = pick(5,10,15)
usr << "<span class='notice'>Scan initiated.</span>"
else
usr << "<span class='warning'>Could not initiate scan, seal requires replacing.</span>"
else
usr << "<span class='warning'>Insert an item to scan.</span>"
if(href_list["maserWavelength"])
maser_wavelength = max(min(maser_wavelength + 1000 * text2num(href_list["maserWavelength"]), 10000), 1)
if(href_list["coolantRate"])
coolant_usage_rate = max(min(coolant_usage_rate + text2num(href_list["coolantRate"]), 10000), 0)
if(href_list["toggle_rad_shield"])
if(rad_shield)
rad_shield = 0
else
rad_shield = 1
if(href_list["ejectItem"])
if(scanned_item)
scanned_item.loc = src.loc
scanned_item = null
add_fingerprint(usr)
return 1 // update UIs attached to this object

View File

@@ -49,6 +49,8 @@
<li><b>Core sampler</b> - use this to take core samples from rock faces, which you can then run to the lab for analysis.</li>
<li><b>Depth scanner</b> - uses x-ray diffraction to locate anomalous densities in rock, indicating archaeological deposits or mineral veins.
Comes with a handy reference log containing co-ordinates and time of each scan.</li>
<li><b>Alden-Saraspova counter</b> - uses a patented application of Fourier Transform analysis to determine the difference between background and
exotic radiation. Use it to determine how far you are from anomalous energy sources.</li>
<li><b>Radio beacon locater</b> - leave a beacon at an item of interest, then track it down later with this handy gadget. Watch for interference from other
devices though.</li>
<li><b>Flashlight or portable light source</b> - Self explanatory, I hope.</li>
@@ -129,51 +131,50 @@
<h1><a name="Contents">Contents</a></h1>
<ol>
<li><a href="#Terms">A note on terms</a></li>
<li><a href="#Isotope">Isotope ratio spectrometer</a></li>
<li><a href="#Accelerator">Accelerator spectrometer</a></li>
<li><a href="#Gas">Gas chromatography spectrometer</a></li>
<li><a href="#Ion">Ion mobility spectrometer</a></li>
<li><a href="#Analysis">Analysis progression</a></li>
<li><a href="#Heat">Heat management</a></li>
<li><a href="#Radiation">Ambient radiation</a></li>
</ol>
<br>
<h1><a name="Terms">A note on terms</a></h1>
<list>
<li><b>Dissonance ratio</b> - This is a pseudoarbitrary value indicating the overal presence of a particular element in a greater composite.
It takes into account volume, density, molecular excitation and isotope spread.</li>
<li><b>Mass spectrometry</b> - MS is the procedure used used to measure and quantify the components of matter. The most prized tool in the field of
'Materials analysis'</li>
<li><b>Radiometric dating</b> - MS applied using the right carrier reagents can be used to accurately determine the age of a sample.</li>
<li><b>Sample specifity</b> - A pseudoarbitrary value used to indicate how well a sample resonates with the employed carrier reagent. Great specifity
(material resonance) indicates that there is much of the carrier reagent present in the sample.</li>
<li><b>Dissonance ratio</b> - This is a pseudoarbitrary value indicating the overal presence of a particular element in a greater composite.
It takes into account volume, density, molecular excitation and isotope spread.</li>
<li><b>Vacuum seal integrity</b> - A reference to how close an airtight seal is to failure.</li>
</list><br>
<a href="#Contents">Contents</a>
<h1><a name="Isotope">Isotope ratio spectrometer</a></h1>
Isotope ratio mass spectrometers work by coating a small surface with a semiliquid <i>stationary phase</i> consisting of the sample to be
analysed, and recording it's interactions with a gaseous <i>mobile phase</i> comprised of an inert or nonreactive gas such as helium or nitrogen.<br>
<h1><a name="Analysis">Analysis progression</a></h1>
Modern mass spectrometry requires constant attention from the diligant researcher in order to be successul. There are many different elements to juggle,
and later chapters will delve into them. For the spectrometry assistant, the first thing you need to know is that the scanner wavelength is automatically
calculated for you. Just tweak the settings and try to match it with the actual wavelength as closely as possible.<br>
<br>
IRMS are employed as radiometric daters, extremely accurate but only so up to ages of one billion years.<br>
<a href="#Contents">Contents</a>
<h1><a name="Accelerator">Accelerator spectrometer</a></h1>
The accelerator mass spectrometer works by accelerating ions to extraordinarily high kinetic energies before mass analysis. The special strength of AMS is
isolate rare or low-strength isotopes, making it able to determine much greater ages with reasonable accuracy.<br>
<h1><a name="Seal">Seal integrity</a></h1>
In order to maintain sterile and environmentally static procedures, a special chamber is setup inside the spectrometer. It's protected by a proprietary vacuum seal
produced by top tier industrial science. It will only last for a certain number of scans before failing outright, but it can be resealed through use of nanite paste.
Unfortunately, it's susceptible to malforming under heat stress so exposing it to higher temperatures will cause it's operation life to drop significantly.<br>
<br>
AMS are employed as extreme age radiometric daters, able to determine the age of the sample on a scale of billions of years.
They are commonly located in geology and archaeology laboratories.<br>
<a href="#Contents">Contents</a>
<h1><a name="Gas">Gas chromatography spectrometer</a></h1>
Gas-liquid chromatography mass spectrometers work by coating a small surface with a semiliquid <i>stationary phase</i> consisting of the sample to be
analysed, and recording it's interactions with a gaseous <i>mobile phase</i> comprised of an inert or nonreactive gas such as helium or nitrogen.<br>
<h1><a name="Heat">Heat management</a></h1>
The scanner relies on a gyro-rotational system that varies in speed and intensity. Over the course of an ordinary scan, the RPMs can change dramatically. Higher RPMs
means greater heat generation, but is necessary for the ongoing continuation of the scan. To offset heat production, spectrometers have an inbuilt cooling system.
Researchers can modify the flow rate of coolant to aid in dropping temperature as necessary, but are advised that frequent coolant replacements may be necessary
depending on coolant purity. Water and substances such as cryoxadone are viable substitutes, but nowhere near as effective as pure coolant itself.<br>
<br>
GLCS are employed in forensic and geological analysis to determine what elements are present in a sample.<br>
<a href="#Contents">Contents</a>
<h1><a name="Ion">Ion mobility spectrometer</a></h1>
Ion mobility mass spectrometers work by examining the mobility of ionized molecules in an inert carrier gas<br>
<h1><a name="Radiation">Ambient radiation</a></h1>
Researchers are warned that while operational, mass spectrometers emit period bursts of radiation and are thus advised to wear protective gear. In the event of
radiation spikes, there is also a special shield that can be lowered to block emissions. Lowering this, however, will have the effect of blocking the scanner
so use it sparingly.<br>
<br>
IMS returns a dissonance ratio over the scanned sample and carrier reagent, indicating the average total presence of the sample.<br>
<a href="#Contents">Contents</a>
</body>
@@ -197,67 +198,17 @@
</head>
<body>
<h1><a name="Contents">Contents</a></h1>
<ol>
<li><a href="#Terms">Some useful phrases for you</a></li>
<li><a href="#Sample">Sample preparation and analysis</a></li>
<li><a href="#Fourier">Fourier transform spectroscope</a></li>
<li><a href="#Hyperspectral">Hyperspectral Imager</a></li>
</ol>
<br>
<h1><a name="Terms">Some useful phrases for you</a></h1>
<list>
<li><b>Spectroscopy</b> - Spectroscopy is the study of the behaviour of light, commonly used in the 26th century for analysis of anomalous
behaviour of energy or light.</li>
<li><b>Sample specifity</b> - A pseudoarbitrary value used to indicate how well a sample resonates with the employed carrier reagent. Great specifity
(material resonance) indicates that there is much of the carrier reagent present in the sample.</li>
<li><b>Anomalies</b> - Inexplicable or uncategorised occurrences in the cosmos. A fascinating and dangerous study is made to determine the function of
these rare finds, and the term is often applied to describe technology left behind by vastly superior ancient alien forerunners.</li>
</list><br>
<a href="#Contents">Contents</a>
<h1><a name="Sample">Sample preparation and analysis</a></h1>
When you are readying your spectrometry lab for analysis, you'll need to make sure the sample is in a form the machines can glean data from.
<list>
<li><b>Obtain material sample</b> - This should be an ordinary chunk of matter the size of your finger, a good example is a 6mm rock core.</li>
<li><b>Run density separation treatment</b> - Perform the DST procedure on your sample, following generic specifications.</li>
<li><b>Ensure sample purity</b> - DST can sometimes leave behind chemical waste or chunks of matter, make sure there aren't any before proceeding.</li>
<li><b>Prepare analysis tray</b> - A sample tray holds a miniscule amount of liquid (2u), but that's all that our spectrometers require for a good reading.</li>
<li><b>Choose carrier reagent</b> - Standard spectrometers require 1u of the material sample, and 1u of a 'carrier' reagent to provide control comparison
and to enable refraction inferencing.</li>
<li><b>Insert sample tray into machine</b> - And press the 'Go' button. Now go make a cup of coffee.</li>
<li><b>Monitor machine heat levels</b> - The upper end mass spectrometers have quite complex internals, and have a tendency to critically overheat.
Make sure the heat limit isn't exceeded, or there may be potentially disastrous consequences.</li>
<li><b>Examine analysis report</b> - it won't always make sense or provide the information you hoped for, but if you've been careful during DST and ensured
sample integrity, then there's always something to be learnt. Just don't lose the paperwork!</li>
</list><br>
<a href="#Contents">Contents</a>
<h1><a name="Fourier">Fourier transform spectroscope</a></h1>
The FTS measures temporal coherence of radiating energy, then applies time-and-space domain measurements on the collected emission data. The collective
procedure is known as the <i>Fourier Transform Procedure,</i> with the mathematical algorithms dating back to the 19th century on Earth.<br>
<br>
As well as providing background energy readings, an FTS calculates the approximate distance and direction towards any anomalous energy signatures from
the location the scanned sample was taken from.<br>
<a href="#Contents">Contents</a>
<h1><a name="Hyperspectral">Hyperspectral Imager</a></h1>
The imager scans and collates spectral energy signatures from across the electromagnetic spectrum. The collected data is then presented to the viewer in
graph form, with any anomalous (uncatalogued or unidentified) energy signatures highlighted.<br>
<br>
As well as visualising background energy readings, a hyperspectral imager will isolate and identify any anomalous energy signatures in the sample.<br>
<a href="#Contents">Contents</a>
</body>
</html>
It's perhaps one of the most exciting times to be alive, with the recent breakthroughs in understanding and categorisation of things we may one day no longer call
'anomalies,' but rather 'infrequent or rare occurrences of certain celestial weather or phenomena.' Perhaps a little more long winded, but no less eloquent all the
same! Why, look at the strides we're making in piercing the walls of bluespace or our steadily improving ability to clarify and stabilise subspace emissions; it's
certainly an exciting time to be alive. For the moment the Hydrolian hasn't seen two spatial anomalies alike but the day will come and it is soon, I can feel it.
"}
/obj/item/weapon/book/manual/materials_chemistry_analysis
name = "Chemical preparation for materials analysis"
name = "Materials analysis and the chemical implications"
icon_state = "chemistry"
author = "Jasper Pascal, Senior Lecturer in Materials Analysis at the University of Jol'Nar"
title = "Chemical preparation for materials analysis"
title = "Materials analysis and the chemical implications"
dat = {"<html>
<head>
<style>
@@ -270,70 +221,13 @@
</head>
<body>
<h1><a name="Contents">Contents</a></h1>
<ol>
<li><a href="#Terms">Relevant words and their meanings</a></li>
<li><a href="#Sample">Sample preparation for spectrometry/spectroscopy</a></li>
<li><a href="#DST">Density Separation Treatment</a></li>
<li><a href="#Carrier">Choosing a carrier reagent</a></li>
</ol>
In today's high tech research fields, leaps and bounds are being made every day. Whether it's great strides forward in our understanding of the physical universe
or the operation of some fancy new piece of equipment, it seems like all the cool fields are producing new toys to play with leaving doddery old fields such as
materials analysis and chemistry relegated to the previous few centuries, when we were still learning the makeup and structure of the elements.<br>
<br>
<h1><a name="Terms">Relevant words and their meanings</a></h1>
<list>
<li><b>Dissonance ratio</b> - This is a pseudoarbitrary value indicating the overal presence of a particular element in a greater composite.
It takes into account volume, density, molecular excitation and isotope spread.</li>
<li><b>Density separation treatment</b> - The DST procedure purifies a sample, removing any unwanted matter to ensure the finest scan resolution possible.</li>
<li><b>Mass spectrometry</b> - MS is the procedure used used to measure and quantify the components of matter. The most prized tool in the field of
'Materials analysis'</li>
<li><b>Spectroscopy</b> - Spectroscopy is the study of the behaviour of light, commonly used in the 26th century for analysis of anomalous
behaviour of energy or light.</li>
<li><b>Sample specifity</b> - A pseudoarbitrary value used to indicate how well a sample resonates with the employed carrier reagent. Great specifity
(material resonance) indicates that there is much of the carrier reagent present in the sample.</li>
</list><br>
<a href="#Contents">Contents</a>
<h1><a name="Sample">Sample preparation for spectrometry/spectroscopy</a></h1>
When you are readying your spectrometry lab for analysis, you'll need to make sure the sample is in a form the machines can glean data from.
<list>
<li><b>Obtain material sample</b> - This should be an ordinary chunk of matter the size of your finger, a good example is a 6mm rock core.</li>
<li><b>Run density separation treatment</b> - Perform the DST procedure on your sample, following generic specifications.</li>
<li><b>Ensure sample purity</b> - DST can sometimes leave behind chemical waste or chunks of matter, make sure there aren't any before proceeding.</li>
<li><b>Prepare analysis tray</b> - A sample tray holds a miniscule amount of liquid (2u), but that's all that our spectrometers require for a good reading.</li>
<li><b>Choose carrier reagent</b> - Standard spectrometers require 1u of the material sample, and 1u of a 'carrier' reagent to provide control comparison
and to enable refraction inferencing.</li>
</list><br>
<a href="#Contents">Contents</a>
<h1><a name="DST">Density Separation Treatment</a></h1>
<list>
<li><b>Obtain material sample</b> - This should be an ordinary chunk of matter the size of your finger, a good example is a 6mm rock core.</li>
<li><b>Grind material to powder</b> - In order to treat the material, we have to have the sample in it's basest form.</li>
<li><b>Prepare separator solution</b> - A chemical solution called LiNa2WO4, or <i>Lithium Sodium Tungstate</i> must be prepared to separate
the the denser clumps of matter out of the refined sample. This is done by mixing 1 part lithium, 2 parts sodium, 1 part tungsten, 4 parts oxygen.</li>
<li><b>Mix separator with sample</b> - The resulting mixture is very close to the final product, but make sure to extract any leftover reagents and
the chemical waste byproduct.</li>
<li><b>Bring sample to boil</b> - Using a standard bunsen burner, bring the mixture containing at least 5u of DST to a boil to vaporise the remaining unwanted matter. Remember
to again clear out any waste byproducts.</li>
</list><br>
<a href="#Contents">Contents</a>
<h1><a name="Carrier">Choosing a carrier reagent</a></h1>
Below is a list of the most commonly used scan carrier reagents, and the particular molecules they resonate most strongly with:
<list>
<li><b>Carbon</b> - Trace organic cells, typically used for carbon dating of organic remains.</li>
<li><b>Potassium</b> - Long exposure particles floating in the depths of space, such as meteorites.</li>
<li><b>Hydrogen</b> - Trace water particles.</li>
<li><b>Nitrogen</b> - Crystalline structures.</li>
<li><b>Mercury</b> - Metallic derivatives such as ferritic elements and pure metallic substances.</li>
<li><b>Iron</b> - Metallic composites such as alloys and atomic structures that are metallic in nature.</li>
<li><b>Chlorine</b> - Metamorphic/igneous rock composite.</li>
<li><b>Phosphorus</b> - Metamorphic/sedimentary rock composite.</li>
<li><b>Plasma</b> - Anomalous materials such as bluespace phased composites that are not fully understood by modern science.</li>
</list><br>
<a href="#Contents">Contents</a>
</body>
</html>
Well, when you're out there building the next gryo-whatsitron or isotope mobility thingummy, remember how the field of archaeology experienced a massive new rebirth
following the excavations at Paranol IV and consider how all of the scientific greats will come crawling back to basic paradigms of natural philosophy when they discover
a new element that defies classification. I defy you to classify it without reviving this once great field!
"}
/obj/item/weapon/book/manual/anomaly_testing
@@ -391,10 +285,11 @@
matter composites that are spatially fixed relative to the source.<br>
<br>
By taking samples of such 'fixed' matter, we can apply complex analytics such as the modified Fourier Transform Procedure to reverse engineer the path of the
energy, and determine the approximate distance and direction that the energy source is, relative to the sample's point in space.<br>
energy, and determine the approximate distance and direction that the energy source is, relative to the sample's point in space. Modern portable devices can do
all this purely by taking readings of local radiation.<br>
<br>
A canny researcher can thusly analyse material samples from pre-chosen points strategically scattered around an area, and if there are any anomalous energy
emissions in range of those points, combined they can direct the researcher to the source.<br>
A canny researcher can thusly analyse radiationat pre-chosen points strategically scattered around an area, and if there are any anomalous energy
emissions in range of those points, combined the researcher can triangulate the source.<br>
<a href="#Contents">Contents</a>
<h1><a name="Synthetic">Harvesting and utilising anomalous energy signatures</a></h1>

View File

@@ -1,14 +1,15 @@
//---- Noticeboard
/obj/structure/noticeboard/anomaly/New()
/obj/structure/noticeboard/anomaly
notices = 5
icon_state = "nboard05"
/obj/structure/noticeboard/anomaly/New()
//add some memos
var/obj/item/weapon/paper/P = new()
P.name = "Memo RE: proper analysis procedure"
P.info = "Rose,<br>activate <i>then</i> analyse the artifacts, the machine will have a much easier time determining their function/s. Remember to employ basic quasi-elemental forces such as heat, energy, force and various chemical mixes - who knows why those ancient aliens made such obscure activation indices.<br><br>And don't forget your suit this time, I can't afford to have any researchers out of commision for as long as that again!.<br>Ward"
P.info = "<br>We keep test dummies in pens here for a reason, so standard procedure should be to activate newfound alien artifacts and place the two in close proximity. Promising items I might even approve monkey testing on."
P.stamped = list(/obj/item/weapon/stamp/rd)
P.overlays = list("paper_stamped_rd")
src.contents += P
@@ -29,7 +30,7 @@
P = new()
P.name = "READ ME! Before you people destroy any more samples"
P.info = "how many times do i have to tell you people, these xeno-arch samples are del-i-cate, and should be handled so! careful application of a focussed, ceoncentrated heat or some corrosive liquids should clear away the extraneous carbon matter, while application of an energy beam will most decidedly destroy it entirely! W, <b>the one who signs your paychecks</b>"
P.info = "how many times do i have to tell you people, these xeno-arch samples are del-i-cate, and should be handled so! careful application of a focussed, concentrated heat or some corrosive liquids should clear away the extraneous carbon matter, while application of an energy beam will most decidedly destroy it entirely - like someone did to the chemical dispenser! W, <b>the one who signs your paychecks</b>"
P.stamped = list(/obj/item/weapon/stamp/rd)
P.overlays = list("paper_stamped_rd")
src.contents += P

View File

@@ -0,0 +1,43 @@
/obj/item/device/ano_scanner
name = "Alden-Saraspova counter"
desc = "Aids in triangulation of exotic particles."
icon = 'icons/obj/xenoarchaeology.dmi'
icon_state = "flashgun"
item_state = "lampgreen"
w_class = 1.0
flags = FPRINT | TABLEPASS
slot_flags = SLOT_BELT
var/nearest_artifact_id = "unknown"
var/nearest_artifact_distance = -1
var/last_scan_time = 0
/obj/item/device/ano_scanner/New()
..()
spawn(0)
scan()
/obj/item/device/ano_scanner/attack_self(var/mob/user as mob)
return src.interact(user)
/obj/item/device/ano_scanner/interact(var/mob/user as mob)
var/message = "Background radiation levels detected."
if(nearest_artifact_distance >= 0)
message = "Exotic energy detected on wavelength '[nearest_artifact_id]' in a radius of [nearest_artifact_distance * 2]m"
user << "<span class='info'>[message]</span>"
if(world.time - last_scan_time > 50)
spawn(0)
scan()
/obj/item/device/ano_scanner/proc/scan()
set background = 1
last_scan_time = world.time
nearest_artifact_distance = -1
for(var/turf/simulated/mineral/T in artifact_spawning_turfs)
if(T.artifact_find && T.z == src.z)
var/cur_dist = get_dist(src.loc, T)
if(nearest_artifact_distance < 0 || cur_dist < nearest_artifact_distance)
nearest_artifact_distance = cur_dist + rand() * 2 - 1
nearest_artifact_id = T.artifact_find.artifact_id
src.visible_message("\icon[src] <span class='info>[src] clicks.</span>")

View File

@@ -37,17 +37,19 @@
D.record_index = positive_locations.len + 1
D.material = M.mineralName
//find whichever is closer: find or mineral
//find the first artifact and store it
if(M.finds.len)
var/datum/find/F = M.finds[1]
D.depth = F.excavation_required * 2
D.depth = F.excavation_required * 2 //0-100% and 0-200cm
D.clearance = F.clearance_range * 2
D.material = get_responsive_reagent(F.find_type)
//check if there are minerals interfering with the scan
if(M.excavation_minerals.len)
if(M.excavation_minerals[1] < D.depth)
if(!D.depth || M.excavation_minerals[1] < D.depth)
D.depth = M.excavation_minerals[1]
D.clearance = rand(2,6)
D.dissonance_spread = rand(1,1000) / 100
D.clearance = rand() * 4 + 1
D.material = M.mineralName
positive_locations.Add(D)
@@ -71,7 +73,7 @@
positive_locations.Add(D)
for(var/mob/L in range(src, 1))
L << "\blue \icon[src] [src] pings [pick("madly","wildly","excitedly","crazily")]."
L << "\blue \icon[src] [src] pings [pick("madly","wildly","excitedly","crazily")]!."
/obj/item/device/depth_scanner/attack_self(var/mob/user as mob)
return src.interact(user)
@@ -85,7 +87,11 @@
dat += "Anomaly depth: [current.depth] cm<br>"
dat += "Clearance above anomaly depth: [current.clearance] cm<br>"
dat += "Dissonance spread: [current.dissonance_spread]<br>"
dat += "Anomaly material: [current.material]<br>"
var/index = responsive_carriers.Find(current.material)
if(index > 0 && index <= finds_as_strings.len)
dat += "Anomaly material: [finds_as_strings[index]]<br>"
else
dat += "Anomaly material: Unknown<br>"
dat += "<A href='?src=\ref[src];clear=[current.record_index]'>clear entry</a><br>"
else
dat += "Select an entry from the list<br>"