Jump to content

Left 4 Dead style use timer


Einlander
 Share

Recommended Posts

I've been doing some coding on a bunch of Left 4 Dead style stuff and this is the latest script I have. A simple use timer. I haven't tested it very hard, but there should not be any glaring bugs. Information about the script:

http://i.imgur.com/ZuzDtap.gifv

 

--[[
Title:			Use Timer
Author:			Einlander
Start Date:		5-22-17
Version:		2
Description:	A simple Left 4 Dead style use timer
Notes:
				WHAT IT DOES: Allows player to use a script to force player/user to use an item for a set period of time.
				Think Left 4 Dead when you need to pour gas or start generators.
				WHAT IT DOESENT DO: It does not immobilize the player/user. 
									It does not cancel when the player/user looks away or is too far.
Changelog:
	1	-Initial release
	2	-style changes small fix
		added self.entity:SetKeyValue("type","use_timer") .
		This will help when trying to figure out what you are using and adjust accordingly. 
		ie:detect you are using the use timer and make it so the player cant move
		-in Script:Start changed self.completed to true to prevent activating when not targeting entity.
	3	-complete rewrite with less code, and smarter time management
]]

 

The script itself:

 

--[[
Title:			Use Timer
Author:			Einlander
Start Date:		5-22-17
Version:		2
Description:	A simple Left 4 Dead style use timer
Notes:
				WHAT IT DOES: Allows player to use a script to force player/user to use an item for a set period of time.
				Think Left 4 Dead when you need to pour gas or start generators.
				WHAT IT DOESENT DO: It does not immobilize the player/user. 
									It does not cancel when the player/user looks away or is too far.
Changelog:
	1	-Initial release
	2	-style changes small fix
		added self.entity:SetKeyValue("type","use_timer") .
		This will help when trying to figure out what you are using and adjust accordingly. 
		ie:detect you are using the use timer and make it so the player cant move
		-in Script:Start changed self.completed to true to prevent activating when not targeting entity.
	3	-complete rewrite with less code, and smarter time management
]]

Script.NullVar 				= nil --choice "Use Timer" "Version: 3, By: Einlander"
Script.enabled 			= true 	-- bool "Enabled"
Script.HoldTime 		= 5 	-- Float "Hold Time" -- How long the use key needs to be held
Script.CumulativeTime 	= false -- bool "Cumulative Time" -- The timer does not reset when the use key is let go
Script.ShowGraphics		= true	-- bool "Show Graphics" -- Draws the completion bar on screen
Script.DisableOnComplete= true 	-- bool "Stop when Done" -- Disables script on completion


function Script:Start()
	self.totaltime = 0	
end



--[[
Description: Allows the fpsplayer to use the entity
Parameters: none
]]
function Script:Use() 
	if self.enabled == false then return end
	self:Begin()			
end

--[[
Description: enables the script
Parameters: none
Notes: Has a flowgraph input
]]
function Script:Enable() --in
	self.enabled = true
	self.component:CallOutputs("_enabled")
end

--[[
Description: Disables script
Parameters: none
Notes: Has a flowgraph input
]]
function Script:Disable() --in
	self.enabled = false
	self.component:CallOutputs("_disabled")
end

--[[
Description: Starts all timers
Parameters: none
Notes: Has a flowgraph input, and a output to tell when the script has started
]]
function Script:Begin()
	if self.enabled == false then return end
	self.started = true	
	self.complete = false	
	--if (self.totaltime >= (self.HoldTime - 1)*1000) then			
			--self.totaltime = 0			
	--end
	if (self.CumulativeTime == false) then
		self.totaltime = 0
	end	
	self.component:CallOutputs("started")
end

--[[
Description: Resets the script to ready it for another use
Parameters: none
Notes: Has a flowgraph input, and a output to tell when the script has completed
]]
function Script:Complete() 	
	if self.enabled == false then return end
	self.complete = true	
	self.totaltime = 0
	if (self.DisableOnComplete == true) then
		self:Disable()
	end
	self.component:CallOutputs("complete")
	--System:Print("complete")	
end


--[[
Description: Keep track of when the use key is pressed, held, and released
Parameters: none
Notes: Also calculates time left
]]
function Script:UpdatePhysics()
	if self.enabled == false then return end
	if self.complete == true then return end	
	if ((self.started == true) or (self.held == true) or (self.released == true)) == true then
		if self.totaltime >= ((self.HoldTime-1) * 1000) then
			self:Complete()
		end
	end
	if self.started == true then
		if (window:KeyDown(Key.E) == true) then
			self.started = false
			self.held = true			
			self.timestart = Time:GetCurrent()			
			return
		end
	end
	if self.held == true then
		if (window:KeyDown(Key.E) == true) then			
			self.held = true
			self.timeend = Time:GetCurrent()
			self.totaltime  = self.totaltime  + (self.timeend - self.timestart)
			self.timestart = Time:GetCurrent()			
			self.component:CallOutputs("running")
			self.timeend = Time:GetCurrent()	
		else
			self.held=false
			self.released = true
			self.timeend = Time:GetCurrent()	
			self.totaltime  = self.totaltime  + (self.timeend - self.timestart)
			self.timestart = Time:GetCurrent()
		end	
		return
	end
	if self.released == true then
		self.timeend = Time:GetCurrent()
		self.totaltime  = self.totaltime  + (self.timeend - self.timestart)
		self.released = false			
		return
	end	
end

--[[
Description: Prints stuff to console
Parameters: 
	inner as anything
Notes: Has a flowgraph input, that will allow an argument
]]
function Script:WritePercentage(number) --in
	System:Print(tostring(number))
end

--[[
Description: Calculates Percent Complete
Parameters: none
Notes: Has a flowgraph ARGUMENT that sends out the percentage completed
]]
function Script:Percentage() --arg
	return math.floor((self.totaltime / ((self.HoldTime-1)*1000))*100)
end


--[[
Description: Draws the Percentage bar on screen
Parameters: 
	context as window context
Notes: The display is resolution independant. It will look the same on all screens.
]]
function Script:PostRender(context)
	if self.enabled == false then return end
	if self.complete == true then return end
	if ((self.started == true) or (self.held == true) or (self.released == true)) == false then return end
		context:SetBlendMode(Blend.Alpha)	
		window = Window:GetCurrent()		
		local segment = Vec2(window:GetWidth() *.25,window:GetHeight() *.47)
		context:SetColor(0,0,0,0.5)	
		context:DrawRect(segment.x, segment.y , window:GetWidth() - (segment.x*2),window:GetHeight() - (segment.y*2))
		context:SetColor(1,1,1,0.5)	
		context:DrawRect(segment.x+4, segment.y+4 , (window:GetWidth() - ((segment.x+4)*2))*(self:Percentage()*.01) , window:GetHeight() - ((segment.y+4)*2))			
end

 

-- edit --

added self.entity:SetKeyValue("type","use_timer") . This will help when trying to figure out what you are using and adjust accordingly. ie:detect you are using the use timer and make it so the player cant move.

in Script:Start changed self.completed to true to prevent activating when not targeting entity.

-- edit --

Link to comment
Share on other sites

You have 666 posts! Quick post again :)

Thanks for sharing. I don't know if you're open to coding suggestions but the thing that instantly stood out to me is the level of indentation. Each indentation is like allocating memory on a stack in our minds. Code with less indentation tends to be easier to read and less error prone. A way to remove indentation, again if you care at all, is to negate and return early. Your PostRender() is a good example of that. 5 levels of indentation can be turned into basically none with:

 

function Script:PostRender(context)	
	if self.ShowGraphics == false then return end
	if self.enabled == false then return end
	if self.using == false then return end
	if self.useold == false then return end
	if self.completed == true then return end

	context:SetBlendMode(Blend.Alpha)	
	window = Window:GetCurrent()		
	local segment = Vec2(window:GetWidth() *.25,window:GetHeight() *.47)
	context:SetColor(0,0,0,0.5)	
	context:DrawRect(segment.x, segment.y , window:GetWidth() - (segment.x*2),window:GetHeight() - (segment.y*2))
	context:SetColor(1,1,1,0.5)	
	context:DrawRect(segment.x+4, segment.y+4 , (window:GetWidth() - ((segment.x+4)*2))*(self:Percentage()*.01) , window:GetHeight() - ((segment.y+4)*2))
end

 

UpdatePhysics is another good example. Checking for self.enabled is very common so negating and bailing out early helps readability.

Again, just something that stood out. You can tell me to piss off if you aren't interested :)

  • Upvote 2
Link to comment
Share on other sites

I've never really thought about that way. I developed that habit in my old qbasic days. I tend to make very nice looking spaghetti code so I like to make sure the scope is super obvious. That and I code at night on low sleep after work. I make all sorts of mistakes. I'm quite sure i have variables that are never used in this script. But I will take it in mind. Now i'm 8 hours overdue from sleep. Now I have 667 posts!

Link to comment
Share on other sites

This might actually be a good example for coroutines too. I'll see what it would look like with coroutines and post and see what you think. Whenever you are mananging a lot of state variables coroutines might be ale to help reduce those and make the code smaller and easier to read.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...