-
-
Notifications
You must be signed in to change notification settings - Fork 452
/
lunge.dm
196 lines (171 loc) · 7.16 KB
/
lunge.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/datum/action/cooldown/bloodsucker/targeted/lunge
name = "Predatory Lunge"
desc = "Spring at your target to grapple them without warning, or tear the dead's heart out. Attacks from concealment or the rear may even knock them down if strong enough."
button_icon_state = "power_lunge"
power_explanation = "Predatory Lunge:\n\
Click any player to start spinning wildly and, after a short delay, dash at them.\n\
When lunging at someone, you will grab them, immediately starting off at aggressive.\n\
Riot gear and Monster Hunters are protected and will only be passively grabbed.\n\
You cannot use the Power if you are already grabbing someone, or are being grabbed.\n\
If you grab from behind, or from darkness (Cloak of Darkness works), you will knock the target down.\n\
If used on a dead body, will tear their heart out.\n\
Higher levels increase the knockdown dealt to enemies.\n\
At level 4, you will no longer spin, but you will be limited to tackling from only 6 tiles away."
power_flags = NONE
check_flags = BP_CANT_USE_IN_TORPOR|BP_CANT_USE_IN_FRENZY|BP_CANT_USE_WHILE_INCAPACITATED|BP_CANT_USE_WHILE_UNCONSCIOUS
purchase_flags = BLOODSUCKER_CAN_BUY|VASSAL_CAN_BUY
bloodcost = 10
cooldown_time = 10 SECONDS
power_activates_immediately = FALSE
ascended_power = /datum/action/cooldown/bloodsucker/targeted/lunge/shadow
/datum/action/cooldown/bloodsucker/targeted/lunge/upgrade_power()
. = ..()
//range is lowered when you get stronger.
if(level_current > 3)
target_range = 6
/*
* Level 1: Grapple level 2
* Level 2: Grapple 3 from Behind
* Level 3: Grapple 3 from Shadows
*/
/datum/action/cooldown/bloodsucker/targeted/lunge/CanUse(mob/living/carbon/user)
. = ..()
if(!.)
return FALSE
// Are we being grabbed?
if(user.pulledby && user.pulledby.grab_state >= GRAB_AGGRESSIVE)
owner.balloon_alert(user, "grabbed!")
return FALSE
if(user.pulling)
owner.balloon_alert(user, "grabbing someone!")
return FALSE
return TRUE
/// Check: Are we lunging at a person?
/datum/action/cooldown/bloodsucker/targeted/lunge/CheckValidTarget(atom/target_atom)
. = ..()
if(!.)
return FALSE
return isliving(target_atom)
/datum/action/cooldown/bloodsucker/targeted/lunge/CheckCanTarget(atom/target_atom)
// Default Checks
. = ..()
if(!.)
return FALSE
// Check: Turf
var/mob/living/turf_target = target_atom
if(!isturf(turf_target.loc))
return FALSE
// Check: can the Bloodsucker even move?
var/mob/living/user = owner
if(!(user.mobility_flags & MOBILITY_STAND) || user.IsImmobilized())
to_chat(user, span_warning("You need to be standing and aware to lunge!"))
return FALSE
return TRUE
/datum/action/cooldown/bloodsucker/targeted/lunge/can_deactivate()
return !(datum_flags & DF_ISPROCESSING) //only if you aren't lunging
/datum/action/cooldown/bloodsucker/targeted/lunge/FireTargetedPower(atom/target_atom)
. = ..()
owner.face_atom(target_atom)
if(level_current > 3)
do_lunge(target_atom)
return
prepare_target_lunge(target_atom)
return TRUE
///Starts processing the power and prepares the lunge by spinning, calls lunge at the end of it.
/datum/action/cooldown/bloodsucker/targeted/lunge/proc/prepare_target_lunge(atom/target_atom)
START_PROCESSING(SSprocessing, src)
owner.balloon_alert(owner, "lunge started!")
//animate them shake
var/base_x = owner.base_pixel_x
var/base_y = owner.base_pixel_y
animate(owner, pixel_x = base_x, pixel_y = base_y, time = 0.1 SECONDS, loop = -1)
for(var/i in 1 to 25)
var/x_offset = base_x + rand(-3, 3)
var/y_offset = base_y + rand(-3, 3)
animate(pixel_x = x_offset, pixel_y = y_offset, time = 0.1 SECONDS)
if(!do_after(owner, 4 SECONDS, timed_action_flags = IGNORE_USER_LOC_CHANGE, extra_checks = CALLBACK(src, PROC_REF(CheckCanTarget), target_atom)))
end_target_lunge(base_x, base_y)
return FALSE
end_target_lunge()
do_lunge(target_atom)
return TRUE
///When preparing to lunge ends, this clears it up.
/datum/action/cooldown/bloodsucker/targeted/lunge/proc/end_target_lunge(base_x, base_y)
animate(owner, pixel_x = base_x, pixel_y = base_y, time = 0.1 SECONDS)
STOP_PROCESSING(SSprocessing, src)
/datum/action/cooldown/bloodsucker/targeted/lunge/process()
if(!active) //If running SSfasprocess (on cooldown)
return ..() //Manage our cooldown timers
if(prob(75))
owner.spin(8, 1)
owner.balloon_alert_to_viewers("spins wildly!", "you spin!")
return
do_smoke(0, owner.loc, smoke_type = /obj/effect/particle_effect/fluid/smoke/transparent)
///Actually lunges the target, then calls lunge end.
/datum/action/cooldown/bloodsucker/targeted/lunge/proc/do_lunge(atom/hit_atom)
var/turf/targeted_turf = get_turf(hit_atom)
var/safety = get_dist(owner, targeted_turf) * 3 + 1
var/consequetive_failures = 0
while(--safety && !hit_atom.Adjacent(owner))
if(!step_to(owner, targeted_turf))
consequetive_failures++
if(consequetive_failures >= 3) // If 3 steps don't work, just stop.
break
lunge_end(hit_atom, targeted_turf)
/datum/action/cooldown/bloodsucker/targeted/lunge/proc/lunge_end(atom/hit_atom, turf/target_turf)
power_activated_sucessfully()
// Am I next to my target to start giving the effects?
if(!owner.Adjacent(hit_atom))
return
var/mob/living/user = owner
var/mob/living/carbon/target = hit_atom
// Did I slip or get knocked unconscious?
if(!(user.mobility_flags & MOBILITY_STAND) || user.incapacitated())
var/send_dir = get_dir(user, target_turf)
new /datum/forced_movement(user, get_ranged_target_turf(user, send_dir, 1), 1, FALSE)
user.spin(10)
return
// Is my target a Monster hunter?
var/mob/living/carbon/human/H = target
if(IS_MONSTERHUNTER(target) || H?.is_shove_knockdown_blocked())
owner.balloon_alert(owner, "pushed away!")
target.grabbedby(owner)
return
owner.balloon_alert(owner, "you lunge at [target]!")
if(target.stat == DEAD)
var/obj/item/bodypart/chest = target.get_bodypart(BODY_ZONE_CHEST)
var/datum/wound/slash/moderate/crit_wound = new
crit_wound.apply_wound(chest)
owner.visible_message(
span_warning("[owner] tears into [target]'s chest!"),
span_warning("You tear into [target]'s chest!"))
var/obj/item/organ/heart/myheart_now = locate() in target.internal_organs
if(myheart_now)
myheart_now.Remove(target)
user.put_in_hands(myheart_now)
else
target.grabbedby(owner)
target.grippedby(owner, instant = TRUE)
// Did we knock them down?
if(!is_A_facing_B(target, owner) || owner.alpha <= 40)
target.Knockdown(10 + level_current * 5)
target.Paralyze(0.1)
/datum/action/cooldown/bloodsucker/targeted/lunge/DeactivatePower()
var/mob/living/O = owner
O.SetImmobilized(0)
return ..()
/datum/action/cooldown/bloodsucker/targeted/lunge/shadow
name = "Dark Embrace"
background_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
active_background_icon_state = "lasombra_power_on"
base_background_icon_state = "lasombra_power_off"
button_icon = 'icons/mob/actions/actions_lasombra_bloodsucker.dmi'
button_icon_state = "power_embrace"
additional_text = "Additionally makes the target walk."
purchase_flags = LASOMBRA_CAN_BUY
ascended_power = null
/datum/action/cooldown/bloodsucker/targeted/lunge/shadow/lunge_end(atom/hit_atom)
. = ..()
var/mob/living/carbon/target = hit_atom
if(target.m_intent != MOVE_INTENT_WALK)
target.toggle_move_intent()