Attempting to create a new Weapon.

devnunuxdevnunux France Join Date: 2013-10-29 Member: 188866Members
Hello guys,

I've started learning lua so i can start modding natural selection 2. Now that learning lua is done, I've setup my modding environment and made some really (really) minor modification to the code (such as print something in the console when you shoot with a certain weapon, and stuff like that).
So, yesterday I decided it was time to make something a bit more difficult : I've decided to add a new weapon to the game (modify an existing weapon : i kept the shotgun model and sounds, but tried to modify its properties).

Here is what i've done yet :
--> I've created a new lua file call : WeirdShotgun.lua
--> I added Script.Load("lua/WeirdShotgun.lua") in ModShared.lua
--> In WeirdShotgun.lua, i created a WeirdShotgun class :
Script.Load("lua/Balance.lua")
Script.Load("lua/LiveMixin.lua")
Script.Load("lua/Weapons/Marine/ClipWeapon.lua")
Script.Load("lua/PickupableWeaponMixin.lua")
Script.Load("lua/PointGiverMixin.lua")

class 'WeirdShotgun' (ClipWeapon)

WeirdShotgun.kMapName = "weirdshotgun"

local kBulletSize = 0.016

local networkVars =
{
    emptyPoseParam = "private float (0 to 1 by 0.01)"
}

AddMixinNetworkVars(LiveMixin, networkVars)

// higher numbers reduces the spread
local kSpreadDistance = 10
local kStartOffset = 0
local kSpreadVectors =
{
    GetNormalizedVector(Vector(-0.01, 0.01, kSpreadDistance)),
    
    GetNormalizedVector(Vector(-0.45, 0.45, kSpreadDistance)),
    GetNormalizedVector(Vector(0.45, 0.45, kSpreadDistance)),
    GetNormalizedVector(Vector(0.45, -0.45, kSpreadDistance)),
    GetNormalizedVector(Vector(-0.45, -0.45, kSpreadDistance)),
    
    GetNormalizedVector(Vector(-1, 0, kSpreadDistance)),
    GetNormalizedVector(Vector(1, 0, kSpreadDistance)),
    GetNormalizedVector(Vector(0, -1, kSpreadDistance)),
    GetNormalizedVector(Vector(0, 1, kSpreadDistance)),
    
    GetNormalizedVector(Vector(-0.35, 0, kSpreadDistance)),
    GetNormalizedVector(Vector(0.35, 0, kSpreadDistance)),
    GetNormalizedVector(Vector(0, -0.35, kSpreadDistance)),
    GetNormalizedVector(Vector(0, 0.35, kSpreadDistance)),
    
    GetNormalizedVector(Vector(-0.8, -0.8, kSpreadDistance)),
    GetNormalizedVector(Vector(-0.8, 0.8, kSpreadDistance)),
    GetNormalizedVector(Vector(0.8, 0.8, kSpreadDistance)),
    GetNormalizedVector(Vector(0.8, -0.8, kSpreadDistance)),
    
}

WeirdShotgun.kModelName = PrecacheAsset("models/marine/shotgun/shotgun.model")
local kViewModels = GenerateMarineViewModelPaths("shotgun")
local kAnimationGraph = PrecacheAsset("models/marine/shotgun/shotgun_view.animation_graph")

local kMuzzleEffect = PrecacheAsset("cinematics/marine/shotgun/muzzle_flash.cinematic")
local kMuzzleAttachPoint = "fxnode_shotgunmuzzle"

function WeirdShotgun:OnCreate()

    ClipWeapon.OnCreate(self)
    
    InitMixin(self, PickupableWeaponMixin)
    InitMixin(self, LiveMixin)
    InitMixin(self, PointGiverMixin)
    
    self.emptyPoseParam = 0

end

if Client then

    function WeirdShotgun:OnInitialized()
    
        ClipWeapon.OnInitialized(self)
    
    end

end

function WeirdShotgun:GetAnimationGraphName()
    return kAnimationGraph
end

function WeirdShotgun:GetViewModelName(sex, variant)
    return kViewModels[sex][variant]
end

function WeirdShotgun:GetDeathIconIndex()
    return kDeathMessageIcon.Shotgun
end

function WeirdShotgun:GetHUDSlot()
    return kPrimaryWeaponSlot
end

function WeirdShotgun:GetClipSize()
    return kShotgunClipSize
end

function WeirdShotgun:GetBulletsPerShot()
    return kShotgunBulletsPerShot
end

function WeirdShotgun:GetRange()
    return 100
end

// Only play weapon effects every other bullet to avoid sonic overload
function WeirdShotgun:GetTracerEffectFrequency()
    return 0.5
end

function WeirdShotgun:GetBulletDamage()
    return kShotgunDamage    
end

function WeirdShotgun:GetHasSecondary(player)
    return false
end

function WeirdShotgun:GetPrimaryCanInterruptReload()
    return true
end

function WeirdShotgun:GetWeight()
    return kShotgunWeight
end

function WeirdShotgun:UpdateViewModelPoseParameters(viewModel)

    viewModel:SetPoseParam("empty", self.emptyPoseParam)
    
end

local function LoadBullet(self)

    if self.ammo > 0 and self.clip < self:GetClipSize() then
    
        self.clip = self.clip + 1
        self.ammo = self.ammo - 1
        
    end
    
end

function WeirdShotgun:OnTag(tagName)

    PROFILE("Shotgun:OnTag")
    
    local continueReloading = false
    if self:GetIsReloading() and tagName == "reload_end" then
    
        continueReloading = true
        self.reloading = false
        
    end
    
    if tagName == "end" then
        self.primaryAttacking = false
    end
    
    ClipWeapon.OnTag(self, tagName)
    
    if tagName == "load_shell" then
        LoadBullet(self)
    elseif tagName == "reload_shotgun_start" then
        self:TriggerEffects("shotgun_reload_start")
    elseif tagName == "reload_shotgun_shell" then
        self:TriggerEffects("shotgun_reload_shell")
    elseif tagName == "reload_shotgun_end" then
        self:TriggerEffects("shotgun_reload_end")
    end
    
    if continueReloading then
    
        local player = self:GetParent()
        if player then
            player:Reload()
        end
        
    end
    
end

// used for last effect
function WeirdShotgun:GetEffectParams(tableParams)
    tableParams[kEffectFilterEmpty] = self.clip == 1
end

function WeirdShotgun:FirePrimary(player)

    local viewAngles = player:GetViewAngles()
    viewAngles.roll = NetworkRandom() * math.pi * 2
    
    local shootCoords = viewAngles:GetCoords()

    // Filter ourself out of the trace so that we don't hit ourselves.
    local filter = EntityFilterTwo(player, self)
    local range = self:GetRange()
    
    if GetIsVortexed(player) then
        range = 5
    end
    
    local numberBullets = self:GetBulletsPerShot()
    local startPoint = player:GetEyePos()
    /*
    local weaponUpgradeLevel = player.GetWeaponUpgradeLevel and player:GetWeaponUpgradeLevel() or 0
    local soundEffectName = "shotgun_attack_sound"
    
    if self.clip == 1 then
        soundEffectName = "shotgun_attack_sound_last"
    elseif weaponUpgradeLevel == 3 then
        soundEffectName = "shotgun_attack_sound_max"
    elseif weaponUpgradeLevel == 2 then
        soundEffectName = "shotgun_attack_sound_medium"
    end
    
    DebugPrint("shotgun soundEffectName %s", soundEffectName)
    */
    
    self:TriggerEffects("shotgun_attack_sound")
    self:TriggerEffects("shotgun_attack")
    
    for bullet = 1, math.min(numberBullets, #kSpreadVectors) do
    
        if not kSpreadVectors[bullet] then
            break
        end    
    
        local spreadDirection = shootCoords:TransformVector(kSpreadVectors[bullet])

        local endPoint = startPoint + spreadDirection * range
        startPoint = player:GetEyePos() + shootCoords.xAxis * kSpreadVectors[bullet].x * kStartOffset + shootCoords.yAxis * kSpreadVectors[bullet].y * kStartOffset
        
        local trace = Shared.TraceRay(startPoint, endPoint, CollisionRep.Damage, PhysicsMask.Bullets, filter)
        if not trace.entity then
        
            -- Limit the box trace to the point where the ray hit as an optimization.
            local boxTraceEndPoint = trace.fraction ~= 1 and trace.endPoint or endPoint
            local extents = GetDirectedExtentsForDiameter(spreadDirection, kBulletSize)
            trace = Shared.TraceBox(extents, startPoint, boxTraceEndPoint, CollisionRep.Damage, PhysicsMask.Bullets, filter)
            
        end
        
        local damage = 0

        /*
        // Check prediction
        local values = GetPredictionValues(startPoint, endPoint, trace)
        if not CheckPredictionData( string.format("attack%d", bullet), true, values ) then
            Server.PlayPrivateSound(player, "sound/NS2.fev/marine/voiceovers/game_start", player, 1.0, Vector(0, 0, 0))
        end
        */
            
        // don't damage 'air'..
        if trace.fraction < 1 or GetIsVortexed(player) then
        
            local direction = (trace.endPoint - startPoint):GetUnit()
            local impactPoint = trace.endPoint - direction * kHitEffectOffset
            local surfaceName = trace.surface

            local effectFrequency = self:GetTracerEffectFrequency()
            local showTracer = bullet % effectFrequency == 0
            
            self:ApplyBulletGameplayEffects(player, trace.entity, impactPoint, direction, kShotgunDamage, trace.surface, showTracer)
            
            if Client and showTracer then
                TriggerFirstPersonTracer(self, trace.endPoint)
            end
            
        end
        
        local client = Server and player:GetClient() or Client
        if not Shared.GetIsRunningPrediction() and client.hitRegEnabled then
            RegisterHitEvent(player, bullet, startPoint, trace, damage)
        end
        
    end
    
    TEST_EVENT("Shotgun primary attack")
    
end

function WeirdShotgun:OnProcessMove(input)
    ClipWeapon.OnProcessMove(self, input)
    self.emptyPoseParam = Clamp(Slerp(self.emptyPoseParam, ConditionalValue(self.clip == 0, 1, 0), input.time * 1), 0, 1)
end

function WeirdShotgun:GetAmmoPackMapName()
    return ShotgunAmmo.kMapName
end    


if Client then

    function WeirdShotgun:GetBarrelPoint()
    
        local player = self:GetParent()
        if player then
        
            local origin = player:GetEyePos()
            local viewCoords= player:GetViewCoords()
            
            return origin + viewCoords.zAxis * 0.4 + viewCoords.xAxis * -0.18 + viewCoords.yAxis * -0.2
            
        end
        
        return self:GetOrigin()
        
    end
    
    function WeirdShotgun:GetUIDisplaySettings()
        return { xSize = 256, ySize = 128, script = "lua/GUIShotgunDisplay.lua" }
    end

end

function WeirdShotgun:ModifyDamageTaken(damageTable, attacker, doer, damageType)
    if damageType ~= kDamageType.Corrode then
        damageTable.damage = 0
    end
end

function WeirdShotgun:GetCanTakeDamageOverride()
    return self:GetParent() == nil
end

if Server then

    function WeirdShotgun:OnKill()
        DestroyEntity(self)
    end
    
    function WeirdShotgun:GetSendDeathMessageOverride()
        return false
    end   
    
end

Shared.LinkClassToMap("WeirdShotgun", WeirdShotgun.kMapName, networkVars)


Here is the error message i've got when i try to me a weirdshotgun (using the command give weirdshotgun after the commands cheats 1) :
Error: lua/Utility.lua:1719: CreateEntity(weirdshotgun, 27.208578 4.344036 -20.600378, 1) returned nil.
[Server] Script Error #1: lua/Utility.lua:1719: CreateEntity(weirdshotgun, 27.208578 4.344036 -20.600378, 1) returned nil.
    Call stack:
    #1: error [C]:-1
    #2: CreateEntity lua/Utility.lua:1719
        mapName = "weirdshotgun"
        origin = cdata
        teamNumber = 1
        extraValues = nil
        values =  {origin=cdata, teamNumber=1 }
        entity = nil
    #3: GiveItem lua/Player_Server.lua:629
        self = Marine-3811 {activeWeaponId=746, alive=true, animateAngles=false, animateDistance=false, animatePosition=false, animateYOffset=false, animationBlend=0.20000000298023, animationGraphIndex=41, animationGraphNode=20, animationSequence2=28, animationSequence=27, animationSpeed2=1, animationSpeed=1, animationStart2=16.818370819092, animationStart=18.461738586426, armor=30, baseYaw=0, blockPersonalResources=false, bodyYaw=0, bodyYawRun=0, cameraDistance=0, canUseTunnel=true, catpackboost=false, clientIndex=1, collisionRep=0, communicationStatus=1, countingDown=false, crouching=false, currentOrderId=-1, darwinMode=false, desiredCameraAngles=cdata, desiredCameraDistance=0, desiredCameraPosition=cdata, desiredCameraYOffset=0, desiredSprinting=false, enableTunnelEntranceCheck=false, flashlightLastFrame=false, flashlightOn=false, flinchIntensity=0, followingTransition=false, fov=90, frozen=false, fullPrecisionOrigin=cdata, gameEffectsFlags=0, gameStarted=true, giveDamageTime=0, health=100, healthIgnored=false, hotGroupNumber=0, inCombat=false, interruptAim=false, isCorroded=false, isMale=true, isMoveBlocked=false, isOnEntity=false, isUsing=false, jumpHandled=false, jumping=false, lastOrderType=1, lastSpitDirection=cdata, lastTakenDamageAmount=0, lastTakenDamageOrigin=cdata, lastTakenDamageTime=0, lastTargetId=-1, layer1AnimationBlend=0, layer1AnimationGraphNode=163, layer1AnimationSequence2=-1, layer1AnimationSequence=-1, layer1AnimationSpeed2=1, layer1AnimationSpeed=1, layer1AnimationStart2=0, layer1AnimationStart=0, locationId=2, maxArmor=30, maxHealth=100, mode=1, modeTime=-1, modelIndex=59, moveButtonPressed=false, moveTransition=false, nanoShielded=false, onGround=true, onLadder=false, parasited=false, physicsGroup=8, physicsGroupFilterMask=0, physicsType=1, playerLevel=0, playerSkill=0, poisoned=false, primaryAttackLastFrame=false, processMove=true, pushImpulse=cdata, pushTime=0, quickSwitchSlot=2, reinforcedTierNum=0, requireNewSprintPress=false, resetMouse=0, resources=20.10000038147, runningBodyYaw=2.9903495311737, ruptured=false, secondaryAttackLastFrame=false, selectionMask=0, shoulderPadIndex=0, sighted=false, slowAmount=0, sprintButtonDownTime=0, sprintButtonUpTime=0, sprintDownLastFrame=false, sprintMode=false, sprintTimeOnChange=12, sprinting=false, sprintingScalar=0, standingBodyYaw=2.9903495311737, startCameraAngles=cdata, startCameraDistance=0, startCameraPosition=cdata, startCameraYOffset=0, stepAmount=-0.0075645446777344, stepStartTime=18.408294677734, strafeJumped=false, stunTime=0, syncHealth=false, teamNumber=1, teamResources=61, techId=53, timeCatpackboost=0, timeGroundAllowed=0, timeGroundTouched=16.818370819092, timeLastBeacon=0, timeLastHealed=0, timeLastMenu=0, timeLastSpitHit=0, timeOfCrouchChange=0, timeOfLastDrop=0, timeOfLastJump=0, timeOfLastOrderComplete=0, timeOfLastPhase=0, timeOfLastPickUpWeapon=0, timeOfLastUse=0, timeOfLastWeaponSwitch=16.890413284302, timeSprintChange=16.890413284302, timeUntilResourceBlock=0, timeWebEnds=0, transitionDuration=0, transitionStart=0, tunnelNearby=false, tweeningFunction=1, unitStatusPercentage=0, upgrade1=1, upgrade2=1, upgrade3=1, upgrade4=1, upgrade5=1, upgrade6=1, variant=3, velocity=cdata, velocityLength=0, velocityPitch=0, velocityYaw=0, viewModelId=3256, viewPitch=0.160878688097, viewRoll=0, viewYaw=2.9903495311737, visibleClient=false, vortexed=false, weaponUpgradeLevel=0, weaponsWeight=0.12999999523163, webbed=false }
        itemMapName = "weirdshotgun"
        setActive = true
        newItem = nil
    #4: lua/NS2ConsoleCommands_Server.lua:424
        client = ServerClient { }
        itemName = "weirdshotgun"
        player = Marine-3811 {activeWeaponId=746, alive=true, animateAngles=false, animateDistance=false, animatePosition=false, animateYOffset=false, animationBlend=0.20000000298023, animationGraphIndex=41, animationGraphNode=20, animationSequence2=28, animationSequence=27, animationSpeed2=1, animationSpeed=1, animationStart2=16.818370819092, animationStart=18.461738586426, armor=30, baseYaw=0, blockPersonalResources=false, bodyYaw=0, bodyYawRun=0, cameraDistance=0, canUseTunnel=true, catpackboost=false, clientIndex=1, collisionRep=0, communicationStatus=1, countingDown=false, crouching=false, currentOrderId=-1, darwinMode=false, desiredCameraAngles=cdata, desiredCameraDistance=0, desiredCameraPosition=cdata, desiredCameraYOffset=0, desiredSprinting=false, enableTunnelEntranceCheck=false, flashlightLastFrame=false, flashlightOn=false, flinchIntensity=0, followingTransition=false, fov=90, frozen=false, fullPrecisionOrigin=cdata, gameEffectsFlags=0, gameStarted=true, giveDamageTime=0, health=100, healthIgnored=false, hotGroupNumber=0, inCombat=false, interruptAim=false, isCorroded=false, isMale=true, isMoveBlocked=false, isOnEntity=false, isUsing=false, jumpHandled=false, jumping=false, lastOrderType=1, lastSpitDirection=cdata, lastTakenDamageAmount=0, lastTakenDamageOrigin=cdata, lastTakenDamageTime=0, lastTargetId=-1, layer1AnimationBlend=0, layer1AnimationGraphNode=163, layer1AnimationSequence2=-1, layer1AnimationSequence=-1, layer1AnimationSpeed2=1, layer1AnimationSpeed=1, layer1AnimationStart2=0, layer1AnimationStart=0, locationId=2, maxArmor=30, maxHealth=100, mode=1, modeTime=-1, modelIndex=59, moveButtonPressed=false, moveTransition=false, nanoShielded=false, onGround=true, onLadder=false, parasited=false, physicsGroup=8, physicsGroupFilterMask=0, physicsType=1, playerLevel=0, playerSkill=0, poisoned=false, primaryAttackLastFrame=false, processMove=true, pushImpulse=cdata, pushTime=0, quickSwitchSlot=2, reinforcedTierNum=0, requireNewSprintPress=false, resetMouse=0, resources=20.10000038147, runningBodyYaw=2.9903495311737, ruptured=false, secondaryAttackLastFrame=false, selectionMask=0, shoulderPadIndex=0, sighted=false, slowAmount=0, sprintButtonDownTime=0, sprintButtonUpTime=0, sprintDownLastFrame=false, sprintMode=false, sprintTimeOnChange=12, sprinting=false, sprintingScalar=0, standingBodyYaw=2.9903495311737, startCameraAngles=cdata, startCameraDistance=0, startCameraPosition=cdata, startCameraYOffset=0, stepAmount=-0.0075645446777344, stepStartTime=18.408294677734, strafeJumped=false, stunTime=0, syncHealth=false, teamNumber=1, teamResources=61, techId=53, timeCatpackboost=0, timeGroundAllowed=0, timeGroundTouched=16.818370819092, timeLastBeacon=0, timeLastHealed=0, timeLastMenu=0, timeLastSpitHit=0, timeOfCrouchChange=0, timeOfLastDrop=0, timeOfLastJump=0, timeOfLastOrderComplete=0, timeOfLastPhase=0, timeOfLastPickUpWeapon=0, timeOfLastUse=0, timeOfLastWeaponSwitch=16.890413284302, timeSprintChange=16.890413284302, timeUntilResourceBlock=0, timeWebEnds=0, transitionDuration=0, transitionStart=0, tunnelNearby=false, tweeningFunction=1, unitStatusPercentage=0, upgrade1=1, upgrade2=1, upgrade3=1, upgrade4=1, upgrade5=1, upgrade6=1, variant=3, velocity=cdata, velocityLength=0, velocityPitch=0, velocityYaw=0, viewModelId=3256, viewPitch=0.160878688097, viewRoll=0, viewYaw=2.9903495311737, visibleClient=false, vortexed=false, weaponUpgradeLevel=0, weaponsWeight=0.12999999523163, webbed=false }

I don't really know where is the mistake (since there are lot of code and i've only been making small mods for approximately 1 week). I hope you guys will help me.

Thankfully Devnunux.

P.S.: Sorry for my English but i'm French and i'm trying to do my best to write correct sentences. I you don't understand something fell free to ask me.

Comments

  • Soul_RiderSoul_Rider Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
    Hi,

    When you create a new weapon, you need to add it to all the places in lua where there is shotgun. This would include such files as TechTreeConstants.lua, TechData.lua, among many.

    In Decoda, do a search for the word Shotgun. look for where it appears, and add your weapon in the appropriate places.

    BTW, Welcome to NS2 modding, I hope you'll have a lot of fun and create some great mods :)
  • devnunuxdevnunux France Join Date: 2013-10-29 Member: 188866Members
    Oh I see. I'll try this and I'll come back to say if it worked. Thank you.
  • Soul_RiderSoul_Rider Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
    Also, there is an error in your weirdshotgun code..
    function WeirdShotgun:OnTag(tagName)
    
        PROFILE("Shotgun:OnTag")
    

    Should be:
    function WeirdShotgun:OnTag(tagName)
    
        PROFILE("WeirdShotgun:OnTag")
    
  • devnunuxdevnunux France Join Date: 2013-10-29 Member: 188866Members
    Ok, so after I modified the whole bunch of files, I managed to make it works.

    Thank you for your answers. Now it's time to try something else.
Sign In or Register to comment.