-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
Copy pathenergy.dm
258 lines (231 loc) · 8.92 KB
/
energy.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
/obj/item/gun/energy
icon_state = "energy"
name = "energy gun"
desc = "A basic energy-based gun."
icon = 'icons/obj/guns/energy.dmi'
ammo_x_offset = 2
var/obj/item/stock_parts/cell/cell //What type of power cell this uses
var/cell_type = /obj/item/stock_parts/cell
var/modifystate = 0
var/list/ammo_type = list(/obj/item/ammo_casing/energy)
var/select = 1 //The state of the select fire switch. Determines from the ammo_type list what kind of shot is fired next.
var/can_charge = TRUE //Can it be charged in a recharger?
var/automatic_charge_overlays = TRUE //Do we handle overlays with base update_overlays?
var/charge_sections = 4
var/shaded_charge = FALSE //if this gun uses a stateful charge bar for more detail
var/selfcharge = 0
var/charge_timer = 0
var/charge_delay = 8
var/charge_amount = 1
var/use_cyborg_cell = FALSE //whether the gun's cell drains the cyborg user's cell to recharge
var/dead_cell = FALSE //set to true so the gun is given an empty cell
var/emp_jammed = FALSE
var/emp_jam_timer
available_attachments = list(
/obj/item/attachment/scope/simple,
/obj/item/attachment/scope/holo,
/obj/item/attachment/scope/infrared,
/obj/item/attachment/laser_sight,
/obj/item/attachment/grip/vertical,
)
max_attachments = 4
recoil = 0.1
/obj/item/gun/energy/emp_act(severity)
. = ..()
if(!(. & EMP_PROTECT_CONTENTS))
cell.use(round(cell.charge * (0.5**(severity/EMP_HEAVY))))
emp_jammed = TRUE
deltimer(emp_jam_timer)
// up to 10 seconds depending on severity, then give or take 0.2 seconds to prevent piercing ears
var/unjam_time = (min(severity, EMP_HEAVY) + (rand(-20,20)*0.01)) SECONDS
emp_jam_timer = addtimer(CALLBACK(src, PROC_REF(emp_unjam)), unjam_time, TIMER_STOPPABLE)
chambered = null //we empty the chamber
recharge_newshot() //and try to charge a new shot
update_appearance(UPDATE_ICON)
/obj/item/gun/energy/shoot_with_empty_chamber(mob/living/user as mob|obj)
if(emp_jammed)
to_chat(user, span_danger("*EMP-JAMMED*"))
playsound(src, dry_fire_sound, 30, TRUE)
else
..()
/obj/item/gun/energy/proc/emp_unjam()
emp_jammed = FALSE
playsound(src, "sound/machines/twobeep.ogg", 50)
/obj/item/gun/energy/get_cell()
return cell
/obj/item/gun/energy/Initialize(mapload)
. = ..()
if(cell_type)
cell = new cell_type(src)
else
cell = new(src)
if(dead_cell)
cell.charge = 0
update_ammo_types()
recharge_newshot(TRUE)
if(selfcharge)
START_PROCESSING(SSobj, src)
update_appearance(UPDATE_ICON)
/obj/item/gun/energy/proc/update_ammo_types()
var/obj/item/ammo_casing/energy/shot
for (var/i = 1, i <= ammo_type.len, i++)
var/shottype = ammo_type[i]
shot = new shottype(src)
ammo_type[i] = shot
shot = ammo_type[select]
fire_sound = shot.fire_sound
fire_delay = shot.delay
/obj/item/gun/energy/Destroy()
if (cell)
QDEL_NULL(cell)
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/gun/energy/process(delta_time)
if(selfcharge && cell && cell.percent() < 100)
charge_timer += delta_time
if(charge_timer < charge_delay)
return
charge_timer = 0
cell.give(100*charge_amount)
if(!chambered) //if empty chamber we try to charge a new shot
recharge_newshot(TRUE)
update_appearance(UPDATE_ICON)
/obj/item/gun/energy/attack_self(mob/living/user as mob)
if(ammo_type.len > 1)
select_fire(user)
update_appearance(UPDATE_ICON)
/obj/item/gun/energy/can_shoot()
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
return (!QDELETED(cell) ? (cell.charge >= shot.e_cost) : FALSE) && !emp_jammed
/obj/item/gun/energy/recharge_newshot(no_cyborg_drain)
if (!ammo_type || !cell)
return
if(use_cyborg_cell && !no_cyborg_drain)
if(iscyborg(loc))
var/mob/living/silicon/robot/R = loc
if(R.cell)
var/obj/item/ammo_casing/energy/shot = ammo_type[select] //Necessary to find cost of shot
if(R.cell.use(shot.e_cost)) //Take power from the borg...
cell.give(shot.e_cost) //... to recharge the shot
if(!chambered)
var/obj/item/ammo_casing/energy/AC = ammo_type[select]
if(cell.charge >= AC.e_cost) //if there's enough power in the cell cell...
chambered = AC //...prepare a new shot based on the current ammo type selected
if(!chambered.BB)
chambered.newshot()
/obj/item/gun/energy/process_chamber()
if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired...
var/obj/item/ammo_casing/energy/shot = chambered
cell.use(shot.e_cost)//... drain the cell cell
chambered = null //either way, released the prepared shot
recharge_newshot() //try to charge a new shot
/obj/item/gun/energy/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
if(!chambered && can_shoot())
process_chamber() // If the gun was drained and then recharged, load a new shot.
return ..()
/obj/item/gun/energy/process_burst(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
if(!chambered && can_shoot())
process_chamber() // Ditto.
return ..()
/obj/item/gun/energy/proc/select_fire(mob/living/user)
select++
if (select > ammo_type.len)
select = 1
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
fire_sound = shot.fire_sound
fire_delay = shot.delay
if (shot.select_name)
to_chat(user, span_notice("[src] is now set to [shot.select_name]."))
chambered = null
recharge_newshot(TRUE)
update_appearance(UPDATE_ICON)
return
/obj/item/gun/energy/update_icon_state()
if(QDELETED(src))
return
. = ..()
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/ratio = get_charge_ratio()
if(!isnull(initial(item_state))) //static item states
return
item_state = "[initial(icon_state)][modifystate ? "[shot.select_name]" : ""][ratio]"
/obj/item/gun/energy/update_overlays()
if(QDELETED(src))
return
. = ..()
if(!automatic_charge_overlays)
return
var/overlay_icon_state = "[icon_state]_charge"
if(modifystate)
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
. += mutable_appearance(icon, "[icon_state]_[initial(shot.select_name)]")
if(cell.charge < shot.e_cost)
. += "[icon_state]_empty"
return
overlay_icon_state += "_[initial(shot.select_name)]"
var/ratio = get_charge_ratio()
if(shaded_charge)
. += "[icon_state]_charge[ratio]"
return
for(var/i = ratio, i >= 1, i--)
var/mutable_appearance/charge_overlay = mutable_appearance(icon, overlay_icon_state)
charge_overlay.pixel_x = ammo_x_offset * (i - 1)
charge_overlay.pixel_y = ammo_y_offset * (i - 1)
. += charge_overlay
///Used by update_icon_state() and update_overlays()
/obj/item/gun/energy/proc/get_charge_ratio()
return can_shoot() ? CEILING(clamp(cell.charge / cell.maxcharge, 0, 1) * charge_sections, 1) : 0
// Sets the ratio to 0 if the gun doesn't have enough charge to fire, or if its power cell is removed.
/obj/item/gun/energy/suicide_act(mob/living/user)
if (istype(user) && can_shoot() && can_trigger_gun(user) && user.get_bodypart(BODY_ZONE_HEAD))
user.visible_message(span_suicide("[user] is putting the barrel of [src] in [user.p_their()] mouth. It looks like [user.p_theyre()] trying to commit suicide!"))
sleep(2.5 SECONDS)
if(user.is_holding(src))
user.visible_message(span_suicide("[user] melts [user.p_their()] face off with [src]!"))
playsound(loc, fire_sound, 50, 1, -1)
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
cell.use(shot.e_cost)
update_appearance(UPDATE_ICON)
return(FIRELOSS)
else
user.visible_message(span_suicide("[user] panics and starts choking to death!"))
return(OXYLOSS)
else
user.visible_message(span_suicide("[user] is pretending to melt [user.p_their()] face off with [src]! It looks like [user.p_theyre()] trying to commit suicide!</b>"))
playsound(src, dry_fire_sound, 30, TRUE)
return (OXYLOSS)
/obj/item/gun/energy/vv_edit_var(var_name, var_value)
switch(var_name)
if("selfcharge")
if(var_value)
START_PROCESSING(SSobj, src)
else
STOP_PROCESSING(SSobj, src)
. = ..()
/obj/item/gun/energy/ignition_effect(atom/A, mob/living/user)
if(!can_shoot() || !ammo_type[select])
shoot_with_empty_chamber()
. = ""
else
var/obj/item/ammo_casing/energy/E = ammo_type[select]
var/obj/projectile/energy/BB = E.BB
if(!BB)
. = ""
else if(BB.nodamage || !BB.damage || BB.damage_type == STAMINA)
user.visible_message(span_danger("[user] tries to light [user.p_their()] [A.name] with [src], but it doesn't do anything. Dumbass."))
playsound(user, E.fire_sound, 50, 1)
playsound(user, BB.hitsound, 50, 1)
cell.use(E.e_cost)
. = ""
else if(BB.damage_type != BURN)
user.visible_message(span_danger("[user] tries to light [user.p_their()] [A.name] with [src], but only succeeds in utterly destroying it. Dumbass."))
playsound(user, E.fire_sound, 50, 1)
playsound(user, BB.hitsound, 50, 1)
cell.use(E.e_cost)
qdel(A)
. = ""
else
playsound(user, E.fire_sound, 50, 1)
playsound(user, BB.hitsound, 50, 1)
cell.use(E.e_cost)
. = span_danger("[user] casually lights their [A.name] with [src]. Damn.")