mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 12:41:09 +01:00
Merge pull request #16334 from ChangelingRain/parasitic
Adds assassin holoparasites
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 << "<span class='notice'>You deactivate your light.</span>"
|
||||
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
|
||||
<br>
|
||||
<b>Chaos</b>: Ignites enemies on touch and causes them to hallucinate all nearby people as the parasite. Automatically extinguishes the user if they catch on fire.<br>
|
||||
<br>
|
||||
<b>Standard</b>:Devastating close combat attacks and high damage resist. Can smash through weak walls.<br>
|
||||
<b>Standard</b>: Devastating close combat attacks and high damage resist. Can smash through weak walls.<br>
|
||||
<br>
|
||||
<b>Ranged</b>: 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.<br>
|
||||
<br>
|
||||
<b>Support</b>: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.<br>
|
||||
<b>Support</b>: 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.<br>
|
||||
<br>
|
||||
<b>Explosive</b>: 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.<br>
|
||||
<br>
|
||||
<b>Lightning</b>: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them.<br>
|
||||
<b>Lightning</b>: Attacks apply lightning chains to targets. Has a lightning chain to the user. Lightning chains shock everything near them, doing constant damage.<br>
|
||||
<br>
|
||||
<b>Assassin</b>: 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.<br
|
||||
"}
|
||||
|
||||
/obj/item/weapon/paper/guardian/update_icon()
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
//Assassin
|
||||
/mob/living/simple_animal/hostile/guardian/assassin
|
||||
melee_damage_lower = 13
|
||||
melee_damage_upper = 13
|
||||
attacktext = "slashes"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
|
||||
playstyle_string = "As an assassin type you do low damage and have no damage resistance, but can enter stealth, massively increasing the damage of your next attack and causing it to ignore armor. Stealth is broken when you attack or take damage."
|
||||
magic_fluff_string = "..And draw the Space Ninja, a lethal, invisible assassin."
|
||||
tech_fluff_string = "Boot sequence complete. Assassin modules loaded. Holoparasite swarm online."
|
||||
var/toggle = FALSE
|
||||
var/stealthcooldown = 200
|
||||
var/obj/screen/alert/canstealthalert
|
||||
var/obj/screen/alert/instealthalert
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/assassin/New()
|
||||
..()
|
||||
stealthcooldown = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/assassin/Life()
|
||||
..()
|
||||
updatestealthalert()
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/assassin/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
if(stealthcooldown >= 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 << "<span class='danger'><B>You exit stealth.</span></B>"
|
||||
else
|
||||
visible_message("<span class='danger'>\The [src] suddenly appears!</span>")
|
||||
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 << "<span class='danger'><B>You enter stealth, empowering your next attack.</span></B>"
|
||||
updatestealthalert()
|
||||
toggle = TRUE
|
||||
else if(!forced)
|
||||
src << "<span class='danger'><B>You cannot yet enter stealth, wait another [max(round((stealthcooldown - world.time)*0.1, 0.1), 0)] seconds!</span></B>"
|
||||
else if(!forced)
|
||||
src << "<span class='danger'><B>You have to be deployed to enter stealth!</span></B>"
|
||||
|
||||
/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
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
..()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;}
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 31 KiB |
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user