Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit697
This commit is contained in:
@@ -429,6 +429,10 @@
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset)
|
||||
dat += {"<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_remove=\ref[rule]'>-> [rule.name] <-</A><br>"}
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_clear=1'>(Clear Rulesets)</A><br>"
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_storyteller=1'>(Force Storyteller)</A><br>"
|
||||
if (GLOB.dynamic_forced_storyteller)
|
||||
var/datum/dynamic_storyteller/S = GLOB.dynamic_forced_storyteller
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_storyteller_clear=1'>-> [initial(S.name)] <-</A><br>"
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_options=1'>(Dynamic mode options)</A><br>"
|
||||
else if (SSticker.IsRoundInProgress())
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_latejoin=1'>(Force Next Latejoin Ruleset)</A><br>"
|
||||
@@ -690,7 +694,7 @@
|
||||
var/prev_dynamic_voting = CONFIG_GET(flag/dynamic_voting)
|
||||
CONFIG_SET(flag/dynamic_voting,!prev_dynamic_voting)
|
||||
if (!prev_dynamic_voting)
|
||||
to_chat(world, "<B>Vote is now a ranked choice of dynamic storytellers.</B>")
|
||||
to_chat(world, "<B>Vote is now between dynamic storytellers.</B>")
|
||||
else
|
||||
to_chat(world, "<B>Vote is now between extended and secret.</B>")
|
||||
log_admin("[key_name(usr)] [prev_dynamic_voting ? "disabled" : "enabled"] dynamic voting.")
|
||||
|
||||
@@ -81,7 +81,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
)
|
||||
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/DB_ban_panel, /client/proc/stickybanpanel))
|
||||
GLOBAL_PROTECT(admin_verbs_ban)
|
||||
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/set_round_end_sound))
|
||||
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/manual_play_web_sound, /client/proc/set_round_end_sound))
|
||||
GLOBAL_PROTECT(admin_verbs_sounds)
|
||||
GLOBAL_LIST_INIT(admin_verbs_fun, list(
|
||||
/client/proc/cmd_admin_dress,
|
||||
@@ -364,7 +364,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
log_admin("[key_name(usr)] admin ghosted.")
|
||||
message_admins("[key_name_admin(usr)] admin ghosted.")
|
||||
var/mob/body = mob
|
||||
body.ghostize(1)
|
||||
body.ghostize(1, voluntary = TRUE)
|
||||
if(body && !body.key)
|
||||
body.key = "@[key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Admin Ghost") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -120,7 +120,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
//adv proc call this, ya nerds
|
||||
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
|
||||
if(target == GLOBAL_PROC)
|
||||
return call(procname)(arglist(arguments))
|
||||
return call(text2path("/proc/[procname]"))(arglist(arguments))
|
||||
else if(target != world)
|
||||
return call(target, procname)(arglist(arguments))
|
||||
else
|
||||
|
||||
@@ -1394,6 +1394,32 @@
|
||||
log_admin("[key_name(usr)] removed [rule] from the forced roundstart rulesets.")
|
||||
message_admins("[key_name(usr)] removed [rule] from the forced roundstart rulesets.", 1)
|
||||
|
||||
else if(href_list["f_dynamic_storyteller"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode.", null, null, null, null)
|
||||
var/list/choices = list()
|
||||
for(var/T in config.storyteller_cache)
|
||||
var/datum/dynamic_storyteller/S = T
|
||||
choices[initial(S.name)] = T
|
||||
var/choice = choices[input("Select storyteller:", "Storyteller", "Classic") as null|anything in choices]
|
||||
if(choice)
|
||||
GLOB.dynamic_forced_storyteller = choice
|
||||
log_admin("[key_name(usr)] forced the storyteller to [GLOB.dynamic_forced_storyteller].")
|
||||
message_admins("[key_name(usr)] forced the storyteller to [GLOB.dynamic_forced_storyteller].")
|
||||
Game()
|
||||
|
||||
else if(href_list["f_dynamic_storyteller_clear"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
GLOB.dynamic_forced_storyteller = null
|
||||
Game()
|
||||
log_admin("[key_name(usr)] cleared the forced storyteller. The mode will pick one as normal.")
|
||||
message_admins("[key_name(usr)] cleared the forced storyteller. The mode will pick one as normal.", 1)
|
||||
|
||||
else if(href_list["f_dynamic_latejoin"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
@@ -138,6 +138,49 @@
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Internet Sound")
|
||||
|
||||
/client/proc/manual_play_web_sound()
|
||||
set category = "Fun"
|
||||
set name = "Manual Play Internet Sound"
|
||||
if(!check_rights(R_SOUNDS))
|
||||
return
|
||||
|
||||
var/web_sound_input = input("Enter content stream URL (fetch this from local youtube-dl!)", "Play Internet Sound via direct URL") as text|null
|
||||
if(istext(web_sound_input))
|
||||
if(!length(web_sound_input))
|
||||
log_admin("[key_name(src)] stopped web sound")
|
||||
message_admins("[key_name(src)] stopped web sound")
|
||||
var/mob/M
|
||||
for(var/i in GLOB.player_list)
|
||||
M = i
|
||||
M?.client?.chatOutput?.stopMusic()
|
||||
return
|
||||
else
|
||||
if(web_sound_input && !findtext(web_sound_input, GLOB.is_http_protocol))
|
||||
to_chat(src, "<span class='boldwarning'>BLOCKED: Content URL not using http(s) protocol</span>")
|
||||
return
|
||||
var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num
|
||||
if(isnull(freq))
|
||||
return
|
||||
if(!freq)
|
||||
freq = 1
|
||||
SSblackbox.record_feedback("nested tally", "played_url", 1, list("[ckey]", "[web_sound_input]"))
|
||||
var/logstr = "[key_name(src)] played web sound at freq [freq]: [web_sound_input]"
|
||||
log_admin(logstr)
|
||||
message_admins(logstr)
|
||||
var/mob/M
|
||||
var/client/C
|
||||
var/datum/chatOutput/O
|
||||
for(var/i in GLOB.player_list)
|
||||
M = i
|
||||
C = M.client
|
||||
if(!(C?.prefs?.toggles & SOUND_MIDI))
|
||||
continue
|
||||
O = C.chatOutput
|
||||
if(!O || O.broken || !O.loaded)
|
||||
continue
|
||||
O.sendMusic(web_sound_input, freq)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Manual Play Internet Sound")
|
||||
|
||||
/client/proc/set_round_end_sound(S as sound)
|
||||
set category = "Fun"
|
||||
set name = "Set Round End Sound"
|
||||
|
||||
@@ -1379,3 +1379,47 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
else
|
||||
message_admins("[key_name_admin(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name_admin(C)]")
|
||||
log_admin("[key_name(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name(C)]")
|
||||
|
||||
/// Allow admin to add or remove traits of datum
|
||||
/datum/admins/proc/modify_traits(datum/D)
|
||||
if(!D)
|
||||
return
|
||||
|
||||
var/add_or_remove = input("Remove/Add?", "Trait Remove/Add") as null|anything in list("Add","Remove")
|
||||
if(!add_or_remove)
|
||||
return
|
||||
var/list/availible_traits = list()
|
||||
|
||||
switch(add_or_remove)
|
||||
if("Add")
|
||||
for(var/key in GLOB.traits_by_type)
|
||||
if(istype(D,key))
|
||||
availible_traits += GLOB.traits_by_type[key]
|
||||
if("Remove")
|
||||
if(!GLOB.trait_name_map)
|
||||
GLOB.trait_name_map = generate_trait_name_map()
|
||||
for(var/trait in D.status_traits)
|
||||
var/name = GLOB.trait_name_map[trait] || trait
|
||||
availible_traits[name] = trait
|
||||
|
||||
var/chosen_trait = input("Select trait to modify", "Trait") as null|anything in sortList(availible_traits)
|
||||
if(!chosen_trait)
|
||||
return
|
||||
chosen_trait = availible_traits[chosen_trait]
|
||||
|
||||
var/source = "adminabuse"
|
||||
switch(add_or_remove)
|
||||
if("Add") //Not doing source choosing here intentionally to make this bit faster to use, you can always vv it.
|
||||
ADD_TRAIT(D,chosen_trait,source)
|
||||
if("Remove")
|
||||
var/specific = input("All or specific source ?", "Trait Remove/Add") as null|anything in list("All","Specific")
|
||||
if(!specific)
|
||||
return
|
||||
switch(specific)
|
||||
if("All")
|
||||
source = null
|
||||
if("Specific")
|
||||
source = input("Source to be removed","Trait Remove/Add") as null|anything in sortList(D.status_traits[chosen_trait])
|
||||
if(!source)
|
||||
return
|
||||
REMOVE_TRAIT(D,chosen_trait,source)
|
||||
|
||||
@@ -194,9 +194,10 @@ GLOBAL_PROTECT(VVpixelmovement)
|
||||
else
|
||||
variable = L[index]
|
||||
//EXPERIMENTAL - Keep old associated value while modifying key, if any
|
||||
var/found = L[variable]
|
||||
if(!isnull(found))
|
||||
old_assoc_value = found
|
||||
if(IS_VALID_ASSOC_KEY(variable))
|
||||
var/found = L[variable]
|
||||
if(!isnull(found))
|
||||
old_assoc_value = found
|
||||
//
|
||||
|
||||
default = vv_get_class(objectvar, variable)
|
||||
|
||||
@@ -47,5 +47,33 @@
|
||||
usr.client.debug_variables(src)
|
||||
if(href_list[VV_HK_MARK])
|
||||
usr.client.mark_datum(target)
|
||||
if(href_list[VV_HK_ADDCOMPONENT])
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
var/list/names = list()
|
||||
var/list/componentsubtypes = subtypesof(/datum/component)
|
||||
names += "---Components---"
|
||||
names += componentsubtypes
|
||||
names += "---Elements---"
|
||||
names += subtypesof(/datum/element)
|
||||
var/result = input(usr, "Choose a component/element to add","better know what ur fuckin doin pal") as null|anything in names
|
||||
if(!usr || !result || result == "---Components---" || result == "---Elements---")
|
||||
return
|
||||
if(QDELETED(src))
|
||||
to_chat(usr, "That thing doesn't exist anymore!")
|
||||
return
|
||||
var/list/lst = get_callproc_args()
|
||||
if(!lst)
|
||||
return
|
||||
var/datumname = "error"
|
||||
lst.Insert(1, result)
|
||||
if(result in componentsubtypes)
|
||||
datumname = "component"
|
||||
target._AddComponent(lst)
|
||||
else
|
||||
datumname = "element"
|
||||
target._AddElement(lst)
|
||||
log_admin("[key_name(usr)] has added [result] [datumname] to [key_name(src)].")
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] has added [result] [datumname] to [key_name_admin(src)].</span>")
|
||||
if(href_list[VV_HK_CALLPROC])
|
||||
usr.client.callproc_datum(target)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
status = ORGAN_ROBOTIC
|
||||
beating = TRUE
|
||||
organ_flags = ORGAN_NO_SPOIL
|
||||
no_pump = TRUE
|
||||
var/true_name = "baseline placebo referencer"
|
||||
var/cooldown_low = 300
|
||||
var/cooldown_high = 300
|
||||
@@ -92,6 +93,7 @@
|
||||
update_gland_hud()
|
||||
|
||||
/obj/item/organ/heart/gland/on_life()
|
||||
. = ..()
|
||||
if(!beating)
|
||||
// alien glands are immune to stopping.
|
||||
beating = TRUE
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
set waitfor = FALSE // Don't make on_gain() wait for this function to finish. This lets this code run on the side.
|
||||
var/notice_healing
|
||||
while(owner && !AmFinalDeath()) // owner.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) == src
|
||||
if(owner.current.stat == CONSCIOUS && !poweron_feed && !HAS_TRAIT(owner.current, TRAIT_DEATHCOMA)) // Deduct Blood
|
||||
if(owner.current.stat == CONSCIOUS && !poweron_feed && !HAS_TRAIT(owner.current, TRAIT_FAKEDEATH)) // Deduct Blood
|
||||
AddBloodVolume(passive_blood_drain) // -.1 currently
|
||||
if(HandleHealing(1)) // Heal
|
||||
if(notice_healing == FALSE && owner.current.blood_volume > 0)
|
||||
if(!notice_healing && owner.current.blood_volume > 0)
|
||||
to_chat(owner, "<span class='notice'>The power of your blood begins knitting your wounds...</span>")
|
||||
notice_healing = TRUE
|
||||
else if(notice_healing == TRUE)
|
||||
@@ -25,7 +25,7 @@
|
||||
HandleStarving() // Death
|
||||
HandleDeath() // Standard Update
|
||||
update_hud()// Daytime Sleep in Coffin
|
||||
if(SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker"))
|
||||
if(SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_FAKEDEATH, "bloodsucker"))
|
||||
if(istype(owner.current.loc, /obj/structure/closet/crate/coffin))
|
||||
Torpor_Begin()
|
||||
// Wait before next pass
|
||||
@@ -83,7 +83,7 @@
|
||||
// NOTE: Mult of 0 is just a TEST to see if we are injured and need to go into Torpor!
|
||||
//It is called from your coffin on close (by you only)
|
||||
var/actual_regen = regen_rate + additional_regen
|
||||
if(poweron_masquerade == TRUE || owner.current.AmStaked())
|
||||
if(poweron_masquerade|| owner.current.AmStaked())
|
||||
return FALSE
|
||||
if(owner.current.reagents.has_reagent(/datum/reagent/consumable/garlic))
|
||||
return FALSE
|
||||
@@ -101,8 +101,8 @@
|
||||
var/mob/living/carbon/C = owner.current
|
||||
var/costMult = 1 // Coffin makes it cheaper
|
||||
var/fireheal = 0 // BURN: Heal in Coffin while Fakedeath, or when damage above maxhealth (you can never fully heal fire)
|
||||
var/amInCoffinWhileTorpor = istype(C.loc, /obj/structure/closet/crate/coffin) && (mult == 0 || HAS_TRAIT(C, TRAIT_FAKEDEATH)) // Check for mult 0 OR death coma. (mult 0 means we're testing from coffin)
|
||||
if(amInCoffinWhileTorpor)
|
||||
// Check for mult 0 OR death coma. (mult 0 means we're testing from coffin)
|
||||
if(istype(C.loc, /obj/structure/closet/crate/coffin) && (mult == 0 || HAS_TRAIT(C, TRAIT_FAKEDEATH)))
|
||||
mult *= 4 // Increase multiplier if we're sleeping in a coffin.
|
||||
fireheal = min(C.getFireLoss(), regen_rate) // NOTE: Burn damage ONLY heals in torpor.
|
||||
C.ExtinguishMob()
|
||||
@@ -112,6 +112,9 @@
|
||||
CheckVampOrgans() // Heart, Eyes
|
||||
if(check_limbs(costMult))
|
||||
return TRUE
|
||||
else if(owner.current.stat >= UNCONSCIOUS) //Faster regeneration and slight burn healing while unconcious
|
||||
mult *= 2
|
||||
fireheal = min(C.getFireLoss(), regen_rate * 0.2)
|
||||
|
||||
// BRUTE: Always Heal
|
||||
var/bruteheal = min(C.getBruteLoss(), actual_regen)
|
||||
@@ -120,8 +123,6 @@
|
||||
if(bruteheal + fireheal + toxinheal > 0) // Just a check? Don't heal/spend, and return.
|
||||
if(mult == 0)
|
||||
return TRUE
|
||||
if(owner.current.stat >= UNCONSCIOUS) //Faster regeneration while unconcious, so you dont have to wait all day
|
||||
mult *= 2
|
||||
// We have damage. Let's heal (one time)
|
||||
C.adjustBruteLoss(-bruteheal * mult, forced = TRUE)// Heal BRUTE / BURN in random portions throughout the body.
|
||||
C.adjustFireLoss(-fireheal * mult, forced = TRUE)
|
||||
@@ -146,12 +147,6 @@
|
||||
to_chat(C, "<span class='notice'>Your flesh knits as it regrows your [L]!</span>")
|
||||
playsound(C, 'sound/magic/demon_consume.ogg', 50, TRUE)
|
||||
return TRUE
|
||||
/*for(var/obj/item/bodypart/BP in C.bodyparts)
|
||||
if(!istype(BP) && !BP.status == 2)
|
||||
return FALSE
|
||||
to_chat(C, "<span class='notice'>Your body expels the [BP]!</span>")
|
||||
BP.drop_limb()
|
||||
return TRUE */
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/CureDisabilities()
|
||||
var/mob/living/carbon/C = owner.current
|
||||
@@ -176,7 +171,7 @@
|
||||
// EMPTY: Frenzy!
|
||||
// BLOOD_VOLUME_GOOD: [336] Pale (handled in bloodsucker_integration.dm
|
||||
// BLOOD_VOLUME_BAD: [224] Jitter
|
||||
if(owner.current.blood_volume < BLOOD_VOLUME_BAD && !prob(0.5))
|
||||
if(owner.current.blood_volume < BLOOD_VOLUME_BAD && !prob(0.5 && HAS_TRAIT(owner, TRAIT_FAKEDEATH)) && !poweron_masquerade)
|
||||
owner.current.Jitter(3)
|
||||
// BLOOD_VOLUME_SURVIVE: [122] Blur Vision
|
||||
if(owner.current.blood_volume < BLOOD_VOLUME_BAD / 2)
|
||||
@@ -230,16 +225,16 @@
|
||||
Torpor_Begin()
|
||||
to_chat(owner, "<span class='danger'>Your immortal body will not yet relinquish your soul to the abyss. You enter Torpor.</span>")
|
||||
sleep(30) //To avoid spam
|
||||
if(poweron_masquerade == TRUE)
|
||||
if(poweron_masquerade)
|
||||
to_chat(owner, "<span class='warning'>Your wounds will not heal until you disable the <span class='boldnotice'>Masquerade</span> power.</span>")
|
||||
// End Torpor:
|
||||
else // No damage, OR toxin healed AND brute healed and NOT in coffin (since you cannot heal burn)
|
||||
if(total_damage <= 0 || total_toxloss <= 0 && total_brute <= 0 && !istype(owner.current.loc, /obj/structure/closet/crate/coffin))
|
||||
// Not Daytime, Not in Torpor
|
||||
if(!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_FAKEDEATH, "bloodsucker"))
|
||||
// Not Daytime, Not in Torpor, enough health to not die the moment you end torpor
|
||||
if(!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_FAKEDEATH, "bloodsucker") && total_damage < owner.current.getMaxHealth())
|
||||
Torpor_End()
|
||||
// Fake Unconscious
|
||||
if(poweron_masquerade == TRUE && total_damage >= owner.current.getMaxHealth() - HEALTH_THRESHOLD_FULLCRIT)
|
||||
if(poweron_masquerade && total_damage >= owner.current.getMaxHealth() - HEALTH_THRESHOLD_FULLCRIT)
|
||||
owner.current.Unconscious(20, 1)
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/Torpor_Begin(amInCoffin = FALSE)
|
||||
@@ -249,6 +244,7 @@
|
||||
ADD_TRAIT(owner.current, TRAIT_NODEATH, "bloodsucker") // Without this, you'll just keep dying while you recover.
|
||||
ADD_TRAIT(owner.current, TRAIT_RESISTHIGHPRESSURE, "bloodsucker") // So you can heal in space. Otherwise you just...heal forever.
|
||||
ADD_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, "bloodsucker")
|
||||
owner.current.Jitter(0)
|
||||
// Visuals
|
||||
owner.current.update_sight()
|
||||
owner.current.reload_fullscreen()
|
||||
@@ -256,6 +252,9 @@
|
||||
for(var/datum/action/bloodsucker/power in powers)
|
||||
if(power.active && !power.can_use_in_torpor)
|
||||
power.DeactivatePower()
|
||||
if(owner.current.suiciding)
|
||||
owner.current.suiciding = FALSE //Youll die but not for long.
|
||||
to_chat(owner.current, "<span class='warning'>Your body keeps you going, even as you try to end yourself.</span>")
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/Torpor_End()
|
||||
owner.current.stat = SOFT_CRIT
|
||||
|
||||
@@ -45,15 +45,15 @@
|
||||
// (FINAL LIL WARNING)
|
||||
while(time_til_cycle > 5)
|
||||
sleep(10)
|
||||
if (cancel_me)
|
||||
if(cancel_me)
|
||||
return
|
||||
//sleep(TIME_BLOODSUCKER_DAY_FINAL_WARN - 50)
|
||||
warn_daylight(3,"<span class = 'userdanger'>Seek cover, for Sol rises!</span>")
|
||||
|
||||
// Part 3: Night Ending
|
||||
while (time_til_cycle > 0)
|
||||
while(time_til_cycle > 0)
|
||||
sleep(10)
|
||||
if (cancel_me)
|
||||
if(cancel_me)
|
||||
return
|
||||
//sleep(50)
|
||||
warn_daylight(4,"<span class = 'userdanger'>Solar flares bombard the station with deadly UV light!</span><br><span class = ''>Stay in cover for the next [TIME_BLOODSUCKER_DAY / 60] minutes or risk Final Death!</span>",\
|
||||
@@ -69,11 +69,11 @@
|
||||
while(time_til_cycle > 0)
|
||||
punish_vamps()
|
||||
sleep(TIME_BLOODSUCKER_BURN_INTERVAL)
|
||||
if (cancel_me)
|
||||
if(cancel_me)
|
||||
return
|
||||
//daylight_time -= TIME_BLOODSUCKER_BURN_INTERVAL
|
||||
// Issue Level Up!
|
||||
if(!issued_XP && time_til_cycle <= 15)
|
||||
if(!issued_XP && time_til_cycle <= 5)
|
||||
issued_XP = TRUE
|
||||
vamps_rank_up()
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
// Traits
|
||||
for(var/T in defaultTraits)
|
||||
REMOVE_TRAIT(owner.current, T, BLOODSUCKER_TRAIT)
|
||||
if(had_toxlover == TRUE)
|
||||
if(had_toxlover)
|
||||
ADD_TRAIT(owner.current, TRAIT_TOXINLOVER, SPECIES_TRAIT)
|
||||
|
||||
// Traits: Species
|
||||
|
||||
@@ -18,14 +18,11 @@
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
// must have nobody around to see the cloak
|
||||
var/watchers = viewers(9,get_turf(owner))
|
||||
for(var/mob/living/M in watchers)
|
||||
for(var/mob/living/M in viewers(9, owner))
|
||||
if(M != owner)
|
||||
to_chat(owner, "<span class='warning'>You may only vanish into the shadows unseen.</span>")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/action/bloodsucker/cloak/ActivatePower()
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
REMOVE_TRAIT(user, TRAIT_NOHARDCRIT, "bloodsucker")
|
||||
REMOVE_TRAIT(user, TRAIT_NOSOFTCRIT, "bloodsucker")
|
||||
REMOVE_TRAIT(user, TRAIT_VIRUSIMMUNE, "bloodsucker")
|
||||
REMOVE_TRAIT(user, TRAIT_NOBREATH, "bloodsucker")
|
||||
var/obj/item/organ/heart/vampheart/H = user.getorganslot(ORGAN_SLOT_HEART)
|
||||
var/obj/item/organ/eyes/vassal/bloodsucker/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
E.flash_protect = 0
|
||||
@@ -93,6 +94,7 @@
|
||||
ADD_TRAIT(user, TRAIT_NOHARDCRIT, "bloodsucker")
|
||||
ADD_TRAIT(user, TRAIT_NOSOFTCRIT, "bloodsucker")
|
||||
ADD_TRAIT(user, TRAIT_VIRUSIMMUNE, "bloodsucker")
|
||||
ADD_TRAIT(user, TRAIT_NOBREATH, "bloodsucker")
|
||||
|
||||
// HEART
|
||||
var/obj/item/organ/heart/H = user.getorganslot(ORGAN_SLOT_HEART)
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
/datum/action/bloodsucker/targeted/trespass/CheckValidTarget(atom/A)
|
||||
// Can't target my tile
|
||||
if (A == get_turf(owner) || get_turf(A) == get_turf(owner))
|
||||
if(A == get_turf(owner) || get_turf(A) == get_turf(owner))
|
||||
return FALSE
|
||||
|
||||
return TRUE // All we care about is destination. Anything you click is fine.
|
||||
@@ -43,13 +43,13 @@
|
||||
// Are either tiles WALLS?
|
||||
var/turf/from_turf = get_turf(owner)
|
||||
var/this_dir // = get_dir(from_turf, target_turf)
|
||||
for (var/i=1 to 2)
|
||||
for(var/i=1 to 2)
|
||||
// Keep Prev Direction if we've reached final turf
|
||||
if (from_turf != final_turf)
|
||||
if(from_turf != final_turf)
|
||||
this_dir = get_dir(from_turf, final_turf) // Recalculate dir so we don't overshoot on a diagonal.
|
||||
from_turf = get_step(from_turf, this_dir)
|
||||
// ERROR! Wall!
|
||||
if (iswallturf(from_turf))
|
||||
if(iswallturf(from_turf))
|
||||
if (display_error)
|
||||
var/wallwarning = (i == 1) ? "in the way" : "at your destination"
|
||||
to_chat(owner, "<span class='warning'>There is a solid wall [wallwarning].</span>")
|
||||
@@ -84,7 +84,7 @@
|
||||
user.next_move = world.time + mist_delay
|
||||
user.Stun(mist_delay, ignore_canstun = TRUE)
|
||||
user.notransform = TRUE
|
||||
user.density = 0
|
||||
user.density = FALSE
|
||||
var/invis_was = user.invisibility
|
||||
user.invisibility = INVISIBILITY_MAXIMUM
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
sleep(mist_delay / 2)
|
||||
|
||||
// Move & Freeze
|
||||
if (isturf(target_turf))
|
||||
if(isturf(target_turf))
|
||||
do_teleport(owner, target_turf, no_effects=TRUE, channel = TELEPORT_CHANNEL_QUANTUM) // in teleport.dm?
|
||||
user.next_move = world.time + mist_delay / 2
|
||||
user.Stun(mist_delay / 2, ignore_canstun = TRUE)
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
H.socks = random_socks(H.gender)
|
||||
//H.eye_color = random_eye_color()
|
||||
REMOVE_TRAIT(H, TRAIT_DISFIGURED, null) //
|
||||
H.dna.features = random_features(H.dna.species?.id)
|
||||
H.dna.features = random_features(H.dna.species?.id, H.gender)
|
||||
|
||||
// Apply Appearance
|
||||
H.update_body(TRUE) // Outfit and underwear, also body and privates.
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
to_chat(user, "<span class='notice'>Our muscles tense and strengthen.</span>")
|
||||
changeling.chem_recharge_slowdown += 0.5
|
||||
else
|
||||
user.remove_movespeed_modifier(MOVESPEED_ID_CHANGELING_MUSCLES)
|
||||
user.remove_movespeed_modifier(/datum/movespeed_modifier/strained_muscles)
|
||||
to_chat(user, "<span class='notice'>Our muscles relax.</span>")
|
||||
changeling.chem_recharge_slowdown -= 0.5
|
||||
if(stacks >= 20)
|
||||
@@ -36,12 +36,12 @@
|
||||
/obj/effect/proc_holder/changeling/strained_muscles/proc/muscle_loop(mob/living/carbon/user)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
while(active)
|
||||
user.add_movespeed_modifier(MOVESPEED_ID_CHANGELING_MUSCLES, update=TRUE, priority=100, multiplicative_slowdown=-1, blacklisted_movetypes=(FLYING|FLOATING))
|
||||
user.add_movespeed_modifier(/datum/movespeed_modifier/strained_muscles)
|
||||
if(user.stat != CONSCIOUS || user.staminaloss >= 90)
|
||||
active = !active
|
||||
to_chat(user, "<span class='notice'>Our muscles relax without the energy to strengthen them.</span>")
|
||||
user.DefaultCombatKnockdown(40)
|
||||
user.remove_movespeed_modifier(MOVESPEED_ID_CHANGELING_MUSCLES)
|
||||
user.remove_movespeed_modifier(/datum/movespeed_modifier/strained_muscles)
|
||||
changeling.chem_recharge_slowdown -= 0.5
|
||||
break
|
||||
|
||||
|
||||
@@ -539,7 +539,7 @@
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
|
||||
var/cursetime = 1800
|
||||
var/timer = SSshuttle.emergency.timeLeft(1) + cursetime
|
||||
var/security_num = seclevel2num(get_security_level())
|
||||
var/security_num = SECLEVEL2NUM(NUM2SECLEVEL(GLOB.security_level))
|
||||
var/set_coefficient = 1
|
||||
switch(security_num)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
STOP_PROCESSING(SSobj, core)
|
||||
update_icon()
|
||||
GLOB.poi_list |= src
|
||||
previous_level = get_security_level()
|
||||
previous_level = NUM2SECLEVEL(GLOB.security_level)
|
||||
|
||||
/obj/machinery/nuclearbomb/Destroy()
|
||||
safety = FALSE
|
||||
@@ -419,7 +419,7 @@
|
||||
return
|
||||
timing = !timing
|
||||
if(timing)
|
||||
previous_level = get_security_level()
|
||||
previous_level = NUM2SECLEVEL(GLOB.security_level)
|
||||
detonation_timer = world.time + (timer_set * 10)
|
||||
for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
|
||||
S.switch_mode_to(TRACK_INFILTRATOR)
|
||||
|
||||
@@ -64,8 +64,8 @@
|
||||
|
||||
/mob/living/simple_animal/slaughter/phasein()
|
||||
. = ..()
|
||||
add_movespeed_modifier(MOVESPEED_ID_SLAUGHTER, update=TRUE, priority=100, multiplicative_slowdown=-1)
|
||||
addtimer(CALLBACK(src, .proc/remove_movespeed_modifier, MOVESPEED_ID_SLAUGHTER, TRUE), 6 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
|
||||
add_movespeed_modifier(/datum/movespeed_modifier/slaughter)
|
||||
addtimer(CALLBACK(src, .proc/remove_movespeed_modifier, /datum/movespeed_modifier/slaughter), 6 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
|
||||
|
||||
|
||||
//The loot from killing a slaughter demon - can be consumed to allow the user to blood crawl
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
var/datum/traitor_class/class = GLOB.traitor_classes[C]
|
||||
var/weight = LOGISTIC_FUNCTION(1.5*class.weight,chaos_weight,class.chaos,0)
|
||||
weights[C] = weight * 1000
|
||||
var/choice = pickweightAllowZero(weights)
|
||||
var/choice = pickweight(weights, 0)
|
||||
if(!choice)
|
||||
choice = TRAITOR_HUMAN // it's an "easter egg"
|
||||
var/datum/traitor_class/actual_class = GLOB.traitor_classes[choice]
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
/obj/item/scrying/attack_self(mob/user)
|
||||
to_chat(user, "<span class='notice'>You can see...everything!</span>")
|
||||
visible_message("<span class='danger'>[user] stares into [src], their eyes glazing over.</span>")
|
||||
user.ghostize(1)
|
||||
user.ghostize(1, voluntary = TRUE)
|
||||
|
||||
/////////////////////////////////////////Necromantic Stone///////////////////
|
||||
|
||||
|
||||
@@ -294,7 +294,7 @@
|
||||
name = "Staff of Change"
|
||||
desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself."
|
||||
item_path = /obj/item/gun/magic/staff/change
|
||||
dynamic_requirement = 60
|
||||
dynamic_requirement = 200
|
||||
|
||||
/datum/spellbook_entry/item/staffanimation
|
||||
name = "Staff of Animation"
|
||||
@@ -361,7 +361,7 @@
|
||||
desc = "A collection of wands that allow for a wide variety of utility. Wands have a limited number of charges, so be conservative in use. Comes in a handy belt."
|
||||
item_path = /obj/item/storage/belt/wands/full
|
||||
category = "Defensive"
|
||||
dynamic_requirement = 60
|
||||
dynamic_requirement = 200
|
||||
|
||||
/datum/spellbook_entry/item/armor
|
||||
name = "Mastercrafted Armor Set"
|
||||
@@ -386,7 +386,7 @@
|
||||
name = "Plasma Fist"
|
||||
desc = "A forbidden martial art designed on the surging power of plasma. Use it to harness the ancient power."
|
||||
item_path = /obj/item/book/granter/martial/plasma_fist
|
||||
cost = 3
|
||||
cost = 2
|
||||
|
||||
/datum/spellbook_entry/item/guardian
|
||||
name = "Guardian Deck"
|
||||
|
||||
@@ -225,6 +225,7 @@
|
||||
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
target_temperature = min_temperature
|
||||
to_chat(user,"<span class='notice'>You minimize the temperature on the [src].</span>")
|
||||
investigate_log("was set to [target_temperature] K by [key_name(usr)]", INVESTIGATE_ATMOS)
|
||||
message_admins("[src.name] was minimized by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
|
||||
return TRUE
|
||||
@@ -257,6 +258,7 @@
|
||||
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
target_temperature = max_temperature
|
||||
to_chat(user,"<span class='notice'>You maximize the temperature on the [src].</span>")
|
||||
investigate_log("was set to [target_temperature] K by [key_name(usr)]", INVESTIGATE_ATMOS)
|
||||
message_admins("[src.name] was maximized by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
|
||||
return TRUE
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
// How much "space" we give the edge of the map
|
||||
GLOBAL_LIST_INIT(potentialRandomZlevels, generateMapList(filename = "[global.config.directory]/awaymissionconfig.txt"))
|
||||
|
||||
/proc/createRandomZlevel()
|
||||
if(GLOB.awaydestinations.len) //crude, but it saves another var!
|
||||
/proc/createRandomZlevel(name = AWAY_MISSION_NAME, list/traits = list(ZTRAIT_AWAY = TRUE), list/potential_levels = GLOB.potential_away_levels)
|
||||
if(GLOB.random_zlevels_generated[name])
|
||||
stack_trace("[name] level already generated.")
|
||||
return
|
||||
if(!length(potential_levels))
|
||||
stack_trace("No potential [name] level to load has been found.")
|
||||
return
|
||||
|
||||
if(GLOB.potentialRandomZlevels && GLOB.potentialRandomZlevels.len)
|
||||
to_chat(world, "<span class='boldannounce'>Loading away mission...</span>")
|
||||
var/map = pick(GLOB.potentialRandomZlevels)
|
||||
load_new_z_level(map, "Away Mission")
|
||||
to_chat(world, "<span class='boldannounce'>Away mission loaded.</span>")
|
||||
var/start_time = REALTIMEOFDAY
|
||||
var/map = pick(potential_levels)
|
||||
if(!load_new_z_level(map, name, traits))
|
||||
INIT_ANNOUNCE("Failed to load [name]! map filepath: [map]!")
|
||||
return
|
||||
INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!")
|
||||
GLOB.random_zlevels_generated[name] = TRUE
|
||||
|
||||
/proc/reset_gateway_spawns(reset = FALSE)
|
||||
for(var/obj/machinery/gateway/G in world)
|
||||
|
||||
@@ -262,7 +262,15 @@
|
||||
return
|
||||
random_look(owner)
|
||||
|
||||
/obj/item/clothing/under/chameleon
|
||||
// Forgive me for my sins...
|
||||
#define CHAMELEON_CLOTHING_DEFINE(path) \
|
||||
##path/syndicate/Initialize(mapload){\
|
||||
. = ..();\
|
||||
AddComponent(/datum/component/identification/syndicate, ID_COMPONENT_DEL_ON_IDENTIFY, ID_COMPONENT_EFFECT_NO_ACTIONS, ID_COMPONENT_IDENTIFY_WITH_DECONSTRUCTOR);\
|
||||
}\
|
||||
##path
|
||||
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/under/chameleon)
|
||||
//starts off as black
|
||||
name = "black jumpsuit"
|
||||
icon_state = "black"
|
||||
@@ -300,7 +308,7 @@
|
||||
. = ..()
|
||||
chameleon_action.emp_randomise(INFINITY)
|
||||
|
||||
/obj/item/clothing/suit/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/suit/chameleon)
|
||||
name = "armor"
|
||||
desc = "A slim armored vest that protects against most types of damage."
|
||||
icon_state = "armor"
|
||||
@@ -329,7 +337,7 @@
|
||||
. = ..()
|
||||
chameleon_action.emp_randomise(INFINITY)
|
||||
|
||||
/obj/item/clothing/glasses/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/glasses/chameleon)
|
||||
name = "Optical Meson Scanner"
|
||||
desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting condition."
|
||||
icon_state = "meson"
|
||||
@@ -357,7 +365,7 @@
|
||||
. = ..()
|
||||
chameleon_action.emp_randomise(INFINITY)
|
||||
|
||||
/obj/item/clothing/gloves/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/gloves/chameleon)
|
||||
desc = "These gloves will protect the wearer from electric shock."
|
||||
name = "insulated gloves"
|
||||
icon_state = "yellow"
|
||||
@@ -368,6 +376,9 @@
|
||||
|
||||
var/datum/action/item_action/chameleon/change/chameleon_action
|
||||
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/gloves/chameleon/insulated)
|
||||
siemens_coefficient = 0
|
||||
|
||||
/obj/item/clothing/gloves/chameleon/Initialize()
|
||||
. = ..()
|
||||
chameleon_action = new(src)
|
||||
@@ -386,7 +397,7 @@
|
||||
. = ..()
|
||||
chameleon_action.emp_randomise(INFINITY)
|
||||
|
||||
/obj/item/clothing/head/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/head/chameleon)
|
||||
name = "grey cap"
|
||||
desc = "It's a baseball hat in a tasteful grey colour."
|
||||
icon_state = "greysoft"
|
||||
@@ -429,7 +440,7 @@
|
||||
var/datum/action/item_action/chameleon/drone/randomise/randomise_action = new(src)
|
||||
randomise_action.UpdateButtonIcon()
|
||||
|
||||
/obj/item/clothing/mask/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/mask/chameleon)
|
||||
name = "gas mask"
|
||||
desc = "A face-covering mask that can be connected to an air supply. While good for concealing your identity, it isn't good for blocking gas flow." //More accurate
|
||||
icon_state = "gas_alt"
|
||||
@@ -486,7 +497,7 @@
|
||||
/obj/item/clothing/mask/chameleon/drone/attack_self(mob/user)
|
||||
to_chat(user, "<span class='notice'>[src] does not have a voice changer.</span>")
|
||||
|
||||
/obj/item/clothing/shoes/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/shoes/chameleon)
|
||||
name = "black shoes"
|
||||
icon_state = "black"
|
||||
desc = "A pair of black shoes."
|
||||
@@ -511,7 +522,7 @@
|
||||
return
|
||||
chameleon_action.emp_randomise()
|
||||
|
||||
/obj/item/clothing/shoes/chameleon/noslip
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/shoes/chameleon/noslip)
|
||||
name = "black shoes"
|
||||
icon_state = "black"
|
||||
desc = "A pair of black shoes."
|
||||
@@ -521,7 +532,7 @@
|
||||
. = ..()
|
||||
chameleon_action.emp_randomise(INFINITY)
|
||||
|
||||
/obj/item/storage/backpack/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/storage/backpack/chameleon)
|
||||
name = "backpack"
|
||||
var/datum/action/item_action/chameleon/change/chameleon_action
|
||||
|
||||
@@ -542,7 +553,7 @@
|
||||
. = ..()
|
||||
chameleon_action.emp_randomise(INFINITY)
|
||||
|
||||
/obj/item/storage/belt/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/storage/belt/chameleon)
|
||||
name = "toolbelt"
|
||||
desc = "Holds tools."
|
||||
var/datum/action/item_action/chameleon/change/chameleon_action
|
||||
@@ -570,7 +581,7 @@
|
||||
. = ..()
|
||||
chameleon_action.emp_randomise(INFINITY)
|
||||
|
||||
/obj/item/radio/headset/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/radio/headset/chameleon)
|
||||
name = "radio headset"
|
||||
var/datum/action/item_action/chameleon/change/chameleon_action
|
||||
|
||||
@@ -591,7 +602,7 @@
|
||||
. = ..()
|
||||
chameleon_action.emp_randomise(INFINITY)
|
||||
|
||||
/obj/item/pda/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/pda/chameleon)
|
||||
name = "PDA"
|
||||
var/datum/action/item_action/chameleon/change/pda/chameleon_action
|
||||
|
||||
@@ -613,7 +624,7 @@
|
||||
. = ..()
|
||||
chameleon_action.emp_randomise(INFINITY)
|
||||
|
||||
/obj/item/stamp/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/stamp/chameleon)
|
||||
var/datum/action/item_action/chameleon/change/chameleon_action
|
||||
|
||||
/obj/item/stamp/chameleon/Initialize()
|
||||
@@ -627,7 +638,7 @@
|
||||
. = ..()
|
||||
chameleon_action.emp_randomise(INFINITY)
|
||||
|
||||
/obj/item/clothing/neck/cloak/chameleon
|
||||
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/neck/cloak/chameleon)
|
||||
name = "black tie"
|
||||
desc = "A neosilk clip-on tie."
|
||||
icon = 'icons/obj/clothing/neck.dmi'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/item/clothing/under/dress/skirt
|
||||
/obj/item/clothing/under/dress
|
||||
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON
|
||||
|
||||
/obj/item/clothing/under/dress/skirt
|
||||
@@ -182,7 +182,6 @@
|
||||
icon_state = "bride_white"
|
||||
item_state = "bride_white"
|
||||
can_adjust = FALSE
|
||||
mutantrace_variation = NONE
|
||||
|
||||
/obj/item/clothing/under/dress/wedding/orange
|
||||
name = "orange wedding dress"
|
||||
@@ -213,7 +212,6 @@
|
||||
desc = "A fancy skirt made with polychromic threads."
|
||||
icon_state = "polyskirt"
|
||||
item_state = "rainbow"
|
||||
mutantrace_variation = NONE
|
||||
var/list/poly_colors = list("#FFFFFF", "#F08080", "#808080")
|
||||
|
||||
/obj/item/clothing/under/dress/skirt/polychromic/ComponentInitialize()
|
||||
@@ -226,5 +224,4 @@
|
||||
icon_state = "polypleat"
|
||||
item_state = "rainbow"
|
||||
body_parts_covered = CHEST|GROIN|ARMS
|
||||
mutantrace_variation = NONE
|
||||
poly_colors = list("#8CC6FF", "#808080", "#FF3535")
|
||||
|
||||
@@ -57,8 +57,7 @@
|
||||
icon_state = "tactifool"
|
||||
item_state = "bl_suit"
|
||||
has_sensor = TRUE
|
||||
mutantrace_variation = NONE
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
|
||||
/obj/item/clothing/under/syndicate/sniper
|
||||
name = "Tactical turtleneck suit"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
if(turfs.len) //Pick a turf to spawn at if we can
|
||||
var/turf/T = pick(turfs)
|
||||
new /datum/spacevine_controller(T) //spawn a controller at turf
|
||||
new /datum/spacevine_controller(T, pick(subtypesof(/datum/spacevine_mutation)), rand(30,100), rand(5,10), src) //spawn a controller at turf with randomized stats and a single random mutation
|
||||
|
||||
|
||||
/datum/spacevine_mutation
|
||||
@@ -227,13 +227,13 @@
|
||||
quality = NEGATIVE
|
||||
|
||||
/datum/spacevine_mutation/thorns/on_cross(obj/structure/spacevine/holder, mob/living/crosser)
|
||||
if(prob(severity) && istype(crosser) && !isvineimmune(holder))
|
||||
if(prob(severity) && istype(crosser) && !isvineimmune(crosser))
|
||||
var/mob/living/M = crosser
|
||||
M.adjustBruteLoss(5)
|
||||
to_chat(M, "<span class='alert'>You cut yourself on the thorny vines.</span>")
|
||||
|
||||
/datum/spacevine_mutation/thorns/on_hit(obj/structure/spacevine/holder, mob/living/hitter, obj/item/I, expected_damage)
|
||||
if(prob(severity) && istype(hitter) && !isvineimmune(holder))
|
||||
if(prob(severity) && istype(hitter) && !isvineimmune(hitter))
|
||||
var/mob/living/M = hitter
|
||||
M.adjustBruteLoss(5)
|
||||
to_chat(M, "<span class='alert'>You cut yourself on the thorny vines.</span>")
|
||||
@@ -251,7 +251,7 @@
|
||||
holder.obj_integrity = holder.max_integrity
|
||||
|
||||
/datum/spacevine_mutation/woodening/on_hit(obj/structure/spacevine/holder, mob/living/hitter, obj/item/I, expected_damage)
|
||||
if(I.get_sharpness())
|
||||
if(I?.get_sharpness())
|
||||
. = expected_damage * 0.5
|
||||
else
|
||||
. = expected_damage
|
||||
@@ -344,16 +344,17 @@
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
if(damage_amount)
|
||||
playsound(src, 'sound/weapons/slash.ogg', 50, 1)
|
||||
playsound(src, 'sound/weapons/slash.ogg', 50, TRUE)
|
||||
else
|
||||
playsound(src, 'sound/weapons/tap.ogg', 50, 1)
|
||||
playsound(src, 'sound/weapons/tap.ogg', 50, TRUE)
|
||||
if(BURN)
|
||||
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
|
||||
playsound(src.loc, 'sound/items/welder.ogg', 100, TRUE)
|
||||
|
||||
/obj/structure/spacevine/Crossed(mob/crosser)
|
||||
if(isliving(crosser))
|
||||
for(var/datum/spacevine_mutation/SM in mutations)
|
||||
SM.on_cross(src, crosser)
|
||||
/obj/structure/spacevine/Crossed(atom/movable/AM)
|
||||
if(!isliving(AM))
|
||||
return
|
||||
for(var/datum/spacevine_mutation/SM in mutations)
|
||||
SM.on_cross(src, AM)
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/structure/spacevine/attack_hand(mob/user)
|
||||
@@ -378,10 +379,9 @@
|
||||
var/list/vine_mutations_list
|
||||
var/mutativeness = 1
|
||||
|
||||
/datum/spacevine_controller/New(turf/location, list/muts, potency, production)
|
||||
/datum/spacevine_controller/New(turf/location, list/muts, potency, production, datum/round_event/event = null)
|
||||
vines = list()
|
||||
growth_queue = list()
|
||||
spawn_spacevine_piece(location, null, muts)
|
||||
START_PROCESSING(SSobj, src)
|
||||
vine_mutations_list = list()
|
||||
init_subtypes(/datum/spacevine_mutation/, vine_mutations_list)
|
||||
@@ -428,6 +428,7 @@
|
||||
for(var/datum/spacevine_mutation/SM in SV.mutations)
|
||||
SM.on_birth(SV)
|
||||
location.Entered(SV)
|
||||
return SV
|
||||
|
||||
/datum/spacevine_controller/proc/VineDestroyed(obj/structure/spacevine/S)
|
||||
S.master = null
|
||||
@@ -531,14 +532,13 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/spacevine/CanPass(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(isvineimmune(mover))
|
||||
. = TRUE
|
||||
else
|
||||
. = ..()
|
||||
return TRUE
|
||||
|
||||
/proc/isvineimmune(atom/A)
|
||||
. = FALSE
|
||||
if(isliving(A))
|
||||
var/mob/living/M = A
|
||||
if(("vines" in M.faction) || ("plants" in M.faction))
|
||||
. = TRUE
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -23,6 +23,9 @@
|
||||
/datum/round_event/wormholes/start()
|
||||
for(var/turf/open/floor/T in world)
|
||||
if(is_station_level(T.z))
|
||||
var/area/A = get_area(T)
|
||||
if(A.outdoors)
|
||||
continue
|
||||
pick_turfs += T
|
||||
|
||||
for(var/i = 1, i <= number_of_wormholes, i++)
|
||||
|
||||
@@ -396,6 +396,16 @@
|
||||
list_reagents = list(/datum/reagent/consumable/orangejuice = 100)
|
||||
foodtype = FRUIT| BREAKFAST
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/bottle/bio_carton
|
||||
name = "small carton box"
|
||||
desc = "A small biodegradable carton box made from plant biomatter."
|
||||
icon_state = "eco_box"
|
||||
item_state = "carton"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
|
||||
volume = 50
|
||||
isGlass = FALSE
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/bottle/cream
|
||||
name = "milk cream"
|
||||
desc = "It's cream. Made from milk. What else did you think you'd find in there?"
|
||||
|
||||
@@ -40,14 +40,14 @@
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/biogenerator/RefreshParts()
|
||||
var/E = 0
|
||||
var/P = 0
|
||||
var/max_storage = 40
|
||||
var/E = 0.5
|
||||
var/P = 0.5
|
||||
var/max_storage = 20
|
||||
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
|
||||
P += B.rating
|
||||
max_storage = 40 * B.rating
|
||||
P += B.rating * 0.5
|
||||
max_storage = max(20 * B.rating, max_storage)
|
||||
for(var/obj/item/stock_parts/manipulator/M in component_parts)
|
||||
E += M.rating
|
||||
E += M.rating * 0.5
|
||||
efficiency = E
|
||||
productivity = P
|
||||
max_items = max_storage
|
||||
@@ -196,7 +196,7 @@
|
||||
dat += "<A href='?src=[REF(src)];create=[D.id];amount=5'>x5</A>"
|
||||
if(ispath(D.build_path, /obj/item/stack))
|
||||
dat += "<A href='?src=[REF(src)];create=[D.id];amount=10'>x10</A>"
|
||||
dat += "([D.materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]/efficiency])<br>"
|
||||
dat += "([CEILING(D.materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]/efficiency, 1)])<br>"
|
||||
dat += "</div>"
|
||||
else
|
||||
dat += "<div class='statusDisplay'>No container inside, please insert container.</div>"
|
||||
@@ -214,12 +214,16 @@
|
||||
to_chat(usr, "<span class='warning'>The biogenerator is in the process of working.</span>")
|
||||
return
|
||||
var/S = 0
|
||||
var/total = 0
|
||||
for(var/obj/item/reagent_containers/food/snacks/grown/I in contents)
|
||||
S += 5
|
||||
if(I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment) < 0.1)
|
||||
points += 1*productivity
|
||||
else points += I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment)*10*productivity
|
||||
var/nutri_amount = I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment)
|
||||
if(nutri_amount < 0.1)
|
||||
total += 1*productivity
|
||||
else
|
||||
total += nutri_amount*10*productivity
|
||||
qdel(I)
|
||||
points += round(total)
|
||||
if(S)
|
||||
processing = TRUE
|
||||
update_icon()
|
||||
@@ -235,12 +239,13 @@
|
||||
/obj/machinery/biogenerator/proc/check_cost(list/materials, multiplier = 1, remove_points = TRUE)
|
||||
if(materials.len != 1 || materials[1] != SSmaterials.GetMaterialRef(/datum/material/biomass))
|
||||
return FALSE
|
||||
if (materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency > points)
|
||||
var/cost = CEILING(materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency, 1)
|
||||
if (cost > points)
|
||||
menustat = "nopoints"
|
||||
return FALSE
|
||||
else
|
||||
if(remove_points)
|
||||
points -= materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency
|
||||
points -= cost
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
@@ -79,7 +79,9 @@
|
||||
|
||||
for(var/I in assembly_components)
|
||||
var/obj/item/integrated_circuit/IC = I
|
||||
. += IC.external_examine(user)
|
||||
var/text = IC.external_examine(user)
|
||||
if(text)
|
||||
. += text
|
||||
if(opened)
|
||||
interact(user)
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@ a creative player the means to solve many problems. Circuits are held inside an
|
||||
/obj/item/integrated_circuit/examine(mob/user)
|
||||
interact(user)
|
||||
. = ..()
|
||||
. += external_examine(user)
|
||||
var/text = external_examine(user)
|
||||
if(text)
|
||||
. += text
|
||||
|
||||
// Can be called via electronic_assembly/attackby()
|
||||
/obj/item/integrated_circuit/proc/additem(var/obj/item/I, var/mob/living/user)
|
||||
@@ -57,7 +59,7 @@ a creative player the means to solve many problems. Circuits are held inside an
|
||||
var/datum/integrated_io/activate/A = activators[k]
|
||||
if(A.linked.len)
|
||||
to_chat(user, "The '[A]' is connected to [A.get_linked_to_desc()].")
|
||||
any_examine(user)
|
||||
to_chat(user, any_examine(user))
|
||||
interact(user)
|
||||
|
||||
// This should be used when someone is examining from an 'outside' perspective, e.g. reading a screen or LED.
|
||||
|
||||
@@ -66,6 +66,11 @@
|
||||
// How much threat this job is worth in dynamic. Is subtracted if the player's not an antag, added if they are.
|
||||
var/threat = 0
|
||||
|
||||
/// Starting skill levels.
|
||||
var/list/starting_skills
|
||||
/// Skill affinities to set
|
||||
var/list/skill_affinities
|
||||
|
||||
//Only override this proc
|
||||
//H is usually a human unless an /equip override transformed it
|
||||
/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE)
|
||||
@@ -142,7 +147,6 @@
|
||||
return TRUE //Available in 0 days = available right now = player is old enough to play.
|
||||
return FALSE
|
||||
|
||||
|
||||
/datum/job/proc/available_in_days(client/C)
|
||||
if(!C)
|
||||
return 0
|
||||
@@ -166,6 +170,17 @@
|
||||
/datum/job/proc/radio_help_message(mob/M)
|
||||
to_chat(M, "<b>Prefix your message with :h to speak on your department's radio. To see other prefixes, look closely at your headset.</b>")
|
||||
|
||||
/datum/job/proc/standard_assign_skills(datum/mind/M)
|
||||
if(!starting_skills)
|
||||
return
|
||||
for(var/skill in starting_skills)
|
||||
M.skill_holder.boost_skill_value_to(skill, starting_skills[skill])
|
||||
// do wipe affinities though
|
||||
M.skill_holder.skill_affinities = list()
|
||||
for(var/skill in skill_affinities)
|
||||
M.skill_holder.skill_affinities[skill] = skill_affinities[skill]
|
||||
UNSETEMPTY(M.skill_holder.skill_affinities) //if we didn't set any.
|
||||
|
||||
/datum/outfit/job
|
||||
name = "Standard Gear"
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
display_order = JOB_DISPLAY_ORDER_CHEMIST
|
||||
threat = 1.5
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/chemist
|
||||
name = "Chemist"
|
||||
jobtype = /datum/job/chemist
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
|
||||
threat = 2
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/cmo
|
||||
name = "Chief Medical Officer"
|
||||
jobtype = /datum/job/cmo
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
display_order = JOB_DISPLAY_ORDER_GENETICIST
|
||||
threat = 1.5
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/geneticist
|
||||
name = "Geneticist"
|
||||
jobtype = /datum/job/geneticist
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
display_order = JOB_DISPLAY_ORDER_MEDICAL_DOCTOR
|
||||
threat = 0.5
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/doctor
|
||||
name = "Medical Doctor"
|
||||
jobtype = /datum/job/doctor
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
threat = 0.5
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/paramedic
|
||||
name = "Paramedic"
|
||||
jobtype = /datum/job/paramedic
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
|
||||
threat = 1.5
|
||||
|
||||
starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
|
||||
skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
|
||||
|
||||
/datum/outfit/job/virologist
|
||||
name = "Virologist"
|
||||
jobtype = /datum/job/virologist
|
||||
|
||||
@@ -55,11 +55,11 @@
|
||||
SSmachines.setup_template_powernets(cables)
|
||||
SSair.setup_template_machinery(atmos_machines)
|
||||
|
||||
/datum/map_template/proc/load_new_z()
|
||||
/datum/map_template/proc/load_new_z(list/traits = list(ZTRAIT_AWAY = TRUE))
|
||||
var/x = round((world.maxx - width)/2)
|
||||
var/y = round((world.maxy - height)/2)
|
||||
|
||||
var/datum/space_level/level = SSmapping.add_new_zlevel(name, list(ZTRAIT_AWAY = TRUE))
|
||||
var/datum/space_level/level = SSmapping.add_new_zlevel(name, traits)
|
||||
var/datum/parsed_map/parsed = load_map(file(mappath), x, y, level.z_value, no_changeturf=(SSatoms.initialized == INITIALIZATION_INSSATOMS), placeOnTop=TRUE)
|
||||
var/list/bounds = parsed.bounds
|
||||
if(!bounds)
|
||||
@@ -121,6 +121,6 @@
|
||||
|
||||
//for your ever biggening badminnery kevinz000
|
||||
//❤ - Cyberboss
|
||||
/proc/load_new_z_level(var/file, var/name)
|
||||
/proc/load_new_z_level(file, name, list/traits)
|
||||
var/datum/map_template/template = new(file, name)
|
||||
template.load_new_z()
|
||||
return template.load_new_z(traits)
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/organ/regenerative_core/on_life()
|
||||
..()
|
||||
. = ..()
|
||||
if(owner.health < owner.crit_threshold)
|
||||
ui_action_click()
|
||||
|
||||
|
||||
@@ -392,6 +392,8 @@
|
||||
|
||||
character.update_parallax_teleport()
|
||||
|
||||
job.standard_assign_skills(character.mind)
|
||||
|
||||
SSticker.minds += character.mind
|
||||
|
||||
var/mob/living/carbon/human/humanc
|
||||
|
||||
@@ -23,11 +23,7 @@
|
||||
if(!pref_species)
|
||||
var/rando_race = pick(GLOB.roundstart_races)
|
||||
pref_species = new rando_race()
|
||||
features = random_features(pref_species?.id)
|
||||
if(gender == MALE || gender != FEMALE)
|
||||
features["body_model"] = gender
|
||||
else if(gender == PLURAL)
|
||||
features["body_model"] = pick(MALE,FEMALE)
|
||||
features = random_features(pref_species?.id, gender)
|
||||
age = rand(AGE_MIN,AGE_MAX)
|
||||
|
||||
/datum/preferences/proc/update_preview_icon(equip_job = TRUE)
|
||||
|
||||
@@ -937,3 +937,20 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
spawners_menu = new(src)
|
||||
|
||||
spawners_menu.ui_interact(src)
|
||||
|
||||
/mob/dead/observer/verb/game_info()
|
||||
set name = "Game info"
|
||||
set desc = "Shows various info relating to the game mode, antagonists etc."
|
||||
set category = "Ghost"
|
||||
if(!started_as_observer && can_reenter_corpse)
|
||||
to_chat(src, "You cannot see this info unless you are an observer or you've chosen Do Not Resuscitate!")
|
||||
return
|
||||
var/list/stuff = list("[SSticker.mode.name]")
|
||||
stuff += "Antagonists:\n"
|
||||
for(var/datum/antagonist/A in GLOB.antagonists)
|
||||
if(A.owner)
|
||||
stuff += "[A.owner] the [A.name]"
|
||||
var/ghost_info = SSticker.mode.ghost_info()
|
||||
if(ghost_info)
|
||||
stuff += ghost_info
|
||||
to_chat(src,stuff.Join("\n"))
|
||||
|
||||
@@ -245,23 +245,17 @@
|
||||
. = adjusted_amount
|
||||
*/
|
||||
|
||||
/obj/item/organ/brain/on_life()
|
||||
if(damage >= BRAIN_DAMAGE_DEATH) //rip
|
||||
to_chat(owner, "<span class='userdanger'>The last spark of life in your brain fizzles out...</span>")
|
||||
owner.death()
|
||||
brain_death = TRUE
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/organ/brain/on_death()
|
||||
if(damage <= BRAIN_DAMAGE_DEATH) //rip
|
||||
brain_death = FALSE
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/organ/brain/applyOrganDamage(var/d, var/maximum = maxHealth)
|
||||
..()
|
||||
|
||||
. = ..()
|
||||
if(!. || !owner)
|
||||
return
|
||||
if(damage >= BRAIN_DAMAGE_DEATH) //rip
|
||||
if(owner.stat != DEAD)
|
||||
to_chat(owner, "<span class='userdanger'>The last spark of life in your brain fizzles out...</span>")
|
||||
owner.death()
|
||||
brain_death = TRUE
|
||||
else
|
||||
brain_death = FALSE
|
||||
|
||||
/obj/item/organ/brain/check_damage_thresholds(mob/M)
|
||||
. = ..()
|
||||
|
||||
@@ -12,6 +12,13 @@
|
||||
bubble_icon = "alien"
|
||||
type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
|
||||
|
||||
/// How much brute damage without armor piercing they do against mobs in melee
|
||||
var/meleeSlashHumanPower = 20
|
||||
/// How much power they have for DefaultCombatKnockdown when attacking humans
|
||||
var/meleeKnockdownPower = 100
|
||||
/// How much brute damage they do to simple animals
|
||||
var/meleeSlashSAPower = 35
|
||||
|
||||
var/obj/item/card/id/wear_id = null // Fix for station bounced radios -- Skie
|
||||
var/has_fine_manipulation = 0
|
||||
var/move_delay_add = 0 // movement delay to add
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
maxHealth = 125
|
||||
health = 125
|
||||
icon_state = "aliend"
|
||||
meleeKnockdownPower = 80
|
||||
|
||||
/mob/living/carbon/alien/humanoid/drone/Initialize()
|
||||
AddAbility(new/obj/effect/proc_holder/alien/evolve(null))
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
/mob/living/carbon/alien/humanoid/hunter
|
||||
name = "alien hunter"
|
||||
caste = "h"
|
||||
maxHealth = 125
|
||||
health = 125
|
||||
maxHealth = 170
|
||||
health = 170
|
||||
icon_state = "alienh"
|
||||
meleeKnockdownPower = 75
|
||||
meleeSlashHumanPower = 20
|
||||
meleeSlashSAPower = 45
|
||||
var/obj/screen/leap_icon = null
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/create_internal_organs()
|
||||
@@ -68,6 +71,7 @@
|
||||
else
|
||||
L.visible_message("<span class ='danger'>[src] pounces on [L]!</span>", "<span class ='userdanger'>[src] pounces on you!</span>")
|
||||
L.DefaultCombatKnockdown(100)
|
||||
L.Stagger(4 SECONDS)
|
||||
sleep(2)//Runtime prevention (infinite bump() calls on hulks)
|
||||
step_towards(src,L)
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/mob/living/carbon/alien/humanoid/sentinel
|
||||
name = "alien sentinel"
|
||||
caste = "s"
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
maxHealth = 140
|
||||
health = 140
|
||||
icon_state = "aliens"
|
||||
meleeSlashHumanPower = 15
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/Initialize()
|
||||
AddAbility(new /obj/effect/proc_holder/alien/sneak)
|
||||
|
||||
@@ -112,7 +112,6 @@
|
||||
return A
|
||||
return FALSE
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/check_breath(datum/gas_mixture/breath)
|
||||
if(breath && breath.total_moles() > 0 && !sneaking)
|
||||
playsound(get_turf(src), pick('sound/voice/lowHiss2.ogg', 'sound/voice/lowHiss3.ogg', 'sound/voice/lowHiss4.ogg'), 50, 0, -5)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/mob/living/carbon/alien/humanoid/grabbedby(mob/living/carbon/user, supress_message = 0)
|
||||
if(user == src && pulling && grab_state >= GRAB_AGGRESSIVE && !pulling.anchored && iscarbon(pulling))
|
||||
devour_mob(pulling, devour_time = 60)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/proc/adjust_body_temperature(current, loc_temp, boost)
|
||||
var/temperature = current
|
||||
var/difference = abs(current-loc_temp) //get difference
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
pressure_resistance = 200 //Because big, stompy xenos should not be blown around like paper.
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/xeno = 20, /obj/item/stack/sheet/animalhide/xeno = 3)
|
||||
|
||||
meleeKnockdownPower = 125
|
||||
meleeSlashHumanPower = 30
|
||||
meleeSlashSAPower = 60
|
||||
|
||||
var/alt_inhands_file = 'icons/mob/alienqueen.dmi'
|
||||
|
||||
/mob/living/carbon/alien/humanoid/royal/can_inject(mob/user, error_msg, target_zone, penetrate_thick = FALSE, bypass_immunity = FALSE)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
density = FALSE
|
||||
hud_type = /datum/hud/larva
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
|
||||
maxHealth = 25
|
||||
health = 25
|
||||
|
||||
@@ -77,6 +77,9 @@
|
||||
alien_powers = list(/obj/effect/proc_holder/alien/transfer)
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/on_life()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
//If there are alien weeds on the ground then heal if needed or give some plasma
|
||||
if(locate(/obj/structure/alien/weeds) in owner.loc)
|
||||
if(owner.health >= owner.maxHealth)
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
/obj/item/organ/body_egg/alien_embryo/on_life()
|
||||
. = ..()
|
||||
if(!owner)
|
||||
return
|
||||
switch(stage)
|
||||
if(2, 3)
|
||||
if(prob(2))
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
update_body_parts() //to update the carbon's new bodyparts appearance
|
||||
GLOB.carbon_list += src
|
||||
blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
|
||||
add_movespeed_modifier(/datum/movespeed_modifier/carbon_crawling)
|
||||
|
||||
/mob/living/carbon/Destroy()
|
||||
//This must be done first, so the mob ghosts correctly before DNA etc is nulled
|
||||
@@ -574,9 +575,9 @@
|
||||
become_husk("burn")
|
||||
med_hud_set_health()
|
||||
if(stat == SOFT_CRIT)
|
||||
add_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE, multiplicative_slowdown = SOFTCRIT_ADD_SLOWDOWN)
|
||||
add_movespeed_modifier(/datum/movespeed_modifier/carbon_softcrit)
|
||||
else
|
||||
remove_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/carbon_softcrit)
|
||||
|
||||
/mob/living/carbon/update_stamina()
|
||||
var/stam = getStaminaLoss()
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
adjustCloneLoss(damage_amount, forced = forced)
|
||||
if(STAMINA)
|
||||
if(BP)
|
||||
if(damage > 0 ? BP.receive_damage(0, 0, damage_amount) : BP.heal_damage(0, 0, abs(damage_amount)))
|
||||
if(damage > 0 ? BP.receive_damage(0, 0, damage_amount) : BP.heal_damage(0, 0, abs(damage_amount), FALSE, FALSE))
|
||||
update_damage_overlays()
|
||||
else
|
||||
adjustStaminaLoss(damage_amount, forced = forced)
|
||||
|
||||
@@ -1041,7 +1041,7 @@
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/proc/clear_shove_slowdown()
|
||||
remove_movespeed_modifier(MOVESPEED_ID_SHOVE)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/shove)
|
||||
var/active_item = get_active_held_item()
|
||||
if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
|
||||
visible_message("<span class='warning'>[src.name] regains their grip on \the [active_item]!</span>", "<span class='warning'>You regain your grip on \the [active_item]</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
@@ -1050,17 +1050,17 @@
|
||||
. = ..()
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_IGNORESLOWDOWN))
|
||||
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN)
|
||||
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
|
||||
return
|
||||
var/stambufferinfluence = (bufferedstam*(100/stambuffer))*0.2 //CIT CHANGE - makes stamina buffer influence movedelay
|
||||
var/health_deficiency = ((100 + stambufferinfluence) - health + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it
|
||||
if(health_deficiency >= 40)
|
||||
add_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN, override = TRUE, multiplicative_slowdown = ((health_deficiency-39) / 75), blacklisted_movetypes = FLOATING|FLYING)
|
||||
add_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING, override = TRUE, multiplicative_slowdown = ((health_deficiency-39) / 25), movetypes = FLYING, blacklisted_movetypes = FLOATING)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown, TRUE, (health_deficiency-39) / 75)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying, TRUE, (health_deficiency-39) / 25)
|
||||
else
|
||||
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN)
|
||||
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
|
||||
|
||||
/mob/living/carbon/human/do_after_coefficent()
|
||||
. = ..()
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
if(M.a_intent == INTENT_HARM)
|
||||
if (w_uniform)
|
||||
w_uniform.add_fingerprint(M)
|
||||
var/damage = prob(90) ? 20 : 0
|
||||
var/damage = prob(90) ? M.meleeSlashHumanPower : 0
|
||||
if(!damage)
|
||||
playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
|
||||
visible_message("<span class='danger'>[M] has lunged at [src]!</span>", \
|
||||
@@ -182,10 +182,7 @@
|
||||
"<span class='userdanger'>[M] disarmed [src]!</span>")
|
||||
else
|
||||
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
|
||||
if(!lying) //CITADEL EDIT
|
||||
DefaultCombatKnockdown(100, TRUE, FALSE, 30, 25)
|
||||
else
|
||||
DefaultCombatKnockdown(100)
|
||||
DefaultCombatKnockdown(M.meleeKnockdownPower)
|
||||
log_combat(M, src, "tackled")
|
||||
visible_message("<span class='danger'>[M] has tackled down [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has tackled down [src]!</span>")
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
/mob/living/carbon/human/get_movespeed_modifiers()
|
||||
var/list/considering = ..()
|
||||
. = considering
|
||||
if(HAS_TRAIT(src, TRAIT_IGNORESLOWDOWN))
|
||||
for(var/id in .)
|
||||
var/list/data = .[id]
|
||||
if(data[MOVESPEED_DATA_INDEX_FLAGS] & IGNORE_NOSLOW)
|
||||
.[id] = data
|
||||
. = list()
|
||||
for(var/id in considering)
|
||||
var/datum/movespeed_modifier/M = considering[id]
|
||||
if(M.flags & IGNORE_NOSLOW || M.multiplicative_slowdown < 0)
|
||||
.[id] = M
|
||||
return
|
||||
return considering
|
||||
|
||||
/mob/living/carbon/human/movement_delay()
|
||||
. = ..()
|
||||
|
||||
@@ -331,7 +331,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(mutant_bodyparts["meat_type"]) //I can't believe it's come to the meat
|
||||
H.type_of_meat = GLOB.meat_types[H.dna.features["meat_type"]]
|
||||
|
||||
C.add_movespeed_modifier(MOVESPEED_ID_SPECIES, TRUE, 100, override=TRUE, multiplicative_slowdown=speedmod, movetypes=(~FLYING))
|
||||
C.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/species, TRUE, multiplicative_slowdown = speedmod)
|
||||
|
||||
SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)
|
||||
|
||||
@@ -349,7 +349,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
for(var/X in inherent_traits)
|
||||
REMOVE_TRAIT(C, X, SPECIES_TRAIT)
|
||||
|
||||
C.remove_movespeed_modifier(MOVESPEED_ID_SPECIES)
|
||||
C.remove_movespeed_modifier(/datum/movespeed_modifier/species)
|
||||
|
||||
if(mutant_bodyparts["meat_type"])
|
||||
C.type_of_meat = GLOB.meat_types[C.dna.features["meat_type"]]
|
||||
@@ -1299,14 +1299,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(H.overeatduration < 100)
|
||||
to_chat(H, "<span class='notice'>You feel fit again!</span>")
|
||||
REMOVE_TRAIT(H, TRAIT_FAT, OBESITY)
|
||||
H.remove_movespeed_modifier(MOVESPEED_ID_FAT)
|
||||
H.remove_movespeed_modifier(/datum/movespeed_modifier/obesity)
|
||||
H.update_inv_w_uniform()
|
||||
H.update_inv_wear_suit()
|
||||
else
|
||||
if(H.overeatduration >= 100)
|
||||
to_chat(H, "<span class='danger'>You suddenly feel blubbery!</span>")
|
||||
ADD_TRAIT(H, TRAIT_FAT, OBESITY)
|
||||
H.add_movespeed_modifier(MOVESPEED_ID_FAT, multiplicative_slowdown = 1.5)
|
||||
H.add_movespeed_modifier(/datum/movespeed_modifier/obesity)
|
||||
H.update_inv_w_uniform()
|
||||
H.update_inv_wear_suit()
|
||||
|
||||
@@ -1362,9 +1362,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(!HAS_TRAIT(H, TRAIT_NOHUNGER))
|
||||
var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80
|
||||
if(hungry >= 70)
|
||||
H.add_movespeed_modifier(MOVESPEED_ID_HUNGRY, override = TRUE, multiplicative_slowdown = (hungry / 50))
|
||||
H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (hungry / 50))
|
||||
else
|
||||
H.remove_movespeed_modifier(MOVESPEED_ID_HUNGRY)
|
||||
H.remove_movespeed_modifier(/datum/movespeed_modifier/hunger)
|
||||
|
||||
switch(H.nutrition)
|
||||
if(NUTRITION_LEVEL_FULL to INFINITY)
|
||||
@@ -1615,7 +1615,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
"You hear a slap."
|
||||
)
|
||||
return FALSE
|
||||
|
||||
|
||||
else
|
||||
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
|
||||
|
||||
@@ -1623,10 +1623,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
user.adjustStaminaLossBuffered(1)
|
||||
else
|
||||
user.adjustStaminaLossBuffered(3)
|
||||
|
||||
|
||||
if(attacker_style && attacker_style.disarm_act(user,target))
|
||||
return TRUE
|
||||
|
||||
|
||||
if(target.w_uniform)
|
||||
target.w_uniform.add_fingerprint(user)
|
||||
//var/randomized_zone = ran_zone(user.zone_selected) CIT CHANGE - comments out to prevent compiling errors
|
||||
@@ -1659,7 +1659,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
randn -= 25 //if you are a pugilist, you're slapping that item from them pretty reliably
|
||||
if(HAS_TRAIT(target, TRAIT_PUGILIST))
|
||||
randn += 25 //meanwhile, pugilists are less likely to get disarmed
|
||||
|
||||
|
||||
if(randn <= 35)//CIT CHANGE - changes this back to a 35% chance to accomodate for the above being commented out in favor of right-click pushing
|
||||
var/obj/item/I = null
|
||||
if(target.pulling)
|
||||
@@ -1932,8 +1932,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/obj/item/target_held_item = target.get_active_held_item()
|
||||
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
|
||||
target_held_item = null
|
||||
if(!target.has_movespeed_modifier(MOVESPEED_ID_SHOVE))
|
||||
target.add_movespeed_modifier(MOVESPEED_ID_SHOVE, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH)
|
||||
if(!target.has_movespeed_modifier(/datum/movespeed_modifier/shove))
|
||||
target.add_movespeed_modifier(/datum/movespeed_modifier/shove)
|
||||
if(target_held_item)
|
||||
if(!HAS_TRAIT(target_held_item, TRAIT_NODROP))
|
||||
target.visible_message("<span class='danger'>[target.name]'s grip on \the [target_held_item] loosens!</span>",
|
||||
@@ -2084,7 +2084,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold")
|
||||
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "hot", /datum/mood_event/hot)
|
||||
|
||||
H.remove_movespeed_modifier(MOVESPEED_ID_COLD)
|
||||
H.remove_movespeed_modifier(/datum/movespeed_modifier/cold)
|
||||
|
||||
var/burn_damage
|
||||
var/firemodifier = H.fire_stacks / 50
|
||||
@@ -2101,8 +2101,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
else if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !HAS_TRAIT(H, TRAIT_RESISTCOLD))
|
||||
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot")
|
||||
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "cold", /datum/mood_event/cold)
|
||||
//Sorry for the nasty oneline but I don't want to assign a variable on something run pretty frequently
|
||||
H.add_movespeed_modifier(MOVESPEED_ID_COLD, override = TRUE, multiplicative_slowdown = ((BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR), blacklisted_movetypes = FLOATING)
|
||||
//Apply cold slowdown
|
||||
H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/cold, multiplicative_slowdown = ((BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR))
|
||||
switch(H.bodytemperature)
|
||||
if(200 to BODYTEMP_COLD_DAMAGE_LIMIT)
|
||||
H.apply_damage(COLD_DAMAGE_LEVEL_1*coldmod*H.physiology.cold_mod, BURN)
|
||||
@@ -2112,7 +2112,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
H.apply_damage(COLD_DAMAGE_LEVEL_3*coldmod*H.physiology.cold_mod, BURN)
|
||||
|
||||
else
|
||||
H.remove_movespeed_modifier(MOVESPEED_ID_COLD)
|
||||
H.remove_movespeed_modifier(/datum/movespeed_modifier/cold)
|
||||
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold")
|
||||
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot")
|
||||
|
||||
|
||||
@@ -101,12 +101,11 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
|
||||
|
||||
/obj/item/organ/dwarfgland/on_life() //Primary loop to hook into to start delayed loops for other loops..
|
||||
. = ..()
|
||||
dwarf_cycle_ticker()
|
||||
if(owner && owner.stat != DEAD)
|
||||
dwarf_cycle_ticker()
|
||||
|
||||
//Handles the delayed tick cycle by just adding on increments per each on_life() tick
|
||||
/obj/item/organ/dwarfgland/proc/dwarf_cycle_ticker()
|
||||
if(owner.stat == DEAD)
|
||||
return //We make sure they are not dead, so they don't increment any tickers.
|
||||
dwarf_eth_ticker++
|
||||
dwarf_filth_ticker++
|
||||
|
||||
|
||||
@@ -91,4 +91,9 @@
|
||||
if((C.dna.features["spines"] != "None" ) && (C.dna.features["tail_lizard"] == "None")) //tbh, it's kinda ugly for them not to have a tail yet have floating spines
|
||||
C.dna.features["tail_lizard"] = "Smooth"
|
||||
C.update_body()
|
||||
if(C.dna.features["legs"] != "digitigrade")
|
||||
C.dna.features["legs"] = "digitigrade"
|
||||
for(var/obj/item/bodypart/leggie in C.bodyparts)
|
||||
if(leggie.body_zone == BODY_ZONE_L_LEG || leggie.body_zone == BODY_ZONE_R_LEG)
|
||||
leggie.update_limb(FALSE, C)
|
||||
return ..()
|
||||
|
||||
@@ -65,12 +65,11 @@
|
||||
|
||||
/mob/living/carbon/monkey/on_reagent_change()
|
||||
. = ..()
|
||||
remove_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE)
|
||||
var/amount
|
||||
if(reagents.has_reagent(/datum/reagent/medicine/morphine))
|
||||
amount = -1
|
||||
if(amount)
|
||||
add_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/monkey_reagent_speedmod, TRUE, amount)
|
||||
|
||||
/mob/living/carbon/monkey/updatehealth()
|
||||
. = ..()
|
||||
@@ -78,7 +77,7 @@
|
||||
var/health_deficiency = (100 - health)
|
||||
if(health_deficiency >= 45)
|
||||
slow += (health_deficiency / 25)
|
||||
add_movespeed_modifier(MOVESPEED_ID_MONKEY_HEALTH_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = slow)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/monkey_health_speedmod, TRUE, slow)
|
||||
|
||||
/mob/living/carbon/monkey/adjust_bodytemperature(amount)
|
||||
. = ..()
|
||||
@@ -87,7 +86,7 @@
|
||||
slow += (283.222 - bodytemperature) / 10 * 1.75
|
||||
if(slow <= 0)
|
||||
return
|
||||
add_movespeed_modifier(MOVESPEED_ID_MONKEY_TEMPERATURE_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/monkey_temperature_speedmod, TRUE, slow)
|
||||
|
||||
/mob/living/carbon/monkey/Stat()
|
||||
..()
|
||||
@@ -99,7 +98,6 @@
|
||||
if(changeling)
|
||||
stat("Chemical Storage", "[changeling.chem_charges]/[changeling.chem_storage]")
|
||||
stat("Absorbed DNA", changeling.absorbedcount)
|
||||
return
|
||||
|
||||
|
||||
/mob/living/carbon/monkey/verb/removeinternal()
|
||||
|
||||
@@ -94,11 +94,13 @@
|
||||
|
||||
if(should_be_lying)
|
||||
mobility_flags &= ~MOBILITY_STAND
|
||||
setMovetype(movement_type | CRAWLING)
|
||||
if(!lying) //force them on the ground
|
||||
lying = pick(90, 270)
|
||||
if(has_gravity() && !buckled)
|
||||
playsound(src, "bodyfall", 20, 1)
|
||||
else
|
||||
setMovetype(movement_type & ~CRAWLING)
|
||||
mobility_flags |= MOBILITY_STAND
|
||||
lying = 0
|
||||
|
||||
@@ -161,8 +163,8 @@
|
||||
if(!has_legs && has_arms < 2)
|
||||
limbless_slowdown += 6 - (has_arms * 3)
|
||||
if(limbless_slowdown)
|
||||
add_movespeed_modifier(MOVESPEED_ID_LIVING_LIMBLESS, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=limbless_slowdown, blacklisted_movetypes = FLYING|FLOATING)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/limbless, multiplicative_slowdown = limbless_slowdown)
|
||||
else
|
||||
remove_movespeed_modifier(MOVESPEED_ID_LIVING_LIMBLESS, update=TRUE)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/limbless)
|
||||
|
||||
return mobility_flags
|
||||
|
||||
@@ -36,38 +36,26 @@
|
||||
sprint_stamina_cost = CONFIG_GET(number/movedelay/sprint_stamina_cost)
|
||||
return ..()
|
||||
|
||||
/mob/living/movement_delay(ignorewalk = 0)
|
||||
. = ..()
|
||||
if(!CHECK_MOBILITY(src, MOBILITY_STAND))
|
||||
. += 6
|
||||
|
||||
/// whether or not we can slide under another living mob. defaults to if we're not dense. CanPass should check "overriding circumstances" like buckled mobs/having PASSMOB flag, etc.
|
||||
/mob/living/proc/can_move_under_living(mob/living/other)
|
||||
return !density
|
||||
|
||||
/mob/living/proc/update_move_intent_slowdown()
|
||||
var/mod = 0
|
||||
if(m_intent == MOVE_INTENT_WALK)
|
||||
mod = CONFIG_GET(number/movedelay/walk_delay)
|
||||
else
|
||||
mod = CONFIG_GET(number/movedelay/run_delay)
|
||||
if(!isnum(mod))
|
||||
mod = 1
|
||||
add_movespeed_modifier(MOVESPEED_ID_MOB_WALK_RUN_CONFIG_SPEED, TRUE, 100, override = TRUE, multiplicative_slowdown = mod)
|
||||
add_movespeed_modifier((m_intent == MOVE_INTENT_WALK)? /datum/movespeed_modifier/config_walk_run/walk : /datum/movespeed_modifier/config_walk_run/run)
|
||||
|
||||
/mob/living/proc/update_turf_movespeed(turf/open/T)
|
||||
if(isopenturf(T) && !is_flying())
|
||||
add_movespeed_modifier(MOVESPEED_ID_LIVING_TURF_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = T.slowdown)
|
||||
if(isopenturf(T))
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/turf_slowdown, multiplicative_slowdown = T.slowdown)
|
||||
else
|
||||
remove_movespeed_modifier(MOVESPEED_ID_LIVING_TURF_SPEEDMOD)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/turf_slowdown)
|
||||
|
||||
/mob/living/proc/update_pull_movespeed()
|
||||
if(pulling && isliving(pulling))
|
||||
var/mob/living/L = pulling
|
||||
if(drag_slowdown && L.lying && !L.buckled && grab_state < GRAB_AGGRESSIVE)
|
||||
add_movespeed_modifier(MOVESPEED_ID_PRONE_DRAGGING, multiplicative_slowdown = PULL_PRONE_SLOWDOWN)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/bulky_drag, multiplicative_slowdown = PULL_PRONE_SLOWDOWN)
|
||||
return
|
||||
remove_movespeed_modifier(MOVESPEED_ID_PRONE_DRAGGING)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/bulky_drag)
|
||||
|
||||
/mob/living/canZMove(dir, turf/target)
|
||||
return can_zTravel(target, dir) && (movement_type & FLYING)
|
||||
|
||||
@@ -273,9 +273,9 @@
|
||||
/mob/living/silicon/pai/Process_Spacemove(movement_dir = 0)
|
||||
. = ..()
|
||||
if(!.)
|
||||
add_movespeed_modifier(MOVESPEED_ID_PAI_SPACEWALK_SPEEDMOD, TRUE, 100, multiplicative_slowdown = 2)
|
||||
add_movespeed_modifier(/datum/movespeed_modifier/pai_spacewalk)
|
||||
return TRUE
|
||||
remove_movespeed_modifier(MOVESPEED_ID_PAI_SPACEWALK_SPEEDMOD, TRUE)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/pai_spacewalk)
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/pai/examine(mob/user)
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
return
|
||||
|
||||
if(!CONFIG_GET(flag/disable_secborg) && GLOB.security_level < CONFIG_GET(number/minimum_secborg_alert))
|
||||
to_chat(src, "<span class='notice'>NOTICE: Due to local station regulations, the security cyborg module and its variants are only available during [num2seclevel(CONFIG_GET(number/minimum_secborg_alert))] alert and greater.</span>")
|
||||
to_chat(src, "<span class='notice'>NOTICE: Due to local station regulations, the security cyborg module and its variants are only available during [NUM2SECLEVEL(CONFIG_GET(number/minimum_secborg_alert))] alert and greater.</span>")
|
||||
|
||||
var/list/modulelist = list("Standard" = /obj/item/robot_module/standard, \
|
||||
"Engineering" = /obj/item/robot_module/engineering, \
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/mob/living/silicon/KnockToFloor(disarm_items = FALSE, silent = TRUE, updating = TRUE)
|
||||
return
|
||||
|
||||
/mob/living/silicon/grippedby(mob/living/user, instant = FALSE)
|
||||
return //can't upgrade a simple pull into a more aggressive grab.
|
||||
|
||||
@@ -61,11 +61,10 @@
|
||||
"<span class='userdanger'>[M] [response_disarm] [name]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
log_combat(M, src, "disarmed")
|
||||
else
|
||||
var/damage = rand(15, 30)
|
||||
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has slashed at [src]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
|
||||
attack_threshold_check(damage)
|
||||
attack_threshold_check(M.meleeSlashSAPower)
|
||||
log_combat(M, src, "attacked")
|
||||
|
||||
/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L)
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
path_image_color = "#993299"
|
||||
weather_immunities = list("lava","ash")
|
||||
|
||||
var/clean_time = 50 //How long do we take to clean?
|
||||
var/broom = FALSE //Do we have an speed buff from a broom?
|
||||
var/adv_mop = FALSE //Do we have a cleaning buff from a better mop?
|
||||
|
||||
|
||||
var/blood = 1
|
||||
var/trash = 0
|
||||
var/pests = 0
|
||||
@@ -75,6 +80,26 @@
|
||||
to_chat(user, "<span class='warning'>Please close the access panel before locking it.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>\The [src] doesn't seem to respect your authority.</span>")
|
||||
|
||||
if(istype(W, /obj/item/mop/advanced))
|
||||
if(bot_core.allowed(user) && open && adv_mop == TRUE)
|
||||
to_chat(user, "<span class='notice'>You replace \the [src] old mop with a new better one!</span>")
|
||||
adv_mop = TRUE
|
||||
clean_time = 20 //2.5 the speed!
|
||||
window_name = "Automatic Station Cleaner v2.1 BETA" //New!
|
||||
qdel(W)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>\the [src] already has this mop!</span>")
|
||||
|
||||
if(istype(W, /obj/item/twohanded/broom))
|
||||
if(bot_core.allowed(user) && open && broom == TRUE)
|
||||
to_chat(user, "<span class='notice'>You add to \the [src] a broom speeding it up!</span>")
|
||||
broom = TRUE
|
||||
base_speed = 1 //2x faster!
|
||||
qdel(W)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>\the [src] already has a broom!</span>")
|
||||
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -221,7 +246,7 @@
|
||||
icon_state = "cleanbot-c"
|
||||
visible_message("<span class='notice'>[src] begins to clean up [A].</span>")
|
||||
mode = BOT_CLEANING
|
||||
spawn(50)
|
||||
spawn(clean_time)
|
||||
if(mode == BOT_CLEANING)
|
||||
if(A && isturf(A.loc))
|
||||
var/atom/movable/AM = A
|
||||
|
||||
@@ -264,6 +264,9 @@
|
||||
if((last_newpatient_speak + 300) < world.time) //Don't spam these messages!
|
||||
var/list/messagevoice = list("Hey, [H.name]! Hold on, I'm coming." = 'sound/voice/medbot/coming.ogg',"Wait [H.name]! I want to help!" = 'sound/voice/medbot/help.ogg',"[H.name], you appear to be injured!" = 'sound/voice/medbot/injured.ogg')
|
||||
var/message = pick(messagevoice)
|
||||
if(prob(1) && ISINRANGE_EX(H.getFireLoss(), 0, 20))
|
||||
message = "Notices your minor burns*OwO what's this?"
|
||||
messagevoice[message] = 'sound/voice/medbot/owo.ogg'
|
||||
speak(message)
|
||||
playsound(loc, messagevoice[message], 50, 0)
|
||||
last_newpatient_speak = world.time
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
icon_living = "carp"
|
||||
icon_dead = "carp_dead"
|
||||
icon_gib = "carp_gib"
|
||||
threat = 0.2
|
||||
threat = 0.1
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
speak_chance = 0
|
||||
turns_per_move = 5
|
||||
|
||||
@@ -186,10 +186,10 @@
|
||||
. = ..()
|
||||
if(slowed_by_webs)
|
||||
if(!(locate(/obj/structure/spider/stickyweb) in loc))
|
||||
remove_movespeed_modifier(MOVESPEED_ID_TARANTULA_WEB)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/tarantula_web)
|
||||
slowed_by_webs = FALSE
|
||||
else if(locate(/obj/structure/spider/stickyweb) in loc)
|
||||
add_movespeed_modifier(MOVESPEED_ID_TARANTULA_WEB, priority=100, multiplicative_slowdown=3)
|
||||
add_movespeed_modifier(/datum/movespeed_modifier/tarantula_web)
|
||||
slowed_by_webs = TRUE
|
||||
|
||||
//midwives are the queen of the spiders, can send messages to all them and web faster. That rare round where you get a queen spider and turn your 'for honor' players into 'r6siege' players will be a fun one.
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
|
||||
|
||||
/**
|
||||
* Kudzu Flower Bud
|
||||
*
|
||||
* A flower created by flowering kudzu which spawns a venus human trap after a certain amount of time has passed.
|
||||
*
|
||||
* A flower created by kudzu with the flowering mutation. Spawns a venus human trap after 2 minutes under normal circumstances.
|
||||
* Also spawns 4 vines going out in diagonal directions from the bud. Any living creature not aligned with plants is damaged by these vines.
|
||||
* Once it grows a venus human trap, the bud itself will destroy itself.
|
||||
*
|
||||
*/
|
||||
/obj/structure/alien/resin/flower_bud_enemy //inheriting basic attack/damage stuff from alien structures
|
||||
name = "flower bud"
|
||||
desc = "A large pulsating plant..."
|
||||
@@ -9,9 +17,9 @@
|
||||
opacity = 0
|
||||
canSmoothWith = list()
|
||||
smooth = SMOOTH_FALSE
|
||||
/// The amount of time it takes to create a venus human trap, in deciseconds
|
||||
var/growth_time = 1200
|
||||
|
||||
|
||||
/obj/structure/alien/resin/flower_bud_enemy/Initialize()
|
||||
. = ..()
|
||||
var/list/anchors = list()
|
||||
@@ -25,36 +33,49 @@
|
||||
B.sleep_time = 10 //these shouldn't move, so let's slow down updates to 1 second (any slower and the deletion of the vines would be too slow)
|
||||
addtimer(CALLBACK(src, .proc/bear_fruit), growth_time)
|
||||
|
||||
/**
|
||||
* Spawns a venus human trap, then qdels itself.
|
||||
*
|
||||
* Displays a message, spawns a human venus trap, then qdels itself.
|
||||
*/
|
||||
/obj/structure/alien/resin/flower_bud_enemy/proc/bear_fruit()
|
||||
visible_message("<span class='danger'>the plant has borne fruit!</span>")
|
||||
visible_message("<span class='danger'>The plant has borne fruit!</span>")
|
||||
new /mob/living/simple_animal/hostile/venus_human_trap(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/effect/ebeam/vine
|
||||
name = "thick vine"
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
desc = "A thick vine, painful to the touch."
|
||||
|
||||
|
||||
/obj/effect/ebeam/vine/Crossed(atom/movable/AM)
|
||||
. = ..()
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(!("vines" in L.faction))
|
||||
if(!isvineimmune(L))
|
||||
L.adjustBruteLoss(5)
|
||||
to_chat(L, "<span class='alert'>You cut yourself on the thorny vines.</span>")
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Venus Human Trap
|
||||
*
|
||||
* The result of a kudzu flower bud, these enemies use vines to drag prey close to them for attack.
|
||||
*
|
||||
* A carnivorious plant which uses vines to catch and ensnare prey. Spawns from kudzu flower buds.
|
||||
* Each one has a maximum of four vines, which can be attached to a variety of things. Carbons are stunned when a vine is attached to them, and movable entities are pulled closer over time.
|
||||
* Attempting to attach a vine to something with a vine already attached to it will pull all movable targets closer on command.
|
||||
* Once the prey is in melee range, melee attacks from the venus human trap heals itself for 10% of its max health, assuming the target is alive.
|
||||
* Akin to certain spiders, venus human traps can also be possessed and controlled by ghosts.
|
||||
*
|
||||
*/
|
||||
/mob/living/simple_animal/hostile/venus_human_trap
|
||||
name = "venus human trap"
|
||||
desc = "Now you know how the fly feels."
|
||||
icon_state = "venus_human_trap"
|
||||
threat = 1
|
||||
layer = SPACEVINE_MOB_LAYER
|
||||
health = 50
|
||||
maxHealth = 50
|
||||
ranged = 1
|
||||
ranged = TRUE
|
||||
harm_intent_damage = 5
|
||||
obj_damage = 60
|
||||
melee_damage_lower = 25
|
||||
@@ -63,65 +84,110 @@
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
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)
|
||||
unsuitable_atmos_damage = 0
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
faction = list("hostile","vines","plants")
|
||||
var/list/grasping = list()
|
||||
var/max_grasps = 4
|
||||
var/grasp_chance = 20
|
||||
var/grasp_pull_chance = 85
|
||||
var/grasp_range = 4
|
||||
del_on_death = 1
|
||||
initial_language_holder = /datum/language_holder/venus
|
||||
del_on_death = TRUE
|
||||
/// A list of all the plant's vines
|
||||
var/list/vines = list()
|
||||
/// The maximum amount of vines a plant can have at one time
|
||||
var/max_vines = 4
|
||||
/// How far away a plant can attach a vine to something
|
||||
var/vine_grab_distance = 5
|
||||
/// Whether or not this plant is ghost possessable
|
||||
var/playable_plant = FALSE //Normal plants can **not** have players.
|
||||
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/Destroy()
|
||||
for(var/L in grasping)
|
||||
var/datum/beam/B = grasping[L]
|
||||
if(B)
|
||||
qdel(B)
|
||||
grasping = null
|
||||
return ..()
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/ghost_playable
|
||||
playable_plant = TRUE //For admins that want to buss some harmless plants
|
||||
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/handle_automated_action()
|
||||
if(..())
|
||||
for(var/mob/living/L in grasping)
|
||||
if(L.stat == DEAD)
|
||||
var/datum/beam/B = grasping[L]
|
||||
if(B)
|
||||
B.End()
|
||||
grasping -= L
|
||||
|
||||
//Can attack+pull multiple times per cycle
|
||||
if(L.Adjacent(src))
|
||||
L.attack_animal(src)
|
||||
else
|
||||
if(prob(grasp_pull_chance))
|
||||
setDir(get_dir(src,L) )//staaaare
|
||||
step(L,get_dir(L,src)) //reel them in
|
||||
L.DefaultCombatKnockdown(60) //you can't get away now~
|
||||
|
||||
if(grasping.len < max_grasps)
|
||||
grasping:
|
||||
for(var/mob/living/L in view(grasp_range, src))
|
||||
if(L == src || faction_check_mob(L) || (L in grasping) || L == target)
|
||||
continue
|
||||
for(var/t in getline(src,L))
|
||||
for(var/a in t)
|
||||
var/atom/A = a
|
||||
if(A.density && A != L)
|
||||
continue grasping
|
||||
if(prob(grasp_chance))
|
||||
to_chat(L, "<span class='userdanger'>\The [src] has you entangled!</span>")
|
||||
grasping[L] = Beam(L, "vine", time=INFINITY, maxdistance=5, beam_type=/obj/effect/ebeam/vine)
|
||||
|
||||
break //only take 1 new victim per cycle
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/Life()
|
||||
. = ..()
|
||||
pull_vines()
|
||||
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/AttackingTarget()
|
||||
. = ..()
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat != DEAD)
|
||||
adjustHealth(-maxHealth * 0.1)
|
||||
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/OpenFire(atom/the_target)
|
||||
var/dist = get_dist(src,the_target)
|
||||
Beam(the_target, "vine", time=dist*2, maxdistance=dist+2, beam_type=/obj/effect/ebeam/vine)
|
||||
the_target.attack_animal(src)
|
||||
for(var/datum/beam/B in vines)
|
||||
if(B.target == the_target)
|
||||
pull_vines()
|
||||
ranged_cooldown = world.time + (ranged_cooldown_time * 0.5)
|
||||
return
|
||||
if(get_dist(src,the_target) > vine_grab_distance || vines.len == max_vines)
|
||||
return
|
||||
for(var/turf/T in getline(src,target))
|
||||
if (T.density)
|
||||
return
|
||||
for(var/obj/O in T)
|
||||
if(O.density)
|
||||
return
|
||||
|
||||
var/datum/beam/newVine = Beam(the_target, "vine", time=INFINITY, maxdistance = vine_grab_distance, beam_type=/obj/effect/ebeam/vine)
|
||||
RegisterSignal(newVine, COMSIG_PARENT_QDELETING, .proc/remove_vine, newVine)
|
||||
vines += newVine
|
||||
if(isliving(the_target))
|
||||
var/mob/living/L = the_target
|
||||
L.Paralyze(20)
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/CanAttack(atom/the_target)
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/Login()
|
||||
. = ..()
|
||||
to_chat(src, "<span class='boldwarning'>You a venus human trap! Protect the kudzu at all costs, and feast on those who oppose you!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/attack_ghost(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
if(the_target in grasping)
|
||||
return 0
|
||||
return
|
||||
humanize_plant(user)
|
||||
|
||||
/**
|
||||
* Sets a ghost to control the plant if the plant is eligible
|
||||
*
|
||||
* Asks the interacting ghost if they would like to control the plant.
|
||||
* If they answer yes, and another ghost hasn't taken control, sets the ghost to control the plant.
|
||||
* Arguments:
|
||||
* * mob/user - The ghost to possibly control the plant
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/proc/humanize_plant(mob/user)
|
||||
if(key || !playable_plant || stat)
|
||||
return
|
||||
var/plant_ask = alert("Become a venus human trap?", "Are you reverse vegan?", "Yes", "No")
|
||||
if(plant_ask == "No" || QDELETED(src))
|
||||
return
|
||||
if(key)
|
||||
to_chat(user, "<span class='warning'>Someone else already took this plant!</span>")
|
||||
return
|
||||
key = user.key
|
||||
log_game("[key_name(src)] took control of [name].")
|
||||
|
||||
/**
|
||||
* Manages how the vines should affect the things they're attached to.
|
||||
*
|
||||
* Pulls all movable targets of the vines closer to the plant
|
||||
* If the target is on the same tile as the plant, destroy the vine
|
||||
* Removes any QDELETED vines from the vines list.
|
||||
*/
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/proc/pull_vines()
|
||||
for(var/datum/beam/B in vines)
|
||||
if(istype(B.target, /atom/movable))
|
||||
var/atom/movable/AM = B.target
|
||||
if(!AM.anchored)
|
||||
step(AM,get_dir(AM,src))
|
||||
if(get_dist(src,B.target) == 0)
|
||||
B.End()
|
||||
|
||||
/**
|
||||
* Removes a vine from the list.
|
||||
*
|
||||
* Removes the vine from our list.
|
||||
* Called specifically when the vine is about to be destroyed, so we don't have any null references.
|
||||
* Arguments:
|
||||
* * datum/beam/vine - The vine to be removed from the list.
|
||||
*/
|
||||
mob/living/simple_animal/hostile/venus_human_trap/proc/remove_vine(datum/beam/vine, force)
|
||||
vines -= vine
|
||||
|
||||
@@ -292,8 +292,8 @@
|
||||
|
||||
/mob/living/simple_animal/proc/update_simplemob_varspeed()
|
||||
if(speed == 0)
|
||||
remove_movespeed_modifier(MOVESPEED_ID_SIMPLEMOB_VARSPEED, TRUE)
|
||||
add_movespeed_modifier(MOVESPEED_ID_SIMPLEMOB_VARSPEED, TRUE, 100, multiplicative_slowdown = speed, override = TRUE)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/simplemob_varspeed)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/simplemob_varspeed, multiplicative_slowdown = speed)
|
||||
|
||||
/mob/living/simple_animal/Stat()
|
||||
..()
|
||||
|
||||
@@ -147,25 +147,25 @@
|
||||
|
||||
/mob/living/simple_animal/slime/on_reagent_change()
|
||||
. = ..()
|
||||
remove_movespeed_modifier(MOVESPEED_ID_SLIME_REAGENTMOD, TRUE)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/slime_reagentmod)
|
||||
var/amount = 0
|
||||
if(reagents.has_reagent(/datum/reagent/medicine/morphine)) // morphine slows slimes down
|
||||
amount = 2
|
||||
if(reagents.has_reagent(/datum/reagent/consumable/frostoil)) // Frostoil also makes them move VEEERRYYYYY slow
|
||||
amount = 5
|
||||
if(amount)
|
||||
add_movespeed_modifier(MOVESPEED_ID_SLIME_REAGENTMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/slime_reagentmod, multiplicative_slowdown = amount)
|
||||
|
||||
/mob/living/simple_animal/slime/updatehealth()
|
||||
. = ..()
|
||||
remove_movespeed_modifier(MOVESPEED_ID_SLIME_HEALTHMOD, FALSE)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/slime_healthmod)
|
||||
var/health_deficiency = (100 - health)
|
||||
var/mod = 0
|
||||
if(health_deficiency >= 45)
|
||||
mod += (health_deficiency / 25)
|
||||
if(health <= 0)
|
||||
mod += 2
|
||||
add_movespeed_modifier(MOVESPEED_ID_SLIME_HEALTHMOD, TRUE, 100, multiplicative_slowdown = mod)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/slime_healthmod, multiplicative_slowdown = mod)
|
||||
|
||||
/mob/living/simple_animal/slime/adjust_bodytemperature()
|
||||
. = ..()
|
||||
@@ -173,9 +173,8 @@
|
||||
if(bodytemperature >= 330.23) // 135 F or 57.08 C
|
||||
mod = -1 // slimes become supercharged at high temperatures
|
||||
else if(bodytemperature < 183.222)
|
||||
mod = (283.222 - bodytemperature) / 10 * 1.75
|
||||
if(mod)
|
||||
add_movespeed_modifier(MOVESPEED_ID_SLIME_TEMPMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = mod)
|
||||
mod = min(15, (283.222 - bodytemperature) / 10 * 1.75)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/slime_tempmod, multiplicative_slowdown = mod)
|
||||
|
||||
/mob/living/simple_animal/slime/ObjBump(obj/O)
|
||||
if(!client && powerlevel > 0)
|
||||
|
||||
@@ -622,10 +622,40 @@
|
||||
tod = STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)
|
||||
update_stat()
|
||||
|
||||
///Unignores all slowdowns that lack the IGNORE_NOSLOW flag.
|
||||
/mob/living/proc/unignore_slowdown(source)
|
||||
REMOVE_TRAIT(src, TRAIT_IGNORESLOWDOWN, source)
|
||||
update_movespeed(FALSE)
|
||||
update_movespeed()
|
||||
|
||||
///Ignores all slowdowns that lack the IGNORE_NOSLOW flag.
|
||||
/mob/living/proc/ignore_slowdown(source)
|
||||
ADD_TRAIT(src, TRAIT_IGNORESLOWDOWN, source)
|
||||
update_movespeed(FALSE)
|
||||
update_movespeed()
|
||||
|
||||
///Ignores specific slowdowns. Accepts a list of slowdowns.
|
||||
/mob/living/proc/add_movespeed_mod_immunities(source, slowdown_type, update = TRUE)
|
||||
if(islist(slowdown_type))
|
||||
for(var/listed_type in slowdown_type)
|
||||
if(ispath(listed_type))
|
||||
listed_type = "[listed_type]" //Path2String
|
||||
LAZYADDASSOC(movespeed_mod_immunities, listed_type, source)
|
||||
else
|
||||
if(ispath(slowdown_type))
|
||||
slowdown_type = "[slowdown_type]" //Path2String
|
||||
LAZYADDASSOC(movespeed_mod_immunities, slowdown_type, source)
|
||||
if(update)
|
||||
update_movespeed()
|
||||
|
||||
///Unignores specific slowdowns. Accepts a list of slowdowns.
|
||||
/mob/living/proc/remove_movespeed_mod_immunities(source, slowdown_type, update = TRUE)
|
||||
if(islist(slowdown_type))
|
||||
for(var/listed_type in slowdown_type)
|
||||
if(ispath(listed_type))
|
||||
listed_type = "[listed_type]" //Path2String
|
||||
LAZYREMOVEASSOC(movespeed_mod_immunities, listed_type, source)
|
||||
else
|
||||
if(ispath(slowdown_type))
|
||||
slowdown_type = "[slowdown_type]" //Path2String
|
||||
LAZYREMOVEASSOC(movespeed_mod_immunities, slowdown_type, source)
|
||||
if(update)
|
||||
update_movespeed()
|
||||
|
||||
@@ -1033,17 +1033,22 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
|
||||
/// Updates the grab state of the mob and updates movespeed
|
||||
/mob/setGrabState(newstate)
|
||||
. = ..()
|
||||
if(grab_state == GRAB_PASSIVE)
|
||||
remove_movespeed_modifier(MOVESPEED_ID_MOB_GRAB_STATE, update=TRUE)
|
||||
else
|
||||
add_movespeed_modifier(MOVESPEED_ID_MOB_GRAB_STATE, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=grab_state*3, blacklisted_movetypes=FLOATING)
|
||||
switch(grab_state)
|
||||
if(GRAB_PASSIVE)
|
||||
remove_movespeed_modifier(MOVESPEED_ID_MOB_GRAB_STATE)
|
||||
if(GRAB_AGGRESSIVE)
|
||||
add_movespeed_modifier(/datum/movespeed_modifier/grab_slowdown/aggressive)
|
||||
if(GRAB_NECK)
|
||||
add_movespeed_modifier(/datum/movespeed_modifier/grab_slowdown/neck)
|
||||
if(GRAB_KILL)
|
||||
add_movespeed_modifier(/datum/movespeed_modifier/grab_slowdown/kill)
|
||||
|
||||
/mob/proc/update_equipment_speed_mods()
|
||||
var/speedies = equipped_speed_mods()
|
||||
if(!speedies)
|
||||
remove_movespeed_modifier(MOVESPEED_ID_MOB_EQUIPMENT, update=TRUE)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/equipment_speedmod, update=TRUE)
|
||||
else
|
||||
add_movespeed_modifier(MOVESPEED_ID_MOB_EQUIPMENT, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=speedies, blacklisted_movetypes=FLOATING)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/equipment_speedmod, multiplicative_slowdown = speedies)
|
||||
|
||||
/// Gets the combined speed modification of all worn items
|
||||
/// Except base mob type doesnt really wear items
|
||||
|
||||
@@ -42,8 +42,11 @@
|
||||
var/lying_prev = 0
|
||||
var/is_shifted = FALSE
|
||||
|
||||
//MOVEMENT SPEED
|
||||
/// List of movement speed modifiers applying to this mob
|
||||
var/list/movespeed_modification //Lazy list, see mob_movespeed.dm
|
||||
/// List of movement speed modifiers ignored by this mob. List -> List (id) -> List (sources)
|
||||
var/list/movespeed_mod_immunities //Lazy list, see mob_movespeed.dm
|
||||
/// The calculated mob speed slowdown based on the modifiers list
|
||||
var/cached_multiplicative_slowdown
|
||||
/////////////////
|
||||
|
||||
|
||||
@@ -80,12 +80,12 @@
|
||||
var/oldloc = mob.loc
|
||||
|
||||
if(L.confused)
|
||||
var/newdir = 0
|
||||
if(L.confused > 40)
|
||||
var/newdir = NONE
|
||||
if((L.confused > 50) && prob(min(L.confused * 0.5, 50)))
|
||||
newdir = pick(GLOB.alldirs)
|
||||
else if(prob(L.confused * 1.5))
|
||||
else if(prob(L.confused))
|
||||
newdir = angle2dir(dir2angle(direction) + pick(90, -90))
|
||||
else if(prob(L.confused * 3))
|
||||
else if(prob(L.confused * 2))
|
||||
newdir = angle2dir(dir2angle(direction) + pick(45, -45))
|
||||
if(newdir)
|
||||
direction = newdir
|
||||
@@ -251,9 +251,9 @@
|
||||
/mob/proc/update_gravity(has_gravity, override=FALSE)
|
||||
var/speed_change = max(0, has_gravity - STANDARD_GRAVITY)
|
||||
if(!speed_change)
|
||||
remove_movespeed_modifier(MOVESPEED_ID_MOB_GRAVITY, update=TRUE)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/gravity)
|
||||
else
|
||||
add_movespeed_modifier(MOVESPEED_ID_MOB_GRAVITY, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=speed_change, blacklisted_movetypes=FLOATING)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/gravity, multiplicative_slowdown = speed_change)
|
||||
|
||||
//bodypart selection - Cyberboss
|
||||
//8 toggles through head - eyes - mouth
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
|
||||
/*Current movespeed modification list format: list(id = list(
|
||||
priority,
|
||||
flags,
|
||||
legacy slowdown/speedup amount,
|
||||
movetype_flags,
|
||||
blacklisted_movetypes,
|
||||
conflict
|
||||
))
|
||||
*/
|
||||
|
||||
//ANY ADD/REMOVE DONE IN UPDATE_MOVESPEED MUST HAVE THE UPDATE ARGUMENT SET AS FALSE!
|
||||
/mob/proc/add_movespeed_modifier(id, update=TRUE, priority=0, flags=NONE, override=FALSE, multiplicative_slowdown=0, movetypes=ALL, blacklisted_movetypes=NONE, conflict=FALSE)
|
||||
var/list/temp = list(priority, flags, multiplicative_slowdown, movetypes, blacklisted_movetypes, conflict) //build the modification list
|
||||
var/resort = TRUE
|
||||
if(LAZYACCESS(movespeed_modification, id))
|
||||
var/list/existing_data = movespeed_modification[id]
|
||||
if(movespeed_modifier_identical_check(existing_data, temp))
|
||||
return FALSE
|
||||
if(!override)
|
||||
return FALSE
|
||||
if(priority == existing_data[MOVESPEED_DATA_INDEX_PRIORITY])
|
||||
resort = FALSE // We don't need to re-sort if we're replacing something already there and it's the same priority
|
||||
LAZYSET(movespeed_modification, id, temp)
|
||||
if(update)
|
||||
update_movespeed(resort)
|
||||
return TRUE
|
||||
|
||||
/mob/proc/remove_movespeed_modifier(id, update = TRUE)
|
||||
if(!LAZYACCESS(movespeed_modification, id))
|
||||
return FALSE
|
||||
LAZYREMOVE(movespeed_modification, id)
|
||||
UNSETEMPTY(movespeed_modification)
|
||||
if(update)
|
||||
update_movespeed(FALSE)
|
||||
return TRUE
|
||||
|
||||
/mob/vv_edit_var(var_name, var_value)
|
||||
var/slowdown_edit = (var_name == NAMEOF(src, cached_multiplicative_slowdown))
|
||||
var/diff
|
||||
if(slowdown_edit && isnum(cached_multiplicative_slowdown) && isnum(var_value))
|
||||
remove_movespeed_modifier(MOVESPEED_ID_ADMIN_VAREDIT)
|
||||
diff = var_value - cached_multiplicative_slowdown
|
||||
. = ..()
|
||||
if(. && slowdown_edit && isnum(diff))
|
||||
add_movespeed_modifier(MOVESPEED_ID_ADMIN_VAREDIT, TRUE, 100, override = TRUE, multiplicative_slowdown = diff)
|
||||
|
||||
/mob/proc/has_movespeed_modifier(id)
|
||||
return LAZYACCESS(movespeed_modification, id)
|
||||
|
||||
/mob/proc/update_config_movespeed()
|
||||
add_movespeed_modifier(MOVESPEED_ID_CONFIG_SPEEDMOD, FALSE, 100, override = TRUE, multiplicative_slowdown = get_config_multiplicative_speed())
|
||||
|
||||
/mob/proc/get_config_multiplicative_speed()
|
||||
if(!islist(GLOB.mob_config_movespeed_type_lookup) || !GLOB.mob_config_movespeed_type_lookup[type])
|
||||
return 0
|
||||
else
|
||||
return GLOB.mob_config_movespeed_type_lookup[type]
|
||||
|
||||
/mob/proc/update_movespeed(resort = TRUE)
|
||||
if(resort)
|
||||
sort_movespeed_modlist()
|
||||
. = 0
|
||||
var/list/conflict_tracker = list()
|
||||
for(var/id in get_movespeed_modifiers())
|
||||
var/list/data = movespeed_modification[id]
|
||||
if(!(data[MOVESPEED_DATA_INDEX_MOVETYPE] & movement_type)) // We don't affect any of these move types, skip
|
||||
continue
|
||||
if(data[MOVESPEED_DATA_INDEX_BL_MOVETYPE] & movement_type) // There's a movetype here that disables this modifier, skip
|
||||
continue
|
||||
var/conflict = data[MOVESPEED_DATA_INDEX_CONFLICT]
|
||||
var/amt = data[MOVESPEED_DATA_INDEX_MULTIPLICATIVE_SLOWDOWN]
|
||||
if(conflict)
|
||||
// Conflicting modifiers prioritize the larger slowdown or the larger speedup
|
||||
// We purposefuly don't handle mixing speedups and slowdowns on the same id
|
||||
if(abs(conflict_tracker[conflict]) < abs(amt))
|
||||
conflict_tracker[conflict] = amt
|
||||
else
|
||||
continue
|
||||
. += amt
|
||||
cached_multiplicative_slowdown = .
|
||||
|
||||
/mob/proc/get_movespeed_modifiers()
|
||||
return movespeed_modification
|
||||
|
||||
/mob/proc/movespeed_modifier_identical_check(list/mod1, list/mod2)
|
||||
if(!islist(mod1) || !islist(mod2) || mod1.len < MOVESPEED_DATA_INDEX_MAX || mod2.len < MOVESPEED_DATA_INDEX_MAX)
|
||||
return FALSE
|
||||
for(var/i in 1 to MOVESPEED_DATA_INDEX_MAX)
|
||||
if(mod1[i] != mod2[i])
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/proc/total_multiplicative_slowdown()
|
||||
. = 0
|
||||
for(var/id in get_movespeed_modifiers())
|
||||
var/list/data = movespeed_modification[id]
|
||||
. += data[MOVESPEED_DATA_INDEX_MULTIPLICATIVE_SLOWDOWN]
|
||||
|
||||
/proc/movespeed_data_null_check(list/data) //Determines if a data list is not meaningful and should be discarded.
|
||||
. = TRUE
|
||||
if(data[MOVESPEED_DATA_INDEX_MULTIPLICATIVE_SLOWDOWN])
|
||||
. = FALSE
|
||||
|
||||
/mob/proc/sort_movespeed_modlist() //Verifies it too. Sorts highest priority (first applied) to lowest priority (last applied)
|
||||
if(!movespeed_modification)
|
||||
return
|
||||
var/list/assembled = list()
|
||||
for(var/our_id in movespeed_modification)
|
||||
var/list/our_data = movespeed_modification[our_id]
|
||||
if(!islist(our_data) || (our_data.len < MOVESPEED_DATA_INDEX_PRIORITY) || movespeed_data_null_check(our_data))
|
||||
movespeed_modification -= our_id
|
||||
continue
|
||||
var/our_priority = our_data[MOVESPEED_DATA_INDEX_PRIORITY]
|
||||
var/resolved = FALSE
|
||||
for(var/their_id in assembled)
|
||||
var/list/their_data = assembled[their_id]
|
||||
if(their_data[MOVESPEED_DATA_INDEX_PRIORITY] < our_priority)
|
||||
assembled.Insert(assembled.Find(their_id), our_id)
|
||||
assembled[our_id] = our_data
|
||||
resolved = TRUE
|
||||
break
|
||||
if(!resolved)
|
||||
assembled[our_id] = our_data
|
||||
movespeed_modification = assembled
|
||||
UNSETEMPTY(movespeed_modification)
|
||||
217
code/modules/movespeed/_movespeed_modifier.dm
Normal file
217
code/modules/movespeed/_movespeed_modifier.dm
Normal file
@@ -0,0 +1,217 @@
|
||||
/*! Movespeed modification datums.
|
||||
|
||||
How move speed for mobs works
|
||||
|
||||
Move speed is now calculated by using modifier datums which are added to mobs. Some of them (nonvariable ones) are globally cached, the variable ones are instanced and changed based on need.
|
||||
|
||||
This gives us the ability to have multiple sources of movespeed, reliabily keep them applied and remove them when they should be
|
||||
|
||||
THey can have unique sources and a bunch of extra fancy flags that control behaviour
|
||||
|
||||
Previously trying to update move speed was a shot in the dark that usually meant mobs got stuck going faster or slower
|
||||
|
||||
Movespeed modification list is a simple key = datum system. Key will be the datum's ID if it is overridden to not be null, or type if it is not.
|
||||
|
||||
DO NOT override datum IDs unless you are going to have multiple types that must overwrite each other. It's more efficient to use types, ID functionality is only kept for cases where dynamic creation of modifiers need to be done.
|
||||
|
||||
When update movespeed is called, the list of items is iterated, according to flags priority and a bunch of conditions
|
||||
this spits out a final calculated value which is used as a modifer to last_move + modifier for calculating when a mob
|
||||
can next move
|
||||
|
||||
Key procs
|
||||
* [add_movespeed_modifier](mob.html#proc/add_movespeed_modifier)
|
||||
* [remove_movespeed_modifier](mob.html#proc/remove_movespeed_modifier)
|
||||
* [has_movespeed_modifier](mob.html#proc/has_movespeed_modifier)
|
||||
* [update_movespeed](mob.html#proc/update_movespeed)
|
||||
*/
|
||||
|
||||
/datum/movespeed_modifier
|
||||
/// Whether or not this is a variable modifier. Variable modifiers can NOT be ever auto-cached. ONLY CHECKED VIA INITIAL(), EFFECTIVELY READ ONLY (and for very good reason)
|
||||
var/variable = FALSE
|
||||
|
||||
/// Unique ID. You can never have different modifications with the same ID. By default, this SHOULD NOT be set. Only set it for cases where you're dynamically making modifiers/need to have two types overwrite each other. If unset, uses path (converted to text) as ID.
|
||||
var/id
|
||||
|
||||
/// Higher ones override lower priorities. This is NOT used for ID, ID must be unique, if it isn't unique the newer one overwrites automatically if overriding.
|
||||
var/priority = 0
|
||||
var/flags = NONE
|
||||
|
||||
/// Multiplicative slowdown
|
||||
var/multiplicative_slowdown = 0
|
||||
|
||||
/// Movetypes this applies to
|
||||
var/movetypes = ALL
|
||||
|
||||
/// Movetypes this never applies to
|
||||
var/blacklisted_movetypes = NONE
|
||||
|
||||
/// Other modification datums this conflicts with.
|
||||
var/conflicts_with
|
||||
|
||||
/datum/movespeed_modifier/New()
|
||||
. = ..()
|
||||
if(!id)
|
||||
id = "[type]" //We turn the path into a string.
|
||||
|
||||
GLOBAL_LIST_EMPTY(movespeed_modification_cache)
|
||||
|
||||
/// Grabs a STATIC MODIFIER datum from cache. YOU MUST NEVER EDIT THESE DATUMS, OR IT WILL AFFECT ANYTHING ELSE USING IT TOO!
|
||||
/proc/get_cached_movespeed_modifier(modtype)
|
||||
if(!ispath(modtype, /datum/movespeed_modifier))
|
||||
CRASH("[modtype] is not a movespeed modification typepath.")
|
||||
var/datum/movespeed_modifier/M = modtype
|
||||
if(initial(M.variable))
|
||||
CRASH("[modtype] is a variable modifier, and can never be cached.")
|
||||
M = GLOB.movespeed_modification_cache[modtype]
|
||||
if(!M)
|
||||
M = GLOB.movespeed_modification_cache[modtype] = new modtype
|
||||
return M
|
||||
|
||||
///Add a move speed modifier to a mob. If a variable subtype is passed in as the first argument, it will make a new datum. If ID conflicts, it will overwrite the old ID.
|
||||
/mob/proc/add_movespeed_modifier(datum/movespeed_modifier/type_or_datum, update = TRUE)
|
||||
if(ispath(type_or_datum))
|
||||
if(!initial(type_or_datum.variable))
|
||||
type_or_datum = get_cached_movespeed_modifier(type_or_datum)
|
||||
else
|
||||
type_or_datum = new type_or_datum
|
||||
var/datum/movespeed_modifier/existing = LAZYACCESS(movespeed_modification, type_or_datum.id)
|
||||
if(existing)
|
||||
if(existing == type_or_datum) //same thing don't need to touch
|
||||
return TRUE
|
||||
remove_movespeed_modifier(existing, FALSE)
|
||||
if(length(movespeed_modification))
|
||||
BINARY_INSERT(type_or_datum.id, movespeed_modification, datum/movespeed_modifier, type_or_datum, priority, COMPARE_VALUE)
|
||||
LAZYSET(movespeed_modification, type_or_datum.id, type_or_datum)
|
||||
if(update)
|
||||
update_movespeed()
|
||||
return TRUE
|
||||
|
||||
/// Remove a move speed modifier from a mob, whether static or variable.
|
||||
/mob/proc/remove_movespeed_modifier(datum/movespeed_modifier/type_id_datum, update = TRUE)
|
||||
var/key
|
||||
if(ispath(type_id_datum))
|
||||
key = initial(type_id_datum.id) || "[type_id_datum]" //id if set, path set to string if not.
|
||||
else if(!istext(type_id_datum)) //if it isn't text it has to be a datum, as it isn't a type.
|
||||
key = type_id_datum.id
|
||||
else //assume it's an id
|
||||
key = type_id_datum
|
||||
if(!LAZYACCESS(movespeed_modification, key))
|
||||
return FALSE
|
||||
LAZYREMOVE(movespeed_modification, key)
|
||||
if(update)
|
||||
update_movespeed(FALSE)
|
||||
return TRUE
|
||||
|
||||
/*! Used for variable slowdowns like hunger/health loss/etc, works somewhat like the old list-based modification adds. Returns the modifier datum if successful
|
||||
How this SHOULD work is:
|
||||
1. Ensures type_id_datum one way or another refers to a /variable datum. This makes sure it can't be cached. This includes if it's already in the modification list.
|
||||
2. Instantiate a new datum if type_id_datum isn't already instantiated + in the list, using the type. Obviously, wouldn't work for ID only.
|
||||
3. Add the datum if necessary using the regular add proc
|
||||
4. If any of the rest of the args are not null (see: multiplicative slowdown), modify the datum
|
||||
5. Update if necessary
|
||||
*/
|
||||
/mob/proc/add_or_update_variable_movespeed_modifier(datum/movespeed_modifier/type_id_datum, update = TRUE, multiplicative_slowdown)
|
||||
var/modified = FALSE
|
||||
var/inject = FALSE
|
||||
var/datum/movespeed_modifier/final
|
||||
if(istext(type_id_datum))
|
||||
final = LAZYACCESS(movespeed_modification, type_id_datum)
|
||||
if(!final)
|
||||
CRASH("Couldn't find existing modification when provided a text ID.")
|
||||
else if(ispath(type_id_datum))
|
||||
if(!initial(type_id_datum.variable))
|
||||
CRASH("Not a variable modifier")
|
||||
final = LAZYACCESS(movespeed_modification, initial(type_id_datum.id) || "[type_id_datum]")
|
||||
if(!final)
|
||||
final = new type_id_datum
|
||||
inject = TRUE
|
||||
modified = TRUE
|
||||
else
|
||||
if(!initial(type_id_datum.variable))
|
||||
CRASH("Not a variable modifier")
|
||||
final = type_id_datum
|
||||
if(!LAZYACCESS(movespeed_modification, final.id))
|
||||
inject = TRUE
|
||||
modified = TRUE
|
||||
if(!isnull(multiplicative_slowdown))
|
||||
final.multiplicative_slowdown = multiplicative_slowdown
|
||||
modified = TRUE
|
||||
if(inject)
|
||||
add_movespeed_modifier(final, FALSE)
|
||||
if(update && modified)
|
||||
update_movespeed(TRUE)
|
||||
return final
|
||||
|
||||
/// Handles the special case of editing the movement var
|
||||
/mob/vv_edit_var(var_name, var_value)
|
||||
var/slowdown_edit = (var_name == NAMEOF(src, cached_multiplicative_slowdown))
|
||||
var/diff
|
||||
if(slowdown_edit && isnum(cached_multiplicative_slowdown) && isnum(var_value))
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/admin_varedit)
|
||||
diff = var_value - cached_multiplicative_slowdown
|
||||
. = ..()
|
||||
if(. && slowdown_edit && isnum(diff))
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/admin_varedit, multiplicative_slowdown = diff)
|
||||
|
||||
///Is there a movespeed modifier for this mob
|
||||
/mob/proc/has_movespeed_modifier(datum/movespeed_modifier/datum_type_id)
|
||||
var/key
|
||||
if(ispath(datum_type_id))
|
||||
key = initial(datum_type_id.id) || "[datum_type_id]"
|
||||
else if(istext(datum_type_id))
|
||||
key = datum_type_id
|
||||
else
|
||||
key = datum_type_id.id
|
||||
return LAZYACCESS(movespeed_modification, key)
|
||||
|
||||
/// Set or update the global movespeed config on a mob
|
||||
/mob/proc/update_config_movespeed()
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/mob_config_speedmod, multiplicative_slowdown = get_config_multiplicative_speed())
|
||||
|
||||
/// Get the global config movespeed of a mob by type
|
||||
/mob/proc/get_config_multiplicative_speed()
|
||||
if(!islist(GLOB.mob_config_movespeed_type_lookup) || !GLOB.mob_config_movespeed_type_lookup[type])
|
||||
return 0
|
||||
else
|
||||
return GLOB.mob_config_movespeed_type_lookup[type]
|
||||
|
||||
/// Go through the list of movespeed modifiers and calculate a final movespeed. ANY ADD/REMOVE DONE IN UPDATE_MOVESPEED MUST HAVE THE UPDATE ARGUMENT SET AS FALSE!
|
||||
/mob/proc/update_movespeed()
|
||||
. = 0
|
||||
var/list/conflict_tracker = list()
|
||||
for(var/key in get_movespeed_modifiers())
|
||||
var/datum/movespeed_modifier/M = movespeed_modification[key]
|
||||
if(!(M.movetypes & movement_type)) // We don't affect any of these move types, skip
|
||||
continue
|
||||
if(M.blacklisted_movetypes & movement_type) // There's a movetype here that disables this modifier, skip
|
||||
continue
|
||||
var/conflict = M.conflicts_with
|
||||
var/amt = M.multiplicative_slowdown
|
||||
if(conflict)
|
||||
// Conflicting modifiers prioritize the larger slowdown or the larger speedup
|
||||
// We purposefuly don't handle mixing speedups and slowdowns on the same id
|
||||
if(abs(conflict_tracker[conflict]) < abs(amt))
|
||||
conflict_tracker[conflict] = amt
|
||||
else
|
||||
continue
|
||||
. += amt
|
||||
cached_multiplicative_slowdown = .
|
||||
|
||||
/// Get the move speed modifiers list of the mob
|
||||
/mob/proc/get_movespeed_modifiers()
|
||||
. = LAZYCOPY(movespeed_modification)
|
||||
for(var/id in movespeed_mod_immunities)
|
||||
. -= id
|
||||
|
||||
/// Calculate the total slowdown of all movespeed modifiers
|
||||
/mob/proc/total_multiplicative_slowdown()
|
||||
. = 0
|
||||
for(var/id in get_movespeed_modifiers())
|
||||
var/datum/movespeed_modifier/M = movespeed_modification[id]
|
||||
. += M.multiplicative_slowdown
|
||||
|
||||
/// Checks if a move speed modifier is valid and not missing any data
|
||||
/proc/movespeed_data_null_check(datum/movespeed_modifier/M) //Determines if a data list is not meaningful and should be discarded.
|
||||
. = TRUE
|
||||
if(M.multiplicative_slowdown)
|
||||
. = FALSE
|
||||
21
code/modules/movespeed/modifiers/components.dm
Normal file
21
code/modules/movespeed/modifiers/components.dm
Normal file
@@ -0,0 +1,21 @@
|
||||
/datum/movespeed_modifier/shrink_ray
|
||||
movetypes = GROUND
|
||||
multiplicative_slowdown = 4
|
||||
flags = IGNORE_NOSLOW
|
||||
|
||||
/datum/movespeed_modifier/snail_crawl
|
||||
multiplicative_slowdown = -7
|
||||
movetypes = GROUND
|
||||
|
||||
/datum/movespeed_modifier/sanity
|
||||
id = MOVESPEED_ID_SANITY
|
||||
blacklisted_movetypes = FLYING
|
||||
|
||||
/datum/movespeed_modifier/sanity/insane
|
||||
multiplicative_slowdown = 1.5
|
||||
|
||||
/datum/movespeed_modifier/sanity/crazy
|
||||
multiplicative_slowdown = 1
|
||||
|
||||
/datum/movespeed_modifier/sanity/disturbed
|
||||
multiplicative_slowdown = 0.5
|
||||
20
code/modules/movespeed/modifiers/innate.dm
Normal file
20
code/modules/movespeed/modifiers/innate.dm
Normal file
@@ -0,0 +1,20 @@
|
||||
/datum/movespeed_modifier/strained_muscles
|
||||
multiplicative_slowdown = -1
|
||||
blacklisted_movetypes = (FLYING|FLOATING)
|
||||
|
||||
/datum/movespeed_modifier/pai_spacewalk
|
||||
multiplicative_slowdown = 2
|
||||
flags = IGNORE_NOSLOW
|
||||
|
||||
/datum/movespeed_modifier/species
|
||||
movetypes = ~FLYING
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/dna_vault_speedup
|
||||
blacklisted_movetypes = (FLYING|FLOATING)
|
||||
multiplicative_slowdown = -1
|
||||
|
||||
/datum/movespeed_modifier/small_stride
|
||||
blacklisted_movetypes = (FLOATING|CRAWLING)
|
||||
variable = TRUE
|
||||
flags = IGNORE_NOSLOW
|
||||
12
code/modules/movespeed/modifiers/items.dm
Normal file
12
code/modules/movespeed/modifiers/items.dm
Normal file
@@ -0,0 +1,12 @@
|
||||
/datum/movespeed_modifier/jetpack
|
||||
conflicts_with = MOVE_CONFLICT_JETPACK
|
||||
movetypes = FLOATING
|
||||
|
||||
/datum/movespeed_modifier/jetpack/cybernetic
|
||||
multiplicative_slowdown = -0.5
|
||||
|
||||
/datum/movespeed_modifier/jetpack/fullspeed
|
||||
multiplicative_slowdown = -2
|
||||
|
||||
/datum/movespeed_modifier/die_of_fate
|
||||
multiplicative_slowdown = 1
|
||||
6
code/modules/movespeed/modifiers/misc.dm
Normal file
6
code/modules/movespeed/modifiers/misc.dm
Normal file
@@ -0,0 +1,6 @@
|
||||
/datum/movespeed_modifier/admin_varedit
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/yellow_orb
|
||||
multiplicative_slowdown = -2
|
||||
blacklisted_movetypes = (FLYING|FLOATING)
|
||||
120
code/modules/movespeed/modifiers/mobs.dm
Normal file
120
code/modules/movespeed/modifiers/mobs.dm
Normal file
@@ -0,0 +1,120 @@
|
||||
/datum/movespeed_modifier/obesity
|
||||
multiplicative_slowdown = 1.5
|
||||
|
||||
/datum/movespeed_modifier/monkey_reagent_speedmod
|
||||
blacklisted_movetypes = FLOATING
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/monkey_health_speedmod
|
||||
blacklisted_movetypes = FLOATING
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/monkey_temperature_speedmod
|
||||
blacklisted_movetypes = FLOATING
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/hunger
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/slaughter
|
||||
multiplicative_slowdown = -1
|
||||
|
||||
/datum/movespeed_modifier/damage_slowdown
|
||||
blacklisted_movetypes = FLOATING|FLYING
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/damage_slowdown_flying
|
||||
movetypes = FLOATING
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/equipment_speedmod
|
||||
variable = TRUE
|
||||
blacklisted_movetypes = FLOATING
|
||||
|
||||
/datum/movespeed_modifier/grab_slowdown
|
||||
id = MOVESPEED_ID_MOB_GRAB_STATE
|
||||
blacklisted_movetypes = FLOATING
|
||||
|
||||
/datum/movespeed_modifier/grab_slowdown/aggressive
|
||||
multiplicative_slowdown = 3
|
||||
|
||||
/datum/movespeed_modifier/grab_slowdown/neck
|
||||
multiplicative_slowdown = 6
|
||||
|
||||
/datum/movespeed_modifier/grab_slowdown/kill
|
||||
multiplicative_slowdown = 9
|
||||
|
||||
/datum/movespeed_modifier/slime_reagentmod
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/slime_healthmod
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/config_walk_run
|
||||
multiplicative_slowdown = 1
|
||||
id = MOVESPEED_ID_MOB_WALK_RUN
|
||||
flags = IGNORE_NOSLOW
|
||||
|
||||
/datum/movespeed_modifier/config_walk_run/proc/sync()
|
||||
|
||||
/datum/movespeed_modifier/config_walk_run/walk/sync()
|
||||
var/mod = CONFIG_GET(number/movedelay/walk_delay)
|
||||
multiplicative_slowdown = isnum(mod)? mod : initial(multiplicative_slowdown)
|
||||
|
||||
/datum/movespeed_modifier/config_walk_run/run/sync()
|
||||
var/mod = CONFIG_GET(number/movedelay/run_delay)
|
||||
multiplicative_slowdown = isnum(mod)? mod : initial(multiplicative_slowdown)
|
||||
|
||||
/datum/movespeed_modifier/turf_slowdown
|
||||
movetypes = GROUND
|
||||
blacklisted_movetypes = (FLYING|FLOATING)
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/bulky_drag
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/cold
|
||||
blacklisted_movetypes = FLOATING
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/shove
|
||||
multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH
|
||||
|
||||
/datum/movespeed_modifier/human_carry
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/limbless
|
||||
variable = TRUE
|
||||
movetypes = GROUND
|
||||
flags = IGNORE_NOSLOW
|
||||
|
||||
/datum/movespeed_modifier/simplemob_varspeed
|
||||
variable = TRUE
|
||||
flags = IGNORE_NOSLOW
|
||||
|
||||
/datum/movespeed_modifier/tarantula_web
|
||||
multiplicative_slowdown = 3
|
||||
|
||||
/datum/movespeed_modifier/gravity
|
||||
blacklisted_movetypes = FLOATING
|
||||
variable = TRUE
|
||||
flags = IGNORE_NOSLOW
|
||||
|
||||
/datum/movespeed_modifier/carbon_softcrit
|
||||
multiplicative_slowdown = SOFTCRIT_ADD_SLOWDOWN
|
||||
|
||||
/datum/movespeed_modifier/slime_tempmod
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/carbon_crawling
|
||||
multiplicative_slowdown = CRAWLING_ADD_SLOWDOWN
|
||||
movetypes = CRAWLING
|
||||
flags = IGNORE_NOSLOW
|
||||
|
||||
/datum/movespeed_modifier/mob_config_speedmod
|
||||
variable = TRUE
|
||||
flags = IGNORE_NOSLOW
|
||||
|
||||
/datum/movespeed_modifier/liver_cirrhosis
|
||||
blacklisted_movetypes = FLOATING
|
||||
variable = TRUE
|
||||
14
code/modules/movespeed/modifiers/reagents.dm
Normal file
14
code/modules/movespeed/modifiers/reagents.dm
Normal file
@@ -0,0 +1,14 @@
|
||||
/datum/movespeed_modifier/reagent
|
||||
blacklisted_movetypes = (FLYING|FLOATING)
|
||||
|
||||
/datum/movespeed_modifier/reagent/stimulants
|
||||
multiplicative_slowdown = -0.5
|
||||
|
||||
/datum/movespeed_modifier/reagent/changelinghaste
|
||||
multiplicative_slowdown = -2
|
||||
|
||||
/datum/movespeed_modifier/reagent/skooma
|
||||
multiplicative_slowdown = -1
|
||||
|
||||
/datum/movespeed_modifier/reagent/nitryl
|
||||
multiplicative_slowdown = -1
|
||||
44
code/modules/movespeed/modifiers/status_effects.dm
Normal file
44
code/modules/movespeed/modifiers/status_effects.dm
Normal file
@@ -0,0 +1,44 @@
|
||||
/datum/movespeed_modifier/status_effect/bloodchill
|
||||
multiplicative_slowdown = 3
|
||||
|
||||
/datum/movespeed_modifier/status_effect/bonechill
|
||||
multiplicative_slowdown = 3
|
||||
|
||||
/datum/movespeed_modifier/status_effect/tarfoot
|
||||
multiplicative_slowdown = 0.5
|
||||
blacklisted_movetypes = (FLYING|FLOATING)
|
||||
|
||||
/datum/movespeed_modifier/status_effect/sepia
|
||||
variable = TRUE
|
||||
blacklisted_movetypes = (FLYING|FLOATING)
|
||||
|
||||
/datum/movespeed_modifier/status_effect/mesmerize
|
||||
blacklisted_movetypes = CRAWLING
|
||||
multiplicative_slowdown = 5
|
||||
priority = 64
|
||||
|
||||
/datum/movespeed_modifier/status_effect/tased
|
||||
multiplicative_slowdown = 1.5
|
||||
priority = 50
|
||||
|
||||
/datum/movespeed_modifier/status_effect/tased/no_combat_mode
|
||||
multiplicative_slowdown = 8
|
||||
priority = 100
|
||||
|
||||
/datum/movespeed_modifier/status_effect/electrostaff
|
||||
multiplicative_slowdown = 1
|
||||
movetypes = GROUND
|
||||
|
||||
//no comment.
|
||||
/datum/movespeed_modifier/status_effect/breast_hypertrophy
|
||||
blacklisted_movetypes = FLOATING
|
||||
variable = TRUE
|
||||
|
||||
//this shouldn't even exist.
|
||||
/datum/movespeed_modifier/status_effect/penis_hypertrophy
|
||||
blacklisted_movetypes = FLOATING
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/status_effect/mkultra
|
||||
multiplicative_slowdown = -2
|
||||
blacklisted_movetypes= FLYING|FLOATING
|
||||
@@ -533,7 +533,7 @@ By design, d1 is the smallest direction and d2 is the highest
|
||||
if(affecting && affecting.status == BODYPART_ROBOTIC)
|
||||
if(user == H)
|
||||
user.visible_message("<span class='notice'>[user] starts to fix some of the wires in [H]'s [affecting.name].</span>", "<span class='notice'>You start fixing some of the wires in [H]'s [affecting.name].</span>")
|
||||
if(!do_after(user, H, 50))
|
||||
if(!do_mob(user, H, 50))
|
||||
return
|
||||
if(item_heal_robotic(H, user, 0, 15))
|
||||
use(1)
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
select_name = "ion"
|
||||
fire_sound = 'sound/weapons/ionrifle.ogg'
|
||||
|
||||
/obj/item/ammo_casing/energy/ion/hos
|
||||
projectile_type = /obj/item/projectile/ion/weak
|
||||
e_cost = 300
|
||||
|
||||
/obj/item/ammo_casing/energy/declone
|
||||
projectile_type = /obj/item/projectile/energy/declone
|
||||
select_name = "declone"
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
fire_sound = 'sound/weapons/gunshot.ogg'
|
||||
e_cost = 100
|
||||
|
||||
/obj/item/ammo_casing/energy/electrode/hos
|
||||
projectile_type = /obj/item/projectile/energy/electrode/security/hos
|
||||
e_cost = 200
|
||||
|
||||
/obj/item/ammo_casing/energy/electrode/old
|
||||
e_cost = 1000
|
||||
|
||||
@@ -41,9 +41,12 @@
|
||||
to_chat(user, "<span class='warning'>You're too exhausted for that.</span>")//CIT CHANGE - ditto
|
||||
return//CIT CHANGE - ditto
|
||||
pump(user, TRUE)
|
||||
recentpump = world.time + 10
|
||||
if(istype(user))//CIT CHANGE - makes pumping shotguns cost a lil bit of stamina.
|
||||
user.adjustStaminaLossBuffered(2) //CIT CHANGE - DITTO. make this scale inversely to the strength stat when stats/skills are added
|
||||
if(HAS_TRAIT(user, TRAIT_FAST_PUMP))
|
||||
recentpump = world.time + 2
|
||||
else
|
||||
recentpump = world.time + 10
|
||||
if(istype(user))//CIT CHANGE - makes pumping shotguns cost a lil bit of stamina.
|
||||
user.adjustStaminaLossBuffered(2) //CIT CHANGE - DITTO. make this scale inversely to the strength stat when stats/skills are added
|
||||
return
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/blow_up(mob/user)
|
||||
@@ -90,7 +93,7 @@
|
||||
fire_delay = 7
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/shot/riot
|
||||
sawn_desc = "Come with me if you want to live."
|
||||
unique_reskin = list("Tatical" = "riotshotgun",
|
||||
unique_reskin = list("Tactical" = "riotshotgun",
|
||||
"Wood Stock" = "wood_riotshotgun"
|
||||
)
|
||||
|
||||
@@ -212,7 +215,7 @@
|
||||
fire_delay = 5
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/shot/com
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
unique_reskin = list("Tatical" = "cshotgun",
|
||||
unique_reskin = list("Tactical" = "cshotgun",
|
||||
"Slick" = "cshotgun_slick"
|
||||
)
|
||||
|
||||
|
||||
@@ -52,13 +52,16 @@
|
||||
|
||||
/obj/item/gun/energy/e_gun/hos
|
||||
name = "\improper X-01 MultiPhase Energy Gun"
|
||||
desc = "This is an expensive, modern recreation of an antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time."
|
||||
desc = "This is an expensive, modern recreation of an antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time in exchange for inbuilt advanced firearm EMP shielding."
|
||||
icon_state = "hoslaser"
|
||||
force = 10
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/electrode/hos, /obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/hos)
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/ion/hos)
|
||||
ammo_x_offset = 4
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
|
||||
/obj/item/gun/energy/e_gun/hos/emp_act(severity)
|
||||
return
|
||||
|
||||
/obj/item/gun/energy/e_gun/dragnet
|
||||
name = "\improper DRAGnet"
|
||||
desc = "The \"Dynamic Rapid-Apprehension of the Guilty\" net is a revolution in law enforcement technology."
|
||||
|
||||
@@ -241,3 +241,87 @@
|
||||
to_chat(user, "<span class='warning'>The pin beeps, refusing to fire.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/firing_pin/security_level
|
||||
name = "security level firing pin"
|
||||
desc = "A sophisticated firing pin that authorizes operation based on its settings and current security level."
|
||||
icon_state = "firing_pin_sec_level"
|
||||
var/min_sec_level = SEC_LEVEL_GREEN
|
||||
var/max_sec_level = SEC_LEVEL_DELTA
|
||||
var/only_lethals = FALSE
|
||||
var/can_toggle = TRUE
|
||||
|
||||
/obj/item/firing_pin/security_level/Initialize()
|
||||
. = ..()
|
||||
fail_message = "<span class='warning'>INVALID SECURITY LEVEL. CURRENT: [uppertext(NUM2SECLEVEL(GLOB.security_level))]. \
|
||||
MIN: [uppertext(NUM2SECLEVEL(min_sec_level))]. MAX: [uppertext(NUM2SECLEVEL(max_sec_level))]. \
|
||||
ONLY LETHALS: [only_lethals ? "YES" : "NO"].</span>"
|
||||
update_icon()
|
||||
|
||||
/obj/item/firing_pin/security_level/examine(mob/user)
|
||||
. = ..()
|
||||
var/lethal = only_lethals ? "only lethal " : ""
|
||||
if(min_sec_level != max_sec_level)
|
||||
. += "<span class='notice'>It's currently set to disallow [lethal]operation when the security level isn't between <b>[NUM2SECLEVEL(min_sec_level)]</b> and <b>[NUM2SECLEVEL(max_sec_level)]</b>.</span>"
|
||||
else
|
||||
. += "<span class='notice'>It's currently set to disallow [lethal]operation when the security level isn't <b>[NUM2SECLEVEL(min_sec_level)]</b>.</span>"
|
||||
if(can_toggle)
|
||||
. += "<span class='notice'>You can use a <b>multitool</b> to modify its settings.</span>"
|
||||
|
||||
/obj/item/firing_pin/security_level/multitool_act(mob/living/user, obj/item/I)
|
||||
. = TRUE
|
||||
if(!can_toggle || !user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
var/selection = alert(user, "Which setting would you want to modify?", "Firing Pin Settings", "Minimum Level Setting", "Maximum Level Setting", "Lethals Only Toggle")
|
||||
if(QDELETED(src) || QDELETED(user) || !user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
var/static/list/till_designs_pr_isnt_merged = list("green", "blue", "amber", "red", "delta")
|
||||
switch(selection)
|
||||
if("Minimum Level Setting")
|
||||
var/input = input(user, "Input the new minimum level setting.", "Firing Pin Settings", NUM2SECLEVEL(min_sec_level)) as null|anything in till_designs_pr_isnt_merged
|
||||
if(!input)
|
||||
return
|
||||
min_sec_level = till_designs_pr_isnt_merged.Find(input) - 1
|
||||
if(min_sec_level > max_sec_level)
|
||||
max_sec_level = SEC_LEVEL_DELTA
|
||||
if("Maximum Level Setting")
|
||||
var/input = input(user, "Input the new maximum level setting.", "Firing Pin Settings", NUM2SECLEVEL(max_sec_level)) as null|anything in till_designs_pr_isnt_merged
|
||||
if(!input)
|
||||
return
|
||||
max_sec_level = till_designs_pr_isnt_merged.Find(input) - 1
|
||||
if(max_sec_level < max_sec_level)
|
||||
min_sec_level = SEC_LEVEL_GREEN
|
||||
if("Lethals Only Toggle")
|
||||
only_lethals = !only_lethals
|
||||
|
||||
fail_message = "<span class='warning'>INVALID SECURITY LEVEL. CURRENT: [uppertext(NUM2SECLEVEL(GLOB.security_level))]. \
|
||||
MIN: [uppertext(NUM2SECLEVEL(min_sec_level))]. MAX: [uppertext(NUM2SECLEVEL(max_sec_level))]. \
|
||||
ONLY LETHALS: [only_lethals ? "YES" : "NO"].</span>"
|
||||
update_icon()
|
||||
|
||||
/obj/item/firing_pin/security_level/update_overlays()
|
||||
. = ..()
|
||||
var/offset = 0
|
||||
for(var/level in list(min_sec_level, max_sec_level))
|
||||
var/mutable_appearance/overlay = mutable_appearance(icon, "pin_sec_level_overlay")
|
||||
overlay.pixel_x += offset
|
||||
offset += 4
|
||||
switch(level)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
overlay.color = "#b2ff59" //light green
|
||||
if(SEC_LEVEL_BLUE)
|
||||
overlay.color = "#99ccff" //light blue
|
||||
if(SEC_LEVEL_AMBER)
|
||||
overlay.color = "#ffae42" //light yellow/orange
|
||||
if(SEC_LEVEL_RED)
|
||||
overlay.color = "#ff3f34" //light red
|
||||
else
|
||||
overlay.color = "#fe59c2" //neon fuchsia
|
||||
. += overlay
|
||||
var/mutable_appearance/overlay = mutable_appearance(icon, "pin_sec_level_overlay")
|
||||
overlay.pixel_x += offset
|
||||
overlay.color = only_lethals ? "#b2ff59" : "#ff3f34"
|
||||
. += overlay
|
||||
|
||||
/obj/item/firing_pin/security_level/pin_auth(mob/living/user)
|
||||
return (only_lethals && !(gun.chambered?.harmful)) || ISINRANGE(GLOB.security_level, min_sec_level, max_sec_level)
|
||||
|
||||
@@ -315,6 +315,8 @@
|
||||
objs += O
|
||||
var/obj/O = safepick(objs)
|
||||
if(O)
|
||||
if(length(O.buckled_mobs))
|
||||
return pick(O.buckled_mobs)
|
||||
return O
|
||||
//Nothing else is here that we can hit, hit the turf if we haven't.
|
||||
if(!(T in permutated) && can_hit_target(T, permutated, T == original, TRUE))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user