// EventScripts corelib v0.5
//  This library is used and shared by other scripts.

block load
{
  es_xsetinfo _tempcore 0

  // register the "stack" and "while" commands
  es_xdoblock corelib/stack_register
  es_xdoblock corelib/while_register
  // register the "foreach" command 
  es_xdoblock corelib/foreach_register

}

// foreach loops are supported through corelib
// syntax:
// foreach player <var> <identifier> "<command>"
// foreach token <var> "<string>" "<separator>" "<command>"
// Originally submitted by [NATO]Hunter
block foreach
{
  es_xsetinfo _foreachcmd 0
  es_xgetargv _foreachcmd 1
  if (server_var(_foreachcmd) equalto "player") do
  {
    es stack push _foreach_stack server_var(_foreachcommand)
    es stack push _foreach_stack server_var(_foreachblock)
    es stack push _foreach_stack server_var(_foreachvar)
    es stack push _foreach_stack server_var(_foreachtarget)
    es stack push _foreach_stack server_var(_foreach_keyname)
        
    // sub command "player"
    es_xgetargv _foreachvar 2
    es_xsetinfo _foreachplayer 0
    if (server_var(_foreachvar) != 0) do
    {
      es_xgetargv _foreachtarget 3

      // check for group/sort/team identifier
      if ("#" in server_var(_foreachtarget)) do
      {
        // we need to preserve the stack so foreach can be called from within itself.
        es_xmath _foreach_keycount + 1
        es_format _foreach_keyname "_foreach_playerlist%1" server_var(_foreach_keycount)
        // create the keygroup with the player information
        es_createplayerlist server_var(_foreach_keyname)

        // expand a group/sort/team of players
        es_xgetargv _foreachcommand 4
        es_format _foreachblock "es_xdoblock corelib/foreach_player_command_%1" server_var(_foreachtarget)
        // run the identifier block on every player
        es_xsetinfo _foreachplayer 0
        es_foreachkey _foreachplayer in server_var(_foreach_keyname) server_var(_foreachblock)
        es_keygroupdelete server_var(_foreach_keyname)
      }
      else do
      {
        // check for single player
        // expand a single player
        es_xsetinfo _foreachplayer 0
        es_getuserid _foreachplayer server_var(_foreachtarget)
        // check for a valid user
        if (server_var(_foreachplayer) > 0) do
        {
          es_xsetinfo _foreachcommand 0
          es_xgetargv _foreachcommand 4
    	    // command block
          es_xdoblock corelib/foreach_player_command_#all
        }
      }

    }
    stack pop _foreach_keyname _foreach_stack
    stack pop _foreachtarget _foreach_stack
    stack pop _foreachvar _foreach_stack
    stack pop _foreachblock _foreach_stack
    stack pop _foreachcommand _foreach_stack

    // end of sub command "player"
  }
  else do
  {
    if (server_var(_foreachcmd) equalto "token") do
    {
      // sub command "token"
      // check arguments
      es_xsetinfo _foreachvar 0
      es_xgetargv _foreachvar 2
      if (server_var(_foreachvar) != "0") do
      {
        es_xsetinfo _foreachstring 0
        es_xgetargv _foreachstring 3
        if (server_var(_foreachstring) != "0") do
        {
          es_xsetinfo _foreachseparator 0
          es_xgetargv _foreachseparator 4
          if (server_var(_foreachseparator) != "0") do
          {
            es_xsetinfo _foreachcommand 0
            es_xgetargv _foreachcommand 5
            if (server_var(_foreachcommand) != "0") do
            {
             // loop through the string
             es_xdoblock corelib/foreach_token_loop
            }
          }
        }
      }
      // end of sub command "token"
    }
  }
}
// set up the token parts
block foreach_token_cmd
{
  es_token _foreachtarget server_var(_foreachstring) 1 server_var(_foreachseparator)
  es_string _foreachstring replace server_var(_foreachtarget)
  es_setinfo server_var(_foreachvar) server_var(_foreachtarget)
  es alias _foreachcorecmd server_var(_foreachcommand)
  _foreachcorecmd
  es_xdoblock corelib/foreach_token_loop
}
// get the next token
block foreach_token_loop
{
  es_xsetinfo _foreachtarget 0
  es_token _foreachtarget server_var(_foreachstring) 0 server_var(_foreachseparator)
  if (server_var(_foreachtarget) > "0") then es_xdoblock corelib/foreach_token_cmd
}
// performe the command on a group/team/sort of players
// all players
block foreach_player_command_#all
{
  // set up the var and run the command
  es_setinfo server_var(_foreachvar) server_var(_foreachplayer)
  es alias _foreachcorecmd server_var(_foreachcommand)
  _foreachcorecmd
}
// unassigned players
block foreach_player_command_#un
{
  es_keygetvalue _tempcore server_var(_foreach_keyname) server_var(_foreachplayer) teamid
  if (server_var(_tempcore) equalto "0") do
  {
    // command block
    es_xdoblock corelib/foreach_player_command_#all
  }
}
// spectators
block foreach_player_command_#spec
{
  es_keygetvalue _tempcore server_var(_foreach_keyname) server_var(_foreachplayer) teamid
  if (server_var(_tempcore) equalto "1") do
  {
    // command block
    es_xdoblock corelib/foreach_player_command_#all
  }
}
// terrorists
block foreach_player_command_#t
{
  es_keygetvalue _tempcore server_var(_foreach_keyname) server_var(_foreachplayer) teamid
  if (server_var(_tempcore) equalto "2") do
  {
    // command block
    es_xdoblock corelib/foreach_player_command_#all
  }
}
// counter-terrorists
block foreach_player_command_#ct
{
  es_keygetvalue _tempcore server_var(_foreach_keyname) server_var(_foreachplayer) teamid
  if (server_var(_tempcore) equalto "3") do
  {
    // command block
    es_xdoblock corelib/foreach_player_command_#all
  }
}
// human players
block foreach_player_command_#human
{
  es_keygetvalue _tempcore server_var(_foreach_keyname) server_var(_foreachplayer) isbot
  if (server_var(_tempcore) equalto "0") do
  {
    // command block
    es_xdoblock corelib/foreach_player_command_#all
  }
}
// cpu/npc/bot players
block foreach_player_command_#bot
{
  es_keygetvalue _tempcore server_var(_foreach_keyname) server_var(_foreachplayer) isbot
  if (server_var(_tempcore) equalto "1") do
  {
    // command block
    es_xdoblock corelib/foreach_player_command_#all
  }
}
// living players
block foreach_player_command_#alive
{
  es_keygetvalue _tempcore server_var(_foreach_keyname) server_var(_foreachplayer) isdead
  if (server_var(_tempcore) equalto "0") do
  {
    // command block
    es_xdoblock corelib/foreach_player_command_#all
  }
}
// dead players
block foreach_player_command_#dead
{
  es_keygetvalue _tempcore server_var(_foreach_keyname) server_var(_foreachplayer) isdead
  if (server_var(_tempcore) equalto "1") do
  {
    // command block
    es_xdoblock corelib/foreach_player_command_#all
  }
}
block foreach_register
{
  // if the foreach command isn't already registered
  es_xexists _tempcore command "foreach"
  if (server_var(_tempcore) == 0) do
  {
    es_xsetinfo _foreach_keycount 0
    es_xsetinfo _foreach_keyname 0
    es_xsetinfo _foreachcommand 0
    es_xsetinfo _foreachblock 0
    es_xsetinfo _foreachvar 0
    es_xsetinfo _foreachtarget 0

    stack create _foreach_stack
    es_xregcmd foreach corelib/foreach "Allows you to loop a command over different things. Currently supports 'foreach player' and 'foreach token'."
  }
}
block foreach_test1
{
  log on
  foreach player _tempuserid #all "es_sexec server_var(_tempuserid) kill"
  foreach player _tempuserid #ct "es_tell server_var(_tempuserid) #lightgreen You died on CT team!"
  foreach player _tempuserid #t "es_tell server_var(_tempuserid) #lightgreen You died on T team!"
  foreach player _tempuserid #spec "es_tell server_var(_tempuserid) #lightgreen You can't die on Spec team!"
}
block foreach_test2
{
  log on
  foreach player _tempuserid #bot "es_sexec server_var(_tempuserid) say I am a silly bot!"
  foreach player _tempuserid #human "es_sexec server_var(_tempuserid) say I am a real player!"
}
block foreach_test3
{
  log on
  foreach player _tempuserid #all "es_xsetinfo _tempusername 0;es_getplayername _tempusername server_var(_tempuserid);es_cexec server_var(_tempuserid) say Hello, my name is server_var(_tempusername)."
}
block foreach_test4
{
  log on
  foreach token _temptoken "a-s-d-f-g-h-j-k-l" "-" "es_log server_var(_temptoken) is a part of the token."
  foreach token _temptoken "a-s-d-f-g-h-j-k-l" "-" "es_msg server_var(_temptoken) is a part of the token."
}

block foreach_test5
{
  log on
  foreach player _tempuserid #bot "es_xdoblock corelib/foreach_test5b"
  foreach player _tempuserid #human "es_xdoblock corelib/foreach_test5c"
}

block foreach_test5b
{
  es_xsetinfo _tempname 0
  es_getplayername _tempname server_var(_tempuserid)
  es_msg Looping bot: server_var(_tempuserid)
  foreach player _tempuserid2 #ct "es_msg server_var(_tempname) hates #ct server_var(_tempuserid2)"
}

block foreach_test5c
{
  es_setinfo _tempname 0
  es_getplayername _tempname server_var(_tempuserid)
  foreach player _tempuserid2 #all "es_msg server_var(_tempname) hates #all server_var(_tempuserid2)"
  foreach player _tempuserid2 #ct "es_msg server_var(_tempname) loves #ct server_var(_tempuserid2)"
}


// while loops are supported through corelib
// syntax:
// while "server_var(hello) > 1" "blockname"
block while
{
  // get condition
  // get command
  // create alias self "if cond then command;self"
  if (server_var(_whilestatement) equalto 0) do
  {
    stack create _whilestack
  }
  else do
  {
    es stack push _whilestack server_var(_whilestatement)
    es stack push _whilestack server_var(_whilecmd)
  }
  es_xgetargv _whilecond 1
  if (server_var(_whilecond) notequalto 0) do
  {
    es_xgetargv _whilecmd 2
    if (server_var(_whilecmd) notequalto 0) do
    {
      es_format _whilecmd "%1;_whileloop" server_var(_whilecmd)
      es alias _whilecmd server_var(_whilecmd)
      es_format _whilestatement "if (%1) then _whilecmd" server_var(_whilecond)
      es alias _whileloop server_var(_whilestatement)
      _whileloop
    }
  }
  stack pop _whilecmd _whilestack
  es alias _whilecmd server_var(_whilecmd)
  stack pop _whilestatement _whilestack
  es alias _whileloop server_var(_whilestatement)
}

// called to register the while command
block while_register
{
  // if the stack command isn't already registered
  es_xexists _tempcore command "while"
  if (server_var(_tempcore) == 0) do
  {
    // while variables
    es_xsetinfo _whilestatement 0
    es_xsetinfo _whilecmd 0
    es_xsetinfo _whilecond 0

    es_xregcmd while corelib/while "Allows you to loop with a condition and a block."
  }
}

// exists to test the while loop command, ignore
// es_doblock corelib/while_test to test the while command
block while_test
{
  log on
  es_setinfo _while_test2 9
  while "server_var(_while_test2) > 0" "es_xdoblock corelib/while_test2"
  if (server_var(_while_test2) > 0) then es_log FAILURE: while test failed. RED RED RED RED
  es_setinfo _while_test3 5
  while "server_var(_while_test3) > 0" "es_xdoblock corelib/while_test3"
  if (server_var(_while_test2) > 0) then es_log FAILURE: while test2 failed. RED RED RED RED
  if (server_var(_while_test3) > 0) then es_log FAILURE: while test3 failed. RED RED RED RED
  es_setinfo _while_test4 0
  while "server_var(_while_test4) < 6" "es_xmath _while_test4 + 1"
  if (server_var(_while_test3) > 0) then es_log FAILURE: while test4 failed. RED RED RED RED
}

// exists to test the while loop command, ignore
block while_test2
{
  es_log _while_test2: server_var(_while_test2)
  es_xmath _while_test2 - 1
}

// exists to test the while loop command, ignore
block while_test3
{
  es_log _while_test3: server_var(_while_test3)
  // call an inner while loop
  es_setinfo _while_test2 4
  while "server_var(_while_test2) > 0" "es_xdoblock corelib/while_test2"

  es_setinfo _while_test2 5
  while "server_var(_while_test2) > 0" "es_xdoblock corelib/while_test2"

  es_xmath _while_test3 - 1
}

// stacks are supported entirely through corelib
// the following block handles everything for the 'stack' console command
block stack
{
  // get the operation they want to do
  es_xgetargv _tempcore 1
  if (server_var(_tempcore) equalto "pop") do
  {
    es_xdoblock corelib/stack_pop
  }
  else do
  {
    if (server_var(_tempcore) equalto "push") do
    {
      es_xdoblock corelib/stack_push
    }
    else do
    {
      if (server_var(_tempcore) equalto "create") do
      {
        es_xdoblock corelib/stack_create
      }
      else do
      {
        if (server_var(_tempcore) equalto "delete") do
        {
          es_xdoblock corelib/stack_delete
        }
        else do
        {
          if (server_var(_tempcore) equalto "getlength") do
          {
            es_xdoblock corelib/stack_getlength
          }
          else do
          {
            // nothing
            // TODO: stack help
            // TODO: stack save
            // TODO: stack load
          }
        }
      }
    }
  }
}

block stack_register
{
  // if the stack command isn't already registered
  es_xexists _tempcore command "stack"
  if (server_var(_tempcore) == 0) do
  {
    es_xregcmd stack corelib/stack "Allows you to do various stack operations with a named stack. Supports create, delete, pop, push, getlength."
  }
}

// stack create stackname
block stack_create
{
  // get the stack name
  es_xgetargv _tempcore 2
  if (server_var(_tempcore) != 0) do
  {
    es_xsetinfo _stackname 0
    es_format _stackname "stack_%1" server_var(_tempcore)
    es_xsetinfo _stackexists 0
    es_exists _stackexists keygroup server_var(_stackname)
    if (server_var(_stackexists) == 0) do
    {
      es_keygroupcreate server_var(_stackname)
      es_keycreate server_var(_stackname) private
      es_keysetvalue server_var(_stackname) private type stack
      es_keysetvalue server_var(_stackname) private head 0
      es_keysetvalue server_var(_stackname) private tail -1
      es_keysetvalue server_var(_stackname) private length 0
    }
    else do
    {
      es echo corelib: The stack already exists: server_var(_stackname).
    }
  }
  else do
  {
    es echo corelib: Invalid arguments to stack create. Syntax: stack create <stackname>
  }
}

// stack push stackname value
block stack_push
{
  // get the stack name
  es_xgetargv _tempcore 2
  if (server_var(_tempcore) != 0) do
  {
    es_xsetinfo _stackname 0
    es_format _stackname "stack_%1" server_var(_tempcore)
    es_xsetinfo _stackexists 0
    es_exists _stackexists keygroup server_var(_stackname)
    if (server_var(_stackexists) == 1) do
    {
      es_xsetinfo _stackvalue 0
      es_xgetargv _stackvalue 3
      // new value is tail + 1
      es_keygetvalue _tempcore server_var(_stackname) private tail
      es_xmath _tempcore + 1
      es_keycreate server_var(_stackname) server_var(_tempcore)
      // add the stack value to the stack
      es_keysetvalue server_var(_stackname) server_var(_tempcore) value server_var(_stackvalue)
      // update the new tail value
      es_keysetvalue server_var(_stackname) private tail server_var(_tempcore)
      // cheat: length is tail + 1
      es_xmath _tempcore + 1
      es_keysetvalue server_var(_stackname) private length server_var(_tempcore)
    }
    else do
    {
      if (server_var(eventscripts_debug) > -1) then echo corelib: The stack doesn't exist: server_var(_stackname).
    }
  }
  else do
  {
    if (server_var(eventscripts_debug) > -1) then  echo corelib: Invalid arguments to stack push. Syntax: stack push <stackname> <value>
  }
}

// stack pop var stackname
block stack_pop
{
  // get the stack name
  es_xgetargv _tempcore 3
  if (server_var(_tempcore) != 0) do
  {
    es_xsetinfo _stackname 0
    es_format _stackname "stack_%1" server_var(_tempcore)
    es_xsetinfo _stackexists 0
    es_exists _stackexists keygroup server_var(_stackname)
    if (server_var(_stackexists) == 1) do
    {
      es_xsetinfo _stackvar 0
      es_xgetargv _stackvar 2
      // value is @ tail
      es_keygetvalue _tempcore server_var(_stackname) private tail
      if (server_var(_tempcore) > -1) do
      {
        es_keygetvalue server_var(_stackvar) server_var(_stackname) server_var(_tempcore) value
        es_keydelete server_var(_stackname) server_var(_tempcore)
        // cheat: length is tail + 1
        es_keysetvalue server_var(_stackname) private length server_var(_tempcore)
        es_xmath _tempcore - 1
        // update the new tail value
        es_keysetvalue server_var(_stackname) private tail server_var(_tempcore)
      }
      else do
      {
        if (server_var(eventscripts_debug) > 0) then echo corelib: ERROR: Pop attempt when stack empty.
      }
    }
    else do
    {
      if (server_var(eventscripts_debug) > 0) then echo corelib: The stack doesn't exist: server_var(_stackname).
    }
  }
  else do
  {
    if (server_var(eventscripts_debug) > 0) then echo corelib: Invalid arguments to stack pop. Syntax: stack pop <var> <stackname>
  }
}

// stack delete stackname
block stack_delete
{
  // get the stack name
  es_xgetargv _tempcore 2
  if (server_var(_tempcore) != 0) do
  {
    es_xsetinfo _stackname 0
    es_format _stackname "stack_%1" server_var(_tempcore)
    es_xsetinfo _stackexists 0
    es_exists _stackexists keygroup server_var(_stackname)
    if (server_var(_stackexists) == 1) do
    {
      es_keygroupdelete server_var(_stackname)
    }
    else do
    {
      es echo corelib: The stack doesn't exist: server_var(_stackname).
    }
  }
  else do
  {
    es echo corelib: Invalid arguments to stack delete. Syntax: stack delete <stackname>
  }
}

// stack getlength var stackname
block stack_getlength
{
  // get the stack name
  es_xgetargv _tempcore 3
  if (server_var(_tempcore) != 0) do
  {
    es_xsetinfo _stackname 0
    es_format _stackname "stack_%1" server_var(_tempcore)
    es_xsetinfo _stackexists 0
    es_exists _stackexists keygroup server_var(_stackname)
    if (server_var(_stackexists) == 1) do
    {
      es_xsetinfo _stackvar 0
      es_xgetargv _stackvar 2
      es_keygetvalue server_var(_stackvar) server_var(_stackname) private length
    }
    else do
    {
      es echo corelib: The stack doesn't exist: server_var(_stackname).
    }
  }
  else do
  {
    es echo corelib: Invalid arguments to stack delete. Syntax: stack getlength <var> <stackname>
  }
}

// this function exists to test the stack commands, you can ignore
block stack_test
{
  log on
  es_xsetinfo _testcore 0
  stack create teststack
  stack push teststack 1
  stack pop _testcore teststack
  if (server_var(_testcore) != 1) then es_log create/push/pop failed. RED RED RED
  stack push teststack 1
  stack push teststack 2
  stack push teststack "hello"
  stack push teststack 3
  stack push teststack 4
  stack pop _testcore teststack
  if (server_var(_testcore) != 4) then es_log multi-push/pop failed. RED RED RED
  stack pop _testcore teststack
  stack pop _testcore teststack
  if (server_var(_testcore) != "hello") then es_log multi-push/pop failed2. RED RED RED
  stack push teststack 5
  stack pop _testcore teststack
  if (server_var(_testcore) != "5") then es_log multi-push/pop failed3. RED RED RED
  stack pop _testcore teststack
  if (server_var(_testcore) != "2") then es_log multi-push/pop failed4. RED RED RED
  stack getlength _testcore teststack
  if (server_var(_testcore) != "1") then es_log getlength failed: server_var(_testcore) RED RED RED
  stack delete teststack
}

// block to increase reference count for eventscripts_noisy (and enable it)
//    if all scripts use this then you can safely load/unload
//    noisy scripts in any order
block noisy_on
{
  if (server_var(eventscripts_noisy) > 1) do
  {
    if (server_var(noisy_refcount) > 0) do
    {
      // increase the reference count because
      //   we're not the only one using noisy
      es_xmath noisy_refcount + 1
      es_log Noisy already on: increased noisy_refcount to server_var(noisy_refcount) .
    }
    else do
    {
      // start the reference count at 2
      //   since someone else didn't increment it
      //   but turned noisy on anyway. Bad people.
      es_xsetinfo noisy_refcount 2
      es_log Noisy already on: started noisy_refcount at server_var(noisy_refcount) .
    }
  }
  else do
  {
    if (server_var(noisy_refcount) > 0) do
    {
        // ERROR: You should never have noisy off when
        //  the refcount is higher than 0! Who did that?
        es_log Warning: eventscripts_noisy was OFF, but it's refcount was server_var(noisy_refcount)
        es_xsetinfo eventscripts_noisy 1
        es_xmath noisy_refcount + 1
        es_log Noisy on: increased noisy_refcount to server_var(noisy_refcount) .
    }
    else do
    {
      // no one was here before us, start the procedure
      es_xsetinfo noisy_refcount 1
      es_xsetinfo eventscripts_noisy 1
      es_log Noisy on: started noisy_refcount at server_var(noisy_refcount) .
    }
  }
}

// block to reduce reference count for eventscripts_noisy (and disable it if needed)
//    if all scripts use this then you can safely load/unload
//    noisy scripts in any order
block noisy_off
{
  if (server_var(noisy_refcount) > 0) do
  {
    // decrease the reference count
    es_xmath noisy_refcount - 1
    if (server_var(noisy_refcount) > 0) do
    {
      es_log Noisy stays on: decreased noisy_refcount to server_var(noisy_refcount) .
    }
    else do
    {
      // everyone is done with noisy
      //   we can disable it
      es_xsetinfo eventscripts_noisy 0
      es_log Noisy off: noisy_refcount dropped to server_var(noisy_refcount) .
    }
  }
  else do
  {
    es_log Warning: eventscripts_noisy refcount has been messed-up! Bad script somewhere.
  }
}
