Material proxies programming

From Valve Developer Community
Jump to: navigation, search

Material proxies can perform specific tasks in a VMT. Even though the scripting is rudimentary, it stills allows to write basic programs. This page aims to show how to create basic logical connectors for VMTs using material proxies. The huge advantage of material proxies over VScripts is that they are allowed to run on most official Valve servers.

Any number of proxies can be added to a material; they will be executed in the order in which they appear.

If (x > y) {a = b} else {a = c}

The LessOrEqual allows to write a basic if (x > y) { a = b } else { a = c } condition. Removing the else is done by setting the same variable as resultVar and LessEqualVar.

The block of code below stores 1 ($a) into $c if the player speed ($x) is higher than 0 ($y), otherwise it stores 2 ($b) into $c.

VertexLitGeneric
{
        $x "0"
        $y "0"        
        $a "1"
        $b "2"
        $c "0"

	Proxies
	{
	
	      PlayerSpeed
      	      {				
          	       scale		        "1"     
          	       resultVar 		"$x"
       	      }

	      LessOrEqual
      	      {				
          	       srcVar1 		        "$x"   // if $x
           	       srcVar2 		        "$y"   // > $y       
          	       resultVar 		"$a"   // { $a =			
          	       greaterVar 	        "$b"   // $b }
        	       LessEqualVar 	        "$c"   // else { $a = $c }
              }

	}
}

If (x == y) {a = b} else {a = c}

It is possible to write an EQUALS operator with the use of three material proxies.

The block of code below stores 1 ($a) into $c if the player speed ($x) is exactly 300 ($y), otherwise it stores 2 ($b) into $c.

What it technically does is that is checks if there's a difference of 0 between $x and $y. Mathematically speaking, if the absolute value or the subtraction between two numbers is equal to 0, it means that the two numbers that were subtracted were the same.

VertexLitGeneric
{
        $x "0"
        $y "300"        
        $a "1"
        $b "2"
        $c "0"

        $zero "0"
        $xsubtract "0"

	Proxies
	{
	
	      PlayerSpeed
      	      {				
          	       scale		        "1"     
          	       resultVar 		"$x"
       	      }

	      Subtract				
      	      {			
	              srcVar1		        "$x"
		      srcVar2 		        "$y"
		      resultVar 		"$xsubtract"
       	      }

	      Abs										
      	      {									
		      srcVar1		        "$xsubtract"									
		      resultVar 		"$xsubtract"										
       	      }

	      LessOrEqual		
      	      {
          	      srcVar1 		        "$xsubtract" // if $x
           	      srcVar2 		        "$zero" // == $y (has a difference of 0 with $y)  
          	      resultVar 		"$a"   // { $a =			
          	      greaterVar 	        "$b"   // $b }
        	      LessEqualVar 	        "$c"   // else { $a = $c }   
       	      }

	}
}

if ($x > $y AND $j <= $k) {$a = $b} else {$a = $c}

It is possible to create AND operators using material proxies by multiplying 2 conditions together. For each condition : 0 = the condition is not met / 1 = the condition is met. Multiplying anything by 0 returns 0, therefore, if any of the two conditions is not met, the multiplication will always be equal to 0. It's only when each factor of the multiplication is over 0 that its result will be over 0.

The following code sets $frame to 1 if the player speed is over 200 AND that a random number associated with the entity is less or equal to 10, otherwise it sets $frame to 0.

VertexLitGeneric
{
	
        $speed            "0"
        $random           "0"     

        $zero             "0"
        $one              "1"
        $ten              "10"
        $th               "200"

        $speedcondition   "0"   // 0 = condition is not met / 1 = condition is met
        $randomconditon   "0"   // ''
        $bothconditions   "0"   // ''

	Proxies
	{
	
	      PlayerSpeed
      	      {				
          	       scale		        "1"     
          	       resultVar 		"$speed"
       	      }

	      LessOrEqual
      	      {				
          	       srcVar1 		        "$speed"             // if $speed
           	       srcVar2 		        "$th"                // > 200      
          	       resultVar 		"$speedcondition"    // { $speedcondition			
          	       greaterVar 	        "$one"               // = 1 }
        	       LessEqualVar 	        "$zero"              // else { $speedcondition = 0 }
              }

	      EntityRandom
      	      {				
          	       scale		        "100"     
          	       resultVar 		"$random"
       	      }

	      LessOrEqual
      	      {				
          	       srcVar1 		        "$random"             // if $random
           	       srcVar2 		        "$ten"                // > 10    
          	       resultVar 		"$randomconditon"     // { $randomconditon			
          	       greaterVar 	        "$zero"               // = 0 }
        	       LessEqualVar 	        "$one"                // else { $randomconditon = 1 }
              }


	      Multiply                                                // if ($speedcondition AND $randomconditon) > 0  {$bothconditions > 0} else {$bothconditions = 0}
      	      {				
          	       srcVar1 		        "$speedcondition"
           	       srcVar2 		        "$randomconditon"       
          	       resultVar 		"$bothconditions"   			
              }

	      LessOrEqual
      	      {				
          	       srcVar1 		        "$bothconditions"      // if $bothconditions
           	       srcVar2 		        "$zero"                // > 0    
          	       resultVar 		"$frame"               // { $frame			
          	       greaterVar 	        "$one"                 // = 1 }
        	       LessEqualVar 	        "$zero"                // else { $frame = 0 }
              }

	}
}

if ($x > $y OR $j > $k) {a = b} else {a = c}

It is possible to create OR operators using material proxies. It can be done by adding 2 conditions together. For each condition : 0 = the condition is not met / 1 = the condition is met. Adding the two conditions will provide a result higher than 0 if any of the two conditions is met, resulting in an "OR" operator.

The following code sets $frame to 1 if the player speed is over 200 OR if the player is looking almost at the center of the material ($view > 80), otherwise it sets $frame to 0.

VertexLitGeneric
{
	
        $speed            "0"
        $view             "0"     

        $zero             "0"
        $one              "1"
        $eighty           "80"
        $th               "200"

        $speedcondition   "0"   // 0 = condition is not met / 1 = condition is met
        $randomconditon   "0"   // ''
        $anycondition     "0"   // ''

	Proxies
	{
	
	      PlayerSpeed
      	      {				
          	       scale		        "1"     
          	       resultVar 		"$speed"
       	      }

	      LessOrEqual
      	      {				
          	       srcVar1 		        "$speed"             // if $speed
           	       srcVar2 		        "$th"                // > 200      
          	       resultVar 		"$speedcondition"    // { $speedcondition			
          	       greaterVar 	        "$one"               // = 1 }
        	       LessEqualVar 	        "$zero"              // else { $speedcondition = 0 }
              }

	      PlayerView
      	      {				
          	       scale		        "100"     
          	       resultVar 		"$view"
       	      }

	      LessOrEqual
      	      {				
          	       srcVar1 		        "$view"               // if $view
           	       srcVar2 		        "$eighty"             // > 80   
          	       resultVar 		"$viewconditon"       // { $viewconditon			
          	       greaterVar 	        "$zero"               // = 1 }
        	       LessEqualVar 	        "$one"                // else { $viewconditon = 0 }
              }


	      Add                                                   // if ($speedcondition OR $viewconditon) > 0  {$bothconditions > 0} else {$bothconditions = 0}
      	      {				
          	       srcVar1 		        "$speedcondition"
           	       srcVar2 		        "$viewonditon"       
          	       resultVar 		"$anycondition"   			
              }

	      LessOrEqual
      	      {				
          	       srcVar1 		        "$anycondition"        // if $anycondition
           	       srcVar2 		        "$zero"                // > 0    
          	       resultVar 		"$frame"               // { $frame			
          	       greaterVar 	        "$one"                 // = 1 }
        	       LessEqualVar 	        "$zero"                // else { $frame = 0 }
              }

	}
}

WHILE LinearRamp

A WHILE LinearRamp is a complex material proxy construction that allows a LinearRamp to increment as long as a condition as met. The LinearRamp virtually resets it to 0 as soon as the condition is no more met.

It is done by subtracting the result of the LinearRamp proxy from itself if the condition is not met, and otherwise subtracting the value the LinearRamp material proxy had when the condition was not met for the last time from its current value.

The following code increments the $rampresult value by 1 every second as long as the player is static ($speed <= 0), otherwise, it resets it to 0.

VertexLitGeneric
{
	
        $speed           "0"

        $zero            "0"

        $ramp            "0"
        $rampcorr        "0"
        $rampresult      "0"

	Proxies
	{
	
	        PlayerSpeed
      	        {				
          	        scale		        "1"     
          	        resultVar 		"$speed"
       	        }

	        LinearRamp					// Generates a Linear Ramp that increments its value by 1 every [rate] second				
	        {						 
		        rate 		        "1"			
		        resultVar 		"$ramp"
	        }

	        LessOrEqual					 // This will result in storing a correction that is equal to the $ramp value if the condition is not met				
      	        {
          	 	srcVar1 		"$playerspeed"   // if $playerspeed
           	  	srcVar2 		"$zero"          // > 0
          	 	resultVar 		"$rampcorr"      // $rampcorr =
          	  	LessEqualVar 	        "$ramp"          // $ramp (triggers the ramp reset)
          		greaterVar 	        "$rampcorr"      // else { $rampcorr = $rampcorr }
       	        }

	        Subtract					// If the correction is equal to $ramp, the LinearRamp (stored in $rampresult) will virtually return to 0.				
      	        {
		        srcVar1		        "$ramp"
		        srcVar2 		"$rampcorr"
		        resultVar 		"$rampresult"   // Final result of the LinearRamp that can be used further in the code as a timer or as a condition 
       	        }

	}
}

It is also possible to modify the LessOrEqual material proxy to create a LinearRamp that loops at a certain value ($valuetoloopat) :

	        LessOrEqual									
      	        {
          	 	srcVar1 		"$rampresult"       // if $rampresult
           	  	srcVar2 		"$valuetoloopat"    // > $valuetoloopat (to define in the variables block)
          	 	resultVar 		"$rampcorr"         // $rampcorr =
          	  	LessEqualVar 	        "$ramp"             // $ramp
          		greaterVar 	        "$rampcorr"         // else { }
       	        }

See also