diff --git a/baystation12.dme b/baystation12.dme index 0de6d131ab..f64655d5a0 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1250,6 +1250,7 @@ #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" 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/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_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/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)