· 5 years ago · Mar 18, 2020, 11:48 PM
1SWEP.PrintName = "SCP - Hacking Device"
2SWEP.Category = "GuthSCP"
3SWEP.Author = "zgredinzyyy & Guthen"
4SWEP.Instructions = "Press Left Mouse Button to hack nearest doors."
5
6SWEP.Spawnable = true
7
8SWEP.Primary.ClipSize = -1
9SWEP.Primary.DefaultClip = -1
10SWEP.Primary.Automatic = true
11SWEP.Primary.Ammo = "none"
12
13SWEP.Secondary.ClipSize = -1
14SWEP.Secondary.DefaultClip = -1
15SWEP.Secondary.Automatic = false
16SWEP.Secondary.Ammo = "none"
17
18SWEP.Weight = 5
19SWEP.AutoSwitchTo = false
20SWEP.AutoSwitchFrom = false
21
22SWEP.Slot = 1
23SWEP.SlotPos = 2
24SWEP.DrawAmmo = false
25SWEP.DrawCrosshair = true
26
27SWEP.ViewModel = "models/weapons/v_grenade.mdl"
28SWEP.WorldModel = "models/weapons/w_grenade.mdl"
29
30SWEP.ShouldDropOnDie = false
31
32SWEP.HoldType = "slam"
33
34SWEP.UseHands = false
35SWEP.ShowViewModel = false
36SWEP.ShowWorldModel = false
37
38SWEP.GuthSCPLVL = 0 -- Starting with 0 so player can't open doors without hacking and let keycard system asociate this SWEP with keycard
39
40SWEP.ViewModelBoneMods = {
41 ["ValveBiped.Grenade_body"] = { scale = Vector(2.037, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
42 ["ValveBiped.Bip01_R_Finger0"] = { scale = Vector(1, 1, 1), pos = Vector(0, 0, 0), angle = Angle(12.052, 0, 0) }
43}
44
45SWEP.VElements = {
46 ["viewcard"] = { type = "Model", model = "models/props/hdevice/hdevice.mdl", bone = "ValveBiped.Grenade_body", rel = "", pos = Vector(0.551, 2, -3.708), angle = Angle(-149.308, 89.911, 129.485), size = Vector(0.95, 0.95, 0.95), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
47}
48
49SWEP.WElements = {
50 ["card"] = { type = "Model", model = "models/props/hdevice/hdevice.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(3.848, 2.743, -1.083), angle = Angle(-41.509, 12.201, 179.57), size = Vector(0.681, 0.681, 1.759), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
51}
52
53-- This addon requires https://steamcommunity.com/sharedfiles/filedetails/?id=1781514401 || Again big thanks to Guthen for this awesome addon and opportunity to make this one possible
54
55-- TODO Add screens
56-- TODO Repair sounds
57
58local hackingdevice_hack_time = CreateConVar("hdevice_hack_time", "5", {FCVAR_REPLICATED,FCVAR_ARCHIVE}, "Amount of seconds needed for hacking device to open certain door.")
59local hackingdevice_hack_max = CreateConVar("hdevice_hack_max", "5", {FCVAR_REPLICATED,FCVAR_ARCHIVE}, "Highest level that the device can crack.")
60
61function SWEP:Success(ent)
62 self.isHacking = false
63 self.Owner:setBottomMessage("Hacking Done!")
64 ent:Use(self.Owner,ent,4,1) -- Opening Doors
65 --self:EmitSound("hdevice/endspark.wav") -- Sounds exported from HL2
66end
67
68function SWEP:Open(ent)
69 ent:Use(self.Owner,ent,4,1)
70end
71
72function SWEP:Failure(fail) -- 1 = Moved mouse, moved too far, 2 = Hacking limited to certain LVL, else = Button blocked
73 self.isHacking = false
74 if fail == 1 then
75 self.Owner:setBottomMessage("Hacking FAILED!")
76 elseif fail == 2 then
77 self.Owner:setBottomMessage("Hacking limited to LVL " .. hackingdevice_hack_max:GetInt() .. " Keycard")
78 else
79 self.Owner:setBottomMessage("Can't hack this!")
80 end
81end
82
83function SWEP:PrimaryAttack()
84
85 local tr = self.Owner:GetEyeTrace()
86 local ent = tr.Entity
87 local trLVL = ent:GetNWInt( "GuthSCP:LVL", 0 ) -- Door req LVL
88
89 if not GuthSCP then return end -- If no Base Guthen Keycard sys = end
90 if not GuthSCP.keycardAvailableClass[ ent:GetClass() ] then return end -- No keycard table
91 if not GuthSCP.exceptionButtonID then return end -- No buttons file
92 if not GuthSCP.exceptionButtonID[game.GetMap()] then return end -- No setting for that map
93
94 if IsValid(tr.Entity) and tr.HitPos:Distance(self.Owner:GetShootPos()) < 50 and trLVL == 0 and not GuthSCP.exceptionButtonID[game.GetMap()][ent:MapCreationID()] then
95 self:Open(ent)
96
97 elseif IsValid(tr.Entity) and tr.HitPos:Distance(self.Owner:GetShootPos()) < 50 and trLVL <= hackingdevice_hack_max:GetInt() and not GuthSCP.exceptionButtonID[game.GetMap()][ent:MapCreationID()] then
98 --self:EmitSound("hdevice/startpress.wav", 60, 100, 1, CHAN_AUTO)
99 self.Owner:setBottomMessage("Hacking Started!")
100 self.isHacking = true
101 self.startHack = CurTime()
102 self.endHack = CurTime() + ent:GetNWInt( "GuthSCP:LVL", 0 )*hackingdevice_hack_time:GetInt()
103 self.Weapon:SetNextPrimaryFire(CurTime()+3)
104
105 elseif GuthSCP.exceptionButtonID[game.GetMap()][ent:MapCreationID()] then
106 self:Failure(3)
107
108 elseif IsValid(tr.Entity) and tr.HitPos:Distance(self.Owner:GetShootPos()) < 50 and trLVL ~= 0 and trLVL > hackingdevice_hack_max:GetInt() then
109 self:Failure(2)
110
111 end
112end
113
114function SWEP:SecondaryAttack() end
115
116function SWEP:Think()
117 local tr = self.Owner:GetEyeTrace()
118 local ent = tr.Entity
119
120 if not self.startHack then
121 self.startHack = 0
122 self.endHack = 0
123 end
124
125 if self.isHacking and IsValid(self.Owner) then
126 local tr = self.Owner:GetEyeTrace()
127 if not IsValid(tr.Entity) or tr.HitPos:Distance(self.Owner:GetShootPos()) > 50 or not GuthSCP.keycardAvailableClass[ ent:GetClass() ] then
128 self:Failure(1)
129 elseif self.endHack <= CurTime() then
130 self:Success(tr.Entity)
131 end
132 else
133 self.startHack = 0
134 self.endHack = 0
135 end
136
137 self:NextThink(CurTime())
138 return true
139end
140
141function SWEP:DrawHUD()
142
143 local ply = self.Owner
144 if not IsValid( ply ) or not ply:Alive() then return end
145
146 local trg = ply:GetEyeTrace().Entity
147 local tr = self.Owner:GetEyeTrace()
148
149 if not IsValid( trg ) then return end
150 if not GuthSCP then return end
151 if not GuthSCP.keycardAvailableClass[ trg:GetClass() ] then return end
152
153 if trg:GetNWInt( "GuthSCP:LVL", 0 ) and tr.HitPos:Distance(self.Owner:GetShootPos()) < 50 then
154 draw.SimpleText( "Keycard LVL Required: " .. trg:GetNWInt( "GuthSCP:LVL", 0 ), "ChatFont", ScrW()/2+50, ScrH()/2, Color( 255, 255, 255 ), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER )
155 if trg:GetNWInt( "GuthSCP:LVL", 0 ) ~= 0 then
156 draw.SimpleText( "Estimated Hack Time: " .. trg:GetNWInt( "GuthSCP:LVL", 0 )*hackingdevice_hack_time:GetInt() .. "s", "ChatFont", ScrW()/2+50, ScrH()/2+15, Color( 255, 255, 255 ), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER )
157 end
158 end
159end
160
161--
162-- SWEP Construction Kit
163--
164
165function SWEP:Initialize()
166
167 if not GuthSCP then
168 self.Owner:ChatPrint("HDevice - Guthen Keycard System not found, HDevice won't work without it.")
169 end
170
171 if CLIENT then
172
173 // Create a new table for every weapon instance
174 self.VElements = table.FullCopy( self.VElements )
175 self.WElements = table.FullCopy( self.WElements )
176 self.ViewModelBoneMods = table.FullCopy( self.ViewModelBoneMods )
177
178 self:CreateModels(self.VElements) // create viewmodels
179 self:CreateModels(self.WElements) // create worldmodels
180
181 // init view model bone build function
182 if IsValid(self.Owner) then
183 local vm = self.Owner:GetViewModel()
184 if IsValid(vm) then
185 self:ResetBonePositions(vm)
186
187 // Init viewmodel visibility
188 if (self.ShowViewModel == nil or self.ShowViewModel) then
189 vm:SetColor(Color(255,255,255,255))
190 else
191 // we set the alpha to 1 instead of 0 because else ViewModelDrawn stops being called
192 vm:SetColor(Color(255,255,255,1))
193 // ^ stopped working in GMod 13 because you have to do Entity:SetRenderMode(1) for translucency to kick in
194 // however for some reason the view model resets to render mode 0 every frame so we just apply a debug material to prevent it from drawing
195 vm:SetMaterial("Debug/hsv")
196 end
197 end
198 end
199
200 end
201
202end
203
204function SWEP:Holster()
205
206 if CLIENT and IsValid(self.Owner) then
207 local vm = self.Owner:GetViewModel()
208 if IsValid(vm) then
209 self:ResetBonePositions(vm)
210 end
211 end
212
213 return true
214end
215
216function SWEP:OnRemove()
217 self:Holster()
218end
219
220if CLIENT then
221
222 SWEP.vRenderOrder = nil
223 function SWEP:ViewModelDrawn()
224
225 local vm = self.Owner:GetViewModel()
226 if !IsValid(vm) then return end
227
228 if (!self.VElements) then return end
229
230 self:UpdateBonePositions(vm)
231
232 if (!self.vRenderOrder) then
233
234 // we build a render order because sprites need to be drawn after models
235 self.vRenderOrder = {}
236
237 for k, v in pairs( self.VElements ) do
238 if (v.type == "Model") then
239 table.insert(self.vRenderOrder, 1, k)
240 elseif (v.type == "Sprite" or v.type == "Quad") then
241 table.insert(self.vRenderOrder, k)
242 end
243 end
244
245 end
246
247 for k, name in ipairs( self.vRenderOrder ) do
248
249 local v = self.VElements[name]
250 if (!v) then self.vRenderOrder = nil break end
251 if (v.hide) then continue end
252
253 local model = v.modelEnt
254 local sprite = v.spriteMaterial
255
256 if (!v.bone) then continue end
257
258 local pos, ang = self:GetBoneOrientation( self.VElements, v, vm )
259
260 if (!pos) then continue end
261
262 if (v.type == "Model" and IsValid(model)) then
263
264 model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
265 ang:RotateAroundAxis(ang:Up(), v.angle.y)
266 ang:RotateAroundAxis(ang:Right(), v.angle.p)
267 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
268
269 model:SetAngles(ang)
270 //model:SetModelScale(v.size)
271 local matrix = Matrix()
272 matrix:Scale(v.size)
273 model:EnableMatrix( "RenderMultiply", matrix )
274
275 if (v.material == "") then
276 model:SetMaterial("")
277 elseif (model:GetMaterial() != v.material) then
278 model:SetMaterial( v.material )
279 end
280
281 if (v.skin and v.skin != model:GetSkin()) then
282 model:SetSkin(v.skin)
283 end
284
285 if (v.bodygroup) then
286 for k, v in pairs( v.bodygroup ) do
287 if (model:GetBodygroup(k) != v) then
288 model:SetBodygroup(k, v)
289 end
290 end
291 end
292
293 if (v.surpresslightning) then
294 render.SuppressEngineLighting(true)
295 end
296
297 render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
298 render.SetBlend(v.color.a/255)
299 model:DrawModel()
300 render.SetBlend(1)
301 render.SetColorModulation(1, 1, 1)
302
303 if (v.surpresslightning) then
304 render.SuppressEngineLighting(false)
305 end
306
307 elseif (v.type == "Sprite" and sprite) then
308
309 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
310 render.SetMaterial(sprite)
311 render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
312
313 elseif (v.type == "Quad" and v.draw_func) then
314
315 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
316 ang:RotateAroundAxis(ang:Up(), v.angle.y)
317 ang:RotateAroundAxis(ang:Right(), v.angle.p)
318 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
319
320 cam.Start3D2D(drawpos, ang, v.size)
321 v.draw_func( self )
322 cam.End3D2D()
323
324 end
325
326 end
327
328 end
329
330 SWEP.wRenderOrder = nil
331 function SWEP:DrawWorldModel()
332
333 if (self.ShowWorldModel == nil or self.ShowWorldModel) then
334 self:DrawModel()
335 end
336
337 if (!self.WElements) then return end
338
339 if (!self.wRenderOrder) then
340
341 self.wRenderOrder = {}
342
343 for k, v in pairs( self.WElements ) do
344 if (v.type == "Model") then
345 table.insert(self.wRenderOrder, 1, k)
346 elseif (v.type == "Sprite" or v.type == "Quad") then
347 table.insert(self.wRenderOrder, k)
348 end
349 end
350
351 end
352
353 if (IsValid(self.Owner)) then
354 bone_ent = self.Owner
355 else
356 // when the weapon is dropped
357 bone_ent = self
358 end
359
360 for k, name in pairs( self.wRenderOrder ) do
361
362 local v = self.WElements[name]
363 if (!v) then self.wRenderOrder = nil break end
364 if (v.hide) then continue end
365
366 local pos, ang
367
368 if (v.bone) then
369 pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent )
370 else
371 pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent, "ValveBiped.Bip01_R_Hand" )
372 end
373
374 if (!pos) then continue end
375
376 local model = v.modelEnt
377 local sprite = v.spriteMaterial
378
379 if (v.type == "Model" and IsValid(model)) then
380
381 model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
382 ang:RotateAroundAxis(ang:Up(), v.angle.y)
383 ang:RotateAroundAxis(ang:Right(), v.angle.p)
384 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
385
386 model:SetAngles(ang)
387 //model:SetModelScale(v.size)
388 local matrix = Matrix()
389 matrix:Scale(v.size)
390 model:EnableMatrix( "RenderMultiply", matrix )
391
392 if (v.material == "") then
393 model:SetMaterial("")
394 elseif (model:GetMaterial() != v.material) then
395 model:SetMaterial( v.material )
396 end
397
398 if (v.skin and v.skin != model:GetSkin()) then
399 model:SetSkin(v.skin)
400 end
401
402 if (v.bodygroup) then
403 for k, v in pairs( v.bodygroup ) do
404 if (model:GetBodygroup(k) != v) then
405 model:SetBodygroup(k, v)
406 end
407 end
408 end
409
410 if (v.surpresslightning) then
411 render.SuppressEngineLighting(true)
412 end
413
414 render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
415 render.SetBlend(v.color.a/255)
416 model:DrawModel()
417 render.SetBlend(1)
418 render.SetColorModulation(1, 1, 1)
419
420 if (v.surpresslightning) then
421 render.SuppressEngineLighting(false)
422 end
423
424 elseif (v.type == "Sprite" and sprite) then
425
426 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
427 render.SetMaterial(sprite)
428 render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
429
430 elseif (v.type == "Quad" and v.draw_func) then
431
432 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
433 ang:RotateAroundAxis(ang:Up(), v.angle.y)
434 ang:RotateAroundAxis(ang:Right(), v.angle.p)
435 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
436
437 cam.Start3D2D(drawpos, ang, v.size)
438 v.draw_func( self )
439 cam.End3D2D()
440
441 end
442
443 end
444
445 end
446
447 function SWEP:GetBoneOrientation( basetab, tab, ent, bone_override )
448
449 local bone, pos, ang
450 if (tab.rel and tab.rel != "") then
451
452 local v = basetab[tab.rel]
453
454 if (!v) then return end
455
456 // Technically, if there exists an element with the same name as a bone
457 // you can get in an infinite loop. Let's just hope nobody's that stupid.
458 pos, ang = self:GetBoneOrientation( basetab, v, ent )
459
460 if (!pos) then return end
461
462 pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
463 ang:RotateAroundAxis(ang:Up(), v.angle.y)
464 ang:RotateAroundAxis(ang:Right(), v.angle.p)
465 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
466
467 else
468
469 bone = ent:LookupBone(bone_override or tab.bone)
470
471 if (!bone) then return end
472
473 pos, ang = Vector(0,0,0), Angle(0,0,0)
474 local m = ent:GetBoneMatrix(bone)
475 if (m) then
476 pos, ang = m:GetTranslation(), m:GetAngles()
477 end
478
479 if (IsValid(self.Owner) and self.Owner:IsPlayer() and
480 ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
481 ang.r = -ang.r // Fixes mirrored models
482 end
483
484 end
485
486 return pos, ang
487 end
488
489 function SWEP:CreateModels( tab )
490
491 if (!tab) then return end
492
493 for k, v in pairs( tab ) do
494 if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and
495 string.find(v.model, ".mdl") and file.Exists (v.model, "GAME") ) then
496
497 v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
498 if (IsValid(v.modelEnt)) then
499 v.modelEnt:SetPos(self:GetPos())
500 v.modelEnt:SetAngles(self:GetAngles())
501 v.modelEnt:SetParent(self)
502 v.modelEnt:SetNoDraw(true)
503 v.createdModel = v.model
504 else
505 v.modelEnt = nil
506 end
507
508 elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite)
509 and file.Exists ("materials/"..v.sprite..".vmt", "GAME")) then
510
511 local name = v.sprite.."-"
512 local params = { ["$basetexture"] = v.sprite }
513 // make sure we create a unique name based on the selected options
514 local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
515 for i, j in pairs( tocheck ) do
516 if (v[j]) then
517 params["$"..j] = 1
518 name = name.."1"
519 else
520 name = name.."0"
521 end
522 end
523
524 v.createdSprite = v.sprite
525 v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
526
527 end
528 end
529
530 end
531
532 local allbones
533 local hasGarryFixedBoneScalingYet = false
534
535 function SWEP:UpdateBonePositions(vm)
536
537 if self.ViewModelBoneMods then
538
539 if (!vm:GetBoneCount()) then return end
540
541 // !! WORKAROUND !! //
542 // We need to check all model names :/
543 local loopthrough = self.ViewModelBoneMods
544 if (!hasGarryFixedBoneScalingYet) then
545 allbones = {}
546 for i=0, vm:GetBoneCount() do
547 local bonename = vm:GetBoneName(i)
548 if (self.ViewModelBoneMods[bonename]) then
549 allbones[bonename] = self.ViewModelBoneMods[bonename]
550 else
551 allbones[bonename] = {
552 scale = Vector(1,1,1),
553 pos = Vector(0,0,0),
554 angle = Angle(0,0,0)
555 }
556 end
557 end
558
559 loopthrough = allbones
560 end
561 // !! ----------- !! //
562
563 for k, v in pairs( loopthrough ) do
564 local bone = vm:LookupBone(k)
565 if (!bone) then continue end
566
567 // !! WORKAROUND !! //
568 local s = Vector(v.scale.x,v.scale.y,v.scale.z)
569 local p = Vector(v.pos.x,v.pos.y,v.pos.z)
570 local ms = Vector(1,1,1)
571 if (!hasGarryFixedBoneScalingYet) then
572 local cur = vm:GetBoneParent(bone)
573 while(cur >= 0) do
574 local pscale = loopthrough[vm:GetBoneName(cur)].scale
575 ms = ms * pscale
576 cur = vm:GetBoneParent(cur)
577 end
578 end
579
580 s = s * ms
581 // !! ----------- !! //
582
583 if vm:GetManipulateBoneScale(bone) != s then
584 vm:ManipulateBoneScale( bone, s )
585 end
586 if vm:GetManipulateBoneAngles(bone) != v.angle then
587 vm:ManipulateBoneAngles( bone, v.angle )
588 end
589 if vm:GetManipulateBonePosition(bone) != p then
590 vm:ManipulateBonePosition( bone, p )
591 end
592 end
593 else
594 self:ResetBonePositions(vm)
595 end
596
597 end
598
599 function SWEP:ResetBonePositions(vm)
600
601 if (!vm:GetBoneCount()) then return end
602 for i=0, vm:GetBoneCount() do
603 vm:ManipulateBoneScale( i, Vector(1, 1, 1) )
604 vm:ManipulateBoneAngles( i, Angle(0, 0, 0) )
605 vm:ManipulateBonePosition( i, Vector(0, 0, 0) )
606 end
607
608 end
609
610 /**************************
611 Global utility code
612 **************************/
613 function table.FullCopy( tab )
614
615 if (!tab) then return nil end
616
617 local res = {}
618 for k, v in pairs( tab ) do
619 if (type(v) == "table") then
620 res[k] = table.FullCopy(v) // recursion ho!
621 elseif (type(v) == "Vector") then
622 res[k] = Vector(v.x, v.y, v.z)
623 elseif (type(v) == "Angle") then
624 res[k] = Angle(v.p, v.y, v.r)
625 else
626 res[k] = v
627 end
628 end
629
630 return res
631
632 end
633
634end