I see a lot of things wrong with this.
First,
chat.AddText is not in the Player metatable, so calling ply:chat.AddText will just throw an error (which is where the error you're getting is coming from).
Second, you can't call "ply:PlayerDeath()". PlayerDeath, for one, is a serverside hook (which you're trying to call inside a clientside OnPlayerChat hook) and, like chat.AddText, PlayerDeath is not in the Player metatable. Instead, is a gamemode hook. This has to be called on it's own hook.Add() declaration.
Third, timer.Stop doesn't erase the timer, it simply stops it and sets it's timer to 0. Using timer.Create() on an already existing timer isn't a great idea. The best way to do this is to use
timer.Remove.
Also, put this file in 'lua/autorun' and not 'lua/autorun/server'.
The way I would tackle this is by doing this:
Using the
net library, you can send specific data/messages to specific players or every player from the Server. This allows the Server to verify that something has occurred, and then let the Client know about it. The first thing I'd use to start doing this is using
util.AddNetworkString in order to set a String to be able to send specific data to the client in an identifiable way.
if ( SERVER ) then
util.AddNetworkString( "TerrorExists" )
util.AddNetworkString( "TerrorEnd" )
util.AddNetworkString( "TerrorBegin" )
end
I'd use a
GM:PlayerSay hook to find when someone says "/terror". This is done similarly to how you're doing it in your script, but instead it would (1) check if the terrortimer already exists, and if it does do nothing but let the player know Terror is already active, and if not it will create the timer; (2) assign a "terror" variable to the player, so that I can use a
GM:PlayerDeath hook to check if that person has died, and if they have announce it and destroy the timer.
hook.Add( "PlayerSay", "CheckForTerrorCommand", function( ply, text, team )
text = string.lower( text ) -- Force it into lowercase.
if ( string.sub( text, 1, 7 ) == "/terror" ) then -- Incase there's any more spaces or something else in the string, this checks only the first 7 characters.
if ( timer.Exists( "terrortimer" ) ) then
net.Start( "TerrorExists" )
net.WriteString( ply:Nick() .. ", Terror is already active" ) -- Feel free to change this to whatever you want.
net.Send( ply ) -- Sends this string to only the player calling it.
return "" -- Makes nothing appear in the chat, and nothing else to happen.
else
ply.terrorActive = true -- This assigns a player variable. This is used to check when the player dies.
net.Start( "TerrorBegin" )
net.WriteColor( Color( 255, 255, 0, 255 ) ) -- Writes the color you want.
net.WriteString( "[Advert] " .. ply:Nick() .. " Terror, 30 seconds" ) -- The message you want to display.
net.Broadcast() -- This sends the message to everyone.
timer.Create( "terrortimer", 30, 1, function()
ply.terrorActive = false
net.Start( "TerrorEnd" )
net.WriteColor( Color( 255, 255, 0, 255 ) )
net.WriteString( "Terror over." )
net.Broadcast()
end )
end
end
end )
Then I would write up a quick
GM:PlayerDeath hook in order to check if the player who activated the terror has died. Since this hook is called every time a player dies, we can check if the player passed in the "victim" argument is the one who has "terrorActive" as "true", and if s/he is, announce that Terror is over.
hook.Add( "PlayerDeath", "CheckForTerrorDeath", function( vic, inf, att )
if ( vic.terrorActive and vic.terrorActive == true ) then
vic.terrorActive = false
timer.Remove( "terrortimer" )
net.Start( "TerrorEnd" )
net.WriteColor( Color( 255, 255, 0, 255 ) )
net.WriteString( "Terror over." )
net.Broadcast()
end
end )
Now, we need the Client to be able to (1) receive and (2) interpret the net messages. We can accomplish this through
net.Receive. This function allows us to read a given NetworkString ("TerrorExists", "TerrorBegin", or "TerrorEnd") and do something with it. This is also where you're going to use
chat.AddText. Since we already wrote our Colour and String, all we have to do is read them and then put them in our function:
net.Receive( "TerrorExists", function( len )
local str = net.ReadString()
chat.AddText( str )
end )
net.Receive( "TerrorBegin", function( len )
-- Data MUST be read in the same order we write it, and above I wrote the colour first, so the colour has to be READ first and THEN the string.
local col = net.ReadColor()
local str = net.ReadString()
chat.AddText( col, str )
end )
net.Receive( "TerrorEnd", function( len )
local col = net.ReadColor()
local str = net.ReadString()
chat.AddText( col, str )
end )
Good so far? Good. Now, since this is all in a shared file (it's usable on both the client
and server), we need to make sure Lua knows when to check for Serverside-only code and Clientside-only code. We can accomplish this by checking if we're on the SERVER or the CLIENT (Yes, they have to be capitalized).
if ( SERVER ) then
AddCSLuaFile()
util.AddNetworkString( "TerrorExists" )
util.AddNetworkString( "TerrorEnd" )
util.AddNetworkString( "TerrorBegin" )
hook.Add( "PlayerSay", "CheckForTerrorCommand", function( ply, text, team )
text = string.lower( text ) -- Force it into lowercase.
if ( string.sub( text, 1, 7 ) == "/terror" ) then -- Incase there's any more spaces or something else in the string, this checks only the first 7 characters.
if ( timer.Exists( "terrortimer" ) ) then
net.Start( "TerrorExists" )
net.WriteString( ply:Nick() .. ", Terror is already active" ) -- Feel free to change this to whatever you want.
net.Send( ply ) -- Sends this string to only the player calling it.
return "" -- Makes nothing appear in the chat, and nothing else to happen.
else
ply.terrorActive = true -- This assigns a player variable. This is used to check when the player dies.
net.Start( "TerrorBegin" )
net.WriteColor( Color( 255, 255, 0, 255 ) ) -- Writes the color you want.
net.WriteString( "[Advert] " .. ply:Nick() .. " Terror, 30 seconds" ) -- The message you want to display.
net.Broadcast() -- This sends the message to everyone.
timer.Create( "terrortimer", 30, 1, function()
ply.terrorActive = false
net.Start( "TerrorEnd" )
net.WriteColor( Color( 255, 255, 0, 255 ) )
net.WriteString( "Terror over." )
net.Broadcast()
end )
end
end
end )
hook.Add( "PlayerDeath", "CheckForTerrorDeath", function( vic, inf, att )
if ( vic.terrorActive and vic.terrorActive == true ) then
vic.terrorActive = false
timer.Remove( "terrortimer" )
net.Start( "TerrorEnd" )
net.WriteColor( Color( 255, 255, 0, 255 ) )
net.WriteString( "Terror over." )
net.Broadcast()
end
end )
elseif ( CLIENT ) then
net.Receive( "TerrorExists", function( len )
local str = net.ReadString()
chat.AddText( str )
end )
net.Receive( "TerrorBegin", function( len )
-- Data MUST be read in the same order we write it, and above I wrote the colour first, so the colour has to be READ first.
local col = net.ReadColor()
local str = net.ReadString()
chat.AddText( col, str )
end )
net.Receive( "TerrorEnd", function( len )
local col = net.ReadColor()
local str = net.ReadString()
chat.AddText( col, str )
end )
end
That should pretty much cover it. I tried to teach you as I went, so please don't just copy and paste the final copy and move on. Also keep in mind that I wrote this without testing it, so there can and probably will be errors. However, if you do run into errors,
please try to solve them first. The best way to learn is to fix mistakes. Obviously, if you can't figure them out, feel free to respond and I'll try to walk you through it.
Also, here's a challenge for you: I called 'net.Start( "TerrorEnd" )' ... twice. This could be done much more efficiently; try to figure that out.