-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
Copy pathpseudocider.dm
125 lines (109 loc) · 4.6 KB
/
pseudocider.dm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/obj/item/pseudocider
name = "syndicate pseudocider"
desc = "A syndicate device that triggers upon taking damage, making you invisible and leaving behind a fake body."
icon = 'icons/obj/device.dmi'
icon_state = "pocketwatch-closed"
base_icon_state = "pocketwatch"
w_class = WEIGHT_CLASS_SMALL
actions_types = list(/datum/action/item_action/toggle_pseudocider)
var/active = FALSE
var/mob/living/carbon/fake_corpse
COOLDOWN_DECLARE(fake_death_timer)
var/fake_death_cooldown = 30 SECONDS
///traits applied to the user when they're faking death
var/list/pseudocider_traits = list(TRAIT_NOINTERACT, TRAIT_HIGHRESISTDAMAGESLOWDOWN, TRAIT_SILENT_FOOTSTEPS)
/obj/item/pseudocider/update_icon_state()
icon_state = "[base_icon_state][active ? "-open" : "-closed"]"
return ..()
/obj/item/pseudocider/Initialize(mapload)
. = ..()
// Meant to work from the pocket as well
RegisterSignals(src, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_PICKUP), PROC_REF(assign_user))
RegisterSignal(src, COMSIG_ITEM_DROPPED, PROC_REF(drop_user))
RegisterSignal(src, COMSIG_ITEM_ATTACK_SELF, PROC_REF(self_attack))
/obj/item/pseudocider/proc/assign_user(datum/source, mob/living/carbon/user)
SIGNAL_HANDLER
if(!istype(user))
return
RegisterSignal(user, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(fake_death))
/obj/item/pseudocider/proc/drop_user(datum/source, mob/living/carbon/user)
SIGNAL_HANDLER
UnregisterSignal(user, COMSIG_MOB_APPLY_DAMAGE)
/obj/item/pseudocider/proc/self_attack(datum/source, mob/user)
SIGNAL_HANDLER
if(!iscarbon(user))
return
if(HAS_TRAIT(user, TRAIT_NOINTERACT))
return
if(!COOLDOWN_FINISHED(src, fake_death_timer) && !active)
to_chat(user, span_notice("\The [src] refuses to open! Wait [COOLDOWN_TIMELEFT(src, fake_death_timer)/10] more seconds!"))
return
active = !active
update_appearance(UPDATE_ICON)
/obj/item/pseudocider/proc/fake_death(mob/living/carbon/copied_mob, damage, damagetype, def_zone)
SIGNAL_HANDLER
if(HAS_TRAIT(copied_mob, TRAIT_NOINTERACT))
return
if(!active)
return
if(!COOLDOWN_FINISHED(src, fake_death_timer))
return
if(damage <= 0)
return
if(!istype(copied_mob))
return
if(copied_mob.stat > CONSCIOUS)
return
var/turf/copy_location = get_turf(copied_mob)
if(!istype(copy_location))
return
COOLDOWN_START(src, fake_death_timer, fake_death_cooldown) // sanity
// Set up the mob to be identical
if(ishuman(copied_mob))
fake_corpse = visually_duplicate_human(copied_mob, TRUE)
else
fake_corpse = new copied_mob.type
// Clothes for monkeys (and xenos?)
for(var/obj/item/clothing/equipped as anything in copied_mob.get_equipped_items())
var/obj/item/clothing/cloth = new equipped.type
cloth.name = equipped.name
cloth.icon = equipped.icon
cloth.icon_state = equipped.icon_state
cloth.item_state = equipped.item_state
cloth.damaged_clothes = equipped.damaged_clothes
if(HAS_BLOOD_DNA(equipped))
var/datum/component/forensics/detective_work = equipped.GetComponent(/datum/component/forensics)
cloth.add_blood_DNA(detective_work.blood_DNA) // authentic
cloth.update_icon(UPDATE_OVERLAYS)
cloth.item_flags |= DROPDEL
if(!fake_corpse.equip_to_appropriate_slot(cloth))
QDEL_NULL(cloth)
// Damage
INVOKE_ASYNC(fake_corpse, TYPE_PROC_REF(/mob/living,take_overall_damage), copied_mob.get_damage_amount(BRUTE), copied_mob.get_damage_amount(BURN))
INVOKE_ASYNC(fake_corpse, TYPE_PROC_REF(/mob/living,take_overall_damage), damagetype == BRUTE ? damage : 0, damagetype == BURN ? damage : 0)
// Fake key + client so they don't appear catatonic/ssd
fake_corpse.key = "#[rand(1000,9999)]#FakeCorpse"
fake_corpse.fake_client = TRUE
// Put the mob in place of the user
fake_corpse.dir = copied_mob.dir
fake_corpse.forceMove(copy_location)
// and vanish the user
copied_mob.alpha = 0
// also make their footsteps silent
copied_mob.add_traits(pseudocider_traits, PSEUDOCIDER_TRAIT)
if(damagetype == STAMINA)
fake_corpse.Paralyze(100 SECONDS)
else
INVOKE_ASYNC(fake_corpse, TYPE_PROC_REF(/mob/living,death))
addtimer(CALLBACK(src, PROC_REF(unfake_death), copied_mob, fake_corpse), 7 SECONDS)
/obj/item/pseudocider/proc/unfake_death(mob/living/carbon/copied_mob, mob/living/carbon/fake_corpse)
active = FALSE
update_appearance(UPDATE_ICON)
COOLDOWN_START(src, fake_death_timer, fake_death_cooldown)
if(!QDELETED(copied_mob) && istype(copied_mob))
animate(copied_mob, 0.5 SECONDS, alpha = 255)
copied_mob.remove_traits(pseudocider_traits, PSEUDOCIDER_TRAIT)
if(!QDELETED(fake_corpse) && istype(fake_corpse))
fake_corpse.visible_message(span_notice("The body vanishes! It was a fake!"))
animate(fake_corpse, 0.5 SECONDS, alpha = 0)
QDEL_IN(fake_corpse, 0.6 SECONDS)