diff --git a/baystation12.dme b/baystation12.dme index 43733732a0..e215d359b6 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1214,6 +1214,7 @@ #include "code\modules\research\xenoarchaeology\chemistry.dm" #include "code\modules\research\xenoarchaeology\geosample.dm" #include "code\modules\research\xenoarchaeology\manuals.dm" +#include "code\modules\research\xenoarchaeology\master_controller.dm" #include "code\modules\research\xenoarchaeology\misc.dm" #include "code\modules\research\xenoarchaeology\artifact\artifact.dm" #include "code\modules\research\xenoarchaeology\artifact\artifact_autocloner.dm" @@ -1249,7 +1250,11 @@ #include "code\modules\research\xenoarchaeology\finds\finds_defines.dm" #include "code\modules\research\xenoarchaeology\finds\finds_fossils.dm" #include "code\modules\research\xenoarchaeology\finds\finds_misc.dm" +#include "code\modules\research\xenoarchaeology\finds\finds_special.dm" #include "code\modules\research\xenoarchaeology\finds\finds_talkingitem.dm" +#include "code\modules\research\xenoarchaeology\genetics\prehistoric_animals.dm" +#include "code\modules\research\xenoarchaeology\genetics\prehistoric_plants.dm" +#include "code\modules\research\xenoarchaeology\genetics\reconstitutor.dm" #include "code\modules\research\xenoarchaeology\machinery\artifact_analyser.dm" #include "code\modules\research\xenoarchaeology\machinery\artifact_harvester.dm" #include "code\modules\research\xenoarchaeology\machinery\artifact_scanner.dm" diff --git a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi index 13cd5e7739..f27897881c 100644 Binary files a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi and b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi differ diff --git a/code/game/dna/dna2_domutcheck.dm b/code/game/dna/dna2_domutcheck.dm index 954c86f2a6..02495bbc49 100644 --- a/code/game/dna/dna2_domutcheck.dm +++ b/code/game/dna/dna2_domutcheck.dm @@ -6,7 +6,7 @@ #define MUTCHK_FORCED 1 /proc/domutcheck(var/mob/living/M, var/connected=null, var/flags=0) for(var/datum/dna/gene/gene in dna_genes) - if(!M) + if(!M || !M.dna) return if(!gene.block) continue diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index d84e3271e1..ee06823cae 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -304,6 +304,21 @@ user.drop_item() del(W) return + else if (istype(W, /obj/item/weapon/wrench)) + if(src.locked && (src.anchored || src.occupant)) + user << "\red Can not do that while [src] is in use." + else + if(src.anchored) + src.anchored = 0 + connected.pod1 = null + connected = null + else + src.anchored = 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + if(anchored) + user.visible_message("[user] secures [src] to the floor.", "You secure [src] to the floor.") + else + user.visible_message("[user] unsecures [src] from the floor.", "You unsecure [src] from the floor.") else ..() diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index fdbb5195f5..b489a69b56 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -121,6 +121,8 @@ /obj/proc/hear_talk(mob/M as mob, text) + if(talking_atom) + talking_atom.catchMessage(text, M) /* var/mob/mo = locate(/mob) in src if(mo) diff --git a/code/global.dm b/code/global.dm index ef34efdf15..1eb82f08cd 100644 --- a/code/global.dm +++ b/code/global.dm @@ -252,3 +252,6 @@ var/DBConnection/dbcon_old = new() //Tgstation database (Old database) - See the // Reference list for disposal sort junctions. Filled up by sorting junction's New() /var/list/tagger_locations = list() + +//added for Xenoarchaeology, might be useful for other stuff +var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z") diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index e359196946..c868c9a779 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -1,9 +1,6 @@ /**********************Mineral deposits**************************/ -datum/controller/game_controller/var/list/artifact_spawning_turfs = list() -var/list/artifact_spawn = list() // Runtime fix for geometry loading before controller is instantiated. - /turf/simulated/mineral //wall piece name = "Rock" icon = 'icons/turf/walls.dmi' @@ -480,6 +477,12 @@ var/list/artifact_spawn = list() // Runtime fix for geometry loading before cont for(var/obj/item/weapon/ore/O in contents) O.attackby(W,user) return + else if(istype(W,/obj/item/weapon/storage/bag/fossils)) + var/obj/item/weapon/storage/bag/fossils/S = W + if(S.collection_mode) + for(var/obj/item/weapon/fossil/F in contents) + F.attackby(W,user) + return else ..(W,user) diff --git a/code/modules/research/xenoarchaeology/artifact/artifact_autocloner.dm b/code/modules/research/xenoarchaeology/artifact/artifact_autocloner.dm index e602e4363f..fb01ee4661 100644 --- a/code/modules/research/xenoarchaeology/artifact/artifact_autocloner.dm +++ b/code/modules/research/xenoarchaeology/artifact/artifact_autocloner.dm @@ -5,8 +5,9 @@ icon = 'icons/obj/cryogenics.dmi' icon_state = "cellold0" var/spawn_type - var/current_ticks_spawning = 0 - var/ticks_required_to_spawn + var/time_spent_spawning = 0 + var/time_per_spawn = 0 + var/last_process= 0 density = 1 var/previous_power_state = 0 @@ -17,7 +18,7 @@ /obj/machinery/auto_cloner/New() ..() - ticks_required_to_spawn = rand(240,1440) + time_per_spawn = rand(1200,3600) //33% chance to spawn nasties if(prob(33)) @@ -53,13 +54,12 @@ src.visible_message("\blue \icon[src] [src] suddenly comes to life!") //slowly grow a mob - current_ticks_spawning++ if(prob(5)) src.visible_message("\blue \icon[src] [src] [pick("gloops","glugs","whirrs","whooshes","hisses","purrs","hums","gushes")].") //if we've finished growing... - if(current_ticks_spawning >= ticks_required_to_spawn) - current_ticks_spawning = 0 + if(time_spent_spawning >= time_per_spawn) + time_spent_spawning = 0 use_power = 1 src.visible_message("\blue \icon[src] [src] pings!") icon_state = "cellold1" @@ -68,7 +68,7 @@ new spawn_type(src.loc) //if we're getting close to finished, kick into overdrive power usage - if(current_ticks_spawning / ticks_required_to_spawn > 0.75) + if(time_spent_spawning / time_per_spawn > 0.75) use_power = 2 icon_state = "cellold2" desc = "It's full of a bubbling viscous liquid, and is lit by a mysterious glow. A dark shape appears to be forming inside..." @@ -76,6 +76,8 @@ use_power = 1 icon_state = "cellold1" desc = "It's full of a bubbling viscous liquid, and is lit by a mysterious glow." + + time_spent_spawning = time_spent_spawning + world.time - last_process else if(previous_power_state) previous_power_state = 0 @@ -83,5 +85,6 @@ src.visible_message("\blue \icon[src] [src] suddenly shuts down.") //cloned mob slowly breaks down - if(current_ticks_spawning > 0) - current_ticks_spawning-- + time_spent_spawning = max(time_spent_spawning + last_process - world.time, 0) + + last_process = world.time diff --git a/code/modules/research/xenoarchaeology/artifact/artifact_replicator.dm b/code/modules/research/xenoarchaeology/artifact/artifact_replicator.dm index 63999f9921..56954dc6dd 100644 --- a/code/modules/research/xenoarchaeology/artifact/artifact_replicator.dm +++ b/code/modules/research/xenoarchaeology/artifact/artifact_replicator.dm @@ -10,10 +10,15 @@ active_power_usage = 1000 use_power = 1 - var/spawn_progress = 0 - var/max_spawn_ticks = 5 + var/spawn_progress_time = 0 + var/max_spawn_time = 50 + var/last_process_time = 0 + var/list/construction = list() var/list/spawning_types = list() + var/list/stored_materials = list() + + var/fail_message /obj/machinery/replicator/New() ..() @@ -66,32 +71,52 @@ var/quantity = rand(5,15) for(var/i=0, i max_spawn_ticks) + spawn_progress_time += world.time - last_process_time + if(spawn_progress_time > max_spawn_time) src.visible_message("\blue \icon[src] [src] pings!") - var/spawn_type = spawning_types[1] - new spawn_type(src.loc) - spawning_types.Remove(spawning_types[1]) - spawn_progress = 0 - max_spawn_ticks = rand(5,30) + var/obj/source_material = pop(stored_materials) + var/spawn_type = pop(spawning_types) + var/obj/spawned_obj = new spawn_type(src.loc) + if(source_material) + if(lentext(source_material.name) < MAX_MESSAGE_LEN) + spawned_obj.name = "[source_material] " + spawned_obj.name + if(lentext(source_material.desc) < MAX_MESSAGE_LEN * 2) + if(spawned_obj.desc) + spawned_obj.desc += " It is made of [source_material]." + else + spawned_obj.desc = "It is made of [source_material]." + source_material.loc = null - if(!spawning_types.len) + spawn_progress_time = 0 + max_spawn_time = rand(30,100) + + if(!spawning_types.len || !stored_materials.len) use_power = 1 icon_state = "borgcharger0(old)" else if(prob(5)) src.visible_message("\blue \icon[src] [src] [pick("clicks","whizzes","whirrs","whooshes","clanks","clongs","clonks","bangs")].") + last_process_time = world.time + /obj/machinery/replicator/attack_hand(mob/user as mob) interact(user) @@ -103,17 +128,26 @@ user << browse(dat, "window=alien_replicator") +/obj/machinery/replicator/attackby(obj/item/weapon/W as obj, mob/living/user as mob) + user.drop_item() + W.loc = src + stored_materials.Add(W) + src.visible_message("\blue [user] inserts [W] into [src].") + /obj/machinery/replicator/Topic(href, href_list) if(href_list["activate"]) var/index = text2num(href_list["activate"]) if(index > 0 && index <= construction.len) - if(spawning_types.len) - src.visible_message("\blue \icon[src] a [pick("light","dial","display","meter","pad")] on [src]'s front [pick("blinks","flashes")] [pick("red","yellow","blue","orange","purple","green","white")].") - else - src.visible_message("\blue \icon[src] [src]'s front compartment slides shut.") + if(stored_materials.len > spawning_types.len) + if(spawning_types.len) + src.visible_message("\blue \icon[src] a [pick("light","dial","display","meter","pad")] on [src]'s front [pick("blinks","flashes")] [pick("red","yellow","blue","orange","purple","green","white")].") + else + src.visible_message("\blue \icon[src] [src]'s front compartment slides shut.") - spawning_types.Add(construction[construction[index]]) - spawn_progress = 0 - use_power = 2 - icon_state = "borgcharger1(old)" + spawning_types.Add(construction[construction[index]]) + spawn_progress_time = 0 + use_power = 2 + icon_state = "borgcharger1(old)" + else + src.visible_message(fail_message) diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_affect_cold.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_affect_cold.dm index fcdb163ac7..f8dad2c4d3 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_affect_cold.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_affect_cold.dm @@ -12,6 +12,7 @@ /datum/artifact_effect/cold/DoEffectTouch(var/mob/user) if(holder) + user << "\blue A chill passes up your spine!" var/datum/gas_mixture/env = holder.loc.return_air() if(env) env.temperature = max(env.temperature - rand(5,50), 0) diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_badfeeling.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_badfeeling.dm index 2e57907b50..1244f802cc 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_badfeeling.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_badfeeling.dm @@ -41,7 +41,8 @@ /datum/artifact_effect/badfeeling/DoEffectAura() if(holder) - for (var/mob/living/carbon/human/H in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) if(prob(5)) if(prob(75)) H << "[pick(messages)]" @@ -54,7 +55,8 @@ /datum/artifact_effect/badfeeling/DoEffectPulse() if(holder) - for (var/mob/living/carbon/human/H in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) if(prob(50)) if(prob(95)) H << "[pick(drastic_messages)]" diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_cellcharge.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_cellcharge.dm index 5105628cfe..d7ff967c2d 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_cellcharge.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_cellcharge.dm @@ -15,7 +15,8 @@ /datum/artifact_effect/cellcharge/DoEffectAura() if(holder) - for (var/obj/machinery/power/apc/C in range(200, holder)) + var/turf/T = get_turf(holder) + for (var/obj/machinery/power/apc/C in range(200, T)) for (var/obj/item/weapon/cell/B in C.contents) B.charge += 25 for (var/obj/machinery/power/smes/S in range (src.effectrange,src)) @@ -28,7 +29,8 @@ /datum/artifact_effect/cellcharge/DoEffectPulse() if(holder) - for (var/obj/machinery/power/apc/C in range(200, holder)) + var/turf/T = get_turf(holder) + for (var/obj/machinery/power/apc/C in range(200, T)) for (var/obj/item/weapon/cell/B in C.contents) B.charge += rand() * 100 for (var/obj/machinery/power/smes/S in range (src.effectrange,src)) diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_celldrain.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_celldrain.dm index 550b49b068..8af61035d4 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_celldrain.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_celldrain.dm @@ -17,7 +17,8 @@ /datum/artifact_effect/celldrain/DoEffectAura() if(holder) - for (var/obj/machinery/power/apc/C in range(200, holder)) + var/turf/T = get_turf(holder) + for (var/obj/machinery/power/apc/C in range(200, T)) for (var/obj/item/weapon/cell/B in C.contents) B.charge = max(B.charge - 50,0) for (var/obj/machinery/power/smes/S in range (src.effectrange,src)) @@ -30,7 +31,8 @@ /datum/artifact_effect/celldrain/DoEffectPulse() if(holder) - for (var/obj/machinery/power/apc/C in range(200, holder)) + var/turf/T = get_turf(holder) + for (var/obj/machinery/power/apc/C in range(200, T)) for (var/obj/item/weapon/cell/B in C.contents) B.charge = max(B.charge - rand() * 150,0) for (var/obj/machinery/power/smes/S in range (src.effectrange,src)) diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_dnaswitch.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_dnaswitch.dm index cff708b0c3..b74ab88a9a 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_dnaswitch.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_dnaswitch.dm @@ -30,7 +30,8 @@ /datum/artifact_effect/dnaswitch/DoEffectAura() if(holder) - for(var/mob/living/carbon/human/H in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for(var/mob/living/carbon/human/H in range(src.effectrange,T)) var/weakness = GetAnomalySusceptibility(H) if(prob(weakness * 100)) if(prob(30)) @@ -48,7 +49,8 @@ /datum/artifact_effect/dnaswitch/DoEffectPulse() if(holder) - for(var/mob/living/carbon/human/H in range(200, holder)) + var/turf/T = get_turf(holder) + for(var/mob/living/carbon/human/H in range(200, T)) var/weakness = GetAnomalySusceptibility(H) if(prob(weakness * 100)) if(prob(75)) diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_emp.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_emp.dm index aeafa6387d..18165cf0d4 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_emp.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_emp.dm @@ -9,5 +9,6 @@ /datum/artifact_effect/emp/DoEffectPulse() if(holder) - empulse(get_turf(holder), effectrange/2, effectrange) + var/turf/T = get_turf(holder) + empulse(T, effectrange/2, effectrange) return 1 diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_goodfeeling.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_goodfeeling.dm index 752aa61ce0..bc45260b2c 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_goodfeeling.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_goodfeeling.dm @@ -39,7 +39,8 @@ /datum/artifact_effect/goodfeeling/DoEffectAura() if(holder) - for (var/mob/living/carbon/human/H in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) if(prob(5)) if(prob(75)) H << "[pick(messages)]" @@ -52,7 +53,8 @@ /datum/artifact_effect/goodfeeling/DoEffectPulse() if(holder) - for (var/mob/living/carbon/human/H in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) if(prob(50)) if(prob(95)) H << "[pick(drastic_messages)]" diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heal.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heal.dm index 8b92784424..d1d3937c97 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heal.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heal.dm @@ -36,7 +36,8 @@ /datum/artifact_effect/heal/DoEffectAura() //todo: check over this properly if(holder) - for (var/mob/living/carbon/C in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) var/weakness = GetAnomalySusceptibility(C) if(prob(weakness * 100)) if(prob(10)) @@ -51,7 +52,8 @@ /datum/artifact_effect/heal/DoEffectPulse() //todo: check over this properly if(holder) - for (var/mob/living/carbon/C in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) var/weakness = GetAnomalySusceptibility(C) if(prob(weakness * 100)) C << "\blue A wave of energy invigorates you." diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heat.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heat.dm index da59078a1b..21304df408 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heat.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_heat.dm @@ -15,6 +15,7 @@ /datum/artifact_effect/heat/DoEffectTouch(var/mob/user) if(holder) + user << "\red You feel a wave of heat travel up your spine!" var/datum/gas_mixture/env = holder.loc.return_air() if(env) env.temperature += rand(5,50) diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_hurt.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_hurt.dm index f69b9b9d9d..77074be63f 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_hurt.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_hurt.dm @@ -21,7 +21,8 @@ /datum/artifact_effect/hurt/DoEffectAura() if(holder) - for (var/mob/living/carbon/C in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) var/weakness = GetAnomalySusceptibility(C) if(prob(weakness * 100)) if(prob(10)) @@ -35,7 +36,8 @@ /datum/artifact_effect/hurt/DoEffectPulse() if(holder) - for (var/mob/living/carbon/C in range(effectrange, holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(effectrange, T)) var/weakness = GetAnomalySusceptibility(C) if(prob(weakness * 100)) C << "\red A wave of painful energy strikes you!" diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_radiate.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_radiate.dm index e6c49c96ce..4310ffb2e7 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_radiate.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_radiate.dm @@ -16,14 +16,16 @@ /datum/artifact_effect/radiate/DoEffectAura() if(holder) - for (var/mob/living/M in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/M in range(src.effectrange,T)) M.apply_effect(radiation_amount,IRRADIATE,0) M.updatehealth() return 1 /datum/artifact_effect/radiate/DoEffectPulse() if(holder) - for (var/mob/living/M in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/M in range(src.effectrange,T)) M.apply_effect(radiation_amount * 25,IRRADIATE,0) M.updatehealth() return 1 diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_roboheal.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_roboheal.dm index 8e154f0b66..a1a89e42cf 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_roboheal.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_roboheal.dm @@ -17,7 +17,8 @@ /datum/artifact_effect/roboheal/DoEffectAura() if(holder) - for (var/mob/living/silicon/robot/M in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) if(prob(10)) M << "\blue SYSTEM ALERT: Beneficial energy field detected!" M.adjustBruteLoss(-1) @@ -27,7 +28,8 @@ /datum/artifact_effect/roboheal/DoEffectPulse() if(holder) - for (var/mob/living/silicon/robot/M in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) M << "\blue SYSTEM ALERT: Structural damage has been repaired by energy pulse!" M.adjustBruteLoss(-10) M.adjustFireLoss(-10) diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_robohurt.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_robohurt.dm index b230efa33e..bc55a76cef 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_robohurt.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_robohurt.dm @@ -17,7 +17,8 @@ /datum/artifact_effect/robohurt/DoEffectAura() if(holder) - for (var/mob/living/silicon/robot/M in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) if(prob(10)) M << "\red SYSTEM ALERT: Harmful energy field detected!" M.adjustBruteLoss(1) M.adjustFireLoss(1) @@ -26,7 +27,8 @@ /datum/artifact_effect/robohurt/DoEffectPulse() if(holder) - for (var/mob/living/silicon/robot/M in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/silicon/robot/M in range(src.effectrange,T)) M << "\red SYSTEM ALERT: Structural damage inflicted by energy pulse!" M.adjustBruteLoss(10) M.adjustFireLoss(10) diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_sleepy.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_sleepy.dm index 1da02ceaa9..61979c5f69 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_sleepy.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_sleepy.dm @@ -22,7 +22,8 @@ /datum/artifact_effect/sleepy/DoEffectAura() if(holder) - for (var/mob/living/carbon/human/H in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/human/H in range(src.effectrange,T)) var/weakness = GetAnomalySusceptibility(H) if(prob(weakness * 100)) if(prob(10)) @@ -35,7 +36,8 @@ /datum/artifact_effect/sleepy/DoEffectPulse() if(holder) - for(var/mob/living/carbon/human/H in range(src.effectrange, holder)) + var/turf/T = get_turf(holder) + for(var/mob/living/carbon/human/H in range(src.effectrange, T)) var/weakness = GetAnomalySusceptibility(H) if(prob(weakness * 100)) H << pick("\blue You feel like taking a nap.","\blue You feel a yawn coming on.","\blue You feel a little tired.") diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_stun.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_stun.dm index b37862eb0c..b7b2864de4 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_stun.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_stun.dm @@ -9,33 +9,35 @@ /datum/artifact_effect/stun/DoEffectTouch(var/mob/toucher) if(toucher && iscarbon(toucher)) var/mob/living/carbon/C = toucher - var/weakness = GetAnomalySusceptibility(C) - if(prob(weakness * 100)) + var/susceptibility = GetAnomalySusceptibility(C) + if(prob(susceptibility * 100)) C << "\red A powerful force overwhelms your consciousness." - C.weakened += 45 * weakness - C.stuttering += 45 * weakness - C.stunned += rand(1,10) * weakness + C.Weaken(rand(1,10) * susceptibility) + C.stuttering += 30 * susceptibility + C.Stun(rand(1,10) * susceptibility) /datum/artifact_effect/stun/DoEffectAura() if(holder) - for (var/mob/living/carbon/C in range(src.effectrange,holder)) - var/weakness = GetAnomalySusceptibility(C) - if(prob(10 * weakness)) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) + var/susceptibility = GetAnomalySusceptibility(C) + if(prob(10 * susceptibility)) C << "\red Your body goes numb for a moment." - C.weakened += 2 + C.Weaken(2) C.stuttering += 2 if(prob(10)) - C.stunned += 1 + C.Stun(1) else if(prob(10)) C << "\red You feel numb." /datum/artifact_effect/stun/DoEffectPulse() if(holder) - for (var/mob/living/carbon/C in range(src.effectrange,holder)) - var/weakness = GetAnomalySusceptibility(C) - if(prob(100 * weakness)) + var/turf/T = get_turf(holder) + for (var/mob/living/carbon/C in range(src.effectrange,T)) + var/susceptibility = GetAnomalySusceptibility(C) + if(prob(100 * susceptibility)) C << "\red A wave of energy overwhelms your senses!" - C.weakened += 4 * weakness - C.stuttering += 4 * weakness + C.SetWeakened(4 * susceptibility) + C.stuttering = 4 * susceptibility if(prob(10)) - C.stunned += 1 * weakness + C.SetStunned(1 * susceptibility) diff --git a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_teleport.dm b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_teleport.dm index e1580e2073..254be3f3d0 100644 --- a/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_teleport.dm +++ b/code/modules/research/xenoarchaeology/artifact/effects/unknown_effect_teleport.dm @@ -6,60 +6,53 @@ /datum/artifact_effect/teleport/DoEffectTouch(var/mob/user) var/weakness = GetAnomalySusceptibility(user) if(prob(100 * weakness)) - var/list/randomturfs = new/list() - for(var/turf/simulated/floor/T in orange(user, 50)) - randomturfs.Add(T) - if(randomturfs.len > 0) - user << "\red You are suddenly zapped away elsewhere!" - if (user.buckled) - user.buckled.unbuckle() + user << "\red You are suddenly zapped away elsewhere!" + if (user.buckled) + user.buckled.unbuckle() - var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(3, 0, get_turf(user)) - sparks.start() - user.loc = pick(randomturfs) - sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(3, 0, get_turf(user)) - sparks.start() + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(user)) + sparks.start() + // + user.loc = pick(orange(get_turf(holder), 50)) + sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(user)) + sparks.start() /datum/artifact_effect/teleport/DoEffectAura() if(holder) - for (var/mob/living/M in range(src.effectrange,holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/M in range(src.effectrange,T)) var/weakness = GetAnomalySusceptibility(M) if(prob(100 * weakness)) - var/list/randomturfs = new/list() - for(var/turf/simulated/floor/T in orange(M, 30)) - randomturfs.Add(T) - if(randomturfs.len > 0) - M << "\red You are displaced by a strange force!" - if(M.buckled) - M.buckled.unbuckle() + M << "\red You are displaced by a strange force!" + if(M.buckled) + M.buckled.unbuckle() - var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(3, 0, get_turf(M)) - sparks.start() - M.loc = pick(randomturfs) - sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(3, 0, get_turf(M)) - sparks.start() + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(M)) + sparks.start() + // + M.loc = pick(orange(get_turf(T), 50)) + sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(M)) + sparks.start() /datum/artifact_effect/teleport/DoEffectPulse() if(holder) - for (var/mob/living/M in range(src.effectrange, holder)) + var/turf/T = get_turf(holder) + for (var/mob/living/M in range(src.effectrange, T)) var/weakness = GetAnomalySusceptibility(M) if(prob(100 * weakness)) - var/list/randomturfs = new/list() - for(var/turf/simulated/floor/T in orange(M, 15)) - randomturfs.Add(T) - if(randomturfs.len > 0) - M << "\red You are displaced by a strange force!" + M << "\red You are displaced by a strange force!" + if(M.buckled) + M.buckled.unbuckle() - var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(3, 0, get_turf(M)) - sparks.start() - if(M.buckled) - M.buckled.unbuckle() - M.loc = pick(randomturfs) - sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(3, 0, get_turf(M)) - sparks.start() + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(M)) + sparks.start() + // + M.loc = pick(orange(get_turf(T), 50)) + sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(M)) + sparks.start() diff --git a/code/modules/research/xenoarchaeology/finds/finds.dm b/code/modules/research/xenoarchaeology/finds/finds.dm index 1d77a68f0f..09f91d0342 100644 --- a/code/modules/research/xenoarchaeology/finds/finds.dm +++ b/code/modules/research/xenoarchaeology/finds/finds.dm @@ -113,7 +113,10 @@ switch(find_type) if(1) item_type = "bowl" - new_item = new /obj/item/weapon/reagent_containers/glass(src.loc) + if(prob(33)) + new_item = new /obj/item/weapon/reagent_containers/glass/replenishing(src.loc) + else + new_item = new /obj/item/weapon/reagent_containers/glass/beaker(src.loc) new_item.icon = 'icons/obj/xenoarchaeology.dmi' new_item.icon_state = "bowl" apply_image_decorations = 1 @@ -121,7 +124,10 @@ additional_desc = "There appear to be [pick("dark","faintly glowing","pungent","bright")] [pick("red","purple","green","blue")] stains inside." if(2) item_type = "urn" - new_item = new /obj/item/weapon/reagent_containers/glass(src.loc) + if(prob(33)) + new_item = new /obj/item/weapon/reagent_containers/glass/replenishing(src.loc) + else + new_item = new /obj/item/weapon/reagent_containers/glass/beaker(src.loc) new_item.icon = 'icons/obj/xenoarchaeology.dmi' new_item.icon_state = "urn" apply_image_decorations = 1 @@ -139,11 +145,14 @@ "It's a mystery how anyone is supposed to eat with this",\ "You wonder what the creator's mouth was shaped like")]." if(4) + name = "statuette" item_type = "statuette" icon_state = "statuette" additional_desc = "It depicts a [pick("small","ferocious","wild","pleasing","hulking")] \ [pick("alien figure","rodent-like creature","reptilian alien","primate","unidentifiable object")] \ [pick("performing unspeakable acts","posing heroically","in a fetal position","cheering","sobbing","making a plaintive gesture","making a rude gesture")]." + if(prob(25)) + new_item = new /obj/item/weapon/vampiric(src.loc) if(5) item_type = "instrument" icon_state = "instrument" @@ -194,6 +203,9 @@ new_item = new /obj/item/weapon/storage/box(src.loc) new_item.icon = 'icons/obj/xenoarchaeology.dmi' new_item.icon_state = "box" + var/obj/item/weapon/storage/box/new_box = new_item + new_box.max_w_class = pick(1,2,2,3,3,3,4,4) + new_box.max_combined_w_class = rand(new_box.max_w_class, new_box.max_w_class * 10) if(prob(30)) apply_image_decorations = 1 if(12) @@ -260,6 +272,10 @@ apply_material_decorations = 0 if(prob(10)) apply_image_decorations = 1 + if(prob(25)) + new_item = new /obj/item/device/soulstone(src.loc) + new_item.icon = 'icons/obj/xenoarchaeology.dmi' + new_item.icon_state = icon_state if(17) //cultblade apply_prefix = 0 @@ -462,7 +478,12 @@ "It doesn't look human.") apply_image_decorations = 0 apply_material_decorations = 0 - + if(35) + //gas mask + if(prob(25)) + new_item = new /obj/item/clothing/mask/gas/poltergeist(src.loc) + else + new_item = new /obj/item/clothing/mask/gas(src.loc) var/decorations = "" if(apply_material_decorations) source_material = pick("cordite","quadrinium","steel","titanium","aluminium","ferritic-alloy","plasteel","duranium") @@ -520,18 +541,14 @@ new_item.name = name new_item.desc = src.desc - if(talkative && istype(new_item,/obj/item/weapon)) - new_item.listening_to_players = 1 - if(prob(25)) - new_item.speaking_to_players = 1 - processing_objects.Add(src) - var/turf/T = get_turf(src) - if(istype(T, /turf/simulated/mineral)) - T:last_find = new_item + if(talkative) + new_item.talking_atom = new() + talking_atom.holder_atom = new_item + talking_atom.init() + del(src) else if(talkative) - listening_to_players = 1 - if(prob(25)) - speaking_to_players = 1 - processing_objects.Add(src) + src.talking_atom = new() + talking_atom.holder_atom = src + talking_atom.init() diff --git a/code/modules/research/xenoarchaeology/finds/finds_defines.dm b/code/modules/research/xenoarchaeology/finds/finds_defines.dm index a28742d6c5..4026cc0a03 100644 --- a/code/modules/research/xenoarchaeology/finds/finds_defines.dm +++ b/code/modules/research/xenoarchaeology/finds/finds_defines.dm @@ -33,7 +33,8 @@ #define ARCHAEO_REMAINS_HUMANOID 32 #define ARCHAEO_REMAINS_ROBOT 33 #define ARCHAEO_REMAINS_XENO 34 -#define MAX_ARCHAEO 34 +#define ARCHAEO_GASMASK 35 +#define MAX_ARCHAEO 35 //eggs //droppings //footprints @@ -119,6 +120,8 @@ return "carbon" if(ARCHAEO_REMAINS_XENO) return "carbon" + if(ARCHAEO_GASMASK) + return "carbon" return "phoron" //see /turf/simulated/mineral/New() in code/modules/mining/mine_turfs.dm @@ -153,6 +156,7 @@ 100;ARCHAEO_PEN,\ 100;ARCHAEO_LIGHTER,\ 100;ARCHAEO_BOX,\ + 75;ARCHAEO_GASMASK,\ 75;ARCHAEO_COIN,\ 75;ARCHAEO_UNKNOWN,\ 50;ARCHAEO_SHARD,\ @@ -161,6 +165,7 @@ ) if(DIGSITE_TECHNICAL) find_type = pick(\ + 125;ARCHAEO_GASMASK,\ 100;ARCHAEO_METAL,\ 100;ARCHAEO_GASTANK,\ 100;ARCHAEO_TELEBEACON,\ @@ -175,6 +180,7 @@ if(DIGSITE_TEMPLE) find_type = pick(\ 200;ARCHAEO_CULTROBES,\ + 200;ARCHAEO_STATUETTE,\ 100;ARCHAEO_URN,\ 100;ARCHAEO_BOWL,\ 100;ARCHAEO_KNIFE,\ @@ -188,7 +194,8 @@ 10;ARCHAEO_CLAYMORE,\ 10;ARCHAEO_SHARD,\ 10;ARCHAEO_RODS,\ - 10;ARCHAEO_METAL\ + 10;ARCHAEO_METAL,\ + 10;ARCHAEO_GASMASK,\ ) if(DIGSITE_WAR) find_type = pick(\ @@ -200,6 +207,7 @@ 50;ARCHAEO_UNKNOWN,\ 50;ARCHAEO_CULTROBES,\ 50;ARCHAEO_CULTBLADE,\ + 50;ARCHAEO_GASMASK,\ 25;ARCHAEO_HANDCUFFS,\ 25;ARCHAEO_BEARTRAP,\ 25;ARCHAEO_TOOL\ @@ -262,6 +270,8 @@ var/list/finds_as_strings = list( \ #undef ARCHAEO_REMAINS_HUMANOID #undef ARCHAEO_REMAINS_ROBOT #undef ARCHAEO_REMAINS_XENO +#undef ARCHAEO_GASMASK +#undef MAX_ARCHAEO #undef DIGSITE_GARDEN #undef DIGSITE_ANIMAL diff --git a/code/modules/research/xenoarchaeology/finds/finds_fossils.dm b/code/modules/research/xenoarchaeology/finds/finds_fossils.dm index 89fc33396d..57d510015f 100644 --- a/code/modules/research/xenoarchaeology/finds/finds_fossils.dm +++ b/code/modules/research/xenoarchaeology/finds/finds_fossils.dm @@ -7,6 +7,7 @@ icon = 'icons/obj/xenoarchaeology.dmi' icon_state = "bone" desc = "It's a fossil." + var/animal = 1 /obj/item/weapon/fossil/base/New() var/list/l = list("/obj/item/weapon/fossil/bone"=9,"/obj/item/weapon/fossil/skull"=3, @@ -97,6 +98,7 @@ name = "Fossilised plant" icon_state = "plant1" desc = "It's fossilised plant remains." + animal = 0 /obj/item/weapon/fossil/plant/New() icon_state = "plant[rand(1,4)]" diff --git a/code/modules/research/xenoarchaeology/finds/finds_special.dm b/code/modules/research/xenoarchaeology/finds/finds_special.dm new file mode 100644 index 0000000000..b2c0fb3898 --- /dev/null +++ b/code/modules/research/xenoarchaeology/finds/finds_special.dm @@ -0,0 +1,203 @@ + + + +//endless reagents! +/obj/item/weapon/reagent_containers/glass/replenishing + var/spawning_id + +/obj/item/weapon/reagent_containers/glass/replenishing/New() + ..() + processing_objects.Add(src) + spawning_id = pick("blood","holywater","lube","stoxin","ethanol","ice","glycerol","fuel","cleaner") + +/obj/item/weapon/reagent_containers/glass/replenishing/process() + reagents.add_reagent(spawning_id, 0.3) + + + +//a talking gas mask! +/obj/item/clothing/mask/gas/poltergeist + var/list/heard_talk = list() + var/last_twitch = 0 + var/max_stored_messages = 100 + +/obj/item/clothing/mask/gas/poltergeist/New() + processing_objects.Add(src) + +/obj/item/clothing/mask/gas/poltergeist/process() + if(heard_talk.len && istype(src.loc, /mob/living) && prob(10)) + var/mob/living/M = src.loc + M.say(pick(heard_talk)) + +/obj/item/clothing/mask/gas/poltergeist/hear_talk(mob/M as mob, text) + ..() + if(heard_talk.len > max_stored_messages) + heard_talk.Remove(pick(heard_talk)) + heard_talk.Add(text) + if(istype(src.loc, /mob/living) && world.time - last_twitch > 50) + last_twitch = world.time + + + +//a vampiric statuette +//todo: cult integration +/obj/item/weapon/vampiric + name = "statuette" + icon_state = "statuette" + icon = 'icons/obj/xenoarchaeology.dmi' + var/charges = 0 + var/list/nearby_mobs = list() + var/last_bloodcall = 0 + var/bloodcall_interval = 50 + var/last_eat = 0 + var/eat_interval = 100 + var/wight_check_index = 1 + var/list/shadow_wights = list() + +/obj/item/weapon/vampiric/New() + ..() + processing_objects.Add(src) + +/obj/item/weapon/vampiric/process() + //see if we've identified anyone nearby + if(world.time - last_bloodcall > bloodcall_interval && nearby_mobs.len) + var/mob/living/carbon/human/M = pop(nearby_mobs) + if(M in view(7,src) && M.health > 20) + if(prob(50)) + bloodcall(M) + nearby_mobs.Add(M) + + //suck up some blood to gain power + if(world.time - last_eat > eat_interval) + var/obj/effect/decal/cleanable/blood/B = locate() in range(2,src) + if(B) + last_eat = world.time + B.loc = null + if(istype(B, /obj/effect/decal/cleanable/blood/drip)) + charges += 0.25 + else + charges += 1 + playsound(src.loc, 'sound/effects/splat.ogg', 50, 1, -3) + + //use up stored charges + if(charges >= 10) + charges -= 10 + new /obj/effect/spider/eggcluster(pick(view(1,src))) + + if(charges >= 3) + if(prob(5)) + charges -= 1 + var/spawn_type = pick(/mob/living/simple_animal/hostile/creature) + new spawn_type(pick(view(1,src))) + playsound(src.loc, pick('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg'), 50, 1, -3) + + if(charges >= 1) + if(shadow_wights.len < 5 && prob(5)) + shadow_wights.Add(new /obj/effect/shadow_wight(src.loc)) + playsound(src.loc, 'sound/effects/ghost.ogg', 50, 1, -3) + charges -= 0.1 + + if(charges >= 0.1) + if(prob(5)) + src.visible_message("\red \icon[src] [src]'s eyes glow ruby red for a moment!") + charges -= 0.1 + + //check on our shadow wights + if(shadow_wights.len) + wight_check_index++ + if(wight_check_index > shadow_wights.len) + wight_check_index = 1 + + var/obj/effect/shadow_wight/W = shadow_wights[wight_check_index] + if(isnull(W)) + shadow_wights.Remove(wight_check_index) + else if(isnull(W.loc)) + shadow_wights.Remove(wight_check_index) + else if(get_dist(W, src) > 10) + shadow_wights.Remove(wight_check_index) + +/obj/item/weapon/vampiric/hear_talk(mob/M as mob, text) + ..() + if(world.time - last_bloodcall >= bloodcall_interval && M in view(7, src)) + bloodcall(M) + +/obj/item/weapon/vampiric/proc/bloodcall(var/mob/living/carbon/human/M) + last_bloodcall = world.time + if(istype(M)) + playsound(src.loc, pick('sound/hallucinations/wail.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/far_noise.ogg'), 50, 1, -3) + nearby_mobs.Add(M) + + var/target = pick("chest","groin","head","l_arm","r_arm","r_leg","l_leg","l_hand","r_hand","l_foot","r_foot") + M.apply_damage(rand(5, 10), BRUTE, target) + M << "\red The skin on your [parse_zone(target)] feels like it's ripping apart, and a stream of blood flies out." + var/obj/effect/decal/cleanable/blood/splatter/animated/B = new(M.loc) + B.target_turf = pick(range(1, src)) + B.blood_DNA = list() + B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type + M.vessel.remove_reagent("blood",rand(25,50)) + +//animated blood 2 SPOOKY +/obj/effect/decal/cleanable/blood/splatter/animated + var/turf/target_turf + var/loc_last_process + +/obj/effect/decal/cleanable/blood/splatter/animated/New() + ..() + processing_objects.Add(src) + loc_last_process = src.loc + +/obj/effect/decal/cleanable/blood/splatter/animated/process() + if(target_turf && src.loc != target_turf) + step_towards(src,target_turf) + if(src.loc == loc_last_process) + target_turf = null + loc_last_process = src.loc + + //leave some drips behind + if(prob(50)) + var/obj/effect/decal/cleanable/blood/drip/D = new(src.loc) + D.blood_DNA = src.blood_DNA.Copy() + if(prob(50)) + D = new(src.loc) + D.blood_DNA = src.blood_DNA.Copy() + if(prob(50)) + D = new(src.loc) + D.blood_DNA = src.blood_DNA.Copy() + else + ..() + +/obj/effect/shadow_wight + name = "shadow wight" + icon = 'icons/mob/mob.dmi' + icon_state = "shade" + density = 1 + +/obj/effect/shadow_wight/New() + processing_objects.Add(src) + +/obj/effect/shadow_wight/process() + if(src.loc) + src.loc = get_turf(pick(orange(1,src))) + var/mob/living/carbon/M = locate() in src.loc + if(M) + playsound(src.loc, pick('sound/hallucinations/behind_you1.ogg',\ + 'sound/hallucinations/behind_you2.ogg',\ + 'sound/hallucinations/i_see_you1.ogg',\ + 'sound/hallucinations/i_see_you2.ogg',\ + 'sound/hallucinations/im_here1.ogg',\ + 'sound/hallucinations/im_here2.ogg',\ + 'sound/hallucinations/look_up1.ogg',\ + 'sound/hallucinations/look_up2.ogg',\ + 'sound/hallucinations/over_here1.ogg',\ + 'sound/hallucinations/over_here2.ogg',\ + 'sound/hallucinations/over_here3.ogg',\ + 'sound/hallucinations/turn_around1.ogg',\ + 'sound/hallucinations/turn_around2.ogg',\ + ), 50, 1, -3) + M.sleeping = max(M.sleeping,rand(5,10)) + src.loc = null + else + processing_objects.Remove(src) + +/obj/effect/shadow_wight/Bump(var/atom/obstacle) + obstacle << "\red You feel a chill run down your spine!" diff --git a/code/modules/research/xenoarchaeology/finds/finds_talkingitem.dm b/code/modules/research/xenoarchaeology/finds/finds_talkingitem.dm index f518030075..65a2e24ca0 100644 --- a/code/modules/research/xenoarchaeology/finds/finds_talkingitem.dm +++ b/code/modules/research/xenoarchaeology/finds/finds_talkingitem.dm @@ -4,50 +4,64 @@ // This could be extended to atoms, but it's bad enough as is // I genuinely tried to Add and Remove them from var and proc lists, but just couldn't get it working -/obj/item/weapon - var/list/heard_words = list() - var/lastsaid - var/listening_to_players = 0 - var/speaking_to_players = 0 +//for easy reference +/obj/var/datum/talking_atom/talking_atom -/obj/item/weapon/process() - if(!speaking_to_players) +/datum/talking_atom + var/list/heard_words = list() + var/last_talk_time = 0 + var/atom/holder_atom + var/talk_interval = 50 + var/talk_chance = 10 + +/datum/talking_atom/proc/init() + if(holder_atom) + processing_objects.Add(src) + +/datum/talking_atom/proc/process() + if(!holder_atom) processing_objects.Remove(src) - return - if(prob(10) && world.timeofday >= lastsaid && heard_words.len >= 1) + + else if(heard_words.len >= 1 && world.time > last_talk_time + talk_interval && prob(talk_chance)) SaySomething() -/obj/item/weapon/proc/catchMessage(var/msg, var/mob/source) - if(speaking_to_players) - var/list/seperate = list() - if(findtext(msg,"((")) - return - else if(findtext(msg,"))")) - return - else if(findtext(msg," ")==0) - return - else - /*var/l = lentext(msg) - if(findtext(msg," ",l,l+1)==0) - msg+=" "*/ - seperate = text2list(msg, " ") +/datum/talking_atom/proc/catchMessage(var/msg, var/mob/source) + if(!holder_atom) + return - for(var/Xa = 1,Xa 20 + rand(10,20)) - heard_words.Remove(heard_words[1]) - if(!heard_words["[lowertext(seperate[Xa])]"]) - heard_words["[lowertext(seperate[Xa])]"] = list() - var/list/w = heard_words["[lowertext(seperate[Xa])]"] - if(w) - w.Add("[lowertext(seperate[next])]") - //world << "Adding [lowertext(seperate[next])] to [lowertext(seperate[Xa])]" + var/list/seperate = list() + if(findtext(msg,"((")) + return + else if(findtext(msg,"))")) + return + else if(findtext(msg," ")==0) + return + else + /*var/l = lentext(msg) + if(findtext(msg," ",l,l+1)==0) + msg+=" "*/ + seperate = text2list(msg, " ") + + for(var/Xa = 1,Xa 20 + rand(10,20)) + heard_words.Remove(heard_words[1]) + if(!heard_words["[lowertext(seperate[Xa])]"]) + heard_words["[lowertext(seperate[Xa])]"] = list() + var/list/w = heard_words["[lowertext(seperate[Xa])]"] + if(w) + w.Add("[lowertext(seperate[next])]") + //world << "Adding [lowertext(seperate[next])] to [lowertext(seperate[Xa])]" - if(!rand(0, 5)) - spawn(2) SaySomething(pick(seperate)) if(prob(30)) - for(var/mob/O in viewers(src)) - O.show_message("\blue [src] hums for bit then stops...", 1) + var/list/options = list("[holder_atom] seems to be listening intently to [source]...",\ + "[holder_atom] seems to be focussing on [source]...",\ + "[holder_atom] seems to turn it's attention to [source]...") + holder_atom.loc.visible_message("\blue \icon[holder_atom] [pick(options)]") + + if(prob(20)) + spawn(2) + SaySomething(pick(seperate)) /*/obj/item/weapon/talkingcrystal/proc/debug() //set src in view() @@ -57,7 +71,9 @@ for(var/X in d) world << "[X]"*/ -/obj/item/weapon/proc/SaySomething(var/word = null) +/datum/talking_atom/proc/SaySomething(var/word = null) + if(!holder_atom) + return var/msg var/limit = rand(max(5,heard_words.len/2))+3 @@ -95,7 +111,7 @@ else msg+="!" - var/list/listening = viewers(src) + var/list/listening = viewers(holder_atom) for(var/mob/M in mob_list) if (!M.client) continue //skip monkeys and leavers @@ -105,5 +121,5 @@ listening|=M for(var/mob/M in listening) - M << "[src] reverberates, \blue\"[msg]\"" - lastsaid = world.timeofday + rand(300,800) + M << "\icon[holder_atom] [holder_atom] reverberates, \blue\"[msg]\"" + last_talk_time = world.time diff --git a/code/modules/research/xenoarchaeology/genetics/prehistoric_animals.dm b/code/modules/research/xenoarchaeology/genetics/prehistoric_animals.dm new file mode 100644 index 0000000000..c9022726a6 --- /dev/null +++ b/code/modules/research/xenoarchaeology/genetics/prehistoric_animals.dm @@ -0,0 +1,77 @@ +/mob/living/simple_animal/hostile/samak + name = "samak" + desc = "A fast, armoured predator accustomed to hiding and ambushing in cold terrain." + faction = "samak" + icon_state = "samak" + icon_living = "samak" + icon_dead = "samak_dead" + icon = 'code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi' + move_to_delay = 2 + maxHealth = 125 + health = 125 + speed = 2 + melee_damage_lower = 5 + melee_damage_upper = 15 + attacktext = "mauls" + cold_damage_per_tick = 0 + speak_chance = 5 + speak = list("Hruuugh!","Hrunnph") + emote_see = list("paws the ground","shakes its mane","stomps") + emote_hear = list("snuffles") + +/mob/living/simple_animal/hostile/diyaab + name = "diyaab" + desc = "A small pack animal. Although omnivorous, it will hunt meat on occasion." + faction = "diyaab" + icon_state = "diyaab" + icon_living = "diyaab" + icon_dead = "diyaab_dead" + icon = 'code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi' + move_to_delay = 1 + maxHealth = 25 + health = 25 + speed = 1 + melee_damage_lower = 1 + melee_damage_upper = 8 + attacktext = "gouges" + cold_damage_per_tick = 0 + speak_chance = 5 + speak = list("Awrr?","Aowrl!","Worrl") + emote_see = list("sniffs the air cautiously","looks around") + emote_hear = list("snuffles") + +/mob/living/simple_animal/hostile/shantak + name = "shantak" + desc = "A piglike creature with a bright iridiscent mane that sparkles as though lit by an inner light. Don't be fooled by its beauty though." + faction = "shantak" + icon_state = "shantak" + icon_living = "shantak" + icon_dead = "shantak_dead" + icon = 'code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi' + move_to_delay = 1 + maxHealth = 75 + health = 75 + speed = 1 + melee_damage_lower = 3 + melee_damage_upper = 12 + attacktext = "gouges" + cold_damage_per_tick = 0 + speak_chance = 5 + speak = list("Shuhn","Shrunnph?","Shunpf") + emote_see = list("scratches the ground","shakes out it's mane","tinkles gently") + +/mob/living/simple_animal/yithian + name = "yithian" + desc = "A friendly creature vaguely resembling an oversized snail without a shell." + icon_state = "yithian" + icon_living = "yithian" + icon_dead = "yithian_dead" + icon = 'code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi' + +/mob/living/simple_animal/tindalos + name = "tindalos" + desc = "It looks like a large, flightless grasshopper." + icon_state = "tindalos" + icon_living = "tindalos" + icon_dead = "tindalos_dead" + icon = 'code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi' diff --git a/code/modules/research/xenoarchaeology/genetics/prehistoric_plants.dm b/code/modules/research/xenoarchaeology/genetics/prehistoric_plants.dm new file mode 100644 index 0000000000..8496869c85 --- /dev/null +++ b/code/modules/research/xenoarchaeology/genetics/prehistoric_plants.dm @@ -0,0 +1,202 @@ + +/obj/item/seeds/telriis + name = "pack of telriis seeds" + desc = "These seeds grow into telriis grass. Not recommended for consumption by sentient species." + icon_state = "seed-alien1" + mypath = "/obj/item/seeds/telriis" + species = "telriis" + plantname = "Telriis grass" + productname = "/obj/item/weapon/telriis_clump" + lifespan = 50 //number of ticks + endurance = 50 // + maturation = 5 //ticks to full growth stage + production = 5 //ticks till ready to harvest + yield = 4 //number produced when harvest + potency = 5 + plant_type = 1 //1=weed, 2=shroom, 0=normal + growthstages = 4 + +/obj/item/weapon/reagent_containers/food/snacks/grown/telriis_clump + name = "telriis grass" + desc = "A clump of telriis grass, not recommended for consumption by sentients." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "telriisclump" + New(var/loc, var/potency) + ..() + reagents.add_reagent("pwine", potency * 5) + reagents.add_reagent("nutriment", potency) + bitesize = 1+round(reagents.total_volume / 2, 1) + + +/obj/item/seeds/thaadra + name = "pack of thaa'dra seeds" + desc = "These seeds grow into Thaa'dra lichen. Likes the cold." + icon_state = "seed-alien3" + mypath = "/obj/item/seeds/thaadra" + species = "thaadra" + plantname = "Thaa'dra lichen" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/thaadra" + lifespan = 20 + endurance = 10 + maturation = 5 + production = 9 + yield = 2 + potency = 5 + plant_type = 2 + growthstages = 4 + +/obj/item/weapon/reagent_containers/food/snacks/grown/thaadrabloom + name = "thaa'dra bloom" + desc = "Looks chewy, might be good to eat." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "thaadrabloom" + New(var/loc, var/potency) + ..() + reagents.add_reagent("frostoil", potency * 1.5 + 5) + reagents.add_reagent("nutriment", potency) + bitesize = 1+round(reagents.total_volume / 2, 1) + + +/obj/item/seeds/jurlmah + name = "pack of jurl'mah seeds" + desc = "These seeds grow into jurl'mah reeds, which produce large syrupy pods." + icon_state = "seed-alien3" + mypath = "/obj/item/seeds/jurlmah" + species = "jurlmah" + plantname = "jurl'mah reeds" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/jurlmah" + lifespan = 20 + endurance = 12 + maturation = 8 + production = 9 + yield = 3 + potency = 10 + growthstages = 5 + +/obj/item/weapon/reagent_containers/food/snacks/grown/jurlmah + name = "jurl'mah pod" + desc = "Bulbous and veiny, it appears to pulse slightly as you look at it." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "jurlmahpod" + New(var/loc, var/potency) + ..() + reagents.add_reagent("serotrotium", potency) + reagents.add_reagent("nutriment", potency) + bitesize = 1+round(reagents.total_volume / 2, 1) + + +/obj/item/seeds/amauri + name = "pack of amauri seeds" + desc = "Grows into a straight, dark plant with small round fruit." + icon_state = "seed-alien3" + mypath = "/obj/item/seeds/amauri" + species = "amauri" + plantname = "amauri plant" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/amauri" + lifespan = 30 + endurance = 10 + maturation = 8 + production = 9 + yield = 4 + potency = 10 + growthstages = 3 + +/obj/item/weapon/reagent_containers/food/snacks/grown/amauri + name = "amauri fruit" + desc = "It is small, round and hard. Its skin is a thick dark purple." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "amaurifruit" + New(var/loc, var/potency) + ..() + reagents.add_reagent("zombiepowder", potency * 10) + reagents.add_reagent("condensedcapsaicin", potency * 5) + reagents.add_reagent("nutriment", potency) + bitesize = 1+round(reagents.total_volume / 2, 1) + + +/obj/item/seeds/gelthi + name = "pack of gelthi seeds" + desc = "Grows into a bright, wavy plant with many small fruits." + icon_state = "seed-alien2" + mypath = "/obj/item/seeds/gelthi" + species = "gelthi" + plantname = "gelthi plant" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/gelthi" + lifespan = 20 + endurance = 15 + maturation = 6 + production = 6 + yield = 2 + potency = 1 + growthstages = 3 + +/obj/item/weapon/reagent_containers/food/snacks/grown/gelthi + name = "gelthi berries" + desc = "They feel fluffy and slightly warm to the touch." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "gelthiberries" + New(var/loc, var/potency) + ..() + //this may prove a little strong + reagents.add_reagent("stoxin", (potency * potency) / 5) + reagents.add_reagent("capsaicin", (potency * potency) / 5) + reagents.add_reagent("nutriment", potency) + bitesize = 1+round(reagents.total_volume / 2, 1) + + +/obj/item/seeds/vale + name = "pack of vale seeds" + desc = "The vale bush is often depicted in ancient heiroglyphs and is similar to cherry blossoms." + icon_state = "seed-alien2" + mypath = "/obj/item/seeds/vale" + species = "vale" + plantname = "vale bush" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/vale" + lifespan = 25 + endurance = 15 + maturation = 8 + production = 10 + yield = 3 + potency = 3 + growthstages = 4 + +/obj/item/weapon/reagent_containers/food/snacks/grown/vale + name = "vale leaves" + desc = "Small, curly leaves covered in a soft pale fur." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "valeleaves" + New(var/loc, var/potency) + ..() + reagents.add_reagent("paracetamol", potency * 5) + reagents.add_reagent("dexalin", potency * 2) + reagents.add_reagent("nutriment", potency) + bitesize = 1+round(reagents.total_volume / 2, 1) + + +/obj/item/seeds/surik + name = "pack of surik seeds" + desc = "A spiky blue vine with large fruit resembling pig ears." + icon_state = "seed-alien3" + mypath = "/obj/item/seeds/surik" + species = "surik" + plantname = "surik vine" + productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/surik" + lifespan = 30 + endurance = 18 + maturation = 7 + production = 7 + yield = 3 + potency = 3 + growthstages = 4 + +/obj/item/weapon/reagent_containers/food/snacks/grown/surik + name = "surik fruit" + desc = "Multiple layers of blue skin peeling away to reveal a spongey core, vaguely resembling an ear." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "surikfruit" + New(var/loc, var/potency) + ..() + reagents.add_reagent("impedrezene", potency * 3) + reagents.add_reagent("synaptizine", potency * 2) + reagents.add_reagent("nutriment", potency) + bitesize = 1+round(reagents.total_volume / 2, 1) diff --git a/code/modules/research/xenoarchaeology/genetics/reconstitutor.dm b/code/modules/research/xenoarchaeology/genetics/reconstitutor.dm new file mode 100644 index 0000000000..b4afc4ff0c --- /dev/null +++ b/code/modules/research/xenoarchaeology/genetics/reconstitutor.dm @@ -0,0 +1,319 @@ +//gene sequence datum +datum/genesequence + var/spawned_type + var/spawned_type_text + var/list/full_genome_sequence = list() + + + +#define SCANFOSSIL_RETVAL_WRONGTYPE 1 +#define SCANFOSSIL_RETVAL_NOMOREGENESEQ 2 +#define SCANFOSSIL_RETVAL_SUCCESS 4 + +/obj/machinery/computer/reconstitutor + name = "Flora reconstitution console" + icon = 'icons/obj/computer.dmi' + icon_state = "dna" + circuit = "/obj/item/weapon/circuitboard/reconstitutor" + req_access = list(access_heads) //Only used for record deletion right now. + var/obj/machinery/clonepod/pod1 = 1 //Linked cloning pod. + var/temp = "" + var/menu = 1 //Which menu screen to display + var/list/records = list() + var/datum/dna2/record/active_record = null + var/obj/item/weapon/disk/data/diskette = null //Mostly so the geneticist can steal everything. + var/loading = 0 // Nice loading text + var/list/undiscovered_genesequences = null + var/list/discovered_genesequences = list() + var/list/completed_genesequences = list() + var/list/undiscovered_genomes = list() + var/list/manually_placed_genomes = list() + var/list/discovered_genomes = list("! Clear !") + var/list/accepted_fossil_types = list(/obj/item/weapon/fossil/plant) + + +/obj/machinery/computer/reconstitutor/New() + if(!undiscovered_genesequences) + undiscovered_genesequences = master_controller.all_plant_genesequences.Copy() + ..() + +/obj/machinery/computer/reconstitutor/animal + name = "Fauna reconstitution console" + accepted_fossil_types = list(/obj/item/weapon/fossil/bone,/obj/item/weapon/fossil/shell,/obj/item/weapon/fossil/skull) + pod1 = null + circuit = "/obj/item/weapon/circuitboard/reconstitutor/animal" + +/obj/machinery/computer/reconstitutor/animal/New() + undiscovered_genesequences = master_controller.all_animal_genesequences.Copy() + ..() + +/obj/machinery/computer/reconstitutor/attackby(obj/item/W, mob/user) + if(istype(W,/obj/item/weapon/fossil)) + user.drop_item() + W.loc = src.loc + switch(scan_fossil(W)) + if(1) + src.visible_message("\red \icon[src] [src] scans the fossil and rejects it.") + if(2) + visible_message("\red \icon[src] [src] can not extract any more genetic data from new fossils.") + if(4) + src.visible_message("\blue \icon[src] [user] inserts [W] into [src], the fossil is consumed as [src] extracts genetic data from it.") + del(W) + updateDialog() + else if (istype(W, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = W + S.hide_from(usr) + var/numaccepted = 0 + var/numrejected = 0 + var/full = 0 + for(var/obj/item/weapon/fossil/F in S.contents) + switch(scan_fossil(F)) + if(SCANFOSSIL_RETVAL_WRONGTYPE) + numrejected += 1 + if(SCANFOSSIL_RETVAL_NOMOREGENESEQ) + full = 1 + if(SCANFOSSIL_RETVAL_SUCCESS) + numaccepted += 1 + S.remove_from_storage(F, src) //This will move the item to this item's contents + del(F) + updateDialog() + var/outmsg = "\blue You empty all the fossils from [S] into [src]." + if(numaccepted) + outmsg += " \blue[numaccepted] fossils were accepted and consumed as [src] extracts genetic data from them." + if(numrejected) + outmsg += " \red[numrejected] fossils were rejected." + if(full) + outmsg += " \red[src] can not extract any more genetic data from new fossils." + visible_message(outmsg) + + else + ..() + +/obj/machinery/computer/reconstitutor/attack_hand(var/mob/user as mob) + src.add_fingerprint(user) + interact(user) + +/obj/machinery/computer/reconstitutor/interact(mob/user) + if(stat & (NOPOWER|BROKEN) || get_dist(src, user) > 1) + user.unset_machine(src) + return + + var/dat = "Garland Corp genetic reconstitutor
" + dat += "
" + if(!pod1) + pod1 = locate() in orange(1, src) + + if(!pod1) + dat += "Unable to locate cloning pod.
" + else if(istype(pod1)) + dat += "Cloning pod connected.
" + + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + + //WIP gene sequences + for(var/sequence_num = 1, sequence_num <= discovered_genesequences.len, sequence_num += 1) + var/datum/genesequence/cur_genesequence = discovered_genesequences[sequence_num] + dat += "" + var/num_correct = 0 + for(var/curindex = 1, curindex <= 7, curindex++) + var/bgcolour = "#ffffff"//white ffffff, red ff0000 + + //background colour hints at correct positioning + if(manually_placed_genomes[sequence_num][curindex]) + //green background if slot is correctly filled + if(manually_placed_genomes[sequence_num][curindex] == cur_genesequence.full_genome_sequence[curindex]) + bgcolour = "#008000" + num_correct += 1 + if(num_correct == 7) + discovered_genesequences -= cur_genesequence + completed_genesequences += cur_genesequence + manually_placed_genomes[sequence_num] = new/list(7) + interact(user) + return + //yellow background if adjacent to correct slot + if(curindex > 1 && manually_placed_genomes[sequence_num][curindex] == cur_genesequence.full_genome_sequence[curindex - 1]) + bgcolour = "#ffff00" + else if(curindex < 7 && manually_placed_genomes[sequence_num][curindex] == cur_genesequence.full_genome_sequence[curindex + 1]) + bgcolour = "#ffff00" + + var/this_genome_slot = manually_placed_genomes[sequence_num][curindex] + if(!this_genome_slot) + this_genome_slot = "- - - - -" + dat += "" + dat += "" + //dat += "" + dat += "" + + //completed gene sequences + for(var/sequence_num = 1, sequence_num <= completed_genesequences.len, sequence_num += 1) + var/datum/genesequence/cur_genesequence = completed_genesequences[sequence_num] + dat += "" + for(var/curindex = 1, curindex <= 7, curindex++) + var/this_genome_slot = cur_genesequence.full_genome_sequence[curindex] + dat += "" + dat += "" + dat += "" + dat += "" + + dat += "
GENE1GENE2GENE3GENE4GENE5GENE6GENE7
[this_genome_slot]ResetClone
[this_genome_slot]WipeClone
" + + dat += "
" + dat += "
" + dat += "Close" + user << browse(dat, "window=reconstitutor;size=600x500") + user.set_machine(src) + onclose(user, "reconstitutor") + +/obj/machinery/computer/reconstitutor/animal/Topic(href, href_list) + if(href_list["clone"]) + var/sequence_num = text2num(href_list["sequence_num"]) + var/datum/genesequence/cloned_genesequence = completed_genesequences[sequence_num] + if(pod1) + if(pod1.occupant) + visible_message("\red \icon[src] The cloning pod is currently occupied.") + else if(pod1.biomass < CLONE_BIOMASS) + visible_message("\red \icon[src] Not enough biomass in the cloning pod.") + else if(pod1.mess) + visible_message("\red \icon[src] Error: clonepod malfunction.") + else + visible_message("\blue \icon[src] [src] clones something from a reconstituted gene sequence!") + playsound(src.loc, 'sound/effects/screech.ogg', 50, 1, -3) + pod1.occupant = new cloned_genesequence.spawned_type(pod1) + pod1.locked = 1 + pod1.icon_state = "pod_1" + //pod1.occupant.name = "[pod1.occupant.name] ([rand(0,999)])" + pod1.biomass -= CLONE_BIOMASS + else + usr << "\red \icon[src] Unable to locate cloning pod!" + else + ..() + +/obj/machinery/computer/reconstitutor/Topic(href, href_list) + if(href_list["insertpos"]) + //world << "inserting gene for genesequence [href_list["insertgenome"]] at pos [text2num(href_list["insertpos"])]" + var/sequence_num = text2num(href_list["sequence_num"]) + var/insertpos = text2num(href_list["insertpos"]) + + var/old_genome = manually_placed_genomes[sequence_num][insertpos] + discovered_genomes = sortList(discovered_genomes) + var/new_genome = input(usr, "Which genome do you want to insert here?") as null|anything in discovered_genomes + if(new_genome == "! Clear !") + manually_placed_genomes[sequence_num][insertpos] = null + else if(new_genome) + manually_placed_genomes[sequence_num][insertpos] = new_genome + discovered_genomes.Remove(new_genome) + if(old_genome) + discovered_genomes.Add(old_genome) + updateDialog() + + else if(href_list["reset"]) + var/sequence_num = text2num(href_list["sequence_num"]) + for(var/curindex = 1, curindex <= 7, curindex++) + var/old_genome = manually_placed_genomes[sequence_num][curindex] + manually_placed_genomes[sequence_num][curindex] = null + if(old_genome) + discovered_genomes.Add(old_genome) + updateDialog() + + else if(href_list["wipe"]) + var/sequence_num = text2num(href_list["sequence_num"]) + var/datum/genesequence/wiped_genesequence = completed_genesequences[sequence_num] + completed_genesequences.Remove(wiped_genesequence) + discovered_genesequences.Add(wiped_genesequence) + + discovered_genomes.Add(wiped_genesequence.full_genome_sequence) + discovered_genomes = sortList(discovered_genomes) + updateDialog() + + else if(href_list["clone"]) + var/sequence_num = text2num(href_list["sequence_num"]) + var/datum/genesequence/cloned_genesequence = completed_genesequences[sequence_num] + visible_message("\blue \icon[src] [src] clones a packet of seeds from a reconstituted gene sequence!") + playsound(src.loc, 'sound/effects/screech.ogg', 50, 1, -3) + new cloned_genesequence.spawned_type(src.loc) + + else if(href_list["close"]) + usr.unset_machine(src) + usr << browse(null, "window=reconstitutor") + + else + ..() + +/obj/machinery/computer/reconstitutor/proc/scan_fossil(var/obj/item/weapon/fossil/scan_fossil) + //see whether we accept these kind of fossils + if(accepted_fossil_types.len && !accepted_fossil_types.Find(scan_fossil.type)) + return SCANFOSSIL_RETVAL_WRONGTYPE + + //see whether we are going to discover a new sequence, new genome for existing sequence or nothing + var/new_genome_prob = discovered_genesequences.len * 50 + + if( (new_genome_prob >= 100 || prob(new_genome_prob)) && undiscovered_genomes.len) + //create a new genome for an existing gene sequence + var/newly_discovered_genome = pick(undiscovered_genomes) + undiscovered_genomes -= newly_discovered_genome + discovered_genomes.Add(newly_discovered_genome) + + //chance to discover a second genome + if(prob(75)) + newly_discovered_genome = pick(undiscovered_genomes) + undiscovered_genomes -= newly_discovered_genome + discovered_genomes.Add(newly_discovered_genome) + //chance to discover a third genome + if(prob(50)) + newly_discovered_genome = pick(undiscovered_genomes) + undiscovered_genomes -= newly_discovered_genome + discovered_genomes.Add(newly_discovered_genome) + + else if(undiscovered_genesequences.len) + //discover new gene sequence + var/datum/genesequence/newly_discovered_genesequence = pick(undiscovered_genesequences) + undiscovered_genesequences -= newly_discovered_genesequence + discovered_genesequences += newly_discovered_genesequence + //add genomes for new gene sequence to pool of discoverable genomes + undiscovered_genomes.Add(newly_discovered_genesequence.full_genome_sequence) + manually_placed_genomes.Add(null) + manually_placed_genomes[manually_placed_genomes.len] = new/list(7) + + else + //there's no point scanning any more fossils, we've already discovered everything + return SCANFOSSIL_RETVAL_NOMOREGENESEQ + + return SCANFOSSIL_RETVAL_SUCCESS + +#undef SCANFOSSIL_RETVAL_WRONGTYPE +#undef SCANFOSSIL_RETVAL_NOMOREGENESEQ +#undef SCANFOSSIL_RETVAL_SUCCESS + + +/obj/item/weapon/circuitboard/reconstitutor + name = "Circuit board (Flora Reconstitution Console)" + build_path = "/obj/machinery/computer/reconstitutor" + origin_tech = "programming=2;biotech=4;materials=6" + frame_desc = "Requires 2 Advanced Scanning Module, 1 Nano Manipulator, 1 Matter Bin and 1 Advanced Capacitor." + req_components = list( + "/obj/item/weapon/stock_parts/scanning_module/adv" = 2, + "/obj/item/weapon/stock_parts/manipulator/nano" = 1, + "/obj/item/weapon/stock_parts/matter_bin" = 1, + "/obj/item/weapon/stock_parts/capacitor/adv" = 1) + +/obj/item/weapon/circuitboard/reconstitutor/animal + name = "Circuit board (Fauna Reconstitution Console)" + build_path = "/obj/machinery/computer/reconstitutor/animal" + origin_tech = "programming=2;biotech=4;materials=6" + frame_desc = "Requires 2 Advanced Scanning Module, 1 Nano Manipulator, 1 Matter Bin and 1 Advanced Capacitor." + req_components = list( + "/obj/item/weapon/stock_parts/scanning_module/adv" = 2, + "/obj/item/weapon/stock_parts/manipulator/nano" = 1, + "/obj/item/weapon/stock_parts/matter_bin" = 1, + "/obj/item/weapon/stock_parts/capacitor/adv" = 1) diff --git a/code/modules/research/xenoarchaeology/machinery/artifact_harvester.dm b/code/modules/research/xenoarchaeology/machinery/artifact_harvester.dm index 117be557da..495d393766 100644 --- a/code/modules/research/xenoarchaeology/machinery/artifact_harvester.dm +++ b/code/modules/research/xenoarchaeology/machinery/artifact_harvester.dm @@ -12,6 +12,7 @@ var/obj/item/weapon/anobattery/inserted_battery var/obj/machinery/artifact/cur_artifact var/obj/machinery/artifact_scanpad/owned_scanner = null + var/last_process = 0 /obj/machinery/artifact_harvester/New() ..() @@ -47,14 +48,14 @@ if(owned_scanner) if(harvesting) if(harvesting > 0) - dat += "Please wait. Harvesting in progress ([(inserted_battery.stored_charge/inserted_battery.capacity)*100]%).
" + dat += "Please wait. Harvesting in progress ([round((inserted_battery.stored_charge/inserted_battery.capacity)*100)]%).
" else - dat += "Please wait. Energy dump in progress ([(inserted_battery.stored_charge/inserted_battery.capacity)*100]%).
" + dat += "Please wait. Energy dump in progress ([round((inserted_battery.stored_charge/inserted_battery.capacity)*100)]%).
" dat += "Halt early
" else if(inserted_battery) dat += "[inserted_battery.name] inserted, charge level: [inserted_battery.stored_charge]/[inserted_battery.capacity] ([(inserted_battery.stored_charge/inserted_battery.capacity)*100]%)
" - dat += "Energy signature ID:[inserted_battery.battery_effect.artifact_id == "" ? "???" : "[inserted_battery.battery_effect.artifact_id]"]
" + dat += "Energy signature ID:[inserted_battery.battery_effect ? (inserted_battery.battery_effect.artifact_id == "" ? "???" : "[inserted_battery.battery_effect.artifact_id]") : "NA"]
" dat += "Eject battery
" dat += "Drain battery of all charge
" dat += "Begin harvesting
" @@ -74,8 +75,9 @@ return if(harvesting > 0) - //gain a bit of charge - inserted_battery.stored_charge += 0.5 + //charge at 33% consumption rate + inserted_battery.stored_charge += (world.time - last_process) / 3 + last_process = world.time //check if we've finished if(inserted_battery.stored_charge >= inserted_battery.capacity) @@ -88,14 +90,14 @@ else if(harvesting < 0) //dump some charge - inserted_battery.stored_charge -= 2 + inserted_battery.stored_charge -= (world.time - last_process) / 3 //do the effect if(inserted_battery.battery_effect) inserted_battery.battery_effect.process() //if the effect works by touch, activate it on anyone viewing the console - if(inserted_battery.battery_effect.effect == 0) + if(inserted_battery.battery_effect.effect == EFFECT_TOUCH) var/list/nearby = viewers(1, src) for(var/mob/M in nearby) if(M.machine == src) @@ -114,79 +116,115 @@ /obj/machinery/artifact_harvester/Topic(href, href_list) if (href_list["harvest"]) - //locate artifact on analysis pad - cur_artifact = null - var/articount = 0 - var/obj/machinery/artifact/analysed - for(var/obj/machinery/artifact/A in get_turf(owned_scanner)) - analysed = A - articount++ + if(!inserted_battery) + src.visible_message("[src] states, \"Cannot harvest. No battery inserted.\"") - var/mundane = 0 - for(var/obj/O in get_turf(owned_scanner)) - if(O.invisibility) - continue - if(!istype(O, /obj/machinery/artifact) && !istype(O, /obj/machinery/artifact_scanpad)) - mundane++ - break - for(var/mob/O in get_turf(owned_scanner)) - if(O.invisibility) - continue - mundane++ - break + else if(inserted_battery.stored_charge >= inserted_battery.capacity) + src.visible_message("[src] states, \"Cannot harvest. battery is full.\"") - if(analysed.being_used) - var/message = "[src] states, \"Cannot harvest. Too much interference.\"" - src.visible_message(message) - else if(articount == 1 && !mundane) - cur_artifact = analysed - //there should already be a battery inserted, but this is just in case - if(inserted_battery) - //see if we can clear out an old effect - //delete it when the ids match to account for duplicate ids having different effects - if(inserted_battery.battery_effect && inserted_battery.stored_charge <= 0) - del(inserted_battery.battery_effect) + else - //only charge up - var/matching_id = 0 - if(inserted_battery.battery_effect) - matching_id = (inserted_battery.battery_effect.artifact_id == cur_artifact.my_effect.artifact_id) - var/matching_effecttype = 0 - if(inserted_battery.battery_effect) - matching_effecttype = (inserted_battery.battery_effect.type == cur_artifact.my_effect.type) - if(!inserted_battery.battery_effect || (matching_id && matching_effecttype)) - harvesting = 1 - use_power = 2 - cur_artifact.anchored = 1 - cur_artifact.being_used = 1 - icon_state = "incubator_on" - var/message = "[src] states, \"Beginning artifact energy harvesting.\"" - src.visible_message(message) + //locate artifact on analysis pad + cur_artifact = null + var/articount = 0 + var/obj/machinery/artifact/analysed + for(var/obj/machinery/artifact/A in get_turf(owned_scanner)) + analysed = A + articount++ - //duplicate the artifact's effect datum - if(!inserted_battery.battery_effect) - var/effecttype = cur_artifact.my_effect.type - var/datum/artifact_effect/E = new effecttype(inserted_battery) - - //duplicate it's unique settings - for(var/varname in list("chargelevelmax","artifact_id","effect","effectrange","trigger")) - E.vars[varname] = cur_artifact.my_effect.vars[varname] - - //copy the new datum into the battery - inserted_battery.battery_effect = E - inserted_battery.stored_charge = 0 - else - var/message = "[src] states, \"Cannot harvest. Incompatible energy signatures detected.\"" - src.visible_message(message) - else if(cur_artifact) - var/message = "[src] states, \"Cannot harvest. No battery inserted.\"" + if(articount <= 0) + var/message = "[src] states, \"Cannot harvest. No noteworthy energy signature isolated.\"" src.visible_message(message) - else if(articount > 1 || mundane) - var/message = "[src] states, \"Cannot harvest. Error isolating energy signature.\"" - src.visible_message(message) - else if(!articount) - var/message = "[src] states, \"Cannot harvest. No noteworthy energy signature isolated.\"" - src.visible_message(message) + + else if(analysed && analysed.being_used) + src.visible_message("[src] states, \"Cannot harvest. Source already being harvested.\"") + + else + var/mundane = 0 + for(var/obj/O in get_turf(owned_scanner)) + if(O.invisibility) + continue + if(!istype(O, /obj/machinery/artifact) && !istype(O, /obj/machinery/artifact_scanpad)) + mundane++ + break + for(var/mob/O in get_turf(owned_scanner)) + if(O.invisibility) + continue + mundane++ + break + + if(articount > 1 || mundane) + var/message = "[src] states, \"Cannot harvest. Too many artifacts on the pad.\"" + src.visible_message(message) + else + cur_artifact = analysed + + //if both effects are active, we can't harvest either + if(cur_artifact.my_effect.activated && cur_artifact.secondary_effect.activated) + src.visible_message("[src] states, \"Cannot harvest. Source is emitting conflicting energy signatures.\"") + else if(!cur_artifact.my_effect.activated && !cur_artifact.secondary_effect.activated) + src.visible_message("[src] states, \"Cannot harvest. No energy emitting from source.\"") + + else + //see if we can clear out an old effect + //delete it when the ids match to account for duplicate ids having different effects + if(inserted_battery.battery_effect && inserted_battery.stored_charge <= 0) + del(inserted_battery.battery_effect) + + // + var/datum/artifact_effect/source_effect + + //if we already have charge in the battery, we can only recharge it from the source artifact + if(inserted_battery.stored_charge > 0) + var/battery_matches_primary_id = 0 + if(inserted_battery.battery_effect && inserted_battery.battery_effect.artifact_id == cur_artifact.my_effect.artifact_id) + battery_matches_primary_id = 1 + if(battery_matches_primary_id && cur_artifact.my_effect.activated) + //we're good to recharge the primary effect! + source_effect = cur_artifact.my_effect + + var/battery_matches_secondary_id = 0 + if(inserted_battery.battery_effect && inserted_battery.battery_effect.artifact_id == cur_artifact.secondary_effect.artifact_id) + battery_matches_secondary_id = 1 + if(battery_matches_secondary_id && cur_artifact.secondary_effect.activated) + //we're good to recharge the secondary effect! + source_effect = cur_artifact.secondary_effect + + if(!source_effect) + src.visible_message("[src] states, \"Cannot harvest. Battery is charged with a different energy signature.\"") + else + //we're good to charge either + if(cur_artifact.my_effect.activated) + //charge the primary effect + source_effect = cur_artifact.my_effect + + else if(cur_artifact.secondary_effect.activated) + //charge the secondary effect + source_effect = cur_artifact.secondary_effect + + + if(source_effect) + harvesting = 1 + use_power = 2 + cur_artifact.anchored = 1 + cur_artifact.being_used = 1 + icon_state = "incubator_on" + var/message = "[src] states, \"Beginning energy harvesting.\"" + src.visible_message(message) + last_process = world.time + + //duplicate the artifact's effect datum + if(!inserted_battery.battery_effect) + var/effecttype = source_effect.type + var/datum/artifact_effect/E = new effecttype(inserted_battery) + + //duplicate it's unique settings + for(var/varname in list("chargelevelmax","artifact_id","effect","effectrange","trigger")) + E.vars[varname] = source_effect.vars[varname] + + //copy the new datum into the battery + inserted_battery.battery_effect = E + inserted_battery.stored_charge = 0 if (href_list["stopharvest"]) if(harvesting) @@ -195,7 +233,7 @@ harvesting = 0 cur_artifact.anchored = 0 cur_artifact.being_used = 0 - src.visible_message("[name] states, \"Activity interrupted.\"") + src.visible_message("[name] states, \"Energy harvesting interrupted.\"") icon_state = "incubator" if (href_list["ejectbattery"]) @@ -207,7 +245,8 @@ if(inserted_battery.battery_effect && inserted_battery.stored_charge > 0) if(alert("This action will dump all charge, safety gear is recommended before proceeding","Warning","Continue","Cancel")) if(!inserted_battery.battery_effect.activated) - inserted_battery.battery_effect.ToggleActivate(0) + inserted_battery.battery_effect.ToggleActivate(1) + last_process = world.time harvesting = -1 use_power = 2 icon_state = "incubator_on" diff --git a/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm b/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm index eaf92181b2..bddd133ade 100644 --- a/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm +++ b/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm @@ -285,10 +285,8 @@ data = " - Mundane object (archaic xenos origins)
" var/obj/item/weapon/archaeological_find/A = scanned_item - if(A.speaking_to_players) - data = " - Exhibits properties consistent with sonic reproduction.
" - if(A.listening_to_players) - data = " - Exhibits properties similar to audio capture technology.
" + if(A.talking_atom) + data = " - Exhibits properties consistent with sonic reproduction and audio capture technologies.
" var/anom_found = 0 if(G) diff --git a/code/modules/research/xenoarchaeology/master_controller.dm b/code/modules/research/xenoarchaeology/master_controller.dm new file mode 100644 index 0000000000..9d347e19c6 --- /dev/null +++ b/code/modules/research/xenoarchaeology/master_controller.dm @@ -0,0 +1,145 @@ + +/datum/controller/game_controller + var/list/all_animal_genesequences = list() + var/list/all_plant_genesequences = list() + var/list/genome_prefixes = null + var/list/artifact_spawning_turfs = list() + var/list/digsite_spawning_turfs = list() + + var/list/spawn_types_animal = list("/mob/living/carbon/slime",\ + "/mob/living/simple_animal/hostile/alien",\ + "/mob/living/simple_animal/hostile/alien/drone",\ + "/mob/living/simple_animal/hostile/alien/sentinel",\ + "/mob/living/simple_animal/hostile/giant_spider",\ + "/mob/living/simple_animal/hostile/giant_spider/hunter",\ + "/mob/living/simple_animal/hostile/giant_spider/nurse",\ + "/mob/living/simple_animal/hostile/creature",\ + "/mob/living/simple_animal/hostile/samak",\ + "/mob/living/simple_animal/hostile/diyaab",\ + "/mob/living/simple_animal/hostile/shantak",\ + "/mob/living/simple_animal/tindalos",\ + "/mob/living/simple_animal/yithian") + + var/list/spawn_types_plant = list("/obj/item/seeds/walkingmushroommycelium",\ + "/obj/item/seeds/killertomatoseed",\ + "/obj/item/seeds/shandseed", + "/obj/item/seeds/mtearseed", + "/obj/item/seeds/thaadra",\ + "/obj/item/seeds/telriis",\ + "/obj/item/seeds/jurlmah",\ + "/obj/item/seeds/amauri",\ + "/obj/item/seeds/gelthi",\ + "/obj/item/seeds/vale",\ + "/obj/item/seeds/surik") + +#define XENOARCH_SPAWN_CHANCE 0.5 +#define DIGSITESIZE_LOWER 4 +#define DIGSITESIZE_UPPER 12 +#define ARTIFACTSPAWNNUM_LOWER 6 +#define ARTIFACTSPAWNNUM_UPPER 12 + +datum/controller/game_controller/proc/SetupXenoarch() + //create digsites + for(var/turf/simulated/mineral/M in block(locate(1,1,1), locate(world.maxx, world.maxy, world.maxz))) + if(isnull(M.geologic_data)) + M.geologic_data = new/datum/geosample(M) + + if(!prob(XENOARCH_SPAWN_CHANCE)) + continue + + digsite_spawning_turfs.Add(M) + var/digsite = get_random_digsite_type() + var/target_digsite_size = rand(DIGSITESIZE_LOWER, DIGSITESIZE_UPPER) + var/list/processed_turfs = list() + var/list/turfs_to_process = list(M) + while(turfs_to_process.len) + var/turf/simulated/mineral/archeo_turf = pop(turfs_to_process) + + if(target_digsite_size > 1) + var/list/viable_adjacent_turfs = orange(1, archeo_turf) + for(var/turf/simulated/mineral/T in orange(1, archeo_turf)) + if(T.finds) + continue + if(T in processed_turfs) + continue + viable_adjacent_turfs.Add(T) + + for(var/turf/simulated/mineral/T in viable_adjacent_turfs) + if(prob(target_digsite_size/viable_adjacent_turfs.len)) + turfs_to_process.Add(T) + target_digsite_size -= 1 + if(target_digsite_size <= 0) + break + + processed_turfs.Add(archeo_turf) + if(isnull(archeo_turf.finds)) + archeo_turf.finds = list() + if(prob(50)) + archeo_turf.finds.Add(new /datum/find(digsite, rand(5,95))) + else if(prob(75)) + archeo_turf.finds.Add(new /datum/find(digsite, rand(5,45))) + archeo_turf.finds.Add(new /datum/find(digsite, rand(55,95))) + else + archeo_turf.finds.Add(new /datum/find(digsite, rand(5,30))) + archeo_turf.finds.Add(new /datum/find(digsite, rand(35,75))) + archeo_turf.finds.Add(new /datum/find(digsite, rand(75,95))) + + //sometimes a find will be close enough to the surface to show + var/datum/find/F = archeo_turf.finds[1] + if(F.excavation_required <= F.view_range) + archeo_turf.archaeo_overlay = "overlay_archaeo[rand(1,3)]" + archeo_turf.overlays += archeo_turf.archaeo_overlay + + //have a chance for an artifact to spawn here, but not in animal or plant digsites + if(isnull(M.artifact_find) && digsite != 1 && digsite != 2) + artifact_spawning_turfs.Add(archeo_turf) + + //create artifact machinery + var/num_artifacts_spawn = rand(ARTIFACTSPAWNNUM_LOWER, ARTIFACTSPAWNNUM_UPPER) + while(artifact_spawning_turfs.len > num_artifacts_spawn) + pick_n_take(artifact_spawning_turfs) + + var/list/artifacts_spawnturf_temp = artifact_spawning_turfs.Copy() + while(artifacts_spawnturf_temp.len > 0) + var/turf/simulated/mineral/artifact_turf = pop(artifacts_spawnturf_temp) + artifact_turf.artifact_find = new() + + //make sure we have some prefixes for the gene sequences + if(!genome_prefixes) + genome_prefixes = alphabet_uppercase.Copy() + if(!genome_prefixes.len) + del genome_prefixes + genome_prefixes = alphabet_uppercase.Copy() + + //create animal gene sequences + while(spawn_types_animal.len && genome_prefixes.len) + var/datum/genesequence/new_sequence = new/datum/genesequence() + new_sequence.spawned_type_text = pick(spawn_types_animal) + new_sequence.spawned_type = text2path(new_sequence.spawned_type_text) + spawn_types_animal -= new_sequence.spawned_type_text + + var/prefixletter = pick(genome_prefixes) + genome_prefixes -= prefixletter + while(new_sequence.full_genome_sequence.len < 7) + new_sequence.full_genome_sequence.Add("[prefixletter][pick(alphabet_uppercase)][pick(alphabet_uppercase)][pick(1,2,3,4,5,6,7,8,9,0)][pick(1,2,3,4,5,6,7,8,9,0)]") + + all_animal_genesequences.Add(new_sequence) + + //create plant gene sequences + while(spawn_types_plant.len && genome_prefixes.len) + var/datum/genesequence/new_sequence = new/datum/genesequence() + new_sequence.spawned_type = pick(spawn_types_plant) + spawn_types_plant -= new_sequence.spawned_type_text + + var/prefixletter = pick(genome_prefixes) + genome_prefixes -= prefixletter + while(new_sequence.full_genome_sequence.len < 7) + new_sequence.full_genome_sequence.Add("[prefixletter][pick(1,2,3,4,5,6,7,8,9,0)][pick(1,2,3,4,5,6,7,8,9,0)][pick(alphabet_uppercase)][pick(alphabet_uppercase)]") + + all_plant_genesequences.Add(new_sequence) + +#undef XENOARCH_SPAWN_CHANCE +#undef DIGSITESIZE_LOWER +#undef DIGSITESIZE_UPPER +#undef ARTIFACTSPAWNNUM_LOWER +#undef ARTIFACTSPAWNNUM_UPPER diff --git a/code/modules/research/xenoarchaeology/misc.dm b/code/modules/research/xenoarchaeology/misc.dm index 6b95d6dfc8..3cfa9d10a5 100644 --- a/code/modules/research/xenoarchaeology/misc.dm +++ b/code/modules/research/xenoarchaeology/misc.dm @@ -1,52 +1,3 @@ -#define XENOARCH_SPAWN_CHANCE 0.5 -#define XENOARCH_SPREAD_CHANCE 15 -#define ARTIFACT_SPAWN_CHANCE 20 - -proc/SetupXenoarch() - for(var/turf/simulated/mineral/M in block(locate(1,1,1), locate(world.maxx, world.maxy, world.maxz))) - if(!M.geologic_data) - M.geologic_data = new/datum/geosample(M) - - if(!prob(XENOARCH_SPAWN_CHANCE)) - continue - - var/digsite = get_random_digsite_type() - var/list/processed_turfs = list() - var/list/turfs_to_process = list(M) - for(var/turf/simulated/mineral/archeo_turf in turfs_to_process) - - for(var/turf/simulated/mineral/T in orange(1, archeo_turf)) - if(T.finds) - continue - if(T in processed_turfs) - continue - if(prob(XENOARCH_SPREAD_CHANCE)) - turfs_to_process.Add(T) - - processed_turfs.Add(archeo_turf) - if(!archeo_turf.finds) - archeo_turf.finds = list() - if(prob(50)) - archeo_turf.finds.Add(new /datum/find(digsite, rand(5,95))) - else if(prob(75)) - archeo_turf.finds.Add(new /datum/find(digsite, rand(5,45))) - archeo_turf.finds.Add(new /datum/find(digsite, rand(55,95))) - else - archeo_turf.finds.Add(new /datum/find(digsite, rand(5,30))) - archeo_turf.finds.Add(new /datum/find(digsite, rand(35,75))) - archeo_turf.finds.Add(new /datum/find(digsite, rand(75,95))) - - //sometimes a find will be close enough to the surface to show - var/datum/find/F = archeo_turf.finds[1] - if(F.excavation_required <= F.view_range) - archeo_turf.archaeo_overlay = "overlay_archaeo[rand(1,3)]" - archeo_turf.overlays += archeo_turf.archaeo_overlay - - //dont create artifact machinery in animal or plant digsites, or if we already have one - if(!M.artifact_find && digsite != 1 && digsite != 2 && prob(ARTIFACT_SPAWN_CHANCE)) - M.artifact_find = new() - artifact_spawn.Add(src) - //---- Noticeboard @@ -152,6 +103,7 @@ proc/SetupXenoarch() new /obj/item/weapon/pickaxe(src) new /obj/item/device/measuring_tape(src) new /obj/item/weapon/pickaxe/hand(src) + new /obj/item/weapon/storage/bag/fossils(src) return //---- Isolation room air alarms diff --git a/code/modules/research/xenoarchaeology/tools/ano_device_battery.dm b/code/modules/research/xenoarchaeology/tools/ano_device_battery.dm index c7779dd5ca..3886f6fec0 100644 --- a/code/modules/research/xenoarchaeology/tools/ano_device_battery.dm +++ b/code/modules/research/xenoarchaeology/tools/ano_device_battery.dm @@ -4,7 +4,7 @@ icon = 'icons/obj/xenoarchaeology.dmi' icon_state = "anobattery0" var/datum/artifact_effect/battery_effect - var/capacity = 200 + var/capacity = 300 var/stored_charge = 0 var/effect_id = "" @@ -20,13 +20,15 @@ name = "Anomaly power utilizer" icon = 'icons/obj/xenoarchaeology.dmi' icon_state = "anodev" - var/cooldown = 0 var/activated = 0 - var/timing = 0 - var/time = 50 - var/archived_time = 50 + var/duration = 0 + var/interval = 0 + var/time_end = 0 + var/last_activation = 0 + var/last_process = 0 var/obj/item/weapon/anobattery/inserted_battery var/turf/archived_loc + var/energy_consumed_on_touch = 100 /obj/item/weapon/anodevice/New() ..() @@ -47,54 +49,35 @@ return src.interact(user) /obj/item/weapon/anodevice/interact(var/mob/user) - user.set_machine(src) var/dat = "Anomalous Materials Energy Utiliser
" if(inserted_battery) - if(cooldown) - dat += "Cooldown in progress, please wait.
" - else if(activated) - if(timing) - dat += "Device active.
" - else - dat += "Device active in timed mode.
" + if(activated) + dat += "Device active.
" dat += "[inserted_battery] inserted, anomaly ID: [inserted_battery.battery_effect.artifact_id ? inserted_battery.battery_effect.artifact_id : "NA"]
" - dat += "Total Power: [inserted_battery.stored_charge]/[inserted_battery.capacity]

" - dat += "Timed activation: -- - [time >= 1000 ? "[time/10]" : time >= 100 ? " [time/10]" : " [time/10]" ] + ++
" - if(cooldown) - dat += "Cooldown in progress.
" - dat += "
" - else if(!activated) - dat += "Start
" - dat += "Start in timed mode
" + dat += "Charge: [inserted_battery.stored_charge] / [inserted_battery.capacity]
" + dat += "Time left activated: [round(max((time_end - last_process) / 10, 0))]
" + if(activated) + dat += "Shutdown
" else - dat += "Shutdown emission
" - dat += "
" + dat += "Start
" + dat += "
" + + dat += "Activate duration (sec): -- - [duration/10] + ++
" + dat += "Activate interval (sec): -- - [interval/10] + ++
" + dat += "
" dat += "Eject battery
" else dat += "Please insert battery
" - dat += "
" - dat += "
" - dat += "
" - - dat += "
" - dat += "
" - dat += "
" - dat += "
" - dat += "Refresh Close" + dat += "Refresh Close" user << browse(dat, "window=anodevice;size=400x500") onclose(user, "anodevice") /obj/item/weapon/anodevice/process() - if(cooldown > 0) - cooldown -= 1 - if(cooldown <= 0) - cooldown = 0 - src.visible_message("\blue \icon[src] [src] chimes.", "\blue \icon[src] You hear something chime.") - else if(activated) + if(activated) if(inserted_battery && inserted_battery.battery_effect) //make sure the effect is active if(!inserted_battery.battery_effect.activated) @@ -106,71 +89,83 @@ archived_loc = T inserted_battery.battery_effect.UpdateMove() - //process the effect - inserted_battery.battery_effect.process() //if someone is holding the device, do the effect on them - if(inserted_battery.battery_effect.effect == 0 && ismob(src.loc)) - inserted_battery.battery_effect.DoEffectTouch(src.loc) + var/mob/holder + if(ismob(src.loc)) + holder = src.loc //handle charge - inserted_battery.stored_charge -= 1 - if(inserted_battery.stored_charge <= 0) - shutdown_emission() + if(world.time - last_activation > interval) + if(inserted_battery.battery_effect.effect == EFFECT_TOUCH) + if(interval > 0) + //apply the touch effect to the holder + if(holder) + holder << "the \icon[src] [src] held by [holder] shudders in your grasp." + else + src.loc.visible_message("the \icon[src] [src] shudders.") + inserted_battery.battery_effect.DoEffectTouch(holder) - //handle timed mode - if(timing) - time -= 1 - if(time <= 0) - shutdown_emission() + //consume power + inserted_battery.stored_charge -= energy_consumed_on_touch + else + //consume power equal to time passed + inserted_battery.stored_charge -= world.time - last_process + + else if(inserted_battery.battery_effect.effect == EFFECT_PULSE) + inserted_battery.battery_effect.chargelevel = inserted_battery.battery_effect.chargelevelmax + + //consume power relative to the time the artifact takes to charge and the effect range + inserted_battery.stored_charge -= inserted_battery.battery_effect.effectrange * inserted_battery.battery_effect.effectrange * inserted_battery.battery_effect.chargelevelmax + + else + //consume power equal to time passed + inserted_battery.stored_charge -= world.time - last_process + + last_activation = world.time + + //process the effect + inserted_battery.battery_effect.process() + + //work out if we need to shutdown + if(inserted_battery.stored_charge <= 0) + src.loc.visible_message("\blue \icon[src] [src] buzzes.", "\blue \icon[src] You hear something buzz.") + shutdown_emission() + else if(world.time > time_end) + src.loc.visible_message("\blue \icon[src] [src] chimes.", "\blue \icon[src] You hear something chime.") + shutdown_emission() else - shutdown() + src.visible_message("\blue \icon[src] [src] buzzes.", "\blue \icon[src] You hear something buzz.") + shutdown_emission() + last_process = world.time /obj/item/weapon/anodevice/proc/shutdown_emission() if(activated) activated = 0 - timing = 0 - src.visible_message("\blue \icon[src] [src] buzzes.", "\icon[src]\blue You hear something buzz.") - - cooldown = archived_time / 2 - if(inserted_battery.battery_effect.activated) inserted_battery.battery_effect.ToggleActivate(1) /obj/item/weapon/anodevice/Topic(href, href_list) - if(href_list["neg_changetime_max"]) - time += -100 - if(time > inserted_battery.capacity) - time = inserted_battery.capacity - else if (time < 0) - time = 0 - if(href_list["neg_changetime"]) - time += -10 - if(time > inserted_battery.capacity) - time = inserted_battery.capacity - else if (time < 0) - time = 0 if(href_list["changetime"]) - time += 10 - if(time > inserted_battery.capacity) - time = inserted_battery.capacity - else if (time < 0) - time = 0 - if(href_list["changetime_max"]) - time += 100 - if(time > inserted_battery.capacity) - time = inserted_battery.capacity - else if (time < 0) - time = 0 + var/timedif = text2num(href_list["changetime"]) + if(href_list["duration"]) + duration += timedif + //max 30 sec duration + duration = min(max(duration, 0), 300) + if(activated) + time_end += timedif + else if(href_list["interval"]) + interval += timedif + //max 10 sec interval + interval = min(max(interval, 0), 100) if(href_list["startup"]) activated = 1 + src.visible_message("\blue \icon[src] [src] whirrs.", "\icon[src]\blue You hear something whirr.") if(!inserted_battery.battery_effect.activated) inserted_battery.battery_effect.ToggleActivate(1) + time_end = world.time + duration if(href_list["shutdown"]) activated = 0 - if(href_list["starttimer"]) - timing = 1 - archived_time = time if(href_list["ejectbattery"]) shutdown_emission() inserted_battery.loc = get_turf(src) @@ -178,10 +173,10 @@ UpdateSprite() if(href_list["close"]) usr << browse(null, "window=anodevice") - usr.unset_machine(src) - + else if(ismob(src.loc)) + var/mob/M = src.loc + src.interact(M) ..() - updateDialog() /obj/item/weapon/anodevice/proc/UpdateSprite() if(!inserted_battery) @@ -194,3 +189,23 @@ /obj/item/weapon/anodevice/Del() processing_objects.Remove(src) ..() + +/obj/item/weapon/anodevice/attack(mob/living/M as mob, mob/living/user as mob, def_zone) + if (!istype(M)) + return + + if(activated && inserted_battery.battery_effect.effect == EFFECT_TOUCH && !isnull(inserted_battery)) + inserted_battery.battery_effect.DoEffectTouch(M) + inserted_battery.stored_charge -= energy_consumed_on_touch + user.visible_message("\blue [user] taps [M] with [src], and it shudders on contact.") + else + user.visible_message("\blue [user] taps [M] with [src], but nothing happens.") + + //admin logging + user.lastattacked = M + M.lastattacker = user + + if(inserted_battery.battery_effect) + user.attack_log += "\[[time_stamp()]\] Tapped [M.name] ([M.ckey]) with [name] (EFFECT: [inserted_battery.battery_effect.effecttype])" + M.attack_log += "\[[time_stamp()]\] Tapped by [user.name] ([user.ckey]) with [name] (EFFECT: [inserted_battery.battery_effect.effecttype])" + msg_admin_attack("[key_name(user)] tapped [key_name(M)] with [name] (EFFECT: [inserted_battery.battery_effect.effecttype])" ) diff --git a/code/modules/research/xenoarchaeology/tools/tools.dm b/code/modules/research/xenoarchaeology/tools/tools.dm index 889e833259..479d0240fa 100644 --- a/code/modules/research/xenoarchaeology/tools/tools.dm +++ b/code/modules/research/xenoarchaeology/tools/tools.dm @@ -22,3 +22,15 @@ w_class = 2 //todo: dig site tape + +/obj/item/weapon/storage/bag/fossils + name = "Fossil Satchel" + desc = "Transports delicate fossils in suspension so they don't break during transit." + icon = 'icons/obj/mining.dmi' + icon_state = "satchel" + slot_flags = SLOT_BELT | SLOT_POCKET + w_class = 3 + storage_slots = 50 + max_combined_w_class = 200 //Doesn't matter what this is, so long as it's more or equal to storage_slots * ore.w_class + max_w_class = 3 + can_hold = list("/obj/item/weapon/fossil") diff --git a/html/changelog.html b/html/changelog.html index 8a248d22e8..334cb8e6ae 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -122,6 +122,18 @@ should be listed in the changelog upon commit though. Thanks. --> +
+

20 June 2014

+

Cael_Aislinn updated:

+
    +
  • New discoverable items added to xenoarchaeology, and new features for some existing ones. Artifact harvesters can now harvest the secondary effect of artifacts as well as the primary one.
    +
  • +
  • Artifact utilisers should be much nicer/easier to use now.
    +
  • Alden-Saraspova counters and talking items should work properly now.
    +
  • +
+
+

3 Juni 2014

Hubblenaut updated:

@@ -171,6 +183,19 @@ should be listed in the changelog upon commit though. Thanks. -->
+ +
+

3 May 2014

+

Cael_Aislinn updated:

+
    +
  • Coming out of nowhere the past few months, the Garland Corporation has made headlines with a new prehistoric theme park delighting travellers with species thought extinct. Now available for research stations everywhere is the technology that made it all possible! Features include:
    + - 13 discoverable prehistoric species to clone from fossils (including 5 brand new ones).
    + - 11 discoverable prehistoric plants to clone from fossils (including 9 brand new ones).
    + - New minigame that involves correctly ordering the genomes inside each genetic sequence to unlock an animal/plant.
    + - Some prehistoric animals and plants may seem strangely familiar... while others may bring more than the erstwhile scientist bargains for.
    +
  • +
+
diff --git a/icons/obj/hydroponics.dmi b/icons/obj/hydroponics.dmi index 2db5f8a1f1..5459ad4cb2 100644 Binary files a/icons/obj/hydroponics.dmi and b/icons/obj/hydroponics.dmi differ diff --git a/icons/obj/xenoarchaeology.dmi b/icons/obj/xenoarchaeology.dmi index 144dfaf1e1..b40ae3db6e 100644 Binary files a/icons/obj/xenoarchaeology.dmi and b/icons/obj/xenoarchaeology.dmi differ