diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index 6b6e077206c..f6e74ef2aad 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -79,10 +79,11 @@
mouse_opacity = 1
var/timeout = 0 //If set to a number, this alert will clear itself after that many deciseconds
var/severity = 0
+ var/alerttooltipstyle = ""
/obj/screen/alert/MouseEntered(location,control,params)
- openToolTip(usr,src,params,title = name,content = desc)
+ openToolTip(usr,src,params,title = name,content = desc,theme = alerttooltipstyle)
/obj/screen/alert/MouseExited()
@@ -234,6 +235,19 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
name = "Charge Ready"
desc = "You are ready to charge at a location!"
icon_state = "guardian_charge"
+ alerttooltipstyle = "parasite"
+
+/obj/screen/alert/canstealth
+ name = "Stealth Ready"
+ desc = "You are ready to enter stealth!"
+ icon_state = "guardian_canstealth"
+ alerttooltipstyle = "parasite"
+
+/obj/screen/alert/instealth
+ name = "In Stealth"
+ desc = "You are in stealth and your next attack will do bonus damage!"
+ icon_state = "guardian_instealth"
+ alerttooltipstyle = "parasite"
//SILICONS
diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm
index 9a6e194c02d..efc7a1ea732 100644
--- a/code/game/objects/effects/overlays.dm
+++ b/code/game/objects/effects/overlays.dm
@@ -73,13 +73,15 @@
/obj/effect/overlay/temp/guardian/phase/out
icon_state = "phaseout"
-/obj/effect/overlay/temp/guardian/charge
+/obj/effect/overlay/temp/decoy
+ desc = "It's a decoy!"
duration = 15
/obj/effect/overlay/temp/decoy/New(loc, atom/mimiced_atom)
..()
alpha = initial(alpha)
if(mimiced_atom)
+ name = mimiced_atom.name
icon = mimiced_atom.icon
icon_state = mimiced_atom.icon_state
dir = mimiced_atom.dir
diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm
index 3ad2dca4f34..1e27ce67aa4 100644
--- a/code/modules/mob/living/simple_animal/guardian/guardian.dm
+++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm
@@ -67,6 +67,12 @@ var/global/list/parasites = list() //all currently existing/living guardians
qdel(src)
snapback()
+/mob/living/simple_animal/hostile/guardian/Stat()
+ ..()
+ if(statpanel("Status"))
+ if(cooldown >= world.time)
+ stat(null, "Manifest/Recall Cooldown Remaining: [max(round((cooldown - world.time)*0.1, 0.1), 0)] seconds")
+
/mob/living/simple_animal/hostile/guardian/Move() //Returns to summoner if they move out of range
. = ..()
snapback()
@@ -232,6 +238,18 @@ var/global/list/parasites = list() //all currently existing/living guardians
src << "You deactivate your light."
SetLuminosity(0)
+////////parasite tracking/finding procs
+
+/mob/living/proc/hasparasites() //returns a list of guardians the mob is a summoner for
+ . = list()
+ for(var/P in parasites)
+ var/mob/living/simple_animal/hostile/guardian/G = P
+ if(G.summoner == src)
+ . |= G
+
+/mob/living/simple_animal/hostile/guardian/proc/hasmatchingsummoner(mob/living/simple_animal/hostile/guardian/G) //returns 1 if the summoner matches the target's summoner
+ return (istype(G) && G.summoner == summoner)
+
////////Creation
@@ -247,14 +265,15 @@ var/global/list/parasites = list() //all currently existing/living guardians
var/used_message = "All the cards seem to be blank now."
var/failure_message = "..And draw a card! It's...blank? Maybe you should try again later."
var/ling_failure = "The deck refuses to respond to a souless creature such as you."
- var/list/possible_guardians = list("Chaos", "Standard", "Ranged", "Support", "Explosive", "Lightning", "Protector", "Charger")
+ var/list/possible_guardians = list("Chaos", "Standard", "Ranged", "Support", "Explosive", "Lightning", "Protector", "Charger", "Assassin")
var/random = TRUE
+ var/allowmultiple = 0
/obj/item/weapon/guardiancreator/attack_self(mob/living/user)
- for(var/mob/living/simple_animal/hostile/guardian/G in living_mob_list)
- if (G.summoner == user)
- user << "You already have a [mob_name]!"
- return
+ var/list/guardians = user.hasparasites()
+ if(guardians.len && !allowmultiple)
+ user << "You already have a [mob_name]!"
+ return
if(user.mind && user.mind.changeling)
user << "[ling_failure]"
return
@@ -307,6 +326,9 @@ var/global/list/parasites = list() //all currently existing/living guardians
if("Charger")
pickedtype = /mob/living/simple_animal/hostile/guardian/charger
+ if("Assassin")
+ pickedtype = /mob/living/simple_animal/hostile/guardian/assassin
+
var/mob/living/simple_animal/hostile/guardian/G = new pickedtype(user)
G.summoner = user
G.key = key
@@ -356,7 +378,7 @@ var/global/list/parasites = list() //all currently existing/living guardians
ling_failure = "The holoparasites recoil in horror. They want nothing to do with a creature like you."
/obj/item/weapon/guardiancreator/tech/choose/traitor
- possible_guardians = list("Chaos", "Standard", "Ranged", "Support", "Explosive", "Lightning")
+ possible_guardians = list("Chaos", "Standard", "Ranged", "Support", "Explosive", "Lightning", "Assassin")
/obj/item/weapon/guardiancreator/tech/choose
random = FALSE
@@ -369,15 +391,17 @@ var/global/list/parasites = list() //all currently existing/living guardians
Chaos: Ignites enemies on touch and causes them to hallucinate all nearby people as the parasite. Automatically extinguishes the user if they catch on fire.
- Standard:Devastating close combat attacks and high damage resist. Can smash through weak walls.
+ Standard: Devastating close combat attacks and high damage resist. Can smash through weak walls.
Ranged: Has two modes. Ranged; which fires a constant stream of weak, armor-ignoring projectiles. Scout; Cannot attack, but can move through walls and is quite hard to see. Can lay surveillance snares, which alert it when crossed, in either mode.
- Support:Has two modes. Combat; Medium power attacks and damage resist. Healer; Heals instead of attack, but has low damage resist and slow movement. Can deploy a bluespace beacon and warp targets to it (including you) in either mode.
+ Support: Has two modes. Combat; Medium power attacks and damage resist. Healer; Heals instead of attack, but has low damage resist and slow movement. Can deploy a bluespace beacon and warp targets to it (including you) in either mode.
Explosive: High damage resist and medium power attack that may explosively teleport targets. Can turn any object, including objects too large to pick up, into a bomb, dealing explosive damage to the next person to touch it. The object will return to normal after the trap is triggered or after a delay.
- Lightning: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them.
+ Lightning: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage.
+
+ Assassin: Does low damage and takes full damage, but can enter stealth, causing its next attack to do massive damage and ignore armor. However, it becomes briefly unable to recall after attacking from stealth.
= world.time)
+ stat(null, "Stealth Cooldown Remaining: [max(round((stealthcooldown - world.time)*0.1, 0.1), 0)] seconds")
+
+/mob/living/simple_animal/hostile/guardian/assassin/AttackingTarget()
+ if(..())
+ if(toggle && (isliving(target) || istype(target, /obj/structure/window) || istype(target, /obj/structure/grille)))
+ ToggleMode(1)
+
+/mob/living/simple_animal/hostile/guardian/assassin/adjustHealth(amount)
+ . = ..()
+ if(. && toggle)
+ ToggleMode(1)
+
+/mob/living/simple_animal/hostile/guardian/assassin/Recall()
+ if(..() && toggle)
+ ToggleMode(0)
+
+/mob/living/simple_animal/hostile/guardian/assassin/ToggleMode(forced = 0)
+ if(src.loc != summoner)
+ if(toggle)
+ melee_damage_lower = initial(melee_damage_lower)
+ melee_damage_upper = initial(melee_damage_upper)
+ armour_penetration = initial(armour_penetration)
+ environment_smash = initial(environment_smash)
+ alpha = initial(alpha)
+ if(!forced)
+ src << "You exit stealth."
+ else
+ visible_message("\The [src] suddenly appears!")
+ stealthcooldown = world.time + initial(stealthcooldown) //we were forced out of stealth and go on cooldown
+ cooldown = world.time + 50 //can't recall for 5 seconds
+ updatestealthalert()
+ toggle = FALSE
+ else if(stealthcooldown <= world.time)
+ melee_damage_lower = 50
+ melee_damage_upper = 50
+ armour_penetration = 100
+ environment_smash = 0
+ PoolOrNew(/obj/effect/overlay/temp/guardian/phase/out, get_turf(src))
+ alpha = 15
+ if(!forced)
+ src << "You enter stealth, empowering your next attack."
+ updatestealthalert()
+ toggle = TRUE
+ else if(!forced)
+ src << "You cannot yet enter stealth, wait another [max(round((stealthcooldown - world.time)*0.1, 0.1), 0)] seconds!"
+ else if(!forced)
+ src << "You have to be deployed to enter stealth!"
+
+/mob/living/simple_animal/hostile/guardian/assassin/proc/updatestealthalert()
+ if(stealthcooldown <= world.time)
+ if(toggle)
+ if(!instealthalert)
+ instealthalert = throw_alert("instealth", /obj/screen/alert/instealth)
+ clear_alert("canstealth")
+ canstealthalert = null
+ else
+ if(!canstealthalert)
+ canstealthalert = throw_alert("canstealth", /obj/screen/alert/canstealth)
+ clear_alert("instealth")
+ instealthalert = null
+ else
+ clear_alert("instealth")
+ instealthalert = null
+ clear_alert("canstealth")
+ canstealthalert = null
diff --git a/code/modules/mob/living/simple_animal/guardian/types/charger.dm b/code/modules/mob/living/simple_animal/guardian/types/charger.dm
index 90a38b46b19..9c9846e8450 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/charger.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/charger.dm
@@ -52,6 +52,8 @@
if(isliving(A) && A != summoner)
var/mob/living/L = A
var/blocked = 0
+ if(hasmatchingsummoner(A)) //if the summoner matches don't hurt them
+ blocked = 1
if(ishuman(A))
var/mob/living/carbon/human/H = A
if(H.check_shields(90, "the [name]", src, attack_type = THROWN_PROJECTILE_ATTACK))
diff --git a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
index 0dfb1de9657..b0a08836acd 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
@@ -18,6 +18,8 @@
PoolOrNew(/obj/effect/overlay/temp/guardian/phase/out, get_turf(M))
do_teleport(M, M, 10)
for(var/mob/living/L in range(1, M))
+ if(hasmatchingsummoner(L)) //if the summoner matches don't hurt them
+ continue
if(L != src && L != summoner)
L.apply_damage(15, BRUTE)
PoolOrNew(/obj/effect/overlay/temp/explosion, get_turf(M))
@@ -42,7 +44,7 @@
name = "bomb"
desc = "You shouldn't be seeing this!"
var/obj/stored_obj
- var/mob/living/spawner
+ var/mob/living/simple_animal/hostile/guardian/spawner
/obj/item/weapon/guardian_bomb/proc/disguise(var/obj/A)
@@ -66,7 +68,7 @@
qdel(src)
/obj/item/weapon/guardian_bomb/Bump(atom/A)
- if(isliving(A))
+ if(isliving(A) && !spawner.hasmatchingsummoner(A))
detonate(A)
else
..()
diff --git a/code/modules/mob/living/simple_animal/guardian/types/fire.dm b/code/modules/mob/living/simple_animal/guardian/types/fire.dm
index 62223bcd38d..3d988c86582 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/fire.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/fire.dm
@@ -20,7 +20,7 @@
/mob/living/simple_animal/hostile/guardian/fire/AttackingTarget()
if(..())
- if(ishuman(target))
+ if(ishuman(target) && target != summoner)
spawn(0)
new /obj/effect/hallucination/delusion(target.loc,target,force_kind="custom",duration=200,skip_nearby=0, custom_icon = src.icon_state, custom_icon_file = src.icon)
@@ -39,6 +39,6 @@
/mob/living/simple_animal/hostile/guardian/fire/proc/collision_ignite(AM as mob|obj)
if(istype(AM, /mob/living/))
var/mob/living/M = AM
- if(AM != summoner && M.fire_stacks < 7)
+ if(!hasmatchingsummoner(M) && M != summoner && M.fire_stacks < 7)
M.fire_stacks = 7
M.IgniteMob()
diff --git a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm b/code/modules/mob/living/simple_animal/guardian/types/lightning.dm
index 2c279e85054..73ebb6eccf8 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/lightning.dm
@@ -88,6 +88,8 @@
var/turf/T = turf
for(var/mob/living/L in T)
if(L.stat != DEAD && L != src && L != summoner)
+ if(hasmatchingsummoner(L)) //if the summoner matches don't hurt them
+ continue
if(successfulshocks > 4)
if(iscarbon(L))
var/mob/living/carbon/C = L
diff --git a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm
index c928c89cde8..81b9ac99b8b 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm
@@ -31,6 +31,7 @@
ranged = 1
melee_damage_lower = 10
melee_damage_upper = 10
+ environment_smash = initial(environment_smash)
alpha = 255
range = 13
incorporeal_move = 0
@@ -40,6 +41,7 @@
ranged = 0
melee_damage_lower = 0
melee_damage_upper = 0
+ environment_smash = 0
alpha = 60
range = 255
incorporeal_move = 1
diff --git a/code/modules/tooltip/tooltip.html b/code/modules/tooltip/tooltip.html
index ede448c54fa..3f0e5784922 100644
--- a/code/modules/tooltip/tooltip.html
+++ b/code/modules/tooltip/tooltip.html
@@ -42,6 +42,9 @@
.blob .wrap {border-color: #2E2E2E;}
.blob .content {color: #82ED00; border-color: #4E4C4A; background-color: #191918;}
+ .parasite .wrap {border-color: #88868D;}
+ .parasite .content {color: #EFEEEF; border-color: #35333A; background-color: #636169;}
+
.wraith .wrap {border-color: #492136;}
.wraith .content {border-color: #331726; background-color: #471962;}
diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi
index b7d64121636..a2fbd692c53 100644
Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 6d912111be7..a5d99cd07c4 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1347,6 +1347,7 @@
#include "code\modules\mob\living\simple_animal\friendly\drone\verbs.dm"
#include "code\modules\mob\living\simple_animal\friendly\drone\visuals_icons.dm"
#include "code\modules\mob\living\simple_animal\guardian\guardian.dm"
+#include "code\modules\mob\living\simple_animal\guardian\types\assassin.dm"
#include "code\modules\mob\living\simple_animal\guardian\types\charger.dm"
#include "code\modules\mob\living\simple_animal\guardian\types\explosive.dm"
#include "code\modules\mob\living\simple_animal\guardian\types\fire.dm"