mirror of
https://github.com/HaodongMo/ARC-9.git
synced 2025-03-03 18:52:58 -05:00
Initial commit
This commit is contained in:
commit
651d37c160
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
134
README.md
Normal file
134
README.md
Normal file
@ -0,0 +1,134 @@
|
||||
|
||||
# ARC9
|
||||
|
||||
### A successor to the ArcCW base that focuses on stability and ease of use.
|
||||
|
||||
ARC9 is so called for being the ninth public Arctic base. It is designed to be a long-term sustainable successor to ArcCW.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why should I use this over ArcCW?
|
||||
It's far better designed, better networked, and in the long run, will be more sustainable. It is easier to develop for, easier to use, has more features, and is more comfortable to use in multiplayer.
|
||||
|
||||
### Why ARC9? Where's ARC2-8? Why not just ArcCW 2?
|
||||
Because I don't want people to think it has anything to do with CW 2.0.
|
||||
|
||||
### Are ArcCW 1 weapons compatible with this?
|
||||
No, they aren't, and without some effort, automatic porting isn't going to be possible. However, manual porting should be doable, and will be a lot easier than creating a new weapon from scratch.
|
||||
|
||||
**New features include:**
|
||||
- Overhauled standardized recoil mechanics
|
||||
- "Supply Limit" system
|
||||
- Magazine dropping
|
||||
- Attachments on top of attachments
|
||||
- Free aim
|
||||
- Free sway
|
||||
- Reworked standardized weapon stat handling
|
||||
- Blind fire for all weapons
|
||||
- Looping sounds
|
||||
- Indoor audio
|
||||
- Reworked RHIK system with greater compatibility, better performance, and multiple targets
|
||||
- RHIK supports right hands too
|
||||
- Snazzy new UI
|
||||
- Better standard weapon ecosystem
|
||||
- Pose Parameter handler
|
||||
|
||||
### New Recoil
|
||||
|
||||
Weapons can be set with a Recoil Seed, unique to that gun, or a lookup table of recoil values. This gives them a recoil pattern which is consistent and predictible every time you shoot.
|
||||
|
||||
Weapons also have an amount of random recoil, which is added onto the predictible recoil. Random recoil cannot be predicted, meaning the pattern will vary a little bit every time.
|
||||
|
||||
### Supply Limit
|
||||
|
||||
The main way to get ammunition is through using Supply Crates or Supply Pickups. These will only resupply you up to your supply limit multiplied by your current magazine capacity worth of ammo. Some attachments will increase your Supply Limit while others will decrease it.
|
||||
|
||||
### Subslots
|
||||
|
||||
Now, attachments can add new slots, which more attachments can be placed onto. Due to internal structure features of ArcCW, this was completely impossible previously.
|
||||
|
||||
### Free Aim and Free Sway
|
||||
|
||||
While hip-firing, your weapon's point of aim will sway around the screen. This means no more perfect center-screen hip shooting. This is another mechanic that can be used to balance attachments and weapons.
|
||||
|
||||
### New Stat Handling
|
||||
|
||||
Each stat is handled more automatically than ever. Each stat has a "Base", such as Speed or ReloadTime or Sway. To create a new modifier to it, we add "Mult", e.g. SpeedMult. To make it conditional, we can then add a condition onto it, e.g. SpeedMultSights. This will make adding new conditions easier than ever, as it only needs to be modified in one place - the condition handler.
|
||||
|
||||
Each condition is handled individually according to the specific condition. For instance, the MidAir condition is binary - so modifiers with this condition are applied only if the player is in mind-air. However, the Sighted condition will interpolate between 0 and 1 multiplied by the total multiplier. So if the player is 50% aimed down their sights, and they have an attachment with SpreadMultSighted of 2, their spread will be multiplied by 1.5x. Mults are multiplied together before this happens - if the player has two attachments, one with SpreadMultSighted of 2 and one with 3, ARC9 will only save "6" and thus if the player is halfway sighted, their spread is multiplied by 3.
|
||||
|
||||
Modifier classes are Override, Mult, Add, and Hook, processed in that order, as in ArcCW.
|
||||
|
||||
Override and Hook modifiers also support _Priority values being assigned to the same attachment or the base weapon for greater control over the order in which they are run. For instance. SpreadOverrideSighted_Priority = 2 on an attachment will cause that attachment's SpreadOverrideSighted to take precedence over all SpreadOverrideSighted values without a priority set or with priority less than 2. Unset priority counts as 1.
|
||||
|
||||
Examples:
|
||||
|
||||
SpeedMult
|
||||
AimDownSightTimeHook
|
||||
AimDownSightOverrideCrouch
|
||||
|
||||
ArcCW: Mult_SpeedMult
|
||||
ARC9: SpeedMult
|
||||
|
||||
ArcCW: Override_Firemodes
|
||||
ARC9: FiremodesOverride
|
||||
|
||||
Hooks make a return outside of stat modifications. Hooks (Like "HookT_MinimapPing") are now separated into different types based on how they accept return data. Hooks that do not have a type ("Hook_Whatever") do not accept any return data and are only present for signalling. Both Hooks and Overrides accept \_Priority, just like in ArcCW. Higher priority will be run with precedence. For instance, Hook_RecoilSeed_Priority = 3 means that attachment's Hook_RecoilSeed will be run before any other hook that belongs to an attachment with Hook_RecoilSeed_Priority = 2.
|
||||
|
||||
The base weapon is also considered.
|
||||
|
||||
HookT: Table hooks. Return a {table} of values. Every hook's returned values are gathered into one big table for later use. Every returned value is used.
|
||||
HookA: Accumulator hooks. Return an Angle, Vector, or Number - the resulting value is made up of all of these values added together.
|
||||
HookP: Pipeline hooks. Accept previously returned data, return new data. Each function modifies the data given. Return nil to make no change. Used for things like animation translate.
|
||||
|
||||
Hooks run in an order that can be compared as such:
|
||||
1. If A's \[Hook_*\]_Priority value is higher than B (Unspecified is treated as 1) then run it first.
|
||||
2. If A belongs to a top level slot with lower value than B, run it first.
|
||||
3. If A and B belong to the same top level slot, the one with the lowest depth will be run first.
|
||||
4. If A and B have the same depth, the one that belongs to the lowest level sub-slot will be run first.
|
||||
|
||||
This is, essentially, a breadth-first tree unwrap which treats each top level slot as its own tree and processes them in numerical order.
|
||||
|
||||
### RHIK
|
||||
|
||||
RHIK is a successor to LHIK. Now, RHIK supports multiple targets, using the RHIK stack. Whenever we request an animation to be played, we put it on top of the stack. Giving priority to the top animation, we blend it seamlessly with every other animation in the stack, giving us the ability to play multiple RHIK animations in quick succession to different targets with maximum smoothness.
|
||||
|
||||
RHIK is also able to accept an attachment that moves the base weapon, allowing for more fluid animations as opposed to the procedural system of ArcCW.
|
||||
|
||||
Some applications of this include the new built-in system for toggleable hybrid optics, underbarrel grenade launchers, and grip options with different poses.
|
||||
|
||||
### New UI
|
||||
|
||||
A new heads-up display with minimap support and cooler design.
|
||||
|
||||
### New Weapon Ecosystem
|
||||
|
||||
Designed from the ground up to be extensible and standardized, so that creators can work together better. New slots better represent what they are meant to accomplish.
|
||||
|
||||
### Pose Parameter Handler
|
||||
|
||||
Allows animations to alter pose param values and keep them there. Several other weapon statistics are also directly tied to pose parameters, allowing for greater animation-based control.
|
||||
|
||||
## How To Contribute
|
||||
|
||||
Whenever you add a feature, please document any additional parameters or variables you've added in shared.lua if they're applicable to the base weapon or default.lua if they're mainly to do with attachments. Please make sure to place your parameter under the appropriate section.
|
||||
|
||||
SWEP and ATT variables should be in CamelCase, as is the Gmod standard. ARC9.ENUMs should be all upper case, as is the Gmod standard. Prefer descriptive variables when possible. Adhere to the Nomenclature guide.
|
||||
|
||||
**Nomenclature:**
|
||||
Only terminology that may cause confusion is laid out. Any terms that are standard to the community or engine are assumed to be used the same way.
|
||||
- Sequence: A Source animation on a gun's viewmodel.
|
||||
- Animation Table: A table for defining custom sequence data.
|
||||
- Attachment: A thing that goes on your gun.
|
||||
- QC Attachment: Attachment point that follows a bone used by Source engine, defined in .qc files.
|
||||
- Slot: Something you can put an attachment on.
|
||||
- Predictible Recoil: Recoil that is part of the pattern, which is the same every single time you shoot a burst.
|
||||
- Random Recoil: Recoil that cannot be predicted, added on to predictible recoil.
|
||||
- Precision: The mechanical accuracy of a gun.
|
||||
- Spread: The amount that a bullet can deviate from the aim point, in 1/10ths of a full circle.
|
||||
- Chamber: An area in a firearm that holds a round before it is fired, separate from the magazine. Only some guns have a chamber in this sense of the word. Allows guns to "+1". Revolvers and open bolt guns lack this ability and cannot chamber.
|
||||
- Clip: The same thing as a magazine.
|
||||
- Stripper Clip: An item that holds rounds that can be used to quickly refill a magazine. NOT the same thing as just a "clip".
|
||||
- VM: View Model.
|
||||
- WM: World Model.
|
||||
- BG: Bodygroup.
|
BIN
hud mockup.png
Normal file
BIN
hud mockup.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
25
lua/arc9/client/cl_bind.lua
Normal file
25
lua/arc9/client/cl_bind.lua
Normal file
@ -0,0 +1,25 @@
|
||||
hook.Add("PlayerBindPress", "ARC9_Binds", function(ply, bind, pressed, code)
|
||||
local wpn = ply:GetActiveWeapon()
|
||||
|
||||
if !wpn or !IsValid(wpn) or !wpn.ARC9 then return end
|
||||
|
||||
if !pressed then return end
|
||||
|
||||
-- print(bind)
|
||||
|
||||
if bind == "+menu_context" then
|
||||
if !LocalPlayer():KeyDown(IN_USE) then
|
||||
if wpn:GetCustomize() then
|
||||
net.Start("ARC9_togglecustomize")
|
||||
net.WriteBool(false)
|
||||
net.SendToServer()
|
||||
else
|
||||
net.Start("ARC9_togglecustomize")
|
||||
net.WriteBool(true)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
end)
|
60
lua/arc9/client/cl_font.lua
Normal file
60
lua/arc9/client/cl_font.lua
Normal file
@ -0,0 +1,60 @@
|
||||
local sizes_to_make = {
|
||||
6,
|
||||
8,
|
||||
10,
|
||||
12,
|
||||
16,
|
||||
32
|
||||
}
|
||||
|
||||
local unscaled_sizes_to_make = {
|
||||
}
|
||||
|
||||
local font = "HD44780A00 5x8"
|
||||
|
||||
local function generatefonts()
|
||||
|
||||
for _, i in pairs(sizes_to_make) do
|
||||
|
||||
surface.CreateFont( "ARC9_" .. tostring(i), {
|
||||
font = font,
|
||||
size = ScreenScale(i),
|
||||
weight = 500,
|
||||
antialias = true,
|
||||
extended = true, -- Required for non-latin fonts
|
||||
} )
|
||||
|
||||
surface.CreateFont( "ARC9_" .. tostring(i) .. "_Glow", {
|
||||
font = font,
|
||||
size = ScreenScale(i),
|
||||
weight = 500,
|
||||
antialias = true,
|
||||
blursize = 6,
|
||||
extended = true,
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
for _, i in pairs(unscaled_sizes_to_make) do
|
||||
|
||||
surface.CreateFont( "ARC9_" .. tostring(i) .. "_Unscaled", {
|
||||
font = font,
|
||||
size = i,
|
||||
weight = 500,
|
||||
antialias = true,
|
||||
extended = true,
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
generatefonts()
|
||||
|
||||
function ARC9.Regen(full)
|
||||
if full then
|
||||
generatefonts()
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add( "OnScreenSizeChanged", "ARC9.Regen", function() ARC9.Regen(true) end)
|
60
lua/arc9/client/cl_garbage.lua
Normal file
60
lua/arc9/client/cl_garbage.lua
Normal file
@ -0,0 +1,60 @@
|
||||
ARC9.CSModelPile = {} -- { {Model = NULL, Weapon = NULL} }
|
||||
ARC9.FlashlightPile = {}
|
||||
|
||||
function ARC9.CollectGarbage()
|
||||
local removed = 0
|
||||
|
||||
local newpile = {}
|
||||
|
||||
for _, k in pairs(ARC9.CSModelPile) do
|
||||
if IsValid(k.Weapon) then
|
||||
table.insert(newpile, k)
|
||||
|
||||
continue
|
||||
end
|
||||
|
||||
SafeRemoveEntity(k.Model)
|
||||
|
||||
removed = removed + 1
|
||||
end
|
||||
|
||||
ARC9.CSModelPile = newpile
|
||||
|
||||
if GetConVar("developer"):GetBool() and removed > 0 then
|
||||
print("Removed " .. tostring(removed) .. " CSModels")
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add("PostCleanupMap", "ARC9.CleanGarbage", function()
|
||||
ARC9.CollectGarbage()
|
||||
end)
|
||||
|
||||
timer.Create("ARC9 CSModel Garbage Collector", 5, 0, ARC9.CollectGarbage)
|
||||
|
||||
hook.Add("PostDrawEffects", "ARC9_CleanFlashlights", function()
|
||||
local newflashlightpile = {}
|
||||
|
||||
for _, k in pairs(ARC9.FlashlightPile) do
|
||||
if IsValid(k.Weapon) and k.Weapon == LocalPlayer():GetActiveWeapon() then
|
||||
table.insert(newflashlightpile, k)
|
||||
|
||||
continue
|
||||
end
|
||||
|
||||
if k.ProjectedTexture and k.ProjectedTexture:IsValid() then
|
||||
k.ProjectedTexture:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
ARC9.FlashlightPile = newflashlightpile
|
||||
|
||||
local wpn = LocalPlayer():GetActiveWeapon()
|
||||
|
||||
if !wpn then return end
|
||||
if !IsValid(wpn) then return end
|
||||
if !wpn.ARC9 then return end
|
||||
|
||||
if GetViewEntity() == LocalPlayer() then return end
|
||||
|
||||
wpn:KillFlashlightsVM()
|
||||
end)
|
18
lua/arc9/client/cl_hud.lua
Normal file
18
lua/arc9/client/cl_hud.lua
Normal file
@ -0,0 +1,18 @@
|
||||
local hide = {
|
||||
["CHudHealth"] = true,
|
||||
["CHudBattery"] = true,
|
||||
["CHudAmmo"] = true,
|
||||
["CHudSecondaryAmmo"] = true,
|
||||
}
|
||||
|
||||
hook.Add("HUDShouldDraw", "ARC9_HideHUD", function(name)
|
||||
if !IsValid(LocalPlayer()) then return end
|
||||
|
||||
local wpn = LocalPlayer():GetActiveWeapon()
|
||||
|
||||
if !wpn.ARC9 then return end
|
||||
|
||||
if wpn:GetCustomize() then
|
||||
if hide[name] then return false end
|
||||
end
|
||||
end)
|
7
lua/arc9/client/cl_net.lua
Normal file
7
lua/arc9/client/cl_net.lua
Normal file
@ -0,0 +1,7 @@
|
||||
net.Receive("ARC9_networkweapon", function(len, ply)
|
||||
local wpn = net.ReadEntity()
|
||||
|
||||
if !wpn.ARC9 then return end
|
||||
|
||||
wpn:ReceiveWeapon()
|
||||
end)
|
27
lua/arc9/client/cl_rendertarget.lua
Normal file
27
lua/arc9/client/cl_rendertarget.lua
Normal file
@ -0,0 +1,27 @@
|
||||
hook.Add("PreRender", "ARC9_PreRender", function()
|
||||
if GetConVar("ARC9_cheapscopes"):GetBool() then return end
|
||||
|
||||
local wpn = LocalPlayer():GetActiveWeapon()
|
||||
|
||||
if !wpn.ARC9 then return end
|
||||
|
||||
local sight = wpn:GetSight()
|
||||
|
||||
if sight.atttbl and sight.atttbl.RTScope and wpn:GetSightAmount() > 0 then
|
||||
wpn:DoRT(sight.atttbl.RTScopeFOV)
|
||||
end
|
||||
end)
|
||||
|
||||
hook.Add("PreDrawViewModels", "ARC9_PreDrawViewModels", function()
|
||||
if !GetConVar("ARC9_cheapscopes"):GetBool() then return end
|
||||
|
||||
local wpn = LocalPlayer():GetActiveWeapon()
|
||||
|
||||
if !wpn.ARC9 then return end
|
||||
|
||||
local sight = wpn:GetSight()
|
||||
|
||||
if sight.atttbl and sight.atttbl.RTScope and wpn:GetSightAmount() > 0 then
|
||||
wpn:DoCheapScope(sight.atttbl.RTScopeFOV)
|
||||
end
|
||||
end)
|
75
lua/arc9/common/attachments/default.lua
Normal file
75
lua/arc9/common/attachments/default.lua
Normal file
@ -0,0 +1,75 @@
|
||||
ATT.PrintName = "Konstantin Red Dot"
|
||||
ATT.CompactName = "RDSx1"
|
||||
ATT.Icon = Material("")
|
||||
ATT.Description = [[Collimated red dot optic sight.]]
|
||||
ATT.SortOrder = 0
|
||||
|
||||
ATT.AdminOnly = false
|
||||
ATT.Free = false
|
||||
ATT.Ignore = true
|
||||
|
||||
ATT.Model = ""
|
||||
ATT.WorldModel = "" // optional
|
||||
ATT.Scale = 1
|
||||
ATT.ModelOffset = Vector(0, 0, 0)
|
||||
|
||||
ATT.InvAtt = "" // Having this other attachment will grant access to this one.
|
||||
|
||||
ATT.Category = "" // can be "string" or {"list", "of", "strings"}
|
||||
|
||||
ATT.ActivateElements = {"plum_stock"}
|
||||
|
||||
ATT.ToggleStats = {
|
||||
["On"] = {
|
||||
SpreadAddHipFire = -0.1,
|
||||
},
|
||||
["Off"] = {}
|
||||
}
|
||||
// max of 256 togglestats
|
||||
|
||||
ATT.MuzzleDevice = false // set to true if you want to use this to emit particles
|
||||
|
||||
ATT.Flashlight = false
|
||||
ATT.FlashlightColor = Color(255, 255, 255)
|
||||
ATT.FlashlightMaterial = Material("")
|
||||
ATT.FlashlightDistance = 1024
|
||||
ATT.FlashlightFOV = 70
|
||||
|
||||
ATT.Laser = false
|
||||
ATT.LaserColor = Color(255, 0, 0)
|
||||
|
||||
// Allows a custom sight position to be defined
|
||||
|
||||
ATT.Sights = {
|
||||
{
|
||||
Pos = Vector(0, 0, 0),
|
||||
Ang = Angle(0, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
ATT.HoloSight = false
|
||||
ATT.HoloSightReticle = Material("")
|
||||
ATT.HoloSightSize = 32
|
||||
ATT.HoloSightColor = Color(255, 255, 255)
|
||||
|
||||
ATT.RTScope = true
|
||||
ATT.RTScopeSubmatIndex = 1
|
||||
ATT.RTScopeFOV = 2.5
|
||||
ATT.RTScopeRes = 512
|
||||
ATT.RTScopeSurface = Material("effects/ARC9_rt")
|
||||
ATT.RTScopeReticle = Material("")
|
||||
|
||||
ATT.Attachments = {
|
||||
{
|
||||
PrintName = "",
|
||||
DefaultIcon = Material(""),
|
||||
InstalledElements = "", // single or list of elements to activate when something is installed here
|
||||
UnInstalledElements = "",
|
||||
Integral = false, // cannot be removed
|
||||
Category = "", // single or {"list", "of", "values"}
|
||||
Bone = "",
|
||||
Pos = Vector(0, 0, 0),
|
||||
Ang = Angle(0, 0, 0),
|
||||
KeepBaseIrons = false,
|
||||
}
|
||||
}
|
75
lua/arc9/common/sh_common.lua
Normal file
75
lua/arc9/common/sh_common.lua
Normal file
@ -0,0 +1,75 @@
|
||||
ARC9.PenTable = {
|
||||
[MAT_ANTLION] = 1,
|
||||
[MAT_BLOODYFLESH] = 1,
|
||||
[MAT_CONCRETE] = 1,
|
||||
[MAT_DIRT] = 1,
|
||||
[MAT_EGGSHELL] = 1,
|
||||
[MAT_FLESH] = 1,
|
||||
[MAT_GRATE] = 1,
|
||||
[MAT_ALIENFLESH] = 1,
|
||||
[MAT_CLIP] = 1,
|
||||
[MAT_SNOW] = 1,
|
||||
[MAT_PLASTIC] = 1,
|
||||
[MAT_METAL] = 2,
|
||||
[MAT_SAND] = 1,
|
||||
[MAT_FOLIAGE] = 1,
|
||||
[MAT_COMPUTER] = 1,
|
||||
[MAT_SLOSH] = 1,
|
||||
[MAT_TILE] = 1,
|
||||
[MAT_GRASS] = 1,
|
||||
[MAT_VENT] = 1,
|
||||
[MAT_WOOD] = 0.5,
|
||||
[MAT_DEFAULT] = 1,
|
||||
[MAT_GLASS] = 0.25,
|
||||
[MAT_WARPSHIELD] = 1,
|
||||
}
|
||||
|
||||
ARC9.PresetPath = "ARC9_presets/"
|
||||
|
||||
ARC9.OverDraw = false
|
||||
|
||||
ARC9.LHIKBones = {
|
||||
"ValveBiped.Bip01_L_UpperArm",
|
||||
"ValveBiped.Bip01_L_Forearm",
|
||||
"ValveBiped.Bip01_L_Wrist",
|
||||
"ValveBiped.Bip01_L_Ulna",
|
||||
"ValveBiped.Bip01_L_Hand",
|
||||
"ValveBiped.Bip01_L_Finger4",
|
||||
"ValveBiped.Bip01_L_Finger41",
|
||||
"ValveBiped.Bip01_L_Finger42",
|
||||
"ValveBiped.Bip01_L_Finger3",
|
||||
"ValveBiped.Bip01_L_Finger31",
|
||||
"ValveBiped.Bip01_L_Finger32",
|
||||
"ValveBiped.Bip01_L_Finger2",
|
||||
"ValveBiped.Bip01_L_Finger21",
|
||||
"ValveBiped.Bip01_L_Finger22",
|
||||
"ValveBiped.Bip01_L_Finger1",
|
||||
"ValveBiped.Bip01_L_Finger11",
|
||||
"ValveBiped.Bip01_L_Finger12",
|
||||
"ValveBiped.Bip01_L_Finger0",
|
||||
"ValveBiped.Bip01_L_Finger01",
|
||||
"ValveBiped.Bip01_L_Finger02"
|
||||
}
|
||||
|
||||
ARC9.RHIKBones = {
|
||||
"ValveBiped.Bip01_R_UpperArm",
|
||||
"ValveBiped.Bip01_R_Forearm",
|
||||
"ValveBiped.Bip01_R_Wrist",
|
||||
"ValveBiped.Bip01_R_Ulna",
|
||||
"ValveBiped.Bip01_R_Hand",
|
||||
"ValveBiped.Bip01_R_Finger4",
|
||||
"ValveBiped.Bip01_R_Finger41",
|
||||
"ValveBiped.Bip01_R_Finger42",
|
||||
"ValveBiped.Bip01_R_Finger3",
|
||||
"ValveBiped.Bip01_R_Finger31",
|
||||
"ValveBiped.Bip01_R_Finger32",
|
||||
"ValveBiped.Bip01_R_Finger2",
|
||||
"ValveBiped.Bip01_R_Finger21",
|
||||
"ValveBiped.Bip01_R_Finger22",
|
||||
"ValveBiped.Bip01_R_Finger1",
|
||||
"ValveBiped.Bip01_R_Finger11",
|
||||
"ValveBiped.Bip01_R_Finger12",
|
||||
"ValveBiped.Bip01_R_Finger0",
|
||||
"ValveBiped.Bip01_R_Finger01",
|
||||
"ValveBiped.Bip01_R_Finger02"
|
||||
}
|
203
lua/arc9/common/sh_convar.lua
Normal file
203
lua/arc9/common/sh_convar.lua
Normal file
@ -0,0 +1,203 @@
|
||||
// the 0 is for load order!!!
|
||||
|
||||
local conVars = {
|
||||
{
|
||||
name = "truenames",
|
||||
default = "0",
|
||||
},
|
||||
{
|
||||
name = "maxatts",
|
||||
default = "100",
|
||||
},
|
||||
{
|
||||
name = "autosave",
|
||||
default = "0",
|
||||
client = true
|
||||
},
|
||||
{
|
||||
name = "bodydamagecancel",
|
||||
default = "1",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "free_atts",
|
||||
default = "0",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "lock_atts",
|
||||
default = "0",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "loseattsondie",
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
name = "generateattentities",
|
||||
default = "1",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "npc_equality",
|
||||
default = "0",
|
||||
},
|
||||
{
|
||||
name = "npc_atts",
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
name = "penetration",
|
||||
default = "1",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "freeaim",
|
||||
default = "1",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "sway",
|
||||
default = "1",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "benchgun",
|
||||
default = "0",
|
||||
},
|
||||
{
|
||||
name = "ricochet",
|
||||
default = "1",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "bullet_physics",
|
||||
default = "1",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "bullet_gravity",
|
||||
default = "1",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "bullet_drag",
|
||||
default = "1",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "bullet_imaginary",
|
||||
default = "1",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "bullet_lifetime",
|
||||
default = "10",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "cheapscopes",
|
||||
default = "0"
|
||||
},
|
||||
{
|
||||
name = "truenames",
|
||||
default = "1",
|
||||
replicated = true
|
||||
},
|
||||
{
|
||||
name = "compensate_sens",
|
||||
default = "1"
|
||||
},
|
||||
{
|
||||
name = "freeaim",
|
||||
default = "1"
|
||||
}
|
||||
}
|
||||
|
||||
local prefix = "arc9_"
|
||||
|
||||
for _, var in pairs(conVars) do
|
||||
local convar_name = prefix .. var.name
|
||||
|
||||
if var.client and CLIENT then
|
||||
CreateClientConVar(convar_name, var.default, true)
|
||||
else
|
||||
local flags = FCVAR_ARCHIVE
|
||||
if var.replicated then
|
||||
flags = flags + FCVAR_REPLICATED
|
||||
end
|
||||
CreateConVar(convar_name, var.default, flags)
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
|
||||
local function menu_client_ti(panel)
|
||||
panel:AddControl("checkbox", {
|
||||
label = "Reload Automatically",
|
||||
command = "ARC9_autoreload"
|
||||
})
|
||||
panel:AddControl("checkbox", {
|
||||
label = "Auto-Save Weapon",
|
||||
command = "ARC9_autosave"
|
||||
})
|
||||
panel:AddControl("checkbox", {
|
||||
label = "Compensate Sensitivity",
|
||||
command = "ARC9_compensate_sens"
|
||||
})
|
||||
end
|
||||
|
||||
local function menu_server_ti(panel)
|
||||
panel:AddControl("checkbox", {
|
||||
label = "Free Attachments",
|
||||
command = "ARC9_free_atts"
|
||||
})
|
||||
panel:AddControl("checkbox", {
|
||||
label = "Attachment Locking",
|
||||
command = "ARC9_lock_atts"
|
||||
})
|
||||
panel:AddControl("checkbox", {
|
||||
label = "Lose Attachments On Death",
|
||||
command = "ARC9_loseattsondie"
|
||||
})
|
||||
panel:AddControl("checkbox", {
|
||||
label = "Generate Attachment Entities",
|
||||
command = "ARC9_generateattentities"
|
||||
})
|
||||
panel:AddControl("checkbox", {
|
||||
label = "Enable Penetration",
|
||||
command = "ARC9_penetration"
|
||||
})
|
||||
panel:AddControl("checkbox", {
|
||||
label = "NPCs Deal Equal Damage",
|
||||
command = "ARC9_npc_equality"
|
||||
})
|
||||
panel:AddControl("checkbox", {
|
||||
label = "NPCs Get Random Attachments",
|
||||
command = "ARC9_npc_atts"
|
||||
})
|
||||
panel:AddControl("label", {
|
||||
text = "Disable body damage cancel only if you have another addon that will override the hl2 limb damage multipliers."
|
||||
})
|
||||
panel:AddControl("checkbox", {
|
||||
label = "Default Body Damage Cancel",
|
||||
command = "ARC9_bodydamagecancel"
|
||||
})
|
||||
end
|
||||
|
||||
local clientmenus_ti = {
|
||||
{
|
||||
text = "Client", func = menu_client_ti
|
||||
},
|
||||
{
|
||||
text = "Server", func = menu_server_ti
|
||||
},
|
||||
}
|
||||
|
||||
hook.Add("PopulateToolMenu", "ARC9_MenuOptions", function()
|
||||
for smenu, data in pairs(clientmenus_ti) do
|
||||
spawnmenu.AddToolMenuOption("Options", "STALKER+ Weapons", "ARC9_" .. tostring(smenu), data.text, "", "", data.func)
|
||||
end
|
||||
end)
|
||||
|
||||
end
|
34
lua/arc9/common/sh_enums.lua
Normal file
34
lua/arc9/common/sh_enums.lua
Normal file
@ -0,0 +1,34 @@
|
||||
ARC9.CLASS_PISTOL = 0
|
||||
ARC9.CLASS_RIFLE = 1
|
||||
ARC9.CLASS_SHOTGUN = 2
|
||||
ARC9.CLASS_PDW = 3
|
||||
ARC9.CLASS_CARBINE = 4
|
||||
ARC9.CLASS_DMR = 5
|
||||
ARC9.CLASS_SNIPER = 6
|
||||
ARC9.CLASS_LAUNCHER = 7
|
||||
ARC9.CLASS_GRENADE = 8
|
||||
ARC9.CLASS_DEPLOYABLE = 9
|
||||
ARC9.CLASS_TOOL = 10
|
||||
ARC9.CLASS_OTHER = 31 -- 11-30 are reserved
|
||||
|
||||
ARC9.HITPROFILE_AR = {
|
||||
[HITGROUP_HEAD] = 1.25,
|
||||
[HITGROUP_CHEST] = 1,
|
||||
[HITGROUP_LEFTARM] = 0.9,
|
||||
[HITGROUP_RIGHTARM] = 0.9,
|
||||
}
|
||||
|
||||
ARC9.HITPROFILE_PISTOL = {
|
||||
[HITGROUP_HEAD] = 2,
|
||||
[HITGROUP_CHEST] = 1,
|
||||
[HITGROUP_LEFTARM] = 0.9,
|
||||
[HITGROUP_RIGHTARM] = 0.9,
|
||||
}
|
||||
|
||||
ARC9.HITPROFILE_SNIPER = {
|
||||
[HITGROUP_HEAD] = 5,
|
||||
[HITGROUP_CHEST] = 1.1,
|
||||
[HITGROUP_STOMACH] = 1.0,
|
||||
[HITGROUP_LEFTARM] = 0.95,
|
||||
[HITGROUP_RIGHTARM] = 0.95,
|
||||
}
|
11
lua/arc9/language/en/arc9_class.lua
Normal file
11
lua/arc9/language/en/arc9_class.lua
Normal file
@ -0,0 +1,11 @@
|
||||
L("CLASS_PISTOL", "Pistol")
|
||||
L("CLASS_RIFLE", "Rifle")
|
||||
L("CLASS_SHOTGUN", "Shotgun")
|
||||
L("CLASS_PDW", "PDW")
|
||||
L("CLASS_CARBINE", "Carbine")
|
||||
L("CLASS_DMR", "DMR")
|
||||
L("CLASS_LAUNCHER", "Launcher")
|
||||
L("CLASS_GRENADE", "Grenade")
|
||||
L("CLASS_DEPLOYABLE", "Deployable")
|
||||
L("CLASS_TOOL", "Tool")
|
||||
L("CLASS_OTHER", "Other")
|
8
lua/arc9/language/en/arc9_firemode.lua
Normal file
8
lua/arc9/language/en/arc9_firemode.lua
Normal file
@ -0,0 +1,8 @@
|
||||
L("FIREMODE_AUTO", "Full Auto")
|
||||
L("FIREMODE_SEMI", "Semi Auto")
|
||||
L("FIREMODE_PUMP", "Pump-Action")
|
||||
L("FIREMODE_LEVER", "Lever-Action")
|
||||
L("FIREMODE_BOLT", "Bolt-Action")
|
||||
L("FIREMODE_MANUAL", "Manual")
|
||||
L("FIREMODE_BURST", " Round Burst")
|
||||
L("FIREMODE_SPUTTER", "Sputter")
|
22
lua/arc9/server/sv_net.lua
Normal file
22
lua/arc9/server/sv_net.lua
Normal file
@ -0,0 +1,22 @@
|
||||
util.AddNetworkString("ARC9_togglecustomize")
|
||||
util.AddNetworkString("ARC9_networkweapon")
|
||||
util.AddNetworkString("ARC9_sendattinv")
|
||||
util.AddNetworkString("ARC9_sendbullet")
|
||||
|
||||
net.Receive("ARC9_togglecustomize", function(len, ply)
|
||||
local bf = net.ReadBool()
|
||||
|
||||
local wpn = ply:GetActiveWeapon()
|
||||
|
||||
if !wpn or !IsValid(wpn) or !wpn.ARC9 then return end
|
||||
|
||||
wpn:ToggleCustomize(bf)
|
||||
end)
|
||||
|
||||
net.Receive("ARC9_networkweapon", function(len, ply)
|
||||
local wpn = net.ReadEntity()
|
||||
|
||||
if !wpn.ARC9 then return end
|
||||
|
||||
wpn:ReceiveWeapon()
|
||||
end)
|
151
lua/arc9/shared/sh_attinv.lua
Normal file
151
lua/arc9/shared/sh_attinv.lua
Normal file
@ -0,0 +1,151 @@
|
||||
function ARC9:PlayerGetAtts(ply, att)
|
||||
if !IsValid(ply) then return 0 end
|
||||
if GetConVar("ARC9_free_atts"):GetBool() then return 999 end
|
||||
|
||||
if att == "" then return 999 end
|
||||
|
||||
local atttbl = ARC9.GetAttTable(att)
|
||||
|
||||
if !atttbl then return 0 end
|
||||
|
||||
if atttbl.Free then return 999 end
|
||||
|
||||
if !IsValid(ply) then return 0 end
|
||||
|
||||
if !ply:IsAdmin() and atttbl.AdminOnly then
|
||||
return 0
|
||||
end
|
||||
|
||||
if atttbl.InvAtt then att = atttbl.InvAtt end
|
||||
|
||||
if !ply.ARC9_AttInv then return 0 end
|
||||
|
||||
if !ply.ARC9_AttInv[att] then return 0 end
|
||||
|
||||
return ply.ARC9_AttInv[att]
|
||||
end
|
||||
|
||||
function ARC9:PlayerGiveAtt(ply, att, amt)
|
||||
amt = amt or 1
|
||||
|
||||
if !IsValid(ply) then return end
|
||||
|
||||
if !ply.ARC9_AttInv then
|
||||
ply.ARC9_AttInv = {}
|
||||
end
|
||||
|
||||
local atttbl = ARC9.GetAttTable(att)
|
||||
|
||||
if !atttbl then print("Invalid att " .. att) return end
|
||||
if atttbl.Free then return end -- You can't give a free attachment, silly
|
||||
if atttbl.AdminOnly and !(ply:IsPlayer() and ply:IsAdmin()) then return false end
|
||||
|
||||
if atttbl.InvAtt then att = atttbl.InvAtt end
|
||||
|
||||
if GetConVar("ARC9_lock_atts"):GetBool() then
|
||||
if ply.ARC9_AttInv[att] == 1 then return end
|
||||
ply.ARC9_AttInv[att] = 1
|
||||
else
|
||||
ply.ARC9_AttInv[att] = (ply.ARC9_AttInv[att] or 0) + amt
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ARC9:PlayerTakeAtt(ply, att, amt)
|
||||
amt = amt or 1
|
||||
|
||||
if GetConVar("ARC9_lock_atts"):GetBool() then return end
|
||||
|
||||
if !IsValid(ply) then return end
|
||||
|
||||
if !ply.ARC9_AttInv then
|
||||
ply.ARC9_AttInv = {}
|
||||
end
|
||||
|
||||
local atttbl = ARC9.GetAttTable(att)
|
||||
if !atttbl or atttbl.Free then return end
|
||||
|
||||
if atttbl.InvAtt then att = atttbl.InvAtt end
|
||||
|
||||
ply.ARC9_AttInv[att] = ply.ARC9_AttInv[att] or 0
|
||||
|
||||
if ply.ARC9_AttInv[att] < amt then
|
||||
return false
|
||||
end
|
||||
|
||||
ply.ARC9_AttInv[att] = ply.ARC9_AttInv[att] - amt
|
||||
if ply.ARC9_AttInv[att] <= 0 then
|
||||
ply.ARC9_AttInv[att] = nil
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
|
||||
net.Receive("ARC9_sendattinv", function(len, ply)
|
||||
LocalPlayer().ARC9_AttInv = {}
|
||||
|
||||
local count = net.ReadUInt(32)
|
||||
|
||||
for i = 1, count do
|
||||
local attid = net.ReadUInt(ARC9.Attachments_Bits)
|
||||
local acount = net.ReadUInt(32)
|
||||
|
||||
local att = ARC9.Attachments_Index[attid]
|
||||
|
||||
LocalPlayer().ARC9_AttInv[att] = acount
|
||||
end
|
||||
end)
|
||||
|
||||
elseif SERVER then
|
||||
|
||||
hook.Add("PlayerDeath", "ARC9_DeathAttInv", function(ply)
|
||||
-- if GetConVar("ARC9_loseattsondie"):GetBool() then
|
||||
-- ply.ARC9_AttInv = ply.ARC9_AttInv or {}
|
||||
-- end
|
||||
-- if table.Count(ply.ARC9_AttInv) > 0
|
||||
-- and GetConVar("ARC9_attinv_loseondie"):GetInt() >= 2
|
||||
-- and !GetConVar("ARC9_free_atts"):GetBool() then
|
||||
-- local boxEnt = ents.Create("ARC9_att_dropped")
|
||||
-- boxEnt:SetPos(ply:GetPos() + Vector(0, 0, 4))
|
||||
-- boxEnt.GiveAttachments = ply.ARC9_AttInv
|
||||
-- boxEnt:Spawn()
|
||||
-- boxEnt:SetNWString("boxname", ply:GetName() .. "'s Death Box")
|
||||
-- local count = 0
|
||||
-- for i, v in pairs(boxEnt.GiveAttachments) do count = count + v end
|
||||
-- boxEnt:SetNWInt("boxcount", count)
|
||||
-- end
|
||||
end)
|
||||
|
||||
hook.Add("PlayerSpawn", "ARC9_SpawnAttInv", function(ply, trans)
|
||||
if trans then return end
|
||||
|
||||
if GetConVar("ARC9_loseattsondie"):GetInt() >= 1 then
|
||||
ply.ARC9_AttInv = {}
|
||||
|
||||
ARC9:PlayerSendAttInv(ply)
|
||||
end
|
||||
end)
|
||||
|
||||
function ARC9:PlayerSendAttInv(ply)
|
||||
if GetConVar("ARC9_free_atts"):GetBool() then return end
|
||||
|
||||
if !IsValid(ply) then return end
|
||||
|
||||
if !ply.ARC9_AttInv then return end
|
||||
|
||||
net.Start("ARC9_sendattinv")
|
||||
|
||||
net.WriteUInt(table.Count(ply.ARC9_AttInv), 32)
|
||||
|
||||
for att, count in pairs(ply.ARC9_AttInv) do
|
||||
local atttbl = ARC9.GetAttTable(att)
|
||||
local attid = atttbl.ID
|
||||
net.WriteUInt(attid, ARC9.Attachments_Bits)
|
||||
net.WriteUInt(count, 32)
|
||||
end
|
||||
|
||||
net.Send(ply)
|
||||
end
|
||||
|
||||
end
|
129
lua/arc9/shared/sh_atts.lua
Normal file
129
lua/arc9/shared/sh_atts.lua
Normal file
@ -0,0 +1,129 @@
|
||||
ARC9.Attachments = {}
|
||||
ARC9.Attachments_Index = {}
|
||||
|
||||
ARC9.Attachments_Count = 0
|
||||
|
||||
ARC9.Attachments_Bits = 16
|
||||
|
||||
function ARC9.LoadAtts()
|
||||
ARC9.Attachments_Count = 0
|
||||
ARC9.Attachments = {}
|
||||
ARC9.Attachments_Index = {}
|
||||
|
||||
local searchdir = "ARC9/common/attachments/"
|
||||
|
||||
local files = file.Find(searchdir .. "/*.lua", "LUA")
|
||||
|
||||
for _, filename in pairs(files) do
|
||||
AddCSLuaFile(searchdir .. filename)
|
||||
end
|
||||
|
||||
files = file.Find(searchdir .. "/*.lua", "LUA")
|
||||
|
||||
for _, filename in pairs(files) do
|
||||
if filename == "default.lua" then continue end
|
||||
|
||||
ATT = {}
|
||||
|
||||
local shortname = string.sub(filename, 1, -5)
|
||||
|
||||
include(searchdir .. filename)
|
||||
|
||||
if ATT.Ignore then continue end
|
||||
|
||||
ARC9.Attachments_Count = ARC9.Attachments_Count + 1
|
||||
|
||||
ATT.ShortName = shortname
|
||||
ATT.ID = ARC9.Attachments_Count
|
||||
|
||||
ARC9.Attachments[shortname] = ATT
|
||||
ARC9.Attachments_Index[ARC9.Attachments_Count] = shortname
|
||||
|
||||
if GetConVar("ARC9_generateattentities"):GetBool() and !ATT.DoNotRegister and !ATT.InvAtt and !ATT.Free then
|
||||
local attent = {}
|
||||
attent.Base = "ARC9_att"
|
||||
attent.Icon = ATT.Icon
|
||||
attent.PrintName = ATT.PrintName or shortname
|
||||
attent.Spawnable = true
|
||||
attent.AdminOnly = ATT.AdminOnly or false
|
||||
attent.AttToGive = shortname
|
||||
attent.Category = "STALKER+ - Attachments"
|
||||
|
||||
print("Registering entity for " .. shortname)
|
||||
|
||||
scripted_ents.Register(attent, "ARC9_att_" .. shortname)
|
||||
end
|
||||
end
|
||||
|
||||
ARC9.Attachments_Bits = math.min(math.ceil(math.log(ARC9.Attachments_Count + 1, 2)), 32)
|
||||
end
|
||||
|
||||
ARC9.LoadAtts()
|
||||
|
||||
function ARC9.GetAttTable(name)
|
||||
local shortname = name
|
||||
if isnumber(shortname) then
|
||||
shortname = ARC9.Attachments_Index[name]
|
||||
end
|
||||
|
||||
if ARC9.Attachments[shortname] then
|
||||
return ARC9.Attachments[shortname]
|
||||
else
|
||||
assert(false, "!!!! ARC9 tried to access invalid attachment " .. (shortname or "NIL") .. "!!!")
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
function ARC9.GetAttsForCats(cats)
|
||||
if !istable(cats) then
|
||||
cats = {cats}
|
||||
end
|
||||
|
||||
local atts = {}
|
||||
|
||||
for i, k in pairs(ARC9.Attachments) do
|
||||
local attcats = k.Category
|
||||
if !istable(attcats) then
|
||||
attcats = {attcats}
|
||||
end
|
||||
|
||||
for _, cat in pairs(cats) do
|
||||
if table.HasValue(attcats, cat) then
|
||||
table.insert(atts, k.ShortName)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return atts
|
||||
end
|
||||
|
||||
function ARC9.GetMaxAtts()
|
||||
return GetConVar("ARC9_maxatts"):GetInt()
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
|
||||
concommand.Add("ARC9_reloadatts", function()
|
||||
if !LocalPlayer():IsSuperAdmin() then return end
|
||||
|
||||
net.Start("ARC9_reloadatts")
|
||||
net.SendToServer()
|
||||
end)
|
||||
|
||||
net.Receive("ARC9_reloadatts", function(len, ply)
|
||||
ARC9.LoadAtts()
|
||||
end)
|
||||
|
||||
elseif SERVER then
|
||||
|
||||
net.Receive("ARC9_reloadatts", function(len, ply)
|
||||
if !ply:IsSuperAdmin() then return end
|
||||
|
||||
ARC9.LoadAtts()
|
||||
|
||||
net.Start("ARC9_reloadatts")
|
||||
net.Broadcast()
|
||||
end)
|
||||
|
||||
end
|
28
lua/arc9/shared/sh_effects.lua
Normal file
28
lua/arc9/shared/sh_effects.lua
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
game.AddParticles( "particles/muzzleflashes_test.pcf" )
|
||||
game.AddParticles( "particles/muzzleflashes_test_b.pcf" )
|
||||
|
||||
PrecacheParticleSystem( "muzzleflash_smg" )
|
||||
PrecacheParticleSystem( "muzzleflash_smg_bizon" )
|
||||
PrecacheParticleSystem( "muzzleflash_shotgun" )
|
||||
PrecacheParticleSystem( "muzzleflash_slug" )
|
||||
PrecacheParticleSystem( "muzzleflash_slug_flame" )
|
||||
PrecacheParticleSystem( "muzzleflash_pistol" )
|
||||
PrecacheParticleSystem( "muzzleflash_pistol_cleric" )
|
||||
PrecacheParticleSystem( "muzzleflash_pistol_deagle" )
|
||||
PrecacheParticleSystem( "muzzleflash_suppressed" )
|
||||
PrecacheParticleSystem( "muzzleflash_mp5" )
|
||||
PrecacheParticleSystem( "muzzleflash_MINIMI" )
|
||||
PrecacheParticleSystem( "muzzleflash_m79" )
|
||||
PrecacheParticleSystem( "muzzleflash_m14" )
|
||||
PrecacheParticleSystem( "muzzleflash_ak47" )
|
||||
PrecacheParticleSystem( "muzzleflash_ak74" )
|
||||
PrecacheParticleSystem( "muzzleflash_m82" )
|
||||
PrecacheParticleSystem( "muzzleflash_m3" )
|
||||
PrecacheParticleSystem( "muzzleflash_famas" )
|
||||
PrecacheParticleSystem( "muzzleflash_g3" )
|
||||
PrecacheParticleSystem( "muzzleflash_1" )
|
||||
PrecacheParticleSystem( "muzzleflash_3" )
|
||||
PrecacheParticleSystem( "muzzleflash_4" )
|
||||
PrecacheParticleSystem( "muzzleflash_5" )
|
||||
PrecacheParticleSystem( "muzzleflash_6" )
|
94
lua/arc9/shared/sh_move.lua
Normal file
94
lua/arc9/shared/sh_move.lua
Normal file
@ -0,0 +1,94 @@
|
||||
ARC9.LastEyeAngles = Angle(0, 0, 0)
|
||||
ARC9.RecoilRise = Angle(0, 0, 0)
|
||||
|
||||
function ARC9.Move(ply, mv, cmd)
|
||||
local wpn = ply:GetActiveWeapon()
|
||||
|
||||
if !wpn.ARC9 then return end
|
||||
|
||||
local basespd = (Vector(cmd:GetForwardMove(), cmd:GetUpMove(), cmd:GetSideMove())):Length()
|
||||
basespd = math.min(basespd, mv:GetMaxClientSpeed())
|
||||
|
||||
local mult = wpn:GetProcessedValue("Speed", 1)
|
||||
|
||||
if wpn:GetSightAmount() > 0 then
|
||||
if ply:KeyDown(IN_SPEED) then
|
||||
mult = mult / Lerp(wpn:GetSightAmount(), 1, ply:GetRunSpeed() / ply:GetWalkSpeed())
|
||||
end
|
||||
end
|
||||
|
||||
mv:SetMaxSpeed(basespd * mult)
|
||||
mv:SetMaxClientSpeed(basespd * mult)
|
||||
end
|
||||
|
||||
hook.Add("SetupMove", "ARC9.SetupMove", ARC9.Move)
|
||||
|
||||
function ARC9.StartCommand(ply, cmd)
|
||||
local wpn = ply:GetActiveWeapon()
|
||||
|
||||
if !wpn.ARC9 then return end
|
||||
|
||||
local diff = ARC9.LastEyeAngles - cmd:GetViewAngles()
|
||||
local recrise = ARC9.RecoilRise
|
||||
|
||||
if recrise.p > 0 then
|
||||
recrise.p = math.Clamp(recrise.p, 0, recrise.p - diff.p)
|
||||
elseif recrise.p < 0 then
|
||||
recrise.p = math.Clamp(recrise.p, recrise.p - diff.p, 0)
|
||||
end
|
||||
|
||||
if recrise.y > 0 then
|
||||
recrise.y = math.Clamp(recrise.y, 0, recrise.y - diff.y)
|
||||
elseif recrise.y < 0 then
|
||||
recrise.y = math.Clamp(recrise.y, recrise.y - diff.y, 0)
|
||||
end
|
||||
|
||||
recrise:Normalize()
|
||||
ARC9.RecoilRise = recrise
|
||||
|
||||
if math.abs(wpn:GetRecoilUp()) > 0 or math.abs(wpn:GetRecoilSide()) > 0 then
|
||||
local eyeang = cmd:GetViewAngles()
|
||||
|
||||
local uprec = FrameTime() * wpn:GetRecoilUp() * 20
|
||||
local siderec = FrameTime() * wpn:GetRecoilSide() * 20
|
||||
|
||||
eyeang.p = eyeang.p + uprec
|
||||
eyeang.y = eyeang.y + siderec
|
||||
|
||||
recrise = ARC9.RecoilRise
|
||||
|
||||
recrise = recrise + Angle(uprec, siderec, 0)
|
||||
|
||||
ARC9.RecoilRise = recrise
|
||||
|
||||
cmd:SetViewAngles(eyeang)
|
||||
|
||||
-- local aim_kick_v = rec * math.sin(CurTime() * 15) * FrameTime() * (1 - sightdelta)
|
||||
-- local aim_kick_h = rec * math.sin(CurTime() * 12.2) * FrameTime() * (1 - sightdelta)
|
||||
|
||||
-- wpn:SetFreeAimAngle(wpn:GetFreeAimAngle() - Angle(aim_kick_v, aim_kick_h, 0))
|
||||
end
|
||||
|
||||
recrise = ARC9.RecoilRise
|
||||
|
||||
local recreset = recrise * FrameTime() * 3.5 * wpn:GetProcessedValue("RecoilAutoControl")
|
||||
|
||||
recrise = recrise - recreset
|
||||
|
||||
recrise:Normalize()
|
||||
|
||||
local eyeang = cmd:GetViewAngles()
|
||||
|
||||
-- eyeang.p = math.AngleDifference(eyeang.p, recreset.p)
|
||||
-- eyeang.y = math.AngleDifference(eyeang.y, recreset.y)
|
||||
|
||||
eyeang = eyeang - recreset
|
||||
|
||||
cmd:SetViewAngles(eyeang)
|
||||
|
||||
ARC9.RecoilRise = recrise
|
||||
|
||||
ARC9.LastEyeAngles = cmd:GetViewAngles()
|
||||
end
|
||||
|
||||
hook.Add("StartCommand", "ARC9_StartCommand", ARC9.StartCommand)
|
388
lua/arc9/shared/sh_physbullet.lua
Normal file
388
lua/arc9/shared/sh_physbullet.lua
Normal file
@ -0,0 +1,388 @@
|
||||
ARC9.PhysBullets = {
|
||||
}
|
||||
|
||||
function ARC9:SendBullet(bullet, attacker)
|
||||
net.Start("ARC9_sendbullet", true)
|
||||
net.WriteVector(bullet.Pos)
|
||||
net.WriteAngle(bullet.Vel:Angle())
|
||||
net.WriteFloat(bullet.Vel:Length())
|
||||
net.WriteFloat(bullet.Drag)
|
||||
net.WriteFloat(bullet.Gravity)
|
||||
net.WriteEntity(bullet.Weapon)
|
||||
|
||||
if attacker and attacker:IsValid() and attacker:IsPlayer() and !game.SinglePlayer() then
|
||||
net.SendOmit(attacker)
|
||||
else
|
||||
if game.SinglePlayer() then
|
||||
net.WriteEntity(attacker)
|
||||
end
|
||||
net.Broadcast()
|
||||
end
|
||||
end
|
||||
|
||||
function ARC9:ShootPhysBullet(wep, pos, vel, tbl)
|
||||
tbl = tbl or {}
|
||||
local bullet = {
|
||||
Penleft = wep:GetProcessedValue("Penetration"),
|
||||
Gravity = wep:GetProcessedValue("PhysBulletGravity"),
|
||||
Pos = pos,
|
||||
Vel = vel,
|
||||
Drag = wep:GetProcessedValue("PhysBulletDrag"),
|
||||
Travelled = 0,
|
||||
StartTime = CurTime(),
|
||||
Imaginary = false,
|
||||
Underwater = false,
|
||||
Weapon = wep,
|
||||
Attacker = wep:GetOwner(),
|
||||
Filter = {wep:GetOwner()},
|
||||
Damaged = {},
|
||||
Dead = false,
|
||||
}
|
||||
|
||||
for i, k in pairs(tbl) do
|
||||
bullet[i] = k
|
||||
end
|
||||
|
||||
if bit.band( util.PointContents( pos ), CONTENTS_WATER ) == CONTENTS_WATER then
|
||||
bullet.Underwater = true
|
||||
end
|
||||
|
||||
table.insert(ARC9.PhysBullets, bullet)
|
||||
|
||||
if !game.SinglePlayer() then
|
||||
local owner = wep:GetOwner()
|
||||
if owner:IsPlayer() and SERVER then
|
||||
local latency = engine.TickCount() - owner:GetCurrentCommand():TickCount()
|
||||
local timestep = engine.TickInterval()
|
||||
|
||||
latency = math.max(latency, 300) // can't let people cheat TOO hard
|
||||
|
||||
while latency > 0 do
|
||||
ARC9:ProgressPhysBullet(bullet, timestep)
|
||||
latency = latency - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
-- ARC9:ProgressPhysBullet(bullet, FrameTime())
|
||||
|
||||
ARC9:SendBullet(bullet, wep:GetOwner())
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
|
||||
net.Receive("ARC9_sendbullet", function(len, ply)
|
||||
local pos = net.ReadVector()
|
||||
local ang = net.ReadAngle()
|
||||
local vel = net.ReadFloat()
|
||||
local drag = net.ReadFloat()
|
||||
local grav = net.ReadFloat()
|
||||
local weapon = net.ReadEntity()
|
||||
local ent = nil
|
||||
|
||||
if game.SinglePlayer() then
|
||||
ent = net.ReadEntity()
|
||||
end
|
||||
|
||||
local bullet = {
|
||||
Pos = pos,
|
||||
Vel = ang:Forward() * vel,
|
||||
Travelled = 0,
|
||||
StartTime = CurTime(),
|
||||
Imaginary = false,
|
||||
Underwater = false,
|
||||
Dead = false,
|
||||
Damaged = {},
|
||||
Drag = drag,
|
||||
Attacker = ent,
|
||||
Gravity = grav,
|
||||
Weapon = weapon,
|
||||
Color = weapon:GetProcessedValue("TracerColor"),
|
||||
Fancy = weapon:GetProcessedValue("FancyBullets")
|
||||
}
|
||||
|
||||
if bit.band( util.PointContents( pos ), CONTENTS_WATER ) == CONTENTS_WATER then
|
||||
bullet.Underwater = true
|
||||
end
|
||||
|
||||
table.insert(ARC9.PhysBullets, bullet)
|
||||
end)
|
||||
|
||||
end
|
||||
|
||||
function ARC9:DoPhysBullets()
|
||||
local new = {}
|
||||
for _, i in pairs(ARC9.PhysBullets) do
|
||||
ARC9:ProgressPhysBullet(i, FrameTime())
|
||||
|
||||
if !i.Dead then
|
||||
table.insert(new, i)
|
||||
end
|
||||
end
|
||||
|
||||
ARC9.PhysBullets = new
|
||||
end
|
||||
|
||||
hook.Add("Think", "ARC9_DoPhysBullets", ARC9.DoPhysBullets)
|
||||
|
||||
local function indim(vec, maxdim)
|
||||
if math.abs(vec.x) > maxdim or math.abs(vec.y) > maxdim or math.abs(vec.z) > maxdim then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function ARC9:ProgressPhysBullet(bullet, timestep)
|
||||
timestep = timestep or FrameTime()
|
||||
|
||||
if bullet.Dead then return end
|
||||
|
||||
local oldpos = bullet.Pos
|
||||
local oldvel = bullet.Vel
|
||||
local dir = bullet.Vel:GetNormalized()
|
||||
local spd = bullet.Vel:Length() * timestep
|
||||
local drag = bullet.Drag * spd * spd * (1 / 150000)
|
||||
local gravity = timestep * GetConVar("ARC9_bullet_gravity"):GetFloat() * (bullet.Gravity or 1) * 600
|
||||
|
||||
local attacker = bullet.Attacker
|
||||
local weapon = bullet.Weapon
|
||||
|
||||
-- if !IsValid(attacker) then
|
||||
-- bullet.Dead = true
|
||||
-- return
|
||||
-- end
|
||||
|
||||
if !IsValid(weapon) then
|
||||
bullet.Dead = true
|
||||
return
|
||||
end
|
||||
|
||||
if bullet.Fancy then
|
||||
weapon:RunHook("HookP_ModifyBullet", bullet)
|
||||
|
||||
if bullet.Dead then return end
|
||||
end
|
||||
|
||||
if bullet.Underwater then
|
||||
drag = drag * 3
|
||||
end
|
||||
|
||||
drag = drag * GetConVar("ARC9_bullet_drag"):GetFloat()
|
||||
|
||||
if spd <= 0.001 then bullet.Dead = true return end
|
||||
|
||||
local newpos = oldpos + (oldvel * timestep)
|
||||
local newvel = oldvel - (dir * drag)
|
||||
newvel = newvel - (Vector(0, 0, 1) * gravity)
|
||||
|
||||
if bullet.Imaginary then
|
||||
-- the bullet has exited the map, but will continue being visible.
|
||||
bullet.Pos = newpos
|
||||
bullet.Vel = newvel
|
||||
bullet.Travelled = bullet.Travelled + spd
|
||||
|
||||
if CLIENT and !GetConVar("ARC9_bullet_imaginary"):GetBool() then
|
||||
bullet.Dead = true
|
||||
end
|
||||
else
|
||||
if attacker:IsPlayer() then
|
||||
attacker:LagCompensation(true)
|
||||
end
|
||||
|
||||
local tr = util.TraceLine({
|
||||
start = oldpos,
|
||||
endpos = newpos,
|
||||
filter = bullet.Filter,
|
||||
mask = MASK_SHOT
|
||||
})
|
||||
|
||||
if attacker:IsPlayer() then
|
||||
attacker:LagCompensation(false)
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
debugoverlay.Line(oldpos, tr.HitPos, 5, Color(100,100,255), true)
|
||||
else
|
||||
debugoverlay.Line(oldpos, tr.HitPos, 5, Color(255,200,100), true)
|
||||
end
|
||||
|
||||
if tr.HitSky then
|
||||
if CLIENT and GetConVar("ARC9_bullet_imaginary"):GetBool() then
|
||||
bullet.Imaginary = true
|
||||
else
|
||||
bullet.Dead = true
|
||||
end
|
||||
|
||||
bullet.Pos = newpos
|
||||
bullet.Vel = newvel
|
||||
bullet.Travelled = bullet.Travelled + spd
|
||||
|
||||
if SERVER then
|
||||
bullet.Dead = true
|
||||
end
|
||||
elseif tr.Hit then
|
||||
bullet.Travelled = bullet.Travelled + (oldpos - tr.HitPos):Length()
|
||||
bullet.Pos = tr.HitPos
|
||||
-- if we're the client, we'll get the bullet back when it exits.
|
||||
|
||||
if attacker:IsPlayer() then
|
||||
attacker:LagCompensation(true)
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
debugoverlay.Cross(tr.HitPos, 5, 5, Color(100,100,255), true)
|
||||
else
|
||||
debugoverlay.Cross(tr.HitPos, 5, 5, Color(255,200,100), true)
|
||||
end
|
||||
|
||||
local eid = tr.Entity:EntIndex()
|
||||
|
||||
if CLIENT then
|
||||
-- do an impact effect and forget about it
|
||||
if !game.SinglePlayer() then
|
||||
attacker:FireBullets({
|
||||
Src = oldpos,
|
||||
Dir = dir,
|
||||
Distance = spd + 16,
|
||||
Tracer = 0,
|
||||
Damage = 0,
|
||||
IgnoreEntity = bullet.Attacker
|
||||
})
|
||||
end
|
||||
bullet.Dead = true
|
||||
return
|
||||
elseif SERVER then
|
||||
bullet.Damaged[eid] = true
|
||||
bullet.Dead = true
|
||||
|
||||
bullet.Attacker:FireBullets({
|
||||
Damage = weapon:GetProcessedValue("Damage_Max"),
|
||||
Force = 8,
|
||||
Tracer = 0,
|
||||
Num = 1,
|
||||
Dir = bullet.Vel:GetNormalized(),
|
||||
Src = oldpos,
|
||||
Spread = Vector(0, 0, 0),
|
||||
Callback = function(att, btr, dmg)
|
||||
local range = bullet.Travelled
|
||||
|
||||
weapon:AfterShotFunction(btr, dmg, range, bullet.Penleft, bullet.Damaged)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
if attacker:IsPlayer() then
|
||||
attacker:LagCompensation(false)
|
||||
end
|
||||
else
|
||||
-- bullet did not impact anything
|
||||
-- break glass in the way
|
||||
-- attacker:FireBullets({
|
||||
-- Src = oldpos,
|
||||
-- Dir = dir,
|
||||
-- Distance = spd,
|
||||
-- Tracer = 0,
|
||||
-- Damage = 0,
|
||||
-- IgnoreEntity = bullet.Attacker
|
||||
-- })
|
||||
|
||||
bullet.Pos = tr.HitPos
|
||||
bullet.Vel = newvel
|
||||
bullet.Travelled = bullet.Travelled + spd
|
||||
|
||||
if bullet.Underwater then
|
||||
if bit.band( util.PointContents( tr.HitPos ), CONTENTS_WATER ) != CONTENTS_WATER then
|
||||
local utr = util.TraceLine({
|
||||
start = tr.HitPos,
|
||||
endpos = oldpos,
|
||||
filter = bullet.Attacker,
|
||||
mask = MASK_WATER
|
||||
})
|
||||
|
||||
if utr.Hit then
|
||||
local fx = EffectData()
|
||||
fx:SetOrigin(utr.HitPos)
|
||||
fx:SetScale(5)
|
||||
fx:SetFlags(0)
|
||||
util.Effect("gunshotsplash", fx)
|
||||
end
|
||||
|
||||
bullet.Underwater = false
|
||||
end
|
||||
else
|
||||
if bit.band( util.PointContents( tr.HitPos ), CONTENTS_WATER ) == CONTENTS_WATER then
|
||||
local utr = util.TraceLine({
|
||||
start = oldpos,
|
||||
endpos = tr.HitPos,
|
||||
filter = bullet.Attacker,
|
||||
mask = MASK_WATER
|
||||
})
|
||||
|
||||
if utr.Hit then
|
||||
local fx = EffectData()
|
||||
fx:SetOrigin(utr.HitPos)
|
||||
fx:SetScale(5)
|
||||
fx:SetFlags(0)
|
||||
util.Effect("gunshotsplash", fx)
|
||||
end
|
||||
|
||||
bullet.Underwater = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local MaxDimensions = 16384 * 4
|
||||
local WorldDimensions = 16384
|
||||
|
||||
if bullet.StartTime <= (CurTime() - GetConVar("ARC9_bullet_lifetime"):GetFloat()) then
|
||||
bullet.Dead = true
|
||||
elseif !indim(bullet.Pos, MaxDimensions) then
|
||||
bullet.Dead = true
|
||||
elseif !indim(bullet.Pos, WorldDimensions) then
|
||||
bullet.Imaginary = true
|
||||
end
|
||||
end
|
||||
|
||||
local head = Material("particle/particle_glow_04")
|
||||
local tracer = Material("effects/tracer_middle")
|
||||
|
||||
function ARC9.DrawPhysBullets()
|
||||
cam.Start3D()
|
||||
for _, i in pairs(ARC9.PhysBullets) do
|
||||
if i.Travelled <= (i.Vel:Length() * 0.1) then continue end
|
||||
|
||||
local size = 1
|
||||
|
||||
size = size * math.log(EyePos():DistToSqr(i.Pos) - math.pow(256, 2))
|
||||
|
||||
size = math.Clamp(size, 0, math.huge)
|
||||
|
||||
-- local delta = (EyePos():DistToSqr(i.Pos) / math.pow(20000, 2))
|
||||
|
||||
-- size = math.pow(size, Lerp(delta, 1, 2))
|
||||
|
||||
-- cam.Start3D()
|
||||
|
||||
local col = i.Color or Color(255, 225, 200)
|
||||
-- local col = Color(255, 225, 200)
|
||||
|
||||
render.SetMaterial(head)
|
||||
render.DrawSprite(i.Pos, size, size, col)
|
||||
|
||||
render.SetMaterial(tracer)
|
||||
render.DrawBeam(i.Pos, i.Pos - i.Vel:GetNormalized() * math.min(i.Vel:Length() * 0.5, 2048), size * 0.75, 0, 1, col)
|
||||
|
||||
-- cam.End3D()
|
||||
end
|
||||
cam.End3D()
|
||||
end
|
||||
|
||||
hook.Add("PreDrawEffects", "ARC9_DrawPhysBullets", ARC9.DrawPhysBullets)
|
||||
|
||||
hook.Add("PostCleanupMap", "ARC9_CleanPhysBullets", function()
|
||||
ARC9.PhysBullets = {}
|
||||
end)
|
3
lua/arc9/shared/sh_truenames.lua
Normal file
3
lua/arc9/shared/sh_truenames.lua
Normal file
@ -0,0 +1,3 @@
|
||||
function ARC9:EnableTrueNames()
|
||||
return GetConVar("arc9_truenames"):GetBool()
|
||||
end
|
30
lua/autorun/sh_arc9_autorun.lua
Normal file
30
lua/autorun/sh_arc9_autorun.lua
Normal file
@ -0,0 +1,30 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
ARC9 = {}
|
||||
|
||||
ARC9.Overrun = false
|
||||
|
||||
local searchdir = "arc9/"
|
||||
|
||||
for _, v in pairs(file.Find(searchdir .. "common/*", "LUA")) do
|
||||
include(searchdir .. "common/" .. v)
|
||||
AddCSLuaFile(searchdir .. "common/" .. v)
|
||||
end
|
||||
|
||||
for _, v in pairs(file.Find(searchdir .. "shared/*", "LUA")) do
|
||||
include(searchdir .. "shared/" .. v)
|
||||
AddCSLuaFile(searchdir .. "shared/" .. v)
|
||||
end
|
||||
|
||||
for _, v in pairs(file.Find(searchdir .. "client/*", "LUA")) do
|
||||
AddCSLuaFile(searchdir .. "client/" .. v)
|
||||
if CLIENT then
|
||||
include(searchdir .. "client/" .. v)
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER or game.SinglePlayer() then
|
||||
for _, v in pairs(file.Find(searchdir .. "server/*", "LUA")) do
|
||||
include(searchdir .. "server/" .. v)
|
||||
end
|
||||
end
|
38
lua/effects/arc9_muzzleeffect.lua
Normal file
38
lua/effects/arc9_muzzleeffect.lua
Normal file
@ -0,0 +1,38 @@
|
||||
function EFFECT:Init(data)
|
||||
local wpn = data:GetEntity()
|
||||
|
||||
if !IsValid(wpn) then self:Remove() return end
|
||||
|
||||
local muzzle = wpn:GetValue("MuzzleEffect")
|
||||
|
||||
local att = data:GetAttachment() or 1
|
||||
|
||||
local wm = false
|
||||
|
||||
if (LocalPlayer():ShouldDrawLocalPlayer() or wpn.Owner != LocalPlayer()) then
|
||||
wm = true
|
||||
att = 1
|
||||
end
|
||||
|
||||
local parent = wpn
|
||||
|
||||
if !wm then
|
||||
parent = LocalPlayer():GetViewModel()
|
||||
end
|
||||
|
||||
parent = wpn:GetMuzzleDevice(wm)
|
||||
|
||||
-- if !IsValid(parent) then return end
|
||||
|
||||
if muzzle then
|
||||
ParticleEffectAttach(muzzle, PATTACH_POINT_FOLLOW, parent, att)
|
||||
end
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
return false
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
return false
|
||||
end
|
178
lua/effects/arc9_shelleffect.lua
Normal file
178
lua/effects/arc9_shelleffect.lua
Normal file
@ -0,0 +1,178 @@
|
||||
EFFECT.Type = 1
|
||||
|
||||
EFFECT.Pitch = 100
|
||||
|
||||
EFFECT.Model = "models/shells/shell_57.mdl"
|
||||
|
||||
EFFECT.AlreadyPlayedSound = false
|
||||
EFFECT.ShellTime = 0.5
|
||||
EFFECT.SpawnTime = 0
|
||||
|
||||
EFFECT.TypeSettings = {
|
||||
[1] = {
|
||||
Model = "models/weapons/shell.mdl",
|
||||
Sounds = {
|
||||
"player/pl_shell1.wav",
|
||||
"player/pl_shell2.wav",
|
||||
"player/pl_shell3.wav",
|
||||
}
|
||||
},
|
||||
[2] = {
|
||||
Model = "models/weapons/rifleshell.mdl",
|
||||
Sounds = {
|
||||
"player/pl_shell1.wav",
|
||||
"player/pl_shell2.wav",
|
||||
"player/pl_shell3.wav",
|
||||
},
|
||||
Scale = 0.5
|
||||
},
|
||||
[3] = {
|
||||
Model = "models/weapons/shotgun_shell.mdl",
|
||||
Sounds = {
|
||||
"weapons/fx/tink/shotgun_shell1.wav",
|
||||
"weapons/fx/tink/shotgun_shell2.wav",
|
||||
"weapons/fx/tink/shotgun_shell3.wav",
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
function EFFECT:Init(data)
|
||||
|
||||
local att = data:GetAttachment()
|
||||
local ent = data:GetEntity()
|
||||
local type = data:GetFlags()
|
||||
|
||||
self.Type = type or self.Type
|
||||
|
||||
local typetbl = self.TypeSettings[self.Type]
|
||||
|
||||
if !IsValid(ent) then self:Remove() return end
|
||||
if !IsValid(ent:GetOwner()) then self:Remove() return end
|
||||
|
||||
if LocalPlayer():ShouldDrawLocalPlayer() or ent:GetOwner() != LocalPlayer() then
|
||||
mdl = ent
|
||||
att = 2
|
||||
else
|
||||
mdl = LocalPlayer():GetViewModel()
|
||||
end
|
||||
|
||||
if !IsValid(ent) then self:Remove() return end
|
||||
if !mdl or !IsValid(mdl) then self:Remove() return end
|
||||
if !mdl:GetAttachment(att) then self:Remove() return end
|
||||
if !typetbl then return end
|
||||
|
||||
local origin, ang = mdl:GetAttachment(att).Pos, mdl:GetAttachment(att).Ang
|
||||
|
||||
-- ang:RotateAroundAxis(ang:Up(), -90)
|
||||
|
||||
-- ang:RotateAroundAxis(ang:Right(), (ent.ShellRotateAngle or Angle(0, 0, 0))[1])
|
||||
-- ang:RotateAroundAxis(ang:Up(), (ent.ShellRotateAngle or Angle(0, 0, 0))[2])
|
||||
-- ang:RotateAroundAxis(ang:Forward(), (ent.ShellRotateAngle or Angle(0, 0, 0))[3])
|
||||
|
||||
local dir = ang:Forward()
|
||||
|
||||
ang:RotateAroundAxis(ang:Forward(), 90)
|
||||
ang:RotateAroundAxis(ang:Up(), 180)
|
||||
|
||||
self:SetPos(origin)
|
||||
self:SetModel(typetbl.Model)
|
||||
self:DrawShadow(true)
|
||||
self:SetAngles(ang)
|
||||
self:SetModelScale(typetbl.Scale or 1)
|
||||
|
||||
-- if !LocalPlayer():ShouldDrawLocalPlayer() and ent:GetOwner() == LocalPlayer() then
|
||||
-- self:SetNoDraw(true)
|
||||
-- end
|
||||
|
||||
-- table.insert(ent.EjectedShells, self)
|
||||
|
||||
self.Sounds = typetbl.Sounds
|
||||
|
||||
local s = typetbl.Scale or 1
|
||||
|
||||
local pb_vert = 2 * s
|
||||
local pb_hor = 0.25 * s
|
||||
|
||||
local mag = 150
|
||||
|
||||
self:PhysicsInitBox(Vector(-pb_vert,-pb_hor,-pb_hor), Vector(pb_vert,pb_hor,pb_hor))
|
||||
|
||||
self:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
local plyvel = Vector(0, 0, 0)
|
||||
|
||||
if IsValid(ent.Owner) then
|
||||
plyvel = ent.Owner:GetAbsVelocity()
|
||||
end
|
||||
|
||||
phys:Wake()
|
||||
phys:SetDamping(0, 0)
|
||||
phys:SetMass(1)
|
||||
phys:SetMaterial("gmod_silent")
|
||||
|
||||
phys:SetVelocity((dir * mag * math.Rand(1, 2)) + plyvel)
|
||||
|
||||
phys:AddAngleVelocity(VectorRand() * 100)
|
||||
phys:AddAngleVelocity(ang:Up() * 2500 * math.Rand(0.75, 1.25))
|
||||
|
||||
-- local emitter = ParticleEmitter(origin)
|
||||
|
||||
-- for i = 1, 3 do
|
||||
-- local particle = emitter:Add("particles/smokey", origin + (dir * 2))
|
||||
|
||||
-- if (particle) then
|
||||
-- particle:SetVelocity(VectorRand() * 10 + (dir * i * math.Rand(48, 64)) + plyvel)
|
||||
-- particle:SetLifeTime(0)
|
||||
-- particle:SetDieTime(math.Rand(0.05, 0.15))
|
||||
-- particle:SetStartAlpha(math.Rand(40, 60))
|
||||
-- particle:SetEndAlpha(0)
|
||||
-- particle:SetStartSize(0)
|
||||
-- particle:SetEndSize(math.Rand(18, 24))
|
||||
-- particle:SetRoll(math.rad(math.Rand(0, 360)))
|
||||
-- particle:SetRollDelta(math.Rand(-1, 1))
|
||||
-- particle:SetLighting(true)
|
||||
-- particle:SetAirResistance(96)
|
||||
-- particle:SetGravity(Vector(-7, 3, 20))
|
||||
-- particle:SetColor(150, 150, 150)
|
||||
-- end
|
||||
-- end
|
||||
|
||||
self.SpawnTime = CurTime()
|
||||
end
|
||||
|
||||
function EFFECT:PhysicsCollide()
|
||||
if self.AlreadyPlayedSound then return end
|
||||
|
||||
sound.Play(self.Sounds[math.random(#self.Sounds)], self:GetPos(), 65, 100, 1)
|
||||
|
||||
self.AlreadyPlayedSound = true
|
||||
end
|
||||
|
||||
function EFFECT:Think()
|
||||
if self:GetVelocity():Length() > 0 then self.SpawnTime = CurTime() end
|
||||
|
||||
if (self.SpawnTime + self.ShellTime) <= CurTime() then
|
||||
if !IsValid(self) then return end
|
||||
self:SetRenderFX( kRenderFxFadeFast )
|
||||
if (self.SpawnTime + self.ShellTime + 0.25) <= CurTime() then
|
||||
if !IsValid(self:GetPhysicsObject()) then return end
|
||||
self:GetPhysicsObject():EnableMotion(false)
|
||||
if (self.SpawnTime + self.ShellTime + 0.5) <= CurTime() then
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function EFFECT:Render()
|
||||
if !IsValid(self) then return end
|
||||
self:DrawModel()
|
||||
end
|
||||
|
||||
function EFFECT:DrawTranslucent()
|
||||
self:DrawModel()
|
||||
end
|
127
lua/weapons/arc9_base/cl_autosolve.lua
Normal file
127
lua/weapons/arc9_base/cl_autosolve.lua
Normal file
@ -0,0 +1,127 @@
|
||||
SWEP.MultiSightTable = {
|
||||
-- {
|
||||
-- Pos = Vector(0, 0, 0),
|
||||
-- Ang = Angle(0, 0, 0)
|
||||
-- }
|
||||
}
|
||||
|
||||
function SWEP:BuildMultiSight()
|
||||
self.MultiSightTable = {}
|
||||
|
||||
local keepbaseirons = true
|
||||
|
||||
for i, slottbl in ipairs(self:GetSubSlotList()) do
|
||||
if !slottbl.Installed then continue end
|
||||
local atttbl = ARC9.GetAttTable(slottbl.Installed)
|
||||
|
||||
if atttbl.Sights then
|
||||
for _, sight in pairs(atttbl.Sights) do
|
||||
local s = self:GenerateAutoSight(sight, slottbl)
|
||||
s.atttbl = atttbl
|
||||
s.ExtraSightDistance = slottbl.ExtraSightDistance or 0
|
||||
table.insert(self.MultiSightTable, s)
|
||||
end
|
||||
|
||||
if !slottbl.KeepBaseIrons and !atttbl.KeepBaseIrons then
|
||||
keepbaseirons = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if keepbaseirons then
|
||||
local tbl = {}
|
||||
table.Add(tbl, self.BaseSights)
|
||||
table.Add(self.MultiSightTable, self.BaseSights)
|
||||
self.MultiSightTable = tbl
|
||||
end
|
||||
|
||||
if self.MultiSightIndex > #self.MultiSightTable then
|
||||
self.MultiSightIndex = 1
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GenerateAutoSight(sight, slottbl)
|
||||
local pos, ang = self:GetAttPos(slottbl, false, true)
|
||||
|
||||
pos = pos - (ang:Right() * sight.Pos.x)
|
||||
pos = pos - (ang:Forward() * sight.Pos.y)
|
||||
pos = pos - (ang:Up() * sight.Pos.z)
|
||||
|
||||
ang:RotateAroundAxis(ang:Right(), sight.Ang.p)
|
||||
ang:RotateAroundAxis(ang:Up(), sight.Ang.y)
|
||||
ang:RotateAroundAxis(ang:Forward(), sight.Ang.r)
|
||||
|
||||
debugoverlay.Axis(pos, ang, 16, 1, true)
|
||||
|
||||
local s_pos = Vector(0, 0, 0)
|
||||
local s_ang = Angle(0, 0, 0)
|
||||
|
||||
local up, forward, right = s_ang:Up(), s_ang:Forward(), s_ang:Right()
|
||||
|
||||
s_pos = s_pos + (right * pos.x)
|
||||
s_pos = s_pos + (forward * pos.y)
|
||||
s_pos = s_pos + (up * -pos.z)
|
||||
|
||||
return {
|
||||
Pos = s_pos,
|
||||
Ang = Angle(0, 0, 0),
|
||||
Magnification = sight.Magnification or 1,
|
||||
-- ExtraAng = ang
|
||||
}
|
||||
end
|
||||
|
||||
SWEP.MultiSightIndex = 1
|
||||
|
||||
function SWEP:GetSight()
|
||||
if GetConVar("developer"):GetBool() then
|
||||
self:BuildMultiSight()
|
||||
end
|
||||
return self.MultiSightTable[self.MultiSightIndex] or self.IronSights
|
||||
end
|
||||
|
||||
function SWEP:GetSightPositions()
|
||||
local s = self:GetSight()
|
||||
return s.Pos, s.Ang
|
||||
end
|
||||
|
||||
function SWEP:GetExtraSightPositions()
|
||||
local s = self:GetSight()
|
||||
local se = s.ExtraPos or Vector(0, 0, 0)
|
||||
se.y = se.y - (s.ExtraSightDistance or 0)
|
||||
return se, s.ExtraAng or Angle(0, 0, 0)
|
||||
end
|
||||
|
||||
function SWEP:SwitchMultiSight()
|
||||
local old_msi = self.MultiSightIndex
|
||||
self.MultiSightIndex = self.MultiSightIndex + 1
|
||||
|
||||
if self.MultiSightIndex > #self.MultiSightTable then
|
||||
self.MultiSightIndex = 1
|
||||
end
|
||||
|
||||
if self.MultiSightIndex != old_msi then
|
||||
// eh put some code in here
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetMagnification()
|
||||
local sight = self:GetSight()
|
||||
return sight.Magnification or 1
|
||||
end
|
||||
|
||||
function SWEP:AdjustMouseSensitivity()
|
||||
if self:GetSightAmount() <= 0 then return end
|
||||
|
||||
local mag = self:GetMagnification()
|
||||
local fov = GetConVar("fov_desired"):GetFloat()
|
||||
|
||||
local sight = self:GetSight()
|
||||
|
||||
if sight.atttbl and sight.atttbl.RTScope then
|
||||
mag = mag + (fov / sight.atttbl.RTScopeFOV)
|
||||
end
|
||||
|
||||
if mag > 0 then
|
||||
return 1 / mag
|
||||
end
|
||||
end
|
29
lua/weapons/arc9_base/cl_camera.lua
Normal file
29
lua/weapons/arc9_base/cl_camera.lua
Normal file
@ -0,0 +1,29 @@
|
||||
SWEP.SmoothedMagnification = 1
|
||||
|
||||
function SWEP:CalcView(ply, pos, ang, fov)
|
||||
local rec = (self:GetLastRecoilTime() + self:GetProcessedValue("RecoilResetTime")) - CurTime()
|
||||
|
||||
rec = rec * 10
|
||||
|
||||
rec = math.Clamp(rec, 0, 1)
|
||||
|
||||
rec = rec * self:GetProcessedValue("RecoilKick")
|
||||
|
||||
if rec > 0 then
|
||||
ang.r = ang.r + (math.sin(CurTime() * 70.151) * rec * 0.25)
|
||||
end
|
||||
|
||||
local mag = 1
|
||||
|
||||
if self:GetSightAmount() > 0 then
|
||||
mag = Lerp(self:GetSightAmount(), 1, self:GetMagnification())
|
||||
end
|
||||
|
||||
local diff = math.abs(self.SmoothedMagnification - mag)
|
||||
|
||||
self.SmoothedMagnification = math.Approach(self.SmoothedMagnification, mag, FrameTime() * diff * 10)
|
||||
|
||||
fov = fov / self.SmoothedMagnification
|
||||
|
||||
return pos, ang, fov
|
||||
end
|
504
lua/weapons/arc9_base/cl_customize.lua
Normal file
504
lua/weapons/arc9_base/cl_customize.lua
Normal file
@ -0,0 +1,504 @@
|
||||
local function multlinetext(text, maxw, font)
|
||||
local content = {}
|
||||
local tline = ""
|
||||
local x = 0
|
||||
surface.SetFont(font)
|
||||
|
||||
local newlined = string.Split(text, "\n")
|
||||
|
||||
for _, line in pairs(newlined) do
|
||||
local words = string.Split(line, " ")
|
||||
|
||||
for _, word in pairs(words) do
|
||||
local tx = surface.GetTextSize(word)
|
||||
|
||||
if x + tx >= maxw then
|
||||
table.insert(content, tline)
|
||||
tline = ""
|
||||
x = surface.GetTextSize(word)
|
||||
end
|
||||
|
||||
tline = tline .. word .. " "
|
||||
|
||||
x = x + surface.GetTextSize(word .. " ")
|
||||
end
|
||||
|
||||
table.insert(content, tline)
|
||||
tline = ""
|
||||
x = 0
|
||||
end
|
||||
|
||||
return content
|
||||
end
|
||||
|
||||
local function PaintScrollBar(panel, w, h)
|
||||
local ss = ScreenScale(2)
|
||||
local s = ss * 2
|
||||
draw.RoundedBox(ss * 1, (w - s) / 2, 0, s, h, col_fg)
|
||||
end
|
||||
|
||||
// span: panel that hosts the rotating text
|
||||
// txt: the text to draw
|
||||
// x: where to start the crop
|
||||
// y: where to start the crp
|
||||
// tx, ty: where to draw the text
|
||||
// maxw: maximum width
|
||||
// only: don't advance text
|
||||
local function DrawTextRot(span, txt, x, y, tx, ty, maxw, only)
|
||||
local tw, th = surface.GetTextSize(txt)
|
||||
|
||||
span.TextRot = span.TextRot or {}
|
||||
|
||||
if tw > maxw then
|
||||
local realx, realy = span:LocalToScreen(x, y)
|
||||
render.SetScissorRect(realx, realy, realx + maxw, realy + (th * 2), true)
|
||||
|
||||
span.TextRot[txt] = span.TextRot[txt] or 0
|
||||
|
||||
if !only then
|
||||
span.StartTextRot = span.StartTextRot or CurTime()
|
||||
span.TextRotState = span.TextRotState or 0 -- 0: start, 1: moving, 2: end
|
||||
if span.TextRotState == 0 then
|
||||
span.TextRot[txt] = 0
|
||||
if span.StartTextRot < CurTime() - 2 then
|
||||
span.TextRotState = 1
|
||||
end
|
||||
elseif span.TextRotState == 1 then
|
||||
span.TextRot[txt] = span.TextRot[txt] + (FrameTime() * ScreenScale(16))
|
||||
if span.TextRot[txt] >= (tw - maxw) + ScreenScale(8) then
|
||||
span.StartTextRot = CurTime()
|
||||
span.TextRotState = 2
|
||||
end
|
||||
elseif span.TextRotState == 2 then
|
||||
if span.StartTextRot < CurTime() - 2 then
|
||||
span.TextRotState = 3
|
||||
span.StartTextRot = CurTime()
|
||||
end
|
||||
elseif span.TextRotState == 3 then
|
||||
span.TextRot[txt] = span.TextRot[txt] - (FrameTime() * ScreenScale(16))
|
||||
if span.TextRot[txt] <= 0 then
|
||||
span.StartTextRot = CurTime()
|
||||
span.TextRotState = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
surface.SetTextPos(tx - span.TextRot[txt], ty)
|
||||
surface.DrawText(txt)
|
||||
render.SetScissorRect(0, 0, 0, 0, false)
|
||||
else
|
||||
surface.SetTextPos(tx, ty)
|
||||
surface.DrawText(txt)
|
||||
end
|
||||
end
|
||||
|
||||
SWEP.CustomizeHUD = nil
|
||||
SWEP.CustomizeBoxes = nil
|
||||
|
||||
local mat_circle = Material("ARC9/circle.png", "mips smooth")
|
||||
|
||||
local col_hi = Color(255, 237, 193)
|
||||
local col_lo = Color(255, 255, 255)
|
||||
|
||||
function SWEP:RefreshCustomizeMenu()
|
||||
if !self.CustomizeHUD then return end
|
||||
|
||||
self:CreateCustomizeBoxes(self.CustomizeHUD)
|
||||
if self.CustomizeSelectAddr then
|
||||
self:CreateCustomizeSelectMenu(self.CustomizeHUD, self:LocateSlotFromAddress(self.CustomizeSelectAddr))
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:CreateCustomizeBoxes(panel)
|
||||
for _, i in pairs(self.CustomizeBoxes or {}) do
|
||||
i:Remove()
|
||||
end
|
||||
|
||||
self.CustomizeBoxes = {}
|
||||
|
||||
for _, i in pairs(self:GetSubSlotList()) do
|
||||
local cbox = vgui.Create("DPanel", panel)
|
||||
cbox.slottbl = i
|
||||
|
||||
cbox:SetSize(ScreenScale(32), ScreenScale(40))
|
||||
cbox:SetPos(0, 0)
|
||||
cbox.Paint = function(self2, w, h)
|
||||
local apos, aang = self:GetAttPos(self2.slottbl, false)
|
||||
apos = apos + (aang:Up() * 3.5)
|
||||
local col1 = col_hi
|
||||
|
||||
if self:GetSlotBlocked(self2.slottbl) and !self2.slottbl.Installed then
|
||||
col1 = Color(255, 100, 100)
|
||||
end
|
||||
|
||||
cam.Start3D(nil, nil, self.ViewModelFOV)
|
||||
local screenpos = apos:ToScreen()
|
||||
cam.End3D()
|
||||
|
||||
local sx = screenpos.x
|
||||
local sy = screenpos.y
|
||||
|
||||
sx = sx - (cbox:GetWide() * 0.5)
|
||||
sy = sy - (cbox:GetTall() * 0.9)
|
||||
|
||||
sx = math.Clamp(sx, 0, ScrW() - ScreenScale(32))
|
||||
sy = math.Clamp(sy, 0, ScrH() - ScreenScale(40))
|
||||
|
||||
self2:SetPos(sx, sy)
|
||||
|
||||
surface.SetDrawColor(col1)
|
||||
surface.SetMaterial(mat_circle)
|
||||
local s = ScreenScale(8)
|
||||
surface.DrawTexturedRect((w - s) / 2, h - s, s, s)
|
||||
end
|
||||
|
||||
cbox:Paint(0, 0)
|
||||
|
||||
csquare = vgui.Create("DPanel", cbox)
|
||||
csquare.slottbl = i
|
||||
csquare:SetSize(ScreenScale(32), ScreenScale(32))
|
||||
csquare:SetPos(0, 0)
|
||||
csquare.OnMousePressed = function(self2, kc)
|
||||
if kc == MOUSE_LEFT then
|
||||
if !self:GetSlotBlocked(self2.slottbl) or self2.slottbl.Installed then
|
||||
if self:CreateCustomizeSelectMenu(panel, self2.slottbl) then
|
||||
self.CustomizeSelectAddr = self2.slottbl.Address
|
||||
self:CreateCustomizeBoxes(panel)
|
||||
end
|
||||
end
|
||||
elseif kc == MOUSE_RIGHT then
|
||||
if self:Detach(self2.slottbl.Address) then
|
||||
self.CustomizeSelectAddr = self2.slottbl.Address
|
||||
self:CreateCustomizeBoxes(panel)
|
||||
self:CreateCustomizeSelectMenu(panel)
|
||||
end
|
||||
end
|
||||
end
|
||||
csquare.Paint = function(self2, w, h)
|
||||
local col1 = Color(0, 0, 0, 150)
|
||||
local col2 = col_hi
|
||||
local col3 = Color(255, 255, 255)
|
||||
|
||||
if self2:IsHovered() then
|
||||
col1 = Color(100, 100, 100, 150)
|
||||
col2 = Color(0, 0, 0, 255)
|
||||
col3 = Color(50, 50, 50)
|
||||
end
|
||||
|
||||
if self:GetSlotBlocked(self2.slottbl) and !self2.slottbl.Installed then
|
||||
col1 = Color(50, 0, 0, 150)
|
||||
col2 = Color(255, 100, 100)
|
||||
col3 = Color(200, 0, 0)
|
||||
end
|
||||
|
||||
surface.SetDrawColor(col1)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
|
||||
if self2.slottbl.Installed then
|
||||
local atttbl = ARC9.GetAttTable(self2.slottbl.Installed)
|
||||
|
||||
surface.SetDrawColor(col3)
|
||||
surface.SetMaterial(atttbl.Icon)
|
||||
surface.DrawTexturedRect(0, 0, w, h)
|
||||
end
|
||||
|
||||
local txt = self2.slottbl.PrintName or ""
|
||||
|
||||
if self2.slottbl.Installed then
|
||||
local atttbl = ARC9.GetAttTable(self2.slottbl.Installed)
|
||||
|
||||
txt = atttbl.CompactName or atttbl.PrintName or atttbl.ShortName
|
||||
end
|
||||
|
||||
surface.SetTextColor(col2)
|
||||
surface.SetFont("ARC9_6")
|
||||
-- local tw = surface.GetTextSize(txt)
|
||||
-- surface.SetTextPos(0, 0)
|
||||
-- surface.DrawText(txt)
|
||||
DrawTextRot(self2, txt, 0, ScreenScale(32 - 6 - 1), ScreenScale(2), ScreenScale(32 - 6 - 1), ScreenScale(32))
|
||||
|
||||
surface.SetDrawColor(col2)
|
||||
|
||||
local outlines = ScreenScale(0.25)
|
||||
|
||||
for j = 0, math.ceil(outlines) do
|
||||
surface.DrawOutlinedRect(j, j, w - (2 * j), h - (2 * j))
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(self.CustomizeBoxes, cbox)
|
||||
end
|
||||
end
|
||||
|
||||
SWEP.CustomizeSelectAddr = nil
|
||||
SWEP.CustomizeSelectMenu = nil
|
||||
|
||||
function SWEP:CreateCustomizeSelectMenu(panel, slottbl)
|
||||
if self.CustomizeSelectMenu then
|
||||
self.CustomizeSelectMenu:Remove()
|
||||
self.CustomizeSelectMenu = nil
|
||||
end
|
||||
|
||||
if !slottbl then return end
|
||||
|
||||
local bg = vgui.Create("DPanel", panel)
|
||||
|
||||
bg:SetSize(ScreenScale(96), ScrH() - ScreenScale(32))
|
||||
bg:SetPos(ScreenScale(16), ScreenScale(16))
|
||||
bg.Paint = function(self2, w, h)
|
||||
local col1 = Color(0, 0, 0, 150)
|
||||
local col2 = col_hi
|
||||
|
||||
surface.SetDrawColor(col1)
|
||||
surface.DrawRect(0, ScreenScale(18), w, h)
|
||||
|
||||
surface.SetDrawColor(col2)
|
||||
surface.DrawLine(0, ScreenScale(18), w, ScreenScale(18))
|
||||
|
||||
surface.SetTextColor(col_hi)
|
||||
surface.SetTextPos(ScreenScale(4), 0)
|
||||
surface.SetFont("ARC9_16")
|
||||
DrawTextRot(self2, slottbl.PrintName or "Attachment", 0, 0, ScreenScale(4), 0, ScreenScale(96), false)
|
||||
end
|
||||
|
||||
-- Menu for attachments
|
||||
attmenu = vgui.Create("DScrollPanel", bg)
|
||||
attmenu:SetPos(0, ScreenScale(18))
|
||||
attmenu:SetSize(ScreenScale(96), ScrH() - ScreenScale(32 + 18))
|
||||
|
||||
-- attmenu.Paint = function(self2, w, h)
|
||||
-- draw.RoundedBox(2, 0, 0, w, h, col_fg)
|
||||
-- end
|
||||
|
||||
local scroll_2 = attmenu:GetVBar()
|
||||
-- scroll_2.AlreadySet = false
|
||||
-- scroll_2.Paint = function(self2, w, h)
|
||||
-- if !self2.AlreadySet then
|
||||
-- self2:SetScroll(self.Inv_Scroll[self.Inv_SelectedSlot or 0] or 0)
|
||||
-- self2.AlreadySet = true
|
||||
-- end
|
||||
|
||||
-- local scroll = self2:GetScroll()
|
||||
|
||||
-- self.Inv_Scroll[self.Inv_SelectedSlot or 0] = scroll
|
||||
-- end
|
||||
|
||||
scroll_2.btnUp.Paint = function(span, w, h)
|
||||
end
|
||||
scroll_2.btnDown.Paint = function(span, w, h)
|
||||
end
|
||||
scroll_2.btnGrip.Paint = PaintScrollBar
|
||||
|
||||
local slot = slottbl
|
||||
|
||||
if !slot then return end
|
||||
|
||||
local atts = ARC9.GetAttsForCats(slottbl.Category or "")
|
||||
|
||||
table.sort(atts, function(a, b)
|
||||
a = a or ""
|
||||
b = b or ""
|
||||
|
||||
if a == "" or b == "" then return true end
|
||||
|
||||
local atttbl_a = ARC9.GetAttTable(a)
|
||||
local atttbl_b = ARC9.GetAttTable(b)
|
||||
|
||||
local order_a = 0
|
||||
local order_b = 0
|
||||
|
||||
order_a = atttbl_a.SortOrder or order_a
|
||||
order_b = atttbl_b.SortOrder or order_b
|
||||
|
||||
if order_a == order_b then
|
||||
return (atttbl_a.PrintName or "") < (atttbl_b.PrintName or "")
|
||||
end
|
||||
|
||||
return order_a < order_b
|
||||
end)
|
||||
|
||||
for i, att in pairs(atts) do
|
||||
local atttbl = ARC9.GetAttTable(att)
|
||||
|
||||
local attbtn = vgui.Create("DScrollPanel", attmenu)
|
||||
attbtn:SetSize(ScreenScale(96), ScreenScale(12))
|
||||
attbtn:Dock(TOP)
|
||||
attbtn.att = att
|
||||
attbtn.slottbl = slottbl
|
||||
attbtn.address = slottbl.Address
|
||||
attbtn.OnMousePressed = function(self2, kc)
|
||||
if kc == MOUSE_LEFT then
|
||||
self:Attach(self2.slottbl.Address, self2.att)
|
||||
self.CustomizeSelectAddr = self2.slottbl.Address
|
||||
self:RefreshCustomizeMenu()
|
||||
elseif kc == MOUSE_RIGHT then
|
||||
self:Detach(self2.slottbl.Address)
|
||||
self.CustomizeSelectAddr = self2.slottbl.Address
|
||||
self:RefreshCustomizeMenu()
|
||||
end
|
||||
end
|
||||
attbtn.Paint = function(self2, w, h)
|
||||
surface.SetDrawColor(col_hi)
|
||||
surface.DrawLine(0, h-1, w, h-1)
|
||||
|
||||
local attached = self2.slottbl.Installed == self2.att
|
||||
|
||||
local col1 = Color(0, 0, 0, 150)
|
||||
local col2 = col_hi
|
||||
|
||||
if self2:IsHovered() or attached then
|
||||
col1 = col_hi
|
||||
col2 = Color(0, 0, 0, 255)
|
||||
end
|
||||
|
||||
if self2:IsHovered() and attached then
|
||||
col1 = col_lo
|
||||
col2 = Color(0, 0, 0, 255)
|
||||
end
|
||||
|
||||
local canattach = self:CanAttach(self2.slottbl.Address, self2.att, self2.slottbl.slottbl)
|
||||
|
||||
if !canattach then
|
||||
col1 = Color(50, 0, 0, 150)
|
||||
col2 = Color(255, 100, 100)
|
||||
col3 = Color(200, 0, 0)
|
||||
end
|
||||
|
||||
surface.SetDrawColor(col1)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
|
||||
local icon = atttbl.Icon
|
||||
|
||||
surface.SetDrawColor(col2)
|
||||
surface.SetMaterial(icon)
|
||||
surface.DrawTexturedRect(0, 0, ScreenScale(12), ScreenScale(12))
|
||||
|
||||
surface.SetTextColor(col2)
|
||||
surface.SetTextPos(ScreenScale(13), 0)
|
||||
surface.SetFont("ARC9_12")
|
||||
DrawTextRot(self2, atttbl.CompactName or atttbl.PrintName or atttbl.ShortName, ScreenScale(12), 0, ScreenScale(13), 0, ScreenScale(96 - 12), false)
|
||||
end
|
||||
end
|
||||
|
||||
self.CustomizeSelectMenu = bg
|
||||
end
|
||||
|
||||
SWEP.MenuRotation = Angle(0, 0, 0)
|
||||
SWEP.MenuPan = Vector(0, 0, 0)
|
||||
SWEP.MenuRotating = false
|
||||
SWEP.MenuZooming = false
|
||||
SWEP.LastMouseX = 0
|
||||
SWEP.LastMouseY = 0
|
||||
|
||||
function SWEP:CreateCustomizeHUD()
|
||||
self:RemoveCustomizeHUD()
|
||||
|
||||
self.MenuRotation = Angle(0, 0, 0)
|
||||
self.MenuPan = Vector(0, 0, 0)
|
||||
self.MenuRotating = false
|
||||
self.MenuZooming = false
|
||||
|
||||
gui.EnableScreenClicker(true)
|
||||
|
||||
local bg = vgui.Create("DPanel")
|
||||
|
||||
self.CustomizeHUD = bg
|
||||
|
||||
local scrw = ScrW()
|
||||
local scrh = ScrH()
|
||||
|
||||
local airgap = ScreenScale(8)
|
||||
local smallgap = ScreenScale(4)
|
||||
|
||||
bg:SetPos(0, 0)
|
||||
bg:SetSize(ScrW(), ScrH())
|
||||
bg.OnRemove = function(self2)
|
||||
if !IsValid(self) then return end
|
||||
-- self:SavePreset()
|
||||
end
|
||||
bg.OnMousePressed = function(self2, kc)
|
||||
if kc == MOUSE_LEFT then
|
||||
self.MenuRotating = true
|
||||
self.LastMousePos = Vec
|
||||
|
||||
self.LastMouseX, self.LastMouseY = input.GetCursorPos()
|
||||
elseif kc == MOUSE_RIGHT then
|
||||
self.MenuZooming = true
|
||||
self.LastMousePos = Vec
|
||||
|
||||
self.LastMouseX, self.LastMouseY = input.GetCursorPos()
|
||||
end
|
||||
end
|
||||
bg.OnMouseWheeled = function(self2, sd)
|
||||
self.MenuPan = self.MenuPan + Vector(0, 0, sd)
|
||||
end
|
||||
|
||||
bg.Paint = function(self2, w, h)
|
||||
if !IsValid(self) then
|
||||
self:Remove()
|
||||
gui.EnableScreenClicker(false)
|
||||
end
|
||||
|
||||
local name_txt = self:GetValue("PrintName")
|
||||
|
||||
surface.SetFont("ARC9_16")
|
||||
local name_w = surface.GetTextSize(name_txt)
|
||||
surface.SetTextPos(w - name_w - ScreenScale(14), airgap)
|
||||
surface.SetTextColor(0, 0, 0)
|
||||
surface.DrawText(name_txt)
|
||||
|
||||
if self.MenuRotating or self.MenuZooming then
|
||||
if !input.IsMouseDown(MOUSE_LEFT) then
|
||||
self.MenuRotating = false
|
||||
end
|
||||
if !input.IsMouseDown(MOUSE_RIGHT) then
|
||||
self.MenuZooming = false
|
||||
end
|
||||
|
||||
local mousex, mousey = input.GetCursorPos()
|
||||
|
||||
local dx = mousex - self.LastMouseX
|
||||
local dy = mousey - self.LastMouseY
|
||||
|
||||
dx = dx * 200 / ScrW()
|
||||
dy = dy * 200 / ScrW()
|
||||
|
||||
if self.MenuRotating then
|
||||
self.MenuRotation = self.MenuRotation + Angle(dx, dy, 0)
|
||||
end
|
||||
|
||||
if self.MenuZooming then
|
||||
self.MenuPan = self.MenuPan + Vector(dx, dy, 0)
|
||||
end
|
||||
self.MenuRotation:Normalize()
|
||||
|
||||
self.LastMouseX, self.LastMouseY = input.GetCursorPos()
|
||||
end
|
||||
end
|
||||
|
||||
timer.Simple(0, function()
|
||||
self:RefreshCustomizeMenu()
|
||||
end)
|
||||
end
|
||||
|
||||
function SWEP:RemoveCustomizeHUD()
|
||||
if self.CustomizeHUD then
|
||||
self.CustomizeHUD:Remove()
|
||||
|
||||
gui.EnableScreenClicker(false)
|
||||
|
||||
self.CustomizeHUD = nil
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:DrawCustomizeHUD()
|
||||
|
||||
local customize = self:GetCustomize()
|
||||
|
||||
if customize and !self.CustomizeHUD then
|
||||
self:CreateCustomizeHUD()
|
||||
elseif !customize and self.CustomizeHUD then
|
||||
self:RemoveCustomizeHUD()
|
||||
end
|
||||
|
||||
lastcustomize = self:GetCustomize()
|
||||
end
|
82
lua/weapons/arc9_base/cl_drawvm.lua
Normal file
82
lua/weapons/arc9_base/cl_drawvm.lua
Normal file
@ -0,0 +1,82 @@
|
||||
function SWEP:PreDrawViewModel()
|
||||
self:DoRHIK()
|
||||
|
||||
if self:GetCustomize() then
|
||||
DrawBokehDOF( 10, 1, 0.1 )
|
||||
|
||||
cam.Start2D()
|
||||
surface.SetDrawColor(0, 0, 0, 150)
|
||||
surface.DrawRect(0, 0, ScrW(), ScrH())
|
||||
cam.End2D()
|
||||
end
|
||||
|
||||
self:DoBodygroups(false)
|
||||
self:GetVM():SetPoseParameter("sights", self:GetSightAmount())
|
||||
|
||||
if GetConVar("ARC9_benchgun"):GetBool() then
|
||||
cam.Start3D()
|
||||
end
|
||||
cam.IgnoreZ(true)
|
||||
end
|
||||
|
||||
function SWEP:PostDrawViewModel()
|
||||
cam.IgnoreZ(false)
|
||||
if GetConVar("ARC9_benchgun"):GetBool() then
|
||||
cam.End3D()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ViewModelDrawn()
|
||||
self:DrawCustomModel(false)
|
||||
-- self:DrawLasers()
|
||||
end
|
||||
|
||||
function SWEP:DrawCustomModel(wm)
|
||||
|
||||
if !wm and !IsValid(self:GetOwner()) then return end
|
||||
if !wm and self:GetOwner():IsNPC() then return end
|
||||
|
||||
local mdl = self.VModel
|
||||
|
||||
if wm then
|
||||
mdl = self.WModel
|
||||
end
|
||||
|
||||
if !mdl then
|
||||
self:SetupModel(wm)
|
||||
|
||||
mdl = self.VModel
|
||||
|
||||
if wm then
|
||||
mdl = self.WModel
|
||||
end
|
||||
end
|
||||
|
||||
for _, model in pairs(mdl) do
|
||||
local slottbl = model.slottbl
|
||||
-- local atttbl = model.atttbl
|
||||
|
||||
local apos, aang = self:GetAttPos(slottbl, wm)
|
||||
|
||||
model:SetPos(apos)
|
||||
model:SetAngles(aang)
|
||||
model:SetRenderOrigin(apos)
|
||||
model:SetRenderAngles(aang)
|
||||
|
||||
if !wm and model.atttbl.HoloSight then
|
||||
self:DoHolosight(model, model.atttbl)
|
||||
end
|
||||
|
||||
if !wm and model.atttbl.RTScope then
|
||||
self:DoRTScope(model, model.atttbl)
|
||||
end
|
||||
|
||||
if !model.NoDraw then
|
||||
model:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
if !wm then
|
||||
self:DrawFlashlightsVM()
|
||||
end
|
||||
end
|
90
lua/weapons/arc9_base/cl_holosight.lua
Normal file
90
lua/weapons/arc9_base/cl_holosight.lua
Normal file
@ -0,0 +1,90 @@
|
||||
function SWEP:DoHolosight(mdl, atttbl)
|
||||
if ARC9.OverDraw then return end
|
||||
if self:GetOwner() != LocalPlayer() then return end
|
||||
|
||||
local ref = 64
|
||||
|
||||
render.UpdateScreenEffectTexture()
|
||||
render.ClearStencil()
|
||||
render.SetStencilEnable(true)
|
||||
render.SetStencilCompareFunction(STENCIL_ALWAYS)
|
||||
render.SetStencilPassOperation(STENCIL_REPLACE)
|
||||
render.SetStencilFailOperation(STENCIL_KEEP)
|
||||
render.SetStencilZFailOperation(STENCIL_KEEP)
|
||||
render.SetStencilWriteMask(255)
|
||||
render.SetStencilTestMask(255)
|
||||
|
||||
render.SetBlend(0)
|
||||
|
||||
render.SetStencilReferenceValue(ref)
|
||||
|
||||
mdl:DrawModel()
|
||||
|
||||
render.SetBlend(1)
|
||||
|
||||
render.SetStencilPassOperation(STENCIL_KEEP)
|
||||
render.SetStencilCompareFunction(STENCIL_EQUAL)
|
||||
|
||||
-- cam.Start2D()
|
||||
|
||||
-- surface.SetDrawColor(255, 255, 255)
|
||||
-- surface.DrawRect(0, 0, ScrW(), ScrH())
|
||||
|
||||
-- render.SetColorMaterial()
|
||||
-- render.DrawScreenQuad()
|
||||
|
||||
local img = atttbl.HoloSightReticle
|
||||
|
||||
if img then
|
||||
local pos = self:GetOwner():EyePos()
|
||||
|
||||
pos = pos + mdl:GetAngles():Forward() * 9000
|
||||
|
||||
-- cam.Start3D()
|
||||
|
||||
local s = atttbl.HoloSightSize
|
||||
|
||||
render.SetMaterial(img)
|
||||
|
||||
local up = mdl:GetAngles():Up()
|
||||
local right = mdl:GetAngles():Right()
|
||||
|
||||
local v1 = pos + (up * s / 2) - (right * s / 2)
|
||||
local v2 = pos + (up * s / 2) + (right * s / 2)
|
||||
local v3 = pos - (up * s / 2) + (right * s / 2)
|
||||
local v4 = pos - (up * s / 2) - (right * s / 2)
|
||||
|
||||
-- render.DrawQuadEasy(pos, -mdl:GetAngles():Forward(), s, s, atttbl.HoloSightColor or Color(255, 255, 255))
|
||||
render.DrawQuad(v1, v2, v3, v4, atttbl.HoloSightColor or Color(255, 255, 255))
|
||||
|
||||
-- cam.End3D()
|
||||
|
||||
-- local toscreen = pos:ToScreen()
|
||||
|
||||
-- local x = toscreen.x
|
||||
-- local y = toscreen.y
|
||||
|
||||
-- local ss = ScreenScale(32)
|
||||
-- local sx = x - (ss / 2)
|
||||
-- local sy = y - (ss / 2)
|
||||
|
||||
-- local shakey = math.min(cross * 35, 3)
|
||||
|
||||
-- sx = sx + math.Round(math.Rand(-shakey, shakey))
|
||||
-- sy = sy + math.Round(math.Rand(-shakey, shakey))
|
||||
|
||||
-- surface.SetMaterial(img)
|
||||
-- surface.SetDrawColor(255, 255, 255, 255)
|
||||
-- surface.DrawTexturedRect(sx, sy, ss, ss)
|
||||
|
||||
-- surface.SetDrawColor(0, 0, 0)
|
||||
-- surface.DrawRect(0, 0, w, sy)
|
||||
-- surface.DrawRect(0, sy + ss, w, h - sy)
|
||||
|
||||
-- surface.DrawRect(0, 0, sx, h)
|
||||
-- surface.DrawRect(sx + ss, 0, w - sx, h)
|
||||
end
|
||||
-- cam.End2D()
|
||||
|
||||
render.SetStencilEnable(false)
|
||||
end
|
42
lua/weapons/arc9_base/cl_hud.lua
Normal file
42
lua/weapons/arc9_base/cl_hud.lua
Normal file
@ -0,0 +1,42 @@
|
||||
function SWEP:ShouldDrawCrosshair()
|
||||
-- return false
|
||||
end
|
||||
|
||||
function SWEP:DoDrawCrosshair(x, y)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:GetBinding(bind)
|
||||
local t_bind = input.LookupBinding(bind)
|
||||
|
||||
if !t_bind then
|
||||
t_bind = "BIND " .. bind .. "!"
|
||||
end
|
||||
|
||||
return string.upper(t_bind)
|
||||
end
|
||||
|
||||
function SWEP:DrawHUD()
|
||||
self:DrawCustomizeHUD()
|
||||
end
|
||||
|
||||
SWEP.Mat_Select = nil
|
||||
|
||||
function SWEP:DrawWeaponSelection(x, y, w, h, a)
|
||||
-- if !self.Mat_Select then
|
||||
-- self.Mat_Select = Material("entities/" .. self:GetClass() .. ".png")
|
||||
-- end
|
||||
|
||||
-- surface.SetDrawColor(255, 255, 255, 255)
|
||||
-- surface.SetMaterial(self.Mat_Select)
|
||||
|
||||
-- if w > h then
|
||||
-- y = y - ((w - h) / 2)
|
||||
-- end
|
||||
|
||||
-- surface.DrawTexturedRect(x, y, w, w)
|
||||
end
|
||||
|
||||
function SWEP:RangeUnitize(range)
|
||||
return tostring(math.Round(range)) .. " HU"
|
||||
end
|
144
lua/weapons/arc9_base/cl_light.lua
Normal file
144
lua/weapons/arc9_base/cl_light.lua
Normal file
@ -0,0 +1,144 @@
|
||||
SWEP.Flashlights = {} -- tracks projectedlights
|
||||
-- {{att = int, light = ProjectedTexture}}
|
||||
|
||||
function SWEP:GetHasFlashlights()
|
||||
for i, k in pairs(self:GetAttachmentList()) do
|
||||
local atttbl = ARC9.GetAttTable(k)
|
||||
|
||||
if atttbl.Flashlight then return true end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:CreateFlashlightsVM()
|
||||
self:KillFlashlights()
|
||||
self.Flashlights = {}
|
||||
|
||||
local total_lights = 0
|
||||
|
||||
for _, k in pairs(self:GetSubSlotList()) do
|
||||
if !k.Installed then continue end
|
||||
local atttbl = ARC9.GetAttTable(k.Installed)
|
||||
|
||||
if atttbl.Flashlight then
|
||||
local newlight = {
|
||||
slottbl = k,
|
||||
light = ProjectedTexture(),
|
||||
col = Color(255, 255, 255),
|
||||
br = 3,
|
||||
}
|
||||
total_lights = total_lights + 1
|
||||
|
||||
local l = newlight.light
|
||||
if !IsValid(l) then continue end
|
||||
|
||||
table.insert(self.Flashlights, newlight)
|
||||
|
||||
l:SetFOV(atttbl.FlashlightFOV or 50)
|
||||
|
||||
|
||||
l:SetFarZ(atttbl.FlashlightDistance or 1024)
|
||||
l:SetNearZ(4)
|
||||
|
||||
l:SetQuadraticAttenuation(100)
|
||||
|
||||
l:SetColor(atttbl.FlashlightColor or Color(255, 255, 255))
|
||||
l:SetTexture(atttbl.FlashlightMaterial or "effects/flashlight001")
|
||||
l:SetBrightness(3)
|
||||
l:SetEnableShadows(true)
|
||||
l:Update()
|
||||
|
||||
local g_light = {
|
||||
Weapon = self,
|
||||
ProjectedTexture = l
|
||||
}
|
||||
|
||||
table.insert(ARC9.FlashlightPile, g_light)
|
||||
end
|
||||
end
|
||||
|
||||
if total_lights > 2 then -- you are a madman
|
||||
for i, k in pairs(self.Flashlights) do
|
||||
if k.light:IsValid() then k.light:SetEnableShadows(false) end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:KillFlashlights()
|
||||
self:KillFlashlightsVM()
|
||||
-- self:KillFlashlightsWM()
|
||||
end
|
||||
|
||||
function SWEP:KillFlashlightsVM()
|
||||
if !self.Flashlights then return end
|
||||
|
||||
for i, k in pairs(self.Flashlights) do
|
||||
if k.light and k.light:IsValid() then
|
||||
k.light:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
self.Flashlights = nil
|
||||
end
|
||||
|
||||
function SWEP:DrawFlashlightsVM()
|
||||
if !self.Flashlights then
|
||||
self:CreateFlashlightsVM()
|
||||
end
|
||||
|
||||
for i, k in pairs(self.Flashlights) do
|
||||
local model = (k.slottbl or {}).VModel
|
||||
|
||||
if !model then continue end
|
||||
|
||||
local pos, ang
|
||||
|
||||
if !model then
|
||||
pos = self:GetOwner():EyePos()
|
||||
ang = self:GetOwner():EyeAngles()
|
||||
else
|
||||
pos = model:GetPos()
|
||||
ang = model:GetAngles()
|
||||
end
|
||||
|
||||
local tr = util.TraceLine({
|
||||
start = self:GetOwner():EyePos(),
|
||||
endpos = self:GetOwner():EyePos() - -ang:Forward() * 128,
|
||||
mask = MASK_OPAQUE,
|
||||
filter = LocalPlayer(),
|
||||
})
|
||||
if tr.Fraction < 1 then -- We need to push the flashlight back
|
||||
local tr2 = util.TraceLine({
|
||||
start = self:GetOwner():EyePos(),
|
||||
endpos = self:GetOwner():EyePos() + -ang:Forward() * 128,
|
||||
mask = MASK_OPAQUE,
|
||||
filter = LocalPlayer(),
|
||||
})
|
||||
-- push it as back as the area behind us allows
|
||||
pos = pos + -ang:Forward() * 128 * math.min(1 - tr.Fraction, tr2.Fraction)
|
||||
end
|
||||
|
||||
-- ang:RotateAroundAxis(ang:Up(), 90)
|
||||
|
||||
k.light:SetPos(pos)
|
||||
k.light:SetAngles(ang)
|
||||
k.light:Update()
|
||||
|
||||
-- local col = k.col
|
||||
|
||||
-- local dl = DynamicLight(self:EntIndex())
|
||||
|
||||
-- if dl then
|
||||
-- dl.pos = pos
|
||||
-- dl.r = col.r
|
||||
-- dl.g = col.g
|
||||
-- dl.b = col.b
|
||||
-- dl.brightness = k.br or 2
|
||||
-- -- print(z / maxz)
|
||||
-- dl.Decay = 1000 / 0.1
|
||||
-- dl.dietime = CurTime() + 0.1
|
||||
-- dl.size = (k.br or 2) * 64
|
||||
-- end
|
||||
end
|
||||
end
|
196
lua/weapons/arc9_base/cl_model.lua
Normal file
196
lua/weapons/arc9_base/cl_model.lua
Normal file
@ -0,0 +1,196 @@
|
||||
function SWEP:GetAttPos(slottbl, wm, idle)
|
||||
idle = idle or false
|
||||
local parentmdl = self:GetVM()
|
||||
|
||||
if wm then
|
||||
if slottbl.WMBase then
|
||||
parentmdl = self:GetOwner()
|
||||
else
|
||||
parentmdl = self.WModel[1]
|
||||
end
|
||||
end
|
||||
|
||||
if idle then
|
||||
parentmdl = ClientsideModel(self.ViewModel)
|
||||
parentmdl:SetPos(Vector(0, 0, 0))
|
||||
parentmdl:SetAngles(Angle(0, 0, 0))
|
||||
parentmdl:SetNoDraw(true)
|
||||
|
||||
local anim = self:TranslateSequence("idle")
|
||||
local seq = parentmdl:LookupSequence(anim)
|
||||
|
||||
parentmdl:ResetSequence(seq)
|
||||
parentmdl:SetPoseParameter("sights", 1)
|
||||
|
||||
parentmdl:SetupBones()
|
||||
end
|
||||
|
||||
local bone = slottbl.Bone
|
||||
local atttbl = {}
|
||||
|
||||
if slottbl.WMBase then
|
||||
bone = "ValveBiped.Bip01_R_Hand"
|
||||
end
|
||||
|
||||
if slottbl.Installed then
|
||||
atttbl = ARC9.GetAttTable(slottbl.Installed)
|
||||
end
|
||||
|
||||
local offset_pos = slottbl.Pos or Vector(0, 0, 0)
|
||||
local offset_ang = slottbl.Ang or Angle(0, 0, 0)
|
||||
|
||||
local boneindex = parentmdl:LookupBone(bone)
|
||||
|
||||
if !boneindex then return Vector(0, 0, 0), Angle(0, 0, 0) end
|
||||
|
||||
local bonemat = parentmdl:GetBoneMatrix(boneindex)
|
||||
if bonemat then
|
||||
bpos = bonemat:GetTranslation()
|
||||
bang = bonemat:GetAngles()
|
||||
end
|
||||
|
||||
local apos, aang
|
||||
|
||||
apos = bpos + bang:Forward() * offset_pos.x
|
||||
apos = apos + bang:Right() * offset_pos.y
|
||||
apos = apos + bang:Up() * offset_pos.z
|
||||
|
||||
aang = Angle()
|
||||
aang:Set(bang)
|
||||
|
||||
aang:RotateAroundAxis(aang:Right(), offset_ang.p)
|
||||
aang:RotateAroundAxis(aang:Up(), offset_ang.y)
|
||||
aang:RotateAroundAxis(aang:Forward(), offset_ang.r)
|
||||
|
||||
local moffset = (atttbl.ModelOffset or Vector(0, 0, 0)) * (slottbl.Scale or 1)
|
||||
|
||||
apos = apos + aang:Forward() * moffset.x
|
||||
apos = apos + aang:Right() * moffset.y
|
||||
apos = apos + aang:Up() * moffset.z
|
||||
|
||||
if idle then
|
||||
SafeRemoveEntity(parentmdl)
|
||||
end
|
||||
|
||||
return apos, aang
|
||||
end
|
||||
|
||||
function SWEP:CreateAttachmentModel(wm, atttbl, slottbl)
|
||||
local model = atttbl.Model
|
||||
|
||||
if wm and atttbl.WorldModel then
|
||||
model = atttbl.WorldModel
|
||||
end
|
||||
|
||||
local csmodel = ClientsideModel(model)
|
||||
|
||||
if !IsValid(csmodel) then return end
|
||||
|
||||
csmodel:SetNoDraw(true)
|
||||
csmodel.atttbl = atttbl
|
||||
csmodel.slottbl = slottbl
|
||||
|
||||
local scale = Matrix()
|
||||
local vec = Vector(1, 1, 1) * (atttbl.Scale or 1)
|
||||
vec = vec * (slottbl.Scale or 1)
|
||||
scale:Scale(vec)
|
||||
csmodel:EnableMatrix("RenderMultiply", scale)
|
||||
|
||||
local tbl = {
|
||||
Model = csmodel,
|
||||
Weapon = self
|
||||
}
|
||||
|
||||
table.insert(ARC9.CSModelPile, tbl)
|
||||
|
||||
if wm then
|
||||
table.insert(self.WModel, csmodel)
|
||||
else
|
||||
table.insert(self.VModel, csmodel)
|
||||
end
|
||||
|
||||
return csmodel
|
||||
end
|
||||
|
||||
function SWEP:SetupModel(wm)
|
||||
self:KillModel()
|
||||
|
||||
if !wm and !IsValid(self:GetOwner()) then return end
|
||||
|
||||
if !wm then
|
||||
self.VModel = {}
|
||||
else
|
||||
self.WModel = {}
|
||||
|
||||
local csmodel = ClientsideModel(self.MirrorModel or self.ViewModel)
|
||||
|
||||
if !IsValid(csmodel) then return end
|
||||
|
||||
csmodel:SetNoDraw(true)
|
||||
csmodel.atttbl = {}
|
||||
csmodel.slottbl = {
|
||||
WMBase = true,
|
||||
Pos = self.WorldModelOffset.Pos,
|
||||
Ang = self.WorldModelOffset.Ang
|
||||
}
|
||||
|
||||
local scale = Matrix()
|
||||
local vec = Vector(1, 1, 1) * (self.WorldModelOffset.Scale or 1)
|
||||
scale:Scale(vec)
|
||||
csmodel:EnableMatrix("RenderMultiply", scale)
|
||||
|
||||
local tbl = {
|
||||
Model = csmodel,
|
||||
Weapon = self
|
||||
}
|
||||
|
||||
table.insert(ARC9.CSModelPile, tbl)
|
||||
|
||||
table.insert(self.WModel, 1, csmodel)
|
||||
end
|
||||
|
||||
self:DoBodygroups(wm)
|
||||
|
||||
if !wm and self:GetOwner() != LocalPlayer() then return end
|
||||
|
||||
for _, slottbl in pairs(self:GetSubSlotList()) do
|
||||
if !slottbl.Installed then continue end
|
||||
|
||||
local atttbl = ARC9.GetAttTable(slottbl.Installed)
|
||||
|
||||
if !atttbl.Model then continue end
|
||||
|
||||
local csmodel = self:CreateAttachmentModel(wm, atttbl, slottbl)
|
||||
|
||||
if atttbl.MuzzleDevice then
|
||||
local slmodel = self:CreateAttachmentModel(wm, atttbl, slottbl)
|
||||
slmodel.IsMuzzleDevice = true
|
||||
slmodel.NoDraw = true
|
||||
end
|
||||
|
||||
if wm then
|
||||
slottbl.WModel = csmodel
|
||||
else
|
||||
slottbl.VModel = csmodel
|
||||
end
|
||||
end
|
||||
|
||||
if !wm then
|
||||
self:CreateFlashlightsVM()
|
||||
end
|
||||
end
|
||||
|
||||
SWEP.VModel = nil
|
||||
SWEP.WModel = nil
|
||||
|
||||
function SWEP:KillModel()
|
||||
for _, model in pairs(self.VModel or {}) do
|
||||
SafeRemoveEntity(model)
|
||||
end
|
||||
for _, model in pairs(self.WModel or {}) do
|
||||
SafeRemoveEntity(model)
|
||||
end
|
||||
|
||||
self.VModel = nil
|
||||
self.WModel = nil
|
||||
end
|
109
lua/weapons/arc9_base/cl_pipscope.lua
Normal file
109
lua/weapons/arc9_base/cl_pipscope.lua
Normal file
@ -0,0 +1,109 @@
|
||||
local rtmat = GetRenderTarget("ARC9_pipscope", 512, 512, false)
|
||||
|
||||
local rtsize = 512
|
||||
|
||||
function SWEP:DoRT(fov)
|
||||
if ARC9.OverDraw then return end
|
||||
|
||||
local rt = {
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = rtsize,
|
||||
h = rtsize,
|
||||
angles = self:GetOwner():EyeAngles(),
|
||||
origin = self:GetOwner():GetShootPos(),
|
||||
drawviewmodel = false,
|
||||
fov = fov,
|
||||
}
|
||||
|
||||
render.PushRenderTarget(rtmat, 0, 0, rtsize, rtsize)
|
||||
|
||||
ARC9.OverDraw = true
|
||||
render.RenderView(rt)
|
||||
ARC9.OverDraw = false
|
||||
|
||||
render.PopRenderTarget()
|
||||
end
|
||||
|
||||
local rtsurf = Material("effects/ARC9_rt")
|
||||
local shadow = Material("ARC9/shadow.png", "smooth")
|
||||
|
||||
function SWEP:DoRTScope(model, atttbl)
|
||||
local pos = model:GetPos()
|
||||
local ang = model:GetAngles()
|
||||
|
||||
pos = pos + ang:Forward() * 12000
|
||||
|
||||
local screenpos = pos:ToScreen()
|
||||
|
||||
local sh_x = (screenpos.x - (ScrW() / 2)) + (rtsize / 2)
|
||||
local sh_y = (screenpos.y - (ScrH() / 2)) + (rtsize / 2)
|
||||
|
||||
local sh_s = math.floor(rtsize * 1)
|
||||
|
||||
sh_x = sh_x - (sh_s / 2)
|
||||
sh_y = sh_y - (sh_s / 2)
|
||||
|
||||
render.PushRenderTarget(rtmat)
|
||||
|
||||
cam.Start2D()
|
||||
|
||||
surface.SetDrawColor(255, 255, 255)
|
||||
surface.SetMaterial(atttbl.RTScopeReticle)
|
||||
surface.DrawTexturedRect(0, 0, rtsize, rtsize)
|
||||
|
||||
surface.SetDrawColor(0, 0, 0)
|
||||
surface.SetMaterial(shadow)
|
||||
surface.DrawTexturedRect(sh_x, sh_y, sh_s, sh_s)
|
||||
|
||||
if !screenpos.visible then
|
||||
surface.DrawRect(0, 0, rtsize, rtsize)
|
||||
else
|
||||
surface.DrawRect(sh_x - rtsize, sh_y - rtsize, rtsize * 4, rtsize)
|
||||
surface.DrawRect(sh_x - rtsize, sh_y - rtsize, rtsize, rtsize * 4)
|
||||
surface.DrawRect(sh_x + sh_s, sh_y - rtsize, rtsize, rtsize * 4)
|
||||
surface.DrawRect(sh_x - rtsize, sh_y + sh_s, rtsize * 4, rtsize)
|
||||
end
|
||||
|
||||
surface.SetDrawColor(0, 0, 0, 255 * (1 - self:GetSightAmount()))
|
||||
surface.DrawRect(0, 0, rtsize, rtsize)
|
||||
|
||||
cam.End2D()
|
||||
|
||||
render.PopRenderTarget()
|
||||
|
||||
rtsurf:SetTexture("$basetexture", rtmat)
|
||||
|
||||
model:SetSubMaterial()
|
||||
|
||||
model:SetSubMaterial(atttbl.RTScopeSubmatIndex, "effects/ARC9_rt")
|
||||
end
|
||||
|
||||
function SWEP:DoCheapScope(fov)
|
||||
local scrw = ScrW()
|
||||
local scrh = ScrH()
|
||||
|
||||
scrw = scrw
|
||||
scrh = scrh * 9 / 16
|
||||
|
||||
local s = (self:GetOwner():GetFOV() / self:GetMagnification() / fov) * 1.40
|
||||
|
||||
local scrx = (ScrW() - scrw * s) / 2
|
||||
local scry = (ScrH() - scrh * s) / 2
|
||||
|
||||
scrx = scrx + 8
|
||||
scry = scry + 8
|
||||
|
||||
ARC9:DrawPhysBullets()
|
||||
|
||||
render.UpdateScreenEffectTexture()
|
||||
local screen = render.GetScreenEffectTexture()
|
||||
render.PushRenderTarget(rtmat, 0, 0, rtsize, rtsize)
|
||||
|
||||
-- cam.Start2D()
|
||||
render.DrawTextureToScreenRect(screen, scrx, scry, scrw * s, scrh * s)
|
||||
-- render.DrawTextureToScreenRect(ITexture tex, number x, number y, number width, number height)
|
||||
-- cam.End2D()
|
||||
|
||||
render.PopRenderTarget()
|
||||
end
|
47
lua/weapons/arc9_base/cl_rhik.lua
Normal file
47
lua/weapons/arc9_base/cl_rhik.lua
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
|
||||
function SWEP:DoRHIK()
|
||||
local vm = self:GetOwner():GetViewModel()
|
||||
|
||||
local delta = self:Curve(self.CustomizeDelta)
|
||||
|
||||
for _, bone in ipairs(ARC9.LHIKBones) do
|
||||
local vmbone = vm:LookupBone(bone)
|
||||
|
||||
if !vmbone then continue end -- Happens when spectating someone prolly
|
||||
|
||||
local vmtransform = vm:GetBoneMatrix(vmbone)
|
||||
|
||||
if !vmtransform then continue end -- something very bad has happened
|
||||
|
||||
local vm_pos = vmtransform:GetTranslation()
|
||||
local vm_ang = vmtransform:GetAngles()
|
||||
|
||||
local newtransform = Matrix()
|
||||
|
||||
newtransform:SetTranslation(LerpVector(delta, vm_pos, vm_pos - (EyeAngles():Up() * 128) - (EyeAngles():Forward() * 128)))
|
||||
newtransform:SetAngles(vm_ang)
|
||||
|
||||
vm:SetBoneMatrix(vmbone, newtransform)
|
||||
end
|
||||
|
||||
for _, bone in ipairs(ARC9.RHIKBones) do
|
||||
local vmbone = vm:LookupBone(bone)
|
||||
|
||||
if !vmbone then continue end -- Happens when spectating someone prolly
|
||||
|
||||
local vmtransform = vm:GetBoneMatrix(vmbone)
|
||||
|
||||
if !vmtransform then continue end -- something very bad has happened
|
||||
|
||||
local vm_pos = vmtransform:GetTranslation()
|
||||
local vm_ang = vmtransform:GetAngles()
|
||||
|
||||
local newtransform = Matrix()
|
||||
|
||||
newtransform:SetTranslation(LerpVector(delta, vm_pos, vm_pos - (EyeAngles():Up() * 128) - (EyeAngles():Forward() * 128)))
|
||||
newtransform:SetAngles(vm_ang)
|
||||
|
||||
vm:SetBoneMatrix(vmbone, newtransform)
|
||||
end
|
||||
end
|
150
lua/weapons/arc9_base/cl_sway.lua
Normal file
150
lua/weapons/arc9_base/cl_sway.lua
Normal file
@ -0,0 +1,150 @@
|
||||
SWEP.ViewModelVelocityPos = Vector(0, 0, 0)
|
||||
SWEP.ViewModelVelocityAng = Angle(0, 0, 0)
|
||||
|
||||
SWEP.ViewModelPos = Vector(0, 0, 0)
|
||||
SWEP.ViewModelAng = Angle(0, 0, 0)
|
||||
|
||||
SWEP.SwayCT = 0
|
||||
|
||||
function SWEP:GetViewModelSway(pos, ang)
|
||||
-- local d = Lerp(self:GetSightAmount(), 1, 0.02)
|
||||
-- local v = 1
|
||||
-- local steprate = 1
|
||||
|
||||
-- d = d * 0.25
|
||||
|
||||
-- pos = pos + (ang:Up() * (math.sin(self.SwayCT * 0.311 * v) + math.cos(self.SwayCT * 0.44 * v)) * math.sin(CurTime() * 0.8) * d)
|
||||
-- pos = pos + (ang:Right() * (math.sin(self.SwayCT * 0.324 * v) + math.cos(self.SwayCT * 0.214 * v)) * math.sin(CurTime() * 0.76) * d)
|
||||
|
||||
-- if IsFirstTimePredicted() then
|
||||
-- self.SwayCT = self.SwayCT + (FrameTime() * steprate)
|
||||
-- end
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
SWEP.ViewModelLastEyeAng = Angle(0, 0, 0)
|
||||
SWEP.ViewModelSwayInertia = Angle(0, 0, 0)
|
||||
|
||||
function SWEP:GetViewModelInertia(pos, ang)
|
||||
local d = 1 - self:GetSightAmount()
|
||||
|
||||
local diff = self:GetOwner():EyeAngles() - self.ViewModelLastEyeAng
|
||||
|
||||
diff = diff / 4
|
||||
|
||||
diff.p = math.Clamp(diff.p, -1, 1)
|
||||
diff.y = math.Clamp(diff.y, -1, 1)
|
||||
|
||||
local vsi = self.ViewModelSwayInertia
|
||||
|
||||
vsi.p = math.ApproachAngle(vsi.p, diff.p, vsi.p / 10 * FrameTime() / 0.5)
|
||||
vsi.y = math.ApproachAngle(vsi.y, diff.y, vsi.y / 10 * FrameTime() / 0.5)
|
||||
|
||||
self.ViewModelLastEyeAng = self:GetOwner():EyeAngles()
|
||||
|
||||
ang:RotateAroundAxis(ang:Up(), vsi.y * 12 * d)
|
||||
ang:RotateAroundAxis(ang:Right(), -vsi.p * 12 * d)
|
||||
|
||||
-- pos = pos - (ang:Up() * vsi.p * 0.5 * d)
|
||||
-- pos = pos - (ang:Right() * vsi.y * 0.5 * d)
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function SWEP:GetViewModelSmooth(pos, ang)
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
SWEP.ViewModelBobVelocity = 0
|
||||
SWEP.ViewModelNotOnGround = 0
|
||||
|
||||
SWEP.BobCT = 0
|
||||
|
||||
function SWEP:GetViewModelBob(pos, ang)
|
||||
local step = 10
|
||||
local mag = 1
|
||||
|
||||
local v = self:GetOwner():GetVelocity():Length()
|
||||
v = math.Clamp(v, 0, 350)
|
||||
self.ViewModelBobVelocity = math.Approach(self.ViewModelBobVelocity, v, FrameTime() * 10000)
|
||||
local d = math.Clamp(self.ViewModelBobVelocity / 350, 0, 1)
|
||||
|
||||
if self:GetOwner():OnGround() then
|
||||
self.ViewModelNotOnGround = math.Approach(self.ViewModelNotOnGround, 0, FrameTime() / 1)
|
||||
else
|
||||
self.ViewModelNotOnGround = math.Approach(self.ViewModelNotOnGround, 1, FrameTime() / 1)
|
||||
end
|
||||
|
||||
d = d * Lerp(self:GetSightAmount(), 1, 0.1)
|
||||
mag = d * 2
|
||||
step = 10
|
||||
|
||||
ang:RotateAroundAxis(ang:Forward(), math.sin(self.BobCT * step * 0.5) * ((math.sin(CurTime() * 6.151) * 0.2) + 1) * 4.5 * d)
|
||||
ang:RotateAroundAxis(ang:Right(), math.sin(self.BobCT * step * 0.12) * ((math.sin(CurTime() * 1.521) * 0.2) + 1) * 2.11 * d)
|
||||
pos = pos - (ang:Up() * math.sin(self.BobCT * step) * 0.07 * ((math.sin(CurTime() * 3.515) * 0.2) + 1) * mag)
|
||||
pos = pos + (ang:Forward() * math.sin(self.BobCT * step * 0.3) * 0.11 * ((math.sin(CurTime() * 1.615) * 0.2) + 1) * mag)
|
||||
pos = pos + (ang:Right() * (math.sin(self.BobCT * step * 0.15) + (math.cos(self.BobCT * step * 0.3332))) * 0.16 * mag)
|
||||
|
||||
local steprate = Lerp(d, 1, 2.5)
|
||||
|
||||
steprate = Lerp(self.ViewModelNotOnGround, steprate, 0.25)
|
||||
|
||||
if IsFirstTimePredicted() or game.SinglePlayer() then
|
||||
self.BobCT = self.BobCT + (FrameTime() * steprate)
|
||||
end
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
SWEP.LastViewModelVerticalVelocity = 0
|
||||
-- SWEP.ViewModelLanded = 0
|
||||
-- SWEP.ViewModelLanding = 0
|
||||
|
||||
function SWEP:GetMidAirBob(pos, ang)
|
||||
local v = -self:GetOwner():GetVelocity().z / 200
|
||||
|
||||
v = math.Clamp(v, -1, 1)
|
||||
|
||||
-- if v == 0 and self.LastViewModelVerticalVelocity != 0 then
|
||||
-- self.ViewModelLanding = self.LastViewModelVerticalVelocity
|
||||
-- self.ViewModelLanded = 1
|
||||
-- end
|
||||
|
||||
-- if self.ViewModelLanded > 0 then
|
||||
-- self.ViewModelLanded = math.Approach(self.ViewModelLanded, 0, FrameTime() / 0.25)
|
||||
|
||||
v = Lerp(5 * FrameTime(), self.LastViewModelVerticalVelocity, v)
|
||||
-- end
|
||||
|
||||
self.LastViewModelVerticalVelocity = v
|
||||
|
||||
local d = self.ViewModelNotOnGround
|
||||
|
||||
d = d * Lerp(self:GetSightAmount(), 1, 0.1)
|
||||
|
||||
ang:RotateAroundAxis(ang:Right(), -v * d * 8 * math.sin(CurTime() * 0.15))
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
SWEP.ViewModelInertiaX = 0
|
||||
SWEP.ViewModelInertiaY = 0
|
||||
|
||||
function SWEP:GetViewModelLeftRight(pos, ang)
|
||||
local v = self:GetOwner():GetVelocity()
|
||||
local d = Lerp(self:GetSightDelta(), 1, 0)
|
||||
|
||||
v, _ = WorldToLocal(v, Angle(0, 0, 0), Vector(0, 0, 0), self:GetOwner():EyeAngles())
|
||||
|
||||
local vx = math.Clamp(v.x / 200, -1, 1)
|
||||
local vy = math.Clamp(v.y / 200, -1, 1)
|
||||
|
||||
self.ViewModelInertiaX = math.Approach(self.ViewModelInertiaX, vx, math.abs(vx) * FrameTime() / 0.1)
|
||||
self.ViewModelInertiaY = math.Approach(self.ViewModelInertiaY, vy, math.abs(vy) * FrameTime() / 0.1)
|
||||
|
||||
pos = pos + (ang:Right() * -self.ViewModelInertiaX * 0.65 * d)
|
||||
pos = pos + (ang:Forward() * self.ViewModelInertiaY * 0.5 * d)
|
||||
|
||||
return pos, ang
|
||||
end
|
152
lua/weapons/arc9_base/cl_vm.lua
Normal file
152
lua/weapons/arc9_base/cl_vm.lua
Normal file
@ -0,0 +1,152 @@
|
||||
SWEP.CustomizeDelta = 0
|
||||
|
||||
SWEP.ViewModelPos = Vector(0, 0, 0)
|
||||
SWEP.ViewModelAng = Angle(0, 0, 0)
|
||||
|
||||
function SWEP:GetViewModelPosition(pos, ang)
|
||||
if GetConVar("ARC9_benchgun"):GetBool() then
|
||||
return Vector(0, 0, 0), Angle(0, 0, 0)
|
||||
end
|
||||
|
||||
-- pos = Vector(0, 0, 0)
|
||||
-- ang = Angle(0, 0, 0)
|
||||
|
||||
local oldang = Angle(0, 0, 0)
|
||||
|
||||
local up, forward, right = oldang:Up(), oldang:Forward(), oldang:Right()
|
||||
|
||||
oldang:Set(ang)
|
||||
|
||||
local cor_val = 0.75
|
||||
|
||||
local offsetpos = Vector(0, 0, 0)
|
||||
local offsetang = Angle(0, 0, 0)
|
||||
|
||||
local extra_offsetpos = Vector(0, 0, 0)
|
||||
local extra_offsetang = Angle(0, 0, 0)
|
||||
|
||||
-- print(extra_offsetang)
|
||||
|
||||
offsetpos:Set(self:GetProcessedValue("ActivePos"))
|
||||
offsetang:Set(self:GetProcessedValue("ActiveAng"))
|
||||
|
||||
local sightdelta = self:Curve(self:GetSightDelta())
|
||||
|
||||
-- cor_val = Lerp(sightdelta, cor_val, 1)
|
||||
|
||||
if sightdelta > 0 then
|
||||
local sightpos, sightang = self:GetSightPositions()
|
||||
|
||||
-- local sightpos = self.SightPos
|
||||
-- local sightang = self.SightAng
|
||||
|
||||
offsetpos = LerpVector(sightdelta, offsetpos, sightpos)
|
||||
offsetang = LerpAngle(sightdelta, offsetang, sightang)
|
||||
end
|
||||
|
||||
local eepos, eeang = self:GetExtraSightPositions()
|
||||
-- local eepos, eeang = Vector(0, 0, 0), Angle(0, 0, 0)
|
||||
|
||||
local im = self:GetProcessedValue("SightMidPoint")
|
||||
|
||||
local midpoint = sightdelta * math.cos(sightdelta * (math.pi / 2))
|
||||
local joffset = (im and im.Pos or Vector(0, 0, 0)) * midpoint
|
||||
local jaffset = (im and im.Ang or Angle(0, 0, 0)) * midpoint
|
||||
|
||||
extra_offsetpos = LerpVector(sightdelta, extra_offsetpos, -eepos + joffset)
|
||||
extra_offsetang = LerpAngle(sightdelta, extra_offsetang, -eeang + jaffset)
|
||||
|
||||
extra_offsetang.y = extra_offsetang.y - (self:GetFreeSwayAngles().p * cor_val)
|
||||
extra_offsetang.p = extra_offsetang.p + (self:GetFreeSwayAngles().y * cor_val)
|
||||
|
||||
extra_offsetang.y = extra_offsetang.y - (self:GetFreeAimOffset().p * cor_val)
|
||||
extra_offsetang.p = extra_offsetang.p + (self:GetFreeAimOffset().y * cor_val)
|
||||
|
||||
if game.SinglePlayer() or IsFirstTimePredicted() then
|
||||
if self:GetCustomize() then
|
||||
self.CustomizeDelta = math.Approach(self.CustomizeDelta, 1, FrameTime() * 1 / 0.15)
|
||||
else
|
||||
self.CustomizeDelta = math.Approach(self.CustomizeDelta, 0, FrameTime() * 1 / 0.15)
|
||||
end
|
||||
end
|
||||
|
||||
local curvedcustomizedelta = self:Curve(self.CustomizeDelta)
|
||||
|
||||
-- local sprintdelta = self:Curve(self:GetSprintDelta())
|
||||
local sprintdelta = self:Curve(self:GetSprintDelta())
|
||||
|
||||
if sprintdelta > 0 then
|
||||
offsetpos = LerpVector(sprintdelta, offsetpos, self:GetProcessedValue("SprintPos") or self:GetProcessedValue("HolsterPos"))
|
||||
offsetang = LerpAngle(sprintdelta, offsetang, self:GetProcessedValue("SprintAng") or self:GetProcessedValue("HolsterAng"))
|
||||
|
||||
extra_offsetang = LerpAngle(sprintdelta, extra_offsetang, Angle(0, 0, 0))
|
||||
end
|
||||
|
||||
local sim = self:GetProcessedValue("SprintMidPoint")
|
||||
|
||||
local spr_midpoint = sprintdelta * math.cos(sprintdelta * (math.pi / 2))
|
||||
local spr_joffset = (sim and sim.Pos or Vector(0, 0, 0)) * spr_midpoint
|
||||
local spr_jaffset = (sim and sim.Ang or Angle(0, 0, 0)) * spr_midpoint
|
||||
|
||||
extra_offsetpos = extra_offsetpos + spr_joffset
|
||||
extra_offsetang = extra_offsetang + spr_jaffset
|
||||
|
||||
self.BobScale = 0
|
||||
self.SwayScale = Lerp(sightdelta, 1, 0.1)
|
||||
|
||||
if curvedcustomizedelta > 0 then
|
||||
offsetpos = LerpVector(curvedcustomizedelta, offsetpos, self:GetProcessedValue("CustomizePos"))
|
||||
offsetang = LerpAngle(curvedcustomizedelta, offsetang, self:GetProcessedValue("CustomizeAng"))
|
||||
|
||||
extra_offsetpos = LerpVector(curvedcustomizedelta, extra_offsetpos, Vector(0, 0, 0))
|
||||
extra_offsetang = LerpAngle(curvedcustomizedelta, extra_offsetang, Angle(0, 0, 0))
|
||||
|
||||
extra_offsetang.p = self.MenuRotation.p
|
||||
extra_offsetang.y = self.MenuRotation.y
|
||||
|
||||
-- extra_offsetpos = extra_offsetpos + (Vector(-24, 0, 0) * (math.cos(math.rad(self.MenuRotation.p)) - 1) / -2)
|
||||
-- extra_offsetpos = extra_offsetpos + (Vector(0, 0, -24) * (math.cos(math.rad(self.MenuRotation.r)) - 1) / -2)
|
||||
extra_offsetpos = extra_offsetpos + Vector(0.5, 0, 0) * self.MenuPan.x
|
||||
extra_offsetpos = extra_offsetpos + Vector(0, 0, -0.5) * self.MenuPan.y
|
||||
extra_offsetpos = extra_offsetpos + Vector(0, -1.5, 0) * self.MenuPan.z
|
||||
|
||||
extra_offsetpos = LerpVector(1 - curvedcustomizedelta, extra_offsetpos, Vector(0, 0, 0))
|
||||
end
|
||||
|
||||
if game.SinglePlayer() or IsFirstTimePredicted() then
|
||||
self.ViewModelPos = LerpVector(0.8, offsetpos, self.ViewModelPos)
|
||||
self.ViewModelAng = LerpAngle(0.8, offsetang, self.ViewModelAng)
|
||||
end
|
||||
|
||||
offsetpos = self.ViewModelPos
|
||||
offsetang = self.ViewModelAng
|
||||
self.ViewModelAng:Normalize()
|
||||
|
||||
pos = pos + (ang:Right() * offsetpos.x)
|
||||
pos = pos + (ang:Forward() * offsetpos.y)
|
||||
pos = pos + (ang:Up() * offsetpos.z)
|
||||
|
||||
ang:RotateAroundAxis(oldang:Up(), offsetang.p)
|
||||
ang:RotateAroundAxis(oldang:Right(), offsetang.y)
|
||||
ang:RotateAroundAxis(oldang:Forward(), offsetang.r)
|
||||
|
||||
pos = pos + (oldang:Right() * extra_offsetpos[1])
|
||||
pos = pos + (oldang:Forward() * extra_offsetpos[2])
|
||||
pos = pos + (oldang:Up() * extra_offsetpos[3])
|
||||
|
||||
ang:RotateAroundAxis(oldang:Up(), extra_offsetang[1])
|
||||
ang:RotateAroundAxis(oldang:Right(), extra_offsetang[2])
|
||||
ang:RotateAroundAxis(oldang:Forward(), extra_offsetang[3])
|
||||
|
||||
pos, ang = self:GetViewModelBob(pos, ang)
|
||||
pos, ang = self:GetMidAirBob(pos, ang)
|
||||
-- pos, ang = self:GetViewModelLeftRight(pos, ang)
|
||||
pos, ang = self:GetViewModelInertia(pos, ang)
|
||||
pos, ang = self:GetViewModelSway(pos, ang)
|
||||
pos, ang = self:GetViewModelSmooth(pos, ang)
|
||||
|
||||
self.LastViewModelPos = pos
|
||||
self.LastViewModelAng = ang
|
||||
|
||||
return pos, ang
|
||||
end
|
3
lua/weapons/arc9_base/cl_wm.lua
Normal file
3
lua/weapons/arc9_base/cl_wm.lua
Normal file
@ -0,0 +1,3 @@
|
||||
function SWEP:DrawWorldModel()
|
||||
self:DrawCustomModel(true)
|
||||
end
|
72
lua/weapons/arc9_base/sh_anim.lua
Normal file
72
lua/weapons/arc9_base/sh_anim.lua
Normal file
@ -0,0 +1,72 @@
|
||||
function SWEP:PlayAnimation(anim, mult, lock, doidle)
|
||||
mult = mult or 1
|
||||
lock = lock or false
|
||||
anim = self:TranslateAnimation(anim)
|
||||
doidle = doidle or true
|
||||
|
||||
mult = self:RunHook("Hook_TranslateAnimSpeed", {mult = mult, anim = anim}).Mult or mult
|
||||
|
||||
if !self:HasAnimation(anim) then return end
|
||||
|
||||
local vm = self:GetVM()
|
||||
|
||||
if !IsValid(vm) then return end
|
||||
|
||||
local animation = self:GetAnimationEntry(anim)
|
||||
|
||||
local source = self:RandomChoice(animation.Source)
|
||||
|
||||
if animation.RareSource then
|
||||
if util.SharedRandom("ARC9_raresource", 0, 1) <= (animation.RareSourceChance or 0.01) then
|
||||
source = self:RandomChoice(animation.RareSource)
|
||||
end
|
||||
end
|
||||
|
||||
local seq = vm:LookupSequence(source)
|
||||
|
||||
if seq == 0 then return end
|
||||
|
||||
local time = animation.Time or vm:SequenceDuration(seq)
|
||||
|
||||
mult = mult * (animation.Mult or 1)
|
||||
|
||||
time = time * mult
|
||||
|
||||
vm:SendViewModelMatchingSequence(seq)
|
||||
vm:SetPlaybackRate(1 / mult)
|
||||
|
||||
if animation.EventTable then
|
||||
self:PlaySoundTable(animation.EventTable, 1 / mult)
|
||||
end
|
||||
|
||||
if lock then
|
||||
self:SetAnimLockTime(CurTime() + time)
|
||||
else
|
||||
self:SetAnimLockTime(CurTime())
|
||||
end
|
||||
|
||||
if doidle then
|
||||
self:SetNextIdle(CurTime() + time)
|
||||
else
|
||||
self:SetNextIdle(math.huge)
|
||||
end
|
||||
|
||||
return time
|
||||
end
|
||||
|
||||
function SWEP:IdleAtEndOfAnimation()
|
||||
local vm = self:GetVM()
|
||||
local cyc = vm:GetCycle()
|
||||
local duration = vm:SequenceDuration()
|
||||
local rate = vm:GetPlaybackRate()
|
||||
|
||||
local time = (1 - cyc) * (duration / rate)
|
||||
|
||||
self:SetNextIdle(CurTime() + time)
|
||||
end
|
||||
|
||||
function SWEP:Idle()
|
||||
if self:GetPrimedAttack() then return end
|
||||
|
||||
self:PlayAnimation("idle")
|
||||
end
|
52
lua/weapons/arc9_base/sh_animtranslate.lua
Normal file
52
lua/weapons/arc9_base/sh_animtranslate.lua
Normal file
@ -0,0 +1,52 @@
|
||||
function SWEP:TranslateAnimation(seq)
|
||||
seq = self:RunHook("Hook_TranslateAnimation", seq) or seq
|
||||
|
||||
if self:GetSightAmount() > 0 and self:HasAnimation(seq .. "_iron") then
|
||||
seq = seq .. "_iron"
|
||||
end
|
||||
|
||||
if (self:Clip1() == 0 or self:GetEmptyReload()) and self:HasAnimation(seq .. "_empty") then
|
||||
seq = seq .. "_empty"
|
||||
end
|
||||
|
||||
if istable(seq) then
|
||||
seq["BaseClass"] = nil
|
||||
seq = seq[math.Round(util.SharedRandom("ARC9_animtr", 1, #seq))]
|
||||
end
|
||||
|
||||
return seq
|
||||
end
|
||||
|
||||
function SWEP:HasAnimation(seq)
|
||||
-- seq = self:TranslateSequence(seq)
|
||||
if self.Animations[seq] then
|
||||
return true
|
||||
end
|
||||
|
||||
local vm = self:GetVM()
|
||||
seq = vm:LookupSequence(seq)
|
||||
|
||||
return seq != -1
|
||||
end
|
||||
|
||||
function SWEP:GetSequenceTime(seq)
|
||||
local vm = self:GetVM()
|
||||
seq = vm:LookupSequence(seq)
|
||||
|
||||
return vm:SequenceDuration(seq)
|
||||
end
|
||||
|
||||
function SWEP:GetAnimationEntry(seq)
|
||||
if self:HasAnimation(seq) then
|
||||
if self.Animations[seq] then
|
||||
return self.Animations[seq]
|
||||
else
|
||||
return {
|
||||
Source = seq,
|
||||
Time = self:GetSequenceTime(seq)
|
||||
}
|
||||
end
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
196
lua/weapons/arc9_base/sh_attach.lua
Normal file
196
lua/weapons/arc9_base/sh_attach.lua
Normal file
@ -0,0 +1,196 @@
|
||||
function SWEP:Attach(addr, att, silent)
|
||||
if !self:CanAttach(addr, att) then return false end
|
||||
|
||||
local slottbl = self:LocateSlotFromAddress(addr)
|
||||
|
||||
slottbl.Installed = att
|
||||
slottbl.ToggleNum = 1
|
||||
|
||||
self:PostModify()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Detach(addr, silent)
|
||||
if !self:CanDetach(addr) then return false end
|
||||
|
||||
local slottbl = self:LocateSlotFromAddress(addr)
|
||||
|
||||
slottbl.Installed = nil
|
||||
|
||||
self:PostModify()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:PostModify()
|
||||
self:InvalidateCache()
|
||||
|
||||
if CLIENT then
|
||||
self:SendWeapon()
|
||||
self:SetupModel(true)
|
||||
self:SetupModel(false)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ToggleCustomize(on)
|
||||
if on == self:GetCustomize() then return end
|
||||
|
||||
self:SetCustomize(on)
|
||||
|
||||
self:SetShouldHoldType()
|
||||
|
||||
if !self:GetCustomize() then
|
||||
self:Inspect(true)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetAttBlocked(atttbl)
|
||||
local eles = self:GetElements()
|
||||
|
||||
if atttbl.ExcludeElements then
|
||||
for _, group in ipairs(atttbl.ExcludeElements) do
|
||||
if !istable(group) then
|
||||
group = {group}
|
||||
end
|
||||
|
||||
local ok = false
|
||||
for _, ele in ipairs(group) do
|
||||
if !eles[ele] then ok = true break end
|
||||
end
|
||||
|
||||
if !ok then return true end
|
||||
end
|
||||
end
|
||||
|
||||
if atttbl.RequireElements then
|
||||
for _, group in ipairs(atttbl.ExcludeElements) do
|
||||
if !istable(group) then
|
||||
group = {group}
|
||||
end
|
||||
|
||||
local ok = true
|
||||
for _, ele in ipairs(group) do
|
||||
if !eles[ele] then ok = false break end
|
||||
end
|
||||
|
||||
if ok then return true end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:GetSlotBlocked(slottbl)
|
||||
local eles = self:GetElements()
|
||||
|
||||
if slottbl.ExcludeElements then
|
||||
for _, group in ipairs(slottbl.ExcludeElements) do
|
||||
if !istable(group) then
|
||||
group = {group}
|
||||
end
|
||||
|
||||
local ok = false
|
||||
for _, ele in ipairs(group) do
|
||||
if !eles[ele] then ok = true break end
|
||||
end
|
||||
|
||||
if !ok then return true end
|
||||
end
|
||||
end
|
||||
|
||||
local totalcount = self:CountAttachments()
|
||||
|
||||
if totalcount >= ARC9.GetMaxAtts() then return true end
|
||||
|
||||
if slottbl.RequireElements then
|
||||
for _, group in ipairs(slottbl.RequireElements) do
|
||||
if !istable(group) then
|
||||
group = {group}
|
||||
end
|
||||
|
||||
local ok = true
|
||||
for _, ele in ipairs(group) do
|
||||
if !eles[ele] then ok = false break end
|
||||
end
|
||||
|
||||
if ok then return true end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:CanAttach(addr, att, slottbl)
|
||||
slottbl = slottbl or self:LocateSlotFromAddress(addr)
|
||||
|
||||
if self:RunHook("Hook_BlockAttachment", {att = att, slottbl = slottbl}) == false then return false end
|
||||
|
||||
if self:GetSlotBlocked(slottbl) then return false end
|
||||
|
||||
local cat = slottbl.Category
|
||||
|
||||
if !istable(cat) then
|
||||
cat = {cat}
|
||||
end
|
||||
|
||||
local atttbl = ARC9.GetAttTable(att)
|
||||
|
||||
if atttbl.Max then
|
||||
local count = self:CountAttachments(att)
|
||||
|
||||
if slottbl.Installed then
|
||||
local installed_atttbl = ARC9.GetAttTable(slottbl.Installed)
|
||||
|
||||
if slottbl.Installed == installed_atttbl.InvAtt then
|
||||
count = count - 1
|
||||
end
|
||||
end
|
||||
|
||||
if count >= atttbl.Max then return false end
|
||||
end
|
||||
|
||||
if self:GetAttBlocked(atttbl) then return false end
|
||||
|
||||
local attcat = atttbl.Category
|
||||
|
||||
if !istable(attcat) then
|
||||
attcat = {attcat}
|
||||
end
|
||||
|
||||
for _, c in pairs(attcat) do
|
||||
if table.HasValue(cat, c) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:CanDetach(addr)
|
||||
local slottbl = self:LocateSlotFromAddress(addr)
|
||||
|
||||
if slottbl and slottbl.Integral then return false end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:CountAttachments(countatt)
|
||||
local qty = 0
|
||||
|
||||
for _, att in ipairs(self:GetAttachmentList()) do
|
||||
if !countatt then
|
||||
qty = qty + 1
|
||||
else
|
||||
if countatt == att then
|
||||
qty = qty + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return qty
|
||||
end
|
52
lua/weapons/arc9_base/sh_bodygroups.lua
Normal file
52
lua/weapons/arc9_base/sh_bodygroups.lua
Normal file
@ -0,0 +1,52 @@
|
||||
function SWEP:DoBodygroups(wm)
|
||||
if !wm and !IsValid(self:GetOwner()) then return end
|
||||
if !wm and self:GetOwner():IsNPC() then return end
|
||||
|
||||
local dbg = self:GetValue("DefaultBodygroups")
|
||||
|
||||
local mdl
|
||||
|
||||
if wm then
|
||||
mdl = self:GetWM()
|
||||
else
|
||||
mdl = self:GetVM()
|
||||
end
|
||||
|
||||
if !IsValid(mdl) then return end
|
||||
|
||||
mdl:SetBodyGroups(dbg or "")
|
||||
|
||||
local eles = self:GetElements()
|
||||
|
||||
for i, k in pairs(eles) do
|
||||
local ele = self.AttachmentElements[i]
|
||||
|
||||
if !ele then continue end
|
||||
|
||||
for _, j in pairs(ele.Bodygroups or {}) do
|
||||
mdl:SetBodygroup(j[1], j[2])
|
||||
end
|
||||
end
|
||||
|
||||
local bbg = self:GetValue("BulletBodygroups")
|
||||
|
||||
if bbg then
|
||||
local amt = self:Clip1()
|
||||
|
||||
if self:GetReloading() then
|
||||
amt = self:GetLoadedRounds()
|
||||
end
|
||||
|
||||
for c, bgs in pairs(bbg) do
|
||||
if !isnumber(c) then continue end
|
||||
if amt < c then
|
||||
mdl:SetBodygroup(bgs[1], bgs[2])
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetElements()
|
||||
return {}
|
||||
end
|
2
lua/weapons/arc9_base/sh_bonemods.lua
Normal file
2
lua/weapons/arc9_base/sh_bonemods.lua
Normal file
@ -0,0 +1,2 @@
|
||||
function SWEP:DoBoneMods()
|
||||
end
|
84
lua/weapons/arc9_base/sh_effects.lua
Normal file
84
lua/weapons/arc9_base/sh_effects.lua
Normal file
@ -0,0 +1,84 @@
|
||||
function SWEP:DoEffects()
|
||||
if !IsFirstTimePredicted() then return end
|
||||
local muzz_qca = self:GetQCAMuzzle()
|
||||
|
||||
local data = EffectData()
|
||||
data:SetEntity(self)
|
||||
data:SetAttachment(muzz_qca)
|
||||
|
||||
util.Effect( "ARC9_muzzleeffect", data )
|
||||
end
|
||||
|
||||
function SWEP:GetQCAMuzzle()
|
||||
return self:GetProcessedValue("MuzzleEffectQCA")
|
||||
end
|
||||
|
||||
function SWEP:GetQCAEject()
|
||||
return self:GetProcessedValue("CaseEffectQCA")
|
||||
end
|
||||
|
||||
SWEP.EjectedShells = {}
|
||||
|
||||
function SWEP:DoEject()
|
||||
if !IsFirstTimePredicted() then return end
|
||||
|
||||
local eject_qca = self:GetQCAEject()
|
||||
|
||||
local data = EffectData()
|
||||
data:SetEntity(self)
|
||||
data:SetAttachment(eject_qca)
|
||||
|
||||
util.Effect("ARC9_shelleffect", data)
|
||||
end
|
||||
|
||||
function SWEP:GetTracerOrigin()
|
||||
local ow = self:GetOwner()
|
||||
local wm = !ow:GetViewModel():IsValid() or ow:ShouldDrawLocalPlayer()
|
||||
local att = self:GetQCAMuzzle()
|
||||
local muzz = self
|
||||
|
||||
if !wm then
|
||||
muzz = ow:GetViewModel()
|
||||
end
|
||||
|
||||
if muzz and muzz:IsValid() then
|
||||
local posang = muzz:GetAttachment(att)
|
||||
if !posang then return muzz:GetPos() end
|
||||
local pos = posang.Pos
|
||||
|
||||
return pos
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetMuzzleDevice(wm)
|
||||
local model = self.VModel
|
||||
local muzz = self:GetVM()
|
||||
|
||||
if wm then
|
||||
model = self.WModel
|
||||
muzz = self:GetWM()
|
||||
end
|
||||
|
||||
-- if model then
|
||||
-- for i, k in pairs(model) do
|
||||
-- if k.IsMuzzleDevice then
|
||||
-- return k
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
|
||||
return muzz
|
||||
end
|
||||
|
||||
function SWEP:DrawEjectedShells()
|
||||
local newshells = {}
|
||||
|
||||
for i, k in pairs(self.EjectedShells) do
|
||||
if !k:IsValid() then continue end
|
||||
|
||||
k:DrawModel()
|
||||
table.insert(newshells, k)
|
||||
end
|
||||
|
||||
self.EjectedShells = newshells
|
||||
end
|
41
lua/weapons/arc9_base/sh_elements.lua
Normal file
41
lua/weapons/arc9_base/sh_elements.lua
Normal file
@ -0,0 +1,41 @@
|
||||
SWEP.ElementsCache = {}
|
||||
|
||||
function SWEP:GetElements()
|
||||
if self.ElementsCache then return self.ElementsCache end
|
||||
|
||||
local eles = {}
|
||||
|
||||
for _, slottbl in pairs(self:GetSubSlotList()) do
|
||||
if slottbl.Installed then
|
||||
table.Add(eles, slottbl.InstalledElements or {})
|
||||
local atttbl = ARC9.GetAttTable(slottbl.Installed)
|
||||
table.Add(eles, atttbl.ActivateElements or {})
|
||||
local cat = atttbl.Category
|
||||
if !istable(cat) then
|
||||
cat = {cat}
|
||||
end
|
||||
table.Add(eles, cat)
|
||||
table.insert(eles, slottbl.Installed)
|
||||
else
|
||||
table.Add(eles, slottbl.UnInstalledElements or {})
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(eles, self.DefaultElements or {})
|
||||
|
||||
if !ARC9.Overrun then
|
||||
ARC9.Overrun = true
|
||||
table.insert(eles, self:GetCurrentFiremodeTable().ActivateElements or {})
|
||||
ARC9.Overrun = false
|
||||
end
|
||||
|
||||
local eles2 = {}
|
||||
|
||||
for _, ele in ipairs(eles) do
|
||||
eles2[ele] = true
|
||||
end
|
||||
|
||||
self.ElementsCache = eles2
|
||||
|
||||
return eles2
|
||||
end
|
53
lua/weapons/arc9_base/sh_firemodes.lua
Normal file
53
lua/weapons/arc9_base/sh_firemodes.lua
Normal file
@ -0,0 +1,53 @@
|
||||
function SWEP:SwitchFiremode()
|
||||
if #self:GetValue("Firemodes") == 0 then return end
|
||||
|
||||
local fm = self:GetFiremode()
|
||||
|
||||
self:PlayAnimation("firemode" .. tostring(fm))
|
||||
|
||||
fm = fm + 1
|
||||
|
||||
if fm > #self:GetValue("Firemodes") then
|
||||
fm = 1
|
||||
end
|
||||
|
||||
self:EmitSound(self:RandomChoice(self:GetProcessedValue("FiremodeSound")), 75, 100, 1, CHAN_ITEM)
|
||||
|
||||
self:SetFiremode(fm)
|
||||
|
||||
self:InvalidateCache()
|
||||
end
|
||||
|
||||
function SWEP:GetCurrentFiremode()
|
||||
mode = self:GetValue("Firemodes")[self:GetFiremode()].Mode
|
||||
|
||||
mode = self:RunHook("Hook_TranslateMode") or mode
|
||||
|
||||
return mode
|
||||
end
|
||||
|
||||
function SWEP:GetCurrentFiremodeTable()
|
||||
local fm = self:GetFiremode()
|
||||
|
||||
if fm > #self:GetValue("Firemodes") then
|
||||
fm = 1
|
||||
end
|
||||
|
||||
return self:GetValue("Firemodes")[fm]
|
||||
end
|
||||
|
||||
function SWEP:ToggleSafety(onoff)
|
||||
onoff = onoff or !self:GetSafe()
|
||||
|
||||
self:SetSafe(onoff)
|
||||
end
|
||||
|
||||
function SWEP:ThinkFiremodes()
|
||||
if self:GetOwner():KeyPressed(IN_ATTACK2) and self:GetOwner():KeyDown(IN_USE) then
|
||||
self:ToggleSafety()
|
||||
end
|
||||
|
||||
if self:GetOwner():KeyPressed(IN_RELOAD) and self:GetOwner():KeyDown(IN_USE) then
|
||||
self:SwitchFiremode()
|
||||
end
|
||||
end
|
58
lua/weapons/arc9_base/sh_freeaim.lua
Normal file
58
lua/weapons/arc9_base/sh_freeaim.lua
Normal file
@ -0,0 +1,58 @@
|
||||
SWEP.ClientFreeAimAng = Angle(0, 0, 0)
|
||||
|
||||
function SWEP:ThinkFreeAim()
|
||||
local diff = self:GetOwner():EyeAngles() - self:GetLastAimAngle()
|
||||
|
||||
local freeaimang = Angle(self:GetFreeAimAngle())
|
||||
|
||||
local max = self:GetProcessedValue("FreeAimRadius")
|
||||
|
||||
diff.p = math.NormalizeAngle(diff.p)
|
||||
diff.y = math.NormalizeAngle(diff.y)
|
||||
|
||||
freeaimang.p = math.Clamp(math.NormalizeAngle(freeaimang.p) + math.NormalizeAngle(diff.p), -max, max)
|
||||
freeaimang.y = math.Clamp(math.NormalizeAngle(freeaimang.y) + math.NormalizeAngle(diff.y), -max, max)
|
||||
|
||||
local ang2d = math.atan2(freeaimang.p, freeaimang.y)
|
||||
local mag2d = math.sqrt(math.pow(freeaimang.p, 2) + math.pow(freeaimang.y, 2))
|
||||
|
||||
mag2d = math.min(mag2d, max)
|
||||
|
||||
freeaimang.p = mag2d * math.sin(ang2d)
|
||||
freeaimang.y = mag2d * math.cos(ang2d)
|
||||
|
||||
self:SetFreeAimAngle(freeaimang)
|
||||
|
||||
if CLIENT then
|
||||
self.ClientFreeAimAng = freeaimang
|
||||
end
|
||||
|
||||
self:SetLastAimAngle(self:GetOwner():EyeAngles())
|
||||
end
|
||||
|
||||
function SWEP:GetFreeAimOffset()
|
||||
if !GetConVar("arc9_freeaim"):GetBool() then return Angle(0, 0, 0) end
|
||||
if CLIENT then
|
||||
return self.ClientFreeAimAng
|
||||
else
|
||||
return self:GetFreeAimAngle()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetFreeSwayAmount()
|
||||
local sway = self:GetProcessedValue("Sway")
|
||||
|
||||
return sway
|
||||
end
|
||||
|
||||
function SWEP:GetFreeSwayAngles()
|
||||
if !GetConVar("arc9_freeaim"):GetBool() then return Angle(0, 0, 0) end
|
||||
local swayamt = self:GetFreeSwayAmount()
|
||||
local swayspeed = 1
|
||||
|
||||
local ang = Angle(math.sin(CurTime() * 0.6 * swayspeed) + (math.cos(CurTime() * 2) * 0.5), math.sin(CurTime() * 0.4 * swayspeed) + (math.cos(CurTime() * 1.6) * 0.5), 0)
|
||||
|
||||
ang = ang * swayamt
|
||||
|
||||
return ang
|
||||
end
|
179
lua/weapons/arc9_base/sh_init.lua
Normal file
179
lua/weapons/arc9_base/sh_init.lua
Normal file
@ -0,0 +1,179 @@
|
||||
function SWEP:DoDeployAnimation()
|
||||
if !self:GetReady() and self:HasAnimation("ready") then
|
||||
self:PlayAnimation("ready", self:GetProcessedValue("DeployTime", 1), true, true)
|
||||
self:SetReady(true)
|
||||
else
|
||||
self:PlayAnimation("draw", self:GetProcessedValue("DeployTime", 1), true, true)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
if self:GetOwner():IsNPC() then
|
||||
return
|
||||
end
|
||||
|
||||
self:InvalidateCache()
|
||||
|
||||
self:SetBaseSettings()
|
||||
|
||||
self:SetNextPrimaryFire(0)
|
||||
self:SetNextSecondaryFire(0)
|
||||
self:SetAnimLockTime(0)
|
||||
self:SetLastMeleeTime(0)
|
||||
self:SetRecoilAmount(0)
|
||||
self:SetPrimedAttack(false)
|
||||
self:SetReloading(false)
|
||||
|
||||
self:SetBlindFire(false)
|
||||
self:SetBlindFireLeft(false)
|
||||
|
||||
self:SetFreeAimAngle(Angle(0, 0, 0))
|
||||
self:SetLastAimAngle(Angle(0, 0, 0))
|
||||
|
||||
self:DoDeployAnimation()
|
||||
|
||||
self:SetBurstCount(0)
|
||||
self:SetSightAmount(0)
|
||||
self:SetLoadedRounds(self:Clip1())
|
||||
self:SetCustomize(false)
|
||||
|
||||
self:SetTriggerDown(self:GetOwner():KeyDown(IN_ATTACK))
|
||||
|
||||
self:GetOwner():DoAnimationEvent(self:GetValue("AnimDraw"))
|
||||
|
||||
if SERVER then
|
||||
if !self.GaveDefaultAmmo then
|
||||
self:GiveDefaultAmmo()
|
||||
self.GaveDefaultAmmo = true
|
||||
end
|
||||
|
||||
-- self:NetworkWeapon()
|
||||
self:SetTimer(0.25, function()
|
||||
self:SendWeapon()
|
||||
end)
|
||||
end
|
||||
|
||||
self:SetShouldHoldType()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:GiveDefaultAmmo()
|
||||
self:SetClip1(self:GetValue("ClipSize"))
|
||||
self:GetOwner():GiveAmmo(self:GetValue("ClipSize") * 2, self:GetValue("Ammo"))
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
if self:GetOwner():IsNPC() then
|
||||
return
|
||||
end
|
||||
|
||||
self:KillTimers()
|
||||
self:GetOwner():SetFOV(0, 0.1)
|
||||
|
||||
if self:GetReloading() then
|
||||
self:SetReady(false)
|
||||
end
|
||||
|
||||
-- if CLIENT then
|
||||
-- self:RemoveCustomizeHUD()
|
||||
-- end
|
||||
|
||||
-- if CLIENT then
|
||||
-- RunConsoleCommand("pp_bokeh", "0")
|
||||
-- end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetShouldHoldType()
|
||||
|
||||
if self:GetOwner():IsNPC() then
|
||||
self:NPC_Initialize()
|
||||
return
|
||||
end
|
||||
|
||||
self:SetBaseSettings()
|
||||
|
||||
self:SetLastMeleeTime(0)
|
||||
self:SetNthShot(0)
|
||||
|
||||
self:BuildAttachmentAddresses()
|
||||
|
||||
self:InitTimers()
|
||||
|
||||
self:ClientInitialize()
|
||||
end
|
||||
|
||||
function SWEP:ClientInitialize()
|
||||
if game.SinglePlayer() then self:CallOnClient("ClientInitialize") end
|
||||
if SERVER then return end
|
||||
|
||||
self:BuildAttachmentAddresses()
|
||||
self:SetBaseSettings()
|
||||
|
||||
self:InitTimers()
|
||||
end
|
||||
|
||||
function SWEP:SetBaseSettings()
|
||||
if game.SinglePlayer() and SERVER then
|
||||
self:CallOnClient("SetBaseSettings")
|
||||
end
|
||||
|
||||
self.Primary.Automatic = true
|
||||
|
||||
self.Primary.ClipSize = self:GetValue("ClipSize")
|
||||
self.Primary.Ammo = self:GetValue("Ammo")
|
||||
|
||||
self.Primary.DefaultClip = self.Primary.ClipSize
|
||||
|
||||
if SERVER then
|
||||
if self:GetCapacity() > 0 and self:Clip1() > self:GetCapacity() then
|
||||
self:GetOwner():GiveAmmo(self:Clip1() - self:GetCapacity(), self:GetValue("Ammo"))
|
||||
self:SetClip1(self:GetCapacity())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SetShouldHoldType()
|
||||
if self:GetOwner():IsNPC() then
|
||||
self:SetHoldType(self:GetValue("HoldTypeNPC") or self:GetValue("HoldType"))
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetSightAmount() > 0 then
|
||||
if self:GetValue("HoldTypeSights") then
|
||||
self:SetHoldType(self:GetValue("HoldTypeSights"))
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetSafe() then
|
||||
if self:GetValue("HoldTypeHolstered") then
|
||||
self:SetHoldType(self:GetValue("HoldTypeHolstered"))
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetIsSprinting() or self:GetSafe() then
|
||||
if self:GetValue("HoldTypeSprint") then
|
||||
self:SetHoldType(self:GetValue("HoldTypeSprint"))
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetCustomize() then
|
||||
if self:GetValue("HoldTypeCustomize") then
|
||||
self:SetHoldType(self:GetValue("HoldTypeCustomize"))
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
self:SetHoldType(self:GetValue("HoldType"))
|
||||
end
|
5
lua/weapons/arc9_base/sh_inspect.lua
Normal file
5
lua/weapons/arc9_base/sh_inspect.lua
Normal file
@ -0,0 +1,5 @@
|
||||
function SWEP:Inspect(force)
|
||||
if !force and self:StillWaiting() then return end
|
||||
|
||||
self:PlayAnimation("inspect", 1, true)
|
||||
end
|
108
lua/weapons/arc9_base/sh_net.lua
Normal file
108
lua/weapons/arc9_base/sh_net.lua
Normal file
@ -0,0 +1,108 @@
|
||||
function SWEP:SendWeapon(rec)
|
||||
net.Start("ARC9_networkweapon")
|
||||
net.WriteEntity(self)
|
||||
|
||||
for i, k in pairs(self.Attachments or {}) do
|
||||
self:SendAttachmentTree(self.Attachments[i])
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
if rec then
|
||||
// send to just this one person
|
||||
net.Send(rec)
|
||||
else
|
||||
net.Broadcast()
|
||||
end
|
||||
else
|
||||
net.SendToServer()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SendAttachmentTree(tree)
|
||||
if tree and tree.Installed then
|
||||
local atttbl = ARC9.GetAttTable(tree.Installed)
|
||||
local id = atttbl.ID
|
||||
|
||||
net.WriteUInt(id, ARC9.Attachments_Bits)
|
||||
|
||||
tree.SubAttachments = tree.SubAttachments or {}
|
||||
|
||||
if atttbl.ToggleStats then
|
||||
net.WriteUInt((atttbl.ToggleNum or 1) - 1, 8)
|
||||
end
|
||||
|
||||
if atttbl.Attachments then
|
||||
for i, k in pairs(atttbl.Attachments) do
|
||||
self:SendAttachmentTree(tree.SubAttachments[i])
|
||||
end
|
||||
end
|
||||
else
|
||||
net.WriteUInt(0, ARC9.Attachments_Bits)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:CountAttsInTree(tree)
|
||||
local flattree = self:AttTreeToList(tree)
|
||||
|
||||
local count = {}
|
||||
|
||||
for _, i in ipairs(flattree) do
|
||||
if i.Installed then
|
||||
local att = i.Installed
|
||||
count[att] = (count[att] or 0) + 1
|
||||
end
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
function SWEP:ReceiveWeapon()
|
||||
local tbl = {}
|
||||
|
||||
for i, k in pairs(self.Attachments or {}) do
|
||||
tbl[i] = self:ReceiveAttachmentTree()
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
if !self:ValidateInventoryForNewTree(tbl) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
self:BuildSubAttachments(tbl)
|
||||
|
||||
if CLIENT then
|
||||
self:SetupModel(true)
|
||||
self:SetupModel(false)
|
||||
self:RefreshCustomizeMenu()
|
||||
else
|
||||
self:SendWeapon()
|
||||
self:InvalidateCache()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ReceiveAttachmentTree()
|
||||
local id = net.ReadUInt(ARC9.Attachments_Bits)
|
||||
local att = ARC9.Attachments_Index[id]
|
||||
|
||||
local tree = {
|
||||
Installed = att,
|
||||
SubAttachments = {}
|
||||
}
|
||||
|
||||
if !att then return tree end
|
||||
|
||||
local atttbl = ARC9.GetAttTable(att)
|
||||
|
||||
if atttbl.ToggleStats then
|
||||
tree.ToggleNum = net.ReadUInt(8) + 1
|
||||
end
|
||||
|
||||
if atttbl.Attachments then
|
||||
for i, k in pairs(atttbl.Attachments) do
|
||||
tree.SubAttachments[i] = self:ReceiveAttachmentTree()
|
||||
end
|
||||
end
|
||||
|
||||
return tree
|
||||
end
|
166
lua/weapons/arc9_base/sh_penetration.lua
Normal file
166
lua/weapons/arc9_base/sh_penetration.lua
Normal file
@ -0,0 +1,166 @@
|
||||
local function IsPenetrating(ptr, ptrent)
|
||||
if ptrent:IsWorld() then
|
||||
return !ptr.StartSolid or ptr.AllSolid
|
||||
elseif IsValid(ptrent) then
|
||||
local mins, maxs = ptrent:WorldSpaceAABB()
|
||||
local wsc = ptrent:WorldSpaceCenter()
|
||||
-- Expand the bounding box by a bit to account for hitboxes outside it
|
||||
-- This is more consistent but less accurate
|
||||
mins = mins + (mins - wsc) * 0.25
|
||||
maxs = maxs + (maxs - wsc) * 0.25
|
||||
local withinbounding = ptr.HitPos:WithinAABox(mins, maxs)
|
||||
if GetConVar("developer"):GetBool() then
|
||||
debugoverlay.Cross(ptr.HitPos, withinbounding and 2 or 6, 5, withinbounding and Color(255, 255, 0) or Color(128, 255, 0), true)
|
||||
end
|
||||
|
||||
if withinbounding then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:Penetrate(tr, range, penleft, alreadypenned)
|
||||
if !GetConVar("ARC9_penetration"):GetBool() then return end
|
||||
|
||||
local hitpos, startpos = tr.HitPos, tr.StartPos
|
||||
local dir = (hitpos - startpos):GetNormalized()
|
||||
|
||||
if tr.HitSky then return end
|
||||
|
||||
if penleft <= 0 then return end
|
||||
|
||||
alreadypenned = alreadypenned or {}
|
||||
|
||||
local skip = false
|
||||
|
||||
local trent = tr.Entity
|
||||
|
||||
local penmult = ARC9.PenTable[tr.MatType] or 1
|
||||
local pentracelen = math.max(penleft * penmult / 8, 1)
|
||||
local curr_ent = trent
|
||||
|
||||
if self:GetRicochetChance(tr) > math.random(0, 100) then
|
||||
local degree = tr.HitNormal:Dot((tr.StartPos - tr.HitPos):GetNormalized())
|
||||
if degree == 0 or degree == 1 then return end
|
||||
-- sound.Play(ArcCW.RicochetSounds[math.random(#ArcCW.RicochetSounds)], tr.HitPos)
|
||||
if (tr.Normal:Length() == 0) then return end
|
||||
-- ACT3_ShootPBullet(tr.HitPos, ((2 * degree * tr.HitNormal) + tr.Normal) * (vel * math.Rand(0.25, 0.75)), owner, inflictor, bulletid, false, 1, penleft, dist)
|
||||
-- return
|
||||
|
||||
dir = (2 * degree * tr.HitNormal) + tr.Normal
|
||||
ang = dir:Angle()
|
||||
ang = ang + (AngleRand() * (1 - degree) * 15 / 360)
|
||||
dir = ang:Forward()
|
||||
|
||||
local d = math.Rand(0.25, 0.95)
|
||||
|
||||
penleft = penleft * d
|
||||
|
||||
skip = true
|
||||
end
|
||||
|
||||
if !tr.HitWorld then penmult = penmult * 0.5 end
|
||||
|
||||
if trent.mmRHAe then penmult = trent.mmRHAe end
|
||||
|
||||
penmult = penmult * math.Rand(0.9, 1.1) * math.Rand(0.9, 1.1)
|
||||
|
||||
local endpos = hitpos
|
||||
|
||||
local td = {}
|
||||
td.start = endpos
|
||||
td.endpos = endpos + (dir * pentracelen)
|
||||
td.mask = MASK_SHOT
|
||||
|
||||
local ptr = util.TraceLine(td)
|
||||
|
||||
local ptrent = ptr.Entity
|
||||
|
||||
while !skip and penleft > 0 and IsPenetrating(ptr, ptrent) and ptr.Fraction < 1 and ptrent == curr_ent do
|
||||
penleft = penleft - (pentracelen * penmult)
|
||||
|
||||
td.start = endpos
|
||||
td.endpos = endpos + (dir * pentracelen)
|
||||
td.mask = MASK_SHOT
|
||||
|
||||
ptr = util.TraceLine(td)
|
||||
|
||||
if GetConVar("developer"):GetBool() then
|
||||
local pdeltap = penleft / self:GetValue("Penetration")
|
||||
local colorlr = Lerp(pdeltap, 0, 255)
|
||||
|
||||
debugoverlay.Line(endpos, endpos + (dir * pentracelen), 10, Color(255, colorlr, colorlr), true)
|
||||
end
|
||||
|
||||
endpos = endpos + (dir * pentracelen)
|
||||
range = range + pentracelen
|
||||
end
|
||||
|
||||
if penleft > 0 then
|
||||
if (dir:Length() == 0) then return end
|
||||
|
||||
if GetConVar("ARC9_bullet_physics"):GetBool() then
|
||||
ARC9:ShootPhysBullet(self, endpos, dir * self:GetProcessedValue("PhysBulletMuzzleVelocity"), {
|
||||
Penleft = penleft,
|
||||
Travelled = range,
|
||||
Damaged = alreadypenned
|
||||
})
|
||||
else
|
||||
self:GetOwner():FireBullets({
|
||||
Damage = self:GetValue("Damage_Max"),
|
||||
Force = 4,
|
||||
Tracer = 0,
|
||||
Num = 1,
|
||||
Dir = dir,
|
||||
Src = endpos,
|
||||
Callback = function(att, btr, dmg)
|
||||
range = range + (btr.HitPos - btr.StartPos):Length()
|
||||
self:AfterShotFunction(btr, dmg, range, penleft, alreadypenned)
|
||||
|
||||
if GetConVar("developer"):GetBool() then
|
||||
if SERVER then
|
||||
debugoverlay.Cross(btr.HitPos, 4, 5, Color(255, 0, 0), false)
|
||||
else
|
||||
debugoverlay.Cross(btr.HitPos, 4, 5, Color(255, 255, 255), false)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
self:GetOwner():FireBullets({
|
||||
Damage = 0,
|
||||
Force = 0,
|
||||
Tracer = 0,
|
||||
Num = 1,
|
||||
Distance = 8,
|
||||
Dir = -dir,
|
||||
Src = endpos,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetRicochetChance(tr)
|
||||
if !GetConVar("ARC9_ricochet"):GetBool() then return 0 end
|
||||
local degree = tr.HitNormal:Dot((tr.StartPos - tr.HitPos):GetNormalized())
|
||||
|
||||
degree = 90 - math.deg(math.acos(degree))
|
||||
|
||||
local ricmult = ARC9.PenTable[tr.MatType] or 1
|
||||
|
||||
-- 0 at 1
|
||||
-- 100 at 0
|
||||
|
||||
if degree > self:GetProcessedValue("RicochetAngleMax") then return 0 end
|
||||
|
||||
local c = self:GetProcessedValue("RicochetChance")
|
||||
|
||||
c = c * ricmult
|
||||
|
||||
-- c = c * GetConVar("arccw_ricochet_mult"):GetFloat()
|
||||
|
||||
-- c = 100
|
||||
|
||||
c = c * 100
|
||||
|
||||
return math.Clamp(c, 0, 100)
|
||||
end
|
91
lua/weapons/arc9_base/sh_recoil.lua
Normal file
91
lua/weapons/arc9_base/sh_recoil.lua
Normal file
@ -0,0 +1,91 @@
|
||||
function SWEP:ThinkRecoil()
|
||||
if (self:GetLastRecoilTime() + self:GetProcessedValue("RecoilResetTime")) < CurTime() then
|
||||
local rec = self:GetRecoilAmount()
|
||||
|
||||
rec = rec - (FrameTime() * self:GetProcessedValue("RecoilDissipationRate"))
|
||||
|
||||
self:SetRecoilAmount(math.max(rec, 0))
|
||||
end
|
||||
|
||||
self:SetRecoilUp(self:GetRecoilUp() - (FrameTime() * self:GetRecoilUp() * self:GetProcessedValue("RecoilDissipationRate")))
|
||||
|
||||
self:SetRecoilSide(self:GetRecoilSide() - (FrameTime() * self:GetRecoilSide() * self:GetProcessedValue("RecoilDissipationRate")))
|
||||
end
|
||||
|
||||
function SWEP:ApplyRecoil()
|
||||
local rec = self:GetRecoilAmount()
|
||||
|
||||
local rps = 1
|
||||
|
||||
rec = rec + rps
|
||||
|
||||
local delay = 60 / self:GetProcessedValue("RPM")
|
||||
|
||||
local recoilup = 1
|
||||
local recoilside = 0
|
||||
|
||||
local seed = self:GetProcessedValue("RecoilSeed") or self:GetClass()
|
||||
local shot = math.floor(self:GetRecoilAmount())
|
||||
|
||||
if isstring(seed) then
|
||||
local numseed = 0
|
||||
|
||||
for _, i in ipairs(string.ToTable(seed)) do
|
||||
numseed = numseed + string.byte(i)
|
||||
end
|
||||
|
||||
numseed = numseed % 16777216
|
||||
|
||||
seed = numseed
|
||||
end
|
||||
|
||||
seed = seed + shot
|
||||
|
||||
if self:GetProcessedValue("RecoilLookupTable") then
|
||||
local recoilpattern = self:PatternWithRunOff(self:GetProcessedValue("RecoilLookupTable"), self:GetProcessedValue("RecoilLookupTableOverrun") or self:GetProcessedValue("RecoilLookupTable"), shot)
|
||||
recoilup = recoilpattern.y or 1
|
||||
recoilside = recoilpattern.x or 0
|
||||
else
|
||||
math.randomseed(seed)
|
||||
recoilup = math.random(-1.5, 0.5)
|
||||
recoilside = math.random(-1.25, 0.75)
|
||||
|
||||
local randomrecoilup = util.SharedRandom("arc9_recoil_up_r", -1, 1)
|
||||
local randomrecoilside = util.SharedRandom("arc9_recoil_side_r", -1, 1)
|
||||
|
||||
recoilup = recoilup * self:GetProcessedValue("RecoilUp")
|
||||
recoilside = recoilside * self:GetProcessedValue("RecoilSide")
|
||||
|
||||
randomrecoilup = randomrecoilup * self:GetProcessedValue("RecoilRandomUp")
|
||||
randomrecoilside = randomrecoilside * self:GetProcessedValue("RecoilRandomSide")
|
||||
|
||||
recoilup = recoilup + randomrecoilup
|
||||
recoilside = recoilside + randomrecoilside
|
||||
|
||||
recoilup = recoilup * self:GetProcessedValue("Recoil")
|
||||
recoilside = recoilside * self:GetProcessedValue("Recoil")
|
||||
end
|
||||
|
||||
self:SetRecoilUp(recoilup)
|
||||
self:SetRecoilSide(recoilside)
|
||||
|
||||
-- self:SetRecoilDirection(-90)
|
||||
self:SetRecoilAmount(rec)
|
||||
|
||||
self:SetLastRecoilTime(CurTime() + (delay * 2))
|
||||
|
||||
-- local vis_kick = self:GetProcessedValue("RecoilKick")
|
||||
-- local vis_shake = 0
|
||||
|
||||
-- vis_kick = vis_kick * rps
|
||||
-- vis_shake = vis_kick * rps
|
||||
|
||||
-- local vis_kick_v = vis_kick * 0.5
|
||||
-- local vis_kick_h = vis_kick * util.SharedRandom("ARC9_vis_kick_h", -1, 1)
|
||||
-- vis_shake = vis_shake * util.SharedRandom("ARC9_vis_kick_shake", -1, 1)
|
||||
|
||||
-- self:GetOwner():SetViewPunchAngles(Angle(vis_kick_v, vis_kick_h, vis_shake))
|
||||
|
||||
-- self:GetOwner():SetFOV(self:GetOwner():GetFOV() * 0.99, 0)
|
||||
-- self:GetOwner():SetFOV(0, 60 / (self:GetProcessedValue("RPM")))
|
||||
end
|
170
lua/weapons/arc9_base/sh_reload.lua
Normal file
170
lua/weapons/arc9_base/sh_reload.lua
Normal file
@ -0,0 +1,170 @@
|
||||
function SWEP:Reload()
|
||||
if self:GetOwner():IsNPC() then
|
||||
self:NPC_Reload()
|
||||
return
|
||||
end
|
||||
|
||||
if !self:GetOwner():KeyPressed(IN_RELOAD) then
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetOwner():KeyDown(IN_USE) then
|
||||
-- firemode switch
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetOwner():KeyDown(IN_WALK) then
|
||||
self:Inspect()
|
||||
return
|
||||
end
|
||||
|
||||
if self:StillWaiting() then return end
|
||||
if self:GetCapacity() <= 0 then return end
|
||||
if self:Clip1() >= self:GetCapacity() then return end
|
||||
if self:Ammo1() <= 0 then return end
|
||||
|
||||
-- self:ScopeToggle(0)
|
||||
-- self:ToggleCustomize(false)
|
||||
|
||||
if self:Clip1() == 0 then
|
||||
self:SetEmptyReload(true)
|
||||
else
|
||||
self:SetEmptyReload(false)
|
||||
end
|
||||
|
||||
local anim = "reload"
|
||||
|
||||
if self:GetShouldShotgunReload() then
|
||||
anim = "reload_start"
|
||||
end
|
||||
|
||||
local t = self:PlayAnimation(anim, self:GetProcessedValue("ReloadTime"), true, true)
|
||||
|
||||
self:GetOwner():DoAnimationEvent(self:GetProcessedValue("AnimReload"))
|
||||
|
||||
if !self:GetShouldShotgunReload() then
|
||||
local minprogress = self:GetAnimationEntry(anim).MinProgress or 1
|
||||
|
||||
self:SetTimer(t * minprogress, function()
|
||||
self:SetLoadedRounds(math.min(self:GetValue("ClipSize"), self:Clip1() + self:Ammo1()))
|
||||
end)
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
self:DropMagazine()
|
||||
end
|
||||
|
||||
self:SetLoadedRounds(self:Clip1())
|
||||
|
||||
self:SetReloading(true)
|
||||
self:SetEndReload(false)
|
||||
|
||||
-- self:SetTimer(t * 0.9, function()
|
||||
-- if !IsValid(self) then return end
|
||||
|
||||
-- self:SetEndReload(false)
|
||||
-- self:EndReload()
|
||||
-- end)
|
||||
|
||||
self:SetReloadFinishTime(CurTime() + (t * 0.95))
|
||||
end
|
||||
|
||||
function SWEP:DropMagazine()
|
||||
-- if !IsFirstTimePredicted() and !game.SinglePlayer() then return end
|
||||
if self:GetProcessedValue("DropMagazineModel") then
|
||||
for i = 1, self:GetProcessedValue("DropMagazineAmount") do
|
||||
local mag = ents.Create("ARC9_droppedmag")
|
||||
|
||||
if mag then
|
||||
mag:SetPos(self:GetOwner():EyePos() - (self:GetOwner():EyeAngles():Up() * 8))
|
||||
mag:SetAngles(self:GetOwner():EyeAngles())
|
||||
mag.Model = self:GetProcessedValue("DropMagazineModel")
|
||||
mag.ImpactType = self:GetProcessedValue("DropMagazineImpact")
|
||||
mag:SetOwner(self:GetOwner())
|
||||
mag:Spawn()
|
||||
|
||||
local phys = mag:GetPhysicsObject()
|
||||
|
||||
if IsValid(phys) then
|
||||
phys:AddAngleVelocity(Vector(math.Rand(-300, 300), math.Rand(-300, 300), math.Rand(-300, 300)))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetCapacity()
|
||||
return self:GetValue("ClipSize") + self:GetValue("ChamberSize")
|
||||
end
|
||||
|
||||
function SWEP:RestoreClip(amt)
|
||||
local reserve = self:Clip1() + self:Ammo1()
|
||||
|
||||
local lastclip1 = self:Clip1()
|
||||
|
||||
self:SetClip1(math.min(math.min(self:Clip1() + amt, self:GetCapacity()), reserve))
|
||||
|
||||
reserve = reserve - self:GetCapacity()
|
||||
|
||||
self:GetOwner():SetAmmo(reserve, self.Primary.Ammo)
|
||||
|
||||
return self:Clip1() - lastclip1
|
||||
end
|
||||
|
||||
function SWEP:GetShouldShotgunReload()
|
||||
if self:GetProcessedValue("HybridReload") then
|
||||
if self:Clip1() >= self:GetProcessedValue("ChamberSize") then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return self:GetProcessedValue("ShotgunReload")
|
||||
end
|
||||
|
||||
function SWEP:EndReload()
|
||||
if self:GetShouldShotgunReload() then
|
||||
if self:Clip1() >= self:GetCapacity() or self:Ammo1() == 0 or self:GetEndReload() then
|
||||
// finish
|
||||
self:PlayAnimation("reload_finish", self:GetProcessedValue("ReloadTime", 1), true, true)
|
||||
self:SetReloading(false)
|
||||
|
||||
self:SetNthShot(0)
|
||||
self:SetNthReload(self:GetNthReload() + 1)
|
||||
else
|
||||
local t = self:PlayAnimation("reload_insert", self:GetProcessedValue("ReloadTime", 1), true)
|
||||
|
||||
local res = math.min(math.min(3, self:GetCapacity() - self:Clip1()), self:Ammo1())
|
||||
|
||||
self:SetLoadedRounds(res)
|
||||
|
||||
for i = 1, res do
|
||||
self:SetTimer(t * 0.95 * ((i - 1) / 3), function()
|
||||
self:RestoreClip(1)
|
||||
end)
|
||||
end
|
||||
|
||||
self:SetReloadFinishTime(CurTime() + (t * 0.95 * (res / 3)))
|
||||
|
||||
-- self:SetTimer(t * 0.95 * (res / 3), function()
|
||||
-- if !IsValid(self) then return end
|
||||
|
||||
-- self:EndReload()
|
||||
-- end)
|
||||
end
|
||||
else
|
||||
self:RestoreClip(self:GetValue("ClipSize"))
|
||||
self:SetReloading(false)
|
||||
|
||||
self:SetNthShot(0)
|
||||
self:SetNthReload(self:GetNthReload() + 1)
|
||||
self:SetEmptyReload(false)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ThinkReload()
|
||||
if self:GetReloading() and self:GetReloadFinishTime() < CurTime() then
|
||||
self:EndReload()
|
||||
end
|
||||
end
|
64
lua/weapons/arc9_base/sh_scope.lua
Normal file
64
lua/weapons/arc9_base/sh_scope.lua
Normal file
@ -0,0 +1,64 @@
|
||||
function SWEP:GetSightDelta()
|
||||
return self:GetSightAmount()
|
||||
end
|
||||
|
||||
function SWEP:EnterSights()
|
||||
if self:GetSprintAmount() > 0 then return end
|
||||
if !self:GetProcessedValue("HasSights") then return end
|
||||
|
||||
self:SetInSights(true)
|
||||
self:EmitSound(self:RandomChoice(self:GetProcessedValue("EnterSightsSound")), 100, 75)
|
||||
|
||||
if CLIENT then
|
||||
self:BuildMultiSight()
|
||||
elseif game.SinglePlayer() then
|
||||
self:CallOnClient("BuildMultiSight")
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ExitSights()
|
||||
self:SetInSights(false)
|
||||
self:EmitSound(self:RandomChoice(self:GetProcessedValue("ExitSightsSound")), 100, 75)
|
||||
end
|
||||
|
||||
SWEP.LastPressedETime = 0
|
||||
|
||||
function SWEP:ThinkSights()
|
||||
if self:GetSafe() then return end
|
||||
|
||||
local sighted = self:GetInSights()
|
||||
|
||||
local amt = self:GetSightAmount()
|
||||
|
||||
if sighted then
|
||||
amt = math.Approach(amt, 1, FrameTime() / self:GetProcessedValue("AimDownSightsTime"))
|
||||
else
|
||||
amt = math.Approach(amt, 0, FrameTime() / self:GetProcessedValue("AimDownSightsTime"))
|
||||
end
|
||||
|
||||
self:GetVM():SetPoseParameter("sights", amt)
|
||||
|
||||
self:SetSightAmount(amt)
|
||||
|
||||
if sighted and !self:GetOwner():KeyDown(IN_ATTACK2) then
|
||||
self:ExitSights()
|
||||
elseif !sighted and self:GetOwner():KeyDown(IN_ATTACK2) then
|
||||
if self:GetOwner():KeyDown(IN_USE) then
|
||||
return
|
||||
end
|
||||
|
||||
self:EnterSights()
|
||||
end
|
||||
|
||||
if self:GetOwner():KeyPressed(IN_USE) then
|
||||
if CurTime() - self.LastPressedETime < 0.33 then
|
||||
if game.SinglePlayer() then
|
||||
self:CallOnClient("SwitchMultiSight")
|
||||
elseif CLIENT then
|
||||
self:SwitchMultiSight()
|
||||
end
|
||||
else
|
||||
self.LastPressedETime = CurTime()
|
||||
end
|
||||
end
|
||||
end
|
299
lua/weapons/arc9_base/sh_shoot.lua
Normal file
299
lua/weapons/arc9_base/sh_shoot.lua
Normal file
@ -0,0 +1,299 @@
|
||||
local cancelmults = {
|
||||
[HITGROUP_HEAD] = 2,
|
||||
[HITGROUP_CHEST] = 1,
|
||||
[HITGROUP_STOMACH] = 1,
|
||||
[HITGROUP_LEFTARM] = 0.25,
|
||||
[HITGROUP_RIGHTARM] = 0.25,
|
||||
[HITGROUP_LEFTLEG] = 0.25,
|
||||
[HITGROUP_RIGHTLEG] = 0.25,
|
||||
[HITGROUP_GEAR] = 0.25
|
||||
}
|
||||
|
||||
function SWEP:StillWaiting()
|
||||
if self:GetNextPrimaryFire() > CurTime() then return true end
|
||||
if self:GetNextSecondaryFire() > CurTime() then return true end
|
||||
if self:GetAnimLockTime() > CurTime() then return true end
|
||||
if self:GetPrimedAttack() then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:SprintLock()
|
||||
if self:GetSprintAmount() > 0 then return true end
|
||||
if self:GetIsSprinting() then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if self:GetOwner():IsNPC() then
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetReloading() then
|
||||
self:SetEndReload(true)
|
||||
end
|
||||
|
||||
if self:StillWaiting() then return end
|
||||
|
||||
if self:GetCustomize() then return end
|
||||
|
||||
-- if self:GetProcessedValue("CanQuickNade") then
|
||||
-- if self:GetOwner():KeyDown(IN_USE) then
|
||||
-- self:PrimeGrenade()
|
||||
-- self:SetBurstCount(0)
|
||||
-- return
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- if self:GetProcessedValue("Melee") then
|
||||
-- if self:GetOwner():KeyDown(IN_USE) then
|
||||
-- self:Melee()
|
||||
-- return
|
||||
-- end
|
||||
-- end
|
||||
|
||||
if self:GetNeedTriggerPress() then return end
|
||||
|
||||
if self:GetSafe() then
|
||||
self:ToggleSafety(false)
|
||||
self:SetNeedTriggerPress(true)
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetCurrentFiremode() > 0 and self:GetBurstCount() >= self:GetCurrentFiremode() then return end
|
||||
|
||||
if self:Clip1() < self:GetProcessedValue("AmmoPerShot") then
|
||||
self:PlayAnimation("dryfire")
|
||||
self:EmitSound(self:RandomChoice(self:GetProcessedValue("DryFireSound")), 75, 100, 1, CHAN_BODY)
|
||||
self:SetBurstCount(0)
|
||||
self:SetNeedTriggerPress(true)
|
||||
return
|
||||
end
|
||||
|
||||
self:SetBaseSettings()
|
||||
|
||||
if self:SprintLock() then return end
|
||||
|
||||
if self:RunHook("HookP_BlockFire") then return end
|
||||
|
||||
if IsFirstTimePredicted() then
|
||||
self:TakePrimaryAmmo(self:GetProcessedValue("AmmoPerShot"))
|
||||
end
|
||||
|
||||
local idle = true
|
||||
|
||||
self:PlayAnimation("fire", 1, false, idle)
|
||||
|
||||
local ejectdelay = self:GetProcessedValue("EjectDelay")
|
||||
|
||||
if ejectdelay == 0 then
|
||||
self:DoEject()
|
||||
else
|
||||
self:SetTimer(ejectdelay, function()
|
||||
self:DoEject()
|
||||
end)
|
||||
end
|
||||
|
||||
self:GetOwner():DoAnimationEvent(self:GetProcessedValue("AnimShoot"))
|
||||
|
||||
local pvar = self:GetProcessedValue("ShootPitchVariation")
|
||||
local pvrand = util.SharedRandom("ARC9_sshoot", -pvar, pvar)
|
||||
|
||||
self:EmitSound(self:RandomChoice(self:GetProcessedValue("ShootSound")) or "", self:GetProcessedValue("ShootVolume"), self:GetProcessedValue("ShootPitch") + pvrand, 1, CHAN_WEAPON)
|
||||
|
||||
self:EmitSound(self:RandomChoice(self:GetProcessedValue("DistantShootSound")) or "", 149, self:GetProcessedValue("ShootPitch") + pvrand, 1, CHAN_WEAPON + 1)
|
||||
|
||||
local delay = 60 / self:GetProcessedValue("RPM")
|
||||
|
||||
local curatt = self:GetNextPrimaryFire()
|
||||
local diff = CurTime() - curatt
|
||||
|
||||
if diff > engine.TickInterval() or diff < 0 then
|
||||
curatt = CurTime()
|
||||
end
|
||||
|
||||
self:SetNextPrimaryFire(curatt + delay)
|
||||
|
||||
self:SetNthShot(self:GetNthShot() + 1)
|
||||
|
||||
self:DoEffects()
|
||||
|
||||
local spread = self:GetProcessedValue("Spread")
|
||||
|
||||
local dir = self:GetShootDir()
|
||||
|
||||
if self:GetProcessedValue("ShootEnt") then
|
||||
self:ShootRocket()
|
||||
else
|
||||
if IsFirstTimePredicted() then
|
||||
if GetConVar("ARC9_bullet_physics"):GetBool() then
|
||||
for i = 1, self:GetProcessedValue("Num") do
|
||||
dir = self:GetOwner():EyeAngles() + (spread * AngleRand() / 3.6)
|
||||
ARC9:ShootPhysBullet(self, self:GetOwner():GetShootPos(), dir:Forward() * self:GetProcessedValue("PhysBulletMuzzleVelocity"))
|
||||
end
|
||||
else
|
||||
self:GetOwner():LagCompensation(true)
|
||||
local tr = self:GetProcessedValue("TracerNum")
|
||||
|
||||
self:GetOwner():FireBullets({
|
||||
Damage = self:GetProcessedValue("Damage_Max"),
|
||||
Force = 8,
|
||||
Tracer = tr,
|
||||
Num = self:GetProcessedValue("Num"),
|
||||
Dir = dir:Forward(),
|
||||
Src = self:GetOwner():GetShootPos(),
|
||||
Spread = Vector(spread, spread, spread),
|
||||
IgnoreEntity = self:GetOwner():GetVehicle(),
|
||||
Callback = function(att, btr, dmg)
|
||||
local range = (btr.HitPos - btr.StartPos):Length()
|
||||
|
||||
self:AfterShotFunction(btr, dmg, range, self:GetProcessedValue("Penetration"), {})
|
||||
|
||||
if GetConVar("developer"):GetBool() then
|
||||
if SERVER then
|
||||
debugoverlay.Cross(btr.HitPos, 4, 5, Color(255, 0, 0), false)
|
||||
else
|
||||
debugoverlay.Cross(btr.HitPos, 4, 5, Color(255, 255, 255), false)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
self:GetOwner():LagCompensation(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:ApplyRecoil()
|
||||
|
||||
self:SetBurstCount(self:GetBurstCount() + 1)
|
||||
|
||||
if self:GetCurrentFiremode() == 1 or self:Clip1() == 0 then
|
||||
self:SetNeedTriggerPress(true)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:AfterShotFunction(tr, dmg, range, penleft, alreadypenned)
|
||||
if !IsFirstTimePredicted() and !game.SinglePlayer() then return end
|
||||
local dmgv = self:GetDamageAtRange(range)
|
||||
|
||||
self:RunHook("Hook_BulletImpact", {
|
||||
tr = tr,
|
||||
dmg = dmg,
|
||||
range = range,
|
||||
penleft = penleft,
|
||||
alreadypenned = alreadypenned
|
||||
})
|
||||
|
||||
local bodydamage = self:GetProcessedValue("BodyDamageMults")
|
||||
|
||||
local dmgbodymult = 1
|
||||
|
||||
if bodydamage[tr.HitGroup] then
|
||||
dmgbodymult = dmgbodymult * bodydamage[tr.HitGroup]
|
||||
end
|
||||
|
||||
if GetConVar("ARC9_bodydamagecancel"):GetBool() and cancelmults[tr.HitGroup] then
|
||||
-- if cancelmults[tr.HitGroup] then
|
||||
dmgbodymult = dmgbodymult / cancelmults[tr.HitGroup]
|
||||
end
|
||||
|
||||
dmgv = dmgv * dmgbodymult
|
||||
|
||||
local pendelta = penleft / self:GetProcessedValue("Penetration")
|
||||
|
||||
pendelta = math.Clamp(pendelta, 0.1, 1)
|
||||
|
||||
dmgv = dmgv * pendelta
|
||||
|
||||
if self:GetOwner():IsNPC() and !GetConVar("ARC9_npc_equality"):GetBool() then
|
||||
dmgv = dmgv * 0.25
|
||||
end
|
||||
|
||||
dmg:SetDamage(dmgv)
|
||||
|
||||
if tr.Entity and alreadypenned[tr.Entity] then
|
||||
dmg:SetDamage(0)
|
||||
elseif tr.Entity then
|
||||
alreadypenned[tr.Entity] = true
|
||||
end
|
||||
|
||||
self:Penetrate(tr, range, penleft, alreadypenned)
|
||||
end
|
||||
|
||||
function SWEP:GetDamageAtRange(range)
|
||||
local d = 1
|
||||
|
||||
local r_min = self:GetProcessedValue("RangeMin")
|
||||
local r_max = self:GetProcessedValue("RangeMax")
|
||||
|
||||
if range <= r_min then
|
||||
d = 0
|
||||
elseif range >= r_max then
|
||||
d = 1
|
||||
else
|
||||
d = (range - r_min) / (r_max - r_min)
|
||||
end
|
||||
|
||||
local dmgv = Lerp(d, self:GetProcessedValue("DamageMax"), self:GetProcessedValue("DamageMin"))
|
||||
|
||||
dmgv = self:GetProcessedValue("Damage", dmgv)
|
||||
|
||||
dmgv = math.ceil(dmgv)
|
||||
|
||||
return dmgv
|
||||
end
|
||||
|
||||
function SWEP:GetShootDir()
|
||||
local dir = self:GetOwner():EyeAngles()
|
||||
|
||||
dir = dir + self:GetFreeAimOffset()
|
||||
|
||||
dir = dir + self:GetFreeSwayAngles()
|
||||
|
||||
return dir
|
||||
end
|
||||
|
||||
function SWEP:ShootRocket()
|
||||
if CLIENT then return end
|
||||
|
||||
local src = self:GetMuzzleOrigin()
|
||||
local dir = self:GetShootDir()
|
||||
|
||||
local num = self:GetProcessedValue("Num")
|
||||
local ent = self:GetProcessedValue("ShootEnt")
|
||||
|
||||
local spread
|
||||
|
||||
if self:GetOwner():IsNPC() then
|
||||
-- ang = self:GetOwner():GetAimVector():Angle()
|
||||
spread = self:GetNPCSpread()
|
||||
else
|
||||
spread = self:GetSpread()
|
||||
end
|
||||
|
||||
for i = 1, num do
|
||||
local dispersion = Angle(math.Rand(-1, 1), math.Rand(-1, 1), 0)
|
||||
|
||||
dispersion = dispersion * spread * 36
|
||||
|
||||
local rocket = ents.Create(ent)
|
||||
if !IsValid(rocket) then return end
|
||||
|
||||
rocket:SetPos(src)
|
||||
rocket:SetOwner(self:GetOwner())
|
||||
rocket:SetAngles(dir + dispersion)
|
||||
rocket:Spawn()
|
||||
|
||||
local phys = rocket:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:ApplyForceCenter((dir + dispersion):Forward() * self:GetProcessedValue("ShootEntForce"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:FireAnimationEvent( pos, ang, event, options )
|
||||
return true
|
||||
end
|
60
lua/weapons/arc9_base/sh_sprint.lua
Normal file
60
lua/weapons/arc9_base/sh_sprint.lua
Normal file
@ -0,0 +1,60 @@
|
||||
function SWEP:GetSprintToFireTime()
|
||||
return self:GetProcessedValue("SprintToFireTime")
|
||||
end
|
||||
|
||||
function SWEP:GetIsSprinting()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if !self:GetOwner():IsValid() or self:GetOwner():IsNPC() then
|
||||
return false
|
||||
end
|
||||
|
||||
local curspeed = owner:GetVelocity():Length()
|
||||
|
||||
if !owner:KeyDown(IN_FORWARD) and !owner:KeyDown(IN_BACK) and !owner:KeyDown(IN_MOVELEFT) and !owner:KeyDown(IN_MOVERIGHT) then return false end
|
||||
if !owner:KeyDown(IN_SPEED) then return false end
|
||||
if curspeed <= 0 then return false end
|
||||
if !owner:OnGround() then return false end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:GetSprintDelta()
|
||||
return self:GetSprintAmount()
|
||||
end
|
||||
|
||||
function SWEP:EnterSprint()
|
||||
self:SetShouldHoldType()
|
||||
end
|
||||
|
||||
function SWEP:ExitSprint()
|
||||
self:SetShouldHoldType()
|
||||
end
|
||||
|
||||
SWEP.LastWasSprinting = false
|
||||
|
||||
function SWEP:ThinkSprint()
|
||||
local sprinting = self:GetIsSprinting() or self:GetSafe()
|
||||
|
||||
if self:GetSightAmount() >= 1 then
|
||||
sprinting = false
|
||||
end
|
||||
|
||||
local amt = self:GetSprintAmount()
|
||||
|
||||
if self.LastWasSprinting and !sprinting then
|
||||
self:ExitSprint()
|
||||
elseif !self.LastWasSprinting and sprinting then
|
||||
self:EnterSprint()
|
||||
end
|
||||
|
||||
self.LastWasSprinting = sprinting
|
||||
|
||||
if sprinting then
|
||||
amt = math.Approach(amt, 1, FrameTime() / self:GetSprintToFireTime())
|
||||
else
|
||||
amt = math.Approach(amt, 0, FrameTime() / self:GetSprintToFireTime())
|
||||
end
|
||||
|
||||
self:SetSprintAmount(amt)
|
||||
end
|
240
lua/weapons/arc9_base/sh_stats.lua
Normal file
240
lua/weapons/arc9_base/sh_stats.lua
Normal file
@ -0,0 +1,240 @@
|
||||
SWEP.StatCache = {}
|
||||
SWEP.HookCache = {}
|
||||
SWEP.AffectorsCache = nil
|
||||
|
||||
SWEP.ExcludeFromRawStats = {
|
||||
["PrintName"] = true,
|
||||
}
|
||||
|
||||
function SWEP:InvalidateCache()
|
||||
self.StatCache = {}
|
||||
self.HookCache = {}
|
||||
self.AffectorsCache = nil
|
||||
self.ElementsCache = nil
|
||||
|
||||
self:SetBaseSettings()
|
||||
end
|
||||
|
||||
function SWEP:RunHook(val, data)
|
||||
if self.HookCache[val] then
|
||||
for _, chook in pairs(self.HookCache[val]) do
|
||||
local d = chook(self, data)
|
||||
|
||||
if d != nil then
|
||||
data = d
|
||||
end
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
self.HookCache[val] = {}
|
||||
|
||||
for _, tbl in pairs(self:GetAllAffectors()) do
|
||||
if tbl[val] then
|
||||
|
||||
table.insert(self.HookCache[val], tbl[val])
|
||||
|
||||
if !pcall(function()
|
||||
local d = tbl[val](self, data)
|
||||
|
||||
if d != nil then
|
||||
data = d
|
||||
end
|
||||
end) then
|
||||
print("!!! ARC9 ERROR - \"" .. (tbl["PrintName"] or "Unknown") .. "\" TRIED TO RUN INVALID HOOK ON " .. val .. "!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
function SWEP:GetFinalAttTableFromAddress(address)
|
||||
return self:GetFinalAttTable(self:LocateSlotFromAddress(address))
|
||||
end
|
||||
|
||||
function SWEP:GetFinalAttTable(slot)
|
||||
if !slot.Installed then return {} end
|
||||
|
||||
local atttbl = ARC9.GetAttTable(slot.Installed)
|
||||
|
||||
if atttbl.ToggleStats then
|
||||
local tbl = table.Copy(atttbl)
|
||||
local toggletbl = atttbl.ToggleStats[slot.ToggleNum or 1]
|
||||
|
||||
table.Add(tbl, toggletbl)
|
||||
|
||||
return tbl
|
||||
else
|
||||
return atttbl
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetAllAffectors()
|
||||
if self.AffectorsCache then return self.AffectorsCache end
|
||||
|
||||
local aff = {}
|
||||
|
||||
table.insert(aff, self:GetTable())
|
||||
|
||||
for _, slot in pairs(self:GetSubSlotList()) do
|
||||
local atttbl = self:GetFinalAttTable(slot)
|
||||
|
||||
if atttbl then
|
||||
table.insert(aff, atttbl)
|
||||
end
|
||||
end
|
||||
|
||||
if !ARC9.Overrun then
|
||||
ARC9.Overrun = true
|
||||
table.insert(aff, self:GetCurrentFiremodeTable())
|
||||
ARC9.Overrun = false
|
||||
end
|
||||
|
||||
self.AffectorsCache = aff
|
||||
|
||||
return aff
|
||||
end
|
||||
|
||||
function SWEP:GetProcessedValue(val, base)
|
||||
local stat = self:GetValue(val, base)
|
||||
|
||||
if self:GetValue("Silencer") then
|
||||
stat = self:GetValue(val, stat, "Silenced")
|
||||
end
|
||||
|
||||
if !self:GetOwner():OnGround() then
|
||||
stat = self:GetValue(val, stat, "MidAir")
|
||||
end
|
||||
|
||||
if self:GetOwner():Crouching() and self:GetOwner():OnGround() then
|
||||
stat = self:GetValue(val, stat, "Crouch")
|
||||
end
|
||||
|
||||
if self:GetBurstCount() == 0 then
|
||||
stat = self:GetValue(val, stat, "FirstShot")
|
||||
stat = self:GetValue(val, stat, "First")
|
||||
end
|
||||
|
||||
if self:Clip1() == 0 then
|
||||
stat = self:GetValue(val, stat, "Empty")
|
||||
stat = self:GetValue(val, stat, "LastShot")
|
||||
stat = self:GetValue(val, stat, "Last")
|
||||
end
|
||||
|
||||
if self:GetNthShot() % 2 == 0 then
|
||||
stat = self:GetValue(val, stat, "EvenShot")
|
||||
else
|
||||
stat = self:GetValue(val, stat, "OddShot")
|
||||
end
|
||||
|
||||
if self:GetNthReload() % 2 == 0 then
|
||||
stat = self:GetValue(val, stat, "EvenReload")
|
||||
else
|
||||
stat = self:GetValue(val, stat, "OddReload")
|
||||
end
|
||||
|
||||
if isnumber(stat) then
|
||||
stat = Lerp(self:GetSightAmount(), self:GetValue(val, stat, "HipFire"), self:GetValue(val, stat, "Sights"))
|
||||
else
|
||||
if self:GetSightAmount() >= 1 then
|
||||
stat = self:GetValue(val, stat, "Sights")
|
||||
else
|
||||
stat = self:GetValue(val, stat, "HipFire")
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetNextPrimaryFire() + 0.1 > CurTime() then
|
||||
local pft = CurTime() - self:GetNextPrimaryFire() + 0.1
|
||||
local d = pft / 0.1
|
||||
|
||||
d = math.Clamp(d, 0, 1)
|
||||
|
||||
if isnumber(stat) then
|
||||
stat = Lerp(d, stat, self:GetValue(val, stat, "Shooting"))
|
||||
else
|
||||
if d > 0 then
|
||||
stat = self:GetValue(val, stat, "Shooting")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
stat = self:GetValue(val, stat, "Recoil", self:GetRecoilAmount())
|
||||
|
||||
local spd = math.min(self:GetOwner():GetAbsVelocity():Length(), 250)
|
||||
|
||||
spd = spd / 250
|
||||
|
||||
if isnumber(stat) then
|
||||
stat = Lerp(spd, stat, self:GetValue(val, stat, "Move"))
|
||||
else
|
||||
if spd > 0 then
|
||||
stat = self:GetValue(val, stat, "Move")
|
||||
end
|
||||
end
|
||||
|
||||
return stat
|
||||
end
|
||||
|
||||
function SWEP:GetValue(val, base, condition, amount)
|
||||
condition = condition or ""
|
||||
amount = amount or 1
|
||||
local stat = base or self:GetTable()[val]
|
||||
|
||||
if self.StatCache[tostring(base) .. val .. condition] then
|
||||
stat = self.StatCache[tostring(base) .. val .. condition]
|
||||
|
||||
stat = self:RunHook(val .. "Hook" .. condition, stat) or stat
|
||||
|
||||
return stat
|
||||
end
|
||||
|
||||
local priority = 0
|
||||
|
||||
if !self.ExcludeFromRawStats[val] then
|
||||
for _, tbl in pairs(self:GetAllAffectors()) do
|
||||
local att_priority = tbl[val .. condition .. "_Priority"] or 1
|
||||
|
||||
if tbl[val .. condition] != nil and att_priority >= priority then
|
||||
stat = tbl[val .. condition]
|
||||
priority = att_priority
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, tbl in pairs(self:GetAllAffectors()) do
|
||||
local att_priority = tbl[val .. "Override" .. condition .. "Priority"] or 1
|
||||
|
||||
if tbl[val .. "Override" .. condition] != nil and att_priority >= priority then
|
||||
stat = tbl[val .. "Override" .. condition]
|
||||
priority = att_priority
|
||||
end
|
||||
end
|
||||
|
||||
if isnumber(stat) then
|
||||
|
||||
for _, tbl in pairs(self:GetAllAffectors()) do
|
||||
if tbl[val .. "Add" .. condition] != nil then
|
||||
if !pcall(function() stat = stat + (tbl[val .. "Add" .. condition] * amount) end) then
|
||||
print("!!! ARC9 ERROR - \"" .. (tbl["PrintName"] or "Unknown") .. "\" TRIED TO ADD INVALID VALUE: (" .. tbl[val .. "Add" .. condition] .. ") TO " .. val .. "!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, tbl in pairs(self:GetAllAffectors()) do
|
||||
if tbl[val .. "Mult" .. condition] != nil then
|
||||
if !pcall(function() stat = stat * math.pow(tbl[val .. "Mult" .. condition], amount) end) then
|
||||
print("!!! ARC9 ERROR - \"" .. (tbl["PrintName"] or "Unknown") .. "\" TRIED TO MULTIPLY INVALID VALUE: (" .. tbl[val .. "Add" .. condition] .. ") TO " .. val .. "!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.StatCache[tostring(base) .. val .. condition] = stat
|
||||
|
||||
stat = self:RunHook(val .. "Hook" .. condition, stat) or stat
|
||||
|
||||
return stat
|
||||
end
|
126
lua/weapons/arc9_base/sh_subatts.lua
Normal file
126
lua/weapons/arc9_base/sh_subatts.lua
Normal file
@ -0,0 +1,126 @@
|
||||
SWEP.AttachmentAddresses = {}
|
||||
|
||||
function SWEP:LocateSlotFromAddress(address)
|
||||
return self.AttachmentAddresses[address]
|
||||
end
|
||||
|
||||
function SWEP:BuildAttachmentAddresses()
|
||||
self.AttachmentAddresses = {}
|
||||
|
||||
for c, i in pairs(self:GetSubSlotList()) do
|
||||
i.Address = c
|
||||
|
||||
self.AttachmentAddresses[c] = i
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:AttTreeToList(tree)
|
||||
if !istable(tree) then return {} end
|
||||
local atts = {}
|
||||
|
||||
atts = {tree}
|
||||
|
||||
if tree.SubAttachments then
|
||||
for _, sub in pairs(tree.SubAttachments) do
|
||||
table.Add(atts, self:AttTreeToList(sub))
|
||||
end
|
||||
end
|
||||
|
||||
return atts
|
||||
end
|
||||
|
||||
function SWEP:GetSubSlotList()
|
||||
local atts = {}
|
||||
|
||||
for _, i in pairs(self.Attachments or {}) do
|
||||
table.Add(atts, self:AttTreeToList(i))
|
||||
end
|
||||
|
||||
return atts
|
||||
end
|
||||
|
||||
function SWEP:GetAttachmentList()
|
||||
local atts = {}
|
||||
|
||||
for _, i in pairs(self:GetSubSlotList()) do
|
||||
if i.Installed then
|
||||
table.insert(atts, i.Installed)
|
||||
end
|
||||
end
|
||||
|
||||
return atts
|
||||
end
|
||||
|
||||
function SWEP:BuildSubAttachmentTree(tbl, parenttbl)
|
||||
if !tbl.Installed then return {} end
|
||||
|
||||
local atttbl = ARC9.GetAttTable(tbl.Installed)
|
||||
|
||||
local subatts = {}
|
||||
|
||||
if atttbl then
|
||||
if atttbl.Attachments then
|
||||
subatts = table.Copy(atttbl.Attachments)
|
||||
|
||||
for i, k in ipairs(tbl.SubAttachments) do
|
||||
subatts[i].Bone = parenttbl.Bone
|
||||
|
||||
local pos, _ = LocalToWorld(subatts[i].Pos or Vector(0, 0, 0), subatts[i].Ang or Angle(0, 0, 0), parenttbl.Pos, parenttbl.Ang)
|
||||
|
||||
subatts[i].Pos = pos
|
||||
subatts[i].Ang = subatts[i].Ang + parenttbl.Ang
|
||||
subatts[i].Ang:Normalize()
|
||||
subatts[i].ExtraSightDistance = parenttbl.ExtraSightDistance
|
||||
subatts[i].Installed = tbl.SubAttachments[i].Installed
|
||||
subatts[i].SubAttachments = self:BuildSubAttachmentTree(k, subatts[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return subatts
|
||||
end
|
||||
|
||||
function SWEP:BuildSubAttachments(tbl)
|
||||
for i, k in pairs(self.Attachments) do
|
||||
k.SubAttachments = {}
|
||||
end
|
||||
|
||||
for i, k in pairs(tbl) do
|
||||
self.Attachments[i].Installed = k.Installed
|
||||
|
||||
if !k.Installed then continue end
|
||||
|
||||
local atttbl = ARC9.GetAttTable(k.Installed)
|
||||
|
||||
if atttbl then
|
||||
if atttbl.Attachments then
|
||||
self.Attachments[i].SubAttachments = self:BuildSubAttachmentTree(k, self.Attachments[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:BuildAttachmentAddresses()
|
||||
end
|
||||
|
||||
function SWEP:ValidateInventoryForNewTree(tree)
|
||||
local count = self:CountAttsInTree(tree)
|
||||
|
||||
local currcount = self:CountAttsInTree(self.Attachments)
|
||||
|
||||
for att, attc in pairs(count) do
|
||||
local atttbl = ARC9.GetAttTable(att)
|
||||
|
||||
if atttbl.Free then continue end
|
||||
|
||||
if (currcount[att] or 0) + ARC9:PlayerGetAtts(self:GetOwner(), att) > count[att] then
|
||||
continue
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:PruneAttachments()
|
||||
end
|
43
lua/weapons/arc9_base/sh_think.lua
Normal file
43
lua/weapons/arc9_base/sh_think.lua
Normal file
@ -0,0 +1,43 @@
|
||||
function SWEP:Think()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:KeyReleased(IN_ATTACK) then
|
||||
self:SetNeedTriggerPress(false)
|
||||
if !self:GetProcessedValue("RunawayBurst") then
|
||||
self:SetBurstCount(0)
|
||||
end
|
||||
if self:GetCurrentFiremode() < 0 and !self:GetProcessedValue("RunawayBurst") and self:GetBurstCount() > 0 then
|
||||
self:SetNextPrimaryFire(CurTime() + self:GetProcessedValue("PostBurstDelay"))
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetProcessedValue("RunawayBurst") then
|
||||
if self:GetBurstCount() >= self:GetCurrentFiremode() and self:GetCurrentFiremode() > 0 then
|
||||
self:SetBurstCount(0)
|
||||
self:SetNextPrimaryFire(CurTime() + self:GetProcessedValue("PostBurstDelay"))
|
||||
if !self:GetProcessedValue("AutoBurst") then
|
||||
self:SetNeedTriggerPress(true)
|
||||
end
|
||||
elseif self:GetBurstCount() > 0 and self:GetBurstCount() < self:GetCurrentFiremode() then
|
||||
self:PrimaryAttack()
|
||||
end
|
||||
end
|
||||
|
||||
self:ThinkRecoil()
|
||||
|
||||
self:ThinkSprint()
|
||||
|
||||
self:ThinkReload()
|
||||
|
||||
self:ThinkSights()
|
||||
|
||||
self:ThinkFiremodes()
|
||||
|
||||
self:ThinkFreeAim()
|
||||
|
||||
self:ProcessTimers()
|
||||
|
||||
if self:GetNextIdle() < CurTime() then
|
||||
self:Idle()
|
||||
end
|
||||
end
|
80
lua/weapons/arc9_base/sh_timers.lua
Normal file
80
lua/weapons/arc9_base/sh_timers.lua
Normal file
@ -0,0 +1,80 @@
|
||||
local tick = 0
|
||||
|
||||
// Avoid using this system - it breaks prediction.
|
||||
|
||||
function SWEP:InitTimers()
|
||||
self.ActiveTimers = {} -- { { time, id, func } }
|
||||
end
|
||||
|
||||
function SWEP:SetTimer(time, callback, id)
|
||||
if !IsFirstTimePredicted() then return end
|
||||
|
||||
table.insert(self.ActiveTimers, { time + CurTime(), id or "", callback })
|
||||
end
|
||||
|
||||
function SWEP:TimerExists(id)
|
||||
for _, v in pairs(self.ActiveTimers) do
|
||||
if v[2] == id then return true end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:KillTimer(id)
|
||||
local keeptimers = {}
|
||||
|
||||
for _, v in pairs(self.ActiveTimers) do
|
||||
if v[2] != id then table.insert(keeptimers, v) end
|
||||
end
|
||||
|
||||
self.ActiveTimers = keeptimers
|
||||
end
|
||||
|
||||
function SWEP:KillTimers()
|
||||
self.ActiveTimers = {}
|
||||
end
|
||||
|
||||
function SWEP:ProcessTimers()
|
||||
local keeptimers = {}
|
||||
local UCT = CurTime()
|
||||
|
||||
if CLIENT and UCT == tick then return end
|
||||
|
||||
if !self.ActiveTimers then self:InitTimers() end
|
||||
|
||||
for _, v in pairs(self.ActiveTimers) do
|
||||
if v[1] <= UCT then v[3]() end
|
||||
end
|
||||
|
||||
for _, v in pairs(self.ActiveTimers) do
|
||||
if v[1] > UCT then table.insert(keeptimers, v) end
|
||||
end
|
||||
|
||||
self.ActiveTimers = keeptimers
|
||||
end
|
||||
|
||||
function SWEP:PlaySoundTable(soundtable, mult)
|
||||
--if CLIENT and game.SinglePlayer() then return end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
start = start or 0
|
||||
mult = 1 / (mult or 1)
|
||||
|
||||
for _, v in pairs(soundtable) do
|
||||
local ttime
|
||||
if v.t then
|
||||
ttime = v.t * mult
|
||||
else
|
||||
continue
|
||||
end
|
||||
if ttime < 0 then continue end
|
||||
if !(IsValid(self) and IsValid(owner)) then continue end
|
||||
|
||||
local playtime = ttime
|
||||
|
||||
self:SetTimer(playtime, function()
|
||||
self:EmitSound(self:RandomChoice(v.s or ""), v.v or 75, v.p or 100, 1, v.c or CHAN_AUTO)
|
||||
end)
|
||||
end
|
||||
end
|
40
lua/weapons/arc9_base/sh_util.lua
Normal file
40
lua/weapons/arc9_base/sh_util.lua
Normal file
@ -0,0 +1,40 @@
|
||||
function SWEP:SanityCheck()
|
||||
if !IsValid(self) then return false end
|
||||
if !IsValid(self:GetOwner()) then return false end
|
||||
if !IsValid(self:GetVM()) then return false end
|
||||
end
|
||||
|
||||
function SWEP:GetWM()
|
||||
return self.WModel[1]
|
||||
end
|
||||
|
||||
function SWEP:GetVM()
|
||||
return self:GetOwner():GetViewModel()
|
||||
end
|
||||
|
||||
function SWEP:Curve(x)
|
||||
return 0.5 * math.cos((x + 1) * math.pi) + 0.5
|
||||
end
|
||||
|
||||
function SWEP:IsAnimLocked()
|
||||
return self:GetAnimLockTime() > CurTime()
|
||||
end
|
||||
|
||||
function SWEP:RandomChoice(choice)
|
||||
if istable(choice) then
|
||||
choice = table.Random(choice)
|
||||
end
|
||||
|
||||
return choice
|
||||
end
|
||||
|
||||
function SWEP:PatternWithRunOff(pattern, runoff, num)
|
||||
if num < #pattern then
|
||||
return pattern[num]
|
||||
else
|
||||
num = num - #pattern
|
||||
num = num % #runoff
|
||||
|
||||
return runoff[num + 1]
|
||||
end
|
||||
end
|
785
lua/weapons/arc9_base/shared.lua
Normal file
785
lua/weapons/arc9_base/shared.lua
Normal file
@ -0,0 +1,785 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.Spawnable = false
|
||||
SWEP.Category = "ARC-9"
|
||||
SWEP.AdminOnly = false
|
||||
|
||||
|
||||
-- Any string can be replaced with a localized string by using # in front of it.
|
||||
-- Get the appropriate localized string for the weapon with #WEAPON_NAME_VARIABLE.
|
||||
-- For example, #A2_BASE_PRINTNAME.
|
||||
-- Otherwise, it'll just use the direct string.
|
||||
-- If a localized string is unavailable in your language, English will be used. Otherwise, the default language will be used.
|
||||
|
||||
SWEP.PrintName = "ARC9 Base"
|
||||
SWEP.TrueName = nil
|
||||
-- PrintName could be a game's fictional name for a gun, while TrueName is its real name.
|
||||
-- You could also have it be a generic name, like "Assault Rifle" vs. "AK-47".
|
||||
-- TrueName should be something that improves the cross-compatibility of weapon naming.
|
||||
|
||||
SWEP.Class = ARC9.CLASS_OTHER -- Refer to ARC9/common/sh_enums.lua.
|
||||
SWEP.Trivia = {} -- Optional. Any stats you like can be added.
|
||||
-- SWEP.Trivia = {
|
||||
-- Manufacturer = "Arctic Armament International",
|
||||
-- Calibre = "9x21mm Jager",
|
||||
-- Mechanism = "Roller-Delayed Blowback",
|
||||
-- Country = "UK-Australia-China",
|
||||
-- Year = 2021
|
||||
-- }
|
||||
SWEP.Description = [[]]
|
||||
-- Multi-line strings are possible with the double square brackets.]]
|
||||
|
||||
SWEP.UseHands = true -- Same as weapon_base
|
||||
|
||||
SWEP.ViewModel = ""
|
||||
SWEP.WorldModel = ""
|
||||
|
||||
SWEP.MirrorVMWM = false -- Use this to use the viewmodel as a worldmodel.
|
||||
-- Highly recommended to save effort!
|
||||
SWEP.WorldModelMirror = nil -- Use this to set a lower-quality version of the viewmodel, with the same bone structure, as a worldmodel, to take advantage of MirrorVMWM without having to use the viewmodel.
|
||||
SWEP.WorldModelOffset = nil
|
||||
-- SWEP.WorldModelOffset = {
|
||||
-- pos = Vector(0, 0, 0),
|
||||
-- ang = Angle(0, 0, 0),
|
||||
-- scale = 1
|
||||
-- }
|
||||
|
||||
-------------------------- SAVING
|
||||
|
||||
SWEP.SaveBase = nil -- set to a weapon class to make this weapon share saves with it.
|
||||
|
||||
-------------------------- DEFAULT ELEMENTS
|
||||
|
||||
-- Using MirrorVMWM will use viewmodel parameters for the world model.
|
||||
|
||||
SWEP.DefaultBodygroups = {}
|
||||
-- {
|
||||
-- {
|
||||
-- ind = 0,
|
||||
-- bg = 0,
|
||||
-- }
|
||||
-- }
|
||||
|
||||
SWEP.DefaultWMBodygroups = {}
|
||||
|
||||
SWEP.DefaultSkin = 0
|
||||
SWEP.DefaultWMSkin = 0
|
||||
|
||||
-------------------------- DAMAGE PROFILE
|
||||
|
||||
SWEP.DamageMax = 20 -- Damage done at point blank range
|
||||
SWEP.DamageMin = 15 -- Damage done at maximum range
|
||||
|
||||
SWEP.DamageRand = 0 -- Damage varies randomly per shot by this fraction. 0.1 = +- 10% damage per shot.
|
||||
|
||||
SWEP.RangeMin = 0 -- How far bullets retain their maximum damage for.
|
||||
SWEP.RangeMax = 5000 -- In Hammer units, how far bullets can travel before dealing DamageMin.
|
||||
|
||||
SWEP.Num = 1 -- Number of bullets to shoot
|
||||
-- Bear in mind: Damage is divided by Num
|
||||
|
||||
SWEP.Penetration = 5 -- Units of wood that can be penetrated by this gun.
|
||||
|
||||
SWEP.RicochetAngleMax = 45 // maximum angle at which a ricochet can occur. Between 1 and 90. Angle of 0 is impossible but would theoretically always ricochet.
|
||||
SWEP.RicochetChance = 1 // if the angle is right, what is the chance that a ricochet can occur?
|
||||
|
||||
SWEP.DamageType = DMG_BULLET -- The damage type of the gun.
|
||||
-- DMG_BLAST will create explosive effects and create AOE damage.
|
||||
-- DMG_BURN will ignite the target.
|
||||
|
||||
SWEP.ArmorPiercing = 0 -- Between 0-1. A proportion of damage that is done as direct damage, ignoring protection.
|
||||
|
||||
SWEP.BodyDamageMults = {
|
||||
[HITGROUP_HEAD] = 1.25,
|
||||
[HITGROUP_CHEST] = 1,
|
||||
[HITGROUP_LEFTARM] = 0.9,
|
||||
[HITGROUP_RIGHTARM] = 0.9,
|
||||
}
|
||||
|
||||
-- Set the multiplier for each part of the body.
|
||||
-- If a limb is not set the damage multiplier will default to 1
|
||||
-- That means gmod's stupid default limb mults will **NOT** apply
|
||||
-- {
|
||||
-- [HITGROUP_HEAD] = 1.25,
|
||||
-- [HITGROUP_CHEST] = 1,
|
||||
-- [HITGROUP_LEFTARM] = 0.9,
|
||||
-- [HITGROUP_RIGHTARM] = 0.9,
|
||||
-- }
|
||||
|
||||
-------------------------- ENTITY LAUNCHING
|
||||
|
||||
SWEP.ShootEntity = nil -- Set to an entity to launch it out of this weapon.
|
||||
SWEP.EntityMuzzleVelocity = 10000
|
||||
SWEP.ShootEntityData = {} -- Extra data that can be given to a projectile. Sets SENT.WeaponDataLink with this table.
|
||||
|
||||
-------------------------- PHYS BULLET BALLISTICS
|
||||
|
||||
-- These settings override the player's physical bullet options.
|
||||
SWEP.AlwaysPhysBullet = false
|
||||
SWEP.NeverPhysBullet = false
|
||||
|
||||
SWEP.PhysBulletMuzzleVelocity = 150000 -- Physical bullet muzzle velocity in Hammer Units/second. 1 HU ~= 1 inch.
|
||||
SWEP.PhysBulletDrag = 1 -- Drag multiplier
|
||||
SWEP.PhysBulletGravity = 1 -- Gravity multiplier
|
||||
SWEP.PhysBulletDontInheritPlayerVelocity = false -- Set to true to disable "Browning Effect"
|
||||
|
||||
SWEP.FancyBullets = false -- set to true to allow for multicolor mags and crap
|
||||
-- Each bullet runs HookP_ModifyBullet, within which modifications can be made
|
||||
|
||||
-------------------------- TRACERS
|
||||
|
||||
SWEP.TracerNum = 1 -- Tracer every X
|
||||
SWEP.TracerFinalMag = 0 -- The last X bullets in a magazine are all tracers
|
||||
SWEP.TracerEffect = "ARC9_tracer" -- The effect to use for hitscan tracers
|
||||
SWEP.TracerColor = Color(255, 255, 255) -- Color of tracers. Only works if tracer effect supports it. For physical bullets, this is compressed down to 9-bit color.
|
||||
|
||||
-------------------------- MAGAZINE
|
||||
|
||||
SWEP.Ammo = "pistol" -- What ammo type this gun uses.
|
||||
|
||||
SWEP.ChamberSize = 1 -- The amount of rounds this gun can chamber.
|
||||
SWEP.ClipSize = 25 -- Self-explanatory.
|
||||
SWEP.SupplyLimit = 5 -- Amount of magazines of ammo this gun can take from an ArcCW-A2 supply crate.
|
||||
SWEP.SecondarySupplyLimit = 2 -- Amount of reserve UBGL magazines you can take.
|
||||
|
||||
SWEP.ForceDefaultClip = nil -- Set to force a default amount of ammo this gun can have. Otherwise, this is controlled by console variables.
|
||||
|
||||
SWEP.AmmoPerShot = 1
|
||||
SWEP.InfiniteAmmo = false -- Weapon reloads for free
|
||||
SWEP.BottomlessClip = false -- Weapon never has to reload
|
||||
|
||||
SWEP.ShotgunReload = false -- Weapon reloads like shotgun. Uses insert_1, insert_2, etc animations instead.
|
||||
SWEP.HybridReload = false -- Enable on top of Shotgun Reload. If the weapon is completely empty, use the normal reload animation.
|
||||
-- Use SWEP.Hook_TranslateAnimation in order to do custom animation stuff.
|
||||
|
||||
SWEP.ManualActionChamber = 1 -- How many shots we go between needing to cycle again.
|
||||
SWEP.ManualAction = false -- Pump/bolt action. Play the "cycle" animation after firing, when the trigger is released.
|
||||
SWEP.ManualActionNoLastCycle = false -- Do not cycle on the last shot.
|
||||
|
||||
SWEP.ReloadInSights = false -- This weapon can aim down sights while reloading.
|
||||
|
||||
SWEP.CanFireUnderwater = false -- This weapon can shoot while underwater.
|
||||
|
||||
SWEP.Disposable = false -- When all ammo is expended, this gun will remove itself from the inventory.
|
||||
|
||||
SWEP.AutoReload = false -- When the gun is drawn, it will automatically reload.
|
||||
|
||||
SWEP.TriggerDelay = 0 -- Set to > 0 to play the "trigger" animation before shooting. Delay time is based on this value.
|
||||
|
||||
SWEP.DropMagazineModel = nil -- Set to a string or table to drop this magazine when reloading.
|
||||
SWEP.DropMagazineSounds = {} -- Table of sounds a dropped magazine should play.
|
||||
SWEP.DropMagazineAmount = 1 -- Amount of mags to drop.
|
||||
|
||||
-------------------------- FIREMODES
|
||||
|
||||
SWEP.RPM = 750
|
||||
|
||||
// Works different to ArcCW
|
||||
|
||||
// -1: Automatic
|
||||
// 0: Safe. Don't use this for safety.
|
||||
// 1: Semi.
|
||||
// 2: Two-round burst.
|
||||
// 3: Three-round burst.
|
||||
// n: n-round burst.
|
||||
SWEP.Firemodes = {
|
||||
{
|
||||
Mode = 1,
|
||||
// add other attachment modifiers
|
||||
}
|
||||
}
|
||||
|
||||
SWEP.AutoBurst = false -- Hold fire to keep firing bursts
|
||||
SWEP.PostBurstDelay = 0
|
||||
SWEP.RunAwayBurst = false -- Burst will keep firing until all of the burst has been expended.
|
||||
SWEP.NonResetBurst = false -- Annoying behaviour where you have to shoot ALL THREE BULLETS of a burst before it resets. Supposedly realistic for the M16.
|
||||
|
||||
SWEP.Akimbo = false
|
||||
|
||||
-- Use this hook to modify features of a firemode.
|
||||
-- SWEP.HookP_ModifyFiremode = function(self, firemode) return firemode end
|
||||
|
||||
-------------------------- RECOIL
|
||||
|
||||
SWEP.RecoilSeed = nil -- Leave blank to use weapon class name as recoil seed.
|
||||
-- Should be a number.
|
||||
SWEP.RecoilLookupTable = nil -- Use to set specific values for predictible recoil. If it runs out, it'll just use Recoil Seed.
|
||||
-- SWEP.RecoilLookupTable = {
|
||||
-- {
|
||||
-- x = -1,
|
||||
-- y = 1
|
||||
-- }
|
||||
-- }
|
||||
SWEP.RecoilLookupTableOverrun = nil -- Repeatedly take values from this table if we run out in the main table
|
||||
|
||||
-- General recoil multiplier
|
||||
SWEP.Recoil = 1
|
||||
|
||||
-- These multipliers affect the predictible recoil by making the pattern taller, shorter, wider, or thinner.
|
||||
SWEP.RecoilUp = 1 -- Multiplier for vertical recoil
|
||||
SWEP.RecoilSide = 1 -- Multiplier for vertical recoil
|
||||
|
||||
-- These values determine how much extra movement is applied to the recoil entirely randomly, like in a circle.
|
||||
-- This type of recoil CANNOT be predicted.
|
||||
SWEP.RecoilRandomUp = 0.1
|
||||
SWEP.RecoilRandomSide = 0.1
|
||||
|
||||
SWEP.RecoilDissipationRate = 10 -- How much recoil dissipates per second.
|
||||
SWEP.RecoilResetTime = 0.1 -- How long the gun must go before the recoil pattern starts to reset.
|
||||
|
||||
SWEP.RecoilAutoControl = 1 -- Multiplier for automatic recoil control.
|
||||
|
||||
-------------------------- VISUAL RECOIL
|
||||
|
||||
SWEP.UseVisualRecoil = true
|
||||
|
||||
SWEP.VisualRecoilUp = 0.15 -- Vertical tilt for visual recoil.
|
||||
SWEP.VisualRecoilSide = 0.1 -- Horizontal tilt for visual recoil.
|
||||
SWEP.VisualRecoilRoll = 1 -- Roll tilt for visual recoil.
|
||||
|
||||
SWEP.VisualRecoilCenter = Vector(0, 2, 2) -- The "axis" of visual recoil. Where your hand is.
|
||||
|
||||
SWEP.VisualRecoilPunch = 1 -- How far back visual recoil moves the gun.
|
||||
|
||||
SWEP.VisualRecoilMultSights = 0.25 -- Visual recoil multiplier while in sights.
|
||||
|
||||
SWEP.RecoilKick = 1 -- Camera recoil
|
||||
|
||||
-------------------------- SPREAD
|
||||
|
||||
SWEP.Spread = 0
|
||||
|
||||
SWEP.UsePelletSpread = false -- Multiple bullets fired at once clump up, like for a shotgun. Spread affects which direction they get fired, not their spread relative to one another.
|
||||
SWEP.PelletSpread = 0.2
|
||||
|
||||
SWEP.PelletSpreadPattern = {} -- Use to give shotguns custom spread patterns. If Pellet Spread is off, each pellet will be subject to spread. Otherwise, the entire pattern shifts, and each pellet is randomly offset by pellet spread amount.
|
||||
|
||||
-- SWEP.PelletSpreadPattern = {
|
||||
-- {
|
||||
-- x = -1,
|
||||
-- y = -1
|
||||
-- },
|
||||
-- {
|
||||
-- x = -1,
|
||||
-- y = 1
|
||||
-- }
|
||||
-- }
|
||||
|
||||
SWEP.PelletSpreadPatternOverrun = nil
|
||||
-- {Angle(1, 1, 0), Angle(1, 0, 0) ..}
|
||||
-- list of how far each pellet should veer
|
||||
-- if only one pellet then it'll use the first index
|
||||
-- if two then the first two
|
||||
-- in case of overrun pellets will start looping, preferably with the second one, so use that for the loopables
|
||||
|
||||
SWEP.SpreadAddMove = 0 -- Applied when speed is equal to walking speed.
|
||||
SWEP.SpreadAddMidAir = 0 -- Applied when not touching the ground.
|
||||
SWEP.SpreadAddHipFire = 0 -- Applied when not sighted.
|
||||
SWEP.SpreadAddSighted = 0 -- Applied when sighted. Can be negative.
|
||||
SWEP.SpreadAddBlindFire = 0 -- Applied when blind firing.
|
||||
SWEP.SpreadAddCrouch = 0 -- Applied when crouching.
|
||||
|
||||
SWEP.SpreadAddRecoil = 0 -- Applied per unit of recoil.
|
||||
|
||||
-------------------------- HANDLING
|
||||
|
||||
SWEP.FreeAimRadius = 10 -- In degrees, how much this gun can free aim in hip fire.
|
||||
SWEP.Sway = 1 -- How much the gun sways.
|
||||
|
||||
SWEP.FreeAimMultSights = 0.25
|
||||
|
||||
SWEP.SwayMultSights = 0.5
|
||||
|
||||
SWEP.AimDownSightsTime = 0.25 -- How long it takes to go from hip fire to aiming down sights.
|
||||
SWEP.SprintToFireTime = 0.25 -- How long it takes to go from sprinting to being able to fire.
|
||||
|
||||
SWEP.ReloadTimeMult = 1
|
||||
SWEP.DeployTimeMult = 1
|
||||
SWEP.CycleTimeMult = 1
|
||||
SWEP.FixTimeMult = 1
|
||||
SWEP.OverheatTimeMult = 1
|
||||
|
||||
SWEP.ShootWhileSprint = false
|
||||
|
||||
SWEP.SpeedMult = 1
|
||||
SWEP.SpeedMultSights = 0.75
|
||||
SWEP.SpeedMultShooting = 1
|
||||
SWEP.SpeedMultMelee = 0.75
|
||||
SWEP.SpeedMultCrouch = 1
|
||||
SWEP.SpeedMultBlindFire = 1
|
||||
|
||||
-------------------------- MALFUNCTIONS
|
||||
|
||||
SWEP.Overheat = false -- Weapon will jam when it overheats, playing the "overheat" animation.
|
||||
SWEP.HeatCapacity = 50 -- rounds that can be fired non-stop before the gun jams, playing the "fix" animation
|
||||
SWEP.HeatDissipation = 10 -- rounds' worth of heat lost per second
|
||||
SWEP.HeatLockout = true -- overheating means you cannot fire until heat has been fully depleted
|
||||
SWEP.HeatDelayTime = 0.5 -- Amount of time that passes before heat begins to dissipate.
|
||||
SWEP.HeatFix = false -- when the "overheat" animation is played, all heat is restored.
|
||||
|
||||
-- If Malfunction is enabled, the gun has a random chance to be jammed
|
||||
-- after the gun is jammed, it won't fire unless reload is pressed, which plays the "fix" animation
|
||||
-- if no "fix" or "cycle" animations exist, the weapon will reload instead
|
||||
-- When the trigger is pressed, the gun will try to play the "jamfire" animation. Otherwise, it will try "dryfire". Otherwise, it will do nothing.
|
||||
SWEP.Malfunction = false
|
||||
SWEP.MalfunctionJam = true -- After a malfunction happens, the gun will dryfire until reload is pressed. If unset, instead plays animation right after.
|
||||
SWEP.MalfunctionTakeRound = true -- When malfunctioning, a bullet is consumed.
|
||||
SWEP.MalfunctionWait = 0.25 -- The amount of time to wait before playing malfunction animation (or can reload)
|
||||
SWEP.MalfunctionMeanShotsToFail = 1000 -- The mean number of shots between malfunctions, will be autocalculated if nil
|
||||
|
||||
-------------------------- HOOKS
|
||||
|
||||
-- SWEP.Hook_Draw = function(self, vm) end # Called when the weapon is drawn. Call functions here to modify the viewmodel, such as drawing RT screens onto the gun.
|
||||
-- SWEP.Hook_HUDPaint = function(self) end
|
||||
-- SWEP.HookP_ModifyFiremode = function(self, firemode) return firemode end
|
||||
-- SWEP.HookP_ModifyBullet = function(self, bullet) return end # bullet = phys bullet table, modify in place, does not accept return
|
||||
-- SWEP.HookP_BlockFire = function(self) return block end # return true to block firing
|
||||
|
||||
-------------------------- BLIND FIRE
|
||||
|
||||
SWEP.CanBlindFire = true -- This weapon is capable of blind firing.
|
||||
SWEP.BlindFireOffset = Vector(0, 0, 16) -- The amount by which to offset the blind fire muzzle.
|
||||
SWEP.BlindFirePos = Vector(1, -2, 0)
|
||||
SWEP.BlindFireAng = Angle(0, 15, 0)
|
||||
SWEP.BlindFireBoneMods = {
|
||||
["ValveBiped.Bip01_R_UpperArm"] = {
|
||||
ang = Angle(25, -50, 0),
|
||||
pos = Vector(0, 0, 0)
|
||||
},
|
||||
["ValveBiped.Bip01_R_Hand"] = {
|
||||
ang = Angle(-50, 0, 0),
|
||||
pos = Vector(0, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
-------------------------- NPC
|
||||
|
||||
SWEP.NotForNPCs = false -- Won't be given to NPCs.
|
||||
SWEP.NPCWeight = 100 -- How likely it is for an NPC to get this weapon as opposed to other weapons.
|
||||
|
||||
-------------------------- BIPOD
|
||||
|
||||
SWEP.Bipod = false -- This weapon comes with a bipod.
|
||||
-- When bipod is deployed, the gun does not experience recoil.
|
||||
SWEP.BipodSpreadPenalty = 0
|
||||
SWEP.BipodSpreadMult = 0.25
|
||||
|
||||
-------------------------- SOUNDS
|
||||
|
||||
SWEP.ShootVolume = 125
|
||||
SWEP.ShootPitch = 100
|
||||
SWEP.ShootPitchVariation = 0.05
|
||||
|
||||
SWEP.FirstShootSound = nil
|
||||
SWEP.ShootSound = ""
|
||||
SWEP.FirstShootSoundSilenced = nil
|
||||
SWEP.ShootSoundSilenced = ""
|
||||
SWEP.FirstShootSoundIndoor = nil
|
||||
SWEP.ShootSoundIndoor = nil
|
||||
SWEP.FirstShootSoundSilencedIndoor = nil
|
||||
SWEP.ShootSoundSilencedIndoor = nil
|
||||
SWEP.ShootSoundLooping = nil
|
||||
SWEP.ShootSoundLoopingSilenced = nil
|
||||
|
||||
SWEP.Silencer = false -- Silencer installed or not?
|
||||
|
||||
SWEP.DistantShootSound = nil
|
||||
|
||||
SWEP.DryFireSound = ""
|
||||
|
||||
SWEP.FiremodeSound = ""
|
||||
|
||||
SWEP.EnterSightsSound = ""
|
||||
SWEP.ExitSightsSound = ""
|
||||
|
||||
SWEP.EnterBipodSound = ""
|
||||
SWEP.ExitBipodSound = ""
|
||||
|
||||
SWEP.SelectUBGLSound = ""
|
||||
SWEP.ExitUBGLSound = ""
|
||||
|
||||
SWEP.MalfunctionSound = ""
|
||||
|
||||
-------------------------- EFFECTS
|
||||
|
||||
SWEP.NoFlash = false -- Disable light flash
|
||||
|
||||
SWEP.MuzzleParticle = "" -- Used for some muzzle effects.
|
||||
|
||||
SWEP.MuzzleEffect = nil
|
||||
SWEP.FastMuzzleEffect = nil
|
||||
|
||||
SWEP.ImpactEffect = nil
|
||||
SWEP.ImpactDecal = nil
|
||||
|
||||
SWEP.ShellEffect = nil -- Override the ARC9 shell eject effect for your own.
|
||||
|
||||
SWEP.ShellModel = "models/shells/shell_556.mdl"
|
||||
SWEP.ShellMaterial = nil
|
||||
|
||||
SWEP.EjectDelay = 0
|
||||
|
||||
SWEP.ShellScale = Vector(1, 1, 1)
|
||||
SWEP.ShellPhysBox = Vector(0.5, 0.5, 2)
|
||||
|
||||
SWEP.ShellPitch = 100 -- for shell sounds
|
||||
SWEP.ShellSounds = ArcCW.ShellSoundsTable
|
||||
|
||||
SWEP.ShellCorrectPos = Vector(0, 0, 0)
|
||||
SWEP.ShellCorrectAng = Angle(0, 0, 0)
|
||||
SWEP.ShellTime = 0.5 -- Extra time these shells stay on the ground for.
|
||||
|
||||
SWEP.MuzzleEffectQCA = 1 -- QC Attachment that controls muzzle effect.
|
||||
SWEP.CaseEffectQCA = 2 -- QC Attachment for shell ejection.
|
||||
SWEP.CamQCA = nil -- QC Attachment for camera movement.
|
||||
SWEP.ProceduralViewQCA = nil -- QC Attachment for procedural camera movement. Use if you don't have a camera. Usually the muzzle.
|
||||
|
||||
-------------------------- VISUALS
|
||||
|
||||
SWEP.BulletBones = { -- the bone that represents bullets in gun/mag
|
||||
-- [0] = "bulletchamber",
|
||||
-- [1] = "bullet1"
|
||||
}
|
||||
SWEP.CaseBones = {}
|
||||
-- Unlike BulletBones, these bones are determined by the missing bullet amount when reloading
|
||||
SWEP.StripperClipBones = {}
|
||||
|
||||
-- The same as the bone versions but works via bodygroups.
|
||||
-- Bodygroups work the same as in attachmentelements.
|
||||
-- [0] = {ind = 0, bg = 1}
|
||||
SWEP.BulletBGs = {}
|
||||
SWEP.CaseBGs = {}
|
||||
SWEP.StripperClipBGs = {}
|
||||
|
||||
SWEP.PoseParameters = {} -- Poseparameters to manage. ["parameter"] = starting value.
|
||||
-- Use animations to switch between different pose parameters.
|
||||
-- When an animation is being played that switches between pose parameters, those parameters are all set to 0 for the animation.
|
||||
-- There are also different default pose parameters:
|
||||
-- firemode (Changes based on Fire Mode. Don't use this if you have animated firemode switching.)
|
||||
-- sights (Changes based on sight delta)
|
||||
-- sprint (Changes based on sprint delta)
|
||||
-- empty (Changes based on whether a bullet is loaded)
|
||||
-- ammo (Changes based on the ammo in the clip)
|
||||
|
||||
-------------------------- POSITIONS
|
||||
|
||||
SWEP.IronSights = {
|
||||
Pos = Vector(0, 0, 0),
|
||||
Ang = Angle(0, 0, 0),
|
||||
Magnification = 1,
|
||||
AssociatedSlot = 0, -- Attachment slot to associate the sights with. Causes RT scopes to render.
|
||||
CrosshairInSights = false,
|
||||
}
|
||||
|
||||
SWEP.SightMidpoint = { -- Where the gun should be at the middle of it's irons
|
||||
Pos = Vector(0, 15, -4),
|
||||
Ang = Angle(0, 0, -45),
|
||||
}
|
||||
|
||||
SWEP.HasSights = true
|
||||
|
||||
-- Alternative "resting" position
|
||||
SWEP.ActivePos = Vector(0, 0, 0)
|
||||
SWEP.ActiveAng = Angle(0, 0, 0)
|
||||
|
||||
-- Position when sprinting or holstered
|
||||
SWEP.HolsterPos = Vector(0.532, -6, 0)
|
||||
SWEP.HolsterAng = Angle(-4.633, 36.881, 0)
|
||||
|
||||
-- Overrides HolsterPos/Ang but only for sprinting
|
||||
SWEP.SprintPos = nil
|
||||
SWEP.SprintAng = nil
|
||||
|
||||
SWEP.SprintMidPoint = {
|
||||
pos = Vector(4, 10, 2),
|
||||
ang = Angle(0, -10, -45)
|
||||
}
|
||||
|
||||
-- Position for customizing
|
||||
SWEP.CustomizeAng = Angle(90, 0, 0)
|
||||
SWEP.CustomizePos = Vector(20, 32, 4)
|
||||
|
||||
SWEP.InBipodPos = Vector(-8, 0, -4)
|
||||
SWEP.InBipodMult = Vector(2, 1, 1)
|
||||
|
||||
-------------------------- HoldTypeS
|
||||
|
||||
SWEP.HoldType = "shotgun"
|
||||
SWEP.HoldTypeSprint = "passive"
|
||||
SWEP.HoldTypeHolstered = nil
|
||||
SWEP.HoldTypeSights = "smg"
|
||||
SWEP.HoldTypeCustomize = "slam"
|
||||
SWEP.HoldTypeBlindfire = "pistol"
|
||||
SWEP.HoldTypeNPC = nil
|
||||
|
||||
SWEP.AnimShoot = ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2
|
||||
SWEP.AnimReload = ACT_HL2MP_GESTURE_RELOAD_AR2
|
||||
SWEP.AnimDraw = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE
|
||||
|
||||
-------------------------- TTT
|
||||
|
||||
-- No free attachments when this gun is purchased
|
||||
SWEP.TTTNoAttachmentsOnBuy = false
|
||||
|
||||
-- Automatically spawn in TTT
|
||||
SWEP.TTTAutospawn = true
|
||||
|
||||
-- Specifically replace a certain weapon in TTT
|
||||
SWEP.TTTWeaponType = nil
|
||||
|
||||
-- The chance this weapon will spawn in TTT
|
||||
SWEP.TTTWeight = 100
|
||||
|
||||
-- Use a different ammo type in TTT
|
||||
SWEP.TTTAmmoType = nil
|
||||
|
||||
-------------------------- ATTACHMENTS
|
||||
|
||||
SWEP.AttachmentBodygroups = {
|
||||
-- ["name"] = {
|
||||
-- VM = {
|
||||
-- {
|
||||
-- ind = 1,
|
||||
-- bg = 1
|
||||
-- }
|
||||
-- },
|
||||
-- WM = {
|
||||
-- {
|
||||
-- ind = 1,
|
||||
-- bg = 1
|
||||
-- }
|
||||
-- },
|
||||
-- }
|
||||
}
|
||||
|
||||
-- Activate attachment elements by default.
|
||||
SWEP.DefaultElements = {}
|
||||
|
||||
-- Allows for the attachment of models and stuff, like SCK.
|
||||
-- You can use SCK to get the positions and angles for this.
|
||||
-- Not recommended to be used.
|
||||
SWEP.AttachmentElements = {
|
||||
-- ["name"] = {
|
||||
-- VM = {
|
||||
-- model = "",
|
||||
-- color = Color(255, 255, 255),
|
||||
-- skin = 0,
|
||||
-- bodygroups = "",
|
||||
-- scale = Vector(1, 1 ,1),
|
||||
-- bone = "",
|
||||
-- pos = Vector(0, 0, 0),
|
||||
-- ang = Angle(0, 0, 0),
|
||||
-- },
|
||||
-- WM = {
|
||||
-- model = "",
|
||||
-- color = Color(255, 255, 255),
|
||||
-- skin = 0,
|
||||
-- bodygroups = "",
|
||||
-- scale = Vector(1, 1 ,1),
|
||||
-- bone = "",
|
||||
-- pos = Vector(0, 0, 0),
|
||||
-- ang = Angle(0, 0, 0),
|
||||
-- }
|
||||
-- }
|
||||
}
|
||||
|
||||
-- Use to override attachment table entry data.
|
||||
SWEP.AttachmentSlotMods = {
|
||||
-- ["name"] = {
|
||||
-- [1] = {
|
||||
-- }
|
||||
-- }
|
||||
}
|
||||
|
||||
-- Adjust the stats of specific attachments when applied to this gun
|
||||
SWEP.AttachmentTableOverrides = {
|
||||
-- ["att_name"] = {
|
||||
-- Mult_Recoil = 1
|
||||
-- }
|
||||
}
|
||||
|
||||
-- Specifically refuse to allow certain attachments to be attached
|
||||
SWEP.RejectAttachments = {
|
||||
-- ["att_name"] = true
|
||||
}
|
||||
|
||||
-- The big one
|
||||
SWEP.Attachments = {
|
||||
-- [1] = {
|
||||
-- PrintName = "",
|
||||
-- DefaultIcon = Material(""),
|
||||
-- InstalledElements = {""}, // list of elements to activate when something is installed here
|
||||
-- UnInstalledElements = {""},
|
||||
-- RequireElements = {}, // {{a and b}, or {c and d and e}, or f}
|
||||
-- // list of "strings" or {"lists", "of", "strings"}.
|
||||
-- // one of these must all be enabled for this to be valid.
|
||||
-- ExcludeElements = {},
|
||||
-- // same but for exclusion.
|
||||
-- Integral = false, // cannot be removed
|
||||
-- Category = "", // single or {"list", "of", "values"}
|
||||
-- Bone = "",
|
||||
-- Pos = Vector(0, 0, 0),
|
||||
-- Ang = Angle(0, 0, 0),
|
||||
-- KeepBaseIrons = false,
|
||||
-- ExtraSightDistance = 0,
|
||||
-- Installed = nil,
|
||||
-- MergeSlots = {},
|
||||
-- SubAttachments = {
|
||||
-- {
|
||||
-- Installed = nil,
|
||||
-- SubAttachments = {}
|
||||
-- },
|
||||
-- {
|
||||
-- Installed = nil,
|
||||
-- SubAttachments = {}
|
||||
-- }
|
||||
-- }
|
||||
-- }
|
||||
-- }
|
||||
}
|
||||
|
||||
-- Not necessary; if your sequences are named the same as animations, they will be used automatically.
|
||||
|
||||
SWEP.Animations = {
|
||||
-- ["idle"] = {
|
||||
-- Source = "idle",
|
||||
-- Mult = 1.1,
|
||||
-- },
|
||||
-- ["draw"] = {
|
||||
-- Source = {"deploy", "deploy2"}, -- QC sequence source, can be {"table", "of", "strings"} or "string"
|
||||
-- RareSource = "magicdeploy", -- Has a small chance to play instead of normal source
|
||||
-- RareSourceChance = 0.01, -- chance that rare source will play
|
||||
-- Time = 0.5, -- overrides the duration of the sequence
|
||||
-- Mult = 1, -- multiplies time
|
||||
-- LHIK = false,
|
||||
-- LHIKTimeline = {
|
||||
-- {
|
||||
-- t = 0.1,
|
||||
-- ik = 0
|
||||
-- },
|
||||
-- {
|
||||
-- t = 0.9,
|
||||
-- ik = 1
|
||||
-- }
|
||||
-- },
|
||||
-- RHIK = false,
|
||||
-- RHIKTimeline = {
|
||||
-- {
|
||||
-- t = 0.1,
|
||||
-- ik = 0
|
||||
-- },
|
||||
-- {
|
||||
-- t = 0.9,
|
||||
-- ik = 1
|
||||
-- }
|
||||
-- },
|
||||
-- EventTable = {
|
||||
-- {
|
||||
-- t = 1, -- in seconds
|
||||
-- s = "", -- sound to play
|
||||
-- chan = CHAN_ITEM, -- sound channel
|
||||
-- e = "", -- effect to emit
|
||||
-- att = nil, -- on attachment point X
|
||||
-- mag = 100, -- with magnitude whatever this is
|
||||
-- ind = 0, -- change bodygroup
|
||||
-- bg = 0,
|
||||
-- }
|
||||
-- },
|
||||
-- PoseParamChanges = { -- pose parameters to change after this animation is done.
|
||||
-- ["selector"] = 1 -- an application might be to change firemodes.
|
||||
-- }, -- relevant pose parameters will be set to default values while the animation is playing, so make sure you take that into consideration for animating.
|
||||
-- MagSwapTime = 0.5, -- in seconds, how long before the new magazine replaces the old one.
|
||||
-- MinProgress = 0, -- seconds that must pass before the reload is considered done
|
||||
-- }
|
||||
}
|
||||
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
|
||||
SWEP.DrawCrosshair = true
|
||||
|
||||
SWEP.ARC9 = true
|
||||
|
||||
local searchdir = "weapons/arc9_base"
|
||||
|
||||
local function autoinclude(dir)
|
||||
local files, dirs = file.Find(searchdir .. "/*.lua", "LUA")
|
||||
|
||||
for _, filename in pairs(files) do
|
||||
if filename == "shared.lua" then continue end
|
||||
local luatype = string.sub(filename, 1, 2)
|
||||
|
||||
if luatype == "sv" then
|
||||
if SERVER then
|
||||
include(dir .. "/" .. filename)
|
||||
end
|
||||
elseif luatype == "cl" then
|
||||
AddCSLuaFile(dir .. "/" .. filename)
|
||||
if CLIENT then
|
||||
include(dir .. "/" .. filename)
|
||||
end
|
||||
else
|
||||
AddCSLuaFile(dir .. "/" .. filename)
|
||||
include(dir .. "/" .. filename)
|
||||
end
|
||||
end
|
||||
|
||||
for _, path in pairs(dirs) do
|
||||
autoinclude(dir .. "/" .. path)
|
||||
end
|
||||
end
|
||||
|
||||
autoinclude(searchdir)
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:NetworkVar("Float", 0, "RecoilAmount")
|
||||
self:NetworkVar("Float", 1, "AnimLockTime")
|
||||
self:NetworkVar("Float", 2, "NextIdle")
|
||||
self:NetworkVar("Float", 3, "LastRecoilTime")
|
||||
self:NetworkVar("Float", 4, "RecoilUp")
|
||||
self:NetworkVar("Float", 5, "RecoilSide")
|
||||
self:NetworkVar("Float", 6, "SprintAmount")
|
||||
self:NetworkVar("Float", 7, "LastMeleeTime")
|
||||
self:NetworkVar("Float", 8, "PrimedAttackTime")
|
||||
self:NetworkVar("Float", 9, "StartPrimedAttackTime")
|
||||
self:NetworkVar("Float", 10, "ReloadFinishTime")
|
||||
self:NetworkVar("Float", 11, "SightAmount")
|
||||
self:NetworkVar("Float", 12, "HeatAmount")
|
||||
self:NetworkVar("Float", 13, "BlindFireAmount")
|
||||
|
||||
self:NetworkVar("Int", 0, "BurstCount")
|
||||
self:NetworkVar("Int", 1, "NthShot")
|
||||
self:NetworkVar("Int", 2, "LoadedRounds")
|
||||
self:NetworkVar("Int", 3, "Firemode")
|
||||
self:NetworkVar("Int", 4, "NthReload")
|
||||
|
||||
self:NetworkVar("Bool", 0, "Customize")
|
||||
self:NetworkVar("Bool", 1, "Reloading")
|
||||
self:NetworkVar("Bool", 2, "EndReload")
|
||||
self:NetworkVar("Bool", 3, "Safe")
|
||||
self:NetworkVar("Bool", 4, "Jammed")
|
||||
self:NetworkVar("Bool", 5, "Ready")
|
||||
self:NetworkVar("Bool", 6, "TriggerDown")
|
||||
self:NetworkVar("Bool", 7, "NeedTriggerPress")
|
||||
self:NetworkVar("Bool", 8, "UBGL")
|
||||
self:NetworkVar("Bool", 9, "EmptyReload")
|
||||
self:NetworkVar("Bool", 10, "InSights")
|
||||
self:NetworkVar("Bool", 11, "PrimedAttack")
|
||||
self:NetworkVar("Bool", 12, "BlindFire")
|
||||
self:NetworkVar("Bool", 13, "BlindFireLeft")
|
||||
|
||||
self:NetworkVar("Angle", 0, "FreeAimAngle")
|
||||
self:NetworkVar("Angle", 1, "LastAimAngle")
|
||||
|
||||
self:SetFiremode(1)
|
||||
self:SetNthReload(0)
|
||||
self:SetNthShot(0)
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
end
|
Loading…
Reference in New Issue
Block a user