Chair Gun Question

Hello,

I am trying to modify the chair throwing gun found on the wiki page so that when you right click, a menu opens up for the user to change the prop. However, the code I have right now doesn’t seem to work. I get no script errors, the swep just does not fire. I am not to experience with lua and thought this would be a decent beginner’s exercise. Any help would be appreciated:



if (SERVER) then --the init.lua stuff goes in here
 
 
   AddCSLuaFile ("shared.lua");
 
 
   SWEP.Weight = 5;
   SWEP.AutoSwitchTo = false;
   SWEP.AutoSwitchFrom = false;
 
end
 
if (CLIENT) then --the cl_init.lua stuff goes in here
 
 
   SWEP.PrintName = "Chair throwing gun";
   SWEP.Slot = 3;
   SWEP.SlotPos = 1;
   SWEP.DrawAmmo = false;
   SWEP.DrawCrosshair = false;
   
   concommand.Add( "propmenu", function()
   
  	local propmenu = vgui.Create( "DFrame" )
	propmenu:SetPos( ScrW() * .35, ScrH() * .3 )
	propmenu:SetSize( 200, 200 )
	propmenu:SetTitle( "Select a prop" )
	propmenu:SetVisible( true )
	propmenu:SetDraggable( true )
	propmenu:ShowCloseButton( true )
	propmenu:MakePopup()
	 
	propList={}
	propList["Chair"] = "models/props/cs_office/Chair_office.mdl"
	propList["Rollermine"] = "models/Roller.mdl"
	
	local pList = vgui.Create("DComboBox", propmenu );
	pList:SetPos( 50, 50 )
	pList:SetSize( 100, 20 )
 
	for k,v in pairs(propList) do
   	 pList:AddChoice( k )
	 
	 	local pButton = vgui.Create( "DButton" )
		pButton:SetParent(propmenu)
		pButton:SetPos( 75, 150 )
		pButton:SetText( "OK" )
		pButton:SetSize( 60, 30 )
		pButton.DoClick = function()
		
		selected = propList[pList:GetSelected()]
		print(selected)
		propmenu:Close()
					end
				end
			end)
end
 
 
SWEP.Author = "Sam Douglas";
SWEP.Contact = "sam.douglas32@gmail.com";
SWEP.Purpose = "Assists in throwing chairs";
SWEP.Instructions = "Left click to throw an office chair; right click to throw a wooden chair";
SWEP.Category = "Prop Launchers"
 
SWEP.Spawnable = true;
SWEP.AdminSpawnable = true;
 
SWEP.ViewModel = "models/weapons/v_pistol.mdl";
SWEP.WorldModel = "models/weapons/w_pistol.mdl";
 
SWEP.Primary.ClipSize = -1;
SWEP.Primary.DefaultClip = -1;
SWEP.Primary.Automatic = false;
SWEP.Primary.Ammo = "none";
 
SWEP.Secondary.ClipSize = -1;
SWEP.Secondary.DefaultClip = -1;
SWEP.Secondary.Automatic = false;
SWEP.Secondary.Ammo = "none";
 
local ShootSound = Sound ("Metal.SawbladeStick");
 
function SWEP:Reload()
end
 
function SWEP:Think()
end
 
function SWEP:throw_attack (model_file)

	local tr = self.Owner:GetEyeTrace();
 
	self:EmitSound (ShootSound);
	self.BaseClass.ShootEffects (self);
 
	if (!SERVER) then return end;
 
	local ent = ents.Create ("prop_physics");
	ent:SetModel (model_file);
 
	ent:SetPos (self.Owner:EyePos() + (self.Owner:GetAimVector() * 16));
	ent:SetAngles (self.Owner:EyeAngles());
	ent:Spawn();
 
	local phys = ent:GetPhysicsObject();
 
	local shot_length = tr.HitPos:Length();
	phys:ApplyForceCenter (self.Owner:GetAimVector():GetNormalized() *  math.pow(shot_length, 3));
 
	cleanup.Add (self.Owner, "props", ent);
 
	undo.Create ("Thrown chair");
	undo.AddEntity (ent);
	undo.SetPlayer (self.Owner);
	undo.Finish();
end
 
function SWEP:PrimaryAttack()
	
	self:throw_attack (selected);
	
end
 
function SWEP:SecondaryAttack()
	RunConsoleCommand("propmenu");
end


You haven’t set the model for the prop_physic

Wouldn’t this function do that though?:



function SWEP:PrimaryAttack()
	
	self:throw_attack (selected);
	
end


[lua]//Change this line:
function SWEP:throw_attack(model_file)
//To this:
SWEP.throw_attack = function(model_file)[/lua]

Let me know if this works.

Unfortunately no, I get the error:

[ERROR] addons/chairlauncher/lua/weapons/shared.lua:92: attempt to index global ‘self’ (a nil value)

  1. throw_attack - addons/chairlauncher/lua/weapons/shared.lua:92
  2. unknown - addons/chairlauncher/lua/weapons/shared.lua:121

My fault, you should have self as your first argument. Change that line to this:
[lua]SWEP.throw_attack = function(self, model_file)[/lua]

No error this time, but still not working :frown:

Something else I noticed is that when I click the “OK” button to close the menu, it takes a few clicks to actually close it. The result is it printing “nil” into console. I have a feeling this may be it since it will not use nil as a prop. Why won’t it close on the first click?

Correct, that could very well be it, you can’t spawn a nil entity obviously. Try changing the models in your PropList table. Here are a few that should not come up as nil.

“models/nova/chair_wood01.mdl”
“models/props_interiors/furniture_chair03a.mdl”
“models/props_wasteland/controlroom_chair001a.mdl”
“models/props_interiors/furniture_chair01a.mdl”

I don’t think that’s it. Any model will work, it’s just that it prints nil after I click “OK” more than once, and it takes multiple clicks to close for some reason.

EDIT: Now when I click OK it also gives the error

[ERROR] lua/vgui/dframe.lua:85: attempt to index local ‘self’ (a nil value)

  1. Close - lua/vgui/dframe.lua:85
  2. DoClick - addons/chairlauncher/lua/weapons/shared.lua:53
    3. unknown - lua/vgui/dlabel.lua:232

There is a singleplayer and a multiplayer menu, they are the same. Make sure if you are trying to change the menu around, that it corresponds with if you are playing singleplayer/multiplayer.

[lua]
AddCSLuaFile()

SWEP.Author = “xdoomx”

SWEP.ViewModel = “models/weapons/v_pistol.mdl”
SWEP.WorldModel = “models/weapons/w_pistol.mdl”
SWEP.AnimPrefix = “python”

SWEP.Primary = {ClipSize = -1, DefaultClip = -1, Automatic = true, Ammo = “none”}
SWEP.Secondary = {ClipSize = -1, DefaultClip = -1, Automatic = false, Ammo = “none”}
SWEP.CanHolster = true
SWEP.CanDeploy = true
SWEP.ShootSound = Sound(“Metal.SawbladeStick”)

SWEP.Props = {}
SWEP.Props[“Wood Chair”] = “models/props_interiors/furniture_chair01a.mdl”
SWEP.Props[“Metal Chair”] = “models/props_interiors/furniture_chair03a.mdl”
SWEP.Props[“Folding Chair”] = “models/props_wasteland/controlroom_chair001a.mdl”

SWEP.Selected = “models/props_interiors/furniture_chair01a.mdl”

function SWEP:Precache()
util.PrecacheModel(self.ViewModel)
util.PrecacheModel(self.WorldModel)

util.PrecacheSound(self.ShootSound)

end

function SWEP:FireAnimationEvent(pos, ang, event, options)
if event == 21 then return true end
if event == 5003 then return true end
end

if (SERVER) then

SWEP.Weight                = 5
SWEP.AutoSwitchTo        = false
SWEP.AutoSwitchFrom        = false

local function PlayerSpawn(pl)
    pl:Give("chairthrower")
end
hook.Add("PlayerSpawn", "Give ChairThrower on spawn.", PlayerSpawn)

function SWEP:ShouldDropOnDie()
    return false
end

function ChairSelection(pl, cmd, arg)
    local mdl = arg[1]

    if pl:GetActiveWeapon():GetClass() == "chairthrower" then
        pl:GetActiveWeapon().Selected = mdl
    end
end
concommand.Add("ChairSelect", ChairSelection)

else --If Client:

SWEP.PrintName            = "Chair Thrower"    
SWEP.Slot                = 1
SWEP.SlotPos            = 1
SWEP.DrawAmmo            = false
SWEP.DrawCrosshair        = true

SWEP.Spawnable            = true
SWEP.AdminSpawnable        = true

SWEP.WepSelectIcon        = surface.GetTextureID( "vgui/gmod_tool" )
SWEP.DrawWeaponInfoBox    = false



SWEP.CreateMenu = function(self)
    self.Menu = vgui.Create( "DFrame" )
    self.Menu:SetPos( ScrW()*0.35, ScrH()*0.3 )
    self.Menu:SetSize( 200, 200 )
    self.Menu:SetTitle( "Select a chair" )
    self.Menu:SetVisible( false )
    self.Menu:SetDraggable( true )
    self.Menu:ShowCloseButton( false )
    self.Menu:MakePopup()

    local Options = vgui.Create( "DComboBox", self.Menu )
    Options:SetPos( 50, 50 )
    Options:SetSize( 100, 20 )

    for k, v in pairs( self.Props ) do
        Options:AddChoice( k )

        local Button = vgui.Create( "DButton", self.Menu )
        Button:SetPos( 75, 150 )
        Button:SetText( "Select" )
        Button:SetSize( 60, 30 )
            Button.DoClick = function()
                RunConsoleCommand("ChairSelect", self.Props[Options:GetSelected()])
                self.Menu:SetVisible(false)
            end
    end
end

if game.SinglePlayer() then
    function SinglePlayerMenu(pl, cmd, arg)
        if pl.ChairMenu == nil then
            local Weapon = pl:GetActiveWeapon()
            pl.ChairMenu = vgui.Create( "DFrame" )
            pl.ChairMenu:SetPos( ScrW()*0.35, ScrH()*0.3 )
            pl.ChairMenu:SetSize( 200, 200 )
            pl.ChairMenu:SetTitle( "Select a chair" )
            pl.ChairMenu:SetVisible( true )
            pl.ChairMenu:SetDraggable( true )
            pl.ChairMenu:ShowCloseButton( false )
            pl.ChairMenu:MakePopup()

            local Options = vgui.Create( "DComboBox", pl.ChairMenu )
            Options:SetPos( 50, 50 )
            Options:SetSize( 100, 20 )

            for k, v in pairs( Weapon.Props ) do
                Options:AddChoice( k )

                local Button = vgui.Create( "DButton", pl.ChairMenu )
                Button:SetPos( 75, 150 )
                Button:SetText( "Select" )
                Button:SetSize( 60, 30 )
                    Button.DoClick = function()
                        RunConsoleCommand("ChairSelect", Weapon.Props[Options:GetSelected()])
                        pl.ChairMenu:SetVisible(false)
                    end
            end
        else
            if pl.ChairMenu:IsVisible() then
                pl.ChairMenu:SetVisible(false)
            else
                pl.ChairMenu:SetVisible(true)
            end
        end
    end
    concommand.Add("CreateChairMenu_Singleplayer", SinglePlayerMenu)
end

end

function SWEP:PrimaryAttack()
self:ThrowChair(self.Selected)
end

function SWEP:SecondaryAttack()

if !game.SinglePlayer() then
    self:SetNextSecondaryFire(CurTime()+0.5)

    if (!CLIENT) then return end

    if self.Menu == nil then
        self:CreateMenu()
        self.Menu:SetVisible(true)
        return
    end

    if self.Menu:IsVisible() then
        self.Menu:SetVisible(false)
    else
        self.Menu:SetVisible(true)
    end
else
    RunConsoleCommand("CreateChairMenu_Singleplayer")
end

end

function SWEP:Reload()

end

function SWEP:DrawWorldModel()
self:DrawModel()
end

SWEP.ThrowChair = function(self, mdl)
local tr = self.Owner:GetEyeTraceNoCursor()

self:EmitSound(self.ShootSound)

if (!SERVER) then return end

local ent = ents.Create ("prop_physics")
ent:SetModel(mdl)

ent:SetPos(self.Owner:EyePos() + (self.Owner:GetAimVector() * 16))
ent:SetAngles(self.Owner:EyeAngles())
ent:Spawn()

local phys = ent:GetPhysicsObject()

local shot_length = tr.HitPos:Length()
phys:ApplyForceCenter (self.Owner:GetAimVector():GetNormalized() *  math.pow(shot_length, 3))

cleanup.Add (self.Owner, "props", ent)

undo.Create("Thrown chair")
undo.AddEntity(ent)
undo.SetPlayer(self.Owner)
undo.Finish()

end
[/lua]

[editline]25th December 2016[/editline]

Also it is one file in your weapons folder, make sure the weapon is called chairthrower

Your problem is that you’re attempting to fire a prop with a model set in a variable, however this variable is only changed clientside and only the server can create entities. You need to network your selected prop to the server so it knows. You should also not use a global variable for the selected model or it can be overwritten externally and also shared by all weapons. Store it on the weapon instead.