mirror of
https://github.com/fulpstation/fulpstation.git
synced 2025-12-09 16:09:15 +00:00
Assimilation 2.0: Not quite a big enough PR to be worthy of the 2.0 title but almost (#42607)
* one * ??? * big * sprites * it is done * oofs * no more bad jokes * location -> reception * i forgot a feature lmao * yo lemme nerf this op power * adjust removal and makes panic less insane * hey i forgot another feature * one mind removals * *laser eyes meme* * Disables multiple one minds for real this time
This commit is contained in:
@@ -42,3 +42,10 @@
|
||||
|
||||
//Overthrow time to update heads obj
|
||||
#define OBJECTIVE_UPDATING_TIME 300
|
||||
|
||||
//Assimilation
|
||||
#define TRACKER_DEFAULT_TIME 900
|
||||
#define TRACKER_MINDSHIELD_TIME 1200
|
||||
#define TRACKER_AWAKENED_TIME 3000
|
||||
#define TRACKER_BONUS_LARGE 300
|
||||
#define TRACKER_BONUS_SMALL 100
|
||||
@@ -100,6 +100,8 @@
|
||||
|
||||
#define STATUS_EFFECT_INLOVE /datum/status_effect/in_love //Displays you as being in love with someone else, and makes hearts appear around them.
|
||||
|
||||
#define STATUS_EFFECT_BUGGED /datum/status_effect/bugged //Lets other mobs listen in on what it hears
|
||||
|
||||
#define STATUS_EFFECT_HIVE_TRACKER /datum/status_effect/hive_track
|
||||
|
||||
#define STATUS_EFFECT_HIVE_RADAR /datum/status_effect/agent_pinpointer/hivemind
|
||||
|
||||
@@ -160,3 +160,4 @@
|
||||
#define LOCKED_HELMET_TRAIT "locked-helmet"
|
||||
#define NINJA_SUIT_TRAIT "ninja-suit"
|
||||
#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant"
|
||||
#define HIVEMIND_ONE_MIND_TRAIT "one_mind"
|
||||
@@ -28,8 +28,8 @@ GLOBAL_LIST_INIT(huds, list(
|
||||
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_HIVE = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_OBSESSED = new/datum/atom_hud/antag/hidden()
|
||||
))
|
||||
ANTAG_HUD_OBSESSED = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_HIVEAWAKE = new/datum/atom_hud/antag() ))
|
||||
|
||||
/datum/atom_hud
|
||||
var/list/atom/hudatoms = list() //list of all atoms which display this hud
|
||||
|
||||
@@ -84,3 +84,15 @@
|
||||
/datum/status_effect/throat_soothed/on_remove()
|
||||
. = ..()
|
||||
owner.remove_trait(TRAIT_SOOTHED_THROAT, "[STATUS_EFFECT_TRAIT]_[id]")
|
||||
|
||||
/datum/status_effect/bugged //Lets another mob hear everything you can
|
||||
id = "bugged"
|
||||
duration = -1
|
||||
status_type = STATUS_EFFECT_MULTIPLE
|
||||
alert_type = null
|
||||
var/mob/living/listening_in
|
||||
|
||||
/datum/status_effect/bugged/on_creation(mob/living/new_owner, mob/living/tracker)
|
||||
. = ..()
|
||||
if(.)
|
||||
listening_in = tracker
|
||||
@@ -6,7 +6,7 @@
|
||||
false_report_weight = 5
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")
|
||||
restricted_jobs = list("Cyborg","AI")
|
||||
required_players = 25
|
||||
required_players = 24
|
||||
required_enemies = 2
|
||||
recommended_enemies = 3
|
||||
reroll_friendly = 1
|
||||
@@ -20,20 +20,19 @@
|
||||
var/list/hosts = list()
|
||||
|
||||
/proc/is_hivehost(mob/living/M)
|
||||
return M && M.mind && M.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
|
||||
/proc/is_real_hivehost(mob/living/M) //This proc ignores mind controlled vessels
|
||||
if(!M || !M.mind)
|
||||
return FALSE
|
||||
var/datum/antagonist/hivemind/hive = M.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(!hive)
|
||||
return FALSE
|
||||
var/obj/effect/proc_holder/spell/target_hive/hive_control/the_spell = locate(/obj/effect/proc_holder/spell/target_hive/hive_control) in M.mind.spell_list
|
||||
if(the_spell && the_spell.active)
|
||||
if(the_spell.original_body == M)
|
||||
return
|
||||
return M.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
|
||||
/mob/living/proc/is_real_hivehost() //This proc ignores mind controlled vessels
|
||||
for(var/datum/antagonist/hivemind/hive in GLOB.antagonists)
|
||||
if(!hive.owner?.spell_list)
|
||||
continue
|
||||
var/obj/effect/proc_holder/spell/target_hive/hive_control/the_spell = locate(/obj/effect/proc_holder/spell/target_hive/hive_control) in hive.owner.spell_list
|
||||
if((!the_spell || !the_spell.active ) && mind == hive.owner)
|
||||
return TRUE
|
||||
if(the_spell?.active && the_spell.original_body == src)
|
||||
return TRUE
|
||||
else
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/proc/get_real_hivehost() //Returns src unless it's under mind control, then it returns the original body
|
||||
@@ -47,7 +46,10 @@
|
||||
return the_spell.original_body
|
||||
return M
|
||||
|
||||
/proc/is_hivemember(mob/living/M)
|
||||
/proc/is_hivemember(mob/living/L)
|
||||
if(!L)
|
||||
return FALSE
|
||||
var/datum/mind/M = L.mind
|
||||
if(!M)
|
||||
return FALSE
|
||||
for(var/datum/antagonist/hivemind/H in GLOB.antagonists)
|
||||
@@ -71,7 +73,7 @@
|
||||
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
|
||||
restricted_jobs += "Assistant"
|
||||
|
||||
var/num_hosts = max( 1 , rand(0,1) + min(5, round(num_players() / 12) ) ) //1 host for every 12 players up to 60, with a 50% chance of an extra
|
||||
var/num_hosts = max( 1 , rand(0,1) + min(8, round(num_players() / 8) ) ) //1 host for every 8 players up to 64, with a 50% chance of an extra
|
||||
|
||||
for(var/j = 0, j < num_hosts, j++)
|
||||
if (!antag_candidates.len)
|
||||
@@ -91,10 +93,6 @@
|
||||
|
||||
|
||||
/datum/game_mode/hivemind/post_setup()
|
||||
if(hosts.len >= 4 && prob(35)) //Create the versus objective here since we want a common target for all the antags
|
||||
var/datum/antagonist/hivemind/hive
|
||||
hive.common_assimilation_obj = new /datum/objective/hivemind/assimilate_common
|
||||
hive.common_assimilation_obj.find_target_by_role(role = ROLE_HIVE, role_type = TRUE, invert = TRUE)
|
||||
for(var/datum/mind/i in hosts)
|
||||
i.add_antag_datum(/datum/antagonist/hivemind)
|
||||
return ..()
|
||||
|
||||
@@ -33,32 +33,17 @@
|
||||
var/datum/antagonist/hivemind/host = owner.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(!host)
|
||||
return FALSE
|
||||
for(var/mob/living/L in host.hivemembers)
|
||||
var/datum/mind/M = L.mind
|
||||
if(M)
|
||||
if(considered_escaped(M))
|
||||
count++
|
||||
for(var/obj/item/organ/brain/B in host.hivemembers)
|
||||
var/mob/living/carbon/C = B.owner
|
||||
if(!C)
|
||||
continue
|
||||
var/datum/mind/M = C.mind
|
||||
if(!M)
|
||||
continue
|
||||
if(considered_escaped(M))
|
||||
count++
|
||||
return count >= target_amount
|
||||
|
||||
/datum/objective/hivemind/assimilate
|
||||
explanation_text = "This is a bug. Error:HIVE3"
|
||||
|
||||
/datum/objective/hivemind/assimilate/update_explanation_text()
|
||||
if(target)
|
||||
explanation_text = "Assimilate [target.name] into the hive and ensure they survive."
|
||||
else
|
||||
explanation_text = "Free Objective."
|
||||
|
||||
/datum/objective/hivemind/assimilate/check_completion()
|
||||
var/datum/antagonist/hivemind/host = owner.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(!host)
|
||||
return FALSE
|
||||
for(var/mob/living/L in host.hivemembers)
|
||||
var/datum/mind/M = L.mind
|
||||
if(M == target)
|
||||
return considered_alive(target)
|
||||
return FALSE
|
||||
|
||||
/datum/objective/hivemind/biggest
|
||||
explanation_text = "End the round with more vessels than any other hivemind host."
|
||||
|
||||
@@ -71,26 +56,4 @@
|
||||
continue
|
||||
if(H.hive_size >= host.hive_size)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/objective/hivemind/assimilate_common
|
||||
explanation_text = "This is a bug. Error:HIVE3"
|
||||
|
||||
/datum/objective/hivemind/assimilate_common/update_explanation_text()
|
||||
if(target)
|
||||
explanation_text = "Ensure that you are the only host assimilating [target.name] at the end of the round."
|
||||
else
|
||||
explanation_text = "Free Objective."
|
||||
|
||||
/datum/objective/hivemind/assimilate_common/check_completion()
|
||||
var/datum/antagonist/hivemind/host = owner.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(!target)
|
||||
return TRUE
|
||||
if(!host || !target.current || !host.hivemembers.Find(target.current))
|
||||
return FALSE
|
||||
for(var/datum/antagonist/hivemind/H in GLOB.antagonists)
|
||||
if(H == host)
|
||||
continue
|
||||
if(H.hivemembers.Find(target.current))
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -41,20 +41,25 @@
|
||||
qdel(src)
|
||||
return FALSE
|
||||
|
||||
var/datum/antagonist/hivevessel/woke = target.is_wokevessel()
|
||||
if(is_hivemember(target))
|
||||
for(var/datum/antagonist/hivemind/hive in GLOB.antagonists)
|
||||
if(hive.hivemembers.Find(target))
|
||||
var/mob/living/carbon/C = hive.owner.current.get_real_hivehost()
|
||||
if(C)
|
||||
C.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, target)
|
||||
target.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, C)
|
||||
C.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, target, woke?TRACKER_AWAKENED_TIME:TRACKER_MINDSHIELD_TIME)
|
||||
target.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, C, TRACKER_DEFAULT_TIME)
|
||||
if(C.mind) //If you were using mind control, too bad
|
||||
C.apply_status_effect(STATUS_EFFECT_HIVE_RADAR)
|
||||
to_chat(C, "<span class='userdanger'>We detect a surge of psionic energy from a far away vessel before they disappear from the hive. Whatever happened, there's a good chance they're after us now.</span>")
|
||||
to_chat(C, "<span class='assimilator'>We detect a surge of psionic energy from a far away vessel before they disappear from the hive. Whatever happened, there's a good chance they're after us now.</span>")
|
||||
to_chat(target, "<span class='assimilator'>You hear supernatural wailing echo throughout your mind as you are finally set free. Deep down, you can feel the lingering presence of those who enslaved you... as can they!</span>")
|
||||
target.apply_status_effect(STATUS_EFFECT_HIVE_RADAR)
|
||||
remove_hivemember(target)
|
||||
|
||||
if(woke)
|
||||
woke.one_mind.remove_member(target.mind)
|
||||
target.mind.remove_antag_datum(/datum/antagonist/hivevessel)
|
||||
|
||||
var/datum/antagonist/rev/rev = target.mind.has_antag_datum(/datum/antagonist/rev)
|
||||
if(rev)
|
||||
rev.remove_revolutionary(FALSE, user)
|
||||
|
||||
@@ -8,83 +8,143 @@
|
||||
var/list/hivemembers = list()
|
||||
var/hive_size = 0
|
||||
var/threat_level = 0 // Part of what determines how strong the radar is, on a scale of 0 to 10
|
||||
var/static/datum/objective/hivemind/assimilate_common/common_assimilation_obj //Make it static since we want a common target for all the antags
|
||||
var/track_bonus = 0 // Bonus time to your tracking abilities
|
||||
var/size_mod = 0 // Bonus size for using reclaim
|
||||
var/list/individual_track_bonus // Bonus time to tracking individual targets
|
||||
var/unlocked_one_mind = FALSE
|
||||
var/datum/team/hivemind/active_one_mind
|
||||
var/mutable_appearance/glow
|
||||
|
||||
var/list/upgrade_tiers = list(
|
||||
//Tier 1
|
||||
//Tier 1 - Roundstart powers
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_add = 0,
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_remove = 0,
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_see = 0,
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_shock = 2,
|
||||
/obj/effect/proc_holder/spell/self/hive_drain = 4,
|
||||
//Tier 2
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_warp = 6,
|
||||
/obj/effect/proc_holder/spell/targeted/hive_hack = 8,
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_control = 10,
|
||||
/obj/effect/proc_holder/spell/targeted/induce_panic = 12,
|
||||
//Tier 3
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_shock = 0,
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_warp = 0,
|
||||
//Tier 2 - Tracking related powers
|
||||
/obj/effect/proc_holder/spell/self/hive_scan = 5,
|
||||
/obj/effect/proc_holder/spell/targeted/hive_reclaim = 5,
|
||||
/obj/effect/proc_holder/spell/targeted/hive_hack = 5,
|
||||
//Tier 3 - Combat related powers
|
||||
/obj/effect/proc_holder/spell/self/hive_drain = 10,
|
||||
/obj/effect/proc_holder/spell/targeted/induce_panic = 10,
|
||||
/obj/effect/proc_holder/spell/targeted/forcewall/hive = 10,
|
||||
//Tier 4 - Chaos-spreading powers
|
||||
/obj/effect/proc_holder/spell/self/hive_wake = 15,
|
||||
/obj/effect/proc_holder/spell/self/hive_loyal = 15,
|
||||
/obj/effect/proc_holder/spell/targeted/hive_assim = 18,
|
||||
/obj/effect/proc_holder/spell/targeted/forcewall/hive = 20,
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_attack = 25)
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_control = 15,
|
||||
//Tier 5 - Deadly powers
|
||||
/obj/effect/proc_holder/spell/targeted/induce_sleep = 20,
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_attack = 20
|
||||
)
|
||||
|
||||
|
||||
/datum/antagonist/hivemind/proc/calc_size()
|
||||
listclearnulls(hivemembers)
|
||||
var/old_size = hive_size
|
||||
hive_size = hivemembers.len
|
||||
if(hive_size != old_size)
|
||||
var/temp = 0
|
||||
for(var/datum/mind/M in hivemembers)
|
||||
if(M.current && M.current.stat != DEAD)
|
||||
temp++
|
||||
if(hive_size != temp)
|
||||
hive_size = temp
|
||||
check_powers()
|
||||
|
||||
/datum/antagonist/hivemind/proc/get_threat_multiplier()
|
||||
calc_size()
|
||||
return min(hive_size/50 + threat_level/20, 1)
|
||||
return min((hive_size+size_mod*2)/50 + threat_level/20, 1)
|
||||
|
||||
/datum/antagonist/hivemind/proc/get_carbon_members()
|
||||
var/list/carbon_members = list()
|
||||
for(var/datum/mind/M in hivemembers)
|
||||
if(!M.current || !iscarbon(M.current))
|
||||
continue
|
||||
carbon_members += M.current
|
||||
return carbon_members
|
||||
|
||||
/datum/antagonist/hivemind/proc/check_powers()
|
||||
for(var/power in upgrade_tiers)
|
||||
var/level = upgrade_tiers[power]
|
||||
if(hive_size >= level && !(locate(power) in owner.spell_list))
|
||||
if(hive_size+size_mod >= level && !(locate(power) in owner.spell_list))
|
||||
var/obj/effect/proc_holder/spell/the_spell = new power(null)
|
||||
owner.AddSpell(the_spell)
|
||||
if(hive_size > 0)
|
||||
to_chat(owner, "<span class='assimilator'>We have unlocked [the_spell.name].</span><span class='bold'> [the_spell.desc]</span>")
|
||||
|
||||
/datum/antagonist/hivemind/proc/add_to_hive(var/mob/living/carbon/human/H)
|
||||
if(!unlocked_one_mind && hive_size >= 15)
|
||||
var/lead = TRUE
|
||||
for(var/datum/antagonist/hivemind/enemy in GLOB.antagonists)
|
||||
if(enemy == src)
|
||||
continue
|
||||
if(!enemy.active_one_mind && enemy.hive_size <= hive_size + size_mod - 20)
|
||||
continue
|
||||
lead = FALSE
|
||||
break
|
||||
if(lead)
|
||||
unlocked_one_mind = TRUE
|
||||
owner.AddSpell(new/obj/effect/proc_holder/spell/self/one_mind)
|
||||
to_chat(owner, "<big><span class='assimilator'>Our true power, the One Mind, is finally within reach.</span></big>")
|
||||
|
||||
/datum/antagonist/hivemind/proc/add_track_bonus(datum/antagonist/hivemind/enemy, bonus)
|
||||
if(!locate(enemy) in individual_track_bonus)
|
||||
individual_track_bonus[enemy] = bonus
|
||||
else
|
||||
individual_track_bonus[enemy] += bonus
|
||||
|
||||
/datum/antagonist/hivemind/proc/get_track_bonus(datum/antagonist/hivemind/enemy)
|
||||
return TRACKER_DEFAULT_TIME + track_bonus + individual_track_bonus[enemy]
|
||||
|
||||
/datum/antagonist/hivemind/proc/add_to_hive(mob/living/carbon/C)
|
||||
if(!C)
|
||||
return
|
||||
var/datum/mind/M = C.mind
|
||||
if(M)
|
||||
hivemembers |= M
|
||||
calc_size()
|
||||
|
||||
var/user_warning = "<span class='userdanger'>We have detected an enemy hivemind using our physical form as a vessel and have begun ejecting their mind! They will be alerted of our disappearance once we succeed!</span>"
|
||||
for(var/datum/antagonist/hivemind/enemy_hive in GLOB.antagonists)
|
||||
if(is_real_hivehost(H))
|
||||
var/eject_time = rand(1400,1600) //2.5 minutes +- 10 seconds
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, H, user_warning), rand(500,1300)) // If the host has assimilated an enemy hive host, alert the enemy before booting them from the hive after a short while
|
||||
addtimer(CALLBACK(src, .proc/handle_ejection, H), eject_time)
|
||||
hivemembers |= H
|
||||
calc_size()
|
||||
if(C.is_real_hivehost())
|
||||
var/eject_time = rand(1400,1600) //2.5 minutes +- 10 seconds
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, C, user_warning), rand(500,1300)) // If the host has assimilated an enemy hive host, alert the enemy before booting them from the hive after a short while
|
||||
addtimer(CALLBACK(src, .proc/handle_ejection, C), eject_time)
|
||||
else if(active_one_mind)
|
||||
C.hive_awaken(final_form=active_one_mind)
|
||||
|
||||
/datum/antagonist/hivemind/proc/remove_from_hive(var/mob/living/carbon/human/H)
|
||||
hivemembers -= H
|
||||
calc_size()
|
||||
/datum/antagonist/hivemind/proc/is_carbon_member(mob/living/carbon/C)
|
||||
if(!hivemembers || !C || !iscarbon(C))
|
||||
return FALSE
|
||||
var/datum/mind/M = C.mind
|
||||
if(!M || !hivemembers.Find(M))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/antagonist/hivemind/proc/handle_ejection(mob/living/carbon/human/H)
|
||||
/datum/antagonist/hivemind/proc/remove_from_hive(mob/living/carbon/C)
|
||||
var/datum/mind/M = C.mind
|
||||
if(M)
|
||||
hivemembers -= M
|
||||
calc_size()
|
||||
|
||||
/datum/antagonist/hivemind/proc/handle_ejection(mob/living/carbon/C)
|
||||
var/user_warning = "The enemy host has been ejected from our mind"
|
||||
|
||||
if(!H || !owner)
|
||||
if(!C || !owner)
|
||||
return
|
||||
var/mob/living/carbon/C2 = owner.current
|
||||
if(!C2)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H2 = owner.current
|
||||
if(!H2)
|
||||
return
|
||||
|
||||
var/mob/living/real_H = H.get_real_hivehost()
|
||||
var/mob/living/real_H2 = H2.get_real_hivehost()
|
||||
|
||||
if(is_real_hivehost(H))
|
||||
real_H2.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, real_H)
|
||||
real_H.apply_status_effect(STATUS_EFFECT_HIVE_RADAR)
|
||||
to_chat(real_H, "<span class='userdanger'>We detect a surge of psionic energy from a far away vessel before they disappear from the hive. Whatever happened, there's a good chance they're after us now.</span>")
|
||||
if(is_real_hivehost(H2))
|
||||
real_H.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, real_H2)
|
||||
real_H2.apply_status_effect(STATUS_EFFECT_HIVE_RADAR)
|
||||
var/mob/living/real_C = C.get_real_hivehost()
|
||||
var/mob/living/real_C2 = C2.get_real_hivehost()
|
||||
var/datum/antagonist/hivemind/hive_C = C.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
var/datum/antagonist/hivemind/hive_C2 = C2.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(C != real_C) //Mind control check
|
||||
real_C2.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, real_C, hive_C.get_track_bonus(hive_C2))
|
||||
real_C.apply_status_effect(STATUS_EFFECT_HIVE_RADAR)
|
||||
to_chat(real_C, "<span class='assimilator'>We detect a surge of psionic energy from a far away vessel before they disappear from the hive. Whatever happened, there's a good chance they're after us now.</span>")
|
||||
if(C2 != real_C2)
|
||||
real_C.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, real_C2, hive_C2.get_track_bonus(hive_C) )
|
||||
real_C2.apply_status_effect(STATUS_EFFECT_HIVE_RADAR)
|
||||
user_warning += " and we've managed to pinpoint their location"
|
||||
|
||||
to_chat(H2, "<span class='userdanger'>[user_warning]!</span>")
|
||||
to_chat(C2, "<span class='userdanger'>[user_warning]!</span>")
|
||||
|
||||
/datum/antagonist/hivemind/proc/destroy_hive()
|
||||
hivemembers = list()
|
||||
@@ -93,8 +153,22 @@
|
||||
/datum/antagonist/hivemind/antag_panel_data()
|
||||
return "Vessels Assimilated: [hive_size]"
|
||||
|
||||
/datum/antagonist/hivemind/on_gain()
|
||||
/datum/antagonist/hivemind/proc/awaken()
|
||||
if(!owner?.current)
|
||||
return
|
||||
var/mob/living/carbon/C = owner.current.get_real_hivehost()
|
||||
if(!C)
|
||||
return
|
||||
active_one_mind = TRUE
|
||||
owner.AddSpell(new/obj/effect/proc_holder/spell/self/hive_comms)
|
||||
C.add_trait(TRAIT_STUNIMMUNE, HIVEMIND_ONE_MIND_TRAIT)
|
||||
C.add_trait(TRAIT_SLEEPIMMUNE, HIVEMIND_ONE_MIND_TRAIT)
|
||||
C.add_trait(TRAIT_VIRUSIMMUNE, HIVEMIND_ONE_MIND_TRAIT)
|
||||
C.add_trait(TRAIT_NOLIMBDISABLE, HIVEMIND_ONE_MIND_TRAIT)
|
||||
C.add_trait(TRAIT_NOHUNGER, HIVEMIND_ONE_MIND_TRAIT)
|
||||
C.add_trait(TRAIT_NODISMEMBER, HIVEMIND_ONE_MIND_TRAIT)
|
||||
|
||||
/datum/antagonist/hivemind/on_gain()
|
||||
owner.special_role = special_role
|
||||
check_powers()
|
||||
forge_objectives()
|
||||
@@ -120,8 +194,6 @@
|
||||
hud.leave_hud(owner.current)
|
||||
set_antag_hud(owner.current, null)
|
||||
|
||||
|
||||
|
||||
/datum/antagonist/hivemind/on_removal()
|
||||
//Remove all hive powers here
|
||||
for(var/power in upgrade_tiers)
|
||||
@@ -133,52 +205,19 @@
|
||||
..()
|
||||
|
||||
/datum/antagonist/hivemind/proc/forge_objectives()
|
||||
if(prob(65))
|
||||
if(prob(50))
|
||||
var/datum/objective/hivemind/hivesize/size_objective = new
|
||||
size_objective.owner = owner
|
||||
objectives += size_objective
|
||||
else
|
||||
else if(prob(70))
|
||||
var/datum/objective/hivemind/hiveescape/hive_escape_objective = new
|
||||
hive_escape_objective.owner = owner
|
||||
objectives += hive_escape_objective
|
||||
|
||||
if(prob(85))
|
||||
var/datum/objective/hivemind/assimilate/assim_objective = new
|
||||
assim_objective.owner = owner
|
||||
if(prob(25)) //Decently high chance to have to assimilate an implanted crew member
|
||||
assim_objective.find_target_by_role(pick("Captain","Head of Security","Security Officer","Detective","Warden"))
|
||||
if(!assim_objective.target) //If the prob doesn't happen or there are no implanted crew, find any target that isn't a hivemmind host
|
||||
assim_objective.find_target_by_role(role = ROLE_HIVE, role_type = TRUE, invert = TRUE)
|
||||
assim_objective.update_explanation_text()
|
||||
objectives += assim_objective
|
||||
else
|
||||
var/datum/objective/hivemind/biggest/biggest_objective = new
|
||||
biggest_objective.owner = owner
|
||||
objectives += biggest_objective
|
||||
|
||||
if(prob(85) && common_assimilation_obj) //If the mode rolled the versus objective IE common_assimilation_obj is not null, add a very high chance to get this
|
||||
var/datum/objective/hivemind/assimilate_common/versus_objective = new
|
||||
versus_objective.owner = owner
|
||||
versus_objective.target = common_assimilation_obj.target
|
||||
versus_objective.update_explanation_text()
|
||||
objectives += versus_objective
|
||||
else if(prob(70))
|
||||
var/giveit = TRUE
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
for(var/datum/objective/hivemind/assimilate/ass_obj in objectives)
|
||||
if(ass_obj.target == kill_objective.target)
|
||||
giveit = FALSE
|
||||
break
|
||||
if(giveit)
|
||||
objectives += kill_objective
|
||||
else
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = owner
|
||||
maroon_objective.find_target()
|
||||
objectives += maroon_objective
|
||||
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = owner
|
||||
objectives += escape_objective
|
||||
|
||||
78
code/modules/antagonists/hivemind/vessel.dm
Normal file
78
code/modules/antagonists/hivemind/vessel.dm
Normal file
@@ -0,0 +1,78 @@
|
||||
/datum/team/hivemind
|
||||
name = "One Mind"
|
||||
|
||||
/datum/antagonist/hivevessel
|
||||
name = "Awoken Vessel"
|
||||
job_rank = ROLE_BRAINWASHED
|
||||
roundend_category = "awoken vessels"
|
||||
show_in_antagpanel = TRUE
|
||||
antagpanel_category = "Other"
|
||||
show_name_in_check_antagonists = TRUE
|
||||
var/datum/team/hivemind/one_mind
|
||||
var/mutable_appearance/glow
|
||||
|
||||
/mob/living/proc/is_wokevessel()
|
||||
return mind?.has_antag_datum(/datum/antagonist/hivevessel)
|
||||
|
||||
/mob/living/proc/hive_awaken(objective, datum/team/final_form)
|
||||
if(!mind)
|
||||
return
|
||||
var/datum/mind/M = mind
|
||||
var/datum/antagonist/hivevessel/vessel = M.has_antag_datum(/datum/antagonist/hivevessel)
|
||||
if(!vessel)
|
||||
vessel = new()
|
||||
if(final_form)
|
||||
vessel.objectives = list() //Reset objectives on re-awoken vessels
|
||||
if(ishuman(M.current))
|
||||
vessel.glow = mutable_appearance('icons/effects/hivemind.dmi', "awoken", -BODY_BEHIND_LAYER)
|
||||
M.current.add_overlay(vessel.glow)
|
||||
M.AddSpell(new/obj/effect/proc_holder/spell/self/hive_comms)
|
||||
vessel.one_mind = final_form
|
||||
vessel.one_mind.add_member(M)
|
||||
vessel.objectives |= vessel.one_mind.objectives
|
||||
else
|
||||
var/datum/objective/brainwashing/obj = new(objective)
|
||||
vessel.objectives += obj
|
||||
M.add_antag_datum(vessel)
|
||||
var/message = "<span class='deadsay'><b>[M]</b> has been brainwashed with the following objectives: [objective]."
|
||||
deadchat_broadcast(message, follow_target = M, turf_target = get_turf(M), message_type=DEADCHAT_REGULAR)
|
||||
|
||||
/datum/antagonist/hivevessel/apply_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
if(!silent)
|
||||
to_chat(traitor_mob, "Our newfound powers allow us to overcome our clownish nature, allowing us to wield weapons with impunity.")
|
||||
traitor_mob.dna.remove_mutation(CLOWNMUT)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_HIVE]
|
||||
hud.join_hud(owner.current)
|
||||
set_antag_hud(owner.current, "hivevessel")
|
||||
|
||||
/datum/antagonist/hivevessel/remove_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
traitor_mob.dna.add_mutation(CLOWNMUT)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_HIVE]
|
||||
hud.leave_hud(owner.current)
|
||||
set_antag_hud(owner.current, null)
|
||||
|
||||
/datum/antagonist/hivevessel/greet()
|
||||
to_chat(owner, "<span class='assimilator'>Your mind is suddenly opened, as you see the pinnacle of evolution...</span>")
|
||||
to_chat(owner, "<big><span class='warning'><b>Follow your objectives, at any cost!</b></span></big>")
|
||||
var/i = 1
|
||||
for(var/X in objectives)
|
||||
var/datum/objective/O = X
|
||||
to_chat(owner, "<b>[i].</b> [O.explanation_text]")
|
||||
i++
|
||||
|
||||
/datum/antagonist/hivevessel/on_removal()
|
||||
if(owner?.current && glow)
|
||||
owner.current.cut_overlay(glow)
|
||||
if(one_mind && owner)
|
||||
one_mind.remove_member(owner)
|
||||
..()
|
||||
|
||||
/datum/antagonist/hivevessel/farewell()
|
||||
to_chat(owner, "<span class='assimilator'>Your mind closes up once more...</span>")
|
||||
to_chat(owner, "<big><span class='warning'><b>You feel the weight of your objectives disappear! You no longer have to obey them.</b></span></big>")
|
||||
@@ -376,6 +376,7 @@ h1.alert, h2.alert {color: #000000;}
|
||||
.alertalien {color: #00c000; font-weight: bold;}
|
||||
.changeling {color: #800080; font-style: italic;}
|
||||
.assimilator {color: #800080; font-size: 16px ; font-weight: bold;}
|
||||
.bigassimilator {color: #800080; font-size: 32px ; font-weight: bold;}
|
||||
|
||||
.spider {color: #4d004d;}
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
/mob/living/carbon/human/Initialize()
|
||||
verbs += /mob/living/proc/mob_sleep
|
||||
verbs += /mob/living/proc/lay_down
|
||||
|
||||
|
||||
icon_state = "" //Remove the inherent human icon that is visible on the map editor. We're rendering ourselves limb by limb, having it still be there results in a bug where the basic human icon appears below as south in all directions and generally looks nasty.
|
||||
|
||||
|
||||
//initialize limbs first
|
||||
create_bodyparts()
|
||||
|
||||
@@ -77,7 +77,8 @@
|
||||
stat("Absorbed DNA", changeling.absorbedcount)
|
||||
var/datum/antagonist/hivemind/hivemind = mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(hivemind)
|
||||
stat("Hivemind Vessels", hivemind.hive_size)
|
||||
stat("Hivemind Vessels", "[hivemind.hive_size] (+[hivemind.size_mod])")
|
||||
stat("Psychic Link Duration", "[(hivemind.track_bonus + TRACKER_DEFAULT_TIME)/10] seconds")
|
||||
|
||||
//NINJACODE
|
||||
if(istype(wear_suit, /obj/item/clothing/suit/space/space_ninja)) //Only display if actually a ninja.
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
. = initial(dt.flags) & TONGUELESS_SPEECH
|
||||
|
||||
/mob/living/carbon/hear_intercept(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
var/datum/status_effect/bugged/B = has_status_effect(STATUS_EFFECT_BUGGED)
|
||||
if(B)
|
||||
B.listening_in.show_message(message)
|
||||
for(var/T in get_traumas())
|
||||
var/datum/brain_trauma/trauma = T
|
||||
message = trauma.on_hear(message, speaker, message_language, raw_message, radio_freq)
|
||||
|
||||
@@ -14,22 +14,22 @@
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/choose_targets(mob/user = usr)
|
||||
var/datum/antagonist/hivemind/hive = user.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(!hive)
|
||||
if(!hive || !hive.hivemembers)
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
return
|
||||
var/list/possible_targets = list()
|
||||
var/list/targets = list()
|
||||
|
||||
if(target_external)
|
||||
for(var/mob/living/carbon/human/H in view_or_range(range, user, selection_type))
|
||||
for(var/mob/living/carbon/H in view_or_range(range, user, selection_type))
|
||||
if(user == H)
|
||||
continue
|
||||
if(!can_target(H))
|
||||
continue
|
||||
if(!hive.hivemembers.Find(H))
|
||||
if(!hive.is_carbon_member(H))
|
||||
possible_targets += H
|
||||
else
|
||||
possible_targets = hive.hivemembers.Copy()
|
||||
possible_targets = hive.get_carbon_members()
|
||||
if(range)
|
||||
possible_targets &= view_or_range(range, user, selection_type)
|
||||
|
||||
@@ -46,13 +46,13 @@
|
||||
selection_type = "view"
|
||||
action_icon_state = "add"
|
||||
|
||||
charge_max = 200
|
||||
charge_max = 50
|
||||
range = 7
|
||||
target_external = 1
|
||||
var/ignore_mindshield = FALSE
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_add/cast(list/targets, mob/living/user = usr)
|
||||
var/mob/living/carbon/human/target = targets[1]
|
||||
var/mob/living/carbon/target = targets[1]
|
||||
var/datum/antagonist/hivemind/hive = user.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
var/success = FALSE
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
success = TRUE
|
||||
hive.add_to_hive(target)
|
||||
if(ignore_mindshield)
|
||||
user.Immobilize(50)
|
||||
SEND_SIGNAL(target, COMSIG_NANITE_SET_VOLUME, 0)
|
||||
for(var/obj/item/implant/mindshield/M in target.implants)
|
||||
qdel(M)
|
||||
@@ -91,25 +92,34 @@
|
||||
selection_type = "view"
|
||||
action_icon_state = "remove"
|
||||
|
||||
charge_max = 100
|
||||
charge_max = 50
|
||||
range = 7
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_remove/cast(list/targets, mob/living/user = usr)
|
||||
var/mob/living/carbon/human/target = targets[1]
|
||||
var/mob/living/carbon/target = targets[1]
|
||||
|
||||
var/datum/antagonist/hivemind/hive = user.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(!hive)
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
return
|
||||
hive.hivemembers -= target
|
||||
var/datum/mind/M = target.mind
|
||||
if(!M)
|
||||
revert_cast()
|
||||
return
|
||||
hive.remove_from_hive(M)
|
||||
hive.calc_size()
|
||||
to_chat(user, "<span class='notice'>We remove [target.name] from the hive</span>")
|
||||
if(hive.active_one_mind)
|
||||
var/datum/antagonist/hivevessel/woke = target.is_wokevessel()
|
||||
if(woke)
|
||||
hive.active_one_mind.remove_member(M)
|
||||
M.remove_antag_datum(/datum/antagonist/hivevessel)
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_see
|
||||
name = "Hive Vision"
|
||||
desc = "We use the eyes of one of our vessels. Use again to look through our own eyes once more."
|
||||
action_icon_state = "see"
|
||||
var/mob/vessel
|
||||
var/mob/living/carbon/vessel
|
||||
var/mob/living/host //Didn't really have any other way to auto-reset the perspective if the other mob got qdeled
|
||||
|
||||
charge_max = 20
|
||||
@@ -122,6 +132,7 @@
|
||||
if(!active)
|
||||
vessel = targets[1]
|
||||
if(vessel)
|
||||
vessel.apply_status_effect(STATUS_EFFECT_BUGGED, user)
|
||||
user.reset_perspective(vessel)
|
||||
active = TRUE
|
||||
host = user
|
||||
@@ -129,6 +140,7 @@
|
||||
user.overlay_fullscreen("hive_eyes", /obj/screen/fullscreen/hive_eyes)
|
||||
revert_cast()
|
||||
else
|
||||
vessel.remove_status_effect(STATUS_EFFECT_BUGGED)
|
||||
user.reset_perspective()
|
||||
user.clear_fullscreen("hive_eyes")
|
||||
var/obj/effect/proc_holder/spell/target_hive/hive_control/the_spell = locate(/obj/effect/proc_holder/spell/target_hive/hive_control) in user.mind.spell_list
|
||||
@@ -141,7 +153,10 @@
|
||||
if(active && (!vessel || !is_hivemember(vessel) || QDELETED(vessel)))
|
||||
to_chat(host, "<span class='warning'>Our vessel is one of us no more!</span>")
|
||||
host.reset_perspective()
|
||||
host.clear_fullscreen("hive_eyes")
|
||||
active = FALSE
|
||||
if(!QDELETED(vessel))
|
||||
vessel.remove_status_effect(STATUS_EFFECT_BUGGED)
|
||||
..()
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_see/choose_targets(mob/user = usr)
|
||||
@@ -164,7 +179,7 @@
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>We begin increasing the psionic bandwidth between ourself and the vessel!</span>")
|
||||
if(do_after(user,60,0,user))
|
||||
if(do_after(user,30,0,user))
|
||||
var/power = 120-get_dist(user, target)
|
||||
if(!is_hivehost(target))
|
||||
switch(hive.hive_size)
|
||||
@@ -187,6 +202,77 @@
|
||||
to_chat(user, "<span class='notice'>Our concentration has been broken!</span>")
|
||||
revert_cast()
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/self/hive_scan
|
||||
name = "Psychoreception"
|
||||
desc = "We release a pulse to receive information on any enemies we have previously located via Network Invasion, as well as those currently tracking us."
|
||||
panel = "Hivemind Abilities"
|
||||
charge_max = 1800
|
||||
invocation_type = "none"
|
||||
clothes_req = 0
|
||||
human_req = 1
|
||||
action_icon = 'icons/mob/actions/actions_hive.dmi'
|
||||
action_background_icon_state = "bg_hive"
|
||||
action_icon_state = "scan"
|
||||
antimagic_allowed = TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/self/hive_scan/cast(mob/living/user = usr)
|
||||
var/datum/antagonist/hivemind/hive = user.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(!hive)
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
return
|
||||
var/message
|
||||
var/distance
|
||||
|
||||
for(var/datum/status_effect/hive_track/track in user.status_effects)
|
||||
var/mob/living/L = track.tracked_by
|
||||
if(!L)
|
||||
continue
|
||||
if(!do_after(user,5,0,user))
|
||||
to_chat(user, "<span class='notice'>Our concentration has been broken!</span>")
|
||||
break
|
||||
distance = get_dist(user, L)
|
||||
message = "[(L.is_real_hivehost()) ? "Someone": "A hivemind host"] tracking us"
|
||||
if(user.z != L.z || L.stat == DEAD)
|
||||
message += " could not be found."
|
||||
else
|
||||
switch(distance)
|
||||
if(0 to 2)
|
||||
message += " is right next to us!"
|
||||
if(2 to 14)
|
||||
message += " is nearby."
|
||||
if(14 to 28)
|
||||
message += " isn't too far away."
|
||||
if(28 to INFINITY)
|
||||
message += " is quite far away."
|
||||
to_chat(user, "<span class='assimilator'>[message]</span>")
|
||||
for(var/datum/antagonist/hivemind/enemy in hive.individual_track_bonus)
|
||||
if(!do_after(user,5,0,user))
|
||||
to_chat(user, "<span class='notice'>Our concentration has been broken!</span>")
|
||||
break
|
||||
var/mob/living/carbon/C = enemy.owner?.current
|
||||
if(!C)
|
||||
continue
|
||||
var/mob/living/real_enemy = C.get_real_hivehost()
|
||||
distance = get_dist(user, real_enemy)
|
||||
message = "A host that we can track for [(hive.individual_track_bonus[enemy])/10] extra seconds"
|
||||
if(user.z != real_enemy.z || real_enemy.stat == DEAD)
|
||||
message += " could not be found."
|
||||
else
|
||||
switch(distance)
|
||||
if(0 to 2)
|
||||
message += " is right next to us!"
|
||||
if(2 to 14)
|
||||
if(enemy.get_threat_multiplier() >= 0.85 && distance <= 7)
|
||||
message += " is in this very room!"
|
||||
else
|
||||
message += " is nearby."
|
||||
if(14 to 28)
|
||||
message += " isn't too far away."
|
||||
if(28 to INFINITY)
|
||||
message += " is quite far away."
|
||||
to_chat(user, "<span class='assimilator'>[message]</span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/self/hive_drain
|
||||
name = "Repair Protocol"
|
||||
desc = "Our many vessels sacrifice a small portion of their mind's vitality to cure us of our physical and mental ailments."
|
||||
@@ -206,13 +292,15 @@
|
||||
if(!hive || !hive.hivemembers)
|
||||
return
|
||||
var/iterations = 0
|
||||
|
||||
var/list/carbon_members = hive.get_carbon_members()
|
||||
if(!carbon_members.len)
|
||||
return
|
||||
if(!user.getBruteLoss() && !user.getFireLoss() && !user.getCloneLoss() && !user.getBrainLoss())
|
||||
to_chat(user, "<span class='notice'>We cannot heal ourselves any more with this power!</span>")
|
||||
revert_cast()
|
||||
to_chat(user, "<span class='notice'>We begin siphoning power from our many vessels!</span>")
|
||||
while(iterations < 7)
|
||||
var/mob/living/carbon/human/target = pick(hive.hivemembers)
|
||||
var/mob/living/carbon/target = pick(carbon_members)
|
||||
if(!do_after(user,15,0,user))
|
||||
to_chat(user, "<span class='warning'>Our concentration has been broken!</span>")
|
||||
break
|
||||
@@ -248,14 +336,15 @@
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_control
|
||||
name = "Mind Control"
|
||||
desc = "We assume direct control of one of our vessels, leaving our current body for up to ten seconds, although a larger hive may be able to sustain it for up to two minutes. It can be cancelled at any time by casting it again. Powers can be used via our vessel, although if it dies, the entire hivemind will come down with it. Our ability to sense psionic energy is completely nullified while using this power."
|
||||
charge_max = 600
|
||||
desc = "We assume direct control of one of our vessels, leaving our current body for up to a minute. It can be cancelled at any time by casting it again. Powers can be used via our vessel, although if it dies, the entire hivemind will come down with it. Our ability to sense psionic energy is completely nullified while using this power, and it will end immediately should we attempt to move too far from our starting point."
|
||||
charge_max = 1500
|
||||
action_icon_state = "force"
|
||||
active = FALSE
|
||||
var/mob/living/carbon/human/original_body //The original hivemind host
|
||||
var/mob/living/carbon/human/vessel
|
||||
var/mob/living/passenger/backseat //Storage for the mind controlled vessel
|
||||
var/power = 100
|
||||
var/turf/starting_spot
|
||||
var/power = 600
|
||||
var/time_initialized = 0
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_control/proc/release_control() //If the spell is active, force everybody into their original bodies if they exist, ghost them otherwise, delete the backseat
|
||||
@@ -288,10 +377,8 @@
|
||||
if(original_body?.mind)
|
||||
var/datum/antagonist/hivemind/hive = original_body.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(hive)
|
||||
if((world.time-time_initialized) <= 300)
|
||||
hive.threat_level += 0.5
|
||||
else
|
||||
hive.threat_level += 1
|
||||
hive.threat_level += 0.5
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_control/on_lose(mob/user)
|
||||
release_control()
|
||||
@@ -303,19 +390,6 @@
|
||||
if(!hive)
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
return
|
||||
switch(hive.hive_size)
|
||||
if(10 to 14)
|
||||
power = 100
|
||||
charge_max = 600
|
||||
if(15 to 19)
|
||||
power = 300
|
||||
charge_max = 900
|
||||
if(20 to 24)
|
||||
power = 600
|
||||
charge_max = 1200
|
||||
else
|
||||
power = 1200
|
||||
charge_max = 1200
|
||||
original_body = user
|
||||
vessel = targets[1]
|
||||
to_chat(user, "<span class='notice'>We begin merging our mind with [vessel.name].</span>")
|
||||
@@ -354,6 +428,7 @@
|
||||
backseat.blind_eyes(power)
|
||||
vessel.overlay_fullscreen("hive_mc", /obj/screen/fullscreen/hive_mc)
|
||||
active = TRUE
|
||||
starting_spot = get_turf(vessel)
|
||||
time_initialized = world.time
|
||||
revert_cast()
|
||||
to_chat(vessel, "<span class='assimilator'>We can sustain our control for a maximum of [round(power/10)] seconds.</span>")
|
||||
@@ -373,10 +448,10 @@
|
||||
if(QDELETED(vessel)) //If we've been gibbed or otherwise deleted, ghost both of them and kill the original
|
||||
original_body.adjustBrainLoss(200)
|
||||
release_control()
|
||||
else if(!is_hivemember(vessel)) //If the vessel is no longer a hive member, return to original bodies
|
||||
else if(!is_hivemember(backseat)) //If the vessel is no longer a hive member, return to original bodies
|
||||
to_chat(vessel, "<span class='warning'>Our vessel is one of us no more!</span>")
|
||||
release_control()
|
||||
else if(!QDELETED(original_body) && (!vessel.ckey || vessel.stat == DEAD)) //If the original body exists and the vessel is dead/ghosted, return both to body but not before killing the original
|
||||
else if(!QDELETED(original_body) && (!backseat.ckey || vessel.stat == DEAD)) //If the original body exists and the vessel is dead/ghosted, return both to body but not before killing the original
|
||||
original_body.adjustBrainLoss(200)
|
||||
to_chat(vessel.mind, "<span class='warning'>Our vessel is one of us no more!</span>")
|
||||
release_control()
|
||||
@@ -386,6 +461,11 @@
|
||||
else if(QDELETED(original_body) || original_body.stat == DEAD) //Return vessel to its body, either return or ghost the original
|
||||
to_chat(vessel, "<span class='userdanger'>Our body has been destroyed, the hive cannot survive without its host!</span>")
|
||||
release_control()
|
||||
else if(get_dist(starting_spot, vessel) > 14)
|
||||
vessel.blur_eyes(20)
|
||||
if(prob(35))
|
||||
to_chat(vessel, "<span class='warning'>Our vessel has been moved too far away from the initial point of control and has been disconnected!</span>")
|
||||
release_control()
|
||||
|
||||
..()
|
||||
|
||||
@@ -397,7 +477,7 @@
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/induce_panic
|
||||
name = "Induce Panic"
|
||||
desc = "We unleash a burst of psionic energy, inducing a debilitating fear in those around us and reducing their combat readiness. Mindshielded foes have a chance to resist this power."
|
||||
desc = "We unleash a burst of psionic energy, inducing a debilitating fear in those around us and reducing their combat readiness. We can also briefly affect silicon-based life with this burst."
|
||||
panel = "Hivemind Abilities"
|
||||
charge_max = 900
|
||||
range = 7
|
||||
@@ -415,13 +495,13 @@
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
return
|
||||
for(var/mob/living/carbon/human/target in targets)
|
||||
if(target.has_trait(TRAIT_MINDSHIELD) && prob(50-hive.hive_size)) //Mindshielded targets resist panic pretty well
|
||||
continue
|
||||
if(target.stat == DEAD)
|
||||
continue
|
||||
target.Jitter(14)
|
||||
target.apply_damage(min(35,hive.hive_size), STAMINA, target.get_bodypart(BODY_ZONE_HEAD))
|
||||
if(prob(50))
|
||||
target.apply_damage(35 + rand(0,15), STAMINA, target.get_bodypart(BODY_ZONE_HEAD))
|
||||
if(target.is_real_hivehost())
|
||||
continue
|
||||
if(prob(20))
|
||||
var/text = pick(";HELP!","I'm losing control of the situation!!","Get me outta here!")
|
||||
target.say(text, forced = "panic")
|
||||
var/effect = rand(1,4)
|
||||
@@ -436,16 +516,52 @@
|
||||
addtimer(CALLBACK(target, "click_random_mob"), 10)
|
||||
addtimer(CALLBACK(target, "click_random_mob"), 15)
|
||||
addtimer(CALLBACK(target, "click_random_mob"), 20)
|
||||
target.Dizzy(2)
|
||||
addtimer(CALLBACK(target, "Stun", 30), 25)
|
||||
target.confused += 10
|
||||
if(3)
|
||||
to_chat(target, "<span class='userdanger'>You freeze up in fear!</span>")
|
||||
target.Stun(70)
|
||||
if(4)
|
||||
to_chat(target, "<span class='userdanger'>You feel nauseous as dread washes over you!</span>")
|
||||
target.Dizzy(15)
|
||||
target.apply_damage(45, STAMINA, target.get_bodypart(BODY_ZONE_HEAD))
|
||||
target.apply_damage(30, STAMINA, target.get_bodypart(BODY_ZONE_HEAD))
|
||||
target.hallucination += 45
|
||||
|
||||
for(var/mob/living/silicon/target in targets)
|
||||
target.Unconscious(50)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/induce_sleep
|
||||
name = "Circadian Shift"
|
||||
desc = "We send out a controlled pulse of psionic energy, temporarily causing a deep sleep to anybody in sight, even in silicon-based lifeforms. The fewer people in sight, the more effective this power is. The weak mind of a vessels cannot handle this ability, using Mind Control and this at the same time would be most unwise."
|
||||
panel = "Hivemind Abilities"
|
||||
charge_max = 1200
|
||||
range = 7
|
||||
invocation_type = "none"
|
||||
clothes_req = 0
|
||||
max_targets = 0
|
||||
include_user = 1 //Checks for real hivemind hosts during the cast, won't smack you unless using mind control
|
||||
antimagic_allowed = TRUE
|
||||
action_icon = 'icons/mob/actions/actions_hive.dmi'
|
||||
action_background_icon_state = "bg_hive"
|
||||
action_icon_state = "sleep"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/induce_sleep/cast(list/targets, mob/living/user = usr)
|
||||
if(!targets)
|
||||
to_chat(user, "<span class='notice'>Nobody is in sight, it'd be a waste to do that now.</span>")
|
||||
revert_cast()
|
||||
return
|
||||
var/list/victims = list()
|
||||
for(var/mob/living/target in targets)
|
||||
if(target.stat == DEAD)
|
||||
continue
|
||||
if(target.is_real_hivehost() || (!iscarbon(target) && !issilicon(target)))
|
||||
continue
|
||||
victims += target
|
||||
for(var/mob/living/carbon/victim in victims)
|
||||
victim.Sleeping(max(80,240/(1+round(victims.len/3))))
|
||||
for(var/mob/living/silicon/victim in victims)
|
||||
victim.Unconscious(240)
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_attack
|
||||
name = "Medullary Failure"
|
||||
desc = "We overload the target's medulla, inducing an immediate heart attack."
|
||||
@@ -454,7 +570,7 @@
|
||||
action_icon_state = "attack"
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_attack/cast(list/targets, mob/living/user = usr)
|
||||
var/mob/living/carbon/human/target = targets[1]
|
||||
var/mob/living/carbon/target = targets[1]
|
||||
if(!target.undergoing_cardiac_arrest() && target.can_heartattack())
|
||||
target.set_heartattack(TRUE)
|
||||
to_chat(target, "<span class='userdanger'>You feel a sharp pain, and foreign presence in your mind!!</span>")
|
||||
@@ -476,7 +592,7 @@
|
||||
action_icon_state = "warp"
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_warp/cast(list/targets, mob/living/user = usr)
|
||||
var/mob/living/carbon/human/target = targets[1]
|
||||
var/mob/living/carbon/target = targets[1]
|
||||
var/datum/antagonist/hivemind/hive = user.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(!hive)
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
@@ -485,12 +601,12 @@
|
||||
to_chat(user, "<span class='notice'>We are too far away from [target.name] to affect them!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>We successfully distort reality surrounding [target.name]!</span>")
|
||||
var/pulse_cap = min(12,max(6, round(3+hive.hive_size/3)))
|
||||
var/pulse_cap = min(12, 8+(round(hive.hive_size/20)))
|
||||
distort(user, target, pulse_cap)
|
||||
|
||||
/obj/effect/proc_holder/spell/target_hive/hive_warp/proc/distort(user, target, pulse_cap, pulses = 0)
|
||||
for(var/mob/living/carbon/human/victim in view(7,target))
|
||||
if(user == victim)
|
||||
if(user == victim || victim.is_real_hivehost())
|
||||
continue
|
||||
if(pulses < 4)
|
||||
victim.apply_damage(10, STAMINA, victim.get_bodypart(BODY_ZONE_HEAD)) // 25 over 10 seconds when taking stamina regen (3 per tick(2 seconds)) into account
|
||||
@@ -524,8 +640,8 @@
|
||||
if(!hive)
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
return
|
||||
var/mob/living/carbon/human/target = targets[1]
|
||||
var/in_hive = hive.hivemembers.Find(target)
|
||||
var/mob/living/carbon/target = targets[1]
|
||||
var/in_hive = hive.is_carbon_member(target)
|
||||
var/list/enemies = list()
|
||||
|
||||
to_chat(user, "<span class='notice'>We begin probing [target.name]'s mind!</span>")
|
||||
@@ -538,25 +654,34 @@
|
||||
return
|
||||
for(var/datum/antagonist/hivemind/enemy in GLOB.antagonists)
|
||||
var/datum/mind/M = enemy.owner
|
||||
if(M?.current == user)
|
||||
if(!M?.current)
|
||||
continue
|
||||
if(enemy.hivemembers.Find(target))
|
||||
if(M.current == user)
|
||||
continue
|
||||
if(enemy.is_carbon_member(target))
|
||||
hive.add_track_bonus(enemy, TRACKER_BONUS_LARGE)
|
||||
var/mob/living/real_enemy = (M.current.get_real_hivehost())
|
||||
enemies += real_enemy
|
||||
enemy.remove_from_hive(target)
|
||||
real_enemy.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, user)
|
||||
if(is_real_hivehost(M.current)) //If they were using mind control, too bad
|
||||
real_enemy.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, user, hive.get_track_bonus(enemy))
|
||||
if(M.current.is_real_hivehost()) //If they were using mind control, too bad
|
||||
real_enemy.apply_status_effect(STATUS_EFFECT_HIVE_RADAR)
|
||||
target.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, real_enemy)
|
||||
to_chat(real_enemy, "<span class='userdanger'>We detect a surge of psionic energy from a far away vessel before they disappear from the hive. Whatever happened, there's a good chance they're after us now.</span>")
|
||||
target.apply_status_effect(STATUS_EFFECT_HIVE_TRACKER, real_enemy, enemy.get_track_bonus(hive))
|
||||
to_chat(real_enemy, "<span class='assimilator'>We detect a surge of psionic energy from a far away vessel before they disappear from the hive. Whatever happened, there's a good chance they're after us now.</span>")
|
||||
|
||||
if(enemy.owner == target && is_real_hivehost(target))
|
||||
user.Stun(70)
|
||||
user.Jitter(14)
|
||||
if(enemy.owner == M && target.is_real_hivehost())
|
||||
var/atom/throwtarget
|
||||
throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(user, src)))
|
||||
SEND_SOUND(user, sound(pick('sound/hallucinations/turn_around1.ogg','sound/hallucinations/turn_around2.ogg'),0,1,50))
|
||||
flash_color(user, flash_color="#800080", flash_time=10)
|
||||
user.Paralyze(10)
|
||||
user.throw_at(throwtarget, 5, 1,src)
|
||||
to_chat(user, "<span class='userdanger'>A sudden surge of psionic energy rushes into your mind, only a Hive host could have such power!!</span>")
|
||||
return
|
||||
if(enemies.len)
|
||||
hive.track_bonus += TRACKER_BONUS_SMALL
|
||||
to_chat(user, "<span class='userdanger'>In a moment of clarity, we see all. Another hive. Faces. Our nemesis. They have heard our call. They know we are coming.</span>")
|
||||
to_chat(user, "<span class='assimilator'>This vision has provided us insight on our very nature, improving our sensory abilities, particularly against the hives this vessel belonged to.</span>")
|
||||
user.apply_status_effect(STATUS_EFFECT_HIVE_RADAR)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>We peer into the inner depths of their mind and see nothing, no enemies lurk inside this mind.</span>")
|
||||
@@ -564,75 +689,103 @@
|
||||
to_chat(user, "<span class='notice'>Our concentration has been broken!</span>")
|
||||
revert_cast()
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/hive_assim
|
||||
name = "Mass Assimilation"
|
||||
desc = "Should we capture an enemy Hive host, we can assimilate their entire hive into ours. It is unlikely their mind will surive the ordeal."
|
||||
/obj/effect/proc_holder/spell/targeted/hive_reclaim
|
||||
name = "Reclaim"
|
||||
desc = "Allows us to instantly syphon the psionic energy from an adjacent critically injured host, killing them immediately. If it succeeds, we will be able to advance our own powers a great deal."
|
||||
panel = "Hivemind Abilities"
|
||||
charge_max = 3000
|
||||
charge_max = 600
|
||||
range = 1
|
||||
max_targets = 0
|
||||
invocation_type = "none"
|
||||
clothes_req = 0
|
||||
max_targets = 1
|
||||
human_req = 1
|
||||
action_icon = 'icons/mob/actions/actions_hive.dmi'
|
||||
action_background_icon_state = "bg_hive"
|
||||
action_icon_state = "assim"
|
||||
action_icon_state = "reclaim"
|
||||
antimagic_allowed = TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/hive_assim/cast(list/targets, mob/living/user = usr)
|
||||
/obj/effect/proc_holder/spell/targeted/hive_reclaim/cast(list/targets, mob/living/user = usr)
|
||||
var/datum/antagonist/hivemind/hive = user.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(!hive)
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
return
|
||||
var/mob/living/carbon/human/target = targets[1]
|
||||
var/found_target = FALSE
|
||||
var/gibbed = FALSE
|
||||
|
||||
to_chat(user, "<span class='notice'>We tear into [target.name]'s mind with all our power!</span>")
|
||||
to_chat(target, "<span class='userdanger'>You feel an excruciating pain in your head!</span>")
|
||||
if(do_after(user,150,1,target))
|
||||
if(!target.mind)
|
||||
to_chat(user, "<span class='notice'>This being has no mind!</span>")
|
||||
revert_cast()
|
||||
return
|
||||
var/datum/antagonist/hivemind/enemy_hive = target.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(enemy_hive)
|
||||
deadchat_broadcast("<span class='deadsay'>A hivemind host is about to get assimilated!</span>", target)
|
||||
to_chat(user, "<span class='danger'>We begin assimilating every psionic link we can find!.</span>")
|
||||
to_chat(target, "<span class='userdanger'>Our grip on our mind is slipping!</span>")
|
||||
target.Jitter(14)
|
||||
target.setBrainLoss(125)
|
||||
if(do_after(user,300,1,target))
|
||||
enemy_hive = target.mind.has_antag_datum(/datum/antagonist/hivemind) //Check again incase they lost it somehow
|
||||
if(enemy_hive)
|
||||
to_chat(user, "<span class='userdanger'>Ours. It is ours. Our mind has never been stronger, never been larger, never been mightier. And theirs is no more.</span>")
|
||||
to_chat(target, "<span class='userdanger'>Our vessels, they're! That's impossible! We can't... we can't... </span><span class ='notice'>I can't...</span>")
|
||||
hive.hivemembers |= enemy_hive.hivemembers
|
||||
enemy_hive.hivemembers = list()
|
||||
hive.calc_size()
|
||||
enemy_hive.calc_size()
|
||||
target.setBrainLoss(200)
|
||||
for(var/mob/living/carbon/C in targets)
|
||||
if(!is_hivehost(C))
|
||||
continue
|
||||
if(C.InCritical())
|
||||
C.gib()
|
||||
hive.track_bonus += TRACKER_BONUS_LARGE
|
||||
hive.size_mod += 5
|
||||
gibbed = TRUE
|
||||
found_target = TRUE
|
||||
else if(C.IsUnconscious())
|
||||
C.adjustOxyLoss(100)
|
||||
found_target = TRUE
|
||||
|
||||
message_admins("[ADMIN_LOOKUPFLW(target)] was killed and had their hive stolen by [ADMIN_LOOKUPFLW(user)].")
|
||||
log_game("[key_name(target)] was killed via Mass Assimilation by [key_name(user)].")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>It seems we have been mistaken, this mind is not the host of a hive.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='userdanger'>Our concentration has been broken, leaving our mind wide open for a counterattack!</span>")
|
||||
to_chat(target, "<span class='userdanger'>Their concentration has been broken... leaving them wide open for a counterattack!</span>")
|
||||
user.Unconscious(120)
|
||||
user.adjustStaminaLoss(70)
|
||||
user.Jitter(60)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>We appear to have made a mistake... this mind is too weak to be the one we're looking for.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Our concentration has been broken!</span>")
|
||||
if(!found_target)
|
||||
revert_cast()
|
||||
return
|
||||
|
||||
flash_color(user, flash_color="#800080", flash_time=10)
|
||||
if(gibbed)
|
||||
to_chat(user,"<span class='assimilator'>We have reclaimed what gifts weaker minds were squandering and gain ever more insight on our psionic abilities.</span>")
|
||||
to_chat(user,"<span class='assimilator'>Thanks to this new knowledge, our sensory powers last a great deal longer.</span>")
|
||||
hive.check_powers()
|
||||
|
||||
/obj/effect/proc_holder/spell/self/hive_wake
|
||||
name = "Chaos Induction"
|
||||
desc = "A one-use power, we awaken four random vessels within our hive and force them to do our bidding."
|
||||
panel = "Hivemind Abilities"
|
||||
charge_type = "charges"
|
||||
charge_max = 1
|
||||
invocation_type = "none"
|
||||
clothes_req = 0
|
||||
human_req = 1
|
||||
action_icon = 'icons/mob/actions/actions_hive.dmi'
|
||||
action_background_icon_state = "bg_hive"
|
||||
action_icon_state = "chaos"
|
||||
antimagic_allowed = TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/self/hive_wake/cast(mob/living/user = usr)
|
||||
var/datum/antagonist/hivemind/hive = user.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(!hive)
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
return
|
||||
if(!hive.hivemembers)
|
||||
return
|
||||
var/list/valid_targets = list()
|
||||
for(var/datum/mind/M in hive.hivemembers)
|
||||
var/mob/living/carbon/C = M.current
|
||||
if(!C)
|
||||
continue
|
||||
if(is_hivehost(C) || C.is_wokevessel())
|
||||
continue
|
||||
if(C.stat == DEAD || C.InCritical())
|
||||
continue
|
||||
valid_targets += C
|
||||
|
||||
if(!valid_targets || valid_targets.len < 4)
|
||||
to_chat(user, "<span class='assimilator'>We lack the vessels to use this power.</span>")
|
||||
revert_cast()
|
||||
return
|
||||
|
||||
var/objective = stripped_input(user, "What objective do you want to give to your vessels?", "Objective")
|
||||
|
||||
for(var/i = 0, i < 4, i++)
|
||||
var/mob/living/carbon/C = pick_n_take(valid_targets)
|
||||
C.hive_awaken(objective)
|
||||
|
||||
/obj/effect/proc_holder/spell/self/hive_loyal
|
||||
name = "Bruteforce"
|
||||
desc = "Our ability to assimilate is temporarily boosted, allowing us to crush the technology shielding the minds of Security and Command personnel and assimilate them."
|
||||
desc = "Our ability to assimilate is boosted at the cost of, allowing us to crush the technology shielding the minds of Security and Command personnel and assimilate them. This power comes at a small price, and we will be immobilized for a few seconds after assimilation."
|
||||
panel = "Hivemind Abilities"
|
||||
charge_max = 1200
|
||||
charge_max = 600
|
||||
invocation_type = "none"
|
||||
clothes_req = 0
|
||||
human_req = 1
|
||||
action_icon = 'icons/mob/actions/actions_hive.dmi'
|
||||
action_background_icon_state = "bg_hive"
|
||||
action_icon_state = "loyal"
|
||||
@@ -644,13 +797,12 @@
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
return
|
||||
var/obj/effect/proc_holder/spell/target_hive/hive_add/the_spell = locate(/obj/effect/proc_holder/spell/target_hive/hive_add) in user.mind.spell_list
|
||||
if(the_spell)
|
||||
the_spell.ignore_mindshield = TRUE
|
||||
to_chat(user, "<span class='notice'>We prepare to crush mindshielding technology!</span>")
|
||||
addtimer(VARSET_CALLBACK(the_spell, ignore_mindshield, FALSE), 300)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, user, "<span class='warning'>Our heightened power wears off, we are once again unable to assimilate mindshielded crew.</span>"), 300)
|
||||
else
|
||||
if(!the_spell)
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE5</span>")
|
||||
return
|
||||
the_spell.ignore_mindshield = !active
|
||||
to_chat(user, "<span class='notice'>We [active?"let our minds rest and cancel our crushing power.":"prepare to crush mindshielding technology!"]</span>")
|
||||
active = !active
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/forcewall/hive
|
||||
name = "Telekinetic Field"
|
||||
@@ -658,6 +810,7 @@
|
||||
panel = "Hivemind Abilities"
|
||||
charge_max = 600
|
||||
clothes_req = 0
|
||||
human_req = 1
|
||||
invocation_type = "none"
|
||||
action_icon = 'icons/mob/actions/actions_hive.dmi'
|
||||
action_background_icon_state = "bg_hive"
|
||||
@@ -695,3 +848,90 @@
|
||||
pixel_x = 0
|
||||
pixel_y = 0
|
||||
invisibility = INVISIBILITY_MAXIMUM
|
||||
|
||||
/obj/effect/proc_holder/spell/self/one_mind
|
||||
name = "One Mind"
|
||||
desc = "Our true power... finally within reach."
|
||||
panel = "Hivemind Abilities"
|
||||
charge_type = "charges"
|
||||
charge_max = 1
|
||||
invocation_type = "none"
|
||||
clothes_req = 0
|
||||
human_req = 1
|
||||
action_icon = 'icons/mob/actions/actions_hive.dmi'
|
||||
action_background_icon_state = "bg_hive"
|
||||
action_icon_state = "assim"
|
||||
antimagic_allowed = TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/self/one_mind/cast(mob/living/user = usr)
|
||||
var/datum/antagonist/hivemind/hive = user.mind.has_antag_datum(/datum/antagonist/hivemind)
|
||||
if(!hive)
|
||||
to_chat(user, "<span class='notice'>This is a bug. Error:HIVE1</span>")
|
||||
return
|
||||
var/mob/living/boss = user.get_real_hivehost()
|
||||
var/datum/objective/objective = "Ensure the One Mind survives under the leadership of [boss.real_name]!"
|
||||
var/datum/team/hivemind/one_mind_team = new /datum/team/hivemind(user.mind)
|
||||
hive.active_one_mind = one_mind_team
|
||||
one_mind_team.objectives += objective
|
||||
for(var/datum/antagonist/hivevessel/vessel in GLOB.antagonists)
|
||||
var/mob/living/carbon/C = vessel.owner?.current
|
||||
if(hive.is_carbon_member(C))
|
||||
vessel.one_mind = one_mind_team
|
||||
for(var/datum/antagonist/hivemind/enemy in GLOB.antagonists)
|
||||
if(enemy.owner)
|
||||
enemy.owner.RemoveSpell(new/obj/effect/proc_holder/spell/self/one_mind)
|
||||
sound_to_playing_players('sound/effects/one_mind.ogg')
|
||||
hive.glow = mutable_appearance('icons/effects/hivemind.dmi', "awoken", -BODY_BEHIND_LAYER)
|
||||
addtimer(CALLBACK(user, /atom/proc/add_overlay, hive.glow), 150)
|
||||
addtimer(CALLBACK(hive, /datum/antagonist/hivemind/proc/awaken), 150)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/send_to_playing_players, "<span class='bigassimilator'>THE ONE MIND RISES</span>"), 150)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/sound_to_playing_players, 'sound/effects/magic.ogg'), 150)
|
||||
for(var/datum/mind/M in hive.hivemembers)
|
||||
var/mob/living/carbon/C = M.current
|
||||
if(!C)
|
||||
continue
|
||||
if(is_hivehost(C))
|
||||
continue
|
||||
if(C.stat == DEAD)
|
||||
continue
|
||||
C.Jitter(15)
|
||||
C.Unconscious(150)
|
||||
to_chat(C, "<span class='boldwarning'>Something's wrong...</span>")
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, C, "<span class='boldwarning'>...your memories are becoming fuzzy.</span>"), 45)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, C, "<span class='boldwarning'>You try to remember who you are...</span>"), 90)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, C, "<span class='assimilator'>There is no you...</span>"), 110)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, C, "<span class='bigassimilator'>...there is only us.</span>"), 130)
|
||||
addtimer(CALLBACK(C, /mob/living/proc/hive_awaken, objective, one_mind_team), 150)
|
||||
addtimer(CALLBACK(one_mind_team, /datum/team/proc/add_member, C.mind), 150)
|
||||
|
||||
/obj/effect/proc_holder/spell/self/hive_comms
|
||||
name = "Hive Communication"
|
||||
desc = "Now that we are free we may finally share our thoughts with our many bretheren."
|
||||
panel = "Hivemind Abilities"
|
||||
charge_max = 100
|
||||
invocation_type = "none"
|
||||
clothes_req = 0
|
||||
human_req = 1
|
||||
action_icon = 'icons/mob/actions/actions_hive.dmi'
|
||||
action_background_icon_state = "bg_hive"
|
||||
action_icon_state = "comms"
|
||||
antimagic_allowed = TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/self/hive_comms/cast(mob/living/user = usr)
|
||||
var/message = stripped_input(user, "What do you want to say?", "Hive Communication")
|
||||
if(!message)
|
||||
return
|
||||
var/title = "One Mind"
|
||||
var/span = "changeling"
|
||||
if(user.mind && user.mind.has_antag_datum(/datum/antagonist/hivemind))
|
||||
span = "assimilator"
|
||||
var/my_message = "<span class='[span]'><b>[title] [findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]:</b> [message]</span>"
|
||||
for(var/i in GLOB.player_list)
|
||||
var/mob/M = i
|
||||
if(is_hivehost(M) || is_hivemember(M))
|
||||
to_chat(M, my_message)
|
||||
else if(M in GLOB.dead_mob_list)
|
||||
var/link = FOLLOW_LINK(M, user)
|
||||
to_chat(M, "[link] [my_message]")
|
||||
|
||||
user.log_talk(message, LOG_SAY, tag="hive")
|
||||
BIN
icons/effects/hivemind.dmi
Normal file
BIN
icons/effects/hivemind.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 831 B |
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -136,6 +136,7 @@ h1.alert, h2.alert {color: #000000;}
|
||||
.alertalien {color: #00c000; font-weight: bold;}
|
||||
.changeling {color: #800080; font-style: italic;}
|
||||
.assimilator {color: #800080; font-size: 2 ; font-weight: bold;}
|
||||
.bigassimilator {color: #800080; font-size: 4 ; font-weight: bold;}
|
||||
|
||||
.spider {color: #4d004d;}
|
||||
|
||||
|
||||
2
sound/effects/license.txt
Normal file
2
sound/effects/license.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
one_mind.ogg is Mars Attacks Sounds, by Mike Koenig (http://soundbible.com/1047-Mars-Attacks.html). It has been licensed under CC-BY 3.0 license.
|
||||
It is unaltered ingame
|
||||
BIN
sound/effects/one_mind.ogg
Normal file
BIN
sound/effects/one_mind.ogg
Normal file
Binary file not shown.
@@ -1289,6 +1289,7 @@
|
||||
#include "code\modules\antagonists\greentext\greentext.dm"
|
||||
#include "code\modules\antagonists\highlander\highlander.dm"
|
||||
#include "code\modules\antagonists\hivemind\hivemind.dm"
|
||||
#include "code\modules\antagonists\hivemind\vessel.dm"
|
||||
#include "code\modules\antagonists\magic_servant\servant.dm"
|
||||
#include "code\modules\antagonists\monkey\monkey.dm"
|
||||
#include "code\modules\antagonists\morph\morph.dm"
|
||||
|
||||
Reference in New Issue
Block a user