-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
Copy path_pointed.dm
177 lines (144 loc) · 6.13 KB
/
_pointed.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
/**
* ## Pointed spells
*
* These spells override the caster's click,
* allowing them to cast the spell on whatever is clicked on.
*
* To add effects on cast, override "cast(atom/cast_on)".
* The cast_on atom is the person who was clicked on.
*/
/datum/action/cooldown/spell/pointed
click_to_activate = TRUE
/// Message showing to the spell owner upon activating pointed spell.
var/active_msg
/// Message showing to the spell owner upon deactivating pointed spell.
var/deactive_msg
/// The casting range of our spell
var/cast_range = 7
/// Variable dictating if the spell will use turf based aim assist
var/aim_assist = TRUE
/datum/action/cooldown/spell/pointed/New(Target)
. = ..()
if(!active_msg)
active_msg = "You prepare to use [src] on a target..."
if(!deactive_msg)
deactive_msg = "You dispel [src]."
/datum/action/cooldown/spell/pointed/set_click_ability(mob/on_who)
. = ..()
if(!.)
return
on_activation(on_who)
// Note: Destroy() calls Remove(), Remove() calls unset_click_ability() if our spell is active.
/datum/action/cooldown/spell/pointed/unset_click_ability(mob/on_who, refund_cooldown = TRUE)
. = ..()
if(!.)
return
on_deactivation(on_who, refund_cooldown = refund_cooldown)
/datum/action/cooldown/spell/pointed/before_cast(atom/cast_on)
. = ..()
if(. & SPELL_CANCEL_CAST)
on_deactivation(owner, refund_cooldown = FALSE)
if(owner && get_dist(get_turf(owner), get_turf(cast_on)) > cast_range)
cast_on.balloon_alert(owner, "too far away!")
return . | SPELL_CANCEL_CAST
/// Called when the spell is activated / the click ability is set to our spell
/datum/action/cooldown/spell/pointed/proc/on_activation(mob/on_who)
SHOULD_CALL_PARENT(TRUE)
to_chat(on_who, span_notice("[active_msg] <B>Left-click to cast the spell on a target!</B>"))
build_all_button_icons()
return TRUE
/// Called when the spell is deactivated / the click ability is unset from our spell
/datum/action/cooldown/spell/pointed/proc/on_deactivation(mob/on_who, refund_cooldown = TRUE)
SHOULD_CALL_PARENT(TRUE)
if(refund_cooldown)
// Only send the "deactivation" message if they're willingly disabling the ability
to_chat(on_who, span_notice("[deactive_msg]"))
build_all_button_icons()
return TRUE
/datum/action/cooldown/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/click_target)
var/atom/aim_assist_target
if(aim_assist && isturf(click_target))
// Find any human in the list. We aren't picky, it's aim assist after all
aim_assist_target = locate(/mob/living/carbon/human) in click_target
if(!aim_assist_target)
// If we didn't find a human, we settle for any living at all
aim_assist_target = locate(/mob/living) in click_target
caller.face_atom(click_target)
return ..(caller, params, aim_assist_target || click_target)
/datum/action/cooldown/spell/pointed/is_valid_target(atom/cast_on)
if(cast_on == owner)
to_chat(owner, span_warning("You cannot cast [src] on yourself!"))
return FALSE
return TRUE
/**
* ### Pointed projectile spells
*
* Pointed spells that, instead of casting a spell directly on the target that's clicked,
* will instead fire a projectile pointed at the target's direction.
*/
/datum/action/cooldown/spell/pointed/projectile
/// What projectile we create when we shoot our spell.
var/obj/projectile/magic/projectile_type = /obj/projectile/magic/teleport
/// How many projectiles we can fire per cast. Not all at once, per click, kinda like charges
var/projectile_amount = 1
/// How many projectiles we have yet to fire, based on projectile_amount
var/current_amount = 0
/// How many projectiles we fire every fire_projectile() call.
/// Unwise to change without overriding or extending ready_projectile.
var/projectiles_per_fire = 1
/datum/action/cooldown/spell/pointed/projectile/New(Target)
. = ..()
if(projectile_amount > 1)
unset_after_click = FALSE
/datum/action/cooldown/spell/pointed/projectile/is_valid_target(atom/cast_on)
return TRUE
/datum/action/cooldown/spell/pointed/projectile/on_activation(mob/on_who)
. = ..()
if(!.)
return
current_amount = projectile_amount
/datum/action/cooldown/spell/pointed/projectile/on_deactivation(mob/on_who, refund_cooldown = TRUE)
. = ..()
if(projectile_amount > 1 && current_amount)
StartCooldown(cooldown_time * ((projectile_amount - current_amount) / projectile_amount))
current_amount = 0
// cast_on is a turf, or atom target, that we clicked on to fire at.
/datum/action/cooldown/spell/pointed/projectile/cast(atom/cast_on)
. = ..()
if(!isturf(owner.loc))
return FALSE
var/turf/caster_turf = get_turf(owner)
// Get the tile infront of the caster, based on their direction
var/turf/caster_front_turf = get_step(owner, owner.dir)
fire_projectile(cast_on)
owner.newtonian_move(get_dir(caster_front_turf, caster_turf))
if(current_amount <= 0)
unset_click_ability(owner, refund_cooldown = FALSE)
return TRUE
/datum/action/cooldown/spell/pointed/projectile/after_cast(atom/cast_on)
. = ..()
if(current_amount > 0)
// We still have projectiles to cast!
// Reset our cooldown and let them fire away
reset_spell_cooldown()
/datum/action/cooldown/spell/pointed/projectile/proc/fire_projectile(atom/target)
current_amount--
for(var/i in 1 to projectiles_per_fire)
var/obj/projectile/to_fire = new projectile_type()
ready_projectile(to_fire, target, owner, i)
SEND_SIGNAL(owner, COMSIG_MOB_SPELL_PROJECTILE, src, target, to_fire)
to_fire.fire()
return TRUE
/datum/action/cooldown/spell/pointed/projectile/proc/ready_projectile(obj/projectile/to_fire, atom/target, mob/user, iteration)
to_fire.firer = owner
to_fire.fired_from = get_turf(owner)
to_fire.preparePixelProjectile(target, owner)
RegisterSignal(to_fire, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(on_cast_hit))
if(istype(to_fire, /obj/projectile/magic))
var/obj/projectile/magic/magic_to_fire = to_fire
magic_to_fire.antimagic_flags = antimagic_flags
/// Signal proc for whenever the projectile we fire hits someone.
/// Pretty much relays to the spell when the projectile actually hits something.
/datum/action/cooldown/spell/pointed/projectile/proc/on_cast_hit(atom/source, mob/firer, atom/hit, angle)
SIGNAL_HANDLER
SEND_SIGNAL(src, COMSIG_SPELL_PROJECTILE_HIT, hit, firer, source)