/
stunbaton.dm
253 lines (219 loc) · 7.87 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
/obj/item/melee/baton
name = "stunbaton"
desc = "A stun baton for incapacitating people with."
icon_state = "stunbaton"
var/base_icon = "stunbaton"
item_state = "baton"
belt_icon = "stunbaton"
slot_flags = SLOT_BELT
force = 10
throwforce = 7
origin_tech = "combat=2"
attack_verb = list("beaten")
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 0, RAD = 0, FIRE = 80, ACID = 80)
/// How many life ticks does the stun last for
var/stunforce = 14 SECONDS
/// Is the baton currently turned on
var/turned_on = FALSE
/// How much power does it cost to stun someone
var/hitcost = 1000
/// Chance for the baton to stun when thrown at someone
var/throw_hit_chance = 35
var/obj/item/stock_parts/cell/high/cell = null
/obj/item/melee/baton/Initialize(mapload)
. = ..()
update_icon()
/obj/item/melee/baton/loaded/Initialize(mapload) //this one starts with a cell pre-installed.
link_new_cell()
return ..()
/obj/item/melee/baton/Destroy()
if(cell?.loc == src)
QDEL_NULL(cell)
return ..()
/**
* Updates the linked power cell on the baton.
*
* If the baton is held by a cyborg, link it to their internal cell.
* Else, spawn a new cell and use that instead.
* Arguments:
* * unlink - If TRUE, sets the `cell` variable to `null` rather than linking it to a new one.
*/
/obj/item/melee/baton/proc/link_new_cell(unlink = FALSE)
if(unlink)
cell = null
else if(isrobot(loc.loc)) // First loc is the module
var/mob/living/silicon/robot/R = loc.loc
cell = R.cell
else
cell = new(src)
/obj/item/melee/baton/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is putting the live [name] in [user.p_their()] mouth! It looks like [user.p_theyre()] trying to commit suicide.</span>")
return FIRELOSS
/obj/item/melee/baton/update_icon()
if(turned_on)
icon_state = "[base_icon]_active"
else if(!cell)
icon_state = "[base_icon]_nocell"
else
icon_state = "[base_icon]"
/obj/item/melee/baton/examine(mob/user)
. = ..()
if(isrobot(user))
. += "<span class='notice'>This baton is drawing power directly from your own internal charge.</span>"
if(cell)
. += "<span class='notice'>The baton is [round(cell.percent())]% charged.</span>"
else
. += "<span class='warning'>The baton does not have a power source installed.</span>"
/obj/item/melee/baton/detailed_examine()
return "The baton needs to be turned on to apply the stunning effect. Use it in your hand to toggle it on or off. If your intent is \
set to 'harm', you will inflict damage when using it, regardless if it is on or not. Each stun reduces the baton's charge, which can be replenished by \
putting it inside a weapon recharger."
/obj/item/melee/baton/get_cell()
return cell
/obj/item/melee/baton/throw_impact(atom/hit_atom)
..()
if(prob(throw_hit_chance) && turned_on && isliving(hit_atom) && !issilicon(hit_atom))
baton_stun(hit_atom)
/**
* Removes the specified amount of charge from the batons power cell.
*
* If `src` is a cyborg baton, this removes the charge from the borg's internal power cell instead.
* Arguments:
* * amount - The amount of battery charge to be used.
*/
/obj/item/melee/baton/proc/deductcharge(amount)
if(!cell)
return
cell.use(amount)
if(cell.rigged)
cell = null
turned_on = FALSE
update_icon()
if(cell.charge < (hitcost)) // If after the deduction the baton doesn't have enough charge for a stun hit it turns off.
turned_on = FALSE
update_icon()
playsound(src, "sparks", 75, TRUE, -1)
/obj/item/melee/baton/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/stock_parts/cell))
var/obj/item/stock_parts/cell/C = I
if(cell)
to_chat(user, "<span class='warning'>[src] already has a cell!</span>")
return
if(C.maxcharge < hitcost)
to_chat(user, "<span class='warning'>[src] requires a higher capacity cell!</span>")
return
if(!user.unEquip(I))
return
I.forceMove(src)
cell = I
to_chat(user, "<span class='notice'>You install [I] into [src].</span>")
update_icon()
/obj/item/melee/baton/screwdriver_act(mob/living/user, obj/item/I)
if(!cell)
to_chat(user, "<span class='warning'>There's no cell installed!</span>")
return
if(!I.use_tool(src, user, volume = I.tool_volume))
return
user.put_in_hands(cell)
to_chat(user, "<span class='notice'>You remove [cell] from [src].</span>")
cell.update_icon()
cell = null
turned_on = FALSE
update_icon()
/obj/item/melee/baton/attack_self(mob/user)
if(cell?.charge >= hitcost)
turned_on = !turned_on
to_chat(user, "<span class='notice'>[src] is now [turned_on ? "on" : "off"].</span>")
playsound(src, "sparks", 75, TRUE, -1)
else
if(isrobot(loc))
to_chat(user, "<span class='warning'>You do not have enough reserve power to charge [src]!</span>")
else if(!cell)
to_chat(user, "<span class='warning'>[src] does not have a power source!</span>")
else
to_chat(user, "<span class='warning'>[src] is out of charge.</span>")
update_icon()
add_fingerprint(user)
/obj/item/melee/baton/attack(mob/M, mob/living/user)
if(turned_on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
user.visible_message("<span class='danger'>[user] accidentally hits [user.p_them()]self with [src]!</span>",
"<span class='userdanger'>You accidentally hit yourself with [src]!</span>")
user.Weaken(stunforce * 3)
deductcharge(hitcost)
return
if(issilicon(M)) // Can't stunbaton borgs and AIs
return ..()
if(!isliving(M))
return
var/mob/living/L = M
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(check_martial_counter(H, user))
return
if(user.a_intent == INTENT_HARM)
if(turned_on)
baton_stun(L, user)
return ..() // Whack them too if in harm intent
if(!turned_on)
L.visible_message("<span class='warning'>[user] has prodded [L] with [src]. Luckily it was off.</span>",
"<span class='danger'>[L == user ? "You prod yourself" : "[user] has prodded you"] with [src]. Luckily it was off.</span>")
return
baton_stun(L, user)
user.do_attack_animation(L)
/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user)
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) //No message; check_shields() handles that
playsound(L, 'sound/weapons/genhit.ogg', 50, TRUE)
return
H.forcesay(GLOB.hit_appends)
SEND_SIGNAL(L, COMSIG_LIVING_MINOR_SHOCK, 33)
L.Weaken(stunforce)
L.Stuttering(stunforce)
if(user)
L.lastattacker = user.real_name
L.lastattackerckey = user.ckey
L.visible_message("<span class='danger'>[user] has stunned [L] with [src]!</span>",
"<span class='userdanger'>[L == user ? "You stun yourself" : "[user] has stunned you"] with [src]!</span>")
add_attack_logs(user, L, "stunned")
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
deductcharge(hitcost)
/obj/item/melee/baton/emp_act(severity)
. = ..()
if(cell)
deductcharge(1000 / severity)
/obj/item/melee/baton/wash(mob/living/user, atom/source)
if(turned_on && cell?.charge)
flick("baton_active", source)
user.Stun(stunforce)
user.Weaken(stunforce)
user.SetStuttering(stunforce)
deductcharge(hitcost)
user.visible_message("<span class='warning'>[user] shocks [user.p_them()]self while attempting to wash the active [src]!</span>",
"<span class='userdanger'>You unwisely attempt to wash [src] while it's still on.</span>")
playsound(src, "sparks", 50, TRUE)
return TRUE
..()
//Makeshift stun baton. Replacement for stun gloves.
/obj/item/melee/baton/cattleprod
name = "stunprod"
desc = "An improvised stun baton."
icon_state = "stunprod_nocell"
base_icon = "stunprod"
item_state = "prod"
force = 3
throwforce = 5
stunforce = 10 SECONDS
hitcost = 2000
throw_hit_chance = 10
slot_flags = SLOT_BACK
var/obj/item/assembly/igniter/sparkler = null
/obj/item/melee/baton/cattleprod/Initialize(mapload)
. = ..()
sparkler = new(src)
/obj/item/melee/baton/cattleprod/Destroy()
QDEL_NULL(sparkler)
return ..()
/obj/item/melee/baton/cattleprod/baton_stun()
if(sparkler.activate())
return ..()