Merge branch 'master' into ghost-rad-hud

This commit is contained in:
Matt
2021-08-10 11:14:35 -07:00
committed by GitHub
593 changed files with 28984 additions and 43984 deletions
+1 -1
View File
@@ -377,7 +377,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
to_chat(usr, "Not when you're not dead!")
return
var/datum/async_input/A = input_autocomplete_async(usr, "Area to jump to: ", GLOB.ghostteleportlocs)
var/datum/async_input/A = input_autocomplete_async(usr, "Area to jump to: ", SSmapping.ghostteleportlocs)
A.on_close(CALLBACK(src, .proc/teleport))
/mob/dead/observer/proc/teleport(area/thearea)
+3 -1
View File
@@ -90,6 +90,8 @@
M.show_message(message, m_type)
O.show_message(message, m_type)
if(O.client?.prefs.toggles2 & PREFTOGGLE_2_RUNECHAT)
O.create_chat_message(src, input, symbol = RUNECHAT_SYMBOL_EMOTE)
// Type 2 (Audible) emotes are sent to anyone in hear range
// of the *LOCATION* -- this is important for pAIs to be heard
@@ -116,7 +118,7 @@
return
if(!src.client.holder)
if(!config.dsay_allowed)
if(!GLOB.dsay_enabled)
to_chat(src, "<span class='warning'>Deadchat is globally muted</span>")
return
+8
View File
@@ -486,6 +486,14 @@
flags = RESTRICTED | HIVEMIND | NOBABEL
follow = TRUE
/datum/language/terrorspider/broadcast(mob/living/speaker, message, speaker_mask)
if(isterrorspider(speaker))
var/mob/living/simple_animal/hostile/poison/terror_spider/T = speaker
if(T.loudspeaker)
..(speaker, "<font size=3><b>[message]</b></font>")
return
..(speaker, message)
/datum/language/ling
name = "Changeling"
desc = "Although they are normally wary and suspicious of each other, changelings can commune over a distance."
@@ -126,7 +126,7 @@
/mob/living/carbon/alien/movement_delay()
. = ..()
. += move_delay_add + config.alien_delay //move_delay_add is used to slow aliens with stuns
. += move_delay_add + GLOB.configuration.movement.alien_delay //move_delay_add is used to slow aliens with stuns
/mob/living/carbon/alien/getDNA()
return null
@@ -99,7 +99,7 @@
new_xeno.mind.assigned_role = SPECIAL_ROLE_XENOMORPH
new_xeno.mind.special_role = SPECIAL_ROLE_XENOMORPH
new_xeno << sound('sound/voice/hiss5.ogg',0,0,0,100)//To get the player's attention
to_chat(new_xeno, "<span class='motd'>For more information, check the wiki page: ([config.wikiurl]/index.php/Xenomorph)</span>")
to_chat(new_xeno, "<span class='motd'>For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Xenomorph)</span>")
if(gib_on_success)
owner.gib()
+1 -1
View File
@@ -13,7 +13,7 @@
/mob/living/carbon/brain/Life()
. = ..()
if(.)
if(!container && (world.time - timeofhostdeath) > config.revival_brain_life)
if(!container && (world.time - timeofhostdeath) > GLOB.configuration.general.revival_brain_life)
death()
/mob/living/carbon/brain/breathe()
+4 -2
View File
@@ -404,6 +404,10 @@
/mob/living/carbon/proc/tintcheck()
return 0
/mob/living/carbon/proc/create_dna()
if(!dna)
dna = new()
/mob/living/carbon/proc/getDNA()
return dna
@@ -1126,8 +1130,6 @@ so that different stomachs can handle things in different ways VB*/
//to recalculate and update the mob's total tint from tinted equipment it's wearing.
/mob/living/carbon/proc/update_tint()
if(!GLOB.tinted_weldhelh)
return
var/tinttotal = get_total_tint()
if(tinttotal >= TINT_BLIND)
overlay_fullscreen("tint", /obj/screen/fullscreen/blind)
@@ -320,7 +320,7 @@
for(var/current_species_name in GLOB.all_species)
var/datum/species/current_species = GLOB.all_species[current_species_name]
if(check_whitelist && config.usealienwhitelist && !check_rights(R_ADMIN, 0, src)) //If we're using the whitelist, make sure to check it!
if(check_whitelist && !check_rights(R_ADMIN, 0, src)) //If we're using the whitelist, make sure to check it!
if(whitelist.len && !(current_species_name in whitelist))
continue
if(blacklist.len && (current_species_name in blacklist))
+14 -1
View File
@@ -134,6 +134,8 @@
on_CD = handle_emote_CD()
if("deathgasp", "deathgasps")
on_CD = handle_emote_CD(50)
if("spin", "spins")
on_CD = handle_emote_CD(50)
if("sneeze", "sneezes")
on_CD = handle_emote_CD()
if("clap", "claps")
@@ -443,6 +445,17 @@
message = "<B>[src]</B> does a flip!"
SpinAnimation(5,1)
if("spin", "spins")
if(!restrained() && !lying)
if(prob(5))
spin(30, 1)
message = "<B>[src]</B> spins too much!"
Dizzy(12)
Confused(12)
else
spin(20, 1)
message = "<B>[src]</B> spins!"
if("aflap", "aflaps")
if(!restrained())
message = "<B>[src]</B> flaps [p_their()] wings ANGRILY!"
@@ -950,7 +963,7 @@
var/emotelist = "aflap(s), airguitar, blink(s), blink(s)_r, blush(es), bow(s)-none/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s), cry, cries, custom, dance, dap(s)-none/mob," \
+ " deathgasp(s), drool(s), eyebrow, fart(s), faint(s), flap(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-none/mob, grin(s), groan(s), grumble(s), grin(s)," \
+ " handshake-mob, hug(s)-none/mob, hem, highfive, johnny, jump, kiss(es), laugh(s), look(s)-none/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-none/mob, scream(s), shake(s)," \
+ " shiver(s), shrug(s), sigh(s), signal(s)-#1-10, slap(s), smile(s),snap(s), sneeze(s), sniff(s), snore(s), stare(s)-none/mob, tremble(s), twitch(es), twitch(es)_s," \
+ " shiver(s), shrug(s), sigh(s), signal(s)-#1-10, slap(s), smile(s),snap(s), sneeze(s), sniff(s), snore(s), spin(s) stare(s)-none/mob, tremble(s), twitch(es), twitch(es)_s," \
+ " wave(s), whimper(s), wink(s), yawn(s)"
switch(dna.species.name)
+48 -26
View File
@@ -14,38 +14,47 @@
. = ..()
/mob/living/carbon/human/Initialize(mapload, datum/species/new_species = /datum/species/human)
if(!dna)
dna = new /datum/dna(null)
// Species name is handled by set_species()
create_dna()
. = ..()
set_species(new_species, 1, delay_icon_update = 1, skip_same_check = TRUE)
if(dna.species)
real_name = dna.species.get_random_name(gender)
name = real_name
if(mind)
mind.name = real_name
create_reagents(330)
handcrafting = new()
// Set up DNA.
if(dna)
dna.ready_dna(src)
dna.real_name = real_name
sync_organ_dna(1)
physiology = new()
AddComponent(/datum/component/footstep, FOOTSTEP_MOB_HUMAN, 1, -6)
setup_dna(new_species)
setup_other()
UpdateAppearance()
GLOB.human_list += src
/**
* Sets up DNA and species.
*
* Arguments:
* * new_species - The new species to assign.
*/
/mob/living/carbon/human/proc/setup_dna(datum/species/new_species)
set_species(new_species, use_default_color = TRUE, delay_icon_update = TRUE, skip_same_check = TRUE)
// Name
real_name = dna.species.get_random_name(gender)
name = real_name
if(mind)
mind.name = real_name
// DNA ready
dna.ready_dna(src)
dna.real_name = real_name
sync_organ_dna()
/**
* Sets up other variables and components that may be needed for gameplay.
*/
/mob/living/carbon/human/proc/setup_other()
create_reagents(330)
physiology = new()
/mob/living/carbon/human/ComponentInitialize()
AddComponent(/datum/component/footstep, FOOTSTEP_MOB_HUMAN, 1, -6)
/mob/living/carbon/human/OpenCraftingMenu()
if(!handcrafting)
handcrafting = new()
handcrafting.ui_interact(src)
/mob/living/carbon/human/prepare_data_huds()
@@ -1211,7 +1220,7 @@
sec_hud_set_ID()
/mob/living/carbon/human/proc/set_species(datum/species/new_species, default_colour, delay_icon_update = FALSE, skip_same_check = FALSE, retain_damage = FALSE, transformation = FALSE)
/mob/living/carbon/human/proc/set_species(datum/species/new_species, use_default_color = FALSE, delay_icon_update = FALSE, skip_same_check = FALSE, retain_damage = FALSE, transformation = FALSE)
if(!skip_same_check)
if(dna.species.name == initial(new_species.name))
return
@@ -1246,7 +1255,7 @@
hunger_drain = dna.species.hunger_drain
digestion_ratio = dna.species.digestion_ratio
if(dna.species.base_color && default_colour)
if(dna.species.base_color && use_default_color)
//Apply colour.
skin_colour = dna.species.base_color
else
@@ -1933,3 +1942,16 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
runechat_msg_location = loc
else
runechat_msg_location = src
/mob/living/carbon/human/verb/Examine_OOC()
set name = "Examine Meta-Info (OOC)"
set category = "OOC"
set src in view()
if(GLOB.configuration.general.allow_character_metadata)
if(client)
to_chat(usr, "[src]'s Metainfo:<br>[sanitize(client.prefs.metadata)]")
else
to_chat(usr, "[src] does not have any stored infomation!")
else
to_chat(usr, "OOC Metadata is not supported by this server!")
@@ -37,10 +37,16 @@ emp_act
return 2
if(mind?.martial_art?.deflection_chance) //Some martial arts users can deflect projectiles!
if(!lying && !HAS_TRAIT(src, TRAIT_HULK) && prob(mind.martial_art.deflection_chance)) //But only if they're not lying down, and hulks can't do it
if(!lying && !HAS_TRAIT(src, TRAIT_HULK) && mind.martial_art.try_deflect(src)) //But only if they're not lying down, and hulks can't do it
add_attack_logs(P.firer, src, "hit by [P.type] but got deflected by martial arts '[mind.martial_art]'")
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
return FALSE
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE)
if(mind.martial_art.reroute_deflection)
P.firer = src
P.setAngle(rand(0, 360))
return -1
else
return FALSE
var/obj/item/organ/external/organ = get_organ(check_zone(def_zone))
if(isnull(organ))
@@ -1,7 +1,7 @@
/mob/living/carbon/human/movement_delay()
. = 0
. += ..()
. += config.human_delay
. += GLOB.configuration.movement.human_delay
. += dna.species.movement_delay(src)
/mob/living/carbon/human/Process_Spacemove(movement_dir = 0)
+1 -1
View File
@@ -61,7 +61,7 @@
player_logged++
if(istype(loc, /obj/machinery/cryopod))
return
if(config.auto_cryo_ssd_mins && (player_logged >= (config.auto_cryo_ssd_mins * 30)) && player_logged % 30 == 0)
if(GLOB.configuration.afk.ssd_auto_cryo_minutes && (player_logged >= (GLOB.configuration.afk.ssd_auto_cryo_minutes * 30)) && player_logged % 30 == 0)
var/turf/T = get_turf(src)
if(!is_station_level(T.z))
return
@@ -129,17 +129,11 @@
if((head_organ.dna.species.name in tmp_hair.species_allowed) && (robohead.company in tmp_hair.models_allowed)) //Populate the list of available monitor styles only with styles that the monitor-head is allowed to use.
hair += i
var/file = file2text("config/custom_sprites.txt") //Pulls up the custom_sprites list
var/lines = splittext(file, "\n")
for(var/line in lines) // Looks for lines set up as screen:ckey:screen_name
var/list/Entry = splittext(line, ":") // split lines
for(var/i = 1 to Entry.len)
Entry[i] = trim(Entry[i]) // Cleans up lines
if(Entry.len != 3 || Entry[1] != "screen") // Ignore entries that aren't for screens
continue
if(Entry[2] == H.ckey) // They're in the list? Custom sprite time, var and icon change required
hair += Entry[3] // Adds custom screen to list
if(H.ckey in GLOB.configuration.custom_sprites.ipc_screen_map)
// key: ckey | value: list of icon states
for(var/style in GLOB.configuration.custom_sprites.ipc_screen_map[H.ckey])
hair += style
var/new_style = input(H, "Select a monitor display", "Monitor Display", head_organ.h_style) as null|anything in hair
var/new_color = input("Please select hair color.", "Monitor Color", head_organ.hair_colour) as null|color
@@ -572,9 +572,22 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
standing.alpha = w_uniform.alpha
standing.color = w_uniform.color
overlays_standing[UNIFORM_LAYER] = standing
else
else if(!dna.species.nojumpsuit)
var/list/uniform_slots = list()
var/obj/item/organ/external/L = get_organ(BODY_ZONE_L_LEG)
if(!(L?.status & ORGAN_ROBOT))
uniform_slots += l_store
var/obj/item/organ/external/R = get_organ(BODY_ZONE_R_LEG)
if(!(R?.status & ORGAN_ROBOT))
uniform_slots += r_store
var/obj/item/organ/external/C = get_organ(BODY_ZONE_CHEST)
if(!(C?.status & ORGAN_ROBOT))
uniform_slots += wear_id
uniform_slots += wear_pda
uniform_slots += belt
// Automatically drop anything in store / id / belt if you're not wearing a uniform. //CHECK IF NECESARRY
for(var/obj/item/thing in list(r_store, l_store, wear_id, wear_pda, belt)) // whoever made this
for(var/obj/item/thing in uniform_slots) // whoever made this
if(thing) // you're a piece of fucking garbage
unEquip(thing) // why the fuck would you goddamn do this motherfucking shit
if(client) // INVENTORY CODE IN FUCKING ICON CODE
+6 -19
View File
@@ -92,6 +92,9 @@
to_chat(src, "<span class='warning'>[L] is restrained, you cannot push past.</span>")
return TRUE
if(pulledby == L && a_intent != INTENT_HELP) //prevents boosting the person pulling you, but you can still move through them on help intent
return TRUE
if(L.pulling)
if(ismob(L.pulling))
var/mob/P = L.pulling
@@ -519,22 +522,6 @@
/mob/living/proc/UpdateDamageIcon()
return
/mob/living/proc/Examine_OOC()
set name = "Examine Meta-Info (OOC)"
set category = "OOC"
set src in view()
if(config.allow_Metadata)
if(client)
to_chat(usr, "[src]'s Metainfo:<br>[client.prefs.metadata]")
else
to_chat(usr, "[src] does not have any stored infomation!")
else
to_chat(usr, "OOC Metadata is not supported by this server!")
return
/mob/living/Move(atom/newloc, direct, movetime)
if(buckled && buckled.loc != newloc) //not updating position
if(!buckled.anchored)
@@ -928,15 +915,15 @@
if(forced_look)
. += 3
if(ignorewalk)
. += config.run_speed
. += GLOB.configuration.movement.base_run_speed
else
switch(m_intent)
if(MOVE_INTENT_RUN)
if(drowsyness > 0)
. += 6
. += config.run_speed
. += GLOB.configuration.movement.base_run_speed
if(MOVE_INTENT_WALK)
. += config.walk_speed
. += GLOB.configuration.movement.base_walk_speed
/mob/living/proc/can_use_guns(obj/item/gun/G)
+7 -31
View File
@@ -53,7 +53,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
var/list/connected_robots = list()
var/aiRestorePowerRoutine = 0
//var/list/laws = list()
alarms_listend_for = list("Motion", "Fire", "Atmosphere", "Power", "Camera", "Burglar")
alarms_listend_for = list("Motion", "Fire", "Atmosphere", "Power", "Burglar")
var/viewalerts = 0
var/icon/holo_icon//Default is assigned when AI is created.
var/obj/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye.
@@ -365,20 +365,8 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
if(stat || aiRestorePowerRoutine)
return
if(!custom_sprite) //Check to see if custom sprite time, checking the appopriate file to change a var
var/file = file2text("config/custom_sprites.txt")
var/lines = splittext(file, "\n")
for(var/line in lines)
// split & clean up
var/list/Entry = splittext(line, ":")
for(var/i = 1 to Entry.len)
Entry[i] = trim(Entry[i])
if(Entry.len < 2 || Entry[1] != "ai") //ignore incorrectly formatted entries or entries that aren't marked for AI
continue
if(Entry[2] == ckey) //They're in the list? Custom sprite time, var and icon change required
custom_sprite = 1
if(ckey in GLOB.configuration.custom_sprites.ai_core_ckeys)
custom_sprite = TRUE
var/display_choices = list(
"Monochrome",
@@ -963,21 +951,9 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
if(check_unable())
return
if(!custom_hologram) //Check to see if custom sprite time, checking the appopriate file to change a var
var/file = file2text("config/custom_sprites.txt")
var/lines = splittext(file, "\n")
for(var/line in lines)
// split & clean up
var/list/Entry = splittext(line, ":")
for(var/i = 1 to Entry.len)
Entry[i] = trim(Entry[i])
if(Entry.len < 2 || Entry[1] != "hologram")
continue
if (Entry[2] == ckey) //Custom holograms
custom_hologram = 1 // option is given in hologram menu
if(!custom_hologram)
if(ckey in GLOB.configuration.custom_sprites.ai_hologram_ckeys)
custom_hologram = TRUE
var/input
switch(alert("Would you like to select a hologram based on a crew member, an animal, or switch to a unique avatar?",,"Crew Member","Unique","Animal"))
@@ -1319,7 +1295,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
/mob/living/silicon/ai/proc/open_nearest_door(mob/living/target)
if(!istype(target))
return
if(check_unable(AI_CHECK_WIRELESS))
return
@@ -9,8 +9,9 @@ GLOBAL_LIST_EMPTY(empty_playable_ai_cores)
if(alert("WARNING: This will immediately wipe your core and ghost you, removing your character from the round permanently (similar to cryo and robotic storage). Are you entirely sure you want to do this?",
"Wipe Core", "No", "No", "Yes") != "Yes")
return
cryo_AI()
// We warned you.
/mob/living/silicon/ai/proc/cryo_AI()
GLOB.empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(loc)
GLOB.global_announcer.autosay("[src] has been moved to intelligence storage.", "Artificial Intelligence Oversight")
+4 -5
View File
@@ -125,11 +125,10 @@
laws.sort_laws()
/mob/living/silicon/proc/make_laws()
switch(config.default_laws)
if(0)
laws = new /datum/ai_laws/crewsimov()
else
laws = get_random_lawset()
if(GLOB.configuration.general.random_ai_lawset)
laws = get_random_lawset()
else
laws = new /datum/ai_laws/crewsimov()
/mob/living/silicon/proc/get_random_lawset()
var/list/law_options[0]
+4 -16
View File
@@ -122,7 +122,7 @@
. = ..()
. += slowdown
. += 1 //A bit slower than humans, so they're easier to smash
. += config.robot_delay
. += GLOB.configuration.movement.robot_delay
/mob/living/silicon/pai/update_icons()
if(stat == DEAD)
@@ -286,21 +286,9 @@
//check for custom_sprite
if(!custom_sprite)
var/file = file2text("config/custom_sprites.txt")
var/lines = splittext(file, "\n")
for(var/line in lines)
// split & clean up
var/list/Entry = splittext(line, ":")
for(var/i = 1 to Entry.len)
Entry[i] = trim(Entry[i])
if(Entry.len < 2 || Entry[1] != "pai") //ignore incorrectly formatted entries or entries that aren't marked for pAI
continue
if(Entry[2] == ckey) //They're in the list? Custom sprite time, var and icon change required
custom_sprite = 1
my_choices["Custom"] = "[ckey]-pai"
if(ckey in GLOB.configuration.custom_sprites.pai_holoform_ckeys)
custom_sprite = TRUE
my_choices["Custom"] = "[ckey]-pai"
my_choices = possible_chassis.Copy()
if(custom_sprite)
@@ -48,6 +48,8 @@
if(brute_damage + electronics_damage >= max_damage)
destroy()
SStgui.update_uis(owner.self_diagnosis)
/datum/robot_component/proc/heal_damage(brute, electronics, updating_health = TRUE)
if(installed != 1)
// If it's not installed, can't repair it.
@@ -59,6 +61,8 @@
brute_damage = max(0, brute_damage - brute)
electronics_damage = max(0, electronics_damage - electronics)
SStgui.update_uis(owner.self_diagnosis)
/datum/robot_component/proc/is_powered()
return (installed == 1) && (brute_damage + electronics_damage < max_damage) && (powered)
@@ -68,6 +72,8 @@
return
powered = 1
SStgui.update_uis(owner.self_diagnosis)
/datum/robot_component/proc/disable()
if(!component_disabled)
go_offline()
@@ -85,6 +91,8 @@
else
go_offline()
SStgui.update_uis(owner.self_diagnosis)
/datum/robot_component/proc/go_online()
return
@@ -29,8 +29,8 @@
return FALSE
notransform = 1
canmove = 0
icon = null
invisibility = 101
dust_animation()
if(mmi)
qdel(mmi) //Delete the MMI first so that it won't go popping out.
GLOB.dead_mob_list -= src
@@ -133,6 +133,16 @@
if(emagged)
return FALSE
/mob/living/silicon/robot/drone/detailed_examine()
return "Drones are player-controlled synthetics which are lawed to maintain the station and not \
interact with anyone else, except for other drones. They hold a wide array of tools to build, repair, maintain, and clean. \
They function similarly to other synthetics, in that they require recharging regularly, have laws, and are resilient to many hazards, \
such as fire, radiation, vacuum, and more. Ghosts can join the round as a maintenance drone by using the appropriate verb in the 'ghost' tab. \
An inactive drone can be rebooted by swiping an ID card on it with engineering or robotics access."
/mob/living/silicon/robot/drone/detailed_examine_antag()
return "An Electromagnetic Sequencer can be used to subvert the drone to your cause."
//Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..().
/mob/living/silicon/robot/drone/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/borg/upgrade))
@@ -49,35 +49,6 @@
else
..()
/mob/living/silicon/robot/drone/verb/customize()
set name = "Customize Chassis"
set desc = "Reconfigure your chassis into a customized version."
set category = "Drone"
if(!custom_sprite) //Check to see if custom sprite time, checking the appopriate file to change a var
var/file = file2text("config/custom_sprites.txt")
var/lines = splittext(file, "\n")
for(var/line in lines)
// split & clean up
var/list/Entry = splittext(line, ":")
for(var/i = 1 to Entry.len)
Entry[i] = trim(Entry[i])
if(Entry.len < 2 || Entry[1] != "drone")
continue
if (Entry[2] == ckey) //Custom holograms
custom_sprite = 1 // option is given in hologram menu
if(!custom_sprite)
to_chat(src, "<span class='warning'>Error 404: Custom chassis not found. Revoking customization option.</span>")
else
icon = 'icons/mob/custom_synthetic/custom-synthetic.dmi'
icon_state = "[ckey]-drone"
to_chat(src, "<span class='notice'>You reconfigure your chassis and improve the station through your new aesthetics.</span>")
verbs -= /mob/living/silicon/robot/drone/verb/customize
/mob/living/silicon/robot/drone/get_scooped(mob/living/carbon/grabber)
var/obj/item/holder/H = ..()
if(!istype(H))
@@ -1,3 +1,6 @@
#define DRONE_BUILD_TIME 2 MINUTES
#define MAX_MAINT_DRONES 5
/obj/machinery/drone_fabricator
name = "drone fabricator"
desc = "A large automated factory for producing maintenance drones."
@@ -37,14 +40,14 @@
icon_state = "drone_fab_active"
var/elapsed = world.time - time_last_drone
drone_progress = clamp(round((elapsed / config.drone_build_time) * 100), 0, 100)
drone_progress = clamp(round((elapsed / DRONE_BUILD_TIME) * 100), 0, 100)
if(drone_progress >= 100)
visible_message("[src] voices a strident beep, indicating a drone chassis is prepared.")
/obj/machinery/drone_fabricator/examine(mob/user)
. = ..()
if(produce_drones && drone_progress >= 100 && isobserver(user) && config.allow_drone_spawn && count_drones() < config.max_maint_drones)
if(produce_drones && drone_progress >= 100 && isobserver(user) && count_drones() < MAX_MAINT_DRONES)
. += "<BR><B>A drone is prepared. Select 'Join As Drone' from the Ghost tab to spawn as a maintenance drone.</B>"
/obj/machinery/drone_fabricator/proc/count_drones()
@@ -58,7 +61,7 @@
if(stat & NOPOWER)
return
if(!produce_drones || !config.allow_drone_spawn || count_drones() >= config.max_maint_drones)
if(!produce_drones || count_drones() >= MAX_MAINT_DRONES)
return
if(!player || !isobserver(player.mob))
@@ -80,10 +83,6 @@
set name = "Join As Drone"
set desc = "If there is a powered, enabled fabricator in the game world with a prepared chassis, join as a maintenance drone."
if(!(config.allow_drone_spawn))
to_chat(src, "<span class='warning'>That verb is not currently permitted.</span>")
return
if(stat != DEAD)
return
@@ -99,7 +98,7 @@
return
var/player_age_check = check_client_age(usr.client, 14) // 14 days to play as a drone
if(player_age_check && config.use_age_restriction_for_antags)
if(player_age_check && GLOB.configuration.gamemode.antag_account_age_restriction)
to_chat(usr, "<span class='warning'>This role is not yet available to you. You need to wait another [player_age_check] days.</span>")
return
@@ -141,7 +140,7 @@
if(DF.stat & NOPOWER || !DF.produce_drones)
continue
if(DF.count_drones() >= config.max_maint_drones)
if(DF.count_drones() >= MAX_MAINT_DRONES)
to_chat(src, "<span class='warning'>There are too many active drones in the world for you to spawn.</span>")
return
@@ -150,3 +149,6 @@
return
to_chat(src, "<span class='warning'>There are no available drone spawn points, sorry.</span>")
#undef DRONE_BUILD_TIME
#undef MAX_MAINT_DRONES
@@ -13,6 +13,8 @@
//Cooldown-inducing emotes
if("law","flip","flips","halt") //halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT.
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
if("spin","spins")
on_CD = handle_emote_CD(5 SECONDS)
//Everything else, including typos of the above emotes
else
on_CD = 0 //If it doesn't induce the cooldown, we won't check for the cooldown
@@ -157,8 +159,12 @@
message = "<B>[src]</B> does a flip!"
src.SpinAnimation(5,1)
if("spin","spins")
spin(20, 1)
message = "<B>[src]</B> spins!"
if("help")
to_chat(src, "salute, bow-(none)/mob, clap, flap, aflap, twitch, twitches, nod, deathgasp, glare-(none)/mob, stare-(none)/mob, look,\n law, halt")
to_chat(src, "salute, bow-(none)/mob, clap, flap, aflap, twitch, twitches, nod, deathgasp, glare-(none)/mob, stare-(none)/mob, look,\n law, halt, flip, spin")
..()
+7 -42
View File
@@ -138,6 +138,9 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
radio = new /obj/item/radio/borg(src)
common_radio = radio
if(!cell) // Make sure a new cell gets created *before* executing initialize_components(). The cell component needs an existing cell for it to get set up properly
cell = new default_cell_type(src)
init(alien, connect_to_AI, ai_to_sync_to)
if(has_camera && !camera)
@@ -151,9 +154,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
mmi = new /obj/item/mmi/robotic_brain(src) //Give the borg an MMI if he spawns without for some reason. (probably not the correct way to spawn a robotic brain, but it works)
mmi.icon_state = "boris"
if(!cell) // Make sure a new cell gets created *before* executing initialize_components(). The cell component needs an existing cell for it to get set up properly
cell = new default_cell_type(src)
initialize_components()
//if(!unfinished)
// Create all the robot parts.
@@ -215,20 +215,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
//Check for custom sprite
if(!custom_sprite)
var/file = file2text("config/custom_sprites.txt")
var/lines = splittext(file, "\n")
for(var/line in lines)
// split & clean up
var/list/Entry = splittext(line, ":")
for(var/i = 1 to Entry.len)
Entry[i] = trim(Entry[i])
if(Entry.len < 2 || Entry[1] != "cyborg") //ignore incorrectly formatted entries or entries that aren't marked for cyborg
continue
if(Entry[2] == ckey) //They're in the list? Custom sprite time, var and icon change required
custom_sprite = 1
if(ckey in GLOB.configuration.custom_sprites.cyborg_ckeys)
custom_sprite = TRUE
if(mmi && mmi.brainmob)
mmi.brainmob.name = newname
@@ -296,7 +284,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
else
to_chat(src, "<span class='boldannounce'>Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.</span>")
ghostize()
error("A borg has been destroyed, but its MMI lacked a brainmob, so the mind could not be transferred. Player: [ckey].")
log_runtime(EXCEPTION("A borg has been destroyed, but its MMI lacked a brainmob, so the mind could not be transferred. Player: [ckey]."), src)
mmi = null
if(connected_ai)
connected_ai.connected_robots -= src
@@ -306,6 +294,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
QDEL_NULL(cell)
QDEL_NULL(robot_suit)
QDEL_NULL(spark_system)
QDEL_NULL(self_diagnosis)
return ..()
/mob/living/silicon/robot/proc/pick_module()
@@ -506,30 +495,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
set name = "Show Station Manifest"
show_station_manifest()
/mob/living/silicon/robot/proc/self_diagnosis()
if(!is_component_functioning("diagnosis unit"))
return null
var/dat = "<HEAD><TITLE>[src.name] Self-Diagnosis Report</TITLE></HEAD><BODY>\n"
for(var/V in components)
var/datum/robot_component/C = components[V]
if(C.installed == 0)
dat += "<b>[C.name]</b><br>MISSING<br>"
else
dat += "<b>[C.name]</b>[C.installed == -1 ? "<br>DESTROYED" : ""]<br><table><tr><td>Brute Damage:</td><td>[C.brute_damage]</td></tr><tr><td>Electronics Damage:</td><td>[C.electronics_damage]</td></tr><tr><td>Powered:</td><td>[C.is_powered() ? "Yes" : "No"]</td></tr><tr><td>Toggled:</td><td>[ C.toggled ? "Yes" : "No"]</td></table><br>"
return dat
/mob/living/silicon/robot/verb/self_diagnosis_verb()
set category = "Robot Commands"
set name = "Self Diagnosis"
if(!is_component_functioning("diagnosis unit"))
to_chat(src, "<span class='warning'>Your self-diagnosis component isn't functioning.</span>")
var/dat = self_diagnosis()
src << browse(dat, "window=robotdiagnosis")
/mob/living/silicon/robot/verb/toggle_component()
set category = "Robot Commands"
set name = "Toggle Component"
@@ -385,7 +385,7 @@
/obj/item/holosign_creator/engineering,
/obj/item/gripper,
/obj/item/matter_decompiler,
/obj/item/floor_painter,
/obj/item/painter,
/obj/item/areaeditor/blueprints/cyborg,
/obj/item/stack/sheet/metal/cyborg,
/obj/item/stack/rods/cyborg,
@@ -416,7 +416,11 @@
/obj/item/clothing/mask/gas/sechailer/cyborg
)
emag_modules = list(/obj/item/gun/energy/laser/cyborg)
special_rechargables = list(/obj/item/melee/baton/loaded, /obj/item/gun/energy/disabler/cyborg)
special_rechargables = list(
/obj/item/melee/baton/loaded,
/obj/item/gun/energy/disabler/cyborg,
/obj/item/gun/energy/laser/cyborg
)
/obj/item/robot_module/security/update_cells(unlink_cell = FALSE)
var/obj/item/melee/baton/B = locate(/obj/item/melee/baton/loaded) in modules
@@ -566,6 +570,7 @@
/obj/item/gun/energy/pulse/cyborg,
/obj/item/crowbar/cyborg
)
special_rechargables = list(/obj/item/gun/energy/pulse/cyborg)
// Sydicate assault cyborg module.
/obj/item/robot_module/syndicate
@@ -658,7 +663,10 @@
/obj/item/pickaxe/drill/jackhammer, // for breaking walls to execute flanking moves
/obj/item/borg/destroyer/mobility
)
special_rechargables = list(/obj/item/melee/baton/loaded)
special_rechargables = list(
/obj/item/melee/baton/loaded,
/obj/item/gun/energy/immolator/multi/cyborg
)
/obj/item/robot_module/combat
name = "combat robot module"
@@ -674,7 +682,10 @@
/obj/item/restraints/handcuffs/cable/zipties/cyborg,
/obj/item/pickaxe/drill/jackhammer // for breaking walls to execute flanking moves
)
special_rechargables = list(/obj/item/melee/baton/loaded)
special_rechargables = list(
/obj/item/melee/baton/loaded,
/obj/item/gun/energy/immolator/multi/cyborg
)
// Xenomorph cyborg module.
/obj/item/robot_module/alien/hunter
@@ -716,6 +727,7 @@
/obj/item/soap,
/obj/item/t_scanner,
/obj/item/rpd,
/obj/item/analyzer,
/obj/item/stack/sheet/metal/cyborg,
/obj/item/stack/rods/cyborg,
/obj/item/stack/tile/plasteel/cyborg,
@@ -11,7 +11,7 @@
. += speed
if(module_active && istype(module_active,/obj/item/borg/destroyer/mobility))
. -= 3
. += config.robot_delay
. += GLOB.configuration.movement.robot_delay
/mob/living/silicon/robot/mob_negates_gravity()
return magpulse
+7 -9
View File
@@ -13,9 +13,9 @@
var/list/stating_laws = list()// Channels laws are currently being stated on
var/list/alarms_to_show = list()
var/list/alarms_to_clear = list()
var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
var/list/alarms_listend_for = list("Motion", "Fire", "Atmosphere", "Power", "Camera")
var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0)
var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0)
var/list/alarms_listend_for = list("Motion", "Fire", "Atmosphere", "Power")
//var/list/hud_list[10]
var/list/speech_synthesizer_langs = list() //which languages can be vocalized by the speech synthesizer
var/designation = ""
@@ -61,6 +61,10 @@
/mob/living/silicon/Destroy()
GLOB.silicon_mob_list -= src
QDEL_NULL(atmos_control)
QDEL_NULL(crew_monitor)
QDEL_NULL(law_manager)
QDEL_NULL(power_monitor)
return ..()
/mob/living/silicon/proc/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
@@ -106,9 +110,6 @@
if(alarm_types_show["Power"])
msg += "POWER: [alarm_types_show["Power"]] alarms detected. - "
if(alarm_types_show["Camera"])
msg += "CAMERA: [alarm_types_show["Camera"]] alarms detected. - "
msg += "<A href=?src=[UID()];showalerts=1'>\[Show Alerts\]</a>"
var/msg_text = msg.Join("")
to_chat(src, msg_text)
@@ -132,9 +133,6 @@
if(alarm_types_clear["Power"])
msg += "POWER: [alarm_types_clear["Power"]] alarms cleared. - "
if(alarm_types_show["Camera"])
msg += "CAMERA: [alarm_types_clear["Camera"]] alarms cleared. - "
msg += "<A href=?src=[UID()];showalerts=1'>\[Show Alerts\]</a>"
var/msg_text = msg.Join("")
@@ -18,8 +18,16 @@
/mob/living/silicon/proc/subsystem_power_monitor
)
/mob/living/silicon/robot
var/datum/ui_module/robot_self_diagnosis/self_diagnosis
silicon_subsystems = list(
/mob/living/silicon/robot/proc/self_diagnosis,
/mob/living/silicon/proc/subsystem_law_manager
)
/mob/living/silicon/robot/drone
silicon_subsystems = list(
/mob/living/silicon/robot/proc/self_diagnosis,
/mob/living/silicon/proc/subsystem_law_manager,
/mob/living/silicon/proc/subsystem_power_monitor
)
@@ -33,6 +41,10 @@
law_manager = new(src)
power_monitor = new(src)
/mob/living/silicon/robot/init_subsystems()
. = ..()
self_diagnosis = new(src)
/********************
* Atmos Control *
********************/
@@ -68,3 +80,12 @@
power_monitor.ui_interact(usr, state = GLOB.self_state)
/mob/living/silicon/robot/proc/self_diagnosis()
set category = "Robot Commands"
set name = "Self Diagnosis"
if(!is_component_functioning("diagnosis unit"))
to_chat(src, "<span class='warning'>Your self-diagnosis component isn't functioning.</span>")
return
self_diagnosis.ui_interact(src)
@@ -139,12 +139,22 @@
update_controls()
/mob/living/simple_animal/bot/New()
/*
HEY! LISTEN!
I see you're poking the the bot/New() proc
Assuming you are converting this to Initialize() [yay], please see my note in
code\game\jobs\job\job.dm | /datum/job/proc/get_access()
Theres a useless check that bugs me but needs to exist because these things New()
-AA07
*/
..()
GLOB.bots_list += src
icon_living = icon_state
icon_dead = icon_state
access_card = new /obj/item/card/id(src)
//This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first.
//This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first.
access_card.access += ACCESS_ROBOTICS
set_custom_texts()
Radio = new/obj/item/radio/headset/bot(src)
@@ -94,6 +94,17 @@
/mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
return FALSE
/mob/living/simple_animal/hostile/construct/Life(seconds, times_fired)
if(holy_check(src))
throw_alert("holy_fire", /obj/screen/alert/holy_fire, override = TRUE)
visible_message("<span class='danger'>[src] slowly crumbles to dust in this holy place!</span>", \
"<span class='danger'>Your shell burns as you crumble to dust in this holy place!</span>")
playsound(loc, 'sound/items/welder.ogg', 150, TRUE)
adjustBruteLoss(maxHealth/8)
else
clear_alert("holy_fire", clear_override = TRUE)
return ..()
/////////////////Juggernaut///////////////
@@ -21,13 +21,16 @@
var/yelp_sound = 'sound/creatures/dog_yelp.ogg' //Used on death.
var/last_eaten = 0
footstep_type = FOOTSTEP_MOB_CLAW
var/next_spin_message = 0
/mob/living/simple_animal/pet/dog/verb/chasetail()
set name = "Chase your tail"
set desc = "d'awwww."
set category = "Dog"
visible_message("[src] [pick("dances around", "chases [p_their()] tail")].", "[pick("You dance around", "You chase your tail")].")
if(next_spin_message <= world.time)
visible_message("[src] [pick("dances around", "chases [p_their()] tail")].", "[pick("You dance around", "You chase your tail")].")
next_spin_message = world.time + 5 SECONDS
spin(20, 1)
/mob/living/simple_animal/pet/dog/death(gibbed)
@@ -29,6 +29,7 @@
can_collar = 1
blood_volume = BLOOD_VOLUME_NORMAL
var/obj/item/udder/udder = null
gender = FEMALE
footstep_type = FOOTSTEP_MOB_SHOE
/mob/living/simple_animal/hostile/retaliate/goat/New()
@@ -114,7 +115,7 @@
icon_living = "cow"
icon_dead = "cow_dead"
icon_gib = "cow_gib"
speak = list("moo?","moo","MOOOOOO")
speak = list("Moo?","Moo","MOOOOOO")
speak_emote = list("moos","moos hauntingly")
emote_hear = list("brays")
emote_see = list("shakes its head")
@@ -81,8 +81,8 @@
pixel_y = 8
if(is_type_in_typecache(get_area(loc), invalid_area_typecache))
var/area = pick(GLOB.teleportlocs)
var/area/tp = GLOB.teleportlocs[area]
var/area = pick(SSmapping.teleportlocs)
var/area/tp = SSmapping.teleportlocs[area]
forceMove(pick(get_area_turfs(tp.type)))
if((!current_victim && !admincluwne) || QDELETED(current_victim))
@@ -56,6 +56,12 @@
for(var/obj/structure/spider/S in range(1, get_turf(src)))
return S
/mob/living/simple_animal/hostile/poison/giant_spider/death(gibbed)
. = ..()
if(!.)
return FALSE
SSmobs.giant_spiders--
//nursemaids - these create webs and eggs
/mob/living/simple_animal/hostile/poison/giant_spider/nurse
desc = "Furry and black, it makes you shudder to look at it. This one has brilliant green eyes."
@@ -1,193 +0,0 @@
/mob/living/simple_animal/hostile/headcrab
name = "headcrab"
desc = "A small parasitic creature that would like to connect with your brain stem."
icon = 'icons/mob/headcrab.dmi'
icon_state = "headcrab"
icon_living = "headcrab"
icon_dead = "headcrab_dead"
health = 60
maxHealth = 60
dodging = 1
melee_damage_lower = 5
melee_damage_upper = 10
ranged = 1
ranged_message = "leaps"
ranged_cooldown_time = 40
var/jumpdistance = 4
var/jumpspeed = 1
attacktext = "bites"
attack_sound = 'sound/creatures/headcrab_attack.ogg'
speak_emote = list("hisses")
var/is_zombie = 0
stat_attack = DEAD // Necessary for them to attack (zombify) dead humans
robust_searching = 1
var/host_species = ""
var/list/human_overlays = list()
/mob/living/simple_animal/hostile/headcrab/Life(seconds, times_fired)
if(..() && !stat)
if(!is_zombie && isturf(src.loc))
for(var/mob/living/carbon/human/H in oview(src, 1)) //Only for corpse right next to/on same tile
if(H.stat == DEAD || (!H.check_death_method() && H.health <= HEALTH_THRESHOLD_DEAD))
Zombify(H)
break
if(times_fired % 4 == 0)
for(var/mob/living/simple_animal/K in oview(src, 1)) //Only for corpse right next to/on same tile
if(K.stat == DEAD || (!K.check_death_method() && K.health <= HEALTH_THRESHOLD_DEAD))
visible_message("<span class='danger'>[src] consumes [K] whole!</span>")
if(health < maxHealth)
health += 10
qdel(K)
break
/mob/living/simple_animal/hostile/headcrab/OpenFire(atom/A)
if(check_friendly_fire)
for(var/turf/T in getline(src,A)) // Not 100% reliable but this is faster than simulating actual trajectory
for(var/mob/living/L in T)
if(L == src || L == A)
continue
if(faction_check_mob(L) && !attack_same)
return
visible_message("<span class='danger'><b>[src]</b> [ranged_message] at [A]!</span>")
throw_at(A, jumpdistance, jumpspeed, spin = FALSE, diagonals_first = TRUE)
ranged_cooldown = world.time + ranged_cooldown_time
/mob/living/simple_animal/hostile/headcrab/proc/Zombify(mob/living/carbon/human/H)
if(!H.check_death_method())
H.death()
var/obj/item/organ/external/head/head_organ = H.get_organ("head")
is_zombie = TRUE
if(H.wear_suit)
var/obj/item/clothing/suit/armor/A = H.wear_suit
if(A.armor && A.armor.getRating("melee"))
maxHealth += A.armor.getRating("melee") //That zombie's got armor, I want armor!
maxHealth += 200
health = maxHealth
name = "zombie"
desc = "A corpse animated by the alien being on its head."
melee_damage_lower = 10
melee_damage_upper = 15
ranged = 0
stat_attack = CONSCIOUS // Disables their targeting of dead mobs once they're already a zombie
icon = H.icon
speak = list('sound/creatures/zombie_idle1.ogg','sound/creatures/zombie_idle2.ogg','sound/creatures/zombie_idle3.ogg')
speak_chance = 50
speak_emote = list("groans")
attacktext = "bites"
attack_sound = 'sound/creatures/zombie_attack.ogg'
icon_state = "zombie2_s"
if(head_organ && !(NO_HAIR in H.dna.species.species_traits))
head_organ.h_style = null
H.update_hair()
host_species = H.dna.species.name
human_overlays = H.overlays
update_icons()
H.forceMove(src)
visible_message("<span class='warning'>The corpse of [H.name] suddenly rises!</span>")
/mob/living/simple_animal/hostile/headcrab/death()
..()
if(is_zombie)
qdel(src)
/mob/living/simple_animal/hostile/headcrab/handle_automated_speech() // This way they have different screams when attacking, sometimes. Might be seen as sphagetthi code though.
if(speak_chance)
if(rand(0,200) < speak_chance)
if(speak && speak.len)
playsound(get_turf(src), pick(speak), 200, 1)
/mob/living/simple_animal/hostile/headcrab/Destroy()
if(contents)
for(var/mob/M in contents)
M.loc = get_turf(src)
return ..()
/mob/living/simple_animal/hostile/headcrab/update_icons()
. = ..()
if(is_zombie)
overlays.Cut()
overlays = human_overlays
var/image/I = image('icons/mob/headcrab.dmi', icon_state = "headcrabpod")
if(host_species == "Vox")
I = image('icons/mob/headcrab.dmi', icon_state = "headcrabpod_vox")
else if(host_species == "Gray")
I = image('icons/mob/headcrab.dmi', icon_state = "headcrabpod_gray")
overlays += I
/mob/living/simple_animal/hostile/headcrab/CanAttack(atom/the_target)
if(stat_attack == DEAD && isliving(the_target) && !ishuman(the_target))
var/mob/living/L = the_target
if(L.stat == DEAD)
// Override default behavior of stat_attack, to stop headcrabs targeting dead mobs they cannot infect, such as silicons.
return FALSE
return ..()
/mob/living/simple_animal/hostile/headcrab/fast
name = "fast headcrab"
desc = "A fast parasitic creature that would like to connect with your brain stem."
icon = 'icons/mob/headcrab.dmi'
icon_state = "fast_headcrab"
icon_living = "fast_headcrab"
icon_dead = "fast_headcrab_dead"
health = 40
maxHealth = 40
ranged_cooldown_time = 30
jumpdistance = 8
jumpspeed = 2
speak_emote = list("screech")
/mob/living/simple_animal/hostile/headcrab/fast/update_icons()
. = ..()
if(is_zombie)
overlays.Cut()
overlays = human_overlays
var/image/I = image('icons/mob/headcrab.dmi', icon_state = "fast_headcrabpod")
if(host_species == "Vox")
I = image('icons/mob/headcrab.dmi', icon_state = "fast_headcrabpod_vox")
else if(host_species == "Gray")
I = image('icons/mob/headcrab.dmi', icon_state = "fast_headcrabpod_gray")
overlays += I
/mob/living/simple_animal/hostile/headcrab/fast/Zombify(mob/living/carbon/human/H)
. = ..()
speak = list('sound/creatures/fast_zombie_idle1.ogg','sound/creatures/fast_zombie_idle2.ogg','sound/creatures/fast_zombie_idle3.ogg')
/mob/living/simple_animal/hostile/headcrab/poison
name = "poison headcrab"
desc = "A poison parasitic creature that would like to connect with your brain stem."
icon = 'icons/mob/headcrab.dmi'
icon_state = "poison_headcrab"
icon_living = "poison_headcrab"
icon_dead = "poison_headcrab_dead"
health = 80
maxHealth = 80
ranged_cooldown_time = 50
jumpdistance = 3
jumpspeed = 1
melee_damage_lower = 8
melee_damage_upper = 20
attack_sound = 'sound/creatures/ph_scream1.ogg'
speak_emote = list("screech")
/mob/living/simple_animal/hostile/headcrab/poison/update_icons()
. = ..()
if(is_zombie)
overlays.Cut()
overlays = human_overlays
var/image/I = image('icons/mob/headcrab.dmi', icon_state = "poison_headcrabpod")
if(host_species == "Vox")
I = image('icons/mob/headcrab.dmi', icon_state = "poison_headcrabpod_vox")
else if(host_species == "Gray")
I = image('icons/mob/headcrab.dmi', icon_state = "poison_headcrabpod_gray")
overlays += I
/mob/living/simple_animal/hostile/headcrab/poison/AttackingTarget()
. = ..()
if(iscarbon(target) && target.reagents)
var/inject_target = pick("chest", "head")
var/mob/living/carbon/C = target
if(C.stunned || C.can_inject(null, FALSE, inject_target, FALSE))
if(C.eye_blurry < 60)
C.AdjustEyeBlurry(10)
visible_message("<span class='danger'>[src] buries its fangs deep into the [inject_target] of [target]!</span>")
@@ -408,7 +408,7 @@ Difficulty: Hard
/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in()
return TRUE
/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon)
/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!charging)
..()
@@ -193,7 +193,7 @@
M.Weaken(4) // 8 seconds.
if(iscarbon(M))
web_special_ability(M)
addtimer(CALLBACK(src, .proc/after_carbon_crossed, M), 0.7 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
addtimer(CALLBACK(src, .proc/after_carbon_crossed, M), 7 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
/**
* Called some time after a carbon mob crossed the terror web.
@@ -42,6 +42,6 @@
to_chat(user, "<span class='notice'>Someone else already took this spider.</span>")
return
key = user.key
to_chat(src, "<span class='motd'>For more information, check the wiki page: ([config.wikiurl]/index.php/Terror_Spider)</span>")
to_chat(src, "<span class='motd'>For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Terror_Spider)</span>")
for(var/mob/dead/observer/G in GLOB.player_list)
G.show_message("<i>A ghost has taken control of <b>[src]</b>. ([ghost_follow_link(src, ghost=G)]).</i>")
@@ -25,6 +25,7 @@
regen_points_per_kill = 200 // >2x normal, since they're food reprocessors
idle_ventcrawl_chance = 5
spider_tier = TS_TIER_3
loudspeaker = TRUE
spider_opens_doors = 2
web_type = /obj/structure/spider/terrorweb/mother
var/datum/action/innate/terrorspider/ventsmash/ventsmash_action
@@ -26,6 +26,7 @@
environment_smash = ENVIRONMENT_SMASH_RWALLS
idle_ventcrawl_chance = 0
spider_tier = TS_TIER_3
loudspeaker = TRUE
spider_opens_doors = 2
web_type = /obj/structure/spider/terrorweb/purple
ai_spins_webs = FALSE
@@ -33,6 +33,7 @@
projectilesound = 'sound/weapons/pierce.ogg'
projectiletype = /obj/item/projectile/terrorqueenspit
spider_tier = TS_TIER_4
loudspeaker = TRUE
spider_opens_doors = 2
web_type = /obj/structure/spider/terrorweb/queen
var/spider_spawnfrequency = 1200 // 120 seconds. Default for player queens and NPC queens on station. Awaymission queens have this changed in New()
@@ -137,6 +137,8 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
var/killcount = 0
var/busy = 0 // leave this alone!
var/spider_tier = TS_TIER_1 // 1 for red,gray,green. 2 for purple,black,white, 3 for prince, mother. 4 for queen
/// Does this terror speak loudly on the terror hivemind?
var/loudspeaker = FALSE
var/hasdied = 0
var/list/spider_special_drops = list()
var/attackstep = 0
@@ -312,6 +314,8 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
/mob/living/simple_animal/hostile/poison/terror_spider/Destroy()
GLOB.ts_spiderlist -= src
var/datum/atom_hud/U = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
U.remove_hud_from(src)
handle_dying()
return ..()
@@ -20,6 +20,7 @@
melee_damage_lower = 5
melee_damage_upper = 15
spider_tier = TS_TIER_2
loudspeaker = TRUE
web_type = /obj/structure/spider/terrorweb/white
@@ -49,6 +49,7 @@
name = "venus human trap"
desc = "Now you know how the fly feels."
icon_state = "venus_human_trap"
icon_living = "venus_human_trap"
mob_biotypes = MOB_ORGANIC | MOB_PLANT
layer = MOB_LAYER + 0.9
health = 50
@@ -332,7 +332,7 @@
. = speed
if(forced_look)
. += 3
. += config.animal_delay
. += GLOB.configuration.movement.animal_delay
/mob/living/simple_animal/Stat()
..()
@@ -157,7 +157,7 @@
if(health <= 0) // if damaged, the slime moves twice as slow
. *= 2
. += config.slime_delay
. += GLOB.configuration.movement.slime_delay
/mob/living/simple_animal/slime/update_health_hud()
if(hud_used)
+3 -2
View File
@@ -211,11 +211,12 @@
/mob/living/SetEyeBlurry(amount, updating = TRUE)
. = STATUS_UPDATE_BLURRY
if((!!amount) == (!!eye_blurry)) // We're not changing from + to 0 or vice versa
//if they're both above max or equal that means we won't change the blur filter
if(amount > MAX_EYE_BLURRY_FILTER_SIZE / EYE_BLUR_TO_FILTER_SIZE_MULTIPLIER && eye_blurry > MAX_EYE_BLURRY_FILTER_SIZE / EYE_BLUR_TO_FILTER_SIZE_MULTIPLIER || eye_blurry == amount)
updating = FALSE
. = STATUS_UPDATE_NONE
eye_blurry = max(amount, 0)
// We transitioned to/from 0, so update the eye blur overlays
if(updating)
update_blurry_effects()
+6 -5
View File
@@ -9,12 +9,13 @@
return 0
/mob/living/update_blurry_effects()
if(eyes_blurred())
overlay_fullscreen("blurry", /obj/screen/fullscreen/blurry)
return 1
var/atom/movable/plane_master_controller/game_plane_master_controller = hud_used?.plane_master_controllers[PLANE_MASTERS_GAME]
if(!game_plane_master_controller)
return
if(eye_blurry)
game_plane_master_controller.add_filter("eye_blur", 1, gauss_blur_filter(clamp(eye_blurry * EYE_BLUR_TO_FILTER_SIZE_MULTIPLIER, 0.6, MAX_EYE_BLURRY_FILTER_SIZE)))
else
clear_fullscreen("blurry")
return 0
game_plane_master_controller.remove_filter("eye_blur")
/mob/living/update_druggy_effects()
if(druggy)
+2 -6
View File
@@ -6,7 +6,7 @@
log_access_in(client)
create_attack_log("<font color='red'>Logged in at [atom_loc_line(get_turf(src))]</font>")
create_log(MISC_LOG, "Logged in")
if(config.log_access)
if(GLOB.configuration.logging.access_logging)
for(var/mob/M in GLOB.player_list)
if(M == src) continue
if( M.key && (M.key != key) )
@@ -16,7 +16,7 @@
if( (M.computer_id == client.computer_id) )
if(matches) matches += " and "
matches += "ID ([client.computer_id])"
if(!config.disable_cid_warn_popup)
if(!GLOB.configuration.general.disable_cid_warning_popup)
spawn() alert("You have logged in already with another key this round, please log out of this one NOW or risk being banned!")
if(matches)
if(M.client)
@@ -68,9 +68,5 @@
for(var/datum/alternate_appearance/AA in viewing_alternate_appearances)
AA.display_to(list(src))
if(!fexists("config/config.txt") || !fexists("config/game_options.txt"))
to_chat(src, "<span class='biggerdanger'>The game config files have not been properly set!\n Please copy ALL files from '/config/example' into the parent folder, '/config'.</span>")
log_world("The game config files have not been properly set! Please copy ALL files from /config/example into the parent folder, /config.")
update_client_colour(0)
update_morgue()
+8 -4
View File
@@ -7,14 +7,18 @@
create_log(MISC_LOG, "Logged out")
// `holder` is nil'd out by now, so we check the `admin_datums` array directly
//Only report this stuff if we are currently playing.
if(GLOB.admin_datums[ckey] && SSticker && SSticker.current_state == GAME_STATE_PLAYING)
if(GLOB.admin_datums[ckey] && SSticker.current_state == GAME_STATE_PLAYING)
var/datum/admins/temp_admin = GLOB.admin_datums[ckey]
// Triggers on people with banhammer power only - no mentors tripping the alarm
if(temp_admin.rights & R_BAN)
if(temp_admin.rights & R_MENTOR)
var/list/mentorcounter = staff_countup(R_MENTOR)
if(mentorcounter[1] == 0) // No active mentors
SSdiscord.send2discord_simple(DISCORD_WEBHOOK_MENTOR, "[key_name(src)] logged out - 0 active mentors, [mentorcounter[2]] non-mentor staff, [mentorcounter[3]] inactive mentors.")
else if(temp_admin.rights & R_BAN)
message_admins("Admin logout: [key_name_admin(src)]")
var/list/admincounter = staff_countup(R_BAN)
if(admincounter[1] == 0) // No active admins
SSdiscord.send2discord_simple(DISCORD_WEBHOOK_ADMIN, "[key_name(src)] logged out - No active admins, [admincounter[2]] non-admin staff, [admincounter[3]] inactive staff.")
SSdiscord.send2discord_simple(DISCORD_WEBHOOK_ADMIN, "[key_name(src)] logged out - 0 active admins, [admincounter[2]] non-admin staff, [admincounter[3]] inactive staff.")
..()
update_morgue()
+41 -15
View File
@@ -8,6 +8,7 @@
spellremove(src)
mobspellremove(src)
QDEL_LIST(viruses)
QDEL_LIST(actions)
ghostize()
QDEL_LIST_ASSOC_VAL(tkgrabbed_objects)
for(var/I in tkgrabbed_objects)
@@ -20,6 +21,7 @@
AA.viewers -= src
viewing_alternate_appearances = null
LAssailant = null
runechat_msg_location = null
return ..()
/mob/Initialize(mapload)
@@ -749,7 +751,7 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
set name = "Respawn"
set category = "OOC"
if(!GLOB.abandon_allowed)
if(!GLOB.configuration.general.respawn_enabled)
to_chat(usr, "<span class='warning'>Respawning is disabled.</span>")
return
@@ -1007,7 +1009,8 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
// this function displays the station time in the status panel
/mob/proc/show_stat_station_time()
stat(null, "Round Time: [worldtime2text()]")
stat(null, "Server Uptime: [worldtime2text()]")
stat(null, "Round Time: [ROUND_TIME ? time2text(ROUND_TIME, "hh:mm:ss") : "N/A"]")
stat(null, "Station Time: [station_time_timestamp()]")
// this function displays the shuttles ETA in the status panel if the shuttle has been called
@@ -1352,20 +1355,14 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
set waitfor = 0
if(!spintime || !speed || spintime > 100)
CRASH("Aborted attempted call of /mob/proc/spin with invalid args ([spintime],[speed]) which could have frozen the server.")
var/D = dir
while(spintime >= speed)
var/end_time = world.time + spintime
var/spin_dir = prob(50)
while(world.time <= end_time)
sleep(speed)
switch(D)
if(NORTH)
D = EAST
if(SOUTH)
D = WEST
if(EAST)
D = SOUTH
if(WEST)
D = NORTH
setDir(D)
spintime -= speed
if(spin_dir)
dir = turn(dir, 90)
else
dir = turn(dir, -90)
/mob/proc/is_literate()
return FALSE
@@ -1481,3 +1478,32 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
MA.plane = GAME_PLANE
pic.appearance = MA
flick_overlay(pic, list(client), 10)
GLOBAL_LIST_INIT(holy_areas, typecacheof(list(
/area/chapel
)))
/mob/proc/holy_check()
if(!is_type_in_typecache(loc.loc, GLOB.holy_areas))
return FALSE
if(!mind)
return FALSE
//Allows fullpower vampires to bypass holy areas
var/datum/vampire/vampire = mind.vampire
if(vampire && vampire.get_ability(/datum/vampire_passive/full))
return FALSE
//Allows cult to bypass holy areas once they summon
var/datum/game_mode/gamemode = SSticker.mode
if(iscultist(src) && gamemode.cult_objs.cult_status == NARSIE_HAS_RISEN)
return FALSE
//Execption for Holy Constructs
if(isconstruct(src) && !iscultist(src))
return FALSE
to_chat(src, "<span class='warning'>Your powers are useless on this holy ground.</span>")
return TRUE
+4 -2
View File
@@ -79,7 +79,7 @@
/proc/cannotPossess(A)
var/mob/dead/observer/G = A
if(G.has_enabled_antagHUD && config.antag_hud_restricted)
if(G.has_enabled_antagHUD && GLOB.configuration.general.restrict_antag_hud_rejoin)
return 1
return 0
@@ -116,7 +116,9 @@
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("[question]?", poll_time = 10 SECONDS, min_hours = minhours, source = M)
var/mob/dead/observer/theghost = null
if(LAZYLEN(candidates))
if(length(candidates))
if(QDELETED(M))
return
theghost = pick(candidates)
to_chat(M, "Your mob has been taken over by a ghost!")
message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(M)])")
+4 -1
View File
@@ -169,7 +169,10 @@
n = get_step(mob, direct)
. = mob.SelfMove(n, direct, delay)
mob.setDir(direct)
if(mob.pulling?.face_while_pulling)
mob.setDir(get_dir(mob, mob.pulling)) // Face welding tanks and stuff when pulling
else
mob.setDir(direct)
if((direct & (direct - 1)) && mob.loc == n) //moved diagonally successfully
delay = mob.movement_delay() * 2 //Will prevent mob diagonal moves from smoothing accurately, sadly
+8 -8
View File
@@ -32,11 +32,11 @@
if(client)
client.playtitlemusic()
if(config.player_overflow_cap && config.overflow_server_url) //Overflow rerouting, if set, forces players to be moved to a different server once a player cap is reached. Less rough than a pure kick.
if(src.client.holder) return //admins are immune to overflow rerouting
if(config.overflow_whitelist.Find(lowertext(src.ckey))) return //Whitelisted people are immune to overflow rerouting.
var/tally = 0
for(var/client/C in GLOB.clients)
tally++
if(tally > config.player_overflow_cap)
src << link(config.overflow_server_url)
//Overflow rerouting, if set, forces players to be moved to a different server once a player cap is reached. Less rough than a pure kick.
if(GLOB.configuration.overflow.reroute_cap && GLOB.configuration.overflow.overflow_server_location)
if(client.holder)
return //admins are immune to overflow rerouting
if(ckey in GLOB.configuration.overflow.overflow_whitelist)
return //Whitelisted people are immune to overflow rerouting.
if(length(GLOB.clients) > GLOB.configuration.overflow.reroute_cap)
src << link(GLOB.configuration.overflow.overflow_server_location)
+7 -7
View File
@@ -115,7 +115,7 @@
return FALSE
if(href_list["consent_signed"])
var/datum/db_query/query = SSdbcore.NewQuery("REPLACE INTO [format_table_name("privacy")] (ckey, datetime, consent) VALUES (:ckey, Now(), 1)", list(
var/datum/db_query/query = SSdbcore.NewQuery("REPLACE INTO privacy (ckey, datetime, consent) VALUES (:ckey, Now(), 1)", list(
"ckey" = ckey
))
// If the query fails we dont want them permenantly stuck on being unable to accept TOS
@@ -129,7 +129,7 @@
if(href_list["consent_rejected"])
client.tos_consent = FALSE
to_chat(usr, "<span class='warning'>You must consent to the terms of service before you can join!</span>")
var/datum/db_query/query = SSdbcore.NewQuery("REPLACE INTO [format_table_name("privacy")] (ckey, datetime, consent) VALUES (:ckey, Now(), 0)", list(
var/datum/db_query/query = SSdbcore.NewQuery("REPLACE INTO privacy (ckey, datetime, consent) VALUES (:ckey, Now(), 0)", list(
"ckey" = ckey
))
// If the query fails we dont want them permenantly stuck on being unable to accept TOS
@@ -214,7 +214,7 @@
return
if(client.prefs.species in GLOB.whitelisted_species)
if(!is_alien_whitelisted(src, client.prefs.species) && config.usealienwhitelist)
if(!is_alien_whitelisted(src, client.prefs.species))
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.species]."))
return FALSE
@@ -233,7 +233,7 @@
client.prefs.load_random_character_slot(client)
if(client.prefs.species in GLOB.whitelisted_species)
if(!is_alien_whitelisted(src, client.prefs.species) && config.usealienwhitelist)
if(!is_alien_whitelisted(src, client.prefs.species))
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.species]."))
return FALSE
@@ -257,14 +257,14 @@
if(job.available_in_playtime(client))
return 0
if(config.assistantlimit)
if(GLOB.configuration.jobs.assistant_limit)
if(job.title == "Civilian")
var/count = 0
var/datum/job/officer = SSjobs.GetJob("Security Officer")
var/datum/job/warden = SSjobs.GetJob("Warden")
var/datum/job/hos = SSjobs.GetJob("Head of Security")
count += (officer.current_positions + warden.current_positions + hos.current_positions)
if(job.current_positions > (config.assistantratio * count))
if(job.current_positions > (GLOB.configuration.jobs.assistant_security_ratio * count))
if(count >= 5) // if theres more than 5 security on the station just let assistants join regardless, they should be able to handle the tide
return 1
return 0
@@ -603,7 +603,7 @@
/mob/new_player/proc/is_species_whitelisted(datum/species/S)
if(!S) return 1
return is_alien_whitelisted(src, S.name) || !config.usealienwhitelist || !(IS_WHITELISTED in S.species_traits)
return is_alien_whitelisted(src, S.name) || !(IS_WHITELISTED in S.species_traits)
/mob/new_player/get_gender()
if(!client || !client.prefs) ..()
@@ -616,3 +616,35 @@
/datum/sprite_accessory/socks/black_fishnet
name = "Black Fishnet"
icon_state = "black_fishnet"
/datum/sprite_accessory/socks/stockings_lpink
name = "Stockings (Programmer)"
icon_state = "stockings_lpink"
/datum/sprite_accessory/socks/stockings_purple
name = "Stockings (Purple)"
icon_state = "stockings_purple"
/datum/sprite_accessory/socks/stockings_green
name = "Stockings (Green)"
icon_state = "stockings_green"
/datum/sprite_accessory/socks/stockings_cyan
name = "Stockings (Cyan)"
icon_state = "stockings_cyan"
/datum/sprite_accessory/socks/stockings_orange
name = "Stockings (Orange)"
icon_state = "stockings_orange"
/datum/sprite_accessory/socks/stockings_yellow
name = "Stockings (Yellow)"
icon_state = "stockings_yellow"
/datum/sprite_accessory/socks/stockings_dpink
name = "Stockings (Dark Pink)"
icon_state = "stockings_dpink"
/datum/sprite_accessory/socks/stockings_blue
name = "Stockings (Blue)"
icon_state = "stockings_blue"
+1 -1
View File
@@ -47,7 +47,7 @@
/mob/proc/say_dead(message)
if(client)
if(!client.holder)
if(!config.dsay_allowed)
if(!GLOB.dsay_enabled)
to_chat(src, "<span class='danger'>Deadchat is globally muted.</span>")
return