Hovering chopper support - choppercover.nut

So here's the idea. If you want to parent a func_tracktrain to something, so it moves relative, you don't parent the path, you parent the func_tracktrain itsef to the item, and the path will move relative to this. So here's what this does.

You make your track as normal, your "train" heli, whatever.

Place an info_target in the center of your path with a name ex: chopper_follow

Then you parent that func_tracktrain to the target (chopper_follow).

Pass that target as the first entitygroup to this script.

Then what happens is that the script computes the average position of the survivors ever 1/10 of a second, moves the info_target there (chopper_follow), and the path_track will follow.

There are a couple caveats, you'll need to call FindSurvivors() after a delay of map load, or it won't work. They won't be loaded yet, a logic_auto output onmapspawn with a delay of 10 seconds should do it.

Also, have your track the height you want, relative to the info_target. That's it.

Example VMF - choppercover.vmf

choppercover.nut - choppercover.nut (this goes in scripts\vscripts

Msg("Initializing chopper hover script");
author: Lee Pumphret

This script simply computes the average survivor position, then moves the entity passed as the
first argument (should be an info_target) to that location. The rest is all handled entity side.

Place a named info_target in your map. Pass this name as the EntityGroup0 in the call to this logic_script.

Design your path_track relative to this info_target Meaning the info_target should be near the center of the
path_track, and the path_track should be as high as you want your entity to hover around, relative to the

Then parent your func_tracktrain to this info_target.

The survivors table, once initialized, holds an entity reference to all survivors
To reference a specific survivor, you can say
survivors.nick (etc...)

survivors <-{
   coach = "models/survivors/survivor_coach.mdl",
   ellis = "models/survivors/survivor_mechanic.mdl",
   nick = "models/survivors/survivor_gambler.mdl",
   rochelle = "models/survivors/survivor_producer.mdl"

survivors_found <- 0 // flag set to true once survivors are found

Find survivors, this needs to be called after a delay. If you call it immediately,
it will fail as they have not been loaded yet, 10 sec after map load should be good.
You can call it with a logic_auto output, runscriptcode FindSurvivors()
function FindSurvivors(){
   foreach(s,m in survivors){
    printl ("looking for "+s+" mdl:"+m);
    survivor <- Entities.FindByModel(null, m)
    if (survivor){
      printl(s+" found: "+survivor);
      survivors[s] = survivor
      printl(s+" NOT FOUND!: "+survivor);
      survivors[s] = null


Assign the info_target that our track will follow, your track should be above
this at the height you want it to hover relative to the survivors

path_follow <- EntityGroup[0];

if (!path_follow){
   printl("ERROR no target");


function Think(){
   if (!survivors_found){
      return   // don't want to get called before we have found the surviors or errors

   if (!path_follow){
      return   // no target for path to follow, nothing to do
   local v = Vector(0,0,0);
   scount <- 0;

   // Add all our survivors together and divide by count for the average position
   foreach(s,m in survivors){
      if (m.IsValid() && (m.GetHealth() > 1)){  // don't count players with 1 health, ie dead
         sorigin <- m.GetOrigin();
         v += sorigin

   if (scount){ // should never not be 1 survivor, but...
      v.x /= scount
      v.y /= scount
      v.z /= scount

   // now v has our average of the players, move the info_target there

Scroll to top