Merge branch 'master' into upstream-merge-32206

This commit is contained in:
LetterJay
2017-10-29 23:36:39 -04:00
committed by GitHub
28 changed files with 13888 additions and 61 deletions
+1 -4
View File
@@ -1,8 +1,5 @@
{
"map_name": "Box Station",
"map_path": "map_files/BoxStation",
"map_file": "BoxStation.dmm",
"minetype": "lavaland",
"transition_config": "default",
"allow_custom_shuttles": "yes"
"map_file": "BoxStation.dmm"
}
+1 -4
View File
@@ -1,8 +1,5 @@
{
"map_name": "Delta Station",
"map_path": "map_files/Deltastation",
"map_file": "DeltaStation2.dmm",
"minetype": "lavaland",
"transition_config": "default",
"allow_custom_shuttles": "yes"
"map_file": "DeltaStation2.dmm"
}
+1 -4
View File
@@ -1,8 +1,5 @@
{
"map_name": "MetaStation",
"map_path": "map_files/MetaStation",
"map_file": "MetaStation.dmm",
"minetype": "lavaland",
"transition_config": "default",
"allow_custom_shuttles": "yes"
"map_file": "MetaStation.dmm"
}
+1 -4
View File
@@ -1,8 +1,5 @@
{
"map_name": "OmegaStation",
"map_path": "map_files/OmegaStation",
"map_file": "OmegaStation.dmm",
"minetype": "lavaland",
"transition_config": "default",
"allow_custom_shuttles": "yes"
"map_file": "OmegaStation.dmm"
}
+1 -4
View File
@@ -1,8 +1,5 @@
{
"map_name": "PubbyStation",
"map_path": "map_files/PubbyStation",
"map_file": "PubbyStation.dmm",
"minetype": "lavaland",
"transition_config": "default",
"allow_custom_shuttles": "yes"
"map_file": "PubbyStation.dmm"
}
+1 -4
View File
@@ -1,8 +1,5 @@
{
"map_name": "Runtime Station",
"map_path": "map_files/debug",
"map_file": "runtimestation.dmm",
"minetype": "lavaland",
"transition_config": "default",
"allow_custom_shuttles": "no"
"map_file": "runtimestation.dmm"
}
+2
View File
@@ -10,6 +10,8 @@
#define T20C 293.15 // 20degC
#define TCMB 2.7 // -270.3degC
#define SHORT_REAL_LIMIT 16777216
//"fancy" math for calculating time in ms from tick_usage percentage and the length of ticks
//percent_of_tick_used * (ticklag * 100(to convert to ms)) / 100(percent ratio)
//collapsed to percent_of_tick_used * tick_lag
+29
View File
@@ -0,0 +1,29 @@
#define PROFILE_START ;PROFILE_STORE = list();PROFILE_SET;
#define PROFILE_STOP ;PROFILE_STORE = null;
#define PROFILE_SET ;PROFILE_TIME = TICK_USAGE_REAL; PROFILE_LINE = __LINE__; PROFILE_FILE = __FILE__; PROFILE_SLEEPCHECK = world.time;
#define PROFILE_TICK ;\
if (PROFILE_STORE) {\
var/PROFILE_TICK_USAGE_REAL = TICK_USAGE_REAL;\
if (PROFILE_SLEEPCHECK == world.time) {\
var/PROFILE_STRING = "[PROFILE_FILE]:[PROFILE_LINE] - [__FILE__]:[__LINE__]";\
var/list/PROFILE_ITEM = PROFILE_STORE[PROFILE_STRING];\
if (!PROFILE_ITEM) {\
PROFILE_ITEM = new(PROFILE_ITEM_LEN);\
PROFILE_STORE[PROFILE_STRING] = PROFILE_ITEM;\
PROFILE_ITEM[PROFILE_ITEM_TIME] = 0;\
PROFILE_ITEM[PROFILE_ITEM_COUNT] = 0;\
};\
PROFILE_ITEM[PROFILE_ITEM_TIME] += TICK_DELTA_TO_MS(PROFILE_TICK_USAGE_REAL-PROFILE_TIME);\
var/PROFILE_INCR_AMOUNT = min(1, 2**round(PROFILE_ITEM[PROFILE_ITEM_COUNT]/SHORT_REAL_LIMIT));\
if (prob(100/PROFILE_INCR_AMOUNT)) {\
PROFILE_ITEM[PROFILE_ITEM_COUNT] += PROFILE_INCR_AMOUNT;\
};\
};\
PROFILE_SET;\
};
#define PROFILE_ITEM_LEN 2
#define PROFILE_ITEM_TIME 1
#define PROFILE_ITEM_COUNT 2
+9
View File
@@ -58,4 +58,13 @@ GLOBAL_VAR_INIT(cmp_field, "name")
. = B.failures - A.failures
if (!.)
. = B.qdels - A.qdels
/proc/cmp_profile_avg_time_dsc(list/A, list/B)
return (B[PROFILE_ITEM_TIME]/(B[PROFILE_ITEM_COUNT] || 1)) - (A[PROFILE_ITEM_TIME]/(A[PROFILE_ITEM_COUNT] || 1))
/proc/cmp_profile_time_dsc(list/A, list/B)
return B[PROFILE_ITEM_TIME] - A[PROFILE_ITEM_TIME]
/proc/cmp_profile_count_dsc(list/A, list/B)
return B[PROFILE_ITEM_COUNT] - A[PROFILE_ITEM_COUNT]
+18
View File
@@ -1411,3 +1411,21 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
//checks if a turf is in the planet z list.
/proc/turf_z_is_planet(turf/T)
return GLOB.z_is_planet["[T.z]"]
//returns a GUID like identifier (using a mostly made up record format)
//guids are not on their own suitable for access or security tokens, as most of their bits are predictable.
// (But may make a nice salt to one)
/proc/GUID()
var/const/GUID_VERSION = "b"
var/const/GUID_VARIANT = "d"
var/node_id = copytext(md5("[rand()*rand(1,9999999)][world.name][world.hub][world.hub_password][world.internet_address][world.address][world.contents.len][world.status][world.port][rand()*rand(1,9999999)]"), 1, 13)
var/time_high = "[num2hex(text2num(time2text(world.realtime,"YYYY")), 2)][num2hex(world.realtime, 6)]"
var/time_mid = num2hex(world.timeofday, 4)
var/time_low = num2hex(world.time, 3)
var/time_clock = num2hex(TICK_DELTA_TO_MS(world.tick_usage), 3)
return "{[time_high]-[time_mid]-[GUID_VERSION][time_low]-[GUID_VARIANT][time_clock]-[node_id]}"
+2 -1
View File
@@ -15,7 +15,7 @@
Override makes it so the alert is not replaced until cleared by a clear_alert with clear_override, and it's used for hallucinations.
*/
if(!category)
if(!category || QDELETED(src))
return
var/obj/screen/alert/thealert
@@ -629,4 +629,5 @@ so as to remain in compliance with the most up-to-date laws."
. = ..()
severity = 0
master = null
mob_viewer = null
screen_loc = ""
+60
View File
@@ -0,0 +1,60 @@
/datum/component/spooky
var/too_spooky = TRUE //will it spawn a new instrument?
/datum/component/spooky/Initialize()
RegisterSignal(COMSIG_ITEM_ATTACK, .proc/spectral_attack)
/datum/component/spooky/proc/spectral_attack(mob/living/carbon/C, mob/user)
if(ishuman(user)) //this weapon wasn't meant for mortals.
var/mob/living/carbon/human/U = user
if(!istype(U.dna.species, /datum/species/skeleton))
U.adjustStaminaLoss(35) //Extra Damage
U.Jitter(35)
U.stuttering = 20
if(U.getStaminaLoss() > 95)
to_chat(U, "<font color ='red', size ='4'><B>Your ears weren't meant for this spectral sound.</B></font>")
spectral_change(U)
return
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(istype(H.dna.species, /datum/species/skeleton))
return ..() //undeads are unaffected by the spook-pocalypse.
if(istype(H.dna.species, /datum/species/zombie))
H.adjustStaminaLoss(25)
H.Knockdown(15) //zombies can't resist the doot
C.Jitter(35)
C.stuttering = 20
if((!istype(H.dna.species, /datum/species/skeleton)) && (!istype(H.dna.species, /datum/species/golem)) && (!istype(H.dna.species, /datum/species/android)) && (!istype(H.dna.species, /datum/species/jelly)))
C.adjustStaminaLoss(25) //boneless humanoids don't lose the will to live
to_chat(C, "<font color='red' size='4'><B>DOOT</B></span>")
spectral_change(H)
else //the sound will spook monkeys.
C.Jitter(15)
C.stuttering = 20
/datum/component/spooky/proc/spectral_change(mob/living/carbon/human/H, mob/user)
if((H.getStaminaLoss() > 95) && (!istype(H.dna.species, /datum/species/skeleton)) && (!istype(H.dna.species, /datum/species/golem)) && (!istype(H.dna.species, /datum/species/android)) && (!istype(H.dna.species, /datum/species/jelly)))
H.Knockdown(20)
H.set_species(/datum/species/skeleton)
H.visible_message("<span class='warning'>[H] has given up on life as a mortal.</span>")
var/T = get_turf(H)
if(too_spooky)
if(prob(30))
new/obj/item/device/instrument/saxophone/spectral(T)
else if(prob(30))
new/obj/item/device/instrument/trumpet/spectral(T)
else if(prob(30))
new/obj/item/device/instrument/trombone/spectral(T)
else
to_chat(H, "The spooky gods forgot to ship your instrument. Better luck next unlife.")
to_chat(H, "<B>You are the spooky skeleton!</B>")
to_chat(H, "A new life and identity has begun. Help your fellow skeletons into bringing out the spooky-pocalypse. You haven't forgotten your past life, and are still beholden to past loyalties.")
change_name(H) //time for a new name!
/datum/component/spooky/proc/change_name(mob/living/carbon/human/H)
var/t = stripped_input(H, "Enter your new skeleton name", H.real_name, null, MAX_NAME_LEN)
if(!t)
t = "spooky skeleton"
H.fully_replace_character_name(H.real_name, t)
+6 -12
View File
@@ -13,7 +13,6 @@
//Order matters here.
var/list/transition_config = list(CENTCOM = SELFLOOPING,
CITY_OF_COGS = SELFLOOPING,
MAIN_STATION = CROSSLINKED,
EMPTY_AREA_1 = CROSSLINKED,
EMPTY_AREA_2 = CROSSLINKED,
@@ -69,12 +68,11 @@
map_path = json["map_path"]
map_file = json["map_file"]
minetype = json["minetype"]
allow_custom_shuttles = json["allow_custom_shuttles"]
minetype = json["minetype"] || minetype
allow_custom_shuttles = json["allow_custom_shuttles"] == TRUE
var/list/jtcl = json["transition_config"]
if(jtcl != "default")
var/jtcl = json["transition_config"]
if(jtcl && jtcl != "default")
transition_config.Cut()
for(var/I in jtcl)
@@ -87,9 +85,6 @@
CHECK_EXISTS("map_name")
CHECK_EXISTS("map_path")
CHECK_EXISTS("map_file")
CHECK_EXISTS("minetype")
CHECK_EXISTS("transition_config")
CHECK_EXISTS("allow_custom_shuttles")
var/path = GetFullMapPath(json["map_path"], json["map_file"])
if(!fexists(path))
@@ -102,11 +97,10 @@
log_world("transition_config is not a list!")
return
var/list/jtcl = json["transition_config"]
for(var/I in jtcl)
for(var/I in tc)
if(isnull(TransitionStringToEnum(I)))
log_world("Invalid transition_config option: [I]!")
if(isnull(TransitionStringToEnum(jtcl[I])))
if(isnull(TransitionStringToEnum(tc[I])))
log_world("Invalid transition_config option: [I]!")
return TRUE
+18
View File
@@ -0,0 +1,18 @@
//these are real globals so you can use profiling to profile early world init stuff.
GLOBAL_REAL_VAR(list/PROFILE_STORE)
GLOBAL_REAL_VAR(PROFILE_LINE)
GLOBAL_REAL_VAR(PROFILE_FILE)
GLOBAL_REAL_VAR(PROFILE_SLEEPCHECK)
GLOBAL_REAL_VAR(PROFILE_TIME)
/proc/profile_show(user, sort = /proc/cmp_profile_avg_time_dsc)
sortTim(PROFILE_STORE, sort, TRUE)
var/list/lines = list()
for (var/entry in PROFILE_STORE)
var/list/data = PROFILE_STORE[entry]
lines += "[entry] => [num2text(data[PROFILE_ITEM_TIME], 10)]ms ([data[PROFILE_ITEM_COUNT]]) (avg:[num2text(data[PROFILE_ITEM_TIME]/(data[PROFILE_ITEM_COUNT] || 1), 99)])"
user << browse("<ol><li>[lines.Join("</li><li>")]</li></ol>", "window=[url_encode(GUID())]")
+4 -2
View File
@@ -98,7 +98,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
var/z_original = ZLEVEL_STATION_PRIMARY
var/threat = 0 // used for determining which meteors are most interesting
var/lifetime = DEFAULT_METEOR_LIFETIME
var/timerid = null
var/list/meteordrop = list(/obj/item/ore/iron)
var/dropamt = 2
@@ -117,6 +117,8 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
get_hit()
/obj/effect/meteor/Destroy()
if (timerid)
deltimer(timerid)
GLOB.meteor_list -= src
SSaugury.unregister_doom(src)
walk(src,0) //this cancels the walk_towards() proc
@@ -127,7 +129,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
GLOB.meteor_list += src
SSaugury.register_doom(src, threat)
SpinAnimation()
QDEL_IN(src, lifetime)
timerid = QDEL_IN(src, lifetime)
chase_target(target)
/obj/effect/meteor/Collide(atom/A)
+58 -1
View File
@@ -110,6 +110,30 @@
item_state = "accordion"
instrumentId = "accordion"
/obj/item/device/instrument/trumpet
name = "trumpet"
desc = "To announce the arrival of the king!"
icon_state = "trumpet"
item_state = "trombone"
instrumentId = "trombone"
/obj/item/device/instrument/trumpet/spectral
name = "spectral trumpet"
desc = "Things are about to get spooky!"
icon_state = "trumpet"
item_state = "trombone"
force = 0
instrumentId = "trombone"
attack_verb = list("played","jazzed","trumpeted","mourned","dooted","spooked")
/obj/item/device/instrument/trumpet/spectral/Initialize()
. = ..()
AddComponent(/datum/component/spooky)
/obj/item/device/instrument/trumpet/spectral/attack(mob/living/carbon/C, mob/user)
playsound (loc, 'sound/instruments/trombone/En4.mid', 100,1,-1)
..()
/obj/item/device/instrument/saxophone
name = "saxophone"
desc = "This soothing sound will be sure to leave your audience in tears."
@@ -117,6 +141,23 @@
item_state = "saxophone"
instrumentId = "saxophone"
/obj/item/device/instrument/saxophone/spectral
name = "spectral saxophone"
desc = "This spooky sound will be sure to leave mortals in bones."
icon_state = "saxophone"
item_state = "saxophone"
instrumentId = "saxophone"
force = 0
attack_verb = list("played","jazzed","saxxed","mourned","dooted","spooked")
/obj/item/device/instrument/saxophone/spectral/Initialize()
. = ..()
AddComponent(/datum/component/spooky)
/obj/item/device/instrument/saxophone/spectral/attack(mob/living/carbon/C, mob/user)
playsound (loc, 'sound/instruments/saxophone/En4.mid', 100,1,-1)
..()
/obj/item/device/instrument/trombone
name = "trombone"
desc = "How can any pool table ever hope to compete?"
@@ -124,6 +165,23 @@
item_state = "trombone"
instrumentId = "trombone"
/obj/item/device/instrument/trombone/spectral
name = "spectral trombone"
desc = "A skeleton's favorite instrument. Apply directly on the mortals."
instrumentId = "trombone"
icon_state = "trombone"
item_state = "trombone"
force = 0
attack_verb = list("played","jazzed","tromboned","mourned","dooted","spooked")
/obj/item/device/instrument/trombone/spectral/Initialize()
. = ..()
AddComponent(/datum/component/spooky)
/obj/item/device/instrument/trombone/spectral/attack(mob/living/carbon/C, mob/user)
playsound (loc, 'sound/instruments/trombone/Cn4.mid', 100,1,-1)
..()
/obj/item/device/instrument/recorder
name = "recorder"
desc = "Just like in school, playing ability and all."
@@ -163,4 +221,3 @@
throw_speed = 3
throw_range = 15
hitsound = 'sound/items/bikehorn.ogg'
+40 -1
View File
@@ -780,7 +780,7 @@ GLOBAL_PROTECT(LastAdminCalledProc)
/client/proc/cmd_display_init_log()
set category = "Debug"
set name = "Display Initialzie() Log"
set name = "Display Initialize() Log"
set desc = "Displays a list of things that didn't handle Initialize() properly"
usr << browse(replacetext(SSatoms.InitLog(), "\n", "<br>"), "window=initlog")
@@ -873,3 +873,42 @@ GLOBAL_PROTECT(LastAdminCalledProc)
message_admins("<span class='adminnotice'>[key_name_admin(src)] pumped a random event.</span>")
SSblackbox.add_details("admin_verb","Pump Random Event")
log_admin("[key_name(src)] pumped a random event.")
/client/proc/start_line_profiling()
set category = "Profile"
set name = "Start Line Profiling"
set desc = "Starts tracking line by line profiling for code lines that support it"
PROFILE_START
message_admins("<span class='adminnotice'>[key_name_admin(src)] started line by line profiling.</span>")
SSblackbox.add_details("admin_verb","Start Line Profiling")
log_admin("[key_name(src)] started line by line profiling.")
/client/proc/stop_line_profiling()
set category = "Profile"
set name = "Stops Line Profiling"
set desc = "Stops tracking line by line profiling for code lines that support it"
PROFILE_STOP
message_admins("<span class='adminnotice'>[key_name_admin(src)] stopped line by line profiling.</span>")
SSblackbox.add_details("admin_verb","stop Line Profiling")
log_admin("[key_name(src)] stopped line by line profiling.")
/client/proc/show_line_profiling()
set category = "Profile"
set name = "Show Line Profiling"
set desc = "Shows tracked profiling info from code lines that support it"
var/sortlist = list(
"Avg time" = /proc/cmp_profile_avg_time_dsc,
"Total Time" = /proc/cmp_profile_time_dsc,
"Call Count" = /proc/cmp_profile_count_dsc
)
var/sort = input(src, "Sort type?", "Sort Type", "Avg time") as null|anything in sortlist
if (!sort)
return
sort = sortlist[sort]
profile_show(src, sort)
+4 -1
View File
@@ -42,7 +42,10 @@ GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list(
/client/proc/print_pointers,
/client/proc/cmd_show_at_list,
/client/proc/cmd_show_at_markers,
/client/proc/manipulate_organs
/client/proc/manipulate_organs,
/client/proc/start_line_profiling,
/client/proc/stop_line_profiling,
/client/proc/show_line_profiling
))
/obj/effect/debugging/mapfix_marker
+1 -1
View File
@@ -40,7 +40,7 @@
/datum/round_event_control/proc/canSpawnEvent(var/players_amt, var/gamemode)
if(occurrences >= max_occurrences)
return FALSE
if(earliest_start >= world.time)
if(earliest_start >= world.time-SSticker.round_start_time)
return FALSE
if(wizardevent != SSevents.wizardmode)
return FALSE
@@ -0,0 +1,149 @@
/datum/species/dullahan
name = "dullahan"
id = "dullahan"
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,NOBREATH,NOHUNGER)
mutant_bodyparts = list("tail_human", "ears", "wings")
default_features = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "wings" = "None")
use_skintones = TRUE
mutant_brain = /obj/item/organ/brain/dullahan
mutanteyes = /obj/item/organ/eyes/dullahan
mutanttongue = /obj/item/organ/tongue/dullahan
mutantears = /obj/item/organ/ears/dullahan
blacklisted = TRUE
limbs_id = "human"
skinned_type = /obj/item/stack/sheet/animalhide/human
var/obj/item/dullahan_relay/myhead
/datum/species/dullahan/check_roundstart_eligible()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
return TRUE
return FALSE
/datum/species/dullahan/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
. = ..()
var/obj/item/bodypart/head/head = H.get_bodypart("head")
if(head)
head.drop_limb()
head.flags_1 = HEAR_1
head.throwforce = 25
myhead = new /obj/item/dullahan_relay (head, H)
H.put_in_hands(head)
/datum/species/dullahan/on_species_loss(mob/living/carbon/human/H)
if(myhead)
var/obj/item/dullahan_relay/DR = myhead
myhead = null
DR.owner = null
qdel(DR)
..()
/datum/species/dullahan/spec_life(mob/living/carbon/human/H)
if(!QDELETED(myhead))
update_vision_perspective(H)
var/turf/Me = get_turf(H)
var/turf/Head = get_turf(myhead)
if(Me == Head || (Head in oview(7, Me)))
H.disabilities &= ~DEAF
else
H.disabilities |= DEAF
else
myhead = null
H.gib()
var/obj/item/bodypart/head/head2 = H.get_bodypart("head")
if(head2)
myhead = null
H.gib()
/datum/species/dullahan/proc/update_vision_perspective(mob/living/carbon/human/H)
var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
if(eyes)
H.update_tint()
if(eyes.tint)
H.reset_perspective(H)
else
H.reset_perspective(myhead)
/obj/item/organ/brain/dullahan
decoy_override = TRUE
vital = FALSE
/obj/item/organ/tongue/dullahan
zone = "abstract"
/obj/item/organ/tongue/dullahan/TongueSpeech(var/message)
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
if(H.dna.species.id == "dullahan")
var/datum/species/dullahan/D = H.dna.species
if(isobj(D.myhead.loc))
var/obj/O = D.myhead.loc
O.say(message)
message = ""
return message
/obj/item/organ/ears/dullahan
zone = "abstract"
/obj/item/organ/eyes/dullahan
name = "head vision"
desc = "An abstraction."
actions_types = list(/datum/action/item_action/organ_action/dullahan)
zone = "abstract"
/datum/action/item_action/organ_action/dullahan
name = "Toggle Perspective"
desc = "Switch between seeing normally from your head, or blindly from your body."
/datum/action/item_action/organ_action/dullahan/Trigger()
. = ..()
var/obj/item/organ/eyes/dullahan/DE = target
if(DE.tint)
DE.tint = 0
else
DE.tint = INFINITY
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
if(H.dna.species.id == "dullahan")
var/datum/species/dullahan/D = H.dna.species
D.update_vision_perspective(H)
/obj/item/dullahan_relay
var/mob/living/owner
flags_1 = HEAR_1
/obj/item/dullahan_relay/Initialize(mapload,new_owner)
. = ..()
owner = new_owner
START_PROCESSING(SSobj, src)
/obj/item/dullahan_relay/process()
if(!istype(loc, /obj/item/bodypart/head) || QDELETED(owner))
. = PROCESS_KILL
qdel(src)
/obj/item/dullahan_relay/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
if(!QDELETED(owner))
var/turf/T = get_turf(speaker)
var/turf/owner_turf = get_turf(owner)
if(T == owner_turf || (T in oview(7, owner_turf))) //Do not relay things we can already hear
return
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
to_chat(owner,message)
else
qdel(src)
/obj/item/dullahan_relay/Destroy()
if(!QDELETED(owner))
var/mob/living/carbon/human/H = owner
if(H.dna.species.id == "dullahan")
var/datum/species/dullahan/D = H.dna.species
D.myhead = null
owner.gib()
owner = null
..()
@@ -24,9 +24,8 @@
to_chat(C, "[info_text]")
C.skin_tone = "albino"
C.update_body(0)
if(C.mind)
var/obj/effect/proc_holder/spell/targeted/shapeshift/bat/B = new
C.mind.AddSpell(B)
var/obj/effect/proc_holder/spell/targeted/shapeshift/bat/B = new
C.AddSpell(B)
/datum/species/vampire/on_species_loss(mob/living/carbon/C)
. = ..()
@@ -45,7 +44,7 @@
C.adjustOxyLoss(-4)
C.adjustCloneLoss(-4)
return
C.blood_volume -= 1.5
C.blood_volume -= 0.75
if(C.blood_volume <= BLOOD_VOLUME_SURVIVE)
to_chat(C, "<span class='danger'>You ran out of blood!</span>")
C.dust()
@@ -123,8 +122,4 @@
invocation = "Squeak!"
charge_max = 50
cooldown_min = 50
shapeshift_type = /mob/living/simple_animal/hostile/retaliate/bat
current_shapes = list(/mob/living/simple_animal/hostile/retaliate/bat)
current_casters = list()
possible_shapes = list(/mob/living/simple_animal/hostile/retaliate/bat)
@@ -34,4 +34,7 @@
//Space bats need no air to fly in.
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
minbodytemp = 0
/mob/living/simple_animal/hostile/retaliate/bat/Process_Spacemove(movement_dir = 0)
return 1
+2
View File
@@ -4,6 +4,8 @@
GLOB.living_mob_list -= src
GLOB.all_clockwork_mobs -= src
GLOB.mob_directory -= tag
for (var/alert in alerts)
clear_alert(alert, TRUE)
if(observers && observers.len)
for(var/M in observers)
var/mob/dead/observe = M
@@ -22,6 +22,11 @@
/mob/living/simple_animal/hostile/construct/armored)
/obj/effect/proc_holder/spell/targeted/shapeshift/cast(list/targets,mob/user = usr)
if(src in user.mob_spell_list)
user.mob_spell_list.Remove(src)
user.mind.AddSpell(src)
if(user.buckled)
user.buckled.unbuckle_mob(src,force=TRUE)
for(var/mob/living/M in targets)
if(!shapeshift_type)
var/list/animal_list = list()
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB

+2 -9
View File
@@ -155,24 +155,17 @@ As a Cultist, you can create an army of manifested goons using a combination of
As a Cultist or Servant, check the alert in the upper-right of your screen for all the details about your cult's current status and objective.
As a Servant, your Clockwork Slab fits in pockets and does not need to be held to communicate with other Servants.
As a Servant, remember that while the selection of scripture and tools Servant cyborgs get is limited, it is still extremely useful, and some of it is unique; for example, engineering and janitor cyborgs get a proselytizer that can use their own power in addition to its own.
As a Servant, the Judicial Visor is an effective defensive combat tool in small spaces, as it stuns and mutes anyone still on it after 3 seconds. It is also useful for stunning already-stunned enemies for long enough to convert them or finish them off.
As a Servant, making, and protecting, Tinkerer's Caches is extremely important, as caches are required to unlock scripture and share components.
As a Servant, the Judicial Visor is an effective defensive combat tool in small spaces, as it immediately slows and briefly knocks down enemies hit while giving them incentive to avoid staying in the hit area.
As a Servant, Ocular Wardens, while fragile, do very high, rapid damage to a target non-Servant that can see them and will even attack mechs that contain heretics. Place them behind objects that don't block vision to get the most use out of them.
As a Servant, Clockwork Structures that require power will draw power from the APC if they cannot find a different source of power, and most power-using Structures will rapidly drain the APC.
As a Servant, you can repair Servant cyborgs and Clockwork Structures with a Replica Fabricator at a rate of 25W power to 1 health. Damaged Clockwork Structures are less efficient, so don't forget to repair them!
As a Servant, securing a reliable source of component generation is high-priority, as simply handing out slabs will slowly become inefficient. Try placing Tinkerer's Caches near clockwork walls or creating and powering Tinkerer's Daemons.
As a Servant, only a single held Clockwork Slab will generate components, no matter how many you're holding. In addition, slabs will generate components slower with large amounts of Servants; you can see the exact time with Recollection.
As a Servant, you can use Geis to easily convert single targets, as it binds them in place, preventing escape unless they react quickly enough. Having another Servant apply Geis to someone already bound will prevent their escape and mute them, even if they reacted quickly.
As a Servant, placing components in a slab or cache places those components in a globally-accessable storage that slabs will draw from to invoke scripture.
As a Servant, you can stack different types of Sigils on the same turf; try stacking a Sigil of Transgression and a Sigil of Submission for a subtle conversion trap.
As a Servant, you can deconstruct a Clockwork Wall with a Replica Fabricator to regain 1000W power. You can also construct Clockwork Walls on Clockwork Floors for a cost of 1000W power.
As a Servant, Fellowship Armory invokes much faster for each nearby servant and attempts to provide each affected servant with powerful armor against melee, bullet, and bomb attacks. The gauntlets provided are also immune to elecricity.
As a Servant, Spatial Gateway can teleport to any living Servant or Clockwork Obelisk, and gains additional uses and duration for each Servant assisting in the invocation.
As a Servant, creating and activating the Gateway to the Celestial Derelict is your ultimate goal, and you must defend it with all the tools you have available.
As a Servant, you can impale human targets with a Ratvarian Spear by pulling them, then attacking them. This does massive damage and stuns them, and should effectively win the fight.
As a Servant, Sentinel's Compromise can instantly return you or another Servant to a fighting state by converting half of all their brute, burn, and oxygen damage to toxin, effectively halving the damage they have. Clockwork Floors will also rapidly heal toxin damage in Servants, allowing the Compromise more effectiveness.
As a Servant, Belligerent and Taunting Tirade are extremely powerful for disabling and disrupting large groups of enemies, though they render you somewhat vulnerable, as Belligerent requires that you stand still, and Taunting Tirade makes you extremely obvious.
As a Servant, you can unwrench Clockwork Structures, but doing so will damage them, severely weakening them until repaired with a Replica Fabricator or Mending Mantra. Damage from other sources will also similarly weaken structures.
As a Servant, you can unwrench Clockwork Structures to move them around.
You can deconvert Cultists of Nar-Sie and Servants of Ratvar by feeding them large amounts of holy water.
As a Wizard, you can turn people to stone, then animate the resulting statue with a staff of animation to create an extremely powerful minion, for all of 5 minutes at least.
As a Wizard, the fireball spell performs very poorly at close range, as it can easily catch you in the blast. It is best used as a form of artillery down long hallways.
+3
View File
@@ -62,6 +62,7 @@
#include "code\__DEFINES\pinpointers.dm"
#include "code\__DEFINES\pipe_construction.dm"
#include "code\__DEFINES\preferences.dm"
#include "code\__DEFINES\profile.dm"
#include "code\__DEFINES\qdel.dm"
#include "code\__DEFINES\radiation.dm"
#include "code\__DEFINES\radio.dm"
@@ -290,6 +291,7 @@
#include "code\datums\mutable_appearance.dm"
#include "code\datums\mutations.dm"
#include "code\datums\outfit.dm"
#include "code\datums\profiling.dm"
#include "code\datums\progressbar.dm"
#include "code\datums\radiation_wave.dm"
#include "code\datums\recipe.dm"
@@ -321,6 +323,7 @@
#include "code\datums\components\rad_insulation.dm"
#include "code\datums\components\radioactive.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\spooky.dm"
#include "code\datums\components\squeek.dm"
#include "code\datums\components\thermite.dm"
#include "code\datums\diseases\_disease.dm"