Derma Panel Ammo Question

Hello I would like to make a derma panel that will have the function to give me ammo when I click the button.

Here is the code, and I am just confused as to what I am missing.

Thanks


function ammohud()

	ammohud = vgui.Create( "DFrame" )
	ammohud:SetPos( ScrW() / 2, ScrH() / 2 )
	ammohud:SetSize( 175, 75 )
	ammohud:SetTitle( "Ammo" )
	ammohud:SetVisible( true )
	ammohud:SetDraggable( true )
	ammohud:ShowCloseButton( true )
	ammohud:MakePopup()
	 
	ready1 = vgui.Create( "DButton", ammohud )
	ready1:SetPos( 20, 25 )
	ready1:SetSize( 140, 40 )
	ready1:SetText( "Buy some ammo" )
	ready1.DoClick = function()
		print("You just bought 200 pistol bullets...")
		self:GiveAmmo(200, pistol, true)
	end
end

jut ignore the self:GiveAmmo, I was testing random stuff at this point lol.

server file:



util.AddNetworkString( "someuniquename" );

net.Receive( "someuniquename", function( len, _p )

    _p:GiveAmmo( 200, pistol, true );
    _p:ChatPrint( "You just bought 200 pistol bullets..." );

end );


client side:



	ready1.DoClick = function()
		net.Start(  "someuniquename" );
                net.SendToServer();
                _ammohud:Close();
	end


Remember: any player can send this to server right now. You can’t give ammo clientside(since that’d allow basically anyone to give themself ammo at any point), it’s a serverside function.

Put serverside file in either:
lua/autorun/server/somename.lua
or
lua/autorun/somename.lua
if second alternative, then it must be in if ( SERVER ) then putcodehere end

since shared (lua/autorun/files here) are run on both client and server

adds:
wiki.garrysmod.com/page/Player/GiveAmmo look blue color = serverside.
Also see second argument is string, you have just put it as pistol. Pistol isn’t defined as a variable. you have 2 choices:

  1. local pistol = “pistol”;
  2. just put “pistol” as second argument(see quotemarks).

Read net library:
wiki.garrysmod.com/page/Net_Library_Usage

What you can add to this DoClick:



net.Start(  "someuniquename" );
net.WriteFloat( 1 );
net.SendToServer();


serverside in the net.Receive function:



util.AddNetworkString( "someuniquename" );

local _weapontypes = { "pistol", "rifle", "smg" };

net.Receive( "someuniquename", function( len, _p )

     local _type = net.ReadFloat();
     if( !_weapontypes[ _type ] ) then
           return;
     end
    _p:GiveAmmo( 200, _weapontypes[ _type ], true );
    _p:ChatPrint( "You just bought 200  " .. _weapontypes[ _type ] .. " bullets..." );

end );


edit: the _weapontypes table has 3 values, “pistol”, “rifle”, and “smg” - indexes/keys are 1, 2, 3. if you have multiple button they can have different net.WriteFloat( values here ); so you can give any of those 3 ammo types. Then you can make it more advanced like putting in shared:



__weapontypes = { { "pistol", "Pistol Bullets",  12, 50 } };


then _weapontypes[ 1 ][ 1 ] = “pistol”, [ 1 ][ 2 ] = “Pistol Bullets”;
then you can in your clientside file loop through the table, print out like This will give you __weaponTypes[ i ][ 3 ] bullets, set net.WriteFloat( i ),
serverside



_p:GiveAmmo( __weapontypes[ _type ][ 3 ], __weapontypes[ _type ][ 1 ], false );
_p:ChatPrint( "You bought " .. __weapontypes[ _type ][ 3 ] .. " " .. __weapontypes[ _type ][ 2 ] .. " for $" .. __weapontypes[ _type ][ 4 ] );
_p:AddMoney( -__weapontypes[ _type ][ 4 ] );


Thanks for the help! I gave you a good rating for the information!
I read through it and it taught me a lot.
I used NWInts for a money system, I now am confused about how to go about removing the money and blocking the ammo if there is no money.

Excessive use of underscores looks ugly and messy. More so when you put it in front a variable name.

For example, you could’ve just used p as player. Or “player” so that your identifier is actually meaningful. “_p” looks like you’re trying to show off and it’s not really helping those who don’t know what it stands for.

Yes, I did know that and I did know what it meant. I did have to think about it for a second lol.
Okay so back on topic, I made my own money system with GetNWInt and SetNWInt and am having trouble making it take money away when I buy the ammo, and also stop buying the ammo if I have no money. The way I did it with props did not work for me lol.

[lua]
function CanAfford( ply, Amount )
return ply:GetNWInt( “YourMoneyName”, 0 ) >= Amount
end

function TakeMoney( ply, Amount )
if not CanAfford( ply, Amount ) then return false end
ply:SetNWInt( “YourMoneyName”, ply:GetNWInt(“YourMoneyName”) - Amount )
return true
end
[/lua]

Something like this? Do it serverside.

Hmm it didn’t work, Here is what my Money is This is just from onnpckilled function I have


	attacker:SetNWInt("PlayerMoney", attacker:GetNWInt("PlayerMoney") + 100)

Here is the functions I added in that you suggested and I understand most of them


function CanAfford( ply, Amount )
	return ply:GetNWInt( "PlayerMoney", 0 ) >= Amount
end

function TakeMoney( ply, Amount )
	if not CanAfford( ply, Amount ) then return false end
	ply:SetNWInt( "PlayerMoney", ply:GetNWInt("PlayerMoney") - Amount )
	return true
end

I didn’t get any errors but it still bought the ammo with 0 dollars :frowning:

Did you call the function to check if they had enough money? Is the price of the ammo 0? Btw, When I said you need it serverside, you only need the TakeMoney serverside, the CanAfford should be shared so you can check on the client if they can afford it before sending a request to the server (where you should also check if they can afford it, as a rule, never trust the client, always assume they are trying to find a flaw in your code).

Now I’m more confused lol. Okay o I get that I can put the takemoney function serverside and canafford can go client. I don’t understand the part where you ask if I called the function to check if they had enough money. I don’t even think I have that function. I just did this for prop block when no money and it worked.


local models = { "crane_frame.mdl" }
local function blockProps( ply, mdl )
	local PlayerMoney = ( ply:GetNWInt( "PlayerMoney" ) )
	for _, v in pairs( models ) do
		if PlayerMoney == 0 then
			return false
		end
	end
end
hook.Add( "PlayerSpawnProp", "blockProps", blockProps )

Other then that I don’t know what you mean.

What is the purpose of that code?
It seems to loop through a table of strings(model names), check if the variable PlayerMoney is 0 and if it is 0, return false.



function CanAfford( ply, Amount )
	return ply:GetNWInt( "PlayerMoney", 0 ) >= Amount
end

function TakeMoney( ply, Amount )
	if not CanAfford( ply, Amount ) then return false end
	ply:SetNWInt( "PlayerMoney", ply:GetNWInt("PlayerMoney") - Amount )
	return true
end

-- how to use it:
net.Receive( "someuniquenamelikebuyammo", function( len, _p )
    if( !CanAfford( _p, 50 ) ) then 
        _p:ChatPrint( "You can't afford to buy this(costs $50)!" );
    else
        TakeMoney( _p, 50 );
        // give him ammo here
        _p:ChatPrint( "You purchased ammo for $50!" );
    end
end );


You can, and should, place the CanAfford in a shared file, then both the server and client can know if the player can afford something. Maybe if he can’t afford it, display price in red text, otherwise, green. TakeMoney must be in a server file because you can’t set networked variables clientside.

That is true that it doesn’t really help those who don’t know, I should’ve put it as ply. But I usually write _p for Player, _e for Entity, so that’s how I keep track of them. And _ for local variables.