-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
Copy pathstunbaton.dm
328 lines (290 loc) · 10.7 KB
/
stunbaton.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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
#define STUNBATON_DISCHARGE_INTERVAL 13 //amount of active processes it takes for the stun baton to start discharging
/obj/item/melee/baton
name = "stun baton"
desc = "A stun baton for incapacitating people with."
icon = 'icons/obj/weapons/baton.dmi'
icon_state = "stunbaton"
item_state = "baton"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
slot_flags = ITEM_SLOT_BELT
force = 10
throwforce = 7
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("beaten")
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 0, RAD = 0, FIRE = 80, ACID = 80)
var/cooldown_check = 0
///how long we can't use this baton for after slapping someone with it. Does not account for melee attack cooldown (default of 0.8 seconds).
var/cooldown = 1.2 SECONDS
///how long a clown stuns themself for, or someone is stunned for if they are hit to >90 stamina damage
var/stunforce = 10 SECONDS
///how much stamina damage we deal per hit, this is combatted by energy armor
var/stamina_damage = 70
///are we turned on
var/status = FALSE
///the cell used by the baton
var/obj/item/stock_parts/cell/cell
///how much charge is deducted from the cell when we slap someone while on
var/hitcost = 1000
///% chance we hit someone with the correct side of the baton when thrown
var/throw_hit_chance = 35
///if not empty the baton starts with this type of cell
var/preload_cell_type
///used for passive discharge
var/cell_last_used = 0
light_range = 1.5
light_system = MOVABLE_LIGHT
light_on = FALSE
light_color = LIGHT_COLOR_ORANGE
light_power = 0.5
/// Toggles the stun baton's light
/obj/item/melee/baton/proc/toggle_light(mob/user)
set_light_on(!light_on)
return
/obj/item/melee/baton/get_cell()
return cell
/obj/item/melee/baton/suicide_act(mob/user)
if(status)
user.visible_message(span_suicide("[user] is putting the live [name] in [user.p_their()] mouth! It looks like [user.p_theyre()] trying to commit suicide!"))
return FIRELOSS
user.visible_message(span_suicide("[user] is putting the [name] in [user.p_their()] mouth! But forgot to turn the [name] on."))
return SHAME
/obj/item/melee/baton/Initialize(mapload)
. = ..()
if(preload_cell_type)
if(!ispath(preload_cell_type,/obj/item/stock_parts/cell))
log_mapping("[src] at [AREACOORD(src)] had an invalid preload_cell_type: [preload_cell_type].")
else
cell = new preload_cell_type(src)
update_appearance(UPDATE_ICON)
/obj/item/melee/baton/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(..())
return
//Only mob/living types have stun handling
if(status && prob(throw_hit_chance) && iscarbon(hit_atom))
baton_stun(hit_atom)
/obj/item/melee/baton/loaded //this one starts with a cell pre-installed.
preload_cell_type = /obj/item/stock_parts/cell/high
/obj/item/melee/baton/proc/deductcharge(chrgdeductamt)
if(cell)
//Note this value returned is significant, as it will determine
//if a stun is applied or not
var/mob/living/M = loc
if(M && iscyborg(M))
var/mob/living/silicon/robot/R = loc
R.cell.use(chrgdeductamt)
else
. = cell.use(chrgdeductamt)
if(status && cell.charge < hitcost)
//we're below minimum, turn off
status = FALSE
set_light_on(FALSE)
update_appearance(UPDATE_ICON)
playsound(loc, "sparks", 75, 1, -1)
STOP_PROCESSING(SSobj, src) // no more charge? stop checking for discharge
/obj/item/melee/baton/update_icon_state()
. = ..()
if(status)
icon_state = "[initial(icon_state)]_active"
else if(!cell)
icon_state = "[initial(icon_state)]_nocell"
else
icon_state = "[initial(icon_state)]"
/obj/item/melee/baton/process()
if(status)
++cell_last_used // Will discharge in 13 processes if it is not turned off
if(cell_last_used >= STUNBATON_DISCHARGE_INTERVAL)
deductcharge(500)
cell_last_used = 6 // Will discharge again in 7 processes if it is not turned off
/obj/item/melee/baton/examine(mob/user)
. = ..()
. += span_notice("Left click to stun, right click to harm.")
if(cell)
. += span_notice("\The [src] is [round(cell.percent())]% charged.")
else
. += span_warning("\The [src] does not have a power source installed.")
/obj/item/melee/baton/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/stock_parts/cell))
var/obj/item/stock_parts/cell/C = W
if(cell)
to_chat(user, span_notice("[src] already has a cell."))
else
if(C.maxcharge < hitcost)
to_chat(user, span_notice("[src] requires a higher capacity cell."))
return
if(!user.transferItemToLoc(W, src))
return
cell = W
to_chat(user, span_notice("You install a cell in [src]."))
update_appearance(UPDATE_ICON)
else if(W.tool_behaviour == TOOL_SCREWDRIVER)
if(cell)
cell.update_appearance(UPDATE_ICON)
cell.forceMove(get_turf(src))
cell = null
to_chat(user, span_notice("You remove the cell from [src]."))
status = FALSE
STOP_PROCESSING(SSobj, src) // no cell, no charge; stop processing for on because it cant be on
update_appearance(UPDATE_ICON)
else
return ..()
/obj/item/melee/baton/attack_self(mob/user)
if(cell && cell.charge > hitcost)
status = !status
to_chat(user, span_notice("[src] is now [status ? "on" : "off"]."))
playsound(loc, "sparks", 75, 1, -1)
toggle_light(user)
do_sparks(1, TRUE, src)
cell_last_used = 0
if(status)
START_PROCESSING(SSobj, src)
else
STOP_PROCESSING(SSobj, src)
else
status = FALSE
if(!cell)
to_chat(user, span_warning("[src] does not have a power source!"))
else
to_chat(user, span_warning("[src] is out of charge."))
update_appearance(UPDATE_ICON)
add_fingerprint(user)
/obj/item/melee/baton/attack(mob/M, mob/living/carbon/human/user, params)
if(status && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
user.visible_message(span_danger("[user] accidentally hits [user.p_them()]self with [src]!"), \
span_userdanger("You accidentally hit yourself with [src]!"))
user.Paralyze(stunforce*3)
deductcharge(hitcost)
return
if(!synth_check(user, SYNTH_RESTRICTED_WEAPON))
return
if(HAS_TRAIT(user, TRAIT_NO_STUN_WEAPONS))
to_chat(user, span_warning("You can't seem to remember how this works!"))
return
//yogs edit begin ---------------------------------
if(status && isethereal(M))
M.adjust_nutrition(40)
to_chat(M,span_notice("You get charged by [src]."))
//yogs edit end ----------------------------------
if(iscyborg(M))
..()
return
if(ishuman(M))
var/mob/living/carbon/human/L = M
var/datum/martial_art/A = L.check_block()
if(A)
A.handle_counter(L, user)
return
var/list/modifiers = params2list(params)
if(modifiers && modifiers[RIGHT_CLICK])
if(status)
if(cooldown_check <= world.time)
baton_stun(M, user)
return ..()
else
if(status)
if(cooldown_check <= world.time)
if(baton_stun(M, user))
user.do_attack_animation(M)
return
else
to_chat(user, span_danger("The baton is still charging!"))
else
M.visible_message(span_warning("[user] has prodded [M] with [src]. Luckily it was off."), \
span_warning("[user] has prodded you with [src]. Luckily it was off."))
/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/living/user)
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.check_shields(src, stamina_damage, "[user]'s [name]", MELEE_ATTACK)) //No message; check_shields() handles that
playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
return 0
if(iscyborg(loc))
var/mob/living/silicon/robot/R = loc
if(!R || !R.cell || !R.cell.use(hitcost))
return FALSE
else
if(!deductcharge(hitcost))
return FALSE
var/obj/item/bodypart/affecting = L.get_bodypart(user? user.zone_selected : BODY_ZONE_CHEST)
var/armor_block = L.run_armor_check(affecting, ENERGY) //check armor on the limb because that's where we are slapping...
L.apply_damage(stamina_damage, STAMINA, BODY_ZONE_CHEST, armor_block) //...then deal damage to chest so we can't do the old hit-a-disabled-limb-200-times thing, batons are electrical not directed.
SEND_SIGNAL(L, COMSIG_LIVING_MINOR_SHOCK)
var/current_stamina_damage = L.getStaminaLoss()
if(current_stamina_damage >= 90)
if(!L.IsParalyzed())
to_chat(L, span_warning("You muscles seize, making you collapse!"))
else
L.Paralyze(stunforce)
L.adjust_jitter(20 SECONDS)
L.apply_effect(EFFECT_STUTTER, stunforce)
else if(current_stamina_damage > 70)
L.adjust_jitter(10 SECONDS)
L.apply_effect(EFFECT_STUTTER, stunforce)
else if(current_stamina_damage >= 20)
L.adjust_jitter(5 SECONDS)
L.apply_effect(EFFECT_STUTTER, stunforce)
if(user)
L.lastattacker = user.real_name
L.lastattackerckey = user.ckey
L.visible_message(span_danger("[user] has stunned [L] with [src]!"), \
span_userdanger("[user] has stunned you with [src]!"))
log_combat(user, L, "stunned")
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
if(ishuman(L))
var/mob/living/carbon/human/H = L
var/datum/mind/M = H.mind
if(M && (M.assigned_role == "Assistant" || M.assigned_role == "Clown") && user.combat_mode)
var/amount_given = 1
if(M.assigned_role == "Clown")
amount_given = 5
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_SEC)
if(D)
D.adjust_money(amount_given)
H.forcesay(GLOB.hit_appends)
cooldown_check = world.time + cooldown
return TRUE
/obj/item/melee/baton/emp_act(severity)
. = ..()
if (!(. & EMP_PROTECT_SELF))
deductcharge(100 * severity)
//Makeshift stun baton. Replacement for stun gloves.
/obj/item/melee/baton/cattleprod
name = "stunprod"
desc = "An improvised stun baton."
icon_state = "stunprod"
item_state = "prod"
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
w_class = WEIGHT_CLASS_BULKY
force = 3
throwforce = 5
stunforce = 100
stamina_damage = 45
hitcost = 2000
throw_hit_chance = 10
slot_flags = ITEM_SLOT_BACK
var/obj/item/assembly/igniter/sparkler = 0
/obj/item/melee/baton/cattleprod/Initialize(mapload)
. = ..()
sparkler = new (src)
/obj/item/melee/baton/cattleprod/baton_stun()
if(sparkler.activate())
..()
/obj/item/melee/baton/cattleprod/tactical
name = "tactical stunprod"
desc = "A cost-effective, mass-produced, tactical stun prod."
icon_state = "tacprod"
item_state = "tacprod"
preload_cell_type = /obj/item/stock_parts/cell/high/plus // comes with a cell
/obj/item/melee/baton/cattleprod/tactical/update_icon_state()
. = ..()
if(status)
item_state = "[initial(item_state)]_active"
else if(!cell)
item_state = "[initial(item_state)]_nocell"
else
item_state = "[initial(item_state)]"
/obj/item/batonupgrade
name = "baton power upgrade"
desc = "A new power management circuit which enables stun batons to instantly stun, at the cost of double power usage."
icon = 'icons/obj/module.dmi'
icon_state = "cyborg_upgrade3"