In-Game Timer

Avatar
UsCobra11
272 Posts
Posted Aug 26, 2012
Hi, I want to create an on-screen timer (Like challenge mode maps) in my map that starts with a trigger, and ends with a trigger. Once the ending trigger is hit, the time stays on the screen for a while, and then fades. What would be an easy, clean way to create this?
Advertisement
Registered users don’t see ads! Register now!
Avatar
FelixGriffin
2,680 Posts
Posted Aug 26, 2012
Replied 36 minutes later
Use 2 game_texts (minute, second) with 2 math_counters and a logic_timer subtracting one from the seconds. OutValue -> game_text -> SetText, OnHitMin -> minutes -> Subtract -> 1, OnHitMin -> !self -> SetValue -> 59 (after 1 second).
Avatar
UsCobra11
272 Posts
Posted Aug 26, 2012
Replied 16 minutes later

FelixGriffin wrote:
Use 2 game_texts (minute, second) with 2 math_counters and a logic_timer subtracting one from the seconds. OutValue -> game_text -> SetText, OnHitMin -> minutes -> Subtract -> 1, OnHitMin -> !self -> SetValue -> 59 (after 1 second).

Is that a timer ticking down? I need a timer ticking up.
Is there a more detailed tutorial somewhere? I'm not that familiar with logic_timers.

Avatar
HMW
806 Posts
Posted Aug 26, 2012
Replied 13 minutes later

https://developer.valvesoftware.com/wiki/Logic_timer

https://developer.valvesoftware.com/wiki/Math_counter

https://developer.valvesoftware.com/wiki/Game_text

Presto!

(You can easily convert Felix's example to a stopwatch-style timer by reversing the various min/max and add/subtract things.)

Avatar
wstrika
200 Posts
Posted Aug 26, 2012
Replied 1 hour later
Would be nice if you could somehow figure out how to overlay an in-game timer on any map you play...would make recording speedruns of custom maps a lot easier with a more universal timer.
Avatar
FelixGriffin
2,680 Posts
Posted Aug 26, 2012
Replied 1 hour later
I could try writing a script to do that, it should be possible using AddOutput and SetX/SetY. Just make something RunScriptCode it, preferably something unmoving. The worldspawn, maybe?
Avatar
UsCobra11
272 Posts
Posted Aug 26, 2012
Replied 14 minutes later

FelixGriffin wrote:
I could try writing a script to do that, it should be possible using AddOutput and SetX/SetY. Just make something RunScriptCode it, preferably something unmoving. The worldspawn, maybe?

Why aren't you community contributor? You are awesome dude, you make great stuff, and you helped me with the most important part in my map. Always volunteering to create amazing things for others.
:thumbup: I'll discuss it with the other mods.

Also... that'd be cool!

Avatar
wstrika
200 Posts
Posted Aug 26, 2012
Replied 37 minutes later

FelixGriffin wrote:
I could try writing a script to do that, it should be possible using AddOutput and SetX/SetY. Just make something RunScriptCode it, preferably something unmoving. The worldspawn, maybe?

Yes, please. That would help a huge amount.

Avatar
ChickenMobile
2,460 Posts
Posted Aug 26, 2012
Replied 3 hours later
The only problem with changing a game_text is that you constantly need to display the game_text in order for it not to 'fade'. I would have the hold time at a second and the fade times at 0 so then you can use the 'Display' input to update every second without the game_text overlaying itself and becoming very bright.

Here's some code I made up if you want to continue working on it. There might be a couple of errors because I haven't actually tested it yet.

//Global counter
counter <- 0

//Display time
function DisplayText()
{
   EntFire( "@DisplayText", "setText", ConvertToFormat(), 0 )
   EntFire( "@DisplayText", "Display", "", 0.01 )

   //Trigger the relay for each second
   counter++
   //The relay here should just call the DisplayText() function
   EntFire( "@DisplayText_Relay", "Trigger", "", 1.0 )
}

function ConvertToFormat()
{
   //using modulus logic we can figure out hours mins and left over seconds from counter
   local modMinuteSeconds = counter % 3600
   local hours = (counter - modMinuteSeconds) / 3600
   local modSecs = modMinuteSeconds % 60
   local mins = (modMinuteSeconds - modSecs) / 60
   local secs = modSecs

   local Smins = ""
   local Ssecs = ""

   if(mins < 10)
   {
      Smins = "0" + mins.tostring()
   }
   else {
      Smins = mins.tostring()
   }
   if(secs < 10)
   {
      Ssecs = "0" + secs.tostring()
   }
   else {
      Ssecs = secs.tostring()
   }

   //Insert time conversion here from seconds from counter to relevant format 00:00:00

   local displayTime = hours  + ":" + Smins  + ":" + Ssecs
   return displayTime
}

// Setup Game_Text - called on mapspawn
function SetPos()
{
printl("starting timer")

   EntFire( "@DisplayText", "SetTextColor", "210 210 210 128", 0.0 )
   EntFire( "@DisplayText", "SetTextColor2", "50 90 116 128", 0.0 )
   EntFire( "@DisplayText", "SetPosY", "0.85", 0.0 )
   EntFire( "@DisplayText", "SetPosX", "0.1", 0.0 )
   EntFire( "@DisplayText", "SetText", "00:00:00", 0.0 )

   DisplayText()
}


Ok So it works and I tested it. Here's the script file and all the entities in a .vmf you will need in order to get this to work:

counter.7z

I beat you Felix G!

Hope this is what you want UsCobra. You can change the position of the text inside the .nut file.

Attachments
counter.7z
0.00 MB 57 downloads
Avatar
FelixGriffin
2,680 Posts
Posted Aug 27, 2012
Replied 10 hours later
Nice! So far the only thing I have working is creating the entities from the NUT

function init(){
   timer <- Entities.CreateByClassname("logic_timer"); //The timer
   EntFireByHandle(timer,"refiretime","1",0,null,null); //Set the timer to 1 second
   EntFireByHandle(timer,"addoutput","targetname felix_script_timer",0,null,null);
   text1 <- Entities.CreateByClassname("game_text");
   text2 <- Entities.CreateByClassname("game_text");
   EntFireByHandle(text1,"addoutput","targetname felix_script_text1",0,null,null);
   EntFireByHandle(text2,"addoutput","targetname felix_script_text2",0,null,null);
...etc...

I'll change the names to work with your part, then you can run it without anything special in the BSP file. Just bind something to ent_fire worldspawn runscriptfile timerscript.nut and hit it to start the clock.

Avatar
UsCobra11
272 Posts
Posted Aug 27, 2012
Replied 22 minutes later
Tested it out in my own map, works out great Chicken. Thanks :thumbup:
Avatar
ChickenMobile
2,460 Posts
Posted Aug 27, 2012
Replied 9 hours later
BAM - winning. I'll edit this later so you can just spawn the entities through press of key.
Avatar
FelixGriffin
2,680 Posts
Posted Aug 27, 2012
Replied 3 hours later
Ha ha! I posted first!

At the beginning:

function init(){
   text <- Entities.CreateByClassname("game_text");
   EntFireByHandle(text,"addoutput","targetname @DisplayText",0,null,null);
   EntFireByHandle(text,"addoutput","spawnflags 1",0,null,null);
   EntFireByHandle(text,"addoutput","fadein 0.01",0,null,null);
   EntFireByHandle(text,"addoutput","fadeout 0.01",0,null,null);
   EntFireByHandle(text,"addoutput","holdtime 1.0",0,null,null);
}

At the end, replace SetPos(){ ... } with this:

function Startup(){
   printl("Starting Timer...");

   init();

   EntFire( "@DisplayText", "SetTextColor", "210 210 210 128", 0.0 );
   EntFire( "@DisplayText", "SetTextColor2", "50 90 116 128", 0.0 );
   EntFire( "@DisplayText", "SetPosY", "0.85", 0.0 );
   EntFire( "@DisplayText", "SetPosX", "0.1", 0.0 );
   EntFire( "@DisplayText", "SetText", "00:00:00", 0.0 );

   DisplayText();
}

Startup();

At the beginning, replace EntFire( "@DisplayText_Relay", "Trigger", "", 1.0 ) with

EntFireByHandle(!self,"RunScriptCode","DisplayText();",1.0,null,null);

And you should have a working timer! Use ent_fire worldspawn RunScriptFile (whatever you called the file).nut to start the timer!

Alter the values to your liking.

Avatar
ChickenMobile
2,460 Posts
Posted Aug 28, 2012
Replied 6 hours later

FelixGriffin wrote:
Ha ha! I posted first!

Hrmm so you did...

Quote:
hey wstrika
did you want me to edit the script so then you can turn cheats on and then have the timer appear?
by binding a button for example
god damn the fucking water monster in half life
NOPE NOPE NOPE NOPE
Nope?
wstrika,
wrathofmobius,
I mean wstrika
wstrika,
wstrika,
wstrika
wstrika
wstrika,
wstrika,
FINE THEN I WONT

back on topic:
perhaps the script can go in the misc downloads section so then it can be shared? (some people are idiots and wont know how to change code or create .nut files to save their life)

Avatar
FelixGriffin
2,680 Posts
Posted Aug 28, 2012
Replied 11 hours later
Good idea. I'll upload it later today then.
Avatar
wstrika
200 Posts
Posted Aug 28, 2012
Replied 1 hour later

ChickenMobile wrote:
FelixGriffin wrote:

Ha ha! I posted first!

Hrmm so you did...
Quote:

hey wstrika
did you want me to edit the script so then you can turn cheats on and then have the timer appear?
by binding a button for example
god damn the fucking water monster in half life
NOPE NOPE NOPE NOPE
Nope?
wstrika,
wrathofmobius,
I mean wstrika
wstrika,
wstrika,
wstrika
wstrika
wstrika,
wstrika,
FINE THEN I WONT

back on topic:
perhaps the script can go in the misc downloads section so then it can be shared? (some people are idiots and wont know how to change code or create .nut files to save their life)

It would have to be something that started on mapload, maybe. Like a bind to a key that restarts the map, and loads it with the timer overlay.

Avatar
FelixGriffin
2,680 Posts
Posted Aug 28, 2012
Replied 1 hour later
Maybe. I'm not sure if that's possible...

Maybe if it were in a preload script, but that kind of defeats the purpose.

Avatar
ChickenMobile
2,460 Posts
Posted Aug 29, 2012
Replied 8 hours later

You could always edit your mapspawn.nut located scripts/vscripts and put in all the relevant commands needed on startup. Therefore you will always have the timer going as soon as you start the level (your computer only).

//********************************************************************************************
//MAPSPAWN.nut is called on newgame or transitions
//********************************************************************************************
printl("==== calling mapspawn.nut")

function init(){
   text <- Entities.CreateByClassname("game_text");
   EntFireByHandle(text,"addoutput","targetname @DisplayText",0,null,null);
   EntFireByHandle(text,"addoutput","spawnflags 1",0,null,null);
   EntFireByHandle(text,"addoutput","fadein 0.01",0,null,null);
   EntFireByHandle(text,"addoutput","fadeout 0.01",0,null,null);
   EntFireByHandle(text,"addoutput","holdtime 1.0",0,null,null);
}

function Startup(){
   printl("Starting Timer...");

   init();

   EntFire( "@DisplayText", "SetTextColor", "210 210 210 128", 0.0 );
   EntFire( "@DisplayText", "SetTextColor2", "50 90 116 128", 0.0 );
   EntFire( "@DisplayText", "SetPosY", "0.85", 0.0 );
   EntFire( "@DisplayText", "SetPosX", "0.1", 0.0 );
   EntFire( "@DisplayText", "SetText", "00:00:00", 0.0 );

   DisplayText();
}

Startup();

//Global counter
counter <- 0

//Display time
function DisplayText()
{
   EntFire( "@DisplayText", "setText", ConvertToFormat(), 0 )
   EntFire( "@DisplayText", "Display", "", 0.01 )

   //Trigger the relay for each second
   counter++
   //The relay here should just call the DisplayText() function
   EntFireByHandle(!self,"RunScriptCode","DisplayText();",1.0,null,null);
}

function ConvertToFormat()
{
   //using modulus logic we can figure out hours mins and left over seconds from counter
   local modMinuteSeconds = counter % 3600
   local hours = (counter - modMinuteSeconds) / 3600
   local modSecs = modMinuteSeconds % 60
   local mins = (modMinuteSeconds - modSecs) / 60
   local secs = modSecs

   local Smins = ""
   local Ssecs = ""

   if(mins < 10)
   {
      Smins = "0" + mins.tostring()
   }
   else {
      Smins = mins.tostring()
   }
   if(secs < 10)
   {
      Ssecs = "0" + secs.tostring()
   }
   else {
      Ssecs = secs.tostring()
   }

   //Insert time conversion here from seconds from counter to relevant format 00:00:00

   local displayTime = hours  + ":" + Smins  + ":" + Ssecs
   return displayTime
}

EDIT: turns out this doesn't work and doesn't want to recognise any Source specific code. Wonder if I can reference the script file though.

EDIT2: YES YES YES YES! I got it to work. Also there is a slight problem in your code Felix: it should be self and not !self.

Add this into your mapspawn.nut

EntFire( "bignet", "RunScriptFile", "chicken_scripts/counter", 1.5 );

And then copy this code and put it in a .nut file located scripts/vscripts/chicken_scripts/ named counter.nut


//Global counter
counter <- 0

//Display time
function DisplayText()
{
   EntFire( "@DisplayText", "setText", ConvertToFormat(), 0 )
   EntFire( "@DisplayText", "Display", "", 0.01 )

   //Trigger the relay for each second
   counter++
   //The relay here should just call the DisplayText() function
   EntFireByHandle(self,"RunScriptCode","DisplayText()",1.0,null,null);
}

function ConvertToFormat()
{
   //using modulus logic we can figure out hours mins and left over seconds from counter
   local modMinuteSeconds = counter % 3600
   local hours = (counter - modMinuteSeconds) / 3600
   local modSecs = modMinuteSeconds % 60
   local mins = (modMinuteSeconds - modSecs) / 60
   local secs = modSecs

   local Smins = ""
   local Ssecs = ""

   if(mins < 10)
   {
      Smins = "0" + mins.tostring()
   }
   else {
      Smins = mins.tostring()
   }
   if(secs < 10)
   {
      Ssecs = "0" + secs.tostring()
   }
   else {
      Ssecs = secs.tostring()
   }

   //Insert time conversion here from seconds from counter to relevant format 00:00:00

   local displayTime = hours  + ":" + Smins  + ":" + Ssecs
   return displayTime
}

function init(){
   text <- Entities.CreateByClassname("game_text");
   EntFireByHandle(text,"addoutput","targetname @DisplayText",0,null,null);
   EntFireByHandle(text,"addoutput","spawnflags 1",0,null,null);
   EntFireByHandle(text,"addoutput","fadein 0",0,null,null);
   EntFireByHandle(text,"addoutput","fadeout 0",0,null,null);
   EntFireByHandle(text,"addoutput","holdtime 1.0",0,null,null);

   SendToConsole("sv_cheats 1")
}

function Startup(){
   printl("Starting Timer...");

   init();

   EntFire( "@DisplayText", "SetTextColor", "210 210 210 128", 0.0 );
   EntFire( "@DisplayText", "SetTextColor2", "50 90 116 128", 0.0 );
   EntFire( "@DisplayText", "SetPosY", "0.85", 0.0 );
   EntFire( "@DisplayText", "SetPosX", "0.1", 0.0 );
   EntFire( "@DisplayText", "SetText", "00:00:00", 0.0 );

   SendToConsole("sv_cheats 0")

   DisplayText();
}

Startup();

Avatar
wstrika
200 Posts
Posted Aug 29, 2012
Replied 10 hours later
Works like a charm, good work, Chicken. I suppose milliseconds are out of the question?
Advertisement
Registered users don’t see ads! Register now!
Avatar
FelixGriffin
2,680 Posts
Posted Aug 29, 2012
Replied 3 hours later
Not necessarily, but IDK how long it takes for each tick. It might get a bit off.

Also, why do you need cheats? Can't a script entfire whenever it wants to?

EDIT: I uploaded it to the Download Database, I hope you don't mind. http://forums.thinking.withportals.com/downloads.php?view=detail&df_id=2331