Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit611
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>")
|
||||
@@ -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)]")
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user