Einlander Posted May 23, 2017 Share Posted May 23, 2017 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 -- Quote Link to comment Share on other sites More sharing options...
Rick Posted May 23, 2017 Share Posted May 23, 2017 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 2 Quote Link to comment Share on other sites More sharing options...
Einlander Posted May 23, 2017 Author Share Posted May 23, 2017 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! Quote Link to comment Share on other sites More sharing options...
Josh Posted May 23, 2017 Share Posted May 23, 2017 That's a nice script. BTW, the end of a multiline comment in Lua is actually just "]]". Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Einlander Posted May 24, 2017 Author Share Posted May 24, 2017 Updated Opening Post. Found that there was a lot of badly thought out code, unused variables and questionable math. Did a complete rewrite to make it cleaner and use better time tracking. 1 Quote Link to comment Share on other sites More sharing options...
Rick Posted May 24, 2017 Share Posted May 24, 2017 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.