Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into traitor-types
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
var/name = "team"
|
||||
var/member_name = "member"
|
||||
var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
|
||||
var/show_roundend_report = TRUE
|
||||
|
||||
/datum/team/New(starting_members)
|
||||
. = ..()
|
||||
@@ -25,6 +26,8 @@
|
||||
|
||||
//Display members/victory/failure/objectives for the team
|
||||
/datum/team/proc/roundend_report()
|
||||
if(!show_roundend_report)
|
||||
return
|
||||
var/list/report = list()
|
||||
|
||||
report += "<span class='header'>[name]:</span>"
|
||||
|
||||
@@ -116,14 +116,13 @@
|
||||
var/mob/living/carbon/human/M = loc
|
||||
M.adjustStaminaLoss(-75)
|
||||
M.SetUnconscious(0)
|
||||
M.SetStun(0)
|
||||
M.SetKnockdown(0)
|
||||
M.SetAllImmobility(0)
|
||||
combat_cooldown = 0
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/clothing/suit/armor/abductor/vest/process()
|
||||
combat_cooldown++
|
||||
if(combat_cooldown==initial(combat_cooldown))
|
||||
if(combat_cooldown == initial(combat_cooldown))
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/clothing/suit/armor/abductor/Destroy()
|
||||
@@ -512,7 +511,7 @@
|
||||
L.lastattackerckey = user.ckey
|
||||
|
||||
L.adjustStaminaLoss(35) //because previously it took 5-6 hits to actually "incapacitate" someone for the purposes of the sleep inducement
|
||||
L.Knockdown(140)
|
||||
L.DefaultCombatKnockdown(140)
|
||||
L.apply_effect(EFFECT_STUTTER, 7)
|
||||
SEND_SIGNAL(L, COMSIG_LIVING_MINOR_SHOCK)
|
||||
|
||||
|
||||
@@ -218,11 +218,16 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/Initialize()
|
||||
. = ..()
|
||||
if(!independent) //no pulling people deep into the blob
|
||||
verbs -= /mob/living/verb/pulled
|
||||
else
|
||||
if(independent)
|
||||
pass_flags &= ~PASSBLOB
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/start_pulling(atom/movable/AM, state, force = pull_force, supress_message = FALSE)
|
||||
if(!independent && ismob(AM))
|
||||
if(!supress_message)
|
||||
to_chat(src, "<span class='warning'>You are unable to grasp people in this form.</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/Life()
|
||||
if(..())
|
||||
var/list/blobs_in_area = range(2, src)
|
||||
|
||||
@@ -157,6 +157,9 @@ GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
BM.overmind = null
|
||||
BM.update_icons()
|
||||
GLOB.overminds -= src
|
||||
blob_mobs = null
|
||||
resource_blobs = null
|
||||
blobs_legit = null
|
||||
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
|
||||
|
||||
@@ -303,8 +303,7 @@
|
||||
|
||||
/obj/structure/blob/proc/change_to(type, controller)
|
||||
if(!ispath(type))
|
||||
throw EXCEPTION("change_to(): invalid type for blob")
|
||||
return
|
||||
CRASH("change_to(): invalid type for blob")
|
||||
var/obj/structure/blob/B = new type(src.loc, controller)
|
||||
B.creation_action()
|
||||
B.update_icon()
|
||||
|
||||
@@ -315,7 +315,7 @@
|
||||
bloodsuckerdatum.handle_eat_human_food(food_nutrition)
|
||||
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/handle_eat_human_food(var/food_nutrition) // Called from snacks.dm and drinks.dm
|
||||
/datum/antagonist/bloodsucker/proc/handle_eat_human_food(food_nutrition, puke_blood = TRUE, masquerade_override) // Called from snacks.dm and drinks.dm
|
||||
set waitfor = FALSE
|
||||
if(!owner.current || !iscarbon(owner.current))
|
||||
return
|
||||
@@ -324,14 +324,14 @@
|
||||
C.nutrition -= food_nutrition
|
||||
foodInGut += food_nutrition
|
||||
// Already ate some bad clams? Then we can back out, because we're already sick from it.
|
||||
if (foodInGut != food_nutrition)
|
||||
if(foodInGut != food_nutrition)
|
||||
return
|
||||
// Haven't eaten, but I'm in a Human Disguise.
|
||||
else if (poweron_masquerade)
|
||||
else if(poweron_masquerade && !masquerade_override)
|
||||
to_chat(C, "<span class='notice'>Your stomach turns, but your \"human disguise\" keeps the food down...for now.</span>")
|
||||
// Keep looping until we purge. If we have activated our Human Disguise, we ignore the food. But it'll come up eventually...
|
||||
var/sickphase = 0
|
||||
while (foodInGut)
|
||||
while(foodInGut)
|
||||
sleep(50)
|
||||
C.adjust_disgust(10 * sickphase)
|
||||
// Wait an interval...
|
||||
@@ -340,24 +340,29 @@
|
||||
if(C.stat == DEAD)
|
||||
return
|
||||
// Put up disguise? Then hold off the vomit.
|
||||
if(poweron_masquerade)
|
||||
if(poweron_masquerade && !masquerade_override)
|
||||
if(sickphase > 0)
|
||||
to_chat(C, "<span class='notice'>Your stomach settles temporarily. You regain your composure...for now.</span>")
|
||||
sickphase = 0
|
||||
continue
|
||||
switch(sickphase)
|
||||
if (1)
|
||||
if(1)
|
||||
to_chat(C, "<span class='warning'>You feel unwell. You can taste ash on your tongue.</span>")
|
||||
C.Stun(10)
|
||||
if (2)
|
||||
if(2)
|
||||
to_chat(C, "<span class='warning'>Your stomach turns. Whatever you ate tastes of grave dirt and brimstone.</span>")
|
||||
C.Dizzy(15)
|
||||
C.Stun(13)
|
||||
if (3)
|
||||
if(3)
|
||||
to_chat(C, "<span class='warning'>You purge the food of the living from your viscera! You've never felt worse.</span>")
|
||||
C.vomit(foodInGut * 4, foodInGut * 2, 0) // (var/lost_nutrition = 10, var/blood = 0, var/stun = 1, var/distance = 0, var/message = 1, var/toxic = 0)
|
||||
C.blood_volume = max(0, C.blood_volume - foodInGut * 2)
|
||||
//Puke blood only if puke_blood is true, and loose some blood, else just puke normally.
|
||||
if(puke_blood)
|
||||
C.blood_volume = max(0, C.blood_volume - foodInGut * 2)
|
||||
C.vomit(foodInGut * 4, foodInGut * 2, 0)
|
||||
else
|
||||
C.vomit(foodInGut * 4, FALSE, 0)
|
||||
C.Stun(30)
|
||||
//C.Dizzy(50)
|
||||
foodInGut = 0
|
||||
SEND_SIGNAL(C, COMSIG_ADD_MOOD_EVENT, "vampdisgust", /datum/mood_event/bloodsucker_disgust)
|
||||
sickphase ++
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
// Incap?
|
||||
if(must_be_capacitated)
|
||||
var/mob/living/L = owner
|
||||
if (L.incapacitated(TRUE, TRUE) || L.resting && !can_be_immobilized)
|
||||
if (L.incapacitated(TRUE, TRUE) || !CHECK_MOBILITY(L, MOBILITY_STAND) && !can_be_immobilized)
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>Not while you're incapacitated!</span>")
|
||||
return FALSE
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
|
||||
|
||||
// organ_internal.dm -- /obj/item/organ
|
||||
|
||||
|
||||
|
||||
// Do I have a stake in my heart?
|
||||
/mob/living/AmStaked()
|
||||
var/obj/item/bodypart/BP = get_bodypart("chest")
|
||||
@@ -13,16 +9,14 @@
|
||||
if (istype(I,/obj/item/stake/))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/proc/AmStaked()
|
||||
return FALSE
|
||||
|
||||
|
||||
/mob/living/proc/StakeCanKillMe()
|
||||
return IsSleeping() || stat >= UNCONSCIOUS || blood_volume <= 0 || HAS_TRAIT(src, TRAIT_DEATHCOMA) // NOTE: You can't go to sleep in a coffin with a stake in you.
|
||||
|
||||
|
||||
///obj/item/weapon/melee/stake
|
||||
/obj/item/stake/
|
||||
/obj/item/stake
|
||||
name = "wooden stake"
|
||||
desc = "A simple wooden stake carved to a sharp point."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
@@ -112,8 +106,7 @@
|
||||
|
||||
// Can this target be staked? If someone stands up before this is complete, it fails. Best used on someone stationary.
|
||||
/mob/living/carbon/proc/can_be_staked()
|
||||
//return resting || IsKnockdown() || IsUnconscious() || (stat && (stat != SOFT_CRIT || pulledby)) || (has_trait(TRAIT_FAKEDEATH)) || resting || IsStun() || IsFrozen() || (pulledby && pulledby.grab_state >= GRAB_NECK)
|
||||
return (resting || lying || IsUnconscious() || pulledby && pulledby.grab_state >= GRAB_NECK)
|
||||
return !CHECK_MOBILITY(src, MOBILITY_STAND)
|
||||
// ABOVE: Taken from update_mobility() in living.dm
|
||||
|
||||
/obj/item/stake/hardened
|
||||
|
||||
@@ -42,25 +42,18 @@
|
||||
/obj/structure/closet/crate
|
||||
var/mob/living/resident // This lets bloodsuckers claim any "closet" as a Coffin, so long as they could get into it and close it. This locks it in place, too.
|
||||
|
||||
/obj/structure/closet/crate/coffin
|
||||
var/pryLidTimer = 250
|
||||
can_weld_shut = FALSE
|
||||
breakout_time = 200
|
||||
|
||||
|
||||
/obj/structure/closet/crate/coffin/blackcoffin
|
||||
name = "black coffin"
|
||||
desc = "For those departed who are not so dear."
|
||||
icon_state = "coffin"
|
||||
icon = 'icons/obj/vamp_obj.dmi'
|
||||
can_weld_shut = FALSE
|
||||
resistance_flags = 0 // Start off with no bonuses.
|
||||
open_sound = 'sound/bloodsucker/coffin_open.ogg'
|
||||
close_sound = 'sound/bloodsucker/coffin_close.ogg'
|
||||
breakout_time = 600
|
||||
pryLidTimer = 400
|
||||
resistance_flags = NONE
|
||||
integrity_failure = 70
|
||||
max_integrity = 100
|
||||
integrity_failure = 0.5
|
||||
armor = list("melee" = 50, "bullet" = 20, "laser" = 30, "energy" = 0, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
|
||||
|
||||
/obj/structure/closet/crate/coffin/meatcoffin
|
||||
@@ -68,8 +61,6 @@
|
||||
desc = "When you're ready to meat your maker, the steaks can never be too high."
|
||||
icon_state = "meatcoffin"
|
||||
icon = 'icons/obj/vamp_obj.dmi'
|
||||
can_weld_shut = FALSE
|
||||
resistance_flags = 0 // Start off with no bonuses.
|
||||
open_sound = 'sound/effects/footstep/slime1.ogg'
|
||||
close_sound = 'sound/effects/footstep/slime1.ogg'
|
||||
breakout_time = 200
|
||||
@@ -77,24 +68,23 @@
|
||||
resistance_flags = NONE
|
||||
material_drop = /obj/item/reagent_containers/food/snacks/meat/slab
|
||||
material_drop_amount = 3
|
||||
integrity_failure = 40
|
||||
integrity_failure = 0.57
|
||||
armor = list("melee" = 70, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 70, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 100)
|
||||
|
||||
|
||||
/obj/structure/closet/crate/coffin/metalcoffin
|
||||
name = "metal coffin"
|
||||
desc = "A big metal sardine can inside of another big metal sardine can, in space."
|
||||
icon_state = "metalcoffin"
|
||||
icon = 'icons/obj/vamp_obj.dmi'
|
||||
can_weld_shut = FALSE
|
||||
resistance_flags = FIRE_PROOF | LAVA_PROOF
|
||||
open_sound = 'sound/effects/pressureplate.ogg'
|
||||
close_sound = 'sound/effects/pressureplate.ogg'
|
||||
breakout_time = 300
|
||||
pryLidTimer = 200
|
||||
resistance_flags = NONE
|
||||
material_drop = /obj/item/stack/sheet/metal
|
||||
material_drop_amount = 5
|
||||
integrity_failure = 60
|
||||
max_integrity = 200
|
||||
integrity_failure = 0.25
|
||||
armor = list("melee" = 40, "bullet" = 15, "laser" = 50, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
buckled_mob.pixel_y = buckled_mob.get_standard_pixel_y_offset(180)
|
||||
src.visible_message(text("<span class='danger'>[buckled_mob][buckled_mob.stat==DEAD?"'s corpse":""] slides off of the rack.</span>"))
|
||||
density = FALSE
|
||||
buckled_mob.AdjustKnockdown(30)
|
||||
buckled_mob.DefaultCombatKnockdown(30)
|
||||
update_icon()
|
||||
useLock = FALSE // Failsafe
|
||||
|
||||
|
||||
@@ -72,8 +72,7 @@
|
||||
if(rand(5 + powerlevel) >= 5)
|
||||
target.visible_message("<span class='danger'>[user] lands a vicious punch, sending [target] away!</span>", \
|
||||
"<span class='userdanger'>[user] has landed a horrifying punch on you, sending you flying!!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
target.Knockdown(min(5, rand(10, 10 * powerlevel)) )
|
||||
|
||||
target.DefaultCombatKnockdown(min(5, rand(10, 10 * powerlevel)) )
|
||||
// Attack!
|
||||
playsound(get_turf(target), 'sound/weapons/punch4.ogg', 60, 1, -1)
|
||||
user.do_attack_animation(target, ATTACK_EFFECT_SMASH)
|
||||
@@ -145,7 +144,7 @@
|
||||
// Knock Down (if Living)
|
||||
if (isliving(M))
|
||||
var/mob/living/L = M
|
||||
L.Knockdown(pull_power * 10 + 20)
|
||||
L.DefaultCombatKnockdown(pull_power * 10 + 20)
|
||||
// Knock Back (before Knockdown, which probably cancels pull)
|
||||
var/send_dir = get_dir(owner, M)
|
||||
var/turf/T = get_ranged_target_turf(M, send_dir, pull_power)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
amToggle = TRUE
|
||||
warn_constant_cost = TRUE
|
||||
var/moveintent_was_run
|
||||
var/runintent
|
||||
var/walk_threshold = 0.4 // arbitrary number, to be changed. edit in last commit: this is fine after testing on box station for a bit
|
||||
var/lum
|
||||
|
||||
@@ -31,23 +32,25 @@
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
var/mob/living/user = owner
|
||||
|
||||
moveintent_was_run = (user.m_intent == MOVE_INTENT_RUN)
|
||||
|
||||
while(bloodsuckerdatum && ContinueActive(user))
|
||||
// Pay Blood Toll (if awake)
|
||||
owner.alpha = max(35, owner.alpha - min(75, 10 + 5 * level_current))
|
||||
bloodsuckerdatum.AddBloodVolume(-0.2)
|
||||
|
||||
moveintent_was_run = (user.m_intent == MOVE_INTENT_RUN)
|
||||
runintent = (user.m_intent == MOVE_INTENT_RUN)
|
||||
var/turf/T = get_turf(user)
|
||||
lum = T.get_lumcount()
|
||||
|
||||
if(istype(owner.loc))
|
||||
if(lum > walk_threshold)
|
||||
if(moveintent_was_run)
|
||||
if(runintent)
|
||||
user.toggle_move_intent()
|
||||
ADD_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
|
||||
|
||||
if(lum < walk_threshold)
|
||||
if(!moveintent_was_run)
|
||||
if(!runintent)
|
||||
user.toggle_move_intent()
|
||||
REMOVE_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
|
||||
|
||||
@@ -65,5 +68,8 @@
|
||||
..()
|
||||
REMOVE_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
|
||||
user.alpha = 255
|
||||
if(!moveintent_was_run)
|
||||
|
||||
runintent = (user.m_intent == MOVE_INTENT_RUN)
|
||||
|
||||
if(!runintent && moveintent_was_run)
|
||||
user.toggle_move_intent()
|
||||
|
||||
@@ -306,7 +306,7 @@
|
||||
// Bloodsuckers not affected by "the Kiss" of another vampire
|
||||
if(!target.mind || !target.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
|
||||
target.Unconscious(50,0)
|
||||
target.Knockdown(40 + 5 * level_current,1)
|
||||
target.DefaultCombatKnockdown(40 + 5 * level_current,1)
|
||||
// NOTE: THis is based on level of power!
|
||||
if(ishuman(target))
|
||||
target.adjustStaminaLoss(5, forced = TRUE)// Base Stamina Damage
|
||||
@@ -321,4 +321,4 @@
|
||||
// My mouth is no longer full
|
||||
REMOVE_TRAIT(owner, TRAIT_MUTE, "bloodsucker_feed")
|
||||
// Let me move immediately
|
||||
user.update_canmove()
|
||||
user.update_mobility()
|
||||
|
||||
@@ -100,8 +100,8 @@
|
||||
var/mob/living/simple_animal/SA = pick(/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse, /mob/living/simple_animal/hostile/retaliate/bat) //prob(300) /mob/living/simple_animal/mouse,
|
||||
new SA (owner.loc)
|
||||
// TELEPORT: Move to Coffin & Close it!
|
||||
user.set_resting(TRUE, TRUE, FALSE)
|
||||
do_teleport(owner, bloodsuckerdatum.coffin, no_effects = TRUE, forced = TRUE, channel = TELEPORT_CHANNEL_QUANTUM)
|
||||
user.resting = TRUE
|
||||
user.Stun(30,1)
|
||||
// CLOSE LID: If fail, force me in.
|
||||
if(!bloodsuckerdatum.coffin.close(owner))
|
||||
|
||||
@@ -76,16 +76,17 @@
|
||||
sleep(speed)
|
||||
UnregisterSignal(owner, COMSIG_MOVABLE_MOVED)
|
||||
hit = null
|
||||
user.update_canmove()
|
||||
user.update_mobility()
|
||||
|
||||
/datum/action/bloodsucker/targeted/haste/DeactivatePower(mob/living/user = owner, mob/living/target)
|
||||
..() // activate = FALSE
|
||||
user.update_canmove()
|
||||
user.update_mobility()
|
||||
|
||||
/datum/action/bloodsucker/targeted/haste/proc/on_move()
|
||||
for(var/mob/living/L in dview(1, get_turf(owner)))
|
||||
if(!hit[L] && (L != owner))
|
||||
hit[L] = TRUE
|
||||
playsound(L, "sound/weapons/punch[rand(1,4)].ogg", 15, 1, -1)
|
||||
L.Knockdown(10 + level_current * 5, override_hardstun = 0.1)
|
||||
L.DefaultCombatKnockdown(10 + level_current * 5)
|
||||
L.Paralyze(0.1)
|
||||
L.spin(10, 1)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
button_icon_state = "power_lunge"
|
||||
bloodcost = 10
|
||||
cooldown = 120
|
||||
target_range = 5
|
||||
target_range = 3
|
||||
power_activates_immediately = TRUE
|
||||
message_Trigger = "Whom will you ensnare within your grasp?"
|
||||
must_be_capacitated = TRUE
|
||||
@@ -52,6 +52,7 @@
|
||||
// set waitfor = FALSE <---- DONT DO THIS!We WANT this power to hold up ClickWithPower(), so that we can unlock the power when it's done.
|
||||
var/mob/living/carbon/target = A
|
||||
var/turf/T = get_turf(target)
|
||||
var/mob/living/L = owner
|
||||
// Clear Vars
|
||||
owner.pulling = null
|
||||
// Will we Knock them Down?
|
||||
@@ -61,9 +62,9 @@
|
||||
addtimer(CALLBACK(owner, .proc/_walk, 0), 2 SECONDS)
|
||||
target.playsound_local(get_turf(owner), 'sound/bloodsucker/lunge_warn.ogg', 60, FALSE, pressure_affected = FALSE) // target-only telegraphing
|
||||
owner.playsound_local(owner, 'sound/bloodsucker/lunge_warn.ogg', 60, FALSE, pressure_affected = FALSE) // audio feedback to the user
|
||||
if(do_mob(owner, owner, 6, TRUE, TRUE))
|
||||
if(do_mob(owner, owner, 7, TRUE, TRUE))
|
||||
walk_towards(owner, T, 0.1, 10) // yes i know i shouldn't use this but i don't know how to work in anything better
|
||||
if(get_turf(owner) != T && !(isliving(target) && target.Adjacent(owner)) && owner.incapacitated() && owner.resting)
|
||||
if(get_turf(owner) != T && !(isliving(target) && target.Adjacent(owner)) && owner.incapacitated() && !CHECK_MOBILITY(L, MOBILITY_STAND))
|
||||
var/send_dir = get_dir(owner, T)
|
||||
new /datum/forced_movement(owner, get_ranged_target_turf(owner, send_dir, 1), 1, FALSE)
|
||||
owner.spin(10)
|
||||
@@ -80,8 +81,8 @@
|
||||
target.grabbedby(owner) // Taken from mutations.dm under changelings
|
||||
target.grippedby(owner, instant = TRUE) //instant aggro grab
|
||||
break
|
||||
sleep(i*3)
|
||||
sleep(3)
|
||||
|
||||
/datum/action/bloodsucker/targeted/lunge/DeactivatePower(mob/living/user = owner, mob/living/target)
|
||||
..() // activate = FALSE
|
||||
user.update_canmove()
|
||||
user.update_mobility()
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
button_icon_state = "power_mez"
|
||||
bloodcost = 30
|
||||
cooldown = 300
|
||||
target_range = 3
|
||||
target_range = 2
|
||||
power_activates_immediately = TRUE
|
||||
message_Trigger = "Whom will you subvert to your will?"
|
||||
must_be_capacitated = TRUE
|
||||
@@ -73,7 +73,7 @@
|
||||
to_chat(owner, "<span class='warning'>You're too far outside your victim's view.</span>")
|
||||
return FALSE
|
||||
|
||||
if(target.has_status_effect(STATUS_EFFECT_MESMERIZE)) // ?
|
||||
if(target.has_status_effect(STATUS_EFFECT_MESMERIZE)) // ignores facing once the windup has started
|
||||
return TRUE
|
||||
|
||||
// Check: Facing target?
|
||||
@@ -82,45 +82,59 @@
|
||||
to_chat(owner, "<span class='warning'>You must be facing your victim.</span>")
|
||||
return FALSE
|
||||
// Check: Target facing me?
|
||||
if(!target.resting && !is_A_facing_B(target,owner))
|
||||
if (CHECK_MOBILITY(target, MOBILITY_STAND) && !is_A_facing_B(target,owner))
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>Your victim must be facing you to see into your eyes.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/bloodsucker/targeted/mesmerize/proc/ContinueTarget(atom/A)
|
||||
var/mob/living/carbon/target = A
|
||||
var/mob/living/user = owner
|
||||
|
||||
var/cancontinue=CheckCanTarget(target)
|
||||
if(!cancontinue)
|
||||
success = FALSE
|
||||
target.remove_status_effect(STATUS_EFFECT_MESMERIZE)
|
||||
user.remove_status_effect(STATUS_EFFECT_MESMERIZE)
|
||||
DeactivatePower()
|
||||
DeactivateRangedAbility()
|
||||
StartCooldown()
|
||||
to_chat(user, "<span class='warning'>[target] has escaped your gaze!</span>")
|
||||
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
|
||||
|
||||
/datum/action/bloodsucker/targeted/mesmerize/FireTargetedPower(atom/A)
|
||||
// set waitfor = FALSE <---- DONT DO THIS!We WANT this power to hold up ClickWithPower(), so that we can unlock the power when it's done.
|
||||
var/mob/living/carbon/target = A
|
||||
var/mob/living/user = owner
|
||||
|
||||
if(istype(target))
|
||||
success = TRUE
|
||||
var/power_time = 138 + level_current * 12
|
||||
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
|
||||
user.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
|
||||
if(do_mob(user, target, 30, TRUE, TRUE)) // 3 seconds windup
|
||||
success = CheckCanTarget(target)
|
||||
if(success) // target just has to be out of view when it is fully charged in order to avoid
|
||||
PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y
|
||||
target.face_atom(user)
|
||||
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time) // pretty much purely cosmetic
|
||||
target.Stun(power_time)
|
||||
to_chat(user, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
|
||||
target.next_move = world.time + power_time // <--- Use direct change instead. We want an unmodified delay to their next move // target.changeNext_move(power_time) // check click.dm
|
||||
target.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[target] has escaped your gaze!</span>")
|
||||
DeactivatePower()
|
||||
DeactivateRangedAbility()
|
||||
StartCooldown()
|
||||
// oops! if they knew how they could just spam stun the victim and themselves.
|
||||
|
||||
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/ContinueTarget)
|
||||
|
||||
spawn(power_time)
|
||||
if(istype(target) && success)
|
||||
target.notransform = FALSE
|
||||
// They Woke Up! (Notice if within view)
|
||||
if(istype(user) && target.stat == CONSCIOUS && (target in view(10, get_turf(user))) )
|
||||
// 3 second windup
|
||||
sleep(30)
|
||||
if(success)
|
||||
PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y
|
||||
target.face_atom(user)
|
||||
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time) // pretty much purely cosmetic
|
||||
target.Stun(power_time)
|
||||
to_chat(user, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
|
||||
target.next_move = world.time + power_time // <--- Use direct change instead. We want an unmodified delay to their next move // target.changeNext_move(power_time) // check click.dm
|
||||
target.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
|
||||
|
||||
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
|
||||
|
||||
spawn(power_time)
|
||||
if(istype(target) && success)
|
||||
target.notransform = FALSE
|
||||
// They Woke Up! (Notice if within view)
|
||||
if(istype(user) && target.stat == CONSCIOUS && (target in view(10, get_turf(user))) )
|
||||
to_chat(user, "<span class='warning'>[target] has snapped out of their trance.</span>")
|
||||
|
||||
|
||||
/datum/action/bloodsucker/targeted/mesmerize/ContinueActive(mob/living/user, mob/living/target)
|
||||
return ..() && CheckCanUse() && CheckCanTarget(target)
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
if(istype(our_target, /datum/cellular_emporium))
|
||||
cellular_emporium = our_target
|
||||
else
|
||||
throw EXCEPTION("cellular_emporium action created with non emporium")
|
||||
CRASH("cellular_emporium action created with non emporium")
|
||||
|
||||
/datum/action/innate/cellular_emporium/Activate()
|
||||
cellular_emporium.ui_interact(owner)
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
user.tod = STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)
|
||||
user.fakedeath("changeling") //play dead
|
||||
user.update_stat()
|
||||
user.update_canmove()
|
||||
|
||||
addtimer(CALLBACK(src, .proc/ready_to_regenerate, user), LING_FAKEDEATH_TIME, TIMER_UNIQUE)
|
||||
return TRUE
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
H.confused += 3
|
||||
for(var/mob/living/silicon/S in range(2,user))
|
||||
to_chat(S, "<span class='userdanger'>Your sensors are disabled by a shower of blood!</span>")
|
||||
S.Knockdown(60)
|
||||
S.DefaultCombatKnockdown(60)
|
||||
var/turf = get_turf(user)
|
||||
user.gib()
|
||||
. = TRUE
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
if(issilicon(M))
|
||||
SEND_SOUND(M, sound('sound/weapons/flash.ogg'))
|
||||
M.Knockdown(rand(100,200))
|
||||
M.DefaultCombatKnockdown(rand(100,200))
|
||||
|
||||
for(var/obj/machinery/light/L in range(4, user))
|
||||
L.on = 1
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
changeling.chem_recharge_slowdown -= 0.5
|
||||
if(stacks >= 20)
|
||||
to_chat(user, "<span class='danger'>We collapse in exhaustion.</span>")
|
||||
user.Knockdown(60)
|
||||
user.DefaultCombatKnockdown(60)
|
||||
user.emote("gasp")
|
||||
|
||||
INVOKE_ASYNC(src, .proc/muscle_loop, user)
|
||||
@@ -40,7 +40,7 @@
|
||||
if(user.stat != CONSCIOUS || user.staminaloss >= 90)
|
||||
active = !active
|
||||
to_chat(user, "<span class='notice'>Our muscles relax without the energy to strengthen them.</span>")
|
||||
user.Knockdown(40)
|
||||
user.DefaultCombatKnockdown(40)
|
||||
user.remove_movespeed_modifier(MOVESPEED_ID_CHANGELING_MUSCLES)
|
||||
changeling.chem_recharge_slowdown -= 0.5
|
||||
break
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
if(iscultist(L)) //No longer stuns cultists, instead sets them on fire and burns them
|
||||
to_chat(L, "<span class='heavy_brass'>\"Watch your step, wretch.\"</span>")
|
||||
L.adjustFireLoss(10)
|
||||
L.Knockdown(20, FALSE)
|
||||
L.DefaultCombatKnockdown(20, FALSE)
|
||||
L.adjust_fire_stacks(5) //Burn!
|
||||
L.IgniteMob()
|
||||
else
|
||||
@@ -155,7 +155,7 @@
|
||||
if(brutedamage || burndamage)
|
||||
L.adjustBruteLoss(-(brutedamage * 0.25))
|
||||
L.adjustFireLoss(-(burndamage * 0.25))
|
||||
L.Knockdown(50) //Completely defenseless for five seconds - mainly to give them time to read over the information they've just been presented with
|
||||
L.DefaultCombatKnockdown(50) //Completely defenseless for five seconds - mainly to give them time to read over the information they've just been presented with
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.silent += 5
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
if(!iscultist(L))
|
||||
L.visible_message("<span class='warning'>[L]'s eyes blaze with brilliant light!</span>", \
|
||||
"<span class='userdanger'>Your vision suddenly screams with white-hot light!</span>")
|
||||
L.Knockdown(15, TRUE, FALSE, 15)
|
||||
L.DefaultCombatKnockdown(15, TRUE, FALSE, 15)
|
||||
L.apply_status_effect(STATUS_EFFECT_KINDLE)
|
||||
L.flash_act(1, 1)
|
||||
if(issilicon(target))
|
||||
|
||||
@@ -57,15 +57,15 @@
|
||||
else if(!..())
|
||||
if(!L.anti_magic_check())
|
||||
if(issilicon(L))
|
||||
L.Knockdown(100)
|
||||
L.DefaultCombatKnockdown(100)
|
||||
else if(iscultist(L))
|
||||
L.confused += CLAMP(10 - L.confused, 0, 5) // Spearthrow now confuses enemy cultists + just deals extra damage / sets on fire instead of hardstunning + damage
|
||||
to_chat(L, "<span class ='userdanger'>[src] crashes into you with burning force, sending you reeling!</span>")
|
||||
L.adjust_fire_stacks(2)
|
||||
L.Knockdown(1)
|
||||
L.DefaultCombatKnockdown(1)
|
||||
L.IgniteMob()
|
||||
else
|
||||
L.Knockdown(40)
|
||||
L.DefaultCombatKnockdown(40)
|
||||
GLOB.clockwork_vitality += L.adjustFireLoss(bonus_burn * 3) //normally a total of 40 damage, 70 with ratvar
|
||||
break_spear(T)
|
||||
else
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
var/datum/status_effect/belligerent/B = C.apply_status_effect(STATUS_EFFECT_BELLIGERENT)
|
||||
if(!QDELETED(B))
|
||||
B.duration = world.time + 30
|
||||
C.Knockdown(5) //knocks down for half a second if affected
|
||||
C.DefaultCombatKnockdown(5) //knocks down for half a second if affected
|
||||
sleep(!GLOB.ratvar_approaches ? 16 : 10)
|
||||
name = "judicial blast"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
@@ -196,7 +196,7 @@
|
||||
L.visible_message("<span class='warning'>Strange energy flows into [L]'s [I.name]!</span>", \
|
||||
"<span class='userdanger'>Your [I.name] shields you from [src]!</span>")
|
||||
continue
|
||||
L.Knockdown(15) //knocks down briefly when exploding
|
||||
L.DefaultCombatKnockdown(15) //knocks down briefly when exploding
|
||||
if(!iscultist(L))
|
||||
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
|
||||
"<span class='userdanger'>[!issilicon(L) ? "An unseen force slams you into the ground!" : "ERROR: Motor servos disabled by external source!"]</span>")
|
||||
|
||||
@@ -57,5 +57,5 @@
|
||||
L.confused = min(L.confused + 15, 50)
|
||||
L.dizziness = min(L.dizziness + 15, 50)
|
||||
if(L.confused >= 25)
|
||||
L.Knockdown(FLOOR(L.confused * 0.8, 1))
|
||||
L.DefaultCombatKnockdown(FLOOR(L.confused * 0.8, 1))
|
||||
take_damage(max_integrity)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
if(buckled_mobs && LAZYLEN(buckled_mobs))
|
||||
var/mob/living/L = buckled_mobs[1]
|
||||
if(iscarbon(L))
|
||||
L.Knockdown(100)
|
||||
L.DefaultCombatKnockdown(100)
|
||||
L.visible_message("<span class='warning'>[L] is maimed as the skewer shatters while still in [L.p_their()] body!</span>")
|
||||
L.adjustBruteLoss(15)
|
||||
unbuckle_mob(L)
|
||||
@@ -117,6 +117,6 @@
|
||||
return
|
||||
skewee.visible_message("<span class='danger'>[skewee] comes free of [src] with a squelching pop!</span>", \
|
||||
"<span class='boldannounce'>You come free of [src]!</span>")
|
||||
skewee.Knockdown(30)
|
||||
skewee.DefaultCombatKnockdown(30)
|
||||
playsound(skewee, 'sound/misc/desceration-03.ogg', 50, TRUE)
|
||||
unbuckle_mob(skewee)
|
||||
|
||||
@@ -446,7 +446,7 @@
|
||||
var/atom/throw_target = get_edge_target_turf(L, user.dir)
|
||||
L.throw_at(throw_target, 7, 1, user)
|
||||
else if(!iscultist(L))
|
||||
L.Knockdown(160)
|
||||
L.DefaultCombatKnockdown(160)
|
||||
L.adjustStaminaLoss(140) //Ensures hard stamcrit
|
||||
L.flash_act(1,1)
|
||||
if(issilicon(target))
|
||||
|
||||
@@ -46,10 +46,11 @@
|
||||
/obj/item/melee/cultblade/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/butchering, 40, 100)
|
||||
AddElement(/datum/element/sword_point)
|
||||
|
||||
/obj/item/melee/cultblade/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
if(!iscultist(user))
|
||||
user.Knockdown(100)
|
||||
user.DefaultCombatKnockdown(100)
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.visible_message("<span class='warning'>A powerful force shoves [user] away from [target]!</span>", \
|
||||
"<span class='cultlarge'>\"You shouldn't play with sharp things. You'll poke someone's eye out.\"</span>")
|
||||
@@ -148,7 +149,7 @@
|
||||
user.emote("scream")
|
||||
user.apply_damage(30, BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Knockdown(50)
|
||||
user.DefaultCombatKnockdown(50)
|
||||
return
|
||||
force = initial(force)
|
||||
jaunt.Grant(user, src)
|
||||
@@ -405,7 +406,7 @@
|
||||
to_chat(user, "<span class='warning'>An overwhelming sense of nausea overpowers you!</span>")
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Dizzy(30)
|
||||
user.Knockdown(100)
|
||||
user.DefaultCombatKnockdown(100)
|
||||
else
|
||||
to_chat(user, "<span class='cultlarge'>\"Trying to use things you don't own is bad, you know.\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>The armor squeezes at your body!</span>")
|
||||
@@ -457,7 +458,7 @@
|
||||
to_chat(user, "<span class='warning'>An overwhelming sense of nausea overpowers you!</span>")
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Dizzy(30)
|
||||
user.Knockdown(100)
|
||||
user.DefaultCombatKnockdown(100)
|
||||
else
|
||||
to_chat(user, "<span class='cultlarge'>\"Trying to use things you don't own is bad, you know.\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>The robes squeeze at your body!</span>")
|
||||
@@ -478,7 +479,7 @@
|
||||
to_chat(user, "<span class='cultlarge'>\"You want to be blind, do you?\"</span>")
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Dizzy(30)
|
||||
user.Knockdown(100)
|
||||
user.DefaultCombatKnockdown(100)
|
||||
user.blind_eyes(30)
|
||||
|
||||
/obj/item/reagent_containers/glass/beaker/unholywater
|
||||
@@ -499,7 +500,7 @@
|
||||
/obj/item/shuttle_curse/attack_self(mob/living/user)
|
||||
if(!iscultist(user))
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Knockdown(100)
|
||||
user.DefaultCombatKnockdown(100)
|
||||
to_chat(user, "<span class='warning'>A powerful force shoves you away from [src]!</span>")
|
||||
return
|
||||
if(curselimit > 1)
|
||||
@@ -705,10 +706,10 @@
|
||||
if(is_servant_of_ratvar(L))
|
||||
to_chat(L, "<span class='cultlarge'>\"Kneel for me, scum\"</span>")
|
||||
L.confused += CLAMP(10 - L.confused, 0, 5) //confuses and lightly knockdowns + damages hostile cultists instead of hardstunning like before
|
||||
L.Knockdown(15)
|
||||
L.DefaultCombatKnockdown(15)
|
||||
L.adjustBruteLoss(10)
|
||||
else
|
||||
L.Knockdown(50)
|
||||
L.DefaultCombatKnockdown(50)
|
||||
break_spear(T)
|
||||
else
|
||||
..()
|
||||
@@ -843,7 +844,7 @@
|
||||
INVOKE_ASYNC(src, .proc/pewpew, user, params)
|
||||
var/obj/structure/emergency_shield/invoker/N = new(user.loc)
|
||||
if(do_after(user, 90, target = user))
|
||||
user.Knockdown(40)
|
||||
user.DefaultCombatKnockdown(40)
|
||||
to_chat(user, "<span class='cult italic'>You have exhausted the power of this spell!</span>")
|
||||
firing = FALSE
|
||||
if(N)
|
||||
@@ -908,7 +909,7 @@
|
||||
else
|
||||
var/mob/living/L = target
|
||||
if(L.density)
|
||||
L.Knockdown(20)
|
||||
L.DefaultCombatKnockdown(20)
|
||||
L.adjustBruteLoss(45)
|
||||
playsound(L, 'sound/hallucinations/wail.ogg', 50, 1)
|
||||
L.emote("scream")
|
||||
@@ -944,7 +945,7 @@
|
||||
T.visible_message("<span class='warning'>The sheer force from [P] shatters the mirror shield!</span>")
|
||||
new /obj/effect/temp_visual/cult/sparks(T)
|
||||
playsound(T, 'sound/effects/glassbr3.ogg', 100)
|
||||
owner.Knockdown(25)
|
||||
owner.DefaultCombatKnockdown(25)
|
||||
qdel(src)
|
||||
return FALSE
|
||||
if(P.is_reflectable)
|
||||
@@ -1001,9 +1002,9 @@
|
||||
else if(!..())
|
||||
if(!L.anti_magic_check())
|
||||
if(is_servant_of_ratvar(L))
|
||||
L.Knockdown(60)
|
||||
L.DefaultCombatKnockdown(60)
|
||||
else
|
||||
L.Knockdown(30)
|
||||
L.DefaultCombatKnockdown(30)
|
||||
if(D.thrower)
|
||||
for(var/mob/living/Next in orange(2, T))
|
||||
if(!Next.density || iscultist(Next))
|
||||
|
||||
@@ -219,7 +219,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
L.visible_message("<span class='warning'>[L]'s eyes glow a defiant yellow!</span>", \
|
||||
"<span class='cultlarge'>\"Stop resisting. You <i>will</i> be mi-\"</span>\n\
|
||||
<span class='large_brass'>\"Give up and you will feel pain unlike anything you've ever felt!\"</span>")
|
||||
L.Knockdown(80)
|
||||
L.DefaultCombatKnockdown(80)
|
||||
else if(is_convertable)
|
||||
do_convert(L, invokers)
|
||||
else
|
||||
@@ -908,7 +908,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
if(affecting.key)
|
||||
affecting.visible_message("<span class='warning'>[affecting] slowly relaxes, the glow around [affecting.p_them()] dimming.</span>", \
|
||||
"<span class='danger'>You are re-united with your physical form. [src] releases its hold over you.</span>")
|
||||
affecting.Knockdown(40)
|
||||
affecting.DefaultCombatKnockdown(40)
|
||||
break
|
||||
if(affecting.health <= 10)
|
||||
to_chat(G, "<span class='cultitalic'>Your body can no longer sustain the connection!</span>")
|
||||
@@ -970,7 +970,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
playsound(T, 'sound/magic/enter_blood.ogg', 100, 1)
|
||||
visible_message("<span class='warning'>A colossal shockwave of energy bursts from the rune, disintegrating it in the process!</span>")
|
||||
for(var/mob/living/L in range(src, 3))
|
||||
L.Knockdown(30)
|
||||
L.DefaultCombatKnockdown(30)
|
||||
empulse(T, 0.42*(intensity), 1)
|
||||
var/list/images = list()
|
||||
var/zmatch = T.z
|
||||
|
||||
@@ -477,7 +477,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
|
||||
if(SOULVALUE >= ARCH_THRESHOLD && ascendable)
|
||||
A.convert_to_archdevil()
|
||||
else
|
||||
throw EXCEPTION("Unable to find a blobstart landmark for hellish resurrection")
|
||||
CRASH("Unable to find a blobstart landmark for hellish resurrection")
|
||||
|
||||
|
||||
/datum/antagonist/devil/proc/update_hud()
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
if(BANE_HARVEST)
|
||||
if(istype(weapon, /obj/item/reagent_containers/food/snacks/grown/))
|
||||
visible_message("<span class='warning'>The spirits of the harvest aid in the exorcism.</span>", "<span class='notice'>The harvest spirits are harming you.</span>")
|
||||
Knockdown(40)
|
||||
DefaultCombatKnockdown(40)
|
||||
qdel(weapon)
|
||||
return 2
|
||||
return 1
|
||||
@@ -70,16 +70,10 @@
|
||||
O.explanation_text = "Protect \the [M.current.real_name], the [M.assigned_role], from harm."
|
||||
objectives += O
|
||||
if(4) //flavor
|
||||
if(helping_station)
|
||||
var/datum/objective/flavor/ninja_helping/O = new /datum/objective/flavor/ninja_helping
|
||||
O.owner = owner
|
||||
O.forge_objective()
|
||||
objectives += O
|
||||
else
|
||||
var/datum/objective/flavor/ninja_syndie/O = new /datum/objective/flavor/ninja_helping
|
||||
O.owner = owner
|
||||
O.forge_objective()
|
||||
objectives += O
|
||||
var/datum/objective/flavor/O = helping_station ? new /datum/objective/flavor/ninja_helping : new /datum/objective/flavor/ninja_syndie
|
||||
O.owner = owner
|
||||
O.forge_objective()
|
||||
objectives += O
|
||||
else
|
||||
break
|
||||
var/datum/objective/O = new /datum/objective/survive()
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
return 0
|
||||
|
||||
/obj/item/IntegrateAmount() //returns the amount of resources gained when eating this item
|
||||
if(custom_materials[getmaterialref(/datum/material/iron)] || custom_materials[getmaterialref(/datum/material/glass)])
|
||||
if(custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)] || custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)])
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
@@ -586,7 +586,7 @@
|
||||
playsound(loc,'sound/effects/snap.ogg',50, 1, -1)
|
||||
L.electrocute_act(0, src, 1, 1, 1)
|
||||
if(iscyborg(L))
|
||||
L.Knockdown(100)
|
||||
L.DefaultCombatKnockdown(100)
|
||||
qdel(src)
|
||||
..()
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
var/should_give_codewords = TRUE
|
||||
var/should_equip = TRUE
|
||||
var/datum/traitor_class/traitor_kind
|
||||
var/datum/contractor_hub/contractor_hub
|
||||
hijack_speed = 0.5 //10 seconds per hijack stage by default
|
||||
|
||||
/datum/antagonist/traitor/New()
|
||||
@@ -245,6 +246,9 @@
|
||||
|
||||
var/special_role_text = lowertext(name)
|
||||
|
||||
if(contractor_hub)
|
||||
result += contractor_round_end()
|
||||
|
||||
if(traitorwin)
|
||||
result += "<span class='greentext'>The [special_role_text] was successful!</span>"
|
||||
else
|
||||
@@ -253,12 +257,44 @@
|
||||
|
||||
return result.Join("<br>")
|
||||
|
||||
/// Proc detailing contract kit buys/completed contracts/additional info
|
||||
/datum/antagonist/traitor/proc/contractor_round_end()
|
||||
var result = ""
|
||||
var total_spent_rep = 0
|
||||
|
||||
var/completed_contracts = 0
|
||||
var/tc_total = contractor_hub.contract_TC_payed_out + contractor_hub.contract_TC_to_redeem
|
||||
for(var/datum/syndicate_contract/contract in contractor_hub.assigned_contracts)
|
||||
if(contract.status == CONTRACT_STATUS_COMPLETE)
|
||||
completed_contracts++
|
||||
|
||||
var/contractor_item_icons = "" // Icons of purchases
|
||||
var/contractor_support_unit = "" // Set if they had a support unit - and shows appended to their contracts completed
|
||||
|
||||
for(var/datum/contractor_item/contractor_purchase in contractor_hub.purchased_items) // Get all the icons/total cost for all our items bought
|
||||
contractor_item_icons += "<span class='tooltip_container'>\[ <i class=\"fas [contractor_purchase.item_icon]\"></i><span class='tooltip_hover'><b>[contractor_purchase.name] - [contractor_purchase.cost] Rep</b><br><br>[contractor_purchase.desc]</span> \]</span>"
|
||||
total_spent_rep += contractor_purchase.cost
|
||||
if(istype(contractor_purchase, /datum/contractor_item/contractor_partner)) // Special case for reinforcements, we want to show their ckey and name on round end.
|
||||
var/datum/contractor_item/contractor_partner/partner = contractor_purchase
|
||||
contractor_support_unit += "<br><b>[partner.partner_mind.key]</b> played <b>[partner.partner_mind.current.name]</b>, their contractor support unit."
|
||||
if (contractor_hub.purchased_items.len)
|
||||
result += "<br>(used [total_spent_rep] Rep)"
|
||||
result += contractor_item_icons
|
||||
result += "<br>"
|
||||
if(completed_contracts > 0)
|
||||
var/pluralCheck = "contract"
|
||||
if(completed_contracts > 1)
|
||||
pluralCheck = "contracts"
|
||||
result += "Completed <span class='greentext'>[completed_contracts]</span> [pluralCheck] for a total of \
|
||||
<span class='greentext'>[tc_total] TC</span>!<br>"
|
||||
return result
|
||||
|
||||
/datum/antagonist/traitor/roundend_report_footer()
|
||||
var/phrases = jointext(GLOB.syndicate_code_phrase, ", ")
|
||||
var/responses = jointext(GLOB.syndicate_code_response, ", ")
|
||||
|
||||
var message = "<br><b>The code phrases were:</b> <span class='bluetext'>[phrases]</span><br>\
|
||||
<b>The code responses were:</b> <span class='redtext'>[responses]</span><br>"
|
||||
<b>The code responses were:</b> <span class='redtext'>[responses]</span><br>"
|
||||
|
||||
return message
|
||||
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
// Support unit gets it's own very basic antag datum for admin logging.
|
||||
/datum/antagonist/traitor/contractor_support
|
||||
name = "Contractor Support Unit"
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
show_in_roundend = FALSE /// We're already adding them in to the contractor's roundend.
|
||||
give_objectives = TRUE /// We give them their own custom objective.
|
||||
show_in_antagpanel = FALSE /// Not a proper/full antag.
|
||||
should_equip = FALSE /// Don't give them an uplink.
|
||||
var/datum/team/contractor_team/contractor_team
|
||||
|
||||
/datum/team/contractor_team // Team for storing both the contractor and their support unit - only really for the HUD and admin logging.
|
||||
show_roundend_report = FALSE
|
||||
|
||||
/datum/antagonist/traitor/contractor_support/forge_traitor_objectives()
|
||||
var/datum/objective/generic_objective = new
|
||||
generic_objective.name = "Follow Contractor's Orders"
|
||||
generic_objective.explanation_text = "Follow your orders. Assist agents in this mission area."
|
||||
generic_objective.completed = TRUE
|
||||
add_objective(generic_objective)
|
||||
|
||||
/datum/contractor_hub
|
||||
var/contract_rep = 0
|
||||
var/list/hub_items = list()
|
||||
var/list/purchased_items = list()
|
||||
var/static/list/contractor_items = typecacheof(/datum/contractor_item/, TRUE)
|
||||
var/datum/syndicate_contract/current_contract
|
||||
var/list/datum/syndicate_contract/assigned_contracts = list()
|
||||
var/list/assigned_targets = list() // used as a blacklist to make sure we're not assigning targets already assigned
|
||||
var/contract_TC_payed_out = 0 // Keeping track for roundend reporting
|
||||
var/contract_TC_to_redeem = 0 // Used internally and roundend reporting - what TC we have available to cashout.
|
||||
|
||||
/datum/contractor_hub/proc/create_hub_items()
|
||||
for(var/path in contractor_items)
|
||||
var/datum/contractor_item/contractor_item = new path
|
||||
hub_items.Add(contractor_item)
|
||||
|
||||
/datum/contractor_hub/proc/create_contracts(datum/mind/owner) // 6 initial contracts
|
||||
var/list/to_generate = list(
|
||||
CONTRACT_PAYOUT_LARGE,
|
||||
CONTRACT_PAYOUT_MEDIUM,
|
||||
CONTRACT_PAYOUT_SMALL,
|
||||
CONTRACT_PAYOUT_SMALL,
|
||||
CONTRACT_PAYOUT_SMALL,
|
||||
CONTRACT_PAYOUT_SMALL
|
||||
)
|
||||
|
||||
var/lowest_TC_threshold = 30 // We don't want the sum of all the payouts to be under this amount
|
||||
var/total = 0
|
||||
var/lowest_paying_sum = 0
|
||||
var/datum/syndicate_contract/lowest_paying_contract
|
||||
|
||||
to_generate = shuffle(to_generate) // Randomise order, so we don't have contracts always in payout order.
|
||||
var/start_index = 1 // Support contract generation happening multiple times
|
||||
if(assigned_contracts.len != 0)
|
||||
start_index = assigned_contracts.len + 1
|
||||
|
||||
for(var/i = 1; i <= to_generate.len; i++) // Generate contracts, and find the lowest paying.
|
||||
var/datum/syndicate_contract/contract_to_add = new(owner, assigned_targets, to_generate[i])
|
||||
var/contract_payout_total = contract_to_add.contract.payout + contract_to_add.contract.payout_bonus
|
||||
assigned_targets.Add(contract_to_add.contract.target)
|
||||
if(!lowest_paying_contract || (contract_payout_total < lowest_paying_sum))
|
||||
lowest_paying_sum = contract_payout_total
|
||||
lowest_paying_contract = contract_to_add
|
||||
total += contract_payout_total
|
||||
contract_to_add.id = start_index
|
||||
assigned_contracts.Add(contract_to_add)
|
||||
start_index++
|
||||
if(total < lowest_TC_threshold) // If the threshold for TC payouts isn't reached, boost the lowest paying contract
|
||||
lowest_paying_contract.contract.payout_bonus += (lowest_TC_threshold - total)
|
||||
|
||||
/datum/contractor_item
|
||||
var/name // Name of item
|
||||
var/desc // description of item
|
||||
var/item // item path, no item path means the purchase needs it's own handle_purchase()
|
||||
var/item_icon = "fa-broadcast-tower" // fontawesome icon to use inside the hub - https://fontawesome.com/icons/
|
||||
var/limited = -1 // Any number above 0 for how many times it can be bought in a round for a single traitor. -1 is unlimited.
|
||||
var/cost // Cost of the item in contract rep.
|
||||
|
||||
/datum/contractor_item/contract_reroll
|
||||
name = "Contract Reroll"
|
||||
desc = "Request a reroll of your current contract list. Will generate a new target, payment, and dropoff for the contracts you currently have available."
|
||||
item_icon = "fa-dice"
|
||||
limited = 2
|
||||
cost = 0
|
||||
|
||||
/datum/contractor_item/contract_reroll/handle_purchase(var/datum/contractor_hub/hub)
|
||||
. = ..()
|
||||
if (.)
|
||||
var/list/new_target_list = list() // We're not regenerating already completed/aborted/extracting contracts, but we don't want to repeat their targets.
|
||||
for(var/datum/syndicate_contract/contract_check in hub.assigned_contracts)
|
||||
if (contract_check.status != CONTRACT_STATUS_ACTIVE && contract_check.status != CONTRACT_STATUS_INACTIVE)
|
||||
if (contract_check.contract.target)
|
||||
new_target_list.Add(contract_check.contract.target)
|
||||
continue
|
||||
for(var/datum/syndicate_contract/rerolling_contract in hub.assigned_contracts) // Reroll contracts without duplicates
|
||||
if (rerolling_contract.status != CONTRACT_STATUS_ACTIVE && rerolling_contract.status != CONTRACT_STATUS_INACTIVE)
|
||||
continue
|
||||
rerolling_contract.generate(new_target_list)
|
||||
new_target_list.Add(rerolling_contract.contract.target)
|
||||
hub.assigned_targets = new_target_list // Set our target list with the new set we've generated.
|
||||
|
||||
/datum/contractor_item/contractor_pinpointer
|
||||
name = "Contractor Pinpointer"
|
||||
desc = "A pinpointer that finds targets even without active suit sensors. Due to taking advantage of an exploit within the system, it can't pinpoint to the same accuracy as the traditional models. Becomes permanently locked to the user that first activates it."
|
||||
item = /obj/item/pinpointer/crew/contractor
|
||||
item_icon = "fa-search-location"
|
||||
limited = 2
|
||||
cost = 1
|
||||
|
||||
/datum/contractor_item/fulton_extraction_kit
|
||||
name = "Fulton Extraction Kit"
|
||||
desc = "For getting your target across the station to those difficult dropoffs. Place the beacon somewhere secure, and link the pack. Activating the pack on your target in space will send them over to the beacon - make sure they're not just going to run away though!"
|
||||
item = /obj/item/storage/box/contractor/fulton_extraction
|
||||
item_icon = "fa-parachute-box"
|
||||
limited = 1
|
||||
cost = 1
|
||||
|
||||
/datum/contractor_item/contractor_partner
|
||||
name = "Reinforcements"
|
||||
desc = "Upon purchase we'll contact available units in the area. Should there be an agent free, we'll send them down to assist you immediately. If no units are free, we give a full refund."
|
||||
item_icon = "fa-user-friends"
|
||||
limited = 1
|
||||
cost = 2
|
||||
var/datum/mind/partner_mind = null
|
||||
|
||||
/datum/contractor_item/contractor_partner/handle_purchase(var/datum/contractor_hub/hub, mob/living/user)
|
||||
. = ..()
|
||||
if (.)
|
||||
to_chat(user, "<span class='notice'>The uplink vibrates quietly, connecting to nearby agents...</span>")
|
||||
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the Contractor Support Unit for [user.real_name]?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_CONTRACTOR_SUPPORT)
|
||||
if(LAZYLEN(candidates))
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
spawn_contractor_partner(user, C.key)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>No available agents at this time, please try again later.</span>")
|
||||
limited += 1 // refund and add the limit back.
|
||||
hub.contract_rep += cost
|
||||
hub.purchased_items -= src
|
||||
|
||||
/datum/outfit/contractor_partner
|
||||
name = "Contractor Support Unit"
|
||||
uniform = /obj/item/clothing/under/chameleon
|
||||
suit = /obj/item/clothing/suit/chameleon
|
||||
back = /obj/item/storage/backpack
|
||||
belt = /obj/item/pda/chameleon
|
||||
mask = /obj/item/clothing/mask/cigarette/syndicate
|
||||
shoes = /obj/item/clothing/shoes/chameleon/noslip
|
||||
ears = /obj/item/radio/headset/chameleon
|
||||
id = /obj/item/card/id/syndicate
|
||||
r_hand = /obj/item/storage/toolbox/syndicate
|
||||
backpack_contents = list(/obj/item/storage/box/survival, /obj/item/implanter/uplink, /obj/item/clothing/mask/chameleon,
|
||||
/obj/item/storage/fancy/cigarettes/cigpack_syndicate, /obj/item/lighter)
|
||||
|
||||
/datum/outfit/contractor_partner/post_equip(mob/living/carbon/human/H, visualsOnly)
|
||||
. = ..()
|
||||
var/obj/item/clothing/mask/cigarette/syndicate/cig = H.get_item_by_slot(SLOT_WEAR_MASK)
|
||||
cig.light() // pre-light their cig for extra badass
|
||||
|
||||
/datum/contractor_item/contractor_partner/proc/spawn_contractor_partner(mob/living/user, key)
|
||||
var/mob/living/carbon/human/partner = new()
|
||||
var/datum/outfit/contractor_partner/partner_outfit = new()
|
||||
partner_outfit.equip(partner)
|
||||
var/obj/structure/closet/supplypod/arrival_pod = new()
|
||||
arrival_pod.style = STYLE_SYNDICATE
|
||||
arrival_pod.explosionSize = list(0,0,0,1)
|
||||
arrival_pod.bluespace = TRUE
|
||||
var/turf/free_location = find_obstruction_free_location(2, user)
|
||||
if (!free_location) // We really want to send them - if we can't find a nice location just land it on top of them.
|
||||
free_location = get_turf(user)
|
||||
partner.forceMove(arrival_pod)
|
||||
partner.ckey = key
|
||||
partner_mind = partner.mind // We give a reference to the mind that'll be the support unit
|
||||
partner_mind.make_Contractor_Support()
|
||||
to_chat(partner_mind.current, "\n<span class='alertwarning'>[user.real_name] is your superior. Follow any, and all orders given by them. You're here to support their mission only.</span>")
|
||||
to_chat(partner_mind.current, "<span class='alertwarning'>Should they perish, or be otherwise unavailable, you're to assist other active agents in this mission area to the best of your ability.</span>\n\n")
|
||||
new /obj/effect/abstract/DPtarget(free_location, arrival_pod)
|
||||
|
||||
/datum/contractor_item/blackout
|
||||
name = "Blackout"
|
||||
desc = "Request Syndicate Command to distrupt the station's powernet. Disables power across the station for a short duration."
|
||||
item_icon = "fa-bolt"
|
||||
limited = 2
|
||||
cost = 3
|
||||
|
||||
/datum/contractor_item/blackout/handle_purchase(var/datum/contractor_hub/hub)
|
||||
. = ..()
|
||||
if (.)
|
||||
power_fail(35, 50)
|
||||
priority_announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure", "poweroff")
|
||||
|
||||
// Subtract cost, and spawn if it's an item.
|
||||
/datum/contractor_item/proc/handle_purchase(var/datum/contractor_hub/hub, mob/living/user)
|
||||
if (hub.contract_rep >= cost)
|
||||
hub.contract_rep -= cost
|
||||
else
|
||||
return FALSE
|
||||
if (limited >= 1)
|
||||
limited -= 1
|
||||
else if (limited == 0)
|
||||
return FALSE
|
||||
hub.purchased_items.Add(src)
|
||||
if (item && ispath(item))
|
||||
var/atom/item_to_create = new item(get_turf(user))
|
||||
|
||||
if(user.put_in_hands(item_to_create))
|
||||
to_chat(user, "<span class='notice'>Your purchase materializes into your hands!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Your purchase materializes onto the floor.</span>")
|
||||
return item_to_create
|
||||
return TRUE
|
||||
|
||||
/obj/item/pinpointer/crew/contractor
|
||||
name = "contractor pinpointer"
|
||||
desc = "A handheld tracking device that locks onto certain signals. Ignores suit sensors, but is much less accurate."
|
||||
icon_state = "pinpointer_syndicate"
|
||||
minimum_range = 25
|
||||
has_owner = TRUE
|
||||
ignore_suit_sensor_level = TRUE
|
||||
|
||||
/obj/item/storage/box/contractor/fulton_extraction
|
||||
name = "Fulton Extraction Kit"
|
||||
icon_state = "syndiebox"
|
||||
illustration = "writing_syndie"
|
||||
|
||||
/obj/item/storage/box/contractor/fulton_extraction/PopulateContents()
|
||||
new /obj/item/extraction_pack(src)
|
||||
new /obj/item/fulton_core(src)
|
||||
@@ -0,0 +1,144 @@
|
||||
/datum/syndicate_contract
|
||||
var/id = 0
|
||||
var/status = CONTRACT_STATUS_INACTIVE
|
||||
var/datum/objective/contract/contract = new()
|
||||
var/ransom = 0
|
||||
var/payout_type = null
|
||||
var/list/victim_belongings = list()
|
||||
|
||||
/datum/syndicate_contract/New(contract_owner, blacklist, type=CONTRACT_PAYOUT_SMALL)
|
||||
contract.owner = contract_owner
|
||||
payout_type = type
|
||||
generate(blacklist)
|
||||
|
||||
/datum/syndicate_contract/proc/generate(blacklist)
|
||||
contract.find_target(null, blacklist)
|
||||
if (payout_type == CONTRACT_PAYOUT_LARGE)
|
||||
contract.payout_bonus = rand(9,13)
|
||||
else if(payout_type == CONTRACT_PAYOUT_MEDIUM)
|
||||
contract.payout_bonus = rand(6,8)
|
||||
else
|
||||
contract.payout_bonus = rand(2,4)
|
||||
contract.payout = rand(0, 2)
|
||||
contract.generate_dropoff()
|
||||
ransom = 100 * rand(18, 45)
|
||||
|
||||
/datum/syndicate_contract/proc/handle_extraction(var/mob/living/user)
|
||||
if (contract.target && contract.dropoff_check(user, contract.target.current))
|
||||
var/turf/free_location = find_obstruction_free_location(3, user, contract.dropoff)
|
||||
if(free_location) // We've got a valid location, launch.
|
||||
launch_extraction_pod(free_location)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Launch the pod to collect our victim.
|
||||
/datum/syndicate_contract/proc/launch_extraction_pod(turf/empty_pod_turf)
|
||||
var/obj/structure/closet/supplypod/extractionpod/empty_pod = new()
|
||||
RegisterSignal(empty_pod, COMSIG_ATOM_ENTERED, .proc/enter_check)
|
||||
empty_pod.stay_after_drop = TRUE
|
||||
empty_pod.reversing = TRUE
|
||||
empty_pod.explosionSize = list(0,0,0,1)
|
||||
empty_pod.leavingSound = 'sound/effects/podwoosh.ogg'
|
||||
new /obj/effect/abstract/DPtarget(empty_pod_turf, empty_pod)
|
||||
|
||||
/datum/syndicate_contract/proc/enter_check(datum/source, sent_mob)
|
||||
if(istype(source, /obj/structure/closet/supplypod/extractionpod))
|
||||
if(isliving(sent_mob))
|
||||
var/mob/living/M = sent_mob
|
||||
var/datum/antagonist/traitor/traitor_data = contract.owner.has_antag_datum(/datum/antagonist/traitor)
|
||||
if(M == contract.target.current)
|
||||
traitor_data.contractor_hub.contract_TC_to_redeem += contract.payout
|
||||
if(M.stat != DEAD)
|
||||
traitor_data.contractor_hub.contract_TC_to_redeem += contract.payout_bonus
|
||||
status = CONTRACT_STATUS_COMPLETE
|
||||
if(traitor_data.contractor_hub.current_contract == src)
|
||||
traitor_data.contractor_hub.current_contract = null
|
||||
traitor_data.contractor_hub.contract_rep += 2
|
||||
else
|
||||
status = CONTRACT_STATUS_ABORTED // Sending a target that wasn't even yours is as good as just aborting it
|
||||
if(traitor_data.contractor_hub.current_contract == src)
|
||||
traitor_data.contractor_hub.current_contract = null
|
||||
if(iscarbon(M))
|
||||
for(var/obj/item/W in M)
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(W == H.w_uniform || W == H.shoes)
|
||||
continue //So all they're left with are shoes and uniform.
|
||||
M.transferItemToLoc(W)
|
||||
victim_belongings.Add(W)
|
||||
var/obj/structure/closet/supplypod/extractionpod/pod = source
|
||||
pod.send_up(pod) // Handle the pod returning
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/target = M // After we remove items, at least give them what they need to live.
|
||||
target.dna.species.give_important_for_life(target)
|
||||
handleVictimExperience(M) // After pod is sent we start the victim narrative/heal.
|
||||
var/points_to_check = SSshuttle.points // This is slightly delayed because of the sleep calls above to handle the narrative. We don't want to tell the station instantly.
|
||||
if(points_to_check >= ransom)
|
||||
SSshuttle.points -= ransom
|
||||
else
|
||||
SSshuttle.points -= points_to_check
|
||||
priority_announce("One of your crew was captured by a rival organisation - we've needed to pay their ransom to bring them back. \
|
||||
As is policy we've taken a portion of the station's funds to offset the overall cost.", null, "attention", null, "Nanotrasen Asset Protection")
|
||||
|
||||
/datum/syndicate_contract/proc/handleVictimExperience(var/mob/living/M) // They're off to holding - handle the return timer and give some text about what's going on.
|
||||
addtimer(CALLBACK(src, .proc/returnVictim, M), (60 * 10) * 4) // Ship 'em back - dead or alive... 4 minutes wait.
|
||||
if(M.stat != DEAD) //Even if they weren't the target, we're still treating them the same.
|
||||
M.reagents.add_reagent(/datum/reagent/medicine/omnizine, 20) // Heal them up - gets them out of crit/soft crit.
|
||||
M.flash_act()
|
||||
M.confused += 10
|
||||
M.blur_eyes(5)
|
||||
to_chat(M, "<span class='warning'>You feel strange...</span>")
|
||||
sleep(60)
|
||||
to_chat(M, "<span class='warning'>That pod did something to you...</span>")
|
||||
M.Dizzy(35)
|
||||
sleep(65)
|
||||
to_chat(M, "<span class='warning'>Your head pounds... It feels like it's going to burst out your skull!</span>")
|
||||
M.flash_act()
|
||||
M.confused += 20
|
||||
M.blur_eyes(3)
|
||||
sleep(30)
|
||||
to_chat(M, "<span class='warning'>Your head pounds...</span>")
|
||||
sleep(100)
|
||||
M.flash_act()
|
||||
M.Unconscious(200)
|
||||
to_chat(M, "<span class='reallybig hypnophrase'>A million voices echo in your head... <i>\"Your mind held many valuable secrets - \
|
||||
we thank you for providing them. Your value is expended, and you will be ransomed back to your station. We always get paid, \
|
||||
so it's only a matter of time before we ship you back...\"</i></span>")
|
||||
M.blur_eyes(10)
|
||||
M.Dizzy(15)
|
||||
M.confused += 20
|
||||
|
||||
/datum/syndicate_contract/proc/returnVictim(var/mob/living/M) // We're returning the victim
|
||||
var/list/possible_drop_loc = list()
|
||||
for(var/turf/possible_drop in contract.dropoff.contents)
|
||||
if(!is_blocked_turf(possible_drop))
|
||||
possible_drop_loc.Add(possible_drop)
|
||||
if(possible_drop_loc.len > 0)
|
||||
var/pod_rand_loc = rand(1, possible_drop_loc.len)
|
||||
var/obj/structure/closet/supplypod/return_pod = new()
|
||||
return_pod.bluespace = TRUE
|
||||
return_pod.explosionSize = list(0,0,0,0)
|
||||
return_pod.style = STYLE_SYNDICATE
|
||||
do_sparks(8, FALSE, M)
|
||||
M.visible_message("<span class='notice'>[M] vanishes...</span>")
|
||||
for(var/obj/item/W in M)
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(W == H.w_uniform || W == H.shoes)
|
||||
continue //So all they're left with are shoes and uniform.
|
||||
M.dropItemToGround(W)
|
||||
for(var/obj/item/W in victim_belongings)
|
||||
W.forceMove(return_pod)
|
||||
M.forceMove(return_pod)
|
||||
M.flash_act()
|
||||
M.blur_eyes(30)
|
||||
M.Dizzy(35)
|
||||
M.confused += 20
|
||||
new /obj/effect/abstract/DPtarget(possible_drop_loc[pod_rand_loc], return_pod)
|
||||
else
|
||||
to_chat(M, "<span class='reallybig hypnophrase'>A million voices echo in your head... <i>\"Seems where you got sent here from won't \
|
||||
be able to handle our pod... You will die here instead.\"</i></span>")
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/C = M
|
||||
if(C.can_heartattack())
|
||||
C.set_heartattack(TRUE)
|
||||
@@ -261,7 +261,7 @@
|
||||
GiveHint(target)
|
||||
else if(is_pointed(I))
|
||||
to_chat(target, "<span class='userdanger'>You feel a stabbing pain in [parse_zone(user.zone_selected)]!</span>")
|
||||
target.Knockdown(40)
|
||||
target.DefaultCombatKnockdown(40)
|
||||
GiveHint(target)
|
||||
else if(istype(I, /obj/item/bikehorn))
|
||||
to_chat(target, "<span class='userdanger'>HONK</span>")
|
||||
@@ -377,7 +377,10 @@
|
||||
/obj/item/warpwhistle/proc/end_effect(mob/living/carbon/user)
|
||||
user.invisibility = initial(user.invisibility)
|
||||
user.status_flags &= ~GODMODE
|
||||
user.canmove = TRUE
|
||||
REMOVE_TRAIT(user, TRAIT_MOBILITY_NOMOVE, src)
|
||||
REMOVE_TRAIT(user, TRAIT_MOBILITY_NOUSE, src)
|
||||
REMOVE_TRAIT(user, TRAIT_MOBILITY_NOPICKUP, src)
|
||||
user.update_mobility()
|
||||
|
||||
/obj/item/warpwhistle/attack_self(mob/living/carbon/user)
|
||||
if(!istype(user) || on_cooldown)
|
||||
@@ -390,7 +393,10 @@
|
||||
on_cooldown = TRUE
|
||||
last_user = user
|
||||
playsound(T,'sound/magic/warpwhistle.ogg', 200, 1)
|
||||
user.canmove = FALSE
|
||||
ADD_TRAIT(user, TRAIT_MOBILITY_NOMOVE, src)
|
||||
ADD_TRAIT(user, TRAIT_MOBILITY_NOUSE, src)
|
||||
ADD_TRAIT(user, TRAIT_MOBILITY_NOPICKUP, src)
|
||||
user.update_mobility()
|
||||
new /obj/effect/temp_visual/tornado(T)
|
||||
sleep(20)
|
||||
if(interrupted(user))
|
||||
@@ -412,7 +418,6 @@
|
||||
return
|
||||
if(T.z != potential_T.z || abs(get_dist_euclidian(potential_T,T)) > 50 - breakout)
|
||||
do_teleport(user, potential_T, channel = TELEPORT_CHANNEL_MAGIC)
|
||||
user.canmove = 0
|
||||
T = potential_T
|
||||
break
|
||||
breakout += 1
|
||||
|
||||
@@ -83,8 +83,8 @@
|
||||
/obj/item/soulstone/proc/release_shades(mob/user)
|
||||
for(var/mob/living/simple_animal/shade/A in src)
|
||||
A.status_flags &= ~GODMODE
|
||||
A.canmove = TRUE
|
||||
A.forceMove(get_turf(user))
|
||||
A.mobility_flags = MOBILITY_FLAGS_DEFAULT
|
||||
A.cancel_camera()
|
||||
icon_state = "soulstone"
|
||||
name = initial(name)
|
||||
@@ -173,7 +173,7 @@
|
||||
else
|
||||
T.forceMove(src) //put shade in stone
|
||||
T.status_flags |= GODMODE
|
||||
T.canmove = FALSE
|
||||
T.mobility_flags = NONE
|
||||
T.health = T.maxHealth
|
||||
icon_state = "soulstone2"
|
||||
name = "soulstone: Shade of [T.real_name]"
|
||||
@@ -240,8 +240,8 @@
|
||||
T.dust_animation()
|
||||
QDEL_IN(T, 5)
|
||||
var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade(src)
|
||||
S.status_flags |= GODMODE //So they won't die inside the stone somehow
|
||||
S.canmove = FALSE//Can't move out of the soul stone
|
||||
S.status_flags |= GODMODE //So they won't die inside the stone somehow
|
||||
S.mobility_flags = NONE //Can't move out of the soul stone
|
||||
S.name = "Shade of [T.real_name]"
|
||||
S.real_name = "Shade of [T.real_name]"
|
||||
T.transfer_ckey(S)
|
||||
|
||||
Reference in New Issue
Block a user