This commit is contained in:
Ghommie
2020-04-13 02:01:01 +02:00
1606 changed files with 335062 additions and 34873 deletions
@@ -22,6 +22,7 @@ GLOBAL_LIST_EMPTY(antagonists)
var/antagpanel_category = "Uncategorized" //Antagpanel will display these together, REQUIRED
var/show_name_in_check_antagonists = FALSE //Will append antagonist name in admin listings - use for categories that share more than one antag type
var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) // Quirks that will be removed upon gaining this antag. Pacifist and mute are default.
var/threat = 0 // Amount of threat this antag poses, for dynamic mode
/datum/antagonist/New()
GLOB.antagonists += src
@@ -75,6 +76,7 @@ GLOBAL_LIST_EMPTY(antagonists)
remove_blacklisted_quirks()
if(is_banned(owner.current) && replace_banned)
replace_banned_player()
SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src)
/datum/antagonist/proc/is_banned(mob/M)
if(!M)
@@ -84,9 +86,9 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/replace_banned_player()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [name]?", "[name]", null, job_rank, 50, owner.current)
var/list/mob/candidates = pollCandidatesForMob("Do you want to play as a [name]?", "[name]", null, job_rank, 50, owner.current)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
var/mob/C = pick(candidates)
to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(owner.current)]) to replace a jobbaned player.")
owner.current.ghostize(0)
@@ -237,6 +239,13 @@ GLOBAL_LIST_EMPTY(antagonists)
return H.hijack_speed_override
return hijack_speed
/// Gets our threat level. Defaults to threat var, override for custom stuff like different traitor goals having different threats.
/datum/antagonist/proc/threat()
. = CONFIG_GET(keyed_list/antag_threat)[lowertext(name)]
if(. == null)
return threat
return threat
//This one is created by admin tools for custom objectives
/datum/antagonist/custom
antagpanel_category = "Custom"
@@ -248,7 +248,7 @@
if(used || QDELETED(src))
return
used = TRUE
var/mob/dead/observer/C = pick(candidates)
var/mob/C = pick(candidates)
spawn_antag(C.client, get_turf(src), initial(demon_type.name),user.mind)
to_chat(user, shatter_msg)
to_chat(user, veil_msg)
@@ -31,4 +31,5 @@
/datum/antagonist/abductee/remove_innate_effects(mob/living/mob_override)
update_abductor_icons_removed(mob_override ? mob_override.mind : owner)
qdel(brain_trauma)
if(!QDELETED(brain_trauma))
qdel(brain_trauma)
@@ -6,6 +6,7 @@
antagpanel_category = "Abductor"
job_rank = ROLE_ABDUCTOR
show_in_antagpanel = FALSE //should only show subtypes
threat = 5
var/datum/team/abductor_team/team
var/sub_role
var/outfit
@@ -92,10 +92,8 @@
M.cut_overlays()
M.regenerate_icons()
/obj/item/clothing/suit/armor/abductor/vest/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
DeactivateStealth()
/obj/item/clothing/suit/armor/abductor/vest/IsReflect()
/obj/item/clothing/suit/armor/abductor/vest/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
. = ..()
DeactivateStealth()
/obj/item/clothing/suit/armor/abductor/vest/ui_action_click()
@@ -419,8 +417,9 @@
<br>
Congratulations! You are now trained for invasive xenobiology research!"}
/obj/item/paper/guides/antag/abductor/update_icon()
return
/obj/item/paper/guides/antag/abductor/ComponentInitialize()
. = ..()
AddElement(/datum/element/update_icon_blocker)
/obj/item/paper/guides/antag/abductor/AltClick()
return //otherwise it would fold into a paperplane.
@@ -442,6 +441,10 @@
w_class = WEIGHT_CLASS_NORMAL
actions_types = list(/datum/action/item_action/toggle_mode)
/obj/item/abductor/baton/ComponentInitialize()
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)
/obj/item/abductor/baton/proc/toggle(mob/living/user=usr)
mode = (mode+1)%BATON_MODES
var/txt
@@ -458,7 +461,7 @@
to_chat(usr, "<span class='notice'>You switch the baton to [txt] mode.</span>")
update_icon()
/obj/item/abductor/baton/update_icon()
/obj/item/abductor/baton/update_icon_state()
switch(mode)
if(BATON_STUN)
icon_state = "wonderprodStun"
@@ -488,7 +491,7 @@
user.do_attack_animation(L)
if(L.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
if(L.run_block(src, 0, "[user]'s [src]", ATTACK_TYPE_MELEE, 0, user, check_zone(user.zone_selected)) & BLOCK_SUCCESS)
playsound(L, 'sound/weapons/genhit.ogg', 50, TRUE)
return FALSE
@@ -61,7 +61,7 @@
/obj/machinery/abductor/experiment/proc/dissection_icon(mob/living/carbon/human/H)
var/icon/photo = null
var/g = (H.gender == FEMALE) ? "f" : "m"
var/g = (H.dna.features["body_model"] == FEMALE) ? "f" : "m"
if(H.dna.species.use_skintones)
photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.skin_tone]_[g]")
else
@@ -209,7 +209,6 @@
open_machine()
SendBack(H)
return "<span class='bad'>Specimen braindead - disposed.</span>"
return "<span class='bad'>ERROR</span>"
/obj/machinery/abductor/experiment/proc/SendBack(mob/living/carbon/human/H)
@@ -223,7 +222,7 @@
return
/obj/machinery/abductor/experiment/update_icon()
/obj/machinery/abductor/experiment/update_icon_state()
if(state_open)
icon_state = "experiment-open"
else
+2 -2
View File
@@ -3,7 +3,7 @@
roundend_category = "blobs"
antagpanel_category = "Blob"
job_rank = ROLE_BLOB
threat = 20
var/datum/action/innate/blobpop/pop_action
var/starting_points_human_blob = 60
var/point_rate_human_blob = 2
@@ -63,4 +63,4 @@
if(owner && owner.current)
var/mob/camera/blob/B = owner.current
if(istype(B))
. += "(Progress: [B.blobs_legit.len]/[B.blobwincount])"
. += "(Progress: [B.blobs_legit.len]/[B.blobwincount])"
@@ -20,7 +20,7 @@
/mob/living/simple_animal/hostile/blob/update_icons()
if(overmind)
add_atom_colour(overmind.blob_reagent_datum.color, FIXED_COLOUR_PRIORITY)
add_atom_colour(overmind.blobstrain.color, FIXED_COLOUR_PRIORITY)
else
remove_atom_colour(FIXED_COLOUR_PRIORITY)
@@ -34,7 +34,7 @@
for(var/i in 1 to 2)
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src)) //hello yes you are being healed
if(overmind)
H.color = overmind.blob_reagent_datum.complementary_color
H.color = overmind.blobstrain.complementary_color
else
H.color = "#000000"
adjustHealth(-maxHealth*0.0125)
@@ -75,6 +75,7 @@
desc = "A floating, fragile spore."
icon_state = "blobpod"
icon_living = "blobpod"
threat = 0.2
health = 30
maxHealth = 30
verb_say = "psychically pulses"
@@ -142,8 +143,10 @@
// Create the reagents to put into the air
create_reagents(10)
if(overmind && overmind.blob_reagent_datum)
reagents.add_reagent(overmind.blob_reagent_datum.type, 10)
if(overmind && overmind.blobstrain)
overmind.blobstrain.on_sporedeath(src)
else
reagents.add_reagent(/datum/reagent/toxin/spore, 10)
@@ -167,14 +170,14 @@
/mob/living/simple_animal/hostile/blob/blobspore/update_icons()
if(overmind)
add_atom_colour(overmind.blob_reagent_datum.complementary_color, FIXED_COLOUR_PRIORITY)
add_atom_colour(overmind.blobstrain.complementary_color, FIXED_COLOUR_PRIORITY)
else
remove_atom_colour(FIXED_COLOUR_PRIORITY)
if(is_zombie)
copy_overlays(oldguy, TRUE)
var/mutable_appearance/blob_head_overlay = mutable_appearance('icons/mob/blob.dmi', "blob_head")
if(overmind)
blob_head_overlay.color = overmind.blob_reagent_datum.complementary_color
blob_head_overlay.color = overmind.blobstrain.complementary_color
color = initial(color)//looks better.
add_overlay(blob_head_overlay)
@@ -243,14 +246,14 @@
adjustHealth(-maxHealth*0.1)
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src)) //hello yes you are being healed
if(overmind)
H.color = overmind.blob_reagent_datum.complementary_color
H.color = overmind.blobstrain.complementary_color
else
H.color = "#000000"
if(locate(/obj/structure/blob/node) in blobs_in_area)
adjustHealth(-maxHealth*0.05)
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src))
if(overmind)
H.color = overmind.blob_reagent_datum.complementary_color
H.color = overmind.blobstrain.complementary_color
else
H.color = "#000000"
if(damagesources)
@@ -259,7 +262,7 @@
var/image/I = new('icons/mob/blob.dmi', src, "nautdamage", MOB_LAYER+0.01)
I.appearance_flags = RESET_COLOR
if(overmind)
I.color = overmind.blob_reagent_datum.complementary_color
I.color = overmind.blobstrain.complementary_color
flick_overlay_view(I, src, 8)
/mob/living/simple_animal/hostile/blob/blobbernaut/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
@@ -274,16 +277,14 @@
/mob/living/simple_animal/hostile/blob/blobbernaut/AttackingTarget()
. = ..()
if(. && isliving(target) && overmind)
var/mob/living/L = target
var/mob_protection = L.get_permeability_protection()
overmind.blob_reagent_datum.reaction_mob(L, VAPOR, 20, 0, mob_protection, overmind)//this will do between 10 and 20 damage(reduced by mob protection), depending on chemical, plus 4 from base brute damage.
overmind.blobstrain.blobbernaut_attack(target)
/mob/living/simple_animal/hostile/blob/blobbernaut/update_icons()
..()
if(overmind) //if we have an overmind, we're doing chemical reactions instead of pure damage
melee_damage_lower = 4
melee_damage_upper = 4
attacktext = overmind.blob_reagent_datum.blobbernaut_message
attacktext = overmind.blobstrain.blobbernaut_message
else
melee_damage_lower = initial(melee_damage_lower)
melee_damage_upper = initial(melee_damage_upper)
@@ -8,12 +8,8 @@
explosion_block = 6
point_return = -1
health_regen = 0 //we regen in Life() instead of when pulsed
var/core_regen = 2
var/resource_delay = 0
var/point_rate = 2
/obj/structure/blob/core/Initialize(mapload, client/new_overmind = null, new_rate = 2, placed = 0)
/obj/structure/blob/core/Initialize(mapload, client/new_overmind = null, placed = 0)
GLOB.blob_cores += src
START_PROCESSING(SSobj, src)
GLOB.poi_list |= src
@@ -22,7 +18,6 @@
return INITIALIZE_HINT_QDEL
if(overmind)
update_icon()
point_rate = new_rate
addtimer(CALLBACK(src, .proc/generate_announcement), 1800)
. = ..()
@@ -37,7 +32,7 @@
color = null
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
if(overmind)
blob_overlay.color = overmind.blob_reagent_datum.color
blob_overlay.color = overmind.blobstrain.color
add_overlay(blob_overlay)
add_overlay(mutable_appearance('icons/mob/blob.dmi', "blob_core_overlay"))
@@ -60,17 +55,13 @@
if(overmind) //we should have an overmind, but...
overmind.update_health_hud()
/obj/structure/blob/core/Life()
/obj/structure/blob/core/process()
if(QDELETED(src))
return
if(!overmind)
qdel(src)
else
if(resource_delay <= world.time)
resource_delay = world.time + 10 // 1 second
overmind.add_points(point_rate)
obj_integrity = min(max_integrity, obj_integrity+core_regen)
if(overmind)
overmind.blobstrain.core_process()
overmind.update_health_hud()
Pulse_Area(overmind, 12, 4, 3)
for(var/obj/structure/blob/normal/B in range(1, src))
@@ -22,7 +22,7 @@
color = null
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
if(overmind)
blob_overlay.color = overmind.blob_reagent_datum.color
blob_overlay.color = overmind.blobstrain.color
add_overlay(blob_overlay)
add_overlay(mutable_appearance('icons/mob/blob.dmi', "blob_node_overlay"))
@@ -31,6 +31,6 @@
STOP_PROCESSING(SSobj, src)
return ..()
/obj/structure/blob/node/Life()
/obj/structure/blob/node/process()
if(overmind)
Pulse_Area(overmind, 10, 3, 2)
@@ -47,7 +47,7 @@
icon_state = "blob_glow"
flags_1 = CHECK_RICOCHET_1
point_return = 8
max_integrity = 50
max_integrity = 100
brute_resist = 1
explosion_block = 2
@@ -0,0 +1,74 @@
GLOBAL_LIST_INIT(valid_blobstrains, subtypesof(/datum/blobstrain) - list(/datum/blobstrain/reagent, /datum/blobstrain/multiplex))
/datum/blobstrain
var/name
var/description
var/color = "#000000"
var/complementary_color = "#000000" //a color that's complementary to the normal blob color
var/shortdesc = null //just damage and on_mob effects, doesn't include special, blob-tile only effects
var/effectdesc = null //any long, blob-tile specific effects
var/analyzerdescdamage = "Unknown. Report this bug to a coder, or just adminhelp."
var/analyzerdesceffect = "N/A"
var/blobbernaut_message = "slams" //blobbernaut attack verb
var/message = "The blob strikes you" //message sent to any mob hit by the blob
var/message_living = null //extension to first mob sent to only living mobs i.e. silicons have no skin to be burnt
var/core_regen = 2
var/resource_delay = 0
var/point_rate = 2
var/mob/camera/blob/overmind
/datum/blobstrain/New(mob/camera/blob/new_overmind)
if (!istype(new_overmind))
stack_trace("blobstrain created without overmind")
overmind = new_overmind
/datum/blobstrain/proc/on_gain()
overmind.color = complementary_color
for(var/BL in GLOB.blobs)
var/obj/structure/blob/B = BL
B.update_icon()
for(var/BLO in overmind.blob_mobs)
var/mob/living/simple_animal/hostile/blob/BM = BLO
BM.update_icons() //If it's getting a new strain, tell it what it does!
to_chat(BM, "Your overmind's blob strain is now: <b><font color=\"[color]\">[name]</b></font>!")
to_chat(BM, "The <b><font color=\"[color]\">[name]</b></font> strain [shortdesc ? "[shortdesc]" : "[description]"]")
/datum/blobstrain/proc/on_lose()
/datum/blobstrain/proc/on_sporedeath(mob/living/spore)
/datum/blobstrain/proc/send_message(mob/living/M)
var/totalmessage = message
if(message_living && !issilicon(M))
totalmessage += message_living
totalmessage += "!"
to_chat(M, "<span class='userdanger'>[totalmessage]</span>")
/datum/blobstrain/proc/core_process()
if(resource_delay <= world.time)
resource_delay = world.time + 10 // 1 second
overmind.add_points(point_rate)
overmind.blob_core.obj_integrity = min(overmind.blob_core.max_integrity, overmind.blob_core.obj_integrity+core_regen)
/datum/blobstrain/proc/attack_living(var/mob/living/L) // When the blob attacks people
send_message(L)
/datum/blobstrain/proc/blobbernaut_attack(mob/living/L) // When this blob's blobbernaut attacks people
/datum/blobstrain/proc/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag, coefficient = 1) //when the blob takes damage, do this
return coefficient*damage
/datum/blobstrain/proc/death_reaction(obj/structure/blob/B, damage_flag, coefficient = 1) //when a blob dies, do this
return
/datum/blobstrain/proc/expand_reaction(obj/structure/blob/B, obj/structure/blob/newB, turf/T, mob/camera/blob/O, coefficient = 1) //when the blob expands, do this
return
/datum/blobstrain/proc/tesla_reaction(obj/structure/blob/B, power, coefficient = 1) //when the blob is hit by a tesla bolt, do this
return 1 //return 0 to ignore damage
/datum/blobstrain/proc/extinguish_reaction(obj/structure/blob/B, coefficient = 1) //when the blob is hit with water, do this
return
/datum/blobstrain/proc/emp_reaction(obj/structure/blob/B, severity, coefficient = 1) //when the blob is hit with an emp, do this
return
@@ -0,0 +1,33 @@
/datum/blobstrain/reagent // Blobs that mess with reagents, all "legacy" ones
var/datum/reagent/reagent
/datum/blobstrain/reagent/New(mob/camera/blob/new_overmind)
. = ..()
reagent = new reagent()
/datum/blobstrain/reagent/attack_living(var/mob/living/L)
var/mob_protection = L.get_permeability_protection()
reagent.reaction_mob(L, VAPOR, 25, 1, mob_protection, overmind)
send_message(L)
/datum/blobstrain/reagent/blobbernaut_attack(mob/living/L)
var/mob_protection = L.get_permeability_protection()
reagent.reaction_mob(L, VAPOR, 20, 0, mob_protection, overmind)//this will do between 10 and 20 damage(reduced by mob protection), depending on chemical, plus 4 from base brute damage.
/datum/blobstrain/reagent/on_sporedeath(mob/living/spore)
spore.reagents.add_reagent(reagent.type, 10)
// These can only be applied by blobs. They are what (reagent) blobs are made out of.
/datum/reagent/blob
name = "Unknown"
description = "shouldn't exist and you should adminhelp immediately."
color = "#FFFFFF"
taste_description = "bad code and slime"
can_synth = FALSE
/datum/reagent/blob/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
if(M.stat == DEAD || istype(M, /mob/living/simple_animal/hostile/blob))
return 0 //the dead, and blob mobs, don't cause reactions
return round(reac_volume * min(1.5 - touch_protection, 1), 0.1) //full touch protection means 50% volume, any prot below 0.5 means 100% volume.
@@ -0,0 +1,41 @@
//sets you on fire, does burn damage, explodes into flame when burnt, weak to water
/datum/blobstrain/reagent/blazing_oil
name = "Blazing Oil"
description = "will do medium burn damage and set targets on fire."
effectdesc = "will also release bursts of flame when burnt, but takes damage from water."
analyzerdescdamage = "Does medium burn damage and sets targets on fire."
analyzerdesceffect = "Releases fire when burnt, but takes damage from water and other extinguishing liquids."
color = "#B68D00"
complementary_color = "#BE5532"
blobbernaut_message = "splashes"
message = "The blob splashes you with burning oil"
message_living = ", and you feel your skin char and melt"
reagent = /datum/reagent/blob/blazing_oil
/datum/blobstrain/reagent/blazing_oil/extinguish_reaction(obj/structure/blob/B)
B.take_damage(1.5, BURN, "energy")
/datum/blobstrain/reagent/blazing_oil/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if(damage_type == BURN && damage_flag != "energy")
for(var/turf/open/T in range(1, B))
var/obj/structure/blob/C = locate() in T
if(!(C && C.overmind && C.overmind.blobstrain.type == B.overmind.blobstrain.type) && prob(80))
new /obj/effect/hotspot(T)
if(damage_flag == "fire")
return 0
return ..()
/datum/reagent/blob/blazing_oil
name = "Blazing Oil"
taste_description = "burning oil"
color = "#B68D00"
/datum/reagent/blob/blazing_oil/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
M.adjust_fire_stacks(round(reac_volume/10))
M.IgniteMob()
if(M)
M.apply_damage(0.8*reac_volume, BURN)
if(iscarbon(M))
M.emote("scream")
@@ -0,0 +1,32 @@
//does brute, burn, and toxin damage, and cools targets down
/datum/blobstrain/reagent/cryogenic_poison
name = "Cryogenic Poison"
description = "will inject targets with a freezing poison that does high damage over time."
analyzerdescdamage = "Injects targets with a freezing poison that will gradually solidify the target's internal organs."
color = "#8BA6E9"
complementary_color = "#7D6EB4"
blobbernaut_message = "injects"
message = "The blob stabs you"
message_living = ", and you feel like your insides are solidifying"
reagent = /datum/reagent/blob/cryogenic_poison
/datum/reagent/blob/cryogenic_poison
name = "Cryogenic Poison"
description = "will inject targets with a freezing poison that does high damage over time."
color = "#8BA6E9"
taste_description = "brain freeze"
/datum/reagent/blob/cryogenic_poison/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
if(M.reagents)
M.reagents.add_reagent("frostoil", 0.3*reac_volume)
M.reagents.add_reagent("ice", 0.3*reac_volume)
M.reagents.add_reagent("cryogenic_poison", 0.3*reac_volume)
M.apply_damage(0.2*reac_volume, BRUTE)
/datum/reagent/blob/cryogenic_poison/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(0.3*REAGENTS_EFFECT_MULTIPLIER, 0)
M.adjustFireLoss(0.3*REAGENTS_EFFECT_MULTIPLIER, 0)
M.adjustToxLoss(0.3*REAGENTS_EFFECT_MULTIPLIER, 0)
. = 1
..()
@@ -0,0 +1,33 @@
//does burn damage and EMPs, slightly fragile
/datum/blobstrain/reagent/electromagnetic_web
name = "Electromagnetic Web"
color = "#83ECEC"
complementary_color = "#EC8383"
reagent = /datum/reagent/blob/electromagnetic_web
/datum/blobstrain/reagent/electromagnetic_web/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if(damage_type == BRUTE) //take full brute
switch(B.brute_resist)
if(0.5)
return damage * 2
if(0.25)
return damage * 4
if(0.1)
return damage * 10
return damage * 1.25 //a laser will do 25 damage, which will kill any normal blob
/datum/blobstrain/reagent/electromagnetic_web/death_reaction(obj/structure/blob/B, damage_flag)
if(damage_flag == "melee" || damage_flag == "bullet" || damage_flag == "laser")
empulse(B.loc, 1, 3) //less than screen range, so you can stand out of range to avoid it
/datum/reagent/blob/electromagnetic_web
name = "Electromagnetic Web"
taste_description = "pop rocks"
color = "#83ECEC"
/datum/reagent/blob/electromagnetic_web/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
if(prob(reac_volume*2))
M.emp_act(EMP_LIGHT)
if(M)
M.apply_damage(reac_volume, BURN)
@@ -0,0 +1,34 @@
//does tons of oxygen damage and a little stamina, immune to tesla bolts, weak to EMP
/datum/blobstrain/reagent/energized_jelly
name = "Energized Jelly"
description = "will cause low stamina and high oxygen damage, and cause targets to be unable to breathe."
effectdesc = "will also conduct electricity, but takes damage from EMPs."
analyzerdescdamage = "Does low stamina damage, high oxygen damage, and prevents targets from breathing."
analyzerdesceffect = "Is immune to electricity and will easily conduct it, but is weak to EMPs."
color = "#EFD65A"
complementary_color = "#00E5B1"
reagent = /datum/reagent/blob/energized_jelly
/datum/blobstrain/reagent/energized_jelly/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if((damage_flag == "melee" || damage_flag == "bullet" || damage_flag == "laser") && B.obj_integrity - damage <= 0 && prob(10))
do_sparks(rand(2, 4), FALSE, B)
return ..()
/datum/blobstrain/reagent/energized_jelly/tesla_reaction(obj/structure/blob/B, power)
return 0
/datum/blobstrain/reagent/energized_jelly/emp_reaction(obj/structure/blob/B, severity)
var/damage = rand(30, 50) - severity * rand(10, 15)
B.take_damage(damage, BURN, "energy")
/datum/reagent/blob/energized_jelly
name = "Energized Jelly"
taste_description = "gelatin"
color = "#EFD65A"
/datum/reagent/blob/energized_jelly/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
M.losebreath += round(0.2*reac_volume)
M.adjustStaminaLoss(0.4*reac_volume)
if(M)
M.apply_damage(0.6*reac_volume, OXY)
@@ -0,0 +1,40 @@
//does aoe brute damage when hitting targets, is immune to explosions
/datum/blobstrain/reagent/explosive_lattice
name = "Explosive Lattice"
description = "will do brute damage in an area around targets."
effectdesc = "will also resist explosions, but takes increased damage from fire and other energy sources."
analyzerdescdamage = "Does medium brute damage and causes damage to everyone near its targets."
analyzerdesceffect = "Is highly resistant to explosions, but takes increased damage from fire and other energy sources."
color = "#8B2500"
complementary_color = "#00668B"
blobbernaut_message = "blasts"
message = "The blob blasts you"
reagent = /datum/reagent/blob/explosive_lattice
/datum/blobstrain/reagent/explosive_lattice/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if(damage_flag == "bomb")
return 0
else if(damage_flag != "melee" && damage_flag != "bullet" && damage_flag != "laser")
return damage * 1.5
return ..()
/datum/reagent/blob/explosive_lattice
name = "Explosive Lattice"
taste_description = "the bomb"
color = "#8B2500"
/datum/reagent/blob/explosive_lattice/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
var/initial_volume = reac_volume
reac_volume = ..()
if(reac_volume >= 10) //if it's not a spore cloud, bad time incoming
var/obj/effect/temp_visual/explosion/fast/E = new /obj/effect/temp_visual/explosion/fast(get_turf(M))
E.alpha = 150
for(var/mob/living/L in orange(get_turf(M), 1))
if(ROLE_BLOB in L.faction) //no friendly fire
continue
var/aoe_volume = ..(L, TOUCH, initial_volume, 0, L.get_permeability_protection(), O)
L.apply_damage(0.4*aoe_volume, BRUTE)
if(M)
M.apply_damage(0.6*reac_volume, BRUTE)
else
M.apply_damage(0.6*reac_volume, BRUTE)
@@ -0,0 +1,40 @@
/datum/blobstrain/multiplex
var/list/blobstrains
var/typeshare
/datum/blobstrain/multiplex/New(mob/camera/blob/new_overmind, list/blobstrains)
. = ..()
for (var/bt in blobstrains)
if (ispath(bt, /datum/blobstrain))
src.blobstrains += new bt(overmind)
else if (istype(bt, /datum/blobstrain))
var/datum/blobstrain/bts = bt
bts.overmind = overmind
src.blobstrains += bt
typeshare = (0.8 * length(src.blobstrains)) - (length(src.blobstrains)-1) // 1 is 80%, 2 are 60% etc
/datum/blobstrain/multiplex/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag, coefficient = 1) //when the blob takes damage, do this
for (var/datum/blobstrain/bt in blobstrains)
. += bt.damage_reaction(B, damage, damage_type, damage_flag, coefficient*typeshare)
/datum/blobstrain/multiplex/death_reaction(obj/structure/blob/B, damage_flag, coefficient = 1) //when a blob dies, do this
for (var/datum/blobstrain/bt in blobstrains)
. += bt.death_reaction(B, damage_flag, coefficient*typeshare)
/datum/blobstrain/multiplex/expand_reaction(obj/structure/blob/B, obj/structure/blob/newB, turf/T, mob/camera/blob/O, coefficient = 1) //when the blob expands, do this
for (var/datum/blobstrain/bt in blobstrains)
. += bt.expand_reaction(B, newB, T, O, coefficient*typeshare)
/datum/blobstrain/multiplex/tesla_reaction(obj/structure/blob/B, power, coefficient = 1) //when the blob is hit by a tesla bolt, do this
for (var/datum/blobstrain/bt in blobstrains)
. += bt.tesla_reaction(B, power, coefficient*typeshare)
if (prob(. / length(blobstrains) * 100))
return 1
/datum/blobstrain/multiplex/extinguish_reaction(obj/structure/blob/B, coefficient = 1) //when the blob is hit with water, do this
for (var/datum/blobstrain/bt in blobstrains)
. += bt.extinguish_reaction(B, coefficient*typeshare)
/datum/blobstrain/multiplex/emp_reaction(obj/structure/blob/B, severity, coefficient = 1) //when the blob is hit with an emp, do this
for (var/datum/blobstrain/bt in blobstrains)
. += bt.emp_reaction(B, severity, coefficient*typeshare)
@@ -0,0 +1,38 @@
//does massive brute and burn damage, but can only expand manually
/datum/blobstrain/reagent/networked_fibers
name = "Networked Fibers"
description = "will do high brute and burn damage and will generate resources quicker, but can only expand manually."
shortdesc = "will do high brute and burn damage."
effectdesc = "will move your core when manually expanding near it."
analyzerdescdamage = "Does high brute and burn damage."
analyzerdesceffect = "Is highly mobile and generates resources rapidly."
color = "#CDC0B0"
complementary_color = "#FFF68F"
reagent = /datum/reagent/blob/networked_fibers
/datum/blobstrain/reagent/networked_fibers/expand_reaction(obj/structure/blob/B, obj/structure/blob/newB, turf/T, mob/camera/blob/O)
if(!O && newB.overmind)
if(!istype(B, /obj/structure/blob/node))
newB.overmind.add_points(1)
qdel(newB)
else
var/area/A = get_area(T)
if(!isspaceturf(T) && !istype(A, /area/shuttle))
for(var/obj/structure/blob/core/C in range(1, newB))
if(C.overmind == O)
newB.forceMove(get_turf(C))
C.forceMove(T)
C.setDir(get_dir(newB, C))
O.add_points(1)
//does massive brute and burn damage, but can only expand manually
/datum/reagent/blob/networked_fibers
name = "Networked Fibers"
taste_description = "efficiency"
color = "#CDC0B0"
/datum/reagent/blob/networked_fibers/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
M.apply_damage(0.6*reac_volume, BRUTE)
if(M)
M.apply_damage(0.6*reac_volume, BURN)
@@ -0,0 +1,51 @@
//does low brute damage, oxygen damage, and stamina damage and wets tiles when damaged
/datum/blobstrain/reagent/pressurized_slime
name = "Pressurized Slime"
description = "will do low brute, oxygen, and stamina damage, and wet tiles under targets."
effectdesc = "will also wet tiles near blobs that are attacked or killed."
analyzerdescdamage = "Does low brute damage, low oxygen damage, drains stamina, and wets tiles under targets, extinguishing them."
analyzerdesceffect = "When attacked or killed, lubricates nearby tiles, extinguishing anything on them."
color = "#AAAABB"
complementary_color = "#BBBBAA"
blobbernaut_message = "emits slime at"
message = "The blob splashes into you"
message_living = ", and you gasp for breath"
reagent = /datum/reagent/blob/pressurized_slime
/datum/blobstrain/reagent/pressurized_slime/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if((damage_flag == "melee" || damage_flag == "bullet" || damage_flag == "laser") || damage_type != BURN)
extinguisharea(B, damage)
return ..()
/datum/blobstrain/reagent/pressurized_slime/death_reaction(obj/structure/blob/B, damage_flag)
if(damage_flag == "melee" || damage_flag == "bullet" || damage_flag == "laser")
B.visible_message("<span class='boldwarning'>The blob ruptures, spraying the area with liquid!</span>")
extinguisharea(B, 50)
/datum/blobstrain/reagent/pressurized_slime/proc/extinguisharea(obj/structure/blob/B, probchance)
for(var/turf/open/T in range(1, B))
if(prob(probchance))
T.MakeSlippery(TURF_WET_LUBE, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
for(var/obj/O in T)
O.extinguish()
for(var/mob/living/L in T)
L.adjust_fire_stacks(-2.5)
L.ExtinguishMob()
/datum/reagent/blob/pressurized_slime
name = "Pressurized Slime"
taste_description = "a sponge"
color = "#AAAABB"
/datum/reagent/blob/pressurized_slime/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
var/turf/open/T = get_turf(M)
if(istype(T) && prob(reac_volume))
T.MakeSlippery(TURF_WET_LUBE, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
M.adjust_fire_stacks(-(reac_volume / 10))
M.ExtinguishMob()
M.apply_damage(0.4*reac_volume, BRUTE)
if(M)
M.apply_damage(0.4*reac_volume, OXY)
if(M)
M.adjustStaminaLoss(0.2*reac_volume)
@@ -0,0 +1,30 @@
//does brute damage through armor and bio resistance
/datum/blobstrain/reagent/reactive_spines
name = "Reactive Spines"
description = "will do medium brute damage through armor and bio resistance."
effectdesc = "will also react when attacked with brute damage, attacking all near the attacked blob."
analyzerdescdamage = "Does medium brute damage, ignoring armor and bio resistance."
analyzerdesceffect = "When attacked with brute damage, will lash out, attacking everything near it."
color = "#9ACD32"
complementary_color = "#FFA500"
blobbernaut_message = "stabs"
message = "The blob stabs you"
reagent = /datum/reagent/blob/reactive_spines
/datum/blobstrain/reagent/reactive_spines/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if(damage && damage_type == BRUTE && B.obj_integrity - damage > 0) //is there any damage, is it brute, and will we be alive
if(damage_flag == "melee")
B.visible_message("<span class='boldwarning'>The blob retaliates, lashing out!</span>")
for(var/atom/A in range(1, B))
A.blob_act(B)
return ..()
/datum/reagent/blob/reactive_spines
name = "Reactive Spines"
taste_description = "rock"
color = "#9ACD32"
/datum/reagent/blob/reactive_spines/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
if(M.stat == DEAD || istype(M, /mob/living/simple_animal/hostile/blob))
return 0 //the dead, and blob mobs, don't cause reactions
M.adjustBruteLoss(0.8*reac_volume)
@@ -0,0 +1,33 @@
//does toxin damage, hallucination, targets think they're not hurt at all
/datum/blobstrain/reagent/regenerative_materia
name = "Regenerative Materia"
description = "will do toxin damage and cause targets to believe they are fully healed."
analyzerdescdamage = "Does toxin damage and injects a toxin that causes the target to believe they are fully healed."
color = "#C8A5DC"
complementary_color = "#CD7794"
message_living = ", and you feel <i>alive</i>"
reagent = /datum/reagent/blob/regenerative_materia
/datum/reagent/blob/regenerative_materia
name = "Regenerative Materia"
taste_description = "heaven"
color = "#C8A5DC"
/datum/reagent/blob/regenerative_materia/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
M.adjust_drugginess(reac_volume)
if(M.reagents)
M.reagents.add_reagent("regenerative_materia", 0.2*reac_volume)
M.reagents.add_reagent("spore", 0.2*reac_volume)
M.apply_damage(0.7*reac_volume, TOX)
/datum/reagent/blob/regenerative_materia/on_mob_life(mob/living/carbon/C)
C.adjustToxLoss(1*REAGENTS_EFFECT_MULTIPLIER)
C.hal_screwyhud = SCREWYHUD_HEALTHY //fully healed, honest
..()
/datum/reagent/blob/regenerative_materia/on_mob_delete(mob/living/M)
if(iscarbon(M))
var/mob/living/carbon/N = M
N.hal_screwyhud = 0
..()
@@ -0,0 +1,34 @@
/datum/blobstrain/reagent/replicating_foam
description = "will do medium brute damage and occasionally expand again when expanding."
shortdesc = "will do medium brute damage."
effectdesc = "will also expand when attacked with burn damage, but takes more brute damage."
color = "#7B5A57"
complementary_color = "#57787B"
analyzerdescdamage = "Does medium brute damage."
analyzerdesceffect = "Expands when attacked with burn damage, will occasionally expand again when expanding, and is fragile to brute damage."
reagent = /datum/reagent/blob/replicating_foam
/datum/blobstrain/reagent/replicating_foam/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if(damage_type == BRUTE)
damage = damage * 2
else if(damage_type == BURN && damage > 0 && B.obj_integrity - damage > 0 && prob(60))
var/obj/structure/blob/newB = B.expand(null, null, 0)
if(newB)
newB.obj_integrity = B.obj_integrity - damage
newB.update_icon()
return ..()
/datum/blobstrain/reagent/replicating_foam/expand_reaction(obj/structure/blob/B, obj/structure/blob/newB, turf/T, mob/camera/blob/O)
if(prob(30))
newB.expand(null, null, 0) //do it again!
/datum/reagent/blob/replicating_foam
name = "Replicating Foam"
taste_description = "duplication"
color = "#7B5A57"
/datum/reagent/blob/replicating_foam/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
M.apply_damage(0.7*reac_volume, BRUTE)
@@ -0,0 +1,35 @@
//does brute damage, shifts away when damaged
/datum/blobstrain/reagent/shifting_fragments
description = "will do medium brute damage."
effectdesc = "will also cause blob parts to shift away when attacked."
analyzerdescdamage = "Does medium brute damage."
analyzerdesceffect = "When attacked, may shift away from the attacker."
color = "#C8963C"
complementary_color = "#3C6EC8"
reagent = /datum/reagent/blob/shifting_fragments
/datum/blobstrain/reagent/shifting_fragments/expand_reaction(obj/structure/blob/B, obj/structure/blob/newB, turf/T, mob/camera/blob/O)
if(istype(B, /obj/structure/blob/normal) || (istype(B, /obj/structure/blob/shield) && prob(25)))
newB.forceMove(get_turf(B))
B.forceMove(T)
/datum/blobstrain/reagent/shifting_fragments/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if((damage_flag == "melee" || damage_flag == "bullet" || damage_flag == "laser") && damage > 0 && B.obj_integrity - damage > 0 && prob(60-damage))
var/list/blobstopick = list()
for(var/obj/structure/blob/OB in orange(1, B))
if((istype(OB, /obj/structure/blob/normal) || (istype(OB, /obj/structure/blob/shield) && prob(25))) && OB.overmind && OB.overmind.blobstrain.type == B.overmind.blobstrain.type)
blobstopick += OB //as long as the blob picked is valid; ie, a normal or shield blob that has the same chemical as we do, we can swap with it
if(blobstopick.len)
var/obj/structure/blob/targeted = pick(blobstopick) //randomize the blob chosen, because otherwise it'd tend to the lower left
var/turf/T = get_turf(targeted)
targeted.forceMove(get_turf(B))
B.forceMove(T) //swap the blobs
return ..()
/datum/reagent/blob/shifting_fragments
name = "Shifting Fragments"
color = "#C8963C"
/datum/reagent/blob/shifting_fragments/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
M.apply_damage(0.7*reac_volume, BRUTE)
@@ -0,0 +1,38 @@
//does brute damage, bonus damage for each nearby blob, and spreads damage out
/datum/blobstrain/reagent/synchronous_mesh
name = "Synchronous Mesh"
description = "will do massively increased brute damage for each blob near the target."
effectdesc = "will also spread damage between each blob near the attacked blob."
analyzerdescdamage = "Does brute damage, increasing for each blob near the target."
analyzerdesceffect = "When attacked, spreads damage between all blobs near the attacked blob."
color = "#65ADA2"
complementary_color = "#AD6570"
blobbernaut_message = "synchronously strikes"
message = "The blobs strike you"
/datum/blobstrain/reagent/synchronous_mesh/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if(damage_flag == "melee" || damage_flag == "bullet" || damage_flag == "laser") //the cause isn't fire or bombs, so split the damage
var/damagesplit = 1 //maximum split is 9, reducing the damage each blob takes to 11% but doing that damage to 9 blobs
for(var/obj/structure/blob/C in orange(1, B))
if(!istype(C, /obj/structure/blob/core) && !istype(C, /obj/structure/blob/node) && C.overmind && C.overmind.blobstrain.type == B.overmind.blobstrain.type) //if it doesn't have the same chemical or is a core or node, don't split damage to it
damagesplit += 1
for(var/obj/structure/blob/C in orange(1, B))
if(!istype(C, /obj/structure/blob/core) && !istype(C, /obj/structure/blob/node) && C.overmind && C.overmind.blobstrain.type == B.overmind.blobstrain.type) //only hurt blobs that have the same overmind chemical and aren't cores or nodes
C.take_damage(damage/damagesplit, CLONE, 0, 0)
return damage / damagesplit
else
return damage * 1.25
/datum/reagent/blob/synchronous_mesh
name = "Synchronous Mesh"
taste_description = "toxic mold"
color = "#65ADA2"
/datum/reagent/blob/synchronous_mesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
M.apply_damage(0.2*reac_volume, BRUTE)
if(M && reac_volume)
for(var/obj/structure/blob/B in range(1, M)) //if the target is completely surrounded, this is 2.4*reac_volume bonus damage, total of 2.6*reac_volume
if(M)
B.blob_attack_animation(M) //show them they're getting a bad time
M.apply_damage(0.3*reac_volume, BRUTE)
@@ -0,0 +1,46 @@
//kills sleeping targets and turns them into blob zombies, produces fragile spores when killed or on expanding
/datum/blobstrain/reagent/zombifying_pods
name = "Zombifying Pods"
description = "will do very low toxin damage and harvest sleeping targets for additional resources and a blob zombie."
effectdesc = "will also produce fragile spores when killed and on expanding."
shortdesc = "will do very low toxin damage and harvest sleeping targets for additional resources(for your overmind) and a blob zombie."
analyzerdescdamage = "Does very low toxin damage and kills unconscious humans, turning them into blob zombies."
analyzerdesceffect = "Produces spores when expanding and when killed."
color = "#E88D5D"
complementary_color = "#823ABB"
message_living = ", and you feel tired"
reagent = /datum/reagent/blob/zombifying_pods
/datum/blobstrain/reagent/zombifying_pods/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if((damage_flag == "melee" || damage_flag == "bullet" || damage_flag == "laser") && damage <= 20 && B.obj_integrity - damage <= 0 && prob(30)) //if the cause isn't fire or a bomb, the damage is less than 21, we're going to die from that damage, 20% chance of a shitty spore.
B.visible_message("<span class='warning'><b>A spore floats free of the blob!</b></span>")
var/mob/living/simple_animal/hostile/blob/blobspore/weak/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(B.loc)
BS.overmind = B.overmind
BS.update_icons()
B.overmind.blob_mobs.Add(BS)
return ..()
/datum/blobstrain/reagent/zombifying_pods/expand_reaction(obj/structure/blob/B, obj/structure/blob/newB, turf/T, mob/camera/blob/O)
if(prob(10))
var/mob/living/simple_animal/hostile/blob/blobspore/weak/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(T)
BS.overmind = B.overmind
BS.update_icons()
newB.overmind.blob_mobs.Add(BS)
/datum/reagent/blob/zombifying_pods
name = "Zombifying Pods"
color = "#E88D5D"
/datum/reagent/blob/zombifying_pods/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
M.apply_damage(0.6*reac_volume, TOX)
if(O && ishuman(M) && M.stat == UNCONSCIOUS)
M.death() //sleeping in a fight? bad plan.
var/points = rand(5, 10)
var/mob/living/simple_animal/hostile/blob/blobspore/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(get_turf(M))
BS.overmind = O
BS.update_icons()
O.blob_mobs.Add(BS)
BS.Zombify(M)
O.add_points(points)
to_chat(O, "<span class='notice'>Gained [points] resources from the zombification of [M].</span>")
+37 -19
View File
@@ -20,25 +20,25 @@ GLOBAL_LIST_EMPTY(blob_nodes)
pass_flags = PASSBLOB
faction = list(ROLE_BLOB)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
call_life = TRUE
hud_type = /datum/hud/blob_overmind
var/obj/structure/blob/core/blob_core = null // The blob overmind's core
var/blob_points = 0
var/max_blob_points = 250
var/last_attack = 0
var/datum/reagent/blob/blob_reagent_datum = new/datum/reagent/blob()
var/datum/blobstrain/blobstrain
var/list/blob_mobs = list()
var/list/resource_blobs = list()
var/free_chem_rerolls = 1 //one free chemical reroll
var/free_strain_rerolls = 1 //one free strain reroll
var/last_reroll_time = 0 //time since we last rerolled, used to give free rerolls
var/nodes_required = 1 //if the blob needs nodes to place resource and factory blobs
var/placed = 0
var/base_point_rate = 2 //for blob core placement
var/manualplace_min_time = 600 //in deciseconds //a minute, to get bearings
var/autoplace_max_time = 3600 //six minutes, as long as should be needed
var/list/blobs_legit = list()
var/max_count = 0 //The biggest it got before death
var/blobwincount = 400
var/victory_in_progress = FALSE
var/rerolling = FALSE
/mob/camera/blob/Initialize(mapload, starting_points = 60)
validate_location()
@@ -50,13 +50,14 @@ GLOBAL_LIST_EMPTY(blob_nodes)
name = new_name
real_name = new_name
last_attack = world.time
var/datum/reagent/blob/BC = pick((subtypesof(/datum/reagent/blob)))
blob_reagent_datum = new BC
color = blob_reagent_datum.complementary_color
var/datum/blobstrain/BS = pick(GLOB.valid_blobstrains)
set_strain(BS)
color = blobstrain.complementary_color
if(blob_core)
blob_core.update_icon()
SSshuttle.registerHostileEnvironment(src)
.= ..()
. = ..()
START_PROCESSING(SSobj, src)
/mob/camera/blob/proc/validate_location()
var/turf/T = get_turf(src)
@@ -70,13 +71,28 @@ GLOBAL_LIST_EMPTY(blob_nodes)
CRASH("No blobspawnpoints and blob spawned in nullspace.")
forceMove(T)
/mob/camera/blob/proc/set_strain(datum/blobstrain/new_strain)
if (ispath(new_strain))
var/hadstrain = FALSE
if (istype(blobstrain))
blobstrain.on_lose()
qdel(blobstrain)
hadstrain = TRUE
blobstrain = new new_strain(src)
blobstrain.on_gain()
if (hadstrain)
to_chat(src, "Your strain is now: <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font>!")
to_chat(src, "The <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font> strain [blobstrain.description]")
if(blobstrain.effectdesc)
to_chat(src, "The <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font> strain [blobstrain.effectdesc]")
/mob/camera/blob/proc/is_valid_turf(turf/T)
var/area/A = get_area(T)
if((A && !A.blob_allowed) || !T || !is_station_level(T.z) || isspaceturf(T))
return FALSE
return TRUE
/mob/camera/blob/Life()
/mob/camera/blob/process()
if(!blob_core)
if(!placed)
if(manualplace_min_time && world.time >= manualplace_min_time)
@@ -84,7 +100,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
to_chat(src, "<span class='big'><font color=\"#EE4000\">You will automatically place your blob core in [DisplayTimeText(autoplace_max_time - world.time)].</font></span>")
manualplace_min_time = 0
if(autoplace_max_time && world.time >= autoplace_max_time)
place_blob_core(base_point_rate, 1)
place_blob_core(1)
else
qdel(src)
else if(!victory_in_progress && (blobs_legit.len >= blobwincount))
@@ -94,11 +110,12 @@ GLOBAL_LIST_EMPTY(blob_nodes)
max_blob_points = INFINITY
blob_points = INFINITY
addtimer(CALLBACK(src, .proc/victory), 450)
else if(!free_strain_rerolls && (last_reroll_time + BLOB_REROLL_TIME<world.time))
to_chat(src, "<b><span class='big'><font color=\"#EE4000\">You have gained another free strain re-roll.</font></span></b>")
free_strain_rerolls = 1
if(!victory_in_progress && max_count < blobs_legit.len)
max_count = blobs_legit.len
..()
/mob/camera/blob/proc/victory()
sound_to_playing_players('sound/machines/alarm.ogg')
@@ -129,7 +146,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
continue
if(!A.blob_allowed)
continue
A.color = blob_reagent_datum.color
A.color = blobstrain.color
A.name = "blob"
A.icon = 'icons/mob/blob.dmi'
A.icon_state = "blob_shield"
@@ -162,6 +179,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
blobs_legit = null
SSshuttle.clearHostileEnvironment(src)
STOP_PROCESSING(SSobj, src)
return ..()
@@ -173,9 +191,9 @@ GLOBAL_LIST_EMPTY(blob_nodes)
add_points(0)
/mob/camera/blob/examine(mob/user)
. = ..()
if(blob_reagent_datum)
. += "Its chemical is <font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</font>."
..()
if(blobstrain)
to_chat(user, "Its strain is <font color=\"[blobstrain.color]\">[blobstrain.name]</font>.")
/mob/camera/blob/update_health_hud()
if(blob_core)
@@ -214,7 +232,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
src.log_talk(message, LOG_SAY)
var/message_a = say_quote(message)
var/rendered = "<span class='big'><font color=\"#EE4000\"><b>\[Blob Telepathy\] [name](<font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</font>)</b> [message_a]</font></span>"
var/rendered = "<span class='big'><font color=\"#EE4000\"><b>\[Blob Telepathy\] [name](<font color=\"[blobstrain.color]\">[blobstrain.name]</font>)</b> [message_a]</font></span>"
for(var/mob/M in GLOB.mob_list)
if(isovermind(M) || istype(M, /mob/living/simple_animal/hostile/blob))
@@ -233,8 +251,8 @@ GLOBAL_LIST_EMPTY(blob_nodes)
stat(null, "Core Health: [blob_core.obj_integrity]")
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
stat(null, "Blobs to Win: [blobs_legit.len]/[blobwincount]")
if(free_chem_rerolls)
stat(null, "You have [free_chem_rerolls] Free Chemical Reroll\s Remaining")
if(free_strain_rerolls)
stat(null, "You have [free_strain_rerolls] Free Strain Reroll\s Remaining")
if(!placed)
if(manualplace_min_time)
stat(null, "Time Before Manual Placement: [max(round((manualplace_min_time - world.time)*0.1, 0.1), 0)]")
+47 -48
View File
@@ -7,7 +7,7 @@
// Power verbs
/mob/camera/blob/proc/place_blob_core(point_rate, placement_override , pop_override = FALSE)
/mob/camera/blob/proc/place_blob_core(placement_override, pop_override = FALSE)
if(placed && placement_override != -1)
return 1
if(!placement_override)
@@ -47,7 +47,7 @@
if(placed && blob_core)
blob_core.forceMove(loc)
else
var/obj/structure/blob/core/core = new(get_turf(src), src, point_rate, 1)
var/obj/structure/blob/core/core = new(get_turf(src), src, 1)
core.overmind = src
blobs_legit += src
blob_core = core
@@ -71,13 +71,13 @@
var/list/nodes = list()
for(var/i in 1 to GLOB.blob_nodes.len)
var/obj/structure/blob/node/B = GLOB.blob_nodes[i]
nodes["Blob Node #[i] ([B.overmind ? "[B.overmind.blob_reagent_datum.name]":"No Chemical"])"] = B
nodes["Blob Node #[i] ([get_area_name(B)])"] = B
var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
var/obj/structure/blob/node/chosen_node = nodes[node_name]
if(chosen_node)
forceMove(chosen_node.loc)
/mob/camera/blob/proc/createSpecial(price, blobType, nearEquals, needsNode, turf/T)
/mob/camera/blob/proc/createSpecial(price, blobstrain, nearEquals, needsNode, turf/T)
if(!T)
T = get_turf(src)
var/obj/structure/blob/B = (locate(/obj/structure/blob) in T)
@@ -93,12 +93,12 @@
return //handholdotron 2000
if(nearEquals)
for(var/obj/structure/blob/L in orange(nearEquals, T))
if(L.type == blobType)
if(L.type == blobstrain)
to_chat(src, "<span class='warning'>There is a similar blob nearby, move more than [nearEquals] tiles away from it!</span>")
return
if(!can_buy(price))
return
var/obj/structure/blob/N = B.change_to(blobType, src)
var/obj/structure/blob/N = B.change_to(blobstrain, src)
return N
/mob/camera/blob/verb/toggle_node_req()
@@ -120,12 +120,13 @@
/mob/camera/blob/proc/create_shield(turf/T)
var/obj/structure/blob/shield/S = locate(/obj/structure/blob/shield) in T
if(S)
if(!can_buy(15))
if(!can_buy(BLOB_REFLECTOR_COST))
return
if(S.obj_integrity < S.max_integrity * 0.5)
add_points(BLOB_REFLECTOR_COST)
to_chat(src, "<span class='warning'>This shield blob is too damaged to be modified properly!</span>")
return
to_chat(src, "<span class='warning'>You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced intregrity.</span>")
to_chat(src, "<span class='warning'>You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced integrity.</span>")
S.change_to(/obj/structure/blob/shield/reflective, src)
else
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
@@ -166,7 +167,9 @@
if(!can_buy(40))
return
var/list/mob/candidates = pollGhostCandidates("Do you want to play as a [blob_reagent_datum.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50) //players must answer rapidly
B.naut = TRUE //temporary placeholder to prevent creation of more than one per factory.
to_chat(src, "<span class='notice'>You attempt to produce a blobbernaut.</span>")
var/list/mob/candidates = pollGhostCandidates("Do you want to play as a [blobstrain.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50) //players must answer rapidly
if(LAZYLEN(candidates)) //if we got at least one candidate, they're a blobbernaut now.
B.max_integrity = initial(B.max_integrity) * 0.25 //factories that produced a blobbernaut have much lower health
B.obj_integrity = min(B.obj_integrity, B.max_integrity)
@@ -188,8 +191,8 @@
to_chat(blobber, "<b>You are a blobbernaut!</b>")
to_chat(blobber, "You are powerful, hard to kill, and slowly regenerate near nodes and cores, <span class='cultlarge'>but will slowly die if not near the blob</span> or if the factory that made you is killed.")
to_chat(blobber, "You can communicate with other blobbernauts and overminds via <b>:b</b>")
to_chat(blobber, "Your overmind's blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
to_chat(blobber, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]")
to_chat(blobber, "Your overmind's blob reagent is: <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font>!")
to_chat(blobber, "The <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font> reagent [blobstrain.shortdesc ? "[blobstrain.shortdesc]" : "[blobstrain.description]"]")
else
to_chat(src, "<span class='warning'>You could not conjure a sentience for your blobbernaut. Your points have been refunded. Try again later.</span>")
add_points(40)
@@ -244,8 +247,8 @@
/mob/camera/blob/verb/expand_blob_power()
set category = "Blob"
set name = "Expand/Attack Blob (4)"
set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects."
set name = "Expand/Attack Blob ([BLOB_SPREAD_COST])"
set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects and refunding [BLOB_ATTACK_REFUND] points."
var/turf/T = get_turf(src)
expand_blob(T)
@@ -258,23 +261,21 @@
if(!possibleblobs.len)
to_chat(src, "<span class='warning'>There is no blob adjacent to the target tile!</span>")
return
if(can_buy(4))
if(can_buy(BLOB_SPREAD_COST))
var/attacksuccess = FALSE
for(var/mob/living/L in T)
if(ROLE_BLOB in L.faction) //no friendly/dead fire
continue
if(L.stat != DEAD)
attacksuccess = TRUE
var/mob_protection = L.get_permeability_protection()
blob_reagent_datum.reaction_mob(L, VAPOR, 25, 1, mob_protection, src)
blob_reagent_datum.send_message(L)
blobstrain.attack_living(L)
var/obj/structure/blob/B = locate() in T
if(B)
if(attacksuccess) //if we successfully attacked a turf with a blob on it, don't refund shit
if(attacksuccess) //if we successfully attacked a turf with a blob on it, only give an attack refund
B.blob_attack_animation(T, src)
else
to_chat(src, "<span class='warning'>There is a blob there!</span>")
add_points(4) //otherwise, refund all of the cost
add_points(BLOB_SPREAD_COST) //otherwise, refund all of the cost
else
var/list/cardinalblobs = list()
var/list/diagonalblobs = list()
@@ -287,14 +288,15 @@
var/obj/structure/blob/OB
if(cardinalblobs.len)
OB = pick(cardinalblobs)
OB.expand(T, src)
if(!OB.expand(T, src))
add_points(BLOB_ATTACK_REFUND) //assume it's attacked SOMETHING, possibly a structure
else
OB = pick(diagonalblobs)
if(attacksuccess)
OB.blob_attack_animation(T, src)
playsound(OB, 'sound/effects/splat.ogg', 50, 1)
else
add_points(4) //if we're attacking diagonally and didn't hit anything, refund
add_points(BLOB_SPREAD_COST) //if we're attacking diagonally and didn't hit anything, refund
if(attacksuccess)
last_attack = world.time + CLICK_CD_MELEE
else
@@ -331,41 +333,38 @@
if(BM.stat == CONSCIOUS)
BM.say(speak_text)
/mob/camera/blob/verb/chemical_reroll()
/mob/camera/blob/verb/strain_reroll()
set category = "Blob"
set name = "Reactive Chemical Adaptation (40)"
set desc = "Replaces your chemical with a random, different one."
if(free_chem_rerolls || can_buy(40))
set_chemical()
if(free_chem_rerolls)
free_chem_rerolls--
set name = "Reactive Strain Adaptation (40)"
set desc = "Replaces your strain with a random, different one."
if(!rerolling && (free_strain_rerolls || can_buy(40)))
rerolling = TRUE
reroll_strain()
rerolling = FALSE
if(free_strain_rerolls)
free_strain_rerolls--
last_reroll_time = world.time
/mob/camera/blob/proc/set_chemical()
var/datum/reagent/blob/BC = pick((subtypesof(/datum/reagent/blob) - blob_reagent_datum.type))
blob_reagent_datum = new BC
color = blob_reagent_datum.complementary_color
for(var/BL in GLOB.blobs)
var/obj/structure/blob/B = BL
B.update_icon()
for(var/BLO in blob_mobs)
var/mob/living/simple_animal/hostile/blob/BM = BLO
BM.update_icons() //If it's getting a new chemical, tell it what it does!
to_chat(BM, "Your overmind's blob reagent is now: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
to_chat(BM, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]")
to_chat(src, "Your reagent is now: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
to_chat(src, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.description]")
if(blob_reagent_datum.effectdesc)
to_chat(src, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.effectdesc]")
/mob/camera/blob/proc/reroll_strain()
var/list/choices = list()
while (length(choices) < 4)
var/datum/blobstrain/bs = pick((GLOB.valid_blobstrains))
choices[initial(bs.name)] = bs
var/choice = input(usr, "Please choose a new strain","Strain") as anything in choices
if (choice && choices[choice] && !QDELETED(src))
var/datum/blobstrain/bs = choices[choice]
set_strain(bs)
/mob/camera/blob/verb/blob_help()
set category = "Blob"
set name = "*Blob Help*"
set desc = "Help on how to blob."
to_chat(src, "<b>As the overmind, you can control the blob!</b>")
to_chat(src, "Your blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
to_chat(src, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.description]")
if(blob_reagent_datum.effectdesc)
to_chat(src, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.effectdesc]")
to_chat(src, "Your blob reagent is: <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font>!")
to_chat(src, "The <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font> reagent [blobstrain.description]")
if(blobstrain.effectdesc)
to_chat(src, "The <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font> reagent [blobstrain.effectdesc]")
to_chat(src, "<b>You can expand, which will attack people, damage objects, or place a Normal Blob if the tile is clear.</b>")
to_chat(src, "<i>Normal Blobs</i> will expand your reach and can be upgraded into special blobs that perform certain functions.")
to_chat(src, "<b>You can upgrade normal blobs into the following types of blob:</b>")
+15 -21
View File
@@ -83,16 +83,10 @@
/obj/structure/blob/update_icon() //Updates color based on overmind color if we have an overmind.
if(overmind)
add_atom_colour(overmind.blob_reagent_datum.color, FIXED_COLOUR_PRIORITY)
add_atom_colour(overmind.blobstrain.color, FIXED_COLOUR_PRIORITY)
else
remove_atom_colour(FIXED_COLOUR_PRIORITY)
/obj/structure/blob/process()
Life()
/obj/structure/blob/proc/Life()
return
/obj/structure/blob/proc/Pulse_Area(mob/camera/blob/pulsing_overmind, claim_range = 10, pulse_range = 3, expand_range = 2)
if(QDELETED(pulsing_overmind))
pulsing_overmind = overmind
@@ -148,10 +142,10 @@
O.setDir(dir)
if(controller)
var/mob/camera/blob/BO = controller
O.color = BO.blob_reagent_datum.color
O.color = BO.blobstrain.color
O.alpha = 200
else if(overmind)
O.color = overmind.blob_reagent_datum.color
O.color = overmind.blobstrain.color
if(A)
O.do_attack_animation(A) //visually attack the whatever
return O //just in case you want to do something to the animation.
@@ -192,7 +186,7 @@
B.forceMove(T)
B.update_icon()
if(B.overmind && expand_reaction)
B.overmind.blob_reagent_datum.expand_reaction(src, B, T, controller)
B.overmind.blobstrain.expand_reaction(src, B, T, controller)
return B
else
blob_attack_animation(T, controller)
@@ -209,14 +203,14 @@
return
if(severity > 0)
if(overmind)
overmind.blob_reagent_datum.emp_reaction(src, severity)
overmind.blobstrain.emp_reaction(src, severity)
if(prob(100 - severity * 30))
new /obj/effect/temp_visual/emp(get_turf(src))
/obj/structure/blob/tesla_act(power)
..()
if(overmind)
if(overmind.blob_reagent_datum.tesla_reaction(src, power))
if(overmind.blobstrain.tesla_reaction(src, power))
take_damage(power/400, BURN, "energy")
else
take_damage(power/400, BURN, "energy")
@@ -224,7 +218,7 @@
/obj/structure/blob/extinguish()
..()
if(overmind)
overmind.blob_reagent_datum.extinguish_reaction(src)
overmind.blobstrain.extinguish_reaction(src)
/obj/structure/blob/hulk_damage()
return 15
@@ -243,13 +237,13 @@
else
return ..()
/obj/structure/blob/proc/chemeffectreport()
/obj/structure/blob/proc/chemeffectreport(mob/user)
RETURN_TYPE(/list)
. = list()
if(overmind)
. += "<b>Material: <font color=\"[overmind.blob_reagent_datum.color]\">[overmind.blob_reagent_datum.name]</font><span class='notice'>.</span></b>"
. += "<b>Material Effects:</b> <span class='notice'>[overmind.blob_reagent_datum.analyzerdescdamage]</span>"
. += "<b>Material Properties:</b> <span class='notice'>[overmind.blob_reagent_datum.analyzerdesceffect]</span><br>"
to_chat(user, "<b>Material: <font color=\"[overmind.blobstrain.color]\">[overmind.blobstrain.name]</font><span class='notice'>.</span></b>")
to_chat(user, "<b>Material Effects:</b> <span class='notice'>[overmind.blobstrain.analyzerdescdamage]</span>")
to_chat(user, "<b>Material Properties:</b> <span class='notice'>[overmind.blobstrain.analyzerdesceffect]</span><br>")
else
. += "<b>No Material Detected!</b><br>"
@@ -288,7 +282,7 @@
armor_protection = armor.getRating(damage_flag)
damage_amount = round(damage_amount * (100 - armor_protection)*0.01, 0.1)
if(overmind && damage_flag)
damage_amount = overmind.blob_reagent_datum.damage_reaction(src, damage_amount, damage_type, damage_flag)
damage_amount = overmind.blobstrain.damage_reaction(src, damage_amount, damage_type, damage_flag)
return damage_amount
/obj/structure/blob/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
@@ -298,7 +292,7 @@
/obj/structure/blob/obj_destruction(damage_flag)
if(overmind)
overmind.blob_reagent_datum.death_reaction(src, damage_flag)
overmind.blobstrain.death_reaction(src, damage_flag)
..()
/obj/structure/blob/proc/change_to(type, controller)
@@ -332,8 +326,8 @@
/obj/structure/blob/proc/get_chem_name()
if(overmind)
return overmind.blob_reagent_datum.name
return "an unknown variant"
return overmind.blobstrain.name
return "some kind of organic tissue"
/obj/structure/blob/normal
name = "normal blob"
@@ -27,7 +27,7 @@
INVOKE_ASYNC(B, /obj/effect/mine/pickup/bloodbath/.proc/mineEffect, H) //could use moving out from the mine
for(var/mob/living/carbon/human/P in GLOB.player_list)
if(P == H)
if(P == H || HAS_TRAIT(P, TRAIT_NO_MIDROUND_ANTAG))
continue
to_chat(P, "<span class='userdanger'>You have an overwhelming desire to kill [H]. [H.p_theyve(TRUE)] been marked red! Whoever [H.p_they()] [H.p_were()], friend or foe, go kill [H.p_them()]!</span>")
P.put_in_hands(new /obj/item/kitchen/knife/butcher(P), TRUE)
@@ -43,7 +43,7 @@
// EXPLANATION
/datum/objective/bloodsucker/lair/update_explanation_text()
explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift"// Make sure to keep it safe!"
explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift."// Make sure to keep it safe!"
// WIN CONDITIONS?
/datum/objective/bloodsucker/lair/check_completion()
@@ -228,7 +228,7 @@
if (SC && SC.lastgen > 0 && SC.connected_panels.len > 0 && SC.connected_tracker)
return FALSE
return TRUE
*/
*/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -250,15 +250,15 @@
// WIN CONDITIONS?
/datum/objective/bloodsucker/heartthief/check_completion()
// -Must have a body.
if (!owner.current)
if(!owner.current)
return FALSE
// Taken from /steal in objective.dm
var/list/all_items = owner.current.GetAllContents() // Includes items inside other items.
var/itemcount = FALSE
for(var/obj/I in all_items) //Check for items
if(I == /obj/item/organ/heart)
itemcount ++
if (itemcount >= target_amount) // Got the right amount?
if(istype(I, /obj/item/organ/heart/))
itemcount++
if(itemcount >= target_amount) // Got the right amount?
return TRUE
return FALSE
@@ -6,7 +6,7 @@
roundend_category = "bloodsuckers"
antagpanel_category = "Bloodsucker"
job_rank = ROLE_BLOODSUCKER
threat = 5
// NAME
var/vampname // My Dracula name
var/vamptitle // My Dracula title
@@ -91,10 +91,8 @@
// Refill with Blood
owner.current.blood_volume = max(owner.current.blood_volume,BLOOD_VOLUME_SAFE)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/antagonist/bloodsucker/threat()
return ..()+3*vamplevel
/datum/antagonist/bloodsucker/proc/SelectFirstName()
@@ -185,10 +183,10 @@
BuyPower(new /datum/action/bloodsucker/veil)
// Traits
for(var/T in defaultTraits)
ADD_TRAIT(owner.current, T, "bloodsucker")
ADD_TRAIT(owner.current, T, BLOODSUCKER_TRAIT)
if(HAS_TRAIT(owner.current, TRAIT_TOXINLOVER)) //No slime bonuses here, no thank you
had_toxlover = TRUE
REMOVE_TRAIT(owner.current, TRAIT_TOXINLOVER, "species")
REMOVE_TRAIT(owner.current, TRAIT_TOXINLOVER, SPECIES_TRAIT)
// Traits: Species
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
@@ -235,9 +233,9 @@
// owner.RemoveSpell(power)
// Traits
for(var/T in defaultTraits)
REMOVE_TRAIT(owner.current, T, "bloodsucker")
REMOVE_TRAIT(owner.current, T, BLOODSUCKER_TRAIT)
if(had_toxlover == TRUE)
ADD_TRAIT(owner.current, TRAIT_TOXINLOVER, "species")
ADD_TRAIT(owner.current, TRAIT_TOXINLOVER, SPECIES_TRAIT)
// Traits: Species
if(ishuman(owner.current))
@@ -387,7 +385,7 @@
add_objective(heartthief_objective)
/*
else
// Solars Objective, doesnt work due to TG updates.
var/datum/objective/bloodsucker/solars/solars_objective = new
solars_objective.owner = owner
@@ -13,7 +13,10 @@
var/list/datum/objective/objectives_given = list() // For removal if needed.
var/datum/martial_art/my_kungfu // Hunters know a lil kung fu.
var/bad_dude = FALSE // Every first hunter spawned is a SHIT LORD.
threat = -3
/datum/antagonist/vamphunter/threat()
return bad_dude ? -(..()) : ..()
/datum/antagonist/vamphunter/on_gain()
@@ -19,6 +19,7 @@
var/datum/antagonist/bloodsucker/master // Who made me?
var/list/datum/action/powers = list()// Purchased powers
var/list/datum/objective/objectives_given = list() // For removal if needed.
threat = 1
/datum/antagonist/vassal/can_be_owned(datum/mind/new_owner)
// If we weren't created by a bloodsucker, then we cannot be a vassal (assigned from antag panel)
@@ -90,6 +90,7 @@
user.dropItemToGround(src, TRUE) //user.drop_item() // "drop item" doesn't seem to exist anymore. New proc is user.dropItemToGround() but it doesn't seem like it's needed now?
var/obj/item/bodypart/B = C.get_bodypart("chest") // This was all taken from hitby() in human_defense.dm
B.embedded_objects |= src
embedded()
add_mob_blood(target)//Place blood on the stake
loc = C // Put INSIDE the character
B.receive_damage(w_class * embedding.embedded_impact_pain_multiplier)
@@ -258,7 +258,7 @@
/obj/structure/bloodsucker/vassalrack/proc/torture_victim(mob/living/user, mob/living/target)
var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
// Check Bloodmob/living/M, force = FALSE, check_loc = TRUE
var/convert_cost = 200 + 200 * bloodsuckerdatum.vassals
var/convert_cost = 200 + 200 * bloodsuckerdatum.vassals
if(user.blood_volume < convert_cost + 5)
to_chat(user, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target].</span>")
return
@@ -449,7 +449,7 @@
/obj/structure/bloodsucker/candelabrum/Destroy()
STOP_PROCESSING(SSobj, src)
/obj/structure/bloodsucker/candelabrum/update_icon()
/obj/structure/bloodsucker/candelabrum/update_icon_state()
icon_state = "candelabrum[lit ? "_lit" : ""]"
/obj/structure/bloodsucker/candelabrum/examine(mob/user)
@@ -59,7 +59,7 @@
var/do_knockdown = !is_A_facing_B(target,owner) || owner.alpha <= 0 || istype(owner.loc, /obj/structure/closet)
// CAUSES: Target has their back to me, I'm invisible, or I'm in a Closet
// Step One: Heatseek toward Target's Turf
addtimer(CALLBACK(owner, .proc/_walk, 0), 2 SECONDS)
addtimer(CALLBACK(GLOBAL_PROC, .proc/_walk, owner, 0), 2 SECONDS)
target.playsound_local(get_turf(owner), 'sound/bloodsucker/lunge_warn.ogg', 60, FALSE, pressure_affected = FALSE) // target-only telegraphing
owner.playsound_local(owner, 'sound/bloodsucker/lunge_warn.ogg', 60, FALSE, pressure_affected = FALSE) // audio feedback to the user
if(do_mob(owner, owner, 7, TRUE, TRUE))
@@ -64,7 +64,7 @@
to_chat(owner, "<span class='warning'>Your victim's eyes are glazed over. They cannot perceive you.</span>")
return FALSE
// Check: Target See Me? (behind wall)
if(!(target in view(target_range, get_turf(owner))))
if(!(target in viewers(target_range, get_turf(owner))))
// Sub-Check: GET CLOSER
//if (!(owner in range(target_range, get_turf(target)))
// if (display_error)
@@ -90,51 +90,56 @@
/datum/action/bloodsucker/targeted/mesmerize/proc/ContinueTarget(atom/A)
var/mob/living/carbon/target = A
var/mob/living/user = owner
var/mob/living/L = owner
var/cancontinue=CheckCanTarget(target)
var/cancontinue = CheckCanTarget(target)
if(!cancontinue)
success = FALSE
target.remove_status_effect(STATUS_EFFECT_MESMERIZE)
user.remove_status_effect(STATUS_EFFECT_MESMERIZE)
L.remove_status_effect(STATUS_EFFECT_MESMERIZE)
DeactivatePower()
DeactivateRangedAbility()
StartCooldown()
to_chat(user, "<span class='warning'>[target] has escaped your gaze!</span>")
to_chat(L, "<span class='warning'>[target] has escaped your gaze!</span>")
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
/datum/action/bloodsucker/targeted/mesmerize/FireTargetedPower(atom/A)
// set waitfor = FALSE <---- DONT DO THIS!We WANT this power to hold up ClickWithPower(), so that we can unlock the power when it's done.
var/mob/living/carbon/target = A
var/mob/living/user = owner
var/mob/living/L = owner
L.face_atom(A)
if(!istype(target))
return
success = TRUE
var/power_time = 138 + level_current * 12
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
L.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/ContinueTarget)
// 5 second windup
addtimer(CALLBACK(src, .proc/apply_effects, L, target, power_time), 6 SECONDS)
ADD_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src)
ADD_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src)
if(istype(target))
success = TRUE
var/power_time = 138 + level_current * 12
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
user.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/ContinueTarget)
/datum/action/bloodsucker/targeted/mesmerize/proc/apply_effects(aggressor, victim, power_time)
var/mob/living/carbon/target = victim
var/mob/living/L = aggressor
if(!success)
return
PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time)
REMOVE_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src)
target.face_atom(L)
target.Stun(power_time)
to_chat(L, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
target.next_move = world.time + power_time // <--- Use direct change instead. We want an unmodified delay to their next move // target.changeNext_move(power_time) // check click.dm
target.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
spawn(power_time)
if(istype(target) && success)
target.notransform = FALSE
REMOVE_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src)
if(istype(L) && target.stat == CONSCIOUS && (target in view(10, get_turf(L)))) // They Woke Up! (Notice if within view)
to_chat(L, "<span class='warning'>[target] has snapped out of their trance.</span>")
// 3 second windup
sleep(30)
if(success)
PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y
target.face_atom(user)
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time) // pretty much purely cosmetic
target.Stun(power_time)
to_chat(user, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
target.next_move = world.time + power_time // <--- Use direct change instead. We want an unmodified delay to their next move // target.changeNext_move(power_time) // check click.dm
target.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
spawn(power_time)
if(istype(target) && success)
target.notransform = FALSE
// They Woke Up! (Notice if within view)
if(istype(user) && target.stat == CONSCIOUS && (target in view(10, get_turf(user))) )
to_chat(user, "<span class='warning'>[target] has snapped out of their trance.</span>")
/datum/action/bloodsucker/targeted/mesmerize/ContinueActive(mob/living/user, mob/living/target)
return ..() && CheckCanUse() && CheckCanTarget(target)
@@ -92,10 +92,10 @@
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.features = random_features(H.dna.species?.id)
// Apply Appearance
H.update_body() // Outfit and underware, also body.
H.update_body(TRUE) // Outfit and underwear, also body and privates.
//H.update_mutant_bodyparts() // Lizard tails etc
H.update_hair()
H.update_body_parts()
@@ -140,7 +140,7 @@
ADD_TRAIT(H, TRAIT_DISFIGURED, "husk") // NOTE: We are ASSUMING husk. // H.status_flags |= DISFIGURED // Restore "Unknown" disfigurement
H.dna.features = prev_features
// Apply Appearance
H.update_body() // Outfit and underware, also body.
H.update_body(TRUE) // Outfit and underwear, also body and privates.
H.update_hair()
H.update_body_parts() // Body itself, maybe skin color?
cast_effect() // POOF
@@ -5,6 +5,7 @@
var/special_role = ROLE_BROTHER
var/datum/team/brother_team/team
antag_moodlet = /datum/mood_event/focused
threat = 3
/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
if(!new_team)
@@ -8,6 +8,7 @@
antagpanel_category = "Changeling"
job_rank = ROLE_CHANGELING
antag_moodlet = /datum/mood_event/focused
threat = 10
var/you_are_greet = TRUE
var/give_objectives = TRUE
@@ -30,6 +31,7 @@
var/isabsorbing = 0
var/islinking = 0
var/geneticpoints = 10
var/maxgeneticpoints = 10
var/purchasedpowers = list()
var/mimicing = ""
var/canrespec = 0
@@ -97,17 +99,24 @@
to_chat(H, "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself.")
H.dna.remove_mutation(CLOWNMUT)
/datum/antagonist/changeling/proc/reset_properties()
/datum/antagonist/changeling/proc/reset_properties(hardReset = FALSE)
changeling_speak = 0
chosen_sting = null
geneticpoints = initial(geneticpoints)
geneticpoints = maxgeneticpoints
sting_range = initial(sting_range)
chem_storage = initial(chem_storage)
chem_recharge_rate = initial(chem_recharge_rate)
chem_charges = min(chem_charges, chem_storage)
chem_recharge_slowdown = initial(chem_recharge_slowdown)
mimicing = ""
if (hardReset)
chem_storage = initial(chem_storage)
chem_recharge_rate = initial(chem_recharge_rate)
geneticpoints = initial(geneticpoints)
maxgeneticpoints = initial(maxgeneticpoints)
chem_charges = min(chem_charges, chem_storage)
/datum/antagonist/changeling/proc/remove_changeling_powers()
if(ishuman(owner.current) || ismonkey(owner.current))
reset_properties()
@@ -286,7 +295,6 @@
prof.name_list[slot] = I.name
prof.appearance_list[slot] = I.appearance
prof.flags_cover_list[slot] = I.flags_cover
prof.item_color_list[slot] = I.item_color
prof.item_state_list[slot] = I.item_state
prof.exists_list[slot] = 1
else
@@ -502,7 +510,6 @@
var/list/appearance_list = list()
var/list/flags_cover_list = list()
var/list/exists_list = list()
var/list/item_color_list = list()
var/list/item_state_list = list()
var/underwear
@@ -525,7 +532,6 @@
newprofile.appearance_list = appearance_list.Copy()
newprofile.flags_cover_list = flags_cover_list.Copy()
newprofile.exists_list = exists_list.Copy()
newprofile.item_color_list = item_color_list.Copy()
newprofile.item_state_list = item_state_list.Copy()
newprofile.underwear = underwear
newprofile.undershirt = undershirt
@@ -96,6 +96,7 @@
to_chat(user, "<span class='boldnotice'>[target] was one of us. We have absorbed their power.</span>")
target_ling.remove_changeling_powers()
changeling.geneticpoints += round(target_ling.geneticpoints/2)
changeling.maxgeneticpoints += round(target_ling.geneticpoints/2)
target_ling.geneticpoints = 0
target_ling.canrespec = 0
changeling.chem_storage += round(target_ling.chem_storage/2)
@@ -13,17 +13,14 @@
var/mob/living/carbon/human/H = user //SHOULD always be human, because req_human = 1
if(!istype(H)) // req_human could be done in can_sting stuff.
return
var/datum/mutation/human/HM = GLOB.mutations_list[CHAMELEON]
if(HM in H.dna.mutations)
HM.force_lose(H)
if(H.dna.get_mutation(CHAMELEON))
H.dna.remove_mutation(CHAMELEON)
else
HM.force_give(H)
H.dna.add_mutation(CHAMELEON)
return TRUE
/obj/effect/proc_holder/changeling/chameleon_skin/on_refund(mob/user)
action.Remove(user)
if(user.has_dna())
var/mob/living/carbon/C = user
var/datum/mutation/human/HM = GLOB.mutations_list[CHAMELEON]
if(HM in C.dna.mutations)
HM.force_lose(C)
C.dna.remove_mutation(CHAMELEON)
@@ -441,23 +441,23 @@
var/remaining_uses //Set by the changeling ability.
/obj/item/shield/changeling/Initialize()
/obj/item/shield/changeling/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
if(ismob(loc))
loc.visible_message("<span class='warning'>The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!</span>", "<span class='warning'>We inflate our hand into a strong shield.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
/obj/item/shield/changeling/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(remaining_uses < 1)
/obj/item/shield/changeling/check_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
block_return[BLOCK_RETURN_BLOCK_CAPACITY] = (block_return[BLOCK_RETURN_BLOCK_CAPACITY] || 0) + remaining_uses
return ..()
/obj/item/shield/changeling/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
. = ..()
if(--remaining_uses < 1)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
H.visible_message("<span class='warning'>With a sickening crunch, [H] reforms [H.p_their()] shield into an arm!</span>", "<span class='notice'>We assimilate our shield into our body</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
qdel(src)
return 0
else
remaining_uses--
return ..()
/***************************************\
|*********SPACE SUIT + HELMET***********|
@@ -251,6 +251,7 @@
return TRUE
/obj/effect/clockwork/sigil/transmission/update_icon()
. = ..()
var/power_charge = get_clockwork_power()
if(GLOB.ratvar_awakens)
alpha = 255
@@ -278,9 +279,15 @@
sigil_name = "Vitality Matrix"
var/revive_cost = 150
var/sigil_active = FALSE
var/min_drain_health = -INFINITY
var/can_dust = TRUE
var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets
var/static/list/damage_heal_order = list(CLONE, TOX, BURN, BRUTE, OXY) //we heal damage in this order
/obj/effect/clockwork/sigil/vitality/neutered
min_drain_health = 20
can_dust = FALSE
/obj/effect/clockwork/sigil/vitality/examine(mob/user)
. = ..()
if(is_servant_of_ratvar(user) || isobserver(user))
@@ -305,7 +312,7 @@
animation_number++
if(!is_servant_of_ratvar(L))
var/vitality_drained = 0
if(L.stat == DEAD && !consumed_vitality)
if(L.stat == DEAD && !consumed_vitality && can_dust)
consumed_vitality = TRUE //Prevent the target from being consumed multiple times
vitality_drained = L.maxHealth
var/obj/effect/temp_visual/ratvar/sigil/vitality/V = new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
@@ -317,7 +324,7 @@
if(!L.dropItemToGround(W))
qdel(W)
L.dust()
else
else if(L.health > min_drain_health)
if(!GLOB.ratvar_awakens && L.stat == CONSCIOUS)
vitality_drained = L.adjustToxLoss(1, forced = TRUE)
else
@@ -351,9 +358,9 @@
break
if(!L.client || L.client.is_afk())
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [L.name], an inactive clock cultist?", ROLE_SERVANT_OF_RATVAR, null, ROLE_SERVANT_OF_RATVAR, 50, L)
var/list/mob/candidates = pollCandidatesForMob("Do you want to play as a [L.name], an inactive clock cultist?", ROLE_SERVANT_OF_RATVAR, null, ROLE_SERVANT_OF_RATVAR, 50, L)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
var/mob/C = pick(candidates)
to_chat(L, "<span class='userdanger'>Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form!</span>")
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(L)]) to replace an inactive clock cultist.")
L.ghostize(0)
@@ -127,7 +127,6 @@
icon = 'icons/obj/clothing/clockwork_garb.dmi'
icon_state = "clockwork_gauntlets"
item_state = "clockwork_gauntlets"
item_color = null //So they don't wash.
strip_delay = 50
equip_delay_other = 30
body_parts_covered = ARMS
@@ -36,6 +36,24 @@
speed_multiplier = 0
no_cost = TRUE
/obj/item/clockwork/slab/traitor
var/spent = FALSE
/obj/item/clockwork/slab/traitor/check_uplink_validity()
return !spent
/obj/item/clockwork/slab/traitor/attack_self(mob/living/user)
if(!is_servant_of_ratvar(user) && !spent)
to_chat(user, "<span class='userdanger'>You press your hand onto [src], golden tendrils of light latching onto you. Was this the best of ideas?</span>")
if(add_servant_of_ratvar(user, FALSE, FALSE, /datum/antagonist/clockcult/neutered/traitor))
spent = TRUE
// Add some (5 KW) power so they don't suffer for 100 ticks
GLOB.clockwork_power += 5000
// This intentionally does not use adjust_clockwork_power.
else
to_chat(user, "<span class='userdanger'>[src] falls dark. It appears you weren't worthy.</span>")
return ..()
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/clockwork/slab/debug/attack_hand(mob/living/user)
if(!is_servant_of_ratvar(user))
@@ -6,6 +6,7 @@
unique_name = 1
minbodytemp = 0
unsuitable_atmos_damage = 0
threat = 1
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) //Robotic
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
healable = FALSE
@@ -37,7 +38,7 @@
/mob/living/simple_animal/hostile/clockwork/ratvar_act()
fully_heal(TRUE)
/mob/living/simple_animal/hostile/clockwork/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
/mob/living/simple_animal/hostile/clockwork/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
return 0 //ouch, my metal-unlikely-to-be-damaged-by-electricity-body
/mob/living/simple_animal/hostile/clockwork/examine(mob/user)
@@ -9,6 +9,7 @@
desc = "The stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield."
icon_state = "clockwork_marauder"
mob_biotypes = MOB_HUMANOID
threat = 3
health = 120
maxHealth = 120
force_threshold = 8
@@ -30,6 +30,7 @@ Applications: 8 servants, 3 caches, and 100 CV
var/primary_component
var/important = FALSE //important scripture will be italicized in the slab's interface
var/sort_priority = 1 //what position the scripture should have in a list of scripture. Should be based off of component costs/reqs, but you can't initial() lists.
var/requires_full_power = FALSE //requires the user to be a full, non neutered servant of ratvar
//messages for offstation scripture recital, courtesy ratvar's generals(and neovgre)
var/static/list/neovgre_penalty = list("Go to the station.", "Useless.", "Don't waste time.", "Pathetic.", "Wasteful.")
@@ -77,6 +78,9 @@ Applications: 8 servants, 3 caches, and 100 CV
/datum/clockwork_scripture/proc/can_recite() //If the words can be spoken
if(!invoker || !slab || invoker.get_active_held_item() != slab)
return FALSE
if(!is_servant_of_ratvar(invoker, requires_full_power))
to_chat(invoker, "<span class='warning'>You aren't strongly connected enough to Ratvar to invoke this!</span>")
return FALSE
if(!invoker.can_speak_vocal())
to_chat(invoker, "<span class='warning'>You are unable to speak the words of the scripture!</span>")
return FALSE
@@ -236,18 +240,21 @@ Applications: 8 servants, 3 caches, and 100 CV
return FALSE
return TRUE
/datum/clockwork_scripture/create_object/proc/get_spawn_path(mob/user)
return object_path
/datum/clockwork_scripture/create_object/scripture_effects()
if(creator_message && observer_message)
invoker.visible_message(observer_message, creator_message)
else if(creator_message)
to_chat(invoker, creator_message)
var/obj/O = new object_path (get_turf(invoker))
var/to_spawn = get_spawn_path(invoker)
var/obj/O = new to_spawn(get_turf(invoker))
O.ratvar_act() //update the new object so it gets buffed if ratvar is alive
if(isitem(O) && put_object_in_hands)
invoker.put_in_hands(O)
return TRUE
//Used specifically to create construct shells.
/datum/clockwork_scripture/create_object/construct
put_object_in_hands = FALSE
@@ -88,7 +88,7 @@
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Submission, which will convert non-Servants that remain on it."
requires_full_power = TRUE
//Kindle: Charges the slab with blazing energy. It can be released to stun and silence a target.
/datum/clockwork_scripture/ranged_ability/kindle
@@ -138,11 +138,11 @@
quickbind_desc = "Applies handcuffs to a struck target."
//Vanguard: Provides twenty seconds of greatly increased stamina and stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker.
//Vanguard: Provides twenty seconds of greatly increased stamina regeneration and stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed aswell as 50% of healed stamloss are applied to the invoker.
/datum/clockwork_scripture/vanguard
descname = "Self Stun Immunity"
name = "Vanguard"
desc = "Provides twenty seconds of greatly increased stamina and stun immunity. At the end of the twenty seconds, the invoker is knocked down for the equivalent of 25% of all stuns they absorbed. \
desc = "Provides twenty seconds of greatly increased stamina regeneration and stun immunity. At the end of the twenty seconds, the invoker is knocked down for the equivalent of 25% of all stuns they absorbed aswell as incurring 50% of the stamina regenerated as stamina loss \
Excessive absorption will cause unconsciousness."
invocations = list("Shield me...", "...from darkness!")
channel_time = 30
@@ -152,7 +152,7 @@
primary_component = VANGUARD_COGWHEEL
sort_priority = 7
quickbind = TRUE
quickbind_desc = "Allows you to temporarily have quickly regenerating stamina and absorb stuns. All stuns absorbed will affect you when disabled."
quickbind_desc = "Allows you to temporarily have quickly regenerating stamina and absorb stuns. Part of the stuns absorbed and staminaloss healed will affect you when disabled."
/datum/clockwork_scripture/vanguard/check_special_requirements()
if(!GLOB.ratvar_awakens && islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time)
@@ -211,6 +211,7 @@
quickbind = TRUE
quickbind_desc = "Returns you to Reebe."
var/client_color
requires_full_power = TRUE
/datum/clockwork_scripture/abscond/check_special_requirements()
if(is_reebe(invoker.z))
@@ -50,7 +50,6 @@
return FALSE
return ..()
//Vitality Matrix: Creates a sigil which will drain health from nonservants and can use that health to heal or even revive servants.
/datum/clockwork_scripture/create_object/vitality_matrix
descname = "Trap, Damage to Healing"
@@ -77,6 +76,10 @@
return FALSE
return ..()
/datum/clockwork_scripture/create_object/vitality_matrix/get_spawn_path(mob/user)
if(!is_servant_of_ratvar(user, TRUE))
return /obj/effect/clockwork/sigil/vitality/neutered
return ..()
//Judicial Visor: Creates a judicial visor, which can smite an area.
/datum/clockwork_scripture/create_object/judicial_visor
@@ -5,14 +5,27 @@
antagpanel_category = "Clockcult"
job_rank = ROLE_SERVANT_OF_RATVAR
antag_moodlet = /datum/mood_event/cult
var/datum/action/innate/hierophant/hierophant_network = new()
var/datum/action/innate/hierophant/hierophant_network = new
threat = 3
var/datum/team/clockcult/clock_team
var/make_team = TRUE //This should be only false for tutorial scarabs
var/neutered = FALSE //can not use round ending, gibbing, converting, or similar things with unmatched round impact
var/ignore_eligibility_check = FALSE
var/ignore_holy_water = FALSE
/datum/antagonist/clockcult/silent
silent = TRUE
show_in_antagpanel = FALSE //internal
/datum/antagonist/clockcult/neutered
neutered = TRUE
/datum/antagonist/clockcult/neutered/traitor
ignore_eligibility_check = TRUE
ignore_holy_water = TRUE
show_in_roundend = FALSE
make_team = FALSE
/datum/antagonist/clockcult/Destroy()
qdel(hierophant_network)
return ..()
@@ -37,7 +50,7 @@
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
if(. && !ignore_eligibility_check)
. = is_eligible_servant(new_owner.current)
/datum/antagonist/clockcult/greet()
+10 -3
View File
@@ -439,7 +439,7 @@
"<span class='userdanger'>A feeling of warmth washes over you, rays of holy light surround your body and protect you from the flash of light!</span>")
else // cult doesn't stun any longer when halos are out, instead it does burn damage + knockback!
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(user_antag.cult_team.cult_ascendent)
if(user_antag.cult_team?.cult_ascendent)
if(!iscultist(L))
L.adjustFireLoss(20)
if(L.move_resist < MOVE_FORCE_STRONG)
@@ -577,7 +577,9 @@
var/turf/T = get_turf(target)
if(istype(target, /obj/item/stack/sheet/metal))
var/obj/item/stack/sheet/candidate = target
if(candidate.use(50))
if(!iscultist(user, TRUE))
to_chat(user, "<span class='warning'>You are not strongly connected enough to Nar'sie to use make constructs...</span>")
else if(candidate.use(50))
uses--
to_chat(user, "<span class='warning'>A dark cloud emanates from your hand and swirls around the metal, twisting it into a construct shell!</span>")
new /obj/structure/constructshell(T)
@@ -600,7 +602,9 @@
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else if(istype(target,/mob/living/silicon/robot))
var/mob/living/silicon/robot/candidate = target
if(candidate.mmi)
if(!iscultist(user, TRUE))
to_chat(user, "<span class='warning'>You are not strongly connected enough to Nar'sie to use make constructs...</span>")
else if(candidate.mmi)
user.visible_message("<span class='danger'>A dark cloud emanates from [user]'s hand and swirls around [candidate]!</span>")
playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
var/prev_color = candidate.color
@@ -656,6 +660,7 @@
C.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), SLOT_WEAR_SUIT)
C.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), SLOT_SHOES)
C.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), SLOT_BACK)
C.equip_to_slot_or_del(new /obj/item/clothing/gloves/fingerless/pugilist/hungryghost(user), SLOT_GLOVES)
if(C == user)
qdel(src) //Clears the hands
C.put_in_hands(new /obj/item/melee/cultblade(user))
@@ -819,6 +824,8 @@
if("Blood Beam (500)")
if(uses < 500)
to_chat(user, "<span class='cultitalic'>You need 500 charges to perform this rite.</span>")
else if(!iscultist(user, TRUE))
to_chat(user, "<span class='warning'>You are not strongly connected to Nar'sie enough to use something of this power.</span>")
else
var/obj/rite = new /obj/item/blood_beam()
uses -= 500
+22 -9
View File
@@ -5,20 +5,33 @@
roundend_category = "cultists"
antagpanel_category = "Cult"
antag_moodlet = /datum/mood_event/cult
threat = 3
var/datum/action/innate/cult/comm/communion = new
var/datum/action/innate/cult/mastervote/vote = new
var/datum/action/innate/cult/blood_magic/magic = new
job_rank = ROLE_CULTIST
var/ignore_implant = FALSE
var/make_team = TRUE
var/give_equipment = FALSE
var/datum/team/cult/cult_team
var/neutered = FALSE //can not use round ending, gibbing, converting, or similar things with unmatched round impact
var/ignore_eligibility_checks = FALSE
var/ignore_holy_water = FALSE
/datum/antagonist/cult/neutered
neutered = TRUE
/datum/antagonist/cult/neutered/traitor
ignore_eligibility_checks = TRUE
ignore_holy_water = TRUE
show_in_roundend = FALSE
make_team = FALSE
/datum/antagonist/cult/get_team()
return cult_team
/datum/antagonist/cult/create_team(datum/team/cult/new_team)
if(!new_team)
if(!new_team && make_team)
//todo remove this and allow admin buttons to create more than one cult
for(var/datum/antagonist/cult/H in GLOB.antagonists)
if(!H.owner)
@@ -29,12 +42,12 @@
cult_team = new /datum/team/cult
cult_team.setup_objectives()
return
if(!istype(new_team))
if(make_team && !istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
cult_team = new_team
/datum/antagonist/cult/proc/add_objectives()
objectives |= cult_team.objectives
objectives |= cult_team?.objectives
/datum/antagonist/cult/Destroy()
QDEL_NULL(communion)
@@ -43,7 +56,7 @@
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
. = ..()
if(. && !ignore_implant)
if(. && !ignore_implant && !ignore_eligibility_checks)
. = is_convertable_to_cult(new_owner.current,cult_team)
/datum/antagonist/cult/greet()
@@ -61,7 +74,7 @@
SSticker.mode.update_cult_icons_added(owner)
current.log_message("has been converted to the cult of Nar'Sie!", LOG_ATTACK, color="#960000")
if(cult_team.blood_target && cult_team.blood_target_image && current.client)
if(cult_team?.blood_target && cult_team.blood_target_image && current.client)
current.client.images += cult_team.blood_target_image
@@ -104,13 +117,13 @@
current = mob_override
current.faction |= "cult"
current.grant_language(/datum/language/narsie)
if(!cult_team.cult_master)
if(!cult_team?.cult_master)
vote.Grant(current)
communion.Grant(current)
if(ishuman(current))
magic.Grant(current)
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
if(cult_team.cult_risen)
if(cult_team?.cult_risen)
cult_team.rise(current)
if(cult_team.cult_ascendent)
cult_team.ascend(current)
@@ -143,7 +156,7 @@
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_theyve()] just reverted to [owner.current.p_their()] old faith!</span>", null, null, null, owner.current)
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
owner.current.log_message("has renounced the cult of Nar'Sie!", LOG_ATTACK, color="#960000")
if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
if(cult_team?.blood_target && cult_team.blood_target_image && owner.current.client)
owner.current.client.images -= cult_team.blood_target_image
. = ..()
@@ -205,7 +218,7 @@
throwing.Grant(current)
current.update_action_buttons_icon()
current.apply_status_effect(/datum/status_effect/cult_master)
if(cult_team.cult_risen)
if(cult_team?.cult_risen)
cult_team.rise(current)
if(cult_team.cult_ascendent)
cult_team.ascend(current)
+16 -4
View File
@@ -74,7 +74,7 @@
/datum/action/innate/cult/mastervote/IsAvailable()
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C || C.cult_team.cult_vote_called || !ishuman(owner))
if(!C?.cult_team || C.cult_team.cult_vote_called || !ishuman(owner))
return FALSE
return ..()
@@ -82,6 +82,9 @@
var/choice = alert(owner, "The mantle of leadership is heavy. Success in this role requires an expert level of communication and experience. Are you sure?",, "Yes", "No")
if(choice == "Yes" && IsAvailable())
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C.cult_team)
to_chat(owner, "<span class='cult bold'>Do you not alreaady lead yourself?</span>")
return
pollCultists(owner,C.cult_team)
/proc/pollCultists(var/mob/living/Nominee,datum/team/cult/team) //Cult Master Poll
@@ -151,6 +154,9 @@
var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!antag)
return
if(!antag.cult_team)
to_chat(owner, "<span class='cult bold'>You have no team. You are alone.</span>")
return
for(var/i in 1 to 4)
chant(i)
var/list/destinations = list()
@@ -261,7 +267,10 @@
return FALSE
var/datum/antagonist/cult/C = caller.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C.cult_team)
to_chat(ranged_ability_user, "<span class='cultlarge'>What is the point of marking a target for yourself?</span>")
remove_ranged_ability()
return
if(target in view(7, get_turf(ranged_ability_user)))
if(C.cult_team.blood_target)
to_chat(ranged_ability_user, "<span class='cult'>The cult has already designated a target!</span>")
@@ -330,8 +339,11 @@
/datum/action/innate/cult/ghostmark/Activate()
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C.cult_team)
to_chat(owner, "<span class='cultbold'>You are alone. You do not have a team.</span>")
return
if(C.cult_team.blood_target)
if(cooldown>world.time)
if(cooldown > world.time)
reset_blood_target(C.cult_team)
to_chat(owner, "<span class='cultbold'>You have cleared the cult's blood target!</span>")
deltimer(C.cult_team.blood_target_reset_timer)
@@ -339,7 +351,7 @@
else
to_chat(owner, "<span class='cultbold'>The cult has already designated a target!</span>")
return
if(cooldown>world.time)
if(cooldown > world.time)
to_chat(owner, "<span class='cultbold'>You aren't ready to place another blood mark yet!</span>")
return
target = owner.orbiting?.parent || get_turf(owner)
+64 -37
View File
@@ -6,6 +6,21 @@
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
/obj/item/tome/traitor
var/spent = FALSE
/obj/item/tome/traitor/check_uplink_validity()
return !spent
/obj/item/tome/traitor/attack_self(mob/living/user)
if(!iscultist(user) && !spent)
to_chat(user, "<span class='userdanger'>You press your hand onto [src], sinister tendrils of corrupted magic swirling around you. Was this the best of ideas?</span>")
if(user.mind.add_antag_datum(/datum/antagonist/cult/neutered/traitor))
spent = TRUE
else
to_chat(user, "<span class='userdanger'>[src] falls dark. It appears you weren't worthy.</span>")
return ..()
/obj/item/melee/cultblade/dagger
name = "ritual dagger"
desc = "A strange dagger said to be used by sinister groups for \"preparing\" a corpse before sacrificing it to their dark gods."
@@ -162,24 +177,20 @@
jaunt.Remove(user)
user.update_icons()
/obj/item/twohanded/required/cult_bastard/IsReflect()
if(spinning)
/obj/item/twohanded/required/cult_bastard/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(spinning && is_energy_reflectable_projectile(object) && (attack_type & ATTACK_TYPE_PROJECTILE))
playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, 1)
return TRUE
else
..()
/obj/item/twohanded/required/cult_bastard/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL | BLOCK_REDIRECTED | BLOCK_SHOULD_REDIRECT
if(prob(final_block_chance))
if(attack_type == PROJECTILE_ATTACK)
if(attack_type & ATTACK_TYPE_PROJECTILE)
owner.visible_message("<span class='danger'>[owner] deflects [attack_text] with [src]!</span>")
playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, 1)
return TRUE
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL | BLOCK_REDIRECTED | BLOCK_SHOULD_REDIRECT
else
playsound(src, 'sound/weapons/parry.ogg', 75, 1)
owner.visible_message("<span class='danger'>[owner] parries [attack_text] with [src]!</span>")
return TRUE
return FALSE
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL
return BLOCK_NONE
/obj/item/twohanded/required/cult_bastard/afterattack(atom/target, mob/user, proximity, click_parameters)
. = ..()
@@ -264,7 +275,7 @@
/obj/item/restraints/legcuffs/bola/cult/pickup(mob/living/user)
if(!iscultist(user))
to_chat(user, "<span class='warning'>The bola seems to take on a life of its own!</span>")
throw_impact(user)
ensnare(user)
/obj/item/restraints/legcuffs/bola/cult/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(iscultist(hit_atom))
@@ -353,6 +364,11 @@
brightness_on = 0
actions_types = list()
/obj/item/clothing/head/helmet/space/hardsuit/cult/ComponentInitialize()
. = ..()
AddElement(/datum/element/spellcasting, SPELL_CULT_HELMET, ITEM_SLOT_HEAD)
/obj/item/clothing/suit/space/hardsuit/cult
name = "\improper Nar'Sien hardened armor"
icon_state = "cult_armor"
@@ -363,6 +379,10 @@
armor = list("melee" = 70, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 40, "acid" = 75)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/cult
/obj/item/clothing/suit/space/hardsuit/cult/ComponentInitialize()
. = ..()
AddElement(/datum/element/spellcasting, SPELL_CULT_ARMOR, ITEM_SLOT_OCLOTHING)
/obj/item/sharpener/cult
name = "eldritch whetstone"
desc = "A block, empowered by dark magic. Sharp weapons will be enhanced when used on the stone."
@@ -372,7 +392,7 @@
max = 40
prefix = "darkened"
/obj/item/sharpener/cult/update_icon()
/obj/item/sharpener/cult/update_icon_state()
var/old_state = icon_state
icon_state = "cult_sharpener[used ? "_used" : ""]"
if(old_state != icon_state)
@@ -414,7 +434,13 @@
user.adjustBruteLoss(25)
user.dropItemToGround(src, TRUE)
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/check_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(current_charges)
block_return[BLOCK_RETURN_NORMAL_BLOCK_CHANCE] = 100
block_return[BLOCK_RETURN_BLOCK_CAPACITY] = (block_return[BLOCK_RETURN_BLOCK_CAPACITY] || 0) + current_charges
return ..()
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(current_charges)
owner.visible_message("<span class='danger'>\The [attack_text] is deflected in a burst of blood-red sparks!</span>")
current_charges--
@@ -422,8 +448,8 @@
if(!current_charges)
owner.visible_message("<span class='danger'>The runed shield around [owner] suddenly disappears!</span>")
owner.update_inv_wear_suit()
return 1
return 0
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL
return BLOCK_NONE
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE)
. = list()
@@ -498,7 +524,7 @@
var/static/curselimit = 0
/obj/item/shuttle_curse/attack_self(mob/living/user)
if(!iscultist(user))
if(!iscultist(user, TRUE))
user.dropItemToGround(src, TRUE)
user.DefaultCombatKnockdown(100)
to_chat(user, "<span class='warning'>A powerful force shoves you away from [src]!</span>")
@@ -688,7 +714,7 @@
qdel(spear_act)
..()
/obj/item/twohanded/cult_spear/update_icon()
/obj/item/twohanded/cult_spear/update_icon_state()
icon_state = "bloodspear[wielded]"
/obj/item/twohanded/cult_spear/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
@@ -725,19 +751,19 @@
playsound(T, 'sound/effects/glassbr3.ogg', 100)
qdel(src)
/obj/item/twohanded/cult_spear/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
/obj/item/twohanded/cult_spear/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(wielded)
final_block_chance *= 2
if(prob(final_block_chance))
if(attack_type == PROJECTILE_ATTACK)
if(attack_type & ATTACK_TYPE_PROJECTILE)
owner.visible_message("<span class='danger'>[owner] deflects [attack_text] with [src]!</span>")
playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, 1)
return TRUE
return BLOCK_SUCCESS | BLOCK_SHOULD_REDIRECT | BLOCK_REDIRECTED | BLOCK_PHYSICAL_EXTERNAL
else
playsound(src, 'sound/weapons/parry.ogg', 100, 1)
owner.visible_message("<span class='danger'>[owner] parries [attack_text] with [src]!</span>")
return TRUE
return FALSE
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL
return BLOCK_NONE
/datum/action/innate/cult/spear
name = "Bloody Bond"
@@ -936,10 +962,18 @@
hitsound = 'sound/weapons/smash.ogg'
var/illusions = 2
/obj/item/shield/mirror/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
/obj/item/shield/mirror/check_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
block_return[BLOCK_RETURN_REFLECT_PROJECTILE_CHANCE] = max(block_return[BLOCK_RETURN_REFLECT_PROJECTILE_CHANCE] || null, final_block_chance)
return ..()
/obj/item/shield/mirror/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(iscultist(owner))
if(istype(hitby, /obj/item/projectile))
var/obj/item/projectile/P = hitby
if(istype(object, /obj/item/projectile) && (attack_type == ATTACK_TYPE_PROJECTILE))
if(is_energy_reflectable_projectile(object))
if(prob(final_block_chance))
return BLOCK_SUCCESS | BLOCK_SHOULD_REDIRECT | BLOCK_PHYSICAL_EXTERNAL | BLOCK_REDIRECTED
return BLOCK_NONE //To avoid reflection chance double-dipping with block chance
var/obj/item/projectile/P = object
if(P.damage >= 30)
var/turf/T = get_turf(owner)
T.visible_message("<span class='warning'>The sheer force from [P] shatters the mirror shield!</span>")
@@ -947,11 +981,9 @@
playsound(T, 'sound/effects/glassbr3.ogg', 100)
owner.DefaultCombatKnockdown(25)
qdel(src)
return FALSE
if(P.is_reflectable)
return FALSE //To avoid reflection chance double-dipping with block chance
return BLOCK_NONE
. = ..()
if(.)
if(. & BLOCK_SUCCESS)
playsound(src, 'sound/weapons/parry.ogg', 100, 1)
if(illusions > 0)
illusions--
@@ -966,7 +998,7 @@
E.Copy_Parent(owner, 70, 10)
E.GiveTarget(owner)
E.Goto(owner, owner.movement_delay(), E.minimum_distance)
return TRUE
return
else
if(prob(50))
var/mob/living/simple_animal/hostile/illusion/H = new(owner.loc)
@@ -975,7 +1007,7 @@
H.GiveTarget(owner)
H.move_to_delay = owner.movement_delay()
to_chat(owner, "<span class='danger'><b>[src] betrays you!</b></span>")
return FALSE
return BLOCK_NONE
/obj/item/shield/mirror/proc/readd()
illusions++
@@ -983,11 +1015,6 @@
var/mob/living/holder = loc
to_chat(holder, "<span class='cult italic'>The shield's illusions are back at full strength!</span>")
/obj/item/shield/mirror/IsReflect()
if(prob(block_chance))
return TRUE
return FALSE
/obj/item/shield/mirror/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
var/turf/T = get_turf(hit_atom)
var/datum/thrownthing/D = throwingdatum
+5 -2
View File
@@ -59,6 +59,9 @@ This file contains the cult dagger and rune list code
rune_to_scribe = GLOB.rune_types[entered_rune_name]
if(!rune_to_scribe)
return
if(!iscultist(user, initial(rune_to_scribe.requires_full_power)))
to_chat(user, "<span class='warning'>You aren't strongly connected enough to Nar'sie to do draw this.</span>")
return
if(initial(rune_to_scribe.req_keyword))
chosen_keyword = stripped_input(user, "Enter a keyword for the new rune.", "Words of Power")
if(!chosen_keyword)
@@ -84,8 +87,8 @@ This file contains the cult dagger and rune list code
to_chat(user, "<span class='cultlarge'>Only one ritual site remains - it must be reserved for the final summoning!</span>")
return
if(ispath(rune_to_scribe, /obj/effect/rune/narsie))
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team?.objectives
var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team?.objectives
if(!summon_objective)
to_chat(user, "<span class='warning'>Nar'Sie does not wish to be summoned!</span>")
return
+13 -2
View File
@@ -32,6 +32,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
var/scribe_delay = 40 //how long the rune takes to create
var/scribe_damage = 0.1 //how much damage you take doing it
var/requires_full_power = FALSE //requires full power to draw or invoke
var/invoke_damage = 0 //how much damage invokers take when invoking it
var/construct_invoke = TRUE //if constructs can invoke it
@@ -185,6 +186,7 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_OFFER
req_cultists = 1
rune_in_use = FALSE
requires_full_power = TRUE
/obj/effect/rune/convert/do_invoke_glow()
return
@@ -458,6 +460,7 @@ structure_check() searches for nearby cultist structures required for the invoca
pixel_y = -32
scribe_delay = 500 //how long the rune takes to create
scribe_damage = 40.1 //how much damage you take doing it
requires_full_power = TRUE
var/used = FALSE
/obj/effect/rune/narsie/Initialize(mapload, set_keyword)
@@ -482,6 +485,9 @@ structure_check() searches for nearby cultist structures required for the invoca
fail_invoke()
return
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!user_antag.cult_team)
to_chat(user, "<span class='cultlarge'>You can't seem to make the arcane links to your fellows that you'd need to use this.</span>")
return
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
var/area/place = get_area(src)
if(!(place in summon_objective.summon_spots))
@@ -569,9 +575,9 @@ structure_check() searches for nearby cultist structures required for the invoca
mob_to_revive.grab_ghost()
if(!mob_to_revive.client || mob_to_revive.client.is_afk())
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.name], an inactive blood cultist?", ROLE_CULTIST, null, ROLE_CULTIST, 50, mob_to_revive)
var/list/mob/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.name], an inactive blood cultist?", ROLE_CULTIST, null, ROLE_CULTIST, 50, mob_to_revive)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
var/mob/C = pick(candidates)
to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.")
mob_to_revive.ghostize(0)
@@ -812,6 +818,7 @@ structure_check() searches for nearby cultist structures required for the invoca
invoke_damage = 10
construct_invoke = FALSE
color = RUNE_COLOR_DARKRED
requires_full_power = TRUE
var/mob/living/affecting = null
var/ghost_limit = 3
var/ghosts = 0
@@ -942,6 +949,7 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_DARKRED
req_cultists = 3
scribe_delay = 100
requires_full_power = TRUE
/obj/effect/rune/apocalypse/invoke(var/list/invokers)
if(rune_in_use)
@@ -950,6 +958,9 @@ structure_check() searches for nearby cultist structures required for the invoca
var/area/place = get_area(src)
var/mob/living/user = invokers[1]
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!user_antag.cult_team)
to_chat(user, "<span class='cultlarge'>You can't seem to make the arcane links to your fellows that you'd need to use this.</span>")
return
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
if(summon_objective.summon_spots.len <= 1)
to_chat(user, "<span class='cultlarge'>Only one ritual site remains - it must be reserved for the final summoning!</span>")
+9 -6
View File
@@ -91,6 +91,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
job_rank = ROLE_DEVIL
//Don't delete upon mind destruction, otherwise soul re-selling will break.
delete_on_mind_deletion = FALSE
threat = 5
var/obligation
var/ban
var/bane
@@ -112,6 +113,9 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
/obj/effect/proc_holder/spell/targeted/summon_dancefloor))
var/ascendable = FALSE
/datum/antagonist/devil/threat()
return ..() + form * 10
/datum/antagonist/devil/can_be_owned(datum/mind/new_owner)
. = ..()
return . && (ishuman(new_owner.current) || iscyborg(new_owner.current))
@@ -120,7 +124,6 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
. = ..()
.["Toggle ascendable"] = CALLBACK(src,.proc/admin_toggle_ascendable)
/datum/antagonist/devil/proc/admin_toggle_ascendable(mob/admin)
ascendable = !ascendable
message_admins("[key_name_admin(admin)] set [owner.current] devil ascendable to [ascendable]")
@@ -244,7 +247,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
H.undershirt = "Nude"
H.socks = "Nude"
H.dna.features["mcolor"] = "511" //A deep red
H.regenerate_icons()
H.update_body(TRUE)
else //Did the devil get hit by a staff of transmutation?
owner.current.color = "#501010"
give_appropriate_spells()
@@ -414,11 +417,11 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
if(BANISH_FUNERAL_GARB)
if(ishuman(body))
var/mob/living/carbon/human/H = body
if(H.w_uniform && istype(H.w_uniform, /obj/item/clothing/under/burial))
if(H.w_uniform && istype(H.w_uniform, /obj/item/clothing/under/misc/burial))
return 1
return 0
else
for(var/obj/item/clothing/under/burial/B in range(0,body))
for(var/obj/item/clothing/under/misc/burial/B in range(0,body))
if(B.loc == get_turf(B)) //Make sure it's not in someone's inventory or something.
return 1
return 0
@@ -456,7 +459,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
return -1
currentMob.change_mob_type( /mob/living/carbon/human, targetturf, null, 1)
var/mob/living/carbon/human/H = owner.current
H.equip_to_slot_or_del(new /obj/item/clothing/under/lawyer/black(H), SLOT_W_UNIFORM)
H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/civilian/lawyer/black(H), SLOT_W_UNIFORM)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), SLOT_SHOES)
H.equip_to_slot_or_del(new /obj/item/storage/briefcase(H), SLOT_HANDS)
H.equip_to_slot_or_del(new /obj/item/pen(H), SLOT_L_STORE)
@@ -466,7 +469,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
H.undershirt = "Nude"
H.socks = "Nude"
H.dna.features["mcolor"] = "511"
H.regenerate_icons()
H.update_body(TRUE)
if(SOULVALUE >= TRUE_THRESHOLD) //Yes, BOTH this and the above if statement are to run if soulpower is high enough.
var/mob/living/carbon/true_devil/A = new /mob/living/carbon/true_devil(targetturf)
A.faction |= "hell"
+13 -13
View File
@@ -8,19 +8,19 @@
var/obj/item/clothing/under/U = H.w_uniform
var/static/list/whiteness = list (
/obj/item/clothing/under/color/white = 2,
/obj/item/clothing/under/rank/bartender = 1,
/obj/item/clothing/under/rank/chef = 1,
/obj/item/clothing/under/rank/chief_engineer = 1,
/obj/item/clothing/under/rank/scientist = 1,
/obj/item/clothing/under/rank/chemist = 1,
/obj/item/clothing/under/rank/chief_medical_officer = 1,
/obj/item/clothing/under/rank/geneticist = 1,
/obj/item/clothing/under/rank/virologist = 1,
/obj/item/clothing/under/rank/nursesuit = 1,
/obj/item/clothing/under/rank/medical = 1,
/obj/item/clothing/under/rank/det = 1,
/obj/item/clothing/under/suit_jacket/white = 0.5,
/obj/item/clothing/under/burial = 1
/obj/item/clothing/under/rank/civilian/bartender = 1,
/obj/item/clothing/under/rank/civilian/chef = 1,
/obj/item/clothing/under/rank/engineering/chief_engineer = 1,
/obj/item/clothing/under/rank/rnd/scientist = 1,
/obj/item/clothing/under/rank/medical/chemist = 1,
/obj/item/clothing/under/rank/medical/chief_medical_officer = 1,
/obj/item/clothing/under/rank/medical/geneticist = 1,
/obj/item/clothing/under/rank/medical/virologist = 1,
/obj/item/clothing/under/rank/medical/doctor/nurse = 1,
/obj/item/clothing/under/rank/medical/doctor = 1,
/obj/item/clothing/under/rank/security/detective = 1,
/obj/item/clothing/under/suit/white = 0.5,
/obj/item/clothing/under/misc/burial = 1
)
if(U && whiteness[U.type])
src.visible_message("<span class='warning'>[src] seems to have been harmed by the purity of [attacker]'s clothes.</span>", "<span class='notice'>Unsullied white clothing is disrupting your form.</span>")
+2 -1
View File
@@ -62,6 +62,7 @@
name = "Imp"
antagpanel_category = "Devil"
show_in_roundend = FALSE
threat = 10
/datum/antagonist/imp/on_gain()
. = ..()
@@ -71,4 +72,4 @@
var/datum/objective/newobjective = new
newobjective.explanation_text = "Try to get a promotion to a higher devilic rank."
newobjective.owner = owner
objectives += newobjective
objectives += newobjective
@@ -14,6 +14,13 @@
var/static/list/sins = list(SIN_ACEDIA,SIN_GLUTTONY,SIN_GREED,SIN_SLOTH,SIN_WRATH,SIN_ENVY,SIN_PRIDE)
/datum/antagonist/sintouched/threat()
switch(sin)
if(SIN_GLUTTONY,SIN_ENVY)
return 1
else
return 0
/datum/antagonist/sintouched/New()
. = ..()
sin = pick(sins)
@@ -80,4 +87,4 @@
#undef SIN_GREED
#undef SIN_PRIDE
#undef SIN_SLOTH
#undef SIN_WRATH
#undef SIN_WRATH
@@ -12,12 +12,7 @@
var/obj/item/r_hand = get_item_for_held_index(2)
if(r_hand)
var/r_state = r_hand.item_state
if(!r_state)
r_state = r_hand.icon_state
var/mutable_appearance/r_hand_overlay = r_hand.build_worn_icon(state = r_state, default_layer = DEVIL_HANDS_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE)
var/mutable_appearance/r_hand_overlay = r_hand.build_worn_icon(default_layer = DEVIL_HANDS_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE)
hands_overlays += r_hand_overlay
@@ -28,12 +23,7 @@
client.screen |= r_hand
if(l_hand)
var/l_state = l_hand.item_state
if(!l_state)
l_state = l_hand.icon_state
var/mutable_appearance/l_hand_overlay = l_hand.build_worn_icon(state = l_state, default_layer = DEVIL_HANDS_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE)
var/mutable_appearance/l_hand_overlay = l_hand.build_worn_icon(default_layer = DEVIL_HANDS_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE)
hands_overlays += l_hand_overlay
@@ -59,7 +59,7 @@ new /datum/disease_ability/symptom/powerful/youth
var/stat_block = ""
var/threshold_block = ""
var/category = ""
var/malefit = 0 // used for threat calculation
var/list/symptoms
var/list/actions
@@ -282,6 +282,7 @@ new /datum/disease_ability/symptom/powerful/youth
/datum/disease_ability/symptom/medium/heal
cost = 5
malefit = -1
category = "Symptom (+)"
/datum/disease_ability/symptom/powerful
@@ -291,6 +292,7 @@ new /datum/disease_ability/symptom/powerful/youth
/datum/disease_ability/symptom/powerful/heal
cost = 8
malefit = -1
category = "Symptom (Strong+)"
/******MILD******/
@@ -319,50 +321,61 @@ new /datum/disease_ability/symptom/powerful/youth
/datum/disease_ability/symptom/medium/hallucigen
symptoms = list(/datum/symptom/hallucigen)
malefit = 1
short_desc = "Cause victims to hallucinate."
long_desc = "Cause victims to hallucinate. Decreases stats, especially resistance."
/datum/disease_ability/symptom/medium/choking
symptoms = list(/datum/symptom/choking)
malefit = 1
short_desc = "Cause victims to choke."
long_desc = "Cause victims to choke, threatening asphyxiation. Decreases stats, especially transmissibility."
/datum/disease_ability/symptom/medium/confusion
symptoms = list(/datum/symptom/confusion)
malefit = 1
short_desc = "Cause victims to become confused."
long_desc = "Cause victims to become confused intermittently."
/datum/disease_ability/symptom/medium/vomit
symptoms = list(/datum/symptom/vomit)
malefit = 1
short_desc = "Cause victims to vomit."
long_desc = "Cause victims to vomit. Slightly increases transmissibility. Vomiting also also causes the victims to lose nutrition and removes some toxin damage."
/datum/disease_ability/symptom/medium/voice_change
symptoms = list(/datum/symptom/voice_change)
malefit = 1
short_desc = "Change the voice of victims."
long_desc = "Change the voice of victims, causing confusion in communications."
/datum/disease_ability/symptom/medium/visionloss
symptoms = list(/datum/symptom/visionloss)
malefit = 1
short_desc = "Damage the eyes of victims, eventually causing blindness."
long_desc = "Damage the eyes of victims, eventually causing blindness. Decreases all stats."
/datum/disease_ability/symptom/medium/deafness
malefit = 1
symptoms = list(/datum/symptom/deafness)
/datum/disease_ability/symptom/medium/fever
malefit = 1
symptoms = list(/datum/symptom/fever)
/datum/disease_ability/symptom/medium/shivering
malefit = 1
symptoms = list(/datum/symptom/shivering)
/datum/disease_ability/symptom/medium/headache
symptoms = list(/datum/symptom/headache)
/datum/disease_ability/symptom/medium/nano_boost
malefit = -1
symptoms = list(/datum/symptom/nano_boost)
/datum/disease_ability/symptom/medium/nano_destroy
malefit = 1
symptoms = list(/datum/symptom/nano_destroy)
/datum/disease_ability/symptom/medium/viraladaptation
@@ -374,18 +387,22 @@ new /datum/disease_ability/symptom/powerful/youth
symptoms = list(/datum/symptom/viralevolution)
/datum/disease_ability/symptom/medium/polyvitiligo
malefit = 1
symptoms = list(/datum/symptom/polyvitiligo)
/datum/disease_ability/symptom/medium/disfiguration
malefit = 1
symptoms = list(/datum/symptom/disfiguration)
/datum/disease_ability/symptom/medium/itching
symptoms = list(/datum/symptom/itching)
malefit = 1
short_desc = "Cause victims to itch."
long_desc = "Cause victims to itch, increasing all stats except stealth."
/datum/disease_ability/symptom/medium/heal/weight_loss
symptoms = list(/datum/symptom/weight_loss)
malefit = 1
short_desc = "Cause victims to lose weight."
long_desc = "Cause victims to lose weight, and make it almost impossible for them to gain nutrition from food. Reduced nutrition allows your infection to spread more easily from hosts, especially by sneezing."
@@ -400,12 +417,15 @@ new /datum/disease_ability/symptom/powerful/youth
/******POWERFUL******/
/datum/disease_ability/symptom/powerful/fire
malefit = 1
symptoms = list(/datum/symptom/fire)
/datum/disease_ability/symptom/powerful/flesh_eating
malefit = 1
symptoms = list(/datum/symptom/flesh_eating)
/datum/disease_ability/symptom/powerful/genetic_mutation
malefit = 1
symptoms = list(/datum/symptom/genetic_mutation)
cost = 8
@@ -413,6 +433,7 @@ new /datum/disease_ability/symptom/powerful/youth
symptoms = list(/datum/symptom/inorganic_adaptation)
/datum/disease_ability/symptom/powerful/narcolepsy
malefit = 1
symptoms = list(/datum/symptom/narcolepsy)
/datum/disease_ability/symptom/powerful/youth
@@ -451,4 +472,4 @@ new /datum/disease_ability/symptom/powerful/youth
/datum/disease_ability/symptom/powerful/heal/coma
symptoms = list(/datum/symptom/heal/coma)
short_desc = "Cause victims to fall into a healing coma when hurt."
long_desc = "Cause victims to fall into a healing coma when hurt."
long_desc = "Cause victims to fall into a healing coma when hurt."
@@ -17,6 +17,14 @@
. = ..()
/datum/antagonist/disease/threat()
var/mob/camera/disease/D = owner.current
var/final_threat = 0
for(var/V in D.purchased_abilities)
var/datum/disease_ability/A = V
final_threat += (A.cost/8)*A.malefit
return final_threat*D.hosts
/datum/antagonist/disease/greet()
to_chat(owner.current, "<span class='notice'>You are the [owner.special_role]!</span>")
to_chat(owner.current, "<span class='notice'>Infect members of the crew to gain adaptation points, and spread your infection further.</span>")
+1
View File
@@ -10,6 +10,7 @@
var/datum/outfit/outfit = /datum/outfit/ert/security
var/role = "Security Officer"
var/list/name_source
threat = -5
show_in_antagpanel = FALSE
antag_moodlet = /datum/mood_event/focused
@@ -2,6 +2,7 @@
name = "Emergency Assistant"
show_name_in_check_antagonists = TRUE
show_in_antagpanel = FALSE
threat = -1
var/mission = "Assist the station."
var/datum/outfit/outfit = /datum/outfit/ert/greybois
@@ -45,7 +45,7 @@
qdel(I)
for(var/obj/item/I in H.held_items)
qdel(I)
H.equip_to_slot_or_del(new /obj/item/clothing/under/kilt/highlander(H), SLOT_W_UNIFORM)
H.equip_to_slot_or_del(new /obj/item/clothing/under/costume/kilt/highlander(H), SLOT_W_UNIFORM)
H.equip_to_slot_or_del(new /obj/item/radio/headset/heads/captain(H), SLOT_EARS)
H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(H), SLOT_HEAD)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(H), SLOT_SHOES)
@@ -73,4 +73,4 @@
antiwelder.name = "compulsion of honor"
antiwelder.desc = "You are unable to hold anything in this hand until you're the last one left!"
antiwelder.icon_state = "bloodhand_right"
H.put_in_hands(antiwelder)
H.put_in_hands(antiwelder)
@@ -8,6 +8,7 @@
job_rank = ROLE_MONKEY
roundend_category = "monkeys"
antagpanel_category = "Monkey"
threat = 3
var/datum/team/monkey/monkey_team
var/monkey_only = TRUE
@@ -81,6 +82,7 @@
/datum/antagonist/monkey/leader
name = "Monkey Leader"
threat = 5
monkey_only = FALSE
/datum/antagonist/monkey/leader/admin_add(datum/mind/new_owner,mob/admin)
@@ -2,5 +2,6 @@
name = "Morph"
show_name_in_check_antagonists = TRUE
show_in_antagpanel = FALSE
threat = 2
//It does nothing! (Besides tracking)
//It does nothing! (Besides tracking)
@@ -1,4 +1,5 @@
/datum/antagonist/nightmare
name = "Nightmare"
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
show_name_in_check_antagonists = TRUE
threat = 5
+4
View File
@@ -4,10 +4,14 @@
job_rank = ROLE_NINJA
show_name_in_check_antagonists = TRUE
antag_moodlet = /datum/mood_event/focused
threat = 8
var/helping_station = FALSE
var/give_objectives = TRUE
var/give_equipment = TRUE
/datum/antagonist/ninja/threat()
return helping_station ? -(..()) : ..()
/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_ninja_icons_added(M)
@@ -3,6 +3,7 @@
name = "Clown Operative"
roundend_category = "clown operatives"
antagpanel_category = "ClownOp"
threat = 7
nukeop_outfit = /datum/outfit/syndicate/clownop
/datum/antagonist/nukeop/clownop/on_gain()
@@ -74,12 +74,6 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
new uplink_type(get_turf(user), user.key, CHALLENGE_TELECRYSTALS - tc_malus + CEILING(PLAYER_SCALING * actual_players, 1))
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
if(istype(SSticker.mode, /datum/game_mode/dynamic))
var/datum/game_mode/dynamic/mode = SSticker.mode
if(!(mode.storyteller.flags & WAROPS_ALWAYS_ALLOWED))
var/threat_spent = CONFIG_GET(number/dynamic_warops_cost)
mode.spend_threat(threat_spent)
mode.log_threat("Nuke ops spent [threat_spent] on war ops.")
SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1)
qdel(src)
@@ -31,6 +31,7 @@
var/interior = ""
var/proper_bomb = TRUE //Please
var/obj/effect/countdown/nuclearbomb/countdown
var/nuclear_cooldown //used to stop global spam.
/obj/machinery/nuclearbomb/Initialize()
. = ..()
@@ -73,16 +74,15 @@
/obj/machinery/nuclearbomb/syndicate/get_cinematic_type(off_station)
var/datum/game_mode/nuclear/NM = SSticker.mode
switch(off_station)
if(0)
if(FALSE)
if(istype(NM) && !NM.nuke_team.syndies_escaped())
return CINEMATIC_ANNIHILATION
else
return CINEMATIC_NUKE_WIN
if(1)
if(NUKE_MISS_STATION)
return CINEMATIC_NUKE_MISS
if(2)
else
return CINEMATIC_NUKE_FAR
return CINEMATIC_NUKE_FAR
/obj/machinery/nuclearbomb/proc/disk_check(obj/item/disk/nuclear/D)
if(D.fake)
@@ -386,14 +386,14 @@
if("anchor")
if(auth && yes_code)
playsound(src, 'sound/machines/nuke/general_beep.ogg', 50, FALSE)
set_anchor()
set_anchor(usr)
else
playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, FALSE)
/obj/machinery/nuclearbomb/proc/set_anchor()
if(isinspace() && !anchored)
to_chat(usr, "<span class='warning'>There is nothing to anchor to!</span>")
/obj/machinery/nuclearbomb/proc/set_anchor(mob/user)
if((istype(get_area(src), /area/space) || isinspace()) && !anchored)
to_chat(user, "<span class='warning'>This is not a suitable platform for anchoring [src]!</span>")
else
anchored = !anchored
@@ -414,6 +414,9 @@
if(safety)
to_chat(usr, "<span class='danger'>The safety is still on.</span>")
return
if(!timing && nuclear_cooldown > world.time)
to_chat(usr, "<span class='danger'>[src]'s timer protocols are currently on cooldown, please stand by.</span>")
return
timing = !timing
if(timing)
previous_level = get_security_level()
@@ -422,6 +425,7 @@
S.switch_mode_to(TRACK_INFILTRATOR)
countdown.start()
set_security_level("delta")
nuclear_cooldown = world.time + 15 SECONDS
if(GLOB.war_declared)
var/area/A = get_area(src)
@@ -475,20 +479,14 @@
GLOB.enter_allowed = FALSE
var/off_station = 0
var/off_station = FALSE
var/turf/bomb_location = get_turf(src)
var/area/A = get_area(bomb_location)
if(bomb_location && is_station_level(bomb_location.z))
if(istype(A, /area/space))
off_station = NUKE_NEAR_MISS
if((bomb_location.x < (128-NUKERANGE)) || (bomb_location.x > (128+NUKERANGE)) || (bomb_location.y < (128-NUKERANGE)) || (bomb_location.y > (128+NUKERANGE)))
off_station = NUKE_NEAR_MISS
if(!bomb_location || !is_station_level(bomb_location.z))
off_station = NUKE_MISS_STATION
else if(bomb_location.onSyndieBase())
off_station = NUKE_SYNDICATE_BASE
else
off_station = NUKE_MISS_STATION
if(off_station < 2)
if(!off_station)
SSshuttle.registerHostileEnvironment(src)
SSshuttle.lockdown = TRUE
@@ -502,7 +500,7 @@
INVOKE_ASYNC(GLOBAL_PROC,.proc/KillEveryoneOnZLevel, z)
/obj/machinery/nuclearbomb/proc/get_cinematic_type(off_station)
if(off_station < 2)
if(!off_station)
return CINEMATIC_SELFDESTRUCT
else
return CINEMATIC_SELFDESTRUCT_MISS
@@ -583,7 +581,7 @@
This is here to make the tiles around the station mininuke change when it's armed.
*/
/obj/machinery/nuclearbomb/selfdestruct/set_anchor()
/obj/machinery/nuclearbomb/selfdestruct/set_anchor(mob/user)
return
/obj/machinery/nuclearbomb/selfdestruct/set_active()
@@ -4,6 +4,7 @@
antagpanel_category = "NukeOp"
job_rank = ROLE_OPERATIVE
antag_moodlet = /datum/mood_event/focused
threat = 10
var/datum/team/nuclear/nuke_team
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
@@ -10,6 +10,7 @@
roundend_category = "syndicate mutineers"
antagpanel_category = "Syndicate Mutineers"
job_rank = ROLE_TRAITOR // simply use the traitor preference & jobban settings
threat = 5
var/datum/team/overthrow/team
var/static/list/possible_useful_items
@@ -49,7 +49,7 @@
else
to_chat(user, "<span class='warning'>[user] fails to implant [M].</span>")
/obj/item/overthrow_converter/update_icon()
/obj/item/overthrow_converter/update_icon_state()
if(uses)
icon_state = "implanter1"
else
+2 -1
View File
@@ -3,6 +3,7 @@
job_rank = ROLE_TRAITOR
roundend_category = "space pirates"
antagpanel_category = "Pirate"
threat = 5
var/datum/team/pirate/crew
/datum/antagonist/pirate/greet()
@@ -104,4 +105,4 @@
else
parts += "<span class='redtext big'>The pirate crew has failed.</span>"
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
@@ -397,7 +397,7 @@
inert = TRUE
visible_message("<span class='revenwarning'>[src] settles down and seems lifeless.</span>")
return
var/mob/dead/observer/C = pick(candidates)
var/mob/C = pick(candidates)
C.transfer_ckey(revenant.key, FALSE)
if(!revenant.key)
qdel(revenant)
@@ -117,7 +117,7 @@
tinfoil_check = FALSE
/obj/effect/proc_holder/spell/aoe_turf/revenant
clothes_req = 0
clothes_req = NONE
action_icon = 'icons/mob/actions/actions_revenant.dmi'
action_background_icon_state = "bg_revenant"
panel = "Revenant Abilities (Locked)"
@@ -135,7 +135,7 @@
else
name = "[initial(name)] ([cast_amount]E)"
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr)
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr, skipcharge = FALSE, silent = FALSE)
if(charge_counter < charge_max)
return FALSE
if(!istype(user)) //Badmins, no. Badmins, don't do it.
@@ -213,7 +213,7 @@
continue
L.Beam(M,icon_state="purple_lightning",time=5)
if(!M.anti_magic_check(FALSE, TRUE))
M.electrocute_act(shock_damage, L, safety=TRUE)
M.electrocute_act(shock_damage, L, flags = SHOCK_NOGLOVES)
do_sparks(4, FALSE, M)
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
@@ -2,6 +2,7 @@
name = "Revenant"
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
threat = 5
/datum/antagonist/revenant/greet()
owner.announce_objectives()
@@ -7,6 +7,7 @@
antagpanel_category = "Revolution"
job_rank = ROLE_REV
antag_moodlet = /datum/mood_event/revolution
threat = 2
var/hud_type = "rev"
var/datum/team/revolution/rev_team
@@ -148,6 +149,7 @@
/datum/antagonist/rev/head
name = "Head Revolutionary"
hud_type = "rev_head"
threat = 8
var/remove_clumsy = FALSE
var/give_flash = FALSE
var/give_hud = TRUE
+1 -1
View File
@@ -18,7 +18,7 @@
owner.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/presents)
var/obj/effect/proc_holder/spell/targeted/area_teleport/teleport/telespell = new
telespell.clothes_req = 0 //santa robes aren't actually magical.
telespell.clothes_req = NONE //santa robes aren't actually magical.
owner.AddSpell(telespell) //does the station have chimneys? WHO KNOWS!
/datum/antagonist/santa/proc/give_objective()
@@ -76,8 +76,9 @@
icon_state = "demon_heart-on"
decay_factor = 0
/obj/item/organ/heart/demon/update_icon()
return //always beating visually
/obj/item/organ/heart/demon/ComponentInitialize()
. = ..()
AddElement(/datum/element/update_icon_blocker)
/obj/item/organ/heart/demon/attack(mob/M, mob/living/carbon/user, obj/target)
if(M != user)
@@ -3,6 +3,7 @@
show_name_in_check_antagonists = TRUE
var/objective_verb = "Kill"
var/datum/mind/summoner
threat = 10
job_rank = ROLE_ALIEN
show_in_antagpanel = FALSE
@@ -28,4 +29,4 @@
/datum/antagonist/slaughter/laughter
name = "Laughter demon"
objective_verb = "Hug and Tickle"
objective_verb = "Hug and Tickle"
@@ -3,6 +3,7 @@
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
blacklisted_quirks = list(/datum/quirk/nonviolent) // mutes are allowed
threat = 1
var/greet_message = ""
/datum/antagonist/survivalist/proc/forge_objectives()
+4 -3
View File
@@ -70,6 +70,7 @@
icon_living = "swarmer"
icon_dead = "swarmer_unactivated"
icon_gib = null
threat = 0.5
wander = 0
harm_intent_damage = 5
minbodytemp = 0
@@ -492,8 +493,8 @@
playsound(src,'sound/effects/sparks4.ogg',50,1)
do_teleport(target, F, 0, channel = TELEPORT_CHANNEL_BLUESPACE)
/mob/living/simple_animal/hostile/swarmer/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE)
if(!tesla_shock)
/mob/living/simple_animal/hostile/swarmer/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
if(!(flags & SHOCK_TESLA))
return FALSE
return ..()
@@ -584,7 +585,7 @@
var/mob/living/L = AM
if(!istype(L, /mob/living/simple_animal/hostile/swarmer))
playsound(loc,'sound/effects/snap.ogg',50, 1, -1)
L.electrocute_act(0, src, 1, 1, 1)
L.electrocute_act(0, src, 1, flags = SHOCK_NOGLOVES|SHOCK_ILLUSION)
if(iscyborg(L))
L.DefaultCombatKnockdown(100)
qdel(src)
@@ -5,6 +5,7 @@
max_occurrences = 0
earliest_start = 30 MINUTES
min_players = 15
gamemode_blacklist = list("dynamic")
/datum/round_event/spawn_swarmer
@@ -120,7 +120,7 @@
/datum/antagonist/traitor/internal_affairs/reinstate_escape_objective()
..()
var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive
var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
var/datum/objective/escape_objective = new objtype
escape_objective.owner = owner
add_objective(escape_objective)
@@ -215,20 +215,12 @@
kill_objective.target = target_mind
kill_objective.update_explanation_text()
add_objective(kill_objective)
//Optional traitor objective
if(prob(PROB_ACTUAL_TRAITOR))
employer = "The Syndicate"
owner.special_role = TRAITOR_AGENT_ROLE
special_role = TRAITOR_AGENT_ROLE
syndicate = TRUE
forge_single_objective()
return
/datum/antagonist/traitor/internal_affairs/forge_traitor_objectives()
forge_iaa_objectives()
var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive
var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
var/datum/objective/escape_objective = new objtype
escape_objective.owner = owner
add_objective(escape_objective)
@@ -0,0 +1,69 @@
/datum/traitor_class/ai // this one is special, so has no weight
name = "Malfunctioning AI"
threat = 20
/datum/traitor_class/ai/forge_objectives(datum/antagonist/traitor/T)
var/objective_count = 0
if(prob(30))
objective_count += forge_single_objective()
for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = T.owner
kill_objective.find_target()
T.add_objective(kill_objective)
var/datum/objective/survive/exist/exist_objective = new
exist_objective.owner = T.owner
T.add_objective(exist_objective)
/datum/traitor_class/ai/forge_single_objective(datum/antagonist/traitor/T)
.=1
var/special_pick = rand(1,4)
switch(special_pick)
if(1)
var/datum/objective/block/block_objective = new
block_objective.owner = T.owner
T.add_objective(block_objective)
if(2)
var/datum/objective/purge/purge_objective = new
purge_objective.owner = T.owner
T.add_objective(purge_objective)
if(3)
var/datum/objective/robot_army/robot_objective = new
robot_objective.owner = T.owner
T.add_objective(robot_objective)
if(4) //Protect and strand a target
var/datum/objective/protect/yandere_one = new
yandere_one.owner = T.owner
T.add_objective(yandere_one)
yandere_one.find_target()
var/datum/objective/maroon/yandere_two = new
yandere_two.owner = T.owner
yandere_two.target = yandere_one.target
yandere_two.update_explanation_text() // normally called in find_target()
T.add_objective(yandere_two)
.=2
/datum/traitor_class/ai/on_removal(datum/antagonist/traitor/T)
var/mob/living/silicon/ai/A = T.owner.current
A.set_zeroth_law("")
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
A.malf_picker.remove_malf_verbs(A)
qdel(A.malf_picker)
/datum/traitor_class/ai/apply_innate_effects(mob/living/M)
var/mob/living/silicon/ai/A = M
A.hack_software = TRUE
/datum/traitor_class/ai/remove_innate_effects(mob/living/M)
var/mob/living/silicon/ai/A = M
A.hack_software = FALSE
/datum/traitor_class/ai/finalize_traitor(datum/antagonist/traitor/T)
T.add_law_zero()
T.owner.current.playsound_local(get_turf(T.owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
T.owner.current.grant_language(/datum/language/codespeak)
return FALSE
@@ -0,0 +1,37 @@
/datum/traitor_class/human/assassin
name = "Donk Co Operative"
employer = "Donk Corporation"
weight = 0
chaos = 1
threat = 2
/datum/traitor_class/human/assassin/forge_single_objective(datum/antagonist/traitor/T)
.=1
var/permakill_prob = 20
var/is_dynamic = FALSE
var/datum/game_mode/dynamic/mode
if(istype(SSticker.mode,/datum/game_mode/dynamic))
mode = SSticker.mode
is_dynamic = TRUE
permakill_prob = max(0,mode.threat_level-50)
var/list/active_ais = active_ais()
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
var/datum/objective/destroy/destroy_objective = new
destroy_objective.owner = T.owner
destroy_objective.find_target()
T.add_objective(destroy_objective)
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
var/datum/objective/maroon/maroon_objective = new
maroon_objective.owner = T.owner
maroon_objective.find_target()
T.add_objective(maroon_objective)
else if(prob(permakill_prob))
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = T.owner
kill_objective.find_target()
T.add_objective(kill_objective)
else
var/datum/objective/assassinate/once/kill_objective = new
kill_objective.owner = T.owner
kill_objective.find_target()
T.add_objective(kill_objective)
@@ -0,0 +1,12 @@
/datum/traitor_class/human/freeform
name = "Waffle Co Agent"
employer = "Waffle Company"
weight = 16
chaos = 0
/datum/traitor_class/human/freeform/forge_objectives(datum/antagonist/traitor/T)
var/datum/objective/escape/O = new
O.explanation_text = "You have no explicit goals! While we don't approve of mindless slaughter, you may antagonize nanotrasen any way you wish! Make sure to escape alive and not in custody, though!"
O.owner = T.owner
T.add_objective(O)
return
@@ -0,0 +1,18 @@
/datum/traitor_class/human/hijack
name = "Gorlex Marauder"
employer = "The Gorlex Marauders"
weight = 3
chaos = 5
threat = 3
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit)
/datum/traitor_class/human/hijack/forge_objectives(datum/antagonist/traitor/T)
var/datum/objective/hijack/O = new
O.explanation_text = "The Gorlex Marauders are letting you do what you want, with one condition: the shuttle must be hijacked by hacking its navigational protocols through the control console (alt click emergency shuttle console)."
O.owner = T.owner
T.add_objective(O)
return
/datum/traitor_class/human/hijack/finalize_traitor(datum/antagonist/traitor/T)
T.hijack_speed=1
return TRUE
@@ -0,0 +1,82 @@
/datum/traitor_class/human
name = "Syndicate Agent"
chaos = 0
/datum/traitor_class/human/forge_objectives(datum/antagonist/traitor/T)
var/objective_count = 0 //Hijacking counts towards number of objectives
if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
if(!SSticker.mode.exchange_red)
SSticker.mode.exchange_red = T.owner
else
SSticker.mode.exchange_blue = T.owner
T.assign_exchange_role(SSticker.mode.exchange_red)
T.assign_exchange_role(SSticker.mode.exchange_blue)
objective_count += 1 //Exchange counts towards number of objectives
var/toa = CONFIG_GET(number/traitor_objectives_amount)
for(var/i = objective_count, i < toa, i++)
forge_single_objective(T)
if(!(locate(/datum/objective/escape) in T.objectives))
var/datum/objective/escape/escape_objective = new
escape_objective.owner = T.owner
T.add_objective(escape_objective)
return
/datum/traitor_class/human/forge_single_objective(datum/antagonist/traitor/T)
.=1
var/assassin_prob = 50
var/is_dynamic = FALSE
var/datum/game_mode/dynamic/mode
if(istype(SSticker.mode,/datum/game_mode/dynamic))
mode = SSticker.mode
is_dynamic = TRUE
assassin_prob = max(0,mode.threat_level-20)
if(prob(assassin_prob))
if(is_dynamic)
var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
mode.spend_threat(threat_spent)
mode.log_threat("[T.owner.name] added [threat_spent] on an assassination target.")
var/list/active_ais = active_ais()
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
var/datum/objective/destroy/destroy_objective = new
destroy_objective.owner = T.owner
destroy_objective.find_target()
T.add_objective(destroy_objective)
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
var/datum/objective/maroon/maroon_objective = new
maroon_objective.owner = T.owner
maroon_objective.find_target()
T.add_objective(maroon_objective)
else if(prob(max(0,assassin_prob-20)))
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = T.owner
kill_objective.find_target()
T.add_objective(kill_objective)
else
var/datum/objective/assassinate/once/kill_objective = new
kill_objective.owner = T.owner
kill_objective.find_target()
T.add_objective(kill_objective)
else
if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
var/datum/objective/download/download_objective = new
download_objective.owner = T.owner
download_objective.gen_amount_goal()
T.add_objective(download_objective)
else if(prob(40)) // cum. not counting download: 40%.
var/datum/objective/steal/steal_objective = new
steal_objective.owner = T.owner
steal_objective.find_target()
T.add_objective(steal_objective)
else if(prob(100/3)) // cum. not counting download: 20%.
var/datum/objective/sabotage/sabotage_objective = new
sabotage_objective.owner = T.owner
sabotage_objective.find_target()
T.add_objective(sabotage_objective)
else // cum. not counting download: 40%
var/datum/objective/flavor/traitor/flavor_objective = new
flavor_objective.owner = T.owner
flavor_objective.forge_objective()
T.add_objective(flavor_objective)
/datum/traitor_class/human/greet(datum/antagonist/traitor/T)
to_chat(T.owner.current, "<B><font size=2 color=red>You are under contract with [employer]. They have given you your objectives.</font></B>")
@@ -0,0 +1,14 @@
/datum/traitor_class/human/martyr
name = "Tiger Cooperator"
employer = "The Tiger Cooperative"
weight = 2
chaos = 5
threat = 5
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit)
/datum/traitor_class/human/martyr/forge_objectives(datum/antagonist/traitor/T)
var/datum/objective/martyr/O = new
O.explanation_text = "The tiger cooperative have given you free reign. You may do as you wish, as long as you die a glorious death!"
O.owner = T.owner
T.add_objective(O)
return
@@ -0,0 +1,40 @@
/datum/traitor_class/human/subterfuge
name = "MI13 Operative"
employer = "MI13"
weight = 20
chaos = -5
/datum/traitor_class/human/subterfuge/forge_single_objective(datum/antagonist/traitor/T)
.=1
var/assassin_prob = 30
var/datum/game_mode/dynamic/mode
if(istype(SSticker.mode,/datum/game_mode/dynamic))
mode = SSticker.mode
assassin_prob = max(0,mode.threat_level-40)
if(prob(assassin_prob))
if(prob(assassin_prob))
var/datum/objective/assassinate/once/kill_objective = new
kill_objective.owner = T.owner
kill_objective.find_target()
T.add_objective(kill_objective)
else
var/datum/objective/maroon/maroon_objective = new
maroon_objective.owner = T.owner
maroon_objective.find_target()
T.add_objective(maroon_objective)
else
if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
var/datum/objective/download/download_objective = new
download_objective.owner = T.owner
download_objective.gen_amount_goal()
T.add_objective(download_objective)
else if(prob(70)) // cum. not counting download: 40%.
var/datum/objective/steal/steal_objective = new
steal_objective.owner = T.owner
steal_objective.find_target()
T.add_objective(steal_objective)
else
var/datum/objective/sabotage/sabotage_objective = new
sabotage_objective.owner = T.owner
sabotage_objective.find_target()
T.add_objective(sabotage_objective)
@@ -0,0 +1,40 @@
GLOBAL_LIST_EMPTY(traitor_classes)
/datum/traitor_class
var/name = "Bad Coders Ltd."
var/employer = "The Syndicate"
var/weight = 0
var/chaos = 0
var/threat = 0
var/TC = 20
var/list/uplink_filters
/datum/traitor_class/New()
..()
if(src.type in GLOB.traitor_classes)
qdel(src)
else
GLOB.traitor_classes += src.type
GLOB.traitor_classes[src.type] = src
/datum/traitor_class/proc/forge_objectives(datum/antagonist/traitor/T)
// Like the old forge_human_objectives. Makes all the objectives for this traitor class.
/datum/traitor_class/proc/forge_single_objective(datum/antagonist/traitor/T)
// As forge_single_objective.
/datum/traitor_class/proc/on_removal(datum/antagonist/traitor/T)
// What this does to the antag datum on removal. Called before proper removal, obviously.
/datum/traitor_class/proc/apply_innate_effects(mob/living/M)
// What innate effects it should have. See: AI.
/datum/traitor_class/proc/remove_innate_effects(mob/living/M)
// Cleaning up the innate effects.
/datum/traitor_class/proc/greet(datum/antagonist/traitor/T)
// Message upon creation. Not necessary, but can be useful.
/datum/traitor_class/proc/finalize_traitor(datum/antagonist/traitor/T)
// Finalization. Return TRUE if should play standard traitor sound/equip, return FALSE if both are special case
return TRUE

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