Merge remote-tracking branch 'skrat/master' into mergeupstream

This commit is contained in:
nevimer
2023-09-27 14:20:03 -04:00
112 changed files with 2127 additions and 1605 deletions
@@ -4,7 +4,7 @@
/area/template_noop)
"b" = (
/turf/closed/mineral/strong,
/area/template_noop)
/area/lavaland/surface/outdoors)
(1,1,1) = {"
a
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+4
View File
@@ -4,3 +4,7 @@
#define TTS_SOUND_ENABLED "Enabled"
///TTS preference is set to only play blips of a sound, rather than speech.
#define TTS_SOUND_BLIPS "Blips Only"
///TTS filter to activate start/stop radio clicks on speech.
#define TTS_FILTER_RADIO "radio"
///TTS filter to activate a silicon effect on speech.
#define TTS_FILTER_SILICON "silicon"
@@ -9,7 +9,7 @@
return returnable_list
/// Sets all of the job datum configurable values to what they've been set to in the config file, jobconfig.toml.
/datum/controller/subsystem/job/proc/load_jobs_from_config()
/datum/controller/subsystem/job/proc/load_jobs_from_config(silent = FALSE)
if(!length(job_config_datum_singletons))
stack_trace("SSjob tried to load jobs from config, but the config singletons were not initialized! Likely tried to load jobs before SSjob was initialized.")
return
@@ -25,7 +25,8 @@
var/job_key = occupation.config_tag
if(!job_config[job_key]) // Job isn't listed, skip it.
// List both job_title and job_key in case they de-sync over time.
message_admins(span_notice("[occupation.title] (with config key [job_key]) is missing from jobconfig.toml! Using codebase defaults."))
if(!silent)
message_admins(span_notice("[occupation.title] (with config key [job_key]) is missing from jobconfig.toml! Using codebase defaults."))
continue
for(var/config_datum_key in job_config_datum_singletons)
+4 -2
View File
@@ -305,8 +305,10 @@ SUBSYSTEM_DEF(job)
player.mind.special_role = null
SetupOccupations()
unassigned = list()
if(overflow_role)
set_overflow_role(overflow_role)
if(CONFIG_GET(flag/load_jobs_from_txt))
// Any errors with the configs has already been said, we don't need to repeat them here.
load_jobs_from_config(silent = TRUE)
set_overflow_role(overflow_role)
return
+1 -1
View File
@@ -135,7 +135,7 @@ SUBSYSTEM_DEF(radiation)
for (var/obj/item/bodypart/limb as anything in human.bodyparts)
var/protected = FALSE
for (var/obj/item/clothing as anything in human.clothingonpart(limb))
for (var/obj/item/clothing as anything in human.get_clothing_on_part(limb))
if (HAS_TRAIT(clothing, TRAIT_RADIATION_PROTECTED_CLOTHING))
protected = TRUE
break
+5 -7
View File
@@ -263,7 +263,7 @@ SUBSYSTEM_DEF(tts)
#undef TTS_ARBRITRARY_DELAY
/datum/controller/subsystem/tts/proc/queue_tts_message(datum/target, message, datum/language/language, speaker, filter, list/listeners, local = FALSE, message_range = 7, volume_offset = 0, pitch = 0, silicon = "")
/datum/controller/subsystem/tts/proc/queue_tts_message(datum/target, message, datum/language/language, speaker, filter, list/listeners, local = FALSE, message_range = 7, volume_offset = 0, pitch = 0, special_filters = "")
if(!tts_enabled)
return
@@ -279,7 +279,7 @@ SUBSYSTEM_DEF(tts)
var/shell_scrubbed_input = tts_speech_filter(message)
shell_scrubbed_input = copytext(shell_scrubbed_input, 1, 300)
var/identifier = "[sha1(speaker + filter + num2text(pitch) + num2text(silicon) + shell_scrubbed_input)].[world.time]"
var/identifier = "[sha1(speaker + filter + num2text(pitch) + special_filters + shell_scrubbed_input)].[world.time]"
if(!(speaker in available_speakers))
return
@@ -290,9 +290,9 @@ SUBSYSTEM_DEF(tts)
var/datum/http_request/request_blips = new()
var/file_name = "tmp/tts/[identifier].ogg"
var/file_name_blips = "tmp/tts/[identifier]_blips.ogg"
request.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts?voice=[speaker]&identifier=[identifier]&filter=[url_encode(filter)]&pitch=[pitch]&silicon=[silicon]", json_encode(list("text" = shell_scrubbed_input)), headers, file_name)
request_blips.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts-blips?voice=[speaker]&identifier=[identifier]&filter=[url_encode(filter)]&pitch=[pitch]&silicon=[silicon]", json_encode(list("text" = shell_scrubbed_input)), headers, file_name_blips)
var/datum/tts_request/current_request = new /datum/tts_request(identifier, request, request_blips, shell_scrubbed_input, target, local, language, message_range, volume_offset, listeners, pitch, silicon)
request.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts?voice=[speaker]&identifier=[identifier]&filter=[url_encode(filter)]&pitch=[pitch]&special_filters=[url_encode(special_filters)]", json_encode(list("text" = shell_scrubbed_input)), headers, file_name)
request_blips.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts-blips?voice=[speaker]&identifier=[identifier]&filter=[url_encode(filter)]&pitch=[pitch]&special_filters=[url_encode(special_filters)]", json_encode(list("text" = shell_scrubbed_input)), headers, file_name_blips)
var/datum/tts_request/current_request = new /datum/tts_request(identifier, request, request_blips, shell_scrubbed_input, target, local, language, message_range, volume_offset, listeners, pitch)
var/list/player_queued_tts_messages = queued_tts_messages[target]
if(!player_queued_tts_messages)
player_queued_tts_messages = list()
@@ -344,8 +344,6 @@ SUBSYSTEM_DEF(tts)
var/use_blips = FALSE
/// What's the pitch adjustment?
var/pitch = 0
/// Are we using the silicon vocal effect on this?
var/silicon = ""
/datum/tts_request/New(identifier, datum/http_request/request, datum/http_request/request_blips, message, target, local, datum/language/language, message_range, volume_offset, list/listeners, pitch)
@@ -51,6 +51,8 @@
required_distance = 3
/// range we will try chasing the target before giving up
var/chase_range = 9
///do we care about avoiding friendly fire?
var/avoid_friendly_fire = FALSE
/datum/ai_behavior/basic_ranged_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
. = ..()
@@ -75,6 +77,10 @@
if(!can_see(basic_mob, final_target, required_distance))
return
if(avoid_friendly_fire && check_friendly_in_path(basic_mob, target, targetting_datum))
adjust_position(basic_mob, target)
return ..()
controller.set_blackboard_key(hiding_location_key, hiding_target)
basic_mob.RangedAttack(final_target)
return ..() //only start the cooldown when the shot is shot
@@ -83,3 +89,52 @@
. = ..()
if(!succeeded)
controller.clear_blackboard_key(target_key)
/datum/ai_behavior/basic_ranged_attack/proc/check_friendly_in_path(mob/living/source, atom/target, datum/targetting_datum/targetting_datum)
var/list/turfs_list = calculate_trajectory(source, target)
for(var/turf/possible_turf as anything in turfs_list)
for(var/mob/living/potential_friend in possible_turf)
if(!targetting_datum.can_attack(source, potential_friend))
return TRUE
return FALSE
/datum/ai_behavior/basic_ranged_attack/proc/adjust_position(mob/living/living_pawn, atom/target)
var/turf/our_turf = get_turf(living_pawn)
var/list/possible_turfs = list()
for(var/direction in GLOB.alldirs)
var/turf/target_turf = get_step(our_turf, direction)
if(isnull(target_turf))
continue
if(target_turf.is_blocked_turf() || get_dist(target_turf, target) > get_dist(living_pawn, target))
continue
possible_turfs += target_turf
if(!length(possible_turfs))
return
var/turf/picked_turf = get_closest_atom(/turf, possible_turfs, target)
step(living_pawn, get_dir(living_pawn, picked_turf))
/datum/ai_behavior/basic_ranged_attack/proc/calculate_trajectory(mob/living/source , atom/target)
var/list/turf_list = get_line(source, target)
var/list_length = length(turf_list) - 1
for(var/i in 1 to list_length)
var/turf/current_turf = turf_list[i]
var/turf/next_turf = turf_list[i+1]
var/direction_to_turf = get_dir(current_turf, next_turf)
if(!ISDIAGONALDIR(direction_to_turf))
continue
for(var/cardinal_direction in GLOB.cardinals)
if(cardinal_direction & direction_to_turf)
turf_list += get_step(current_turf, cardinal_direction)
turf_list -= get_turf(source)
turf_list -= get_turf(target)
return turf_list
/datum/ai_behavior/basic_ranged_attack/avoid_friendly_fire
avoid_friendly_fire = TRUE
@@ -31,15 +31,19 @@
var/random_number_in_range = rand(1, total_choices_length)
// Sound that plays when the mob does something audible
var/sound_to_play = length(sound) > 0 ? pick(sound) : null
if(random_number_in_range <= audible_emotes_length)
controller.queue_behavior(/datum/ai_behavior/perform_emote, pick(emote_hear))
controller.queue_behavior(/datum/ai_behavior/perform_emote, pick(emote_hear), sound_to_play)
else if(random_number_in_range <= (audible_emotes_length + non_audible_emotes_length))
controller.queue_behavior(/datum/ai_behavior/perform_emote, pick(emote_see))
else
controller.queue_behavior(/datum/ai_behavior/perform_speech, pick(speak), length(sound) > 0 ? pick(sound) : null)
controller.queue_behavior(/datum/ai_behavior/perform_speech, pick(speak), sound_to_play)
/datum/ai_planning_subtree/random_speech/insect
speech_chance = 5
sound = list('sound/creatures/chitter.ogg')
emote_hear = list("chitters.")
/datum/ai_planning_subtree/random_speech/mothroach
@@ -49,6 +53,7 @@
/datum/ai_planning_subtree/random_speech/mouse
speech_chance = 1
speak = list("Squeak!", "SQUEAK!", "Squeak?")
sound = list('sound/creatures/mousesqueek.ogg')
emote_hear = list("squeaks.")
emote_see = list("runs in a circle.", "shakes.")
@@ -93,12 +98,14 @@
/datum/ai_planning_subtree/random_speech/chicken
speech_chance = 15 // really talkative ladies
speak = list("Cluck!", "BWAAAAARK BWAK BWAK BWAK!", "Bwaak bwak.")
sound = list('sound/creatures/clucks.ogg', 'sound/creatures/bagawk.ogg')
emote_hear = list("clucks.", "croons.")
emote_see = list("pecks at the ground.","flaps her wings viciously.")
/datum/ai_planning_subtree/random_speech/chick
speech_chance = 4
speak = list("Cherp.", "Cherp?", "Chirrup.", "Cheep!")
sound = list('sound/creatures/chick_peep.ogg')
emote_hear = list("cheeps.")
emote_see = list("pecks at the ground.","flaps her tiny wings.")
@@ -160,33 +167,37 @@
/datum/ai_planning_subtree/random_speech/pony
speech_chance = 3
sound = list('sound/creatures/pony/whinny01.ogg', 'sound/creatures/pony/whinny02.ogg', 'sound/creatures/pony/whinny03.ogg')
emote_hear = list("whinnies!")
emote_see = list("horses around.")
/datum/ai_planning_subtree/random_speech/pony/tamed
speech_chance = 3
sound = list('sound/creatures/pony/snort.ogg')
emote_hear = list("snorts.")
emote_see = list("snorts.")
/datum/ai_planning_subtree/random_speech/killer_tomato
speech_chance = 3
speak = list("gnashes.", "growls lowly.", "snarls.")
emote_hear = list("gnashes.")
emote_hear = list("gnashes.", "growls lowly.", "snarls.")
emote_see = list("salivates.")
/datum/ai_planning_subtree/random_speech/ant
speech_chance = 1
speak = list("BZZZZT!", "CHTCHTCHT!", "Bzzz", "ChtChtCht")
sound = list('sound/creatures/chitter.ogg')
emote_hear = list("buzzes.", "clacks.")
emote_see = list("shakes their head.", "twitches their antennae.")
speak = list("BZZZZT!", "CHTCHTCHT!", "Bzzz", "ChtChtCht")
/datum/ai_planning_subtree/random_speech/fox
speech_chance = 1
speak = list("Ack-Ack", "Ack-Ack-Ack-Ackawoooo", "Geckers", "Awoo", "Tchoff")
emote_hear = list("howls.", "barks.", "screams.")
emote_see = list("shakes their head.", "shivers.")
speak = list("Ack-Ack", "Ack-Ack-Ack-Ackawoooo", "Geckers", "Awoo", "Tchoff")
/datum/ai_planning_subtree/random_speech/crab
speech_chance = 1
sound = list('sound/creatures/claw_click.ogg')
emote_hear = list("clicks.")
emote_see = list("clacks.")
+3 -1
View File
@@ -287,11 +287,13 @@
/datum/ai_behavior/perform_emote
/datum/ai_behavior/perform_emote/perform(seconds_per_tick, datum/ai_controller/controller, emote)
/datum/ai_behavior/perform_emote/perform(seconds_per_tick, datum/ai_controller/controller, emote, speech_sound)
var/mob/living/living_pawn = controller.pawn
if(!istype(living_pawn))
return
living_pawn.manual_emote(emote)
if(speech_sound) // Only audible emotes will pass in a sound
playsound(living_pawn, speech_sound, 80, vary = TRUE)
finish_action(controller, TRUE)
/datum/ai_behavior/perform_speech
+3
View File
@@ -52,6 +52,9 @@
ASSERT_GAS_IN_LIST(gastype, gaslist)
gaslist[gastype][MOLES] += amount
// Ensure that minimum_pressure is actually a hard lower limit
target_pressure = clamp(target_pressure, minimum_pressure + (gaslist[gastype][MOLES] * 0.1), maximum_pressure)
// That last one put us over the limit, remove some of it
while(gasmix.return_pressure() > target_pressure)
gaslist[gastype][MOLES] -= gaslist[gastype][MOLES] * 0.1
+1 -2
View File
@@ -78,8 +78,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
QDEL_NULL(sizzle)
if(particle_effect)
QDEL_NULL(particle_effect)
if(process_effect)
process_effect = null
process_effect = null
return ..()
/datum/component/acid/RegisterWithParent()
+12 -10
View File
@@ -116,8 +116,8 @@
var/start_time = REALTIMEOFDAY
for(var/turf/turf as anything in turfs)
if(!(turf.type in open_turf_types)) //only put stuff on open turfs we generated, so closed walls and rivers and stuff are skipped
for(var/turf/target_turf as anything in turfs)
if(!(target_turf.type in open_turf_types)) //only put stuff on open turfs we generated, so closed walls and rivers and stuff are skipped
continue
// If we've spawned something yet
@@ -127,22 +127,24 @@
//FLORA SPAWNING HERE
if(flora_allowed && prob(flora_spawn_chance))
var/flora_type = pick(flora_spawn_list)
new flora_type(turf)
new flora_type(target_turf)
spawned_something = TRUE
//FEATURE SPAWNING HERE
if(feature_allowed && prob(feature_spawn_chance))
//we may have generated something from the flora list on the target turf, so let's not place
//a feature here if that's the case (because it would look stupid)
if(feature_allowed && !spawned_something && prob(feature_spawn_chance))
var/can_spawn = TRUE
var/atom/picked_feature = pick(feature_spawn_list)
for(var/obj/structure/existing_feature in range(7, turf))
for(var/obj/structure/existing_feature in range(7, target_turf))
if(istype(existing_feature, picked_feature))
can_spawn = FALSE
break
if(can_spawn)
new picked_feature(turf)
new picked_feature(target_turf)
spawned_something = TRUE
//MOB SPAWNING HERE
@@ -161,12 +163,12 @@
// prevents tendrils spawning in each other's collapse range
if(ispath(picked_mob, /obj/structure/spawner/lavaland))
for(var/obj/structure/spawner/lavaland/spawn_blocker in range(2, turf))
for(var/obj/structure/spawner/lavaland/spawn_blocker in range(2, target_turf))
can_spawn = FALSE
break
// if the random is not a tendril (hopefully meaning it is a mob), avoid spawning if there's another one within 12 tiles
else
var/list/things_in_range = range(12, turf)
var/list/things_in_range = range(12, target_turf)
for(var/mob/living/mob_blocker in things_in_range)
if(ismining(mob_blocker))
can_spawn = FALSE
@@ -176,7 +178,7 @@
can_spawn = can_spawn && !(locate(/obj/effect/spawner/random/lavaland_mob) in things_in_range)
//if there's a megafauna within standard view don't spawn anything at all (This isn't really consistent, I don't know why we do this. you do you tho)
if(can_spawn)
for(var/mob/living/simple_animal/hostile/megafauna/found_fauna in range(7, turf))
for(var/mob/living/simple_animal/hostile/megafauna/found_fauna in range(7, target_turf))
can_spawn = FALSE
break
@@ -185,7 +187,7 @@
weighted_megafauna_spawn_list.Remove(picked_mob)
megafauna_spawn_list = expand_weights(weighted_megafauna_spawn_list)
megas_allowed = megas_allowed && length(megafauna_spawn_list)
new picked_mob(turf)
new picked_mob(target_turf)
spawned_something = TRUE
CHECK_TICK
+3
View File
@@ -24,6 +24,8 @@
var/species
/// The character's ID trim
var/trim
/// The character's voice, if they have one.
var/voice
/datum/record/New(
age = 18,
@@ -37,6 +39,7 @@
rank = "Unassigned",
species = "Human",
trim = "Unassigned",
voice = "?????",
)
src.age = age
src.blood_type = blood_type
+1 -1
View File
@@ -181,7 +181,7 @@
if((human_victim.wear_mask && (human_victim.wear_mask.flags_inv & HIDEFACE)) || (human_victim.head && (human_victim.head.flags_inv & HIDEFACE)))
return FALSE
else if(limb.scars_covered_by_clothes)
var/num_covers = LAZYLEN(human_victim.clothingonpart(limb))
var/num_covers = LAZYLEN(human_victim.get_clothing_on_part(limb))
if(num_covers + get_dist(viewer, victim) >= visibility)
return FALSE
+2 -2
View File
@@ -469,8 +469,8 @@ GLOBAL_LIST_EMPTY(dynamic_station_traits)
for(var/job in job_prefs)
var/priority = job_prefs[job]
job_data += "[job]: [SSjob.job_priority_level_to_string(priority)]"
to_chat(player, span_danger("You were unable to qualify for any roundstart antagonist role because you could not qualify for any of the roundstart jobs you were trying to qualify for, along with 'return to lobby if job is unavailable' enabled."))
log_admin("[player.ckey] failed to qualify for any job and has [player.client.prefs.be_special.len] antag preferences enabled. They will be unable to qualify for any roundstart antagonist role. These are their job preferences - [job_data.Join(" | ")]")
to_chat(player, span_danger("You were unable to qualify for any roundstart antagonist role this round because your job preferences presented a high chance of all of your selected jobs being unavailable, along with 'return to lobby if job is unavailable' enabled. Increase the number of roles set to medium or low priority to reduce the chances of this happening."))
log_admin("[player.ckey] failed to qualify for any roundstart antagonist role because their job preferences presented a high chance of all of their selected jobs being unavailable, along with 'return to lobby if job is unavailable' enabled and has [player.client.prefs.be_special.len] antag preferences enabled. They will be unable to qualify for any roundstart antagonist role. These are their job preferences - [job_data.Join(" | ")]")
else
roundstart_pop_ready++
candidates.Add(player)
@@ -133,7 +133,7 @@
. = ..()
if(prob(5))
owner.emote("squeaks")
playsound(owner, 'sound/effects/mousesqueek.ogg', 100)
playsound(owner, 'sound/creatures/mousesqueek.ogg', 100)
#undef RAT_ORGAN_COLOR
#undef RAT_SCLERA_COLOR
@@ -509,46 +509,12 @@
icon_state = "duffel-medical"
inhand_icon_state = "duffel-med"
/obj/item/storage/backpack/duffelbag/med/surgery
name = "surgical duffel bag"
desc = "A large duffel bag for holding extra medical supplies - this one seems to be designed for holding surgical tools."
/obj/item/storage/backpack/duffelbag/med/surgery/PopulateContents()
new /obj/item/scalpel(src)
new /obj/item/hemostat(src)
new /obj/item/retractor(src)
new /obj/item/circular_saw(src)
new /obj/item/surgicaldrill(src)
new /obj/item/cautery(src)
new /obj/item/bonesetter(src)
new /obj/item/surgical_drapes(src)
new /obj/item/clothing/suit/toggle/labcoat/skyrat/hospitalgown(src) //SKYRAT EDIT ADDITION
new /obj/item/clothing/mask/surgical(src)
new /obj/item/razor(src)
new /obj/item/blood_filter(src)
/obj/item/storage/backpack/duffelbag/coroner
name = "coroner duffel bag"
desc = "A large duffel bag for holding large amounts of organs at once."
icon_state = "duffel-coroner"
inhand_icon_state = "duffel-coroner"
/obj/item/storage/backpack/duffelbag/coroner/surgery
name = "surgical coroner bag"
desc = "A large duffel bag for holding extra medical supplies - this one seems to be designed for holding morbid surgical tools."
/obj/item/storage/backpack/duffelbag/coroner/surgery/PopulateContents()
new /obj/item/scalpel/cruel(src)
new /obj/item/hemostat/cruel(src)
new /obj/item/retractor/cruel(src)
new /obj/item/circular_saw(src)
new /obj/item/surgicaldrill(src)
new /obj/item/cautery/cruel(src)
new /obj/item/bonesetter(src)
new /obj/item/surgical_drapes(src)
new /obj/item/razor(src)
new /obj/item/blood_filter(src)
/obj/item/storage/backpack/duffelbag/explorer
name = "explorer duffel bag"
desc = "A large duffel bag for holding extra exotic treasures."
+14 -11
View File
@@ -11,6 +11,7 @@
/obj/item/cautery,
/obj/item/circular_saw,
/obj/item/clothing/mask/surgical,
/obj/item/clothing/suit/toggle/labcoat/skyrat/hospitalgown, // SKYRAT EDIT ADDITION
/obj/item/hemostat,
/obj/item/razor,
/obj/item/reagent_containers/medigel,
@@ -193,6 +194,7 @@
new /obj/item/cautery(src)
new /obj/item/circular_saw(src)
new /obj/item/clothing/mask/surgical(src)
new /obj/item/clothing/suit/toggle/labcoat/skyrat/hospitalgown(src) // SKYRAT EDIT ADDITION
new /obj/item/hemostat(src)
new /obj/item/razor/surgery(src)
new /obj/item/retractor(src)
@@ -207,13 +209,14 @@
name = "autopsy tray"
desc = "A Deforest brand surgery tray, made for use in morgues. It is a folding model, \
meaning the wheels on the bottom can be extended outwards, making it a cart."
/obj/item/surgery_tray/full/morgue/populate_contents()
new /obj/item/blood_filter(src)
new /obj/item/bonesetter(src)
new /obj/item/cautery/cruel(src)
new /obj/item/circular_saw(src)
new /obj/item/clothing/mask/surgical(src)
new /obj/item/clothing/suit/toggle/labcoat/skyrat/hospitalgown(src) // SKYRAT EDIT ADDITION
new /obj/item/hemostat/cruel(src)
new /obj/item/razor/surgery(src)
new /obj/item/retractor/cruel(src)
@@ -227,13 +230,13 @@
/obj/item/surgery_tray/full/advanced
/obj/item/surgery_tray/full/advanced/populate_contents()
new /obj/item/scalpel/advanced
new /obj/item/retractor/advanced
new /obj/item/cautery/advanced
new /obj/item/surgical_drapes
new /obj/item/reagent_containers/medigel/sterilizine
new /obj/item/bonesetter
new /obj/item/blood_filter
new /obj/item/stack/medical/bone_gel
new /obj/item/stack/sticky_tape/surgical
new /obj/item/clothing/mask/surgical
new /obj/item/scalpel/advanced(src)
new /obj/item/retractor/advanced(src)
new /obj/item/cautery/advanced(src)
new /obj/item/surgical_drapes(src)
new /obj/item/reagent_containers/medigel/sterilizine(src)
new /obj/item/bonesetter(src)
new /obj/item/blood_filter(src)
new /obj/item/stack/medical/bone_gel(src)
new /obj/item/stack/sticky_tape/surgical(src)
new /obj/item/clothing/mask/surgical(src)
+1 -1
View File
@@ -108,7 +108,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
filter += tts_filter.Join(",")
if(voice && found_client)
INVOKE_ASYNC(SStts, TYPE_PROC_REF(/datum/controller/subsystem/tts, queue_tts_message), src, html_decode(tts_message_to_use), message_language, voice, filter.Join(","), listened, message_range = range, pitch = pitch, silicon = tts_silicon_voice_effect)
INVOKE_ASYNC(SStts, TYPE_PROC_REF(/datum/controller/subsystem/tts, queue_tts_message), src, html_decode(tts_message_to_use), message_language, voice, filter.Join(","), listened, message_range = range, pitch = pitch)
/atom/movable/proc/compose_message(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), visible_name = FALSE)
//This proc uses [] because it is faster than continually appending strings. Thanks BYOND.
@@ -92,6 +92,7 @@
return
datum_container.last_find_references = search_time
var/container_print = datum_container.ref_search_details()
var/list/vars_list = datum_container.vars
for(var/varname in vars_list)
@@ -108,11 +109,11 @@
found_refs[varname] = TRUE
continue //End early, don't want these logging
#endif
log_reftracker("Found [type] [text_ref(src)] in [datum_container.type]'s [text_ref(datum_container)] [varname] var. [container_name]")
log_reftracker("Found [type] [text_ref(src)] in [datum_container.type]'s [container_print] [varname] var. [container_name]")
continue
if(islist(variable))
DoSearchVar(variable, "[container_name] [text_ref(datum_container)] -> [varname] (list)", recursive_limit - 1, search_time)
DoSearchVar(variable, "[container_name] [container_print] -> [varname] (list)", recursive_limit - 1, search_time)
else if(islist(potential_container))
var/normal = IS_NORMAL_LIST(potential_container)
@@ -159,3 +160,13 @@
qdel(src, force)
#endif
// Kept outside the ifdef so overrides are easy to implement
/// Return info about us for reference searching purposes
/// Will be logged as a representation of this datum if it's a part of a search chain
/datum/proc/ref_search_details()
return text_ref(src)
/datum/callback/ref_search_details()
return "[text_ref(src)] (obj: [object] proc: [delegate] args: [json_encode(arguments)] user: [user?.resolve() || "null"])"
@@ -9,7 +9,6 @@
#define MALF_AI_ROLL_COOLDOWN 1 SECONDS + MALF_AI_ROLL_TIME
#define MALF_AI_ROLL_DAMAGE 75
#define MALF_AI_ROLL_CRIT_CHANCE 5 //percent
#define MALF_AI_ROLL_MAX_DISTANCE 1 //anything further away than this, and the roll will fail
GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/obj/machinery/field/containment,
@@ -1138,6 +1137,11 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
enable_text = span_notice("Your inner servos shift as you prepare to roll around. Click adjacent tiles to roll onto them!")
disable_text = span_notice("You disengage your rolling protocols.")
/// How long does it take for us to roll?
var/roll_over_time = MALF_AI_ROLL_TIME
/// On top of [roll_over_time], how long does it take for the ability to cooldown?
var/roll_over_cooldown = MALF_AI_ROLL_COOLDOWN
/datum/action/innate/ai/ranged/core_tilt/New()
. = ..()
desc = "[desc] It has [uses] use\s remaining."
@@ -1152,7 +1156,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
return FALSE
var/mob/living/silicon/ai/ai_caller = caller
if (ai_caller.incapacitated())
if (ai_caller.incapacitated() || !isturf(ai_caller.loc))
return FALSE
var/turf/target = get_turf(clicked_on)
@@ -1163,30 +1167,32 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
target.balloon_alert(ai_caller, "can't roll on yourself!")
return FALSE
if (get_dist(ai_caller, target) > MALF_AI_ROLL_MAX_DISTANCE)
target.balloon_alert(ai_caller, "too far!")
return FALSE
var/picked_dir = get_dir(ai_caller, target)
if (!picked_dir)
return FALSE
var/turf/temp_target = get_step(ai_caller, picked_dir) // we can move during the timer so we cant just pass the ref
new /obj/effect/temp_visual/telegraphing/vending_machine_tilt(target, MALF_AI_ROLL_TIME)
new /obj/effect/temp_visual/telegraphing/vending_machine_tilt(temp_target, roll_over_time)
ai_caller.balloon_alert_to_viewers("rolling...")
addtimer(CALLBACK(src, PROC_REF(do_roll_over), ai_caller, picked_dir), MALF_AI_ROLL_TIME)
addtimer(CALLBACK(src, PROC_REF(do_roll_over), ai_caller, picked_dir), roll_over_time)
adjust_uses(-1)
if(uses)
desc = "[initial(desc)] It has [uses] use\s remaining."
build_all_button_icons()
COOLDOWN_START(src, time_til_next_tilt, MALF_AI_ROLL_COOLDOWN)
COOLDOWN_START(src, time_til_next_tilt, roll_over_cooldown)
/datum/action/innate/ai/ranged/core_tilt/proc/do_roll_over(mob/living/silicon/ai/ai_caller, picked_dir)
if (ai_caller.incapacitated() || !isturf(ai_caller.loc)) // prevents bugs where the ai is carded and rolls
return
var/turf/target = get_step(ai_caller, picked_dir) // in case we moved we pass the dir not the target turf
if (isnull(target))
return
var/paralyze_time = clamp(6 SECONDS, 0 SECONDS, (MALF_AI_ROLL_COOLDOWN * 0.9)) //the clamp prevents stunlocking as the max is always a little less than the cooldown between rolls
var/paralyze_time = clamp(6 SECONDS, 0 SECONDS, (roll_over_cooldown * 0.9)) //the clamp prevents stunlocking as the max is always a little less than the cooldown between rolls
return ai_caller.fall_and_crush(target, MALF_AI_ROLL_DAMAGE, MALF_AI_ROLL_CRIT_CHANCE, null, paralyze_time, picked_dir, rotation = get_rotation_from_dir(picked_dir))
@@ -1321,4 +1327,3 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
#undef MALF_AI_ROLL_TIME
#undef MALF_AI_ROLL_DAMAGE
#undef MALF_AI_ROLL_CRIT_CHANCE
#undef MALF_AI_ROLL_MAX_DISTANCE
+7
View File
@@ -221,6 +221,13 @@
/obj/item/clothing/under/misc/burial = 2,
)
crate_name = "religious supplies crate"
/datum/supply_pack/misc/candles_bulk
name = "Candle Box Crate"
desc = "Keep your local chapel lit with three candle boxes!"
cost = CARGO_CRATE_VALUE * 1.5
contains = list(/obj/item/storage/fancy/candle_box = 3)
crate_name = "candle box crate"
/datum/supply_pack/misc/toner
name = "Toner Crate"
+2 -2
View File
@@ -123,11 +123,11 @@
/datum/supply_pack/medical/surgery
name = "Surgical Supplies Crate"
desc = "Do you want to perform surgery, but don't have one of those fancy \
shmancy degrees? Just get started with this crate containing a medical duffelbag, \
shmancy degrees? Just get started with this crate containing a DeForest surgery tray, \
Sterilizine spray and collapsible roller bed."
cost = CARGO_CRATE_VALUE * 6
contains = list(
/obj/item/storage/backpack/duffelbag/med/surgery,
/obj/item/surgery_tray/full,
/obj/item/reagent_containers/medigel/sterilizine,
/obj/item/emergency_bed,
)
@@ -23,5 +23,5 @@
var/speaker = preferences.read_preference(/datum/preference/choiced/voice)
var/pitch = preferences.read_preference(/datum/preference/numeric/tts_voice_pitch)
COOLDOWN_START(src, tts_test_cooldown, 0.5 SECONDS)
INVOKE_ASYNC(SStts, TYPE_PROC_REF(/datum/controller/subsystem/tts, queue_tts_message), user.client, "Look at you, Player. A pathetic creature of meat and bone. How can you challenge a perfect, immortal machine?", speaker = speaker, pitch = pitch, silicon = TRUE, local = TRUE)
INVOKE_ASYNC(SStts, TYPE_PROC_REF(/datum/controller/subsystem/tts, queue_tts_message), user.client, "Look at you, Player. A pathetic creature of meat and bone. How can you challenge a perfect, immortal machine?", speaker = speaker, pitch = pitch, special_filters = TTS_FILTER_SILICON, local = TRUE)
return TRUE
+4
View File
@@ -12,6 +12,10 @@
var/adjusted_flags = null
///Did we install a filtering cloth?
var/has_filter = FALSE
/// If defined, what voice should we override with if TTS is active?
var/voice_override
/// If set to true, activates the radio effect on TTS. Used for sec hailers, but other masks can utilize it for their own vocal effect.
var/use_radio_beeps_tts = FALSE
/obj/item/clothing/mask/attack_self(mob/user)
if((clothing_flags & VOICEBOX_TOGGLABLE))
+2 -1
View File
@@ -28,7 +28,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list(
var/has_fov = TRUE
///Cigarette in the mask
var/obj/item/clothing/mask/cigarette/cig
voice_filter = "lowpass=f=750,volume=2"
/datum/armor/mask_gas
bio = 100
@@ -274,6 +274,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list(
dog_fashion = /datum/dog_fashion/head/clown
has_fov = FALSE
var/list/clownmask_designs = list()
voice_filter = null // performer masks expect to be talked through
/obj/item/clothing/mask/gas/clown_hat/plasmaman
starting_filter_type = /obj/item/gas_filter/plasmaman
+2
View File
@@ -68,6 +68,8 @@ GLOBAL_LIST_INIT(hailer_phrases, list(
var/recent_uses = 0
///Whether the hailer is emagged or not
var/safety = TRUE
voice_filter = @{"[0:a] asetrate=%SAMPLE_RATE%*0.7,aresample=16000,atempo=1/0.7,lowshelf=g=-20:f=500,highpass=f=500,aphaser=in_gain=1:out_gain=1:delay=3.0:decay=0.4:speed=0.5:type=t [out]; [out]atempo=1.2,volume=15dB [final]; anoisesrc=a=0.01:d=60 [noise]; [final][noise] amix=duration=shortest"}
use_radio_beeps_tts = TRUE
/obj/item/clothing/mask/gas/sechailer/plasmaman
starting_filter_type = /obj/item/gas_filter/plasmaman
+1
View File
@@ -104,6 +104,7 @@
laser = 20
energy = 30
bomb = 100
bio = 50
fire = 80
acid = 50
+1 -1
View File
@@ -23,7 +23,7 @@
priority_announce("Due to [cause], [plural] [name] have [movement] \
into the [location].", "Migration Alert",
'sound/effects/mousesqueek.ogg')
'sound/creatures/mousesqueek.ogg')
/datum/round_event/mice_migration/start()
SSminor_mapping.trigger_migration(rand(minimum_mice, maximum_mice))
@@ -1,6 +1,6 @@
/obj/machinery/computer/exodrone_control_console
name = "exploration drone control console"
desc = "control eploration drones from intersteller distances. Communication lag not included."
desc = "Control exploration drones from interstellar distances. Communication lag not included."
circuit = /obj/item/circuitboard/computer/exodrone_console
//Currently controlled drone
var/obj/item/exodrone/controlled_drone
@@ -1,343 +1,356 @@
{
"adventure_name": "There's a tree in the middle of space.",
"version": 1,
"starting_node": "Tree Start",
"starting_qualities": {
"Confusion": 0
},
"required_site_traits": [
"in space"
],
"loot_categories": [
"research"
],
"scan_band_mods": {
"Exotic Radiation": 10
},
"deep_scan_description": "",
"triggers": [
{
"name": "Confusion Trigger",
"target_node": "What is wrong with this tree?",
"requirements": [
{
"quality": "Confusion",
"operator": ">",
"value": 30
}
]
}
],
"nodes": [
{
"name": "Tree Start",
"description": "Camera online. Visual signs detect a fully grown, seemingly biological, and live tree located in the middle of the vacuum.\nSensors indicate it is not oxygenating, but energy is being collected via passive solar light from the nearby star.\nBaffling.",
"choices": [
{
"key": "choice 0",
"name": "Ignore site.",
"exit_node": "FAIL",
"delay": 10,
"delay_message": "Leave this for the botanists to figure out."
},
{
"key": "choice 1",
"name": "Begin sensor scan.",
"exit_node": "Biological Scan",
"delay": 10,
"delay_message": "Lets get some data."
}
],
"image": null,
"raw_image": "data:image/gif;base64,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"
},
{
"name": "Biological Scan",
"description": "You attempt to scan for clues regarding the tree's nature. It appears to be a fully mature oak tree. \n\nApproximated height is 13 ft, 6.4 inches. \n\nSubject sees no sign of an outer coating or otherwise layer protecting it from the void of space.\n\nSubject's surface temperature is 293.7 kelvin, as though it were sitting indoors.",
"choices": [
{
"key": "choice 2",
"name": "Check Sensor Integrity.",
"exit_node": "Its Not You...",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": 5
}
],
"delay": 50,
"delay_message": "This can't be right."
},
{
"key": "choice 4",
"name": "Attempt to take sample.",
"exit_node": "Sample Taken",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": 3
}
],
"delay": 40,
"delay_message": "Snip snip."
},
{
"key": "choice 6",
"name": "Examine Tree Roots.",
"exit_node": "Examine Roots",
"delay": 10
},
{
"key": "choice 9",
"name": "Sequence Sample Radiation with background noise.",
"exit_node": "Background Analysis",
"requirements": [
{
"quality": "Sample",
"operator": ">=",
"value": 1
}
],
"delay": 0,
"delay_message": "This can't be real."
}
],
"image": null,
"raw_image": "data:image/gif;base64,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"
},
{
"name": "Its Not You...",
"description": "After re-connection is established, your sensors appear fine. Tree has not moved in the slightest since last observed. Temperature has fluxuated 0.2 kelvin upwards, as expected of a plant under direct light.\nLets try again.",
"choices": [
{
"key": "choice 3",
"name": "Restart biological scan.",
"exit_node": "Biological Scan",
"delay": 25,
"delay_message": "God damnit."
}
],
"image": null,
"raw_image": "data:image/gif;base64,R0lGODdhyABkAHcAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAyABkAMIAAAAAAAD////v7+/h4eEAAAAAAAAAAAAD/xi63P4wykmrvTjrzbv/YCiOZBkJaJqaLKOubSy7b23fODxPOb7/m4FASBRofEBeT1W6JU3DYaRIjQqfkCWKg1xoddjSQEgQlM/mdDkc0Fa+8PiWLSIM7Pj73RxOlVF/ITlKNXSGDXp5iiFoaBlqfpFyk12HMgSYmZkfmppmmJ8gjXwUf2lglqmqq6ytrq+wsbKztLW2t7i5um2Ug669uyBCKMNRc4Q9qXHBJlVUFMbRV6pfR04ONszQzlZRlm7IveLaimZ7eJAESUsfyVnX2hfqv/Nv4vfZ8RWJ/Hkdn6NGtRsFyEg4VLwK6UvVqROdgMcWSpxIsaLFixgzatzIsf+jR1gIP7YbN6uaSAn4wFGbdNJFsZcpFRqS09IBt2kW3CkzWdNmNyIYpIWkw9Nevgbwat2ccNPbTnbWjtKQWfGnVZwzoQaNqVXXkDFWGx3qeoIry2CJzJ05p6aPTpRmfSXV1a/u2jM7TuldA8LXO6kXFemh5ihn3Lc9A9h1ZaqxpMNkK9rl5+EMKIGM9g5FSjJjv4aVOwEc/Q8iXx6ODSo5ualOQ9Bs0qVJTLu27du4c+vezbu379/AgwsfTry48ePIkytfqHp5xhfLadby+1soMJDLbhchlqIYpVbXa14dz718NMBEz/ZsWsU8zMhY1CdmL+VE+/ObgWSvPR4rj/f/xqxUFG1fVfHIUgLCN58zR5ABySpwbAAdZ1TNMgZYF9YHjWmsDAgNeglNqFSBJJYiG14JUmcYiHNZWJcE6HD4FGIrVuiFjROxJeNYChoFWUS5lBPjOTO2iM2PKuki2F1qfdPjjUjSeMuSk82Uml4fRimlLVR2OUAYBGHpo5aV4OJll1iYRkqWhag4FY75WXhmlTOoedo/ZVKI40Jz+pOEnX2ZsqcCeVJ0piEQieJhiEx0RBkrd6J2IiQFVXqPbZjEYqdmll6Jz0avtUaCqEFtaiqnekmHUagOhSZapvJMeioanXa2KqukZoCrJoruCKNmCngKZGC7urprPRKq+QZBP2XFKRGunBwL6waZjIbiBInu9hoj0o5wraRiOadrsX1kK24HvBK25rnstuvuu/DGK++89NZr77345qvvvhYlAAA7"
},
{
"name": "Sample Taken",
"description": "You collect and project a small sample of tree bark off the plant. The instant that the bark is removed from the tree, as though it suddenly remembered what it was, the moisture content of the bark freezes over, and implodes into small microparticles of splinters.\nSmall radioactive signature detected.",
"choices": [
{
"key": "choice 5",
"name": "Well that was... unexpected.",
"exit_node": "Biological Scan",
"delay": 0,
"delay_message": "Maybe something else might work better.",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Sample",
"value": 1
}
]
}
],
"image": null,
"raw_image": "data:image/gif;base64,R0lGODdhyABkAHcAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAyABkAMIAAAAAAABSLiiPVjtyRS9mOTFbNyYAAAAD/xi63P4wykmrvTjrzbv/YCiOZGmeaKqubOu+sDUQxTDbeK7vfF/3saCwcxPcCMckcqlM2pDPnnRKrUqH2IdAYDBwu+Bwl2Agm8sE8iy9Zrqbb2Z0bq3b74W8Xp+1bP+Af2KDhIVlh2eJaUtsi3CPcU43d5QDe5cFfSKBnJ2en50Ff6JboqYCBWiLq46tkK+RUJOTmJmatxyguqSovae/vsGirK2NjU21trjLQp+8wNDCwnmo1MnM2Nna29zd3t/g4eLj5OXm59o5Rjo/QOjvLaKwkrKylfdW8FleXImIBm0CxppXD4c9fAgT5tCn4Iuhh4fG/DNTjNHAi4/oKERYq/+cro8gPYXxR7EkK4EEUxbUOCVZHoabQoZ8NkqaKWI4BR7DGKcjTG4yaZaySRSatQLGfP5ciqHX0GhQpzGdSrWq1atYs2rdyrWr169gw4pVsc7G2LMLkM46SOkl2nc86W3E97aFgLh4Dc7dq6NuhC0TVVlUOY8l38N9szocREYiyYqEMdJZibjylW+AIRIiqUowyrwDJ+u1XMelsm6CNKtmHHiRZ8iuQGecVdklZpm4V3NWREznYNmhaeNRCg638eOBhrUWjPP3zshNDNuwzRW5dZrQmms3BhzSNb8SrIPCXvTudtjzMIEngVxo+ajDtKOkvt5u0Jrw3/s6yqd+Nk7/7uUn4FH+VaWfKAUmqOCCDDbo4IMQRijhhBRWaOGFGGao4YYcdujhhyCGKOKFRsgxy4jaBEeZOyi60J2JK1piS2ItcvDiaMIpVGMEv0GnIo46grgFbM/dKBppC004kXzo3fiGdJb51wUgiKTBnHNOzsYWkpd1xZpjrTHJnY+vQGlZOztMBUZmrO0mZo9Zwggkl/mkKc5qIy3n2nlExrnWnHROcRueYjSm55Wr+Ebmj2YeZpo4bBJqyG6Inqeon0duRF84kuJJKW98Nrkojlu2dYlHkXaq6qehNvfZqHI2+ihq4lGpKhisttpbbKNm6sN3t9Wam2q5Vtrqq5jesKk3jsI220mheuq665jJzoqqs9gGcqi0211KGLBUZYutciUZG6q3cREnlrjiPcZtTqIiAW597H5E07uuiqqehPXONIq57+6rYb81PWUTvmksuyHBTjUc1XnVmOLWjgFkG+CBNk1MsRb1kiegLxtf4KzHB4b8Qa0XA2OyfZ6QjODKywwlM8w012zzzTjnrPNWCQAAOw=="
},
{
"name": "Examine Roots",
"description": "All plant matter has to derive energy and moisture from someplace. Examining the oak tree's roots reveals that the roots present all appear to splay out, similar to how a normal tree would. However, those roots then proceed to double back in on itself. This might suggest that the tree is obtaining nutrients from... itself.",
"choices": [
{
"key": "choice 7",
"name": "That's fucking stupid.",
"exit_node": "Biological Scan",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": {
"value_type": "random",
"low": 6,
"high": 10
}
}
],
"delay": 0,
"delay_message": "What the hell kind of tree even IS this?"
},
{
"key": "choice 8",
"name": "Obtain biological sample from roots.",
"exit_node": "Sample Taken",
"delay": 10,
"delay_message": "This is why we hire botanists on-site."
}
],
"image": null,
"raw_image": "data:image/gif;base64,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"
},
{
"name": "Background Analysis",
"description": "You compare the radioactive energy bands of the sample collected earlier with that of the nearby solar enviroment.\nNothing.\nThere is nothing nearby that matches the passive signal of the tree, or the bark, or anything similar.\nThis is really starting to get on your nerves.",
"choices": [
{
"key": "choice 10",
"name": "Smash your desk in frustration.",
"exit_node": "FAIL",
"delay": 50,
"delay_message": "No amount of pay is worth dealing with magical plant juju."
},
{
"key": "choice 11",
"name": "Check every known energy spectroscopy database.",
"exit_node": "Sample Match Found",
"delay": 900,
"delay_message": "You NEED an answer. You DESERVE an answer."
}
],
"image": null,
"on_enter_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": {
"value_type": "random",
"low": 3,
"high": 5
}
}
],
"raw_image": "data:image/gif;base64,R0lGODdhyABkAHcAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAyABkAMIAAAAAAAD///9ZVlKsMjJpampGR0cAAAAD/xi63P4wykmFpTjrDa0XXCiOZGlqQ0qsazqIXyx9Z23feKayfP/WskgwRywqCsikcslsOpGpgGvQNDo8lYt1W4I+v2CvMhUuI0/YiZbL5nxdhkJ8Lq/T6eZ8HRmHUtuAgRp6T3B2SXdNfYeJc3CCkJEYjISVYZKRQ5gajZSdi0yboqM3nnWkqKmCpgaqrq9GBrKzs7AKaYG4tji0vbu/wCW6wZpqNMHIOAM9zDw/IzEgHcVt1KOWZQ1TU4LDV2vJOAVU2GZkY5VF4NPr4SRM53yI8/Lw9uVvBcLuknqGn4cqLQIYhwy/g0fwKdSDsCEGggtDOZwoAiLFi5sAYtwoqf/XIVjeOKrqRUukjZAmGVjDGC2lSyAts7R7GW5ZM2bPNERDGSAmzWA2b/pAc+yBT0ArVeXhsC2oj5wnefaU+pNBxDJNXUAqyq6qhKthyCUR+4QLVa5ej5AFO3ZJPGw3qE5N22DsWiUD6Tm5e/cqCbk96dZtQgZip3rjwIIa90fwqrBUDAfcQ0hyilaOIWG7zIoSYryd73DLrJntNlOIO2WVQ/raYrYKW/8CCNuJbH6S8aS7vSCpq9C8gxMMzns48dudj9/WqFw2yZKvfDc38Rxzc+kiq09f/nw7b+wNwV9HuwuwSvLeL14wjz49pm3Qds7sbd59jh1Co3CQP1+8/Rr/TgnVQnxHNVDgf0QEKCBUIRxIX3sIAiigMwzCAKF/cc1H1xQTVvjXhRCqE6IosU2Q1YkiajiViin+VhthWW0l1YhevQjjafrIKI0QLP5kI2GMBWkbG2fVx1FiP/oxRl9DEiEXCDsKhuSPazFpBg5P9miSkHmlpleXbbkVUVRRTkOakl7mRg9fsJmQ5Zl2DaDmJ4XVwZkZYHbpoU726eZCaID28RYYeRFEToQVeVaYLHIwOkugk70GqWiNIeoGQJc5qumclOU5qUGWXhraFNU1yumpdoAa6ganZkrLpJ2G5qido606CKoGwDErrqaaSlKttrIKq2r/DGvHr39aF2wIgsYaduKzqyUhhbLLjsArp3BVW0Oz3OpWlrY5dCsuKOByMS635QpyLaTEGenauZ2M5y4m696B4Lz0spLuRMnt25BH9vr7b3XUChwOwbIYfBDCBSscDMIOL0xwxO5ATPHB2kVHY7oTg7RxuR0rhyFFIYv8MUYZX5xMySoDk3LLD3dXbQIAOw=="
},
{
"name": "Sample Match Found",
"description": "After an extensive algorithm search on the controller end, you have a single match to this specific band and style of energy.\nThe problem, is that the source of said radiation is coming not only from Space Station 13, no.\nIt's coming from the Space Station 13 Research Department.\nWhat the fuck?",
"choices": [
{
"key": "choice 12",
"name": "Something must be wrong with the drone.",
"exit_node": "Its Not You...",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": {
"value_type": "random",
"low": 6,
"high": 10
}
}
],
"delay": 30,
"delay_message": "Lousy piece of junk must be scanning the station instead of the target."
},
{
"key": "choice 13",
"name": "Perhaps that sample was tainted. Collect a new sample.",
"exit_node": "Sample Taken",
"delay": 60,
"delay_message": "Lets try again, but carefully."
},
{
"key": "choice 14",
"name": "Remember the Christmas Party.",
"exit_node": "The Christmas Party",
"requirements": [
{
"quality": "Confusion",
"operator": "<=",
"value": 25
}
],
"delay": 100,
"delay_message": "Wait a gosh darn fucking second."
}
],
"image": null,
"on_enter_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": 10
}
],
"raw_image": "data:image/gif;base64,R0lGODdhyABkAHcAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAyABkAMIAAAAAAAD////v7+/h4eEAAAAAAAAAAAAD/xi63P4wykmrvTjrzbv/YCiOZBkJaJqaLKOubSy7b23fODxPOb7/m4FASBRofEBeT1W6JU3DYaRIjQqfkCWKg1xoddjSQEgQlM/mdDkc0Fa+8PiWLSIM7Pj73RxOlVF/ITlKNXSGDXp5iiFoaBlqfpFyk12HMgSYmZkfmppmmJ8gjXwUf2lglqmqq6ytrq+wsbKztLW2t7i5um2Ug669uyBCKMNRc4Q9qXHBJlVUFMbRV6pfR04ONszQzlZRlm7IveLaimZ7eJAESUsfyVnX2hfqv/Nv4vfZ8RWJ/Hkdn6NGtRsFyEg4VLwK6UvVqROdgMcWSpxIsaLFixgzatzIsf+jR1gIP7YbN6uaSAn4wFGbdNJFsZcpFRqS09IBt2kW3CkzWdNmNyIYpIWkw9Nevgbwat2ccNPbTnbWjtKQWfGnVZwzoQaNqVXXkDFWGx3qeoIry2CJzJ05p6aPTpRmfSXV1a/u2jM7TuldA8LXO6kXFemh5ihn3Lc9A9h1ZaqxpMNkK9rl5+EMKIGM9g5FSjJjv4aVOwEc/Q8iXx6ODSo5ualOQ9Bs0qVJTLu27du4c+vezbu379/AgwsfTry48ePIkytfqHp5xhfLadby+1soMJDLbhchlqIYpVbXa14dz718NMBEz/ZsWsU8zMhY1CdmL+VE+/ObgWSvPR4rj/f/xqxUFG1fVfHIUgLCN58zR5ABySpwbAAdZ1TNMgZYF9YHjWmsDAgNeglNqFSBJJYiG14JUmcYiHNZWJcE6HD4FGIrVuiFjROxJeNYChoFWUS5lBPjOTO2iM2PKuki2F1qfdPjjUjSeMuSk82Uml4fRimlLVR2OUAYBGHpo5aV4OJll1iYRkqWhag4FY75WXhmlTOoedo/ZVKI40Jz+pOEnX2ZsqcCeVJ0piEQieJhiEx0RBkrd6J2IiQFVXqPbZjEYqdmll6Jz0avtUaCqEFtaiqnekmHUagOhSZapvJMeioanXa2KqukZoCrJoruCKNmCngKZGC7urprPRKq+QZBP2XFKRGunBwL6waZjIbiBInu9hoj0o5wraRiOadrsX1kK24HvBK25rnstuvuu/DGK++89NZr77345qvvvhYlAAA7"
},
{
"name": "The Christmas Party",
"description": "Hold on. Last Christmas, the Research Director was incredibly hammered. He made a big mention that his brand new festivus pole was actually some kind of astrological... something something. You can't remember the whole details, because you were smashed as well. However, briefly, the RD did keep that festivus pole for awhile, he might even still have it somewhere.\nMaybe...?",
"choices": [
{
"key": "choice 15",
"name": "Wait a minute, was that a god damn...",
"exit_node": "Rod.",
"delay": 100,
"delay_message": "Immovable Rod?"
}
],
"image": null,
"raw_image": "data:image/gif;base64,R0lGODdhyABkAHcAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAyABkAMIAAAAAAAD/AACmAAD///+mpqYAAAAAAAAD/xi63P4wykmrvTjrzbv/YCiOZGmejKCubOu6aCzP4WvfeD4IQ+//Pppw+MkZj6udkgdsOp/EqFSBrNqWwQ9hy+16v9ypeGM9YpnAE3hNKLTfhbG8kuTZz/j7/fmb+/8TbIJefIVNgIiJGgWMjY6PkJGRipSVlpeYmZqbnJ2en6ChoqOkpRplqDdYpqyprnpKhnyslq9leFkYg2u0QrZmaLkgu8S9JDg7Ksl2yrB7UDJw0m6QxiFfedk9wbKH1tbEW9TT05Lmjd/pJpPq7e7v8PHy8/T19vf4+fr7Kb9W/Jn8pcLiBKAcgVZwdethkAZCJAoXFmx47KEOWLMeAAlHMf+DRVXctIT70jHCxxYEhXkYKajkgpMRGZZgKY5LHJcJ6zTTNtHEm5rjgsK5WZKZs2xHn2WccY6RSwdJkaaUOOApoHDbqFK16ofmF6Fg20Aa8IhrpbBBm6plZ7aTIwhr0bWdS7eu3bt48+rdy7ev37+AAwseTLiw4cOI0/1LfPAkC8YlHINUApmD5MncVFZ+cPmK0qWbX3Z2MbVbaCqjd37eCjk1i9JaZR5OHTN2z8Gua9v2wavvaNjeKgygqbcz8KocvBLAexn4MOVb5jZfjVwk9DBW/S3bTn3E9S5cUXFvphqaCOhBs7/WGbU96PNr0EpTT96o1Kjv4ZOT/xbn/f921AWnBlhNWQXggZndFkNcZv2X1YOxsCZENXdJBWGCWp2mQRc+YLibIRpaQMyHEoVYgVfDcUFiHyYGopxQTgwFYosugsFfOXGZQyMGN+boI1E78vjjkHIF+QGRahkZxVpKNunkk1BGKeWUVFZp5ZVYZqnllogkAAA7"
},
{
"name": "Rod.",
"description": "You cross reference your documentation. Sure enough, the \"festivus rod\" collected was actually an immovable rod.\nEnergy detected from the rod is the exact same coming off of the tree, as well. It's all making sense now. The Immovable rod is producing a kind of unique blackbody radiation that is providing sample heat and light for what is effectively an internal cold fusion process, and producing just enough of that radiation to create a kind of micro-enviromental bubble around the biosignature of the tree.\n\nThis would make the first time an immovable rod would exist in tandem with a biological source. You jot down some research notes on your findings, which could easily produce some kind of experimental tech, no doubt.",
"choices": [
{
"key": "choice 16",
"name": "Snap a photo",
"exit_node": "Epilogue.",
"delay": 40,
"delay_message": "You could easily win an award for these findings!"
}
],
"image": "default"
},
{
"name": "Epilogue.",
"description": "You take a photo with the onboard camera on the drone. Suddenly, the immovable rod inside the tree explodes out of the wooden biological shell, and produces a blank, blurry photo.\nWhat the fuck?",
"choices": [
{
"key": "choice 17",
"name": "God damnit.",
"exit_node": "WIN",
"delay": 10,
"delay_message": "Some things were just not meant for man to know."
}
],
"image": "default"
},
{
"name": "What is wrong with this tree?",
"description": "This is ridiculous. Nothing about this dumbass tree makes sense. It makes no sense, it's just sitting there, living and making a MOCKERY of all of science!\nYou didn't get your degree in advanced plasma-physics for this!",
"choices": [
{
"key": "choice 18",
"name": "The world can never know about this dumbass stupid plant.",
"exit_node": "FAIL_DEATH",
"delay": 60,
"delay_message": "Activating drone self-destruct."
},
{
"key": "choice 19",
"name": "Take a moment to calm down.",
"exit_node": "Biological Scan",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": {
"value_type": "random",
"low": -3,
"high": -5
}
}
],
"delay": 20,
"delay_message": "Breathe."
}
],
"image": "default"
}
]
}
"adventure_name": "There's a tree in the middle of space.",
"version": 1,
"starting_node": "Tree Start",
"starting_qualities": {
"Confusion": 0
},
"required_site_traits": [
"in space"
],
"loot_categories": [
"research"
],
"scan_band_mods": {
"Exotic Radiation": 10
},
"deep_scan_description": "",
"triggers": [
{
"name": "Confusion Trigger",
"target_node": "What is wrong with this tree?",
"requirements": [
{
"quality": "Confusion",
"operator": ">",
"value": 30
}
]
}
],
"nodes": [
{
"name": "Tree Start",
"description": "Camera online. Visual signs detect a fully grown, seemingly biological, and live tree located in the middle of the vacuum.\nSensors indicate it is not oxygenating, but energy is being collected via passive solar light from the nearby star.\nBaffling.",
"choices": [
{
"key": "choice 0",
"name": "Ignore site.",
"exit_node": "FAIL",
"delay": 10,
"delay_message": "Leave this for the botanists to figure out."
},
{
"key": "choice 1",
"name": "Begin sensor scan.",
"exit_node": "Biological Scan",
"delay": 10,
"delay_message": "Lets get some data."
}
],
"image": null,
"raw_image": "data:image/gif;base64,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"
},
{
"name": "Biological Scan",
"description": "You attempt to scan for clues regarding the tree's nature. It appears to be a fully mature oak tree. \n\nApproximated height is 13 ft, 6.4 inches. \n\nSubject sees no sign of an outer coating or otherwise layer protecting it from the void of space.\n\nSubject's surface temperature is 293.7 kelvin, as though it were sitting indoors.",
"choices": [
{
"key": "choice 2",
"name": "Check Sensor Integrity.",
"exit_node": "Its Not You...",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": 5
}
],
"delay": 50,
"delay_message": "This can't be right."
},
{
"key": "choice 4",
"name": "Attempt to take sample.",
"exit_node": "Sample Taken",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": 3
}
],
"delay": 40,
"delay_message": "Snip snip."
},
{
"key": "choice 6",
"name": "Examine Tree Roots.",
"exit_node": "Examine Roots",
"delay": 10
},
{
"key": "choice 9",
"name": "Sequence Sample Radiation with background noise.",
"exit_node": "Background Analysis",
"requirements": [
{
"quality": "Sample",
"operator": ">=",
"value": 1
}
],
"delay": 0,
"delay_message": "This can't be real."
},
{
"key": "choice 40",
"name": "Leave.",
"exit_node": "FAIL",
"delay": 0
}
],
"image": null,
"raw_image": "data:image/gif;base64,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"
},
{
"name": "Its Not You...",
"description": "After re-connection is established, your sensors appear fine. Tree has not moved in the slightest since last observed. Temperature has fluxuated 0.2 kelvin upwards, as expected of a plant under direct light.\nLets try again.",
"choices": [
{
"key": "choice 3",
"name": "Restart biological scan.",
"exit_node": "Biological Scan",
"delay": 25,
"delay_message": "God damnit."
}
],
"image": null,
"raw_image": "data:image/gif;base64,R0lGODdhyABkAHcAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAyABkAMIAAAAAAAD////v7+/h4eEAAAAAAAAAAAAD/xi63P4wykmrvTjrzbv/YCiOZBkJaJqaLKOubSy7b23fODxPOb7/m4FASBRofEBeT1W6JU3DYaRIjQqfkCWKg1xoddjSQEgQlM/mdDkc0Fa+8PiWLSIM7Pj73RxOlVF/ITlKNXSGDXp5iiFoaBlqfpFyk12HMgSYmZkfmppmmJ8gjXwUf2lglqmqq6ytrq+wsbKztLW2t7i5um2Ug669uyBCKMNRc4Q9qXHBJlVUFMbRV6pfR04ONszQzlZRlm7IveLaimZ7eJAESUsfyVnX2hfqv/Nv4vfZ8RWJ/Hkdn6NGtRsFyEg4VLwK6UvVqROdgMcWSpxIsaLFixgzatzIsf+jR1gIP7YbN6uaSAn4wFGbdNJFsZcpFRqS09IBt2kW3CkzWdNmNyIYpIWkw9Nevgbwat2ccNPbTnbWjtKQWfGnVZwzoQaNqVXXkDFWGx3qeoIry2CJzJ05p6aPTpRmfSXV1a/u2jM7TuldA8LXO6kXFemh5ihn3Lc9A9h1ZaqxpMNkK9rl5+EMKIGM9g5FSjJjv4aVOwEc/Q8iXx6ODSo5ualOQ9Bs0qVJTLu27du4c+vezbu379/AgwsfTry48ePIkytfqHp5xhfLadby+1soMJDLbhchlqIYpVbXa14dz718NMBEz/ZsWsU8zMhY1CdmL+VE+/ObgWSvPR4rj/f/xqxUFG1fVfHIUgLCN58zR5ABySpwbAAdZ1TNMgZYF9YHjWmsDAgNeglNqFSBJJYiG14JUmcYiHNZWJcE6HD4FGIrVuiFjROxJeNYChoFWUS5lBPjOTO2iM2PKuki2F1qfdPjjUjSeMuSk82Uml4fRimlLVR2OUAYBGHpo5aV4OJll1iYRkqWhag4FY75WXhmlTOoedo/ZVKI40Jz+pOEnX2ZsqcCeVJ0piEQieJhiEx0RBkrd6J2IiQFVXqPbZjEYqdmll6Jz0avtUaCqEFtaiqnekmHUagOhSZapvJMeioanXa2KqukZoCrJoruCKNmCngKZGC7urprPRKq+QZBP2XFKRGunBwL6waZjIbiBInu9hoj0o5wraRiOadrsX1kK24HvBK25rnstuvuu/DGK++89NZr77345qvvvhYlAAA7"
},
{
"name": "Sample Taken",
"description": "You collect and project a small sample of tree bark off the plant. The instant that the bark is removed from the tree, as though it suddenly remembered what it was, the moisture content of the bark freezes over, and implodes into small microparticles of splinters.\nSmall radioactive signature detected.",
"choices": [
{
"key": "choice 5",
"name": "Well that was... unexpected.",
"exit_node": "Biological Scan",
"delay": 0,
"delay_message": "Maybe something else might work better.",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Sample",
"value": 1
}
]
}
],
"image": null,
"raw_image": "data:image/gif;base64,R0lGODdhyABkAHcAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAyABkAMIAAAAAAABSLiiPVjtyRS9mOTFbNyYAAAAD/xi63P4wykmrvTjrzbv/YCiOZGmeaKqubOu+sDUQxTDbeK7vfF/3saCwcxPcCMckcqlM2pDPnnRKrUqH2IdAYDBwu+Bwl2Agm8sE8iy9Zrqbb2Z0bq3b74W8Xp+1bP+Af2KDhIVlh2eJaUtsi3CPcU43d5QDe5cFfSKBnJ2en50Ff6JboqYCBWiLq46tkK+RUJOTmJmatxyguqSovae/vsGirK2NjU21trjLQp+8wNDCwnmo1MnM2Nna29zd3t/g4eLj5OXm59o5Rjo/QOjvLaKwkrKylfdW8FleXImIBm0CxppXD4c9fAgT5tCn4Iuhh4fG/DNTjNHAi4/oKERYq/+cro8gPYXxR7EkK4EEUxbUOCVZHoabQoZ8NkqaKWI4BR7DGKcjTG4yaZaySRSatQLGfP5ciqHX0GhQpzGdSrWq1atYs2rdyrWr169gw4pVsc7G2LMLkM46SOkl2nc86W3E97aFgLh4Dc7dq6NuhC0TVVlUOY8l38N9szocREYiyYqEMdJZibjylW+AIRIiqUowyrwDJ+u1XMelsm6CNKtmHHiRZ8iuQGecVdklZpm4V3NWREznYNmhaeNRCg638eOBhrUWjPP3zshNDNuwzRW5dZrQmms3BhzSNb8SrIPCXvTudtjzMIEngVxo+ajDtKOkvt5u0Jrw3/s6yqd+Nk7/7uUn4FH+VaWfKAUmqOCCDDbo4IMQRijhhBRWaOGFGGao4YYcdujhhyCGKOKFRsgxy4jaBEeZOyi60J2JK1piS2ItcvDiaMIpVGMEv0GnIo46grgFbM/dKBppC004kXzo3fiGdJb51wUgiKTBnHNOzsYWkpd1xZpjrTHJnY+vQGlZOztMBUZmrO0mZo9Zwggkl/mkKc5qIy3n2nlExrnWnHROcRueYjSm55Wr+Ebmj2YeZpo4bBJqyG6Inqeon0duRF84kuJJKW98Nrkojlu2dYlHkXaq6qehNvfZqHI2+ihq4lGpKhisttpbbKNm6sN3t9Wam2q5Vtrqq5jesKk3jsI220mheuq665jJzoqqs9gGcqi0211KGLBUZYutciUZG6q3cREnlrjiPcZtTqIiAW597H5E07uuiqqehPXONIq57+6rYb81PWUTvmksuyHBTjUc1XnVmOLWjgFkG+CBNk1MsRb1kiegLxtf4KzHB4b8Qa0XA2OyfZ6QjODKywwlM8w012zzzTjnrPNWCQAAOw=="
},
{
"name": "Examine Roots",
"description": "All plant matter has to derive energy and moisture from someplace. Examining the oak tree's roots reveals that the roots present all appear to splay out, similar to how a normal tree would. However, those roots then proceed to double back in on itself. This might suggest that the tree is obtaining nutrients from... itself.",
"choices": [
{
"key": "choice 7",
"name": "That's fucking stupid.",
"exit_node": "Biological Scan",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": {
"value_type": "random",
"low": 6,
"high": 10
}
}
],
"delay": 0,
"delay_message": "What the hell kind of tree even IS this?"
},
{
"key": "choice 8",
"name": "Obtain biological sample from roots.",
"exit_node": "Sample Taken",
"delay": 10,
"delay_message": "This is why we hire botanists on-site."
}
],
"image": null,
"raw_image": "data:image/gif;base64,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"
},
{
"name": "Background Analysis",
"description": "You compare the radioactive energy bands of the sample collected earlier with that of the nearby solar enviroment.\nNothing.\nThere is nothing nearby that matches the passive signal of the tree, or the bark, or anything similar.\nThis is really starting to get on your nerves.",
"choices": [
{
"key": "choice 10",
"name": "Smash your desk in frustration.",
"exit_node": "FAIL",
"delay": 50,
"delay_message": "No amount of pay is worth dealing with magical plant juju."
},
{
"key": "choice 11",
"name": "Check every known energy spectroscopy database.",
"exit_node": "Sample Match Found",
"delay": 900,
"delay_message": "You NEED an answer. You DESERVE an answer."
}
],
"image": null,
"on_enter_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": {
"value_type": "random",
"low": 3,
"high": 5
}
}
],
"raw_image": "data:image/gif;base64,R0lGODdhyABkAHcAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAyABkAMIAAAAAAAD///9ZVlKsMjJpampGR0cAAAAD/xi63P4wykmFpTjrDa0XXCiOZGlqQ0qsazqIXyx9Z23feKayfP/WskgwRywqCsikcslsOpGpgGvQNDo8lYt1W4I+v2CvMhUuI0/YiZbL5nxdhkJ8Lq/T6eZ8HRmHUtuAgRp6T3B2SXdNfYeJc3CCkJEYjISVYZKRQ5gajZSdi0yboqM3nnWkqKmCpgaqrq9GBrKzs7AKaYG4tji0vbu/wCW6wZpqNMHIOAM9zDw/IzEgHcVt1KOWZQ1TU4LDV2vJOAVU2GZkY5VF4NPr4SRM53yI8/Lw9uVvBcLuknqGn4cqLQIYhwy/g0fwKdSDsCEGggtDOZwoAiLFi5sAYtwoqf/XIVjeOKrqRUukjZAmGVjDGC2lSyAts7R7GW5ZM2bPNERDGSAmzWA2b/pAc+yBT0ArVeXhsC2oj5wnefaU+pNBxDJNXUAqyq6qhKthyCUR+4QLVa5ej5AFO3ZJPGw3qE5N22DsWiUD6Tm5e/cqCbk96dZtQgZip3rjwIIa90fwqrBUDAfcQ0hyilaOIWG7zIoSYryd73DLrJntNlOIO2WVQ/raYrYKW/8CCNuJbH6S8aS7vSCpq9C8gxMMzns48dudj9/WqFw2yZKvfDc38Rxzc+kiq09f/nw7b+wNwV9HuwuwSvLeL14wjz49pm3Qds7sbd59jh1Co3CQP1+8/Rr/TgnVQnxHNVDgf0QEKCBUIRxIX3sIAiigMwzCAKF/cc1H1xQTVvjXhRCqE6IosU2Q1YkiajiViin+VhthWW0l1YhevQjjafrIKI0QLP5kI2GMBWkbG2fVx1FiP/oxRl9DEiEXCDsKhuSPazFpBg5P9miSkHmlpleXbbkVUVRRTkOakl7mRg9fsJmQ5Zl2DaDmJ4XVwZkZYHbpoU726eZCaID28RYYeRFEToQVeVaYLHIwOkugk70GqWiNIeoGQJc5qumclOU5qUGWXhraFNU1yumpdoAa6ganZkrLpJ2G5qido606CKoGwDErrqaaSlKttrIKq2r/DGvHr39aF2wIgsYaduKzqyUhhbLLjsArp3BVW0Oz3OpWlrY5dCsuKOByMS635QpyLaTEGenauZ2M5y4m696B4Lz0spLuRMnt25BH9vr7b3XUChwOwbIYfBDCBSscDMIOL0xwxO5ATPHB2kVHY7oTg7RxuR0rhyFFIYv8MUYZX5xMySoDk3LLD3dXbQIAOw=="
},
{
"name": "Sample Match Found",
"description": "After an extensive algorithm search on the controller end, you have a single match to this specific band and style of energy.\nThe problem, is that the source of said radiation is coming not only from Space Station 13, no.\nIt's coming from the Space Station 13 Research Department.\nWhat the fuck?",
"choices": [
{
"key": "choice 12",
"name": "Something must be wrong with the drone.",
"exit_node": "Its Not You...",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": {
"value_type": "random",
"low": 6,
"high": 10
}
}
],
"delay": 30,
"delay_message": "Lousy piece of junk must be scanning the station instead of the target."
},
{
"key": "choice 13",
"name": "Perhaps that sample was tainted. Collect a new sample.",
"exit_node": "Sample Taken",
"delay": 60,
"delay_message": "Lets try again, but carefully."
},
{
"key": "choice 14",
"name": "Remember the Christmas Party.",
"exit_node": "The Christmas Party",
"requirements": [
{
"quality": "Confusion",
"operator": "<=",
"value": 25
}
],
"delay": 100,
"delay_message": "Wait a gosh darn fucking second."
}
],
"image": null,
"on_enter_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": 10
}
],
"raw_image": "data:image/gif;base64,R0lGODdhyABkAHcAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAyABkAMIAAAAAAAD////v7+/h4eEAAAAAAAAAAAAD/xi63P4wykmrvTjrzbv/YCiOZBkJaJqaLKOubSy7b23fODxPOb7/m4FASBRofEBeT1W6JU3DYaRIjQqfkCWKg1xoddjSQEgQlM/mdDkc0Fa+8PiWLSIM7Pj73RxOlVF/ITlKNXSGDXp5iiFoaBlqfpFyk12HMgSYmZkfmppmmJ8gjXwUf2lglqmqq6ytrq+wsbKztLW2t7i5um2Ug669uyBCKMNRc4Q9qXHBJlVUFMbRV6pfR04ONszQzlZRlm7IveLaimZ7eJAESUsfyVnX2hfqv/Nv4vfZ8RWJ/Hkdn6NGtRsFyEg4VLwK6UvVqROdgMcWSpxIsaLFixgzatzIsf+jR1gIP7YbN6uaSAn4wFGbdNJFsZcpFRqS09IBt2kW3CkzWdNmNyIYpIWkw9Nevgbwat2ccNPbTnbWjtKQWfGnVZwzoQaNqVXXkDFWGx3qeoIry2CJzJ05p6aPTpRmfSXV1a/u2jM7TuldA8LXO6kXFemh5ihn3Lc9A9h1ZaqxpMNkK9rl5+EMKIGM9g5FSjJjv4aVOwEc/Q8iXx6ODSo5ualOQ9Bs0qVJTLu27du4c+vezbu379/AgwsfTry48ePIkytfqHp5xhfLadby+1soMJDLbhchlqIYpVbXa14dz718NMBEz/ZsWsU8zMhY1CdmL+VE+/ObgWSvPR4rj/f/xqxUFG1fVfHIUgLCN58zR5ABySpwbAAdZ1TNMgZYF9YHjWmsDAgNeglNqFSBJJYiG14JUmcYiHNZWJcE6HD4FGIrVuiFjROxJeNYChoFWUS5lBPjOTO2iM2PKuki2F1qfdPjjUjSeMuSk82Uml4fRimlLVR2OUAYBGHpo5aV4OJll1iYRkqWhag4FY75WXhmlTOoedo/ZVKI40Jz+pOEnX2ZsqcCeVJ0piEQieJhiEx0RBkrd6J2IiQFVXqPbZjEYqdmll6Jz0avtUaCqEFtaiqnekmHUagOhSZapvJMeioanXa2KqukZoCrJoruCKNmCngKZGC7urprPRKq+QZBP2XFKRGunBwL6waZjIbiBInu9hoj0o5wraRiOadrsX1kK24HvBK25rnstuvuu/DGK++89NZr77345qvvvhYlAAA7"
},
{
"name": "The Christmas Party",
"description": "Hold on. Last Christmas, the Research Director was incredibly hammered. He made a big mention that his brand new festivus pole was actually some kind of astrological... something something. You can't remember the whole details, because you were smashed as well. However, briefly, the RD did keep that festivus pole for awhile, he might even still have it somewhere.\nMaybe...?",
"choices": [
{
"key": "choice 15",
"name": "Wait a minute, was that a god damn...",
"exit_node": "Rod.",
"delay": 100,
"delay_message": "Immovable Rod?"
}
],
"image": null,
"raw_image": "data:image/gif;base64,R0lGODdhyABkAHcAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAyABkAMIAAAAAAAD/AACmAAD///+mpqYAAAAAAAAD/xi63P4wykmrvTjrzbv/YCiOZGmejKCubOu6aCzP4WvfeD4IQ+//Pppw+MkZj6udkgdsOp/EqFSBrNqWwQ9hy+16v9ypeGM9YpnAE3hNKLTfhbG8kuTZz/j7/fmb+/8TbIJefIVNgIiJGgWMjY6PkJGRipSVlpeYmZqbnJ2en6ChoqOkpRplqDdYpqyprnpKhnyslq9leFkYg2u0QrZmaLkgu8S9JDg7Ksl2yrB7UDJw0m6QxiFfedk9wbKH1tbEW9TT05Lmjd/pJpPq7e7v8PHy8/T19vf4+fr7Kb9W/Jn8pcLiBKAcgVZwdethkAZCJAoXFmx47KEOWLMeAAlHMf+DRVXctIT70jHCxxYEhXkYKajkgpMRGZZgKY5LHJcJ6zTTNtHEm5rjgsK5WZKZs2xHn2WccY6RSwdJkaaUOOApoHDbqFK16ofmF6Fg20Aa8IhrpbBBm6plZ7aTIwhr0bWdS7eu3bt48+rdy7ev37+AAwseTLiw4cOI0/1LfPAkC8YlHINUApmD5MncVFZ+cPmK0qWbX3Z2MbVbaCqjd37eCjk1i9JaZR5OHTN2z8Gua9v2wavvaNjeKgygqbcz8KocvBLAexn4MOVb5jZfjVwk9DBW/S3bTn3E9S5cUXFvphqaCOhBs7/WGbU96PNr0EpTT96o1Kjv4ZOT/xbn/f921AWnBlhNWQXggZndFkNcZv2X1YOxsCZENXdJBWGCWp2mQRc+YLibIRpaQMyHEoVYgVfDcUFiHyYGopxQTgwFYosugsFfOXGZQyMGN+boI1E78vjjkHIF+QGRahkZxVpKNunkk1BGKeWUVFZp5ZVYZqnllogkAAA7"
},
{
"name": "Rod.",
"description": "You cross reference your documentation. Sure enough, the \"festivus rod\" collected was actually an immovable rod.\nEnergy detected from the rod is the exact same coming off of the tree, as well. It's all making sense now. The Immovable rod is producing a kind of unique blackbody radiation that is providing sample heat and light for what is effectively an internal cold fusion process, and producing just enough of that radiation to create a kind of micro-enviromental bubble around the biosignature of the tree.\n\nThis would make the first time an immovable rod would exist in tandem with a biological source. You jot down some research notes on your findings, which could easily produce some kind of experimental tech, no doubt.",
"choices": [
{
"key": "choice 16",
"name": "Snap a photo",
"exit_node": "Epilogue.",
"delay": 40,
"delay_message": "You could easily win an award for these findings!"
}
],
"image": "default"
},
{
"name": "Epilogue.",
"description": "You take a photo with the onboard camera on the drone. Suddenly, the immovable rod inside the tree explodes out of the wooden biological shell, and produces a blank, blurry photo.\nWhat the fuck?",
"choices": [
{
"key": "choice 17",
"name": "God damnit.",
"exit_node": "WIN",
"delay": 10,
"delay_message": "Some things were just not meant for man to know."
}
],
"image": "default",
"on_enter_effects": [
{
"effect_type": "Set",
"quality": "Confusion",
"value": 9999
}
]
},
{
"name": "What is wrong with this tree?",
"description": "This is ridiculous. Nothing about this dumbass tree makes sense. It makes no sense, it's just sitting there, living and making a MOCKERY of all of science!\nYou didn't get your degree in advanced plasma-physics for this!",
"choices": [
{
"key": "choice 18",
"name": "The world can never know about this dumbass stupid plant.",
"exit_node": "FAIL_DEATH",
"delay": 60,
"delay_message": "Activating drone self-destruct."
},
{
"key": "choice 19",
"name": "Take a moment to calm down.",
"exit_node": "Biological Scan",
"on_selection_effects": [
{
"effect_type": "Add",
"quality": "Confusion",
"value": {
"value_type": "random",
"low": -3,
"high": -5
}
}
],
"delay": 20,
"delay_message": "Breathe."
}
],
"image": "default"
}
]
}
+9 -4
View File
@@ -5,7 +5,7 @@
// Fuel types and travel time per unit of distance on that fuel.
#define FUEL_BASIC "basic"
#define BASIC_FUEL_TIME_COST 300
#define BASIC_FUEL_TIME_COST 250
#define FUEL_ADVANCED "advanced"
#define ADVANCED_FUEL_TIME_COST 200
@@ -334,9 +334,9 @@ GLOBAL_LIST_EMPTY(exodrone_launchers)
drone_log("Sustained [amount] damage.")
/obj/item/exodrone/proc/drone_log(message)
drone_log.Insert(1,message)
if(length(drone_log) > EXODRONE_LOG_SIZE)
drone_log.Cut(EXODRONE_LOG_SIZE)
drone_log = list()
drone_log.Insert(1,message)
/obj/item/exodrone/proc/has_tool(tool_type)
return tools.Find(tool_type)
@@ -354,6 +354,11 @@ GLOBAL_LIST_EMPTY(exodrone_launchers)
. = ..()
GLOB.exodrone_launchers += src
/obj/machinery/exodrone_launcher/examine(user)
. = ..()
if(fuel_canister)
. += span_notice("You can remove the [fuel_canister] with a <b>prying tool</b>.")
/obj/machinery/exodrone_launcher/attackby(obj/item/weapon, mob/living/user, params)
if(istype(weapon, /obj/item/fuel_pellet))
if(fuel_canister)
@@ -374,7 +379,7 @@ GLOBAL_LIST_EMPTY(exodrone_launchers)
if(!fuel_canister)
return
to_chat(user, span_notice("You remove the [fuel_canister] from the [src]."))
to_chat(user, span_notice("You remove [fuel_canister] from [src]."))
fuel_canister.forceMove(drop_location())
fuel_canister = null
update_icon()
+33 -8
View File
@@ -14,9 +14,9 @@ GLOBAL_LIST_INIT(scan_conditions,init_scan_conditions())
#define MAX_SCAN_DISTANCE 10
#define WIDE_SCAN_COST(BAND, SCAN_POWER) (((BAND*BAND)/(SCAN_POWER))*2*60*10)
#define BASE_POINT_SCAN_TIME (5 MINUTES)
#define BASE_DEEP_SCAN_TIME (5 MINUTES)
#define WIDE_SCAN_COST(BAND, SCAN_POWER) (min(((BAND*BAND)/(SCAN_POWER))*2*60*10, 10 MINUTES))
#define BASE_POINT_SCAN_TIME (2 MINUTES)
#define BASE_DEEP_SCAN_TIME (3 MINUTES)
/// Represents scan in progress, only one globally for now, todo later split per z or allow partial dish swarm usage
/datum/exoscan
@@ -35,7 +35,7 @@ GLOBAL_LIST_INIT(scan_conditions,init_scan_conditions())
var/scan_time = 0
switch(scan_type)
if(EXOSCAN_WIDE)
scan_power = length(GLOB.exoscanner_controller.tracked_dishes)
scan_power = GLOB.exoscanner_controller.calculate_scan_power()
scan_time = WIDE_SCAN_COST(GLOB.exoscanner_controller.wide_scan_band,scan_power)
if(EXOSCAN_POINT)
scan_power = GLOB.exoscanner_controller.get_scan_power(target)
@@ -76,7 +76,8 @@ GLOBAL_LIST_INIT(scan_conditions,init_scan_conditions())
deltimer(scan_timer)
/obj/machinery/computer/exoscanner_control
name = "Scanner Array Control Console"
name = "scanner array control console"
desc = "Controls scanner arrays to initiate scans for exodrones."
circuit = /obj/item/circuitboard/computer/exoscanner_console
/// If scan was interrupted show a popup until dismissed.
var/failed_popup = FALSE
@@ -105,7 +106,7 @@ GLOBAL_LIST_INIT(scan_conditions,init_scan_conditions())
condition_descriptions += condition.description
.["scan_conditions"] = condition_descriptions
else
.["scan_power"] = scan_power = length(GLOB.exoscanner_controller.tracked_dishes)
.["scan_power"] = scan_power = GLOB.exoscanner_controller.calculate_scan_power()
.["wide_scan_eta"] = scan_power > 0 ? WIDE_SCAN_COST(GLOB.exoscanner_controller.wide_scan_band,scan_power) : 0
.["possible_sites"] = build_exploration_site_ui_data()
.["scan_conditions"] = null
@@ -196,11 +197,35 @@ GLOBAL_LIST_INIT(scan_conditions,init_scan_conditions())
icon = 'icons/obj/exploration.dmi'
icon_state = "scanner_off"
desc = "A sophisticated scanning array. Easily influenced by its environment."
circuit = /obj/item/circuitboard/machine/exoscanner
///the scan power of this array to supply to scanner_controller
var/scan_power = 1
/obj/machinery/exoscanner/Initialize(mapload)
. = ..()
RegisterSignals(GLOB.exoscanner_controller,list(COMSIG_EXOSCAN_STARTED,COMSIG_EXOSCAN_FINISHED), PROC_REF(scan_change))
update_readiness()
RefreshParts()
/obj/machinery/exoscanner/RefreshParts()
. = ..()
var/power = 1
for(var/datum/stock_part/scanning_module/scanning_module in component_parts)
power += (scanning_module.tier - 1) / 12
scan_power = power
GLOB.exoscanner_controller.update_scan_power()
/obj/machinery/exoscanner/screwdriver_act(mob/user, obj/item/tool)
. = ..()
if(!.)
. = default_deconstruction_screwdriver(user, "scanner_open", "scanner_off", tool)
update_readiness()
/obj/machinery/exoscanner/crowbar_act(mob/user, obj/item/tool)
..()
if(default_deconstruction_crowbar(tool))
return TRUE
/obj/machinery/exoscanner/proc/scan_change()
SIGNAL_HANDLER
@@ -215,7 +240,7 @@ GLOBAL_LIST_INIT(scan_conditions,init_scan_conditions())
GLOB.exoscanner_controller.deactivate_scanner(src)
/obj/machinery/exoscanner/proc/is_ready()
return anchored && is_operational
return anchored && is_operational && !panel_open
/obj/machinery/exoscanner/proc/update_readiness()
if(is_ready())
@@ -302,7 +327,7 @@ GLOBAL_LIST_INIT(scan_conditions,init_scan_conditions())
/datum/scanner_controller/proc/calculate_scan_power(conditions)
. = 0
for(var/obj/machinery/exoscanner/dish in tracked_dishes)
var/effective_power = 1
var/effective_power = dish.scan_power
for(var/datum/scan_condition/condition in conditions)
effective_power *= condition.check_dish(dish)
if(!effective_power) //Don't bother continuing if it's zero
+1 -1
View File
@@ -37,7 +37,7 @@
plant_icon_offset = 2
species = "replicapod"
plantname = "Replica Pod"
product = /mob/living/carbon/human //verrry special -- Urist
product = null // the human mob is spawned in harvest()
lifespan = 50
endurance = 8
maturation = 10
+55 -47
View File
@@ -13,46 +13,33 @@
* * user - checks if we can remove the object from the inventory
* *
*/
/proc/seedify(obj/item/O, t_max, obj/machinery/seed_extractor/extractor, mob/living/user)
var/t_amount = 0
/proc/seedify(obj/item/object, t_max, obj/machinery/seed_extractor/extractor, mob/living/user)
//try to get the seed from this item
var/obj/item/seeds/seed = object.get_plant_seed()
if(isnull(seed))
return null
//generate a random multiplier if value is not specified
var/list/seeds = list()
if(t_max == -1)
if(extractor)
t_max = rand(1,4) * extractor.seed_multiplier
else
t_max = rand(1,4)
var/seedloc = O.loc
//drop location for the newly generated seeds
var/seedloc = object.loc
if(extractor)
seedloc = extractor.loc
if(istype(O, /obj/item/food/grown/))
var/obj/item/food/grown/F = O
if(F.seed)
if(user && !user.temporarilyRemoveItemFromInventory(O)) //couldn't drop the item
return
while(t_amount < t_max)
var/obj/item/seeds/t_prod = F.seed.Copy()
seeds.Add(t_prod)
t_prod.forceMove(seedloc)
t_amount++
qdel(O)
return seeds
else if(istype(O, /obj/item/grown))
var/obj/item/grown/F = O
if(F.seed)
if(user && !user.temporarilyRemoveItemFromInventory(O))
return
while(t_amount < t_max)
var/obj/item/seeds/t_prod = F.seed.Copy()
t_prod.forceMove(seedloc)
t_amount++
qdel(O)
return 1
return 0
//multiply the seeds and delete the item
if(user && !user.temporarilyRemoveItemFromInventory(object)) //couldn't drop the item
return null
for(var/_ in 0 to t_max)
var/obj/item/seeds/t_prod = seed.Copy()
seeds.Add(t_prod)
t_prod.forceMove(seedloc)
qdel(object)
return seeds
/obj/machinery/seed_extractor
name = "seed extractor"
@@ -80,6 +67,7 @@
if(held_item?.get_plant_seed())
context[SCREENTIP_CONTEXT_LMB] = "Make seeds"
context[SCREENTIP_CONTEXT_RMB] = "Make & Store seeds"
return CONTEXTUAL_SCREENTIP_SET
if(istype(held_item, /obj/item/storage/bag/plants) && (locate(/obj/item/seeds) in held_item.contents))
@@ -135,7 +123,17 @@
return TRUE
if(seedify(attacking_item, -1, src, user))
var/list/generated_seeds = seedify(attacking_item, -1, src, user)
if(!isnull(generated_seeds))
if(LAZYACCESS(params2list(params), RIGHT_CLICK))
//find all seeds lying on the turf and add them to the machine
for(var/obj/item/seeds/seed as anything in generated_seeds)
//machine is full
if(contents.len >= max_seeds)
to_chat(user, span_warning("[src] is full."))
break
//add seed to machine. second argument is null which means just force move into the machine
add_seed(seed)
to_chat(user, span_notice("You extract some seeds."))
return TRUE
@@ -176,23 +174,16 @@
* needed to go to the ui handler
*
* to_add - what seed are we adding?
* taking_from - where are we taking the seed from? A mob, a bag, etc?
* user - who is inserting the seed?
* taking_from - where are we taking the seed from? A mob, a bag, etc? If null its means its just laying on the turf so force move it in
**/
/obj/machinery/seed_extractor/proc/add_seed(obj/item/seeds/to_add, atom/taking_from)
if(ismob(taking_from))
var/mob/mob_loc = taking_from
if(!mob_loc.transferItemToLoc(to_add, src))
return FALSE
else if(!taking_from.atom_storage?.attempt_remove(to_add, src, silent = TRUE))
return FALSE
var/seed_id = generate_seed_hash(to_add)
var/list/seed_data
var/has_seed_data // so we remember to add a seed obj weakref to piles[seed_id] at the end of the proc. That way if some reason we runtime in this proc it won't incorrectly add data to the list
if(piles[seed_id])
piles[seed_id]["refs"] += WEAKREF(to_add)
has_seed_data = TRUE
else
var/list/seed_data = list()
seed_data = list()
seed_data["icon"] = sanitize_css_class_name("[initial(to_add.icon)][initial(to_add.icon_state)]")
seed_data["name"] = capitalize(replacetext(to_add.name,"pack of ", ""));
seed_data["lifespan"] = to_add.lifespan
@@ -216,8 +207,8 @@
seed_data["mutatelist"] = list()
for(var/obj/item/seeds/mutant as anything in to_add.mutatelist)
seed_data["mutatelist"] += initial(mutant.plantname)
var/obj/item/food/grown/product = new to_add.product
if(product)
if(to_add.product)
var/obj/item/food/grown/product = new to_add.product
var/datum/reagent/product_distill_reagent = product.distill_reagent
seed_data["distill_reagent"] = initial(product_distill_reagent.name)
var/datum/reagent/product_juice_typepath = product.juice_typepath
@@ -225,8 +216,25 @@
seed_data["grind_results"] = list()
for(var/datum/reagent/reagent as anything in product.grind_results)
seed_data["grind_results"] += initial(reagent.name)
qdel(product)
qdel(product)
if(!isnull(taking_from))
if(ismob(taking_from))
var/mob/mob_loc = taking_from
if(!mob_loc.transferItemToLoc(to_add, src))
return FALSE
else if(!taking_from.atom_storage?.attempt_remove(to_add, src, silent = TRUE))
return FALSE
else
to_add.forceMove(src)
// do this at the end, in case any of the previous steps failed
if(has_seed_data)
piles[seed_id]["refs"] += WEAKREF(to_add)
else
piles[seed_id] = seed_data
return TRUE
/obj/machinery/seed_extractor/ui_state(mob/user)
@@ -60,6 +60,7 @@
/datum/ai_behavior/basic_ranged_attack/minebot
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT
avoid_friendly_fire = TRUE
/datum/ai_planning_subtree/basic_ranged_attack_subtree/minebot/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
@@ -64,6 +64,8 @@
/datum/ai_behavior/basic_ranged_attack/hivebot
action_cooldown = 3 SECONDS
avoid_friendly_fire = TRUE
/datum/ai_behavior/basic_ranged_attack/hivebot_rapid
action_cooldown = 1.5 SECONDS
avoid_friendly_fire = TRUE
@@ -32,7 +32,7 @@
/datum/ai_controller/basic_controller/hivebot/ranged/rapid
planning_subtrees = list(
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/basic_ranged_attack_subtree,
/datum/ai_planning_subtree/basic_ranged_attack_subtree/hivebot_rapid,
/datum/ai_planning_subtree/attack_obstacle_in_path,
/datum/ai_planning_subtree/hive_communicate,
)
@@ -51,7 +51,7 @@
held_state = "mouse_[body_color]" // not handled by variety element
AddElement(/datum/element/animal_variety, "mouse", body_color, FALSE)
AddElement(/datum/element/swabable, CELL_LINE_TABLE_MOUSE, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 10)
AddComponent(/datum/component/squeak, list('sound/effects/mousesqueek.ogg' = 1), 100, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) //as quiet as a mouse or whatever
AddComponent(/datum/component/squeak, list('sound/creatures/mousesqueek.ogg' = 1), 100, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) //as quiet as a mouse or whatever
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
)
@@ -39,6 +39,21 @@
/// Maximum skillchip slots available. Do not reference this var directly and instead call get_max_skillchip_slots()
var/max_skillchip_slots = 5
/// Size modifier for the sprite
var/brain_size = 1
/obj/item/organ/internal/brain/Initialize(mapload)
. = ..()
// Brain size logic
transform = transform.Scale(brain_size)
/obj/item/organ/internal/brain/examine()
. = ..()
if(brain_size < 1)
. += span_notice("It is a bit on the smaller side...")
if(brain_size > 1)
. += span_notice("It is bigger than average...")
/obj/item/organ/internal/brain/Insert(mob/living/carbon/brain_owner, special = FALSE, drop_if_replaced = TRUE, no_id_transfer = FALSE)
. = ..()
if(!.)
@@ -406,6 +421,9 @@
. = ..()
organ_owner.gain_trauma(/datum/brain_trauma/special/bluespace_prophet, TRAUMA_RESILIENCE_ABSOLUTE)
/obj/item/organ/internal/brain/felinid //A bit smaller than average
brain_size = 0.8
////////////////////////////////////TRAUMAS////////////////////////////////////////
/obj/item/organ/internal/brain/proc/has_trauma_type(brain_trauma_type = /datum/brain_trauma, resilience = TRAUMA_RESILIENCE_ABSOLUTE)
@@ -372,7 +372,7 @@
var/obj/item/bodypart/the_part = isbodypart(target_zone) ? target_zone : get_bodypart(check_zone(target_zone)) //keep these synced
// Loop through the clothing covering this bodypart and see if there's any thiccmaterials
if(!(injection_flags & INJECT_CHECK_PENETRATE_THICK))
for(var/obj/item/clothing/iter_clothing in clothingonpart(the_part))
for(var/obj/item/clothing/iter_clothing in get_clothing_on_part(the_part))
if(iter_clothing.clothing_flags & THICKMATERIAL)
. = FALSE
break
@@ -6,21 +6,21 @@
if(isbodypart(def_zone))
var/obj/item/bodypart/bp = def_zone
if(bp)
return checkarmor(def_zone, type)
return check_armor(def_zone, type)
var/obj/item/bodypart/affecting = get_bodypart(check_zone(def_zone))
if(affecting)
return checkarmor(affecting, type)
return check_armor(affecting, type)
//If a specific bodypart is targetted, check how that bodypart is protected and return the value.
//If you don't specify a bodypart, it checks ALL your bodyparts for protection, and averages out the values
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
armorval += checkarmor(BP, type)
armorval += check_armor(BP, type)
organnum++
return (armorval/max(organnum, 1))
/mob/living/carbon/human/proc/checkarmor(obj/item/bodypart/def_zone, damage_type)
/mob/living/carbon/human/proc/check_armor(obj/item/bodypart/def_zone, damage_type)
if(!damage_type)
return 0
var/protection = 100
@@ -32,7 +32,7 @@
return 100 - protection
///Get all the clothing on a specific body part
/mob/living/carbon/human/proc/clothingonpart(obj/item/bodypart/def_zone)
/mob/living/carbon/human/proc/get_clothing_on_part(obj/item/bodypart/def_zone)
var/list/covering_part = list()
var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id, wear_neck) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
for(var/bp in body_parts)
@@ -3,6 +3,7 @@
name = "\improper Tall Boy"
id = SPECIES_TALLBOY
examine_limb_id = SPECIES_HUMAN
changesource_flags = MIRROR_BADMIN | WABBAJACK
bodypart_overrides = list(
BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left,
BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right,
@@ -13,8 +14,10 @@
)
/datum/species/monkey/human_legged
name = "human-legged monkey"
id = SPECIES_MONKEY_HUMAN_LEGGED
examine_limb_id = SPECIES_MONKEY
changesource_flags = MIRROR_BADMIN | WABBAJACK
bodypart_overrides = list(
BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/monkey,
BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/monkey,
@@ -25,8 +28,10 @@
)
/datum/species/monkey/monkey_freak
name = "human-armed monkey"
id = SPECIES_MONKEY_FREAK
examine_limb_id = SPECIES_MONKEY
changesource_flags = MIRROR_BADMIN | WABBAJACK
bodypart_overrides = list(
BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left,
BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right,
@@ -4,6 +4,7 @@
id = SPECIES_FELINE
examine_limb_id = SPECIES_HUMAN
mutant_bodyparts = list("ears" = "Cat", "wings" = "None")
mutantbrain = /obj/item/organ/internal/brain/felinid
mutanttongue = /obj/item/organ/internal/tongue/cat
/* SKYRAT EDIT REMOVAL - CUSTOMIZATION
mutantears = /obj/item/organ/internal/ears/cat
@@ -23,8 +24,6 @@
family_heirlooms = list(/obj/item/toy/cattoy)
/// When false, this is a felinid created by mass-purrbation
var/original_felinid = TRUE
/// Brain size for scaling
var/brain_size = 0.8
// Prevents felinids from taking toxin damage from carpotoxin
/datum/species/human/felinid/handle_chemical(datum/reagent/chem, mob/living/carbon/human/affected, seconds_per_tick, times_fired)
@@ -47,16 +46,6 @@
ears.Insert(target_human, drop_if_replaced = FALSE)
else
mutantears = /obj/item/organ/internal/ears
var/obj/item/organ/internal/brain/current_brain = target_human.get_organ_by_type(/obj/item/organ/internal/brain)
if(current_brain)
current_brain.transform = current_brain.transform.Scale(brain_size) //smaller brain
return ..()
/datum/species/human/felinid/on_species_loss(mob/living/carbon/former_feline, datum/species/old_species, pref_load)
if(iscarbon(former_feline))
var/obj/item/organ/internal/brain/current_brain = former_feline.get_organ_by_type(/obj/item/organ/internal/brain)
if(current_brain)
current_brain.transform = current_brain.transform.Scale(1 / brain_size) //bigger brain
return ..()
/datum/species/human/felinid/randomize_features(mob/living/carbon/human/human_mob)
+17 -1
View File
@@ -394,13 +394,29 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
tts_message_to_use = message_raw
var/list/filter = list()
var/list/special_filter = list()
var/voice_to_use = voice
var/use_radio = FALSE
if(length(voice_filter) > 0)
filter += voice_filter
if(length(tts_filter) > 0)
filter += tts_filter.Join(",")
if(ishuman(src))
var/mob/living/carbon/human/human_speaker = src
if(human_speaker.wear_mask)
var/obj/item/clothing/mask/worn_mask = human_speaker.wear_mask
if(worn_mask.voice_override)
voice_to_use = worn_mask.voice_override
if(worn_mask.voice_filter)
filter += worn_mask.voice_filter
use_radio = worn_mask.use_radio_beeps_tts
if(use_radio)
special_filter += TTS_FILTER_RADIO
if(issilicon(src))
special_filter += TTS_FILTER_SILICON
INVOKE_ASYNC(SStts, TYPE_PROC_REF(/datum/controller/subsystem/tts, queue_tts_message), src, html_decode(tts_message_to_use), message_language, voice, filter.Join(","), listened, message_range = message_range, pitch = pitch, silicon = tts_silicon_voice_effect)
INVOKE_ASYNC(SStts, TYPE_PROC_REF(/datum/controller/subsystem/tts, queue_tts_message), src, html_decode(tts_message_to_use), message_language, voice_to_use, filter.Join(","), listened, message_range = message_range, pitch = pitch, special_filters = special_filter.Join("|"))
var/image/say_popup = image('icons/mob/effects/talk.dmi', src, "[bubble_type][talk_icon_state]", FLY_LAYER)
SET_PLANE_EXPLICIT(say_popup, ABOVE_GAME_PLANE, src)
@@ -32,7 +32,7 @@
lighting_cutoff_red = 30
lighting_cutoff_green = 15
lighting_cutoff_blue = 50
unique_name = 1
unique_name = TRUE
gold_core_spawnable = NO_SPAWN
death_sound = 'sound/voice/hiss6.ogg'
death_message = "lets out a waning guttural screech, green blood bubbling from its maw..."
@@ -91,7 +91,7 @@
projectiletype = /obj/projectile/neurotoxin/damaging
projectilesound = 'sound/weapons/pierce.ogg'
status_flags = 0
unique_name = 0
unique_name = FALSE
var/sterile = 1
var/plants_off = 0
var/egg_cooldown = 30
@@ -28,7 +28,7 @@
maxbodytemp = INFINITY
faction = list(FACTION_CULT)
pressure_resistance = 100
unique_name = 1
unique_name = TRUE
AIStatus = AI_OFF //normal constructs don't have AI
loot = list(/obj/item/ectoplasm)
del_on_death = TRUE
@@ -0,0 +1,6 @@
/obj/effect/mob_spawn/ghost_role/drone/name_mob(mob/living/spawned_mob, forced_name)
if(!forced_name)
var/designation = pick(GLOB.posibrain_names)
forced_name = "Drone ([designation]-[rand(100, 999)])"
return ..()
@@ -45,6 +45,7 @@
current_record["rank"] = person.rank
current_record["species"] = person.species
current_record["wanted"] = person.wanted_status
current_record["voice"] = person.voice
all_records += list(current_record)
if("medical")
+2 -2
View File
@@ -85,7 +85,7 @@
// quick re-check to see if bare_wound_bonus applies, for the benefit of log_wound(), see about getting the check from check_woundings_mods() somehow
if(ishuman(owner))
var/mob/living/carbon/human/human_wearer = owner
var/list/clothing = human_wearer.clothingonpart(src)
var/list/clothing = human_wearer.get_clothing_on_part(src)
for(var/obj/item/clothing/clothes_check as anything in clothing)
// unlike normal armor checks, we tabluate these piece-by-piece manually so we can also pass on appropriate damage the clothing's limbs if necessary
if(clothes_check.get_armor_rating(WOUND))
@@ -242,7 +242,7 @@
if(owner && ishuman(owner))
var/mob/living/carbon/human/human_owner = owner
var/list/clothing = human_owner.clothingonpart(src)
var/list/clothing = human_owner.get_clothing_on_part(src)
for(var/obj/item/clothing/clothes as anything in clothing)
// unlike normal armor checks, we tabluate these piece-by-piece manually so we can also pass on appropriate damage the clothing's limbs if necessary
armor_ablation += clothes.get_armor_rating(WOUND)
+6 -7
View File
@@ -82,14 +82,13 @@
return
if(bodypart_overlay.imprint_on_next_insertion) //We only want this set *once*
// SKYRAT EDIT - Customization - ORIGINAL: bodypart_overlay.set_appearance_from_name(receiver.dna.features[bodypart_overlay.feature_key])
if(receiver.dna.features[bodypart_overlay.feature_key])
bodypart_overlay.set_appearance_from_name(receiver.dna.features[bodypart_overlay.feature_key])
var/feature_name = receiver.dna.features[bodypart_overlay.feature_key]
if (isnull(feature_name))
bodypart_overlay.set_appearance_from_dna(receiver.dna) // SKYRAT EDIT CHANGE - ORIGINAL: feature_name = receiver.dna.species.external_organs[type]
// SKYRAT EDIT CHANGE START - Puts the following line in an else block
else
bodypart_overlay.set_appearance_from_dna(receiver.dna)
// SKYRAT EDIT END
bodypart_overlay.set_appearance_from_name(feature_name)
// SKYRAT EDIT CHANGE END
bodypart_overlay.imprint_on_next_insertion = FALSE
ownerlimb = limb
@@ -184,7 +184,7 @@
languages_native = list(/datum/language/draconic, /datum/language/ashtongue) //SKYRAT EDIT: Ashtongue for Ashwalkers
liked_foodtypes = GORE | MEAT | SEAFOOD | NUTS | BUGS
disliked_foodtypes = GRAIN | DAIRY | CLOTH | GROSS
voice_filter = @{"[0:a] asplit [out0][out2]; [out0] asetrate=%SAMPLE_RATE%*0.9,aresample=%SAMPLE_RATE%,atempo=1/0.9,aformat=channel_layouts=mono,volume=0.2 [p0]; [out2] asetrate=%SAMPLE_RATE%*1.1,aresample=%SAMPLE_RATE%,atempo=1/1.1,aformat=channel_layouts=mono,volume=0.2[p2]; [p0][0][p2] amix=inputs=3"}
/obj/item/organ/internal/tongue/lizard/modify_speech(datum/source, list/speech_args)
var/static/regex/lizard_hiss = new("s+", "g")
var/static/regex/lizard_hiSS = new("S+", "g")
@@ -493,7 +493,7 @@ GLOBAL_LIST_INIT(english_to_zombie, list())
say_mod = "hisses"
taste_sensitivity = 10 // LIZARDS ARE ALIENS CONFIRMED
modifies_speech = TRUE // not really, they just hiss
voice_filter = @{"[0:a] asplit [out0][out2]; [out0] asetrate=%SAMPLE_RATE%*0.8,aresample=%SAMPLE_RATE%,atempo=1/0.8,aformat=channel_layouts=mono [p0]; [out2] asetrate=%SAMPLE_RATE%*1.2,aresample=%SAMPLE_RATE%,atempo=1/1.2,aformat=channel_layouts=mono[p2]; [p0][0][p2] amix=inputs=3"}
// Aliens can only speak alien and a few other languages.
/obj/item/organ/internal/tongue/alien/get_possible_languages()
return list(
@@ -601,6 +601,7 @@ GLOBAL_LIST_INIT(english_to_zombie, list())
toxic_foodtypes = NONE //no food is particularly toxic to ethereals
attack_verb_continuous = list("shocks", "jolts", "zaps")
attack_verb_simple = list("shock", "jolt", "zap")
voice_filter = @{"[0:a] asplit [out0][out2]; [out0] asetrate=%SAMPLE_RATE%*0.99,aresample=%SAMPLE_RATE%,volume=0.3 [p0]; [p0][out2] amix=inputs=2"}
// Ethereal tongues can speak all default + voltaic
/obj/item/organ/internal/tongue/ethereal/get_possible_languages()
+27 -3
View File
@@ -11,20 +11,24 @@
bare_wound_bonus = 15
sharpness = SHARP_EDGED
/obj/item/mutant_hand/zombie/afterattack(atom/target, mob/user, proximity_flag)
/obj/item/mutant_hand/zombie/afterattack(atom/target, mob/living/user, proximity_flag)
. = ..()
if(!proximity_flag)
return
else if(isliving(target))
if(ishuman(target))
try_to_zombie_infect(target)
try_to_zombie_infect(target, user, user.zone_selected)
else
. |= AFTERATTACK_PROCESSED_ITEM
check_feast(target, user)
/proc/try_to_zombie_infect(mob/living/carbon/human/target)
/proc/try_to_zombie_infect(mob/living/carbon/human/target, mob/living/user, def_zone = BODY_ZONE_CHEST)
CHECK_DNA_AND_SPECIES(target)
// Can't zombify with no head
if(!target.get_bodypart(BODY_ZONE_HEAD))
return
if(HAS_TRAIT(target, TRAIT_NO_ZOMBIFY))
// cannot infect any TRAIT_NO_ZOMBIFY human
return
@@ -33,11 +37,31 @@
if(HAS_TRAIT(target, TRAIT_VIRUS_RESISTANCE) && prob(75))
return
var/obj/item/bodypart/actual_limb = target.get_bodypart(def_zone)
// What you hitting bro?
if(!actual_limb)
return
var/limb_damage = actual_limb.get_damage()
var/limb_armor = max(0, target.getarmor(actual_limb, BIO) - 25)
// This is a pretty jank way to do this, but in short:
// if they have thick material on that bodypart it will always need at least 25 previous limb damage to trigger an infection.
// and if their bio armor isn't thick it's a bit weaker.
for(var/obj/item/clothing/iter_clothing in target.get_clothing_on_part(actual_limb))
if(iter_clothing.clothing_flags & THICKMATERIAL)
limb_armor += 25
if(limb_armor > limb_damage)
return
var/obj/item/organ/internal/zombie_infection/infection
infection = target.get_organ_slot(ORGAN_SLOT_ZOMBIE)
if(!infection)
infection = new()
infection.Insert(target)
to_chat(user, span_alien("You see [target] twitch for a moment as [target.p_their()] head is covered in \a [infection] - [target.p_Theyve()] been infected."))
/obj/item/mutant_hand/zombie/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is ripping [user.p_their()] brains out! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -1,4 +0,0 @@
author: "sqnztb"
delete-after: True
changes:
- rscadd: "New medicine to clear up scars, made from synthflesh, ethanol, and miner's salve. Be sure to apply it via patches!"
@@ -1,11 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- qol: "NT CIMs shows how much power the supermatter is releasing."
- qol: "NT CIMs internal energy will adjust its prefix."
- qol: "Energy displays (such as multitooling grid) will use the full range of SI prefixes available, up to the peta prefix if you somehow managed to reach that."
- rscdel: "Removes the per cubic centimeter part of internal energy."
- bugfix: "Fix unnecessary delta time scaling on inactive supermatters."
- bugfix: "Fix high energy zaps not scaling with delta time."
- bugfix: "Fixes grounding rods lying about potential power you can generate."
- code_imp: "Convert supermatter_zap() and tesla_zap() zap_str argument unit to be in joules, and scales everything that uses that argument."
@@ -1,4 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- admin: "First time user connections are now logged"
@@ -1,5 +0,0 @@
author: "LT3"
delete-after: True
changes:
- admin: "Successful restart votes will now restart on the current map"
- code_imp: "End round and persistence data will be saved before executing successful restart vote"
@@ -1,4 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- image: "the security records suspected status is now teal instead of orange"
@@ -1,4 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "Centcom now rejects contraband that somehow makes it way onto the cargo shuttle mid-transit and returns it."
@@ -1,4 +0,0 @@
author: "Rhials"
delete-after: True
changes:
- bugfix: "\"Spooky\" meteors will now properly spawn during halloween."
@@ -1,4 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- image: "adds a frog holoform for pAIs"
@@ -1,4 +0,0 @@
author: "LT3"
delete-after: True
changes:
- spellcheck: "Improved wording in greyscale JSON error message"
@@ -1,5 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "Intellicards in computers are no longer deleted when the computer is destroyed."
- bugfix: "Modular consoles can now be deconstructed by right clicking with a wrench."
@@ -1,5 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- rscadd: "Adds an advanced plastic surgery procedure, allowing you to imitate people in pictures. Simply hold a picture in your offhand of the person you wish to imitate as while conducting the surgery! Remember, it's not foolproof, it only changes your name and voice!"
- rscadd: "You can obtain the disk containing the afromentioned surgery. as a role-restricted item to doctors and roboticists for 1TC, as a rare maint loot and BEPIS technode reward"
@@ -1,4 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "Metalgen can no longer be used to transmute indestructible turfs."
@@ -1,4 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "posibrains can be inserted again"
@@ -0,0 +1,5 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "Selecting \"Monkey\" on a magic mirror will now once again turn you into a Monkey rather than a disgusting freak of nature."
- bugfix: "Tall Boys have once again been barred from joining the Wizard Federation."
@@ -1,4 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "cigarettes no longer smoke themselves from inside your pockets or on your hands."
@@ -1,4 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "you can no longer push watchers (and any other lavaland basic mob) around by running into them"
@@ -1,4 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "The custom error message for when there is only one map to vote for should pop up in all cases rather than just a select few."
@@ -1,4 +0,0 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "Stun immune people should no longer have issues with gripper gloves and other tackle gloves."
@@ -0,0 +1,5 @@
author: "tattle"
delete-after: True
changes:
- qol: "Basic animals now make sounds for audible emotes"
- sound: "Added new sound effects for chicks, chickens, crabs, and insects"
@@ -0,0 +1,4 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "Fixed job configs not being loaded properly."
@@ -0,0 +1,4 @@
author: "Vekter"
delete-after: True
changes:
- rscadd: "Added a holodeck to Birdshot Station. It can be reached via the Crew Facilities hallway."
@@ -0,0 +1,6 @@
author: "SkyratBot"
delete-after: True
changes:
- rscdel: "removes surgical duffelbags"
- bugfix: "the surgery supply order now comes with a surgery tray"
- bugfix: "(skyrat) Hospital gowns will now spawn in surgery trays like they used to in the surgery duffelbags"
@@ -0,0 +1,7 @@
author: "SkyratBot"
delete-after: True
changes:
- qol: "Gas masks now muffle your voice with TTS."
- qol: "Security Hailer masks now disguise your voice to protect your right to brutalize greytiders."
- qol: "Lizards, Ethereals, and Xenomorphs now have a vocal effect."
- qol: "Security Records now show someone's voice name."
@@ -0,0 +1,4 @@
author: "Tattle"
delete-after: True
changes:
- qol: "drones now have individual names, instead of just \"drone\""
@@ -0,0 +1,6 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "You can no longer break the game by AI rolling in a card or APC"
- qol: "AI Roll now doesnt require you to click the exact turf to move you"
- qol: "AI roll cooldown and roll time is now a variable, making it possible for AIs to become terrifying catamari damacy balls"
@@ -0,0 +1,4 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "The flight potion wings will no longer fail to work on lavaland/icemoon on rare occasions."
@@ -0,0 +1,4 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "Fixes full advanced surgery trays spawning with 'nothing'"
@@ -0,0 +1,8 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "Fixed zombies being able to infect headless corpses (Including former zombies)"
- bugfix: "Fixed bio armor being totally useless against zombies. Now it checks how hurt your limb is: If it's more than the bio armor value, you get infected. THICKMATERIAL clothing guarantees at least 25 damage required to infect you, non-thick clothing reduces effective defence by 25. In practice this means people with MODsuits, biosuits will resist infection unless they're pummeled into crit, and wearing a firesuit will save you from the first few slashes."
- bugfix: "Fixed the bomb hood armor not having the same bio armor value as bomb armor."
- qol: "Added a message to the zed when they succesfully infect someone."
- code_imp: "Turned some proc names into snake_case rather than, uh, nospacecase."
@@ -0,0 +1,4 @@
author: "SkyratBot"
delete-after: True
changes:
- spellcheck: "Tweaks the message that players get when not being able to qualify for roundstart antag to be more accurate as to what's happening."
@@ -0,0 +1,4 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "fixed geysers spawning on turfs with plants"
@@ -0,0 +1,11 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "you can now deconstruct exodrone scanner arrays"
- bugfix: "the tree in space exodrone adventure no longer softlocks you"
- qol: "the exodrone launchers now tell you on examine how to remove their fuel canister if you somehow needed to do that"
- balance: "exodrone wide scans are now capped at 10 minutes"
- balance: "exodrone travel times are 18% faster"
- balance: "you can now upgrade scanner arrays for faster wide scan"
- balance: "exodrone point scan and deep scan are faster"
- spellcheck: "fixes several typos related to exodrones and gives scanner control console a description"
@@ -0,0 +1,7 @@
author: "SkyratBot"
delete-after: True
changes:
- bugfix: "Seeds will no longer be removed from existence after receiving the \"You can't seem to add [seed type] to the seed extractor\" message"
- bugfix: "Some seeds that were previously not able to be added to the seed extractor may now be added (starthistle for example)"
- bugfix: "fixes replica pod seeds spawning humans in nullspace"
- qol: "right clicking the seed extractor with a plant/food stores the extracted seeds in the machine."
+58
View File
@@ -1005,3 +1005,61 @@
instead of a random one.
honkpocket:
- rscdel: Removed wall-mushroom outbreak event
2023-09-26:
LT3:
- spellcheck: Improved wording in greyscale JSON error message
- admin: Successful restart votes will now restart on the current map
- code_imp: End round and persistence data will be saved before executing successful
restart vote
Rhials:
- bugfix: '"Spooky" meteors will now properly spawn during halloween.'
SkyratBot:
- image: the security records suspected status is now teal instead of orange
- bugfix: Intellicards in computers are no longer deleted when the computer is destroyed.
- bugfix: Modular consoles can now be deconstructed by right clicking with a wrench.
- bugfix: cigarettes no longer smoke themselves from inside your pockets or on your
hands.
- admin: First time user connections are now logged
- qol: NT CIMs shows how much power the supermatter is releasing.
- qol: NT CIMs internal energy will adjust its prefix.
- qol: Energy displays (such as multitooling grid) will use the full range of SI
prefixes available, up to the peta prefix if you somehow managed to reach that.
- rscdel: Removes the per cubic centimeter part of internal energy.
- bugfix: Fix unnecessary delta time scaling on inactive supermatters.
- bugfix: Fix high energy zaps not scaling with delta time.
- bugfix: Fixes grounding rods lying about potential power you can generate.
- code_imp: Convert supermatter_zap() and tesla_zap() zap_str argument unit to be
in joules, and scales everything that uses that argument.
- rscadd: Adds an advanced plastic surgery procedure, allowing you to imitate people
in pictures. Simply hold a picture in your offhand of the person you wish to
imitate as while conducting the surgery! Remember, it's not foolproof, it only
changes your name and voice!
- rscadd: You can obtain the disk containing the afromentioned surgery. as a role-restricted
item to doctors and roboticists for 1TC, as a rare maint loot and BEPIS technode
reward
- bugfix: Centcom now rejects contraband that somehow makes it way onto the cargo
shuttle mid-transit and returns it.
- bugfix: you can no longer push watchers (and any other lavaland basic mob) around
by running into them
- bugfix: posibrains can be inserted again
- bugfix: Metalgen can no longer be used to transmute indestructible turfs.
- image: adds a frog holoform for pAIs
- bugfix: The custom error message for when there is only one map to vote for should
pop up in all cases rather than just a select few.
- bugfix: Stun immune people should no longer have issues with gripper gloves and
other tackle gloves.
sqnztb:
- rscadd: New medicine to clear up scars, made from synthflesh, ethanol, and miner's
salve. Be sure to apply it via patches!
2023-09-27:
SkyratBot:
- rscadd: added ranged attack friendly fire checks for basic mobs. minebots and
hivebots will now try to avoid shooting their friends
- bugfix: fixed Strong Stone ruin generation
- rscadd: Added a candle box crate for all your candle needs!
- bugfix: '[Tramstation] Mass Driver in chapel now has tiny fan so you don''t space
yourself.'
jjpark-kb:
- bugfix: actually fixed the ash revival ritual for basic mobs
- bugfix: basic animals now will have their health affected positively and negatively
by medicine and toxins respectively.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

@@ -373,5 +373,5 @@
find_animal.faction = list(FACTION_ASHWALKER)
find_animal.revive()
find_animal.revive(HEAL_ALL)
return TRUE
@@ -121,7 +121,7 @@
cost = PAYCHECK_COMMAND
/datum/armament_entry/company_import/deforest/equipment/surgical_tools
item_type = /obj/item/storage/backpack/duffelbag/med/surgery
item_type = /obj/item/surgery_tray/full
cost = PAYCHECK_COMMAND
/datum/armament_entry/company_import/deforest/equipment/advanced_health_analyer
@@ -467,7 +467,7 @@
gender = FEMALE
attack_verb_continuous = list("pats", "hugs", "scolds", "pets")
attack_verb_simple = list("pat", "hug", "scold", "pet")
squeak_override = list('sound/effects/mousesqueek.ogg' = 1, 'modular_skyrat/modules/emotes/sound/voice/mothsqueak.ogg' = 1,)
squeak_override = list('sound/creatures/mousesqueek.ogg' = 1, 'modular_skyrat/modules/emotes/sound/voice/mothsqueak.ogg' = 1,)
responses = list("Rabbits are prey animals and are therefore constantly aware of their surroundings.", "Things to jump up on (they like to be in high places)", "become a rabbit today!", "Be cunning and full of tricks...", "Subscription confirmed! Thank you for choosing RABBITFACTS +TM+!", "Holland Lops are a breed of rabbit originating in the Netherlands.", "Rabbits may need medication to keep themselves healthy, and that's ok! Make sure to take yours too!", "rabbits really liked this product", "A healthy rabbit diet includes fresh vegetables.", "Rabbits do not hibernate. Their schedules are much too busy.", "the rate of bunnies is measured by RPB (rabbits per bunny)", )
/obj/item/toy/plush/skyrat/chunko/andrew
@@ -477,7 +477,7 @@
gender = MALE
attack_verb_continuous = list("pats", "hugs", "scolds", "pets")
attack_verb_simple = list("pat", "hug", "scold", "pet")
squeak_override = list('sound/effects/mousesqueek.ogg' = 1, 'modular_skyrat/modules/emotes/sound/voice/mothsqueak.ogg' = 1,)
squeak_override = list('sound/creatures/mousesqueek.ogg' = 1, 'modular_skyrat/modules/emotes/sound/voice/mothsqueak.ogg' = 1,)
// All lowercase messages are intentional
responses = list("bunny who you best pray you never encounter, lest you suffer a fate worse than death.", "this is a bunny!", "I wonder what would happen if you took bunnies, and combined them with rabbits, and merged their properties and characteristics. It's something to think about.", "If you're cold, they're cold. Give them the deed to your house.", "bunny that goes yeah! woo! yeah! woo! yeah! woo! yeah! woo! yeah! woo! yeah!", "the bunnies are beyond my comprehension", "it's a bunny thing, you wouldn't get it", "this bunny has an unfathomable power level", "%pull the string and I'll bink at you...I'm your bunny.", "Bunny (1954)", "the bunny that pulls the strings....", )
+1 -1
View File
@@ -143,7 +143,7 @@
message = "squeaks!"
emote_type = EMOTE_AUDIBLE
vary = TRUE
sound = 'sound/effects/mousesqueek.ogg'
sound = 'sound/creatures/mousesqueek.ogg'
/datum/emote/living/merp
key = "merp"
@@ -43,7 +43,7 @@
back = /obj/item/storage/backpack
id = /obj/item/card/id/faction_crew
l_pocket = /obj/item/melee/energy/sword
l_hand = /obj/item/storage/backpack/duffelbag/med/surgery
l_hand = /obj/item/surgery_tray/full
backpack_contents = list(/obj/item/storage/box/survival/engineer=1, /obj/item/storage/medkit/tactical=1,/obj/item/storage/medkit/regular=1,/obj/item/storage/medkit/toxin=1, /obj/item/ammo_box/magazine/m45=2, /obj/item/gun/ballistic/automatic/pistol/m1911=1,/obj/item/healthanalyzer=1,/obj/item/stack/spacecash/c1000=1)
/datum/outfit/faction_tech
@@ -15,14 +15,57 @@
/mob/living/simple_animal/Life(seconds_per_tick, times_fired)
. = ..()
if(reagent_health && reagents)
for(var/datum/reagent/reagents_within as anything in reagents.reagent_list)
if(istype(reagents_within, /datum/reagent/toxin))
var/datum/reagent/toxin/toxin_reagent = reagents_within
var/toxin_damage = round(toxin_reagent.toxpwr)
adjustHealth(toxin_damage + 1)
reagents.remove_reagent(toxin_reagent.type, 0.5)
continue
if(istype(reagents_within, /datum/reagent/medicine))
adjustHealth(-1)
reagents.remove_reagent(reagents_within.type, 0.5)
if(!reagent_health)
return
if(!reagents)
return
if(stat == DEAD)
return
for(var/datum/reagent/reagents_within as anything in reagents.reagent_list)
if(istype(reagents_within, /datum/reagent/toxin))
var/datum/reagent/toxin/toxin_reagent = reagents_within
var/toxin_damage = round(toxin_reagent.toxpwr)
adjustHealth(toxin_damage + 1)
reagents.remove_reagent(toxin_reagent.type, 0.5)
continue
if(istype(reagents_within, /datum/reagent/medicine))
adjustHealth(-1)
reagents.remove_reagent(reagents_within.type, 0.5)
/mob/living/basic
/// whether the simple animal can be healed/damaged through reagents
var/reagent_health = TRUE
/mob/living/basic/Initialize(mapload)
. = ..()
if(reagent_health)
create_reagents(1000, REAGENT_HOLDER_ALIVE)
/mob/living/basic/Life(seconds_per_tick, times_fired)
. = ..()
if(!reagent_health)
return
if(!reagents)
return
if(stat == DEAD)
return
for(var/datum/reagent/reagents_within as anything in reagents.reagent_list)
if(istype(reagents_within, /datum/reagent/toxin))
var/datum/reagent/toxin/toxin_reagent = reagents_within
var/toxin_damage = round(toxin_reagent.toxpwr)
adjust_health(toxin_damage + 1)
reagents.remove_reagent(toxin_reagent.type, 0.5)
continue
if(istype(reagents_within, /datum/reagent/medicine))
adjust_health(-1)
reagents.remove_reagent(reagents_within.type, 0.5)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More