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:
Kierany9
2019-02-13 02:02:23 +01:00
committed by moo
parent 18bdc8f6a4
commit 14fa6040e5
21 changed files with 624 additions and 270 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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 ..()

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View 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>")

View File

@@ -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;}

View File

@@ -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.

View File

@@ -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)

View File

@@ -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

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

View File

@@ -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;}

View 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

Binary file not shown.

View File

@@ -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"