---------------------------------------------------------------------------------------------------------------
ForceField Tutorial
---------------------------------------------------------------------------------------------------------------
This will create a deployable forcefield that doesn't require beacons, and scales to fit. It still uses an invisibile static to pass and show damage, but the forcefield itself can be hit to do damage.

Update: Added all the needed code to function ForceFieldBare::damage in gameBase.cs (12/09/01)

Update: added one line to the forceFieldBare datablock to make fields team permiable. 11/29/01

Step #1
// ------------------------------------------
// defaultGame.cs
// ------------------------------------------

function DefaultGame::clearDeployableMaxes(%game)
{

      $TeamDeployedCount[%i, ForceFieldDeployable] = 0;

}


Step #2
// ------------------------------------------
// deployables.cs
// ------------------------------------------

2a)Near the top of the file add this:

$TeamDeployableMax[ForceFieldDeployable] = 10;


Step #3
// ------------------------------------------
// inventoryHud.cs
// ------------------------------------------
Add this near the top of the file:

$InvPack[18] = "ForceField";
$NTInvPack[11] = "ForceField";
$NameToInv["ForceField"] = "ForceFieldDeployable";


Step #4
// ------------------------------------------
// pack.cs
// ------------------------------------------
exec("scripts/packs/DeployableForceField.cs");


Step #5
// ------------------------------------------
// repairpack.cs
// ------------------------------------------
This will handle repairing the forcefield directly. Note: you need to add this to any repair guns your mod uses.


5a) In function repairGunImage::onValidate, add $TypeMasks::ForceFieldObjectType to %searchmasks.


5b) Still in function repairGunImage::onValidate, above this line:

   if(%scanTarg && !(%scanTarg.getType() & $TypeMasks::InteriorObjectType))

add this:

   if (%scanTarg)
   {
      if (%scanTarg.getType() & $TypeMasks::ForceFieldObjectType)
      {
         if (%scanTarg.getDataBlock().getName() $= "DeployedForceField2")
            %scanTarg = %scanTarg.parent;
         else
            %scanTarg = "";
      }
   }


5c) In function repairGunImage::onRepair, add $TypeMasks::ForceFieldObjectType to %searchmasks.


5d) Still in function repairGunImage::onRepair, above these lines:

         if (%scanTarg)
         {
            %pos = getWords(%scanTarg, 1, 3);
            %obstructMask = $TypeMasks::InteriorObjectType | $TypeMasks::TerrainObjectType;
            %obstruction = ContainerRayCast(%muzPoint, %pos, %obstructMask, %obj);
            if (%obstruction)
               %scanTarg = "0";
         }

add this:

         if (%scanTarg)
         {
            if (%scanTarg.getType() & $TypeMasks::ForceFieldObjectType)
            {
               if (%scanTarg.getDataBlock().getName() $= "DeployedForceField2")
               {
                  %pos = getWords(%scanTarg, 1, 3);
                  %scanTarg = %scanTarg.parent SPC %pos;
               }
               else
                  %scanTarg = "";
            }
        }


5e) In function startRepairing change these lines:

      %player.repairProjectile = new RepairProjectile() {
         dataBlock = DefaultRepairBeam;
         initialDirection = %initialDirection;
         initialPosition  = %initialPosition;
         sourceObject     = %player;
         sourceSlot       = $WeaponSlot;
         targetObject     = %player.repairing;
      };
      MissionCleanup.add(%player.repairProjectile);

to this:

      if (%player.repairing.getDataBlock().getName() $= "DeployedForceField")
         %targetObject = %player.repairing.field;
      else
         %targetObject = %player.repairing;
       %player.repairProjectile = new RepairProjectile() {
         dataBlock = DefaultRepairBeam;
         initialDirection = %initialDirection;
         initialPosition  = %initialPosition;
         sourceObject     = %player;
         sourceSlot       = $WeaponSlot;
         targetObject     = %targetObject;
      };
      MissionCleanup.add(%player.repairProjectile);



Step #6
// ------------------------------------------
// player.cs
// ------------------------------------------

6a) In each player datablock add this. Since it's a deployable, only mediums and heavies need it.
   max[ForceFieldDeployable] = 1;


Step #7
// ------------------------------------------
// Projectiles.cs
// ------------------------------------------
All of this takes place in function RadiusExplosion

1a) replace:

   InitContainerRadiusSearch(%position, %radius, $TypeMasks::PlayerObjectType      |
                                                 $TypeMasks::VehicleObjectType     |
                                                 $TypeMasks::StaticShapeObjectType |
                                                 $TypeMasks::TurretObjectType      |
                                                 $TypeMasks::ItemObjectType);
with this:

   InitContainerRadiusSearch(%position, %radius, $TypeMasks::PlayerObjectType      |
                                                 $TypeMasks::VehicleObjectType     |
                                                 $TypeMasks::StaticShapeObjectType |
                                                 $TypeMasks::TurretObjectType      |
                                                 $TypeMasks::ForceFieldObjectType |
                                                 $TypeMasks::ItemObjectType);

1b) Below these lines:

      if (%dist > %radius)
         continue;

add this:

      if (%targetObject.getType() & $TypeMasks::ForceFieldObjectType)
         if (%targetObject.getDataBlock().getName() !$= "DeployedForceField2")
            continue;

1c) Finially, replace

      %coverage = calcExplosionCoverage(%position, %targetObject,
                                     ($TypeMasks::InteriorObjectType |
                                      $TypeMasks::TerrainObjectType |
                                      $TypeMasks::ForceFieldObjectType |
                                      $TypeMasks::VehicleObjectType));
with this:

      if (%targetObject.getType() & $TypeMasks::ForceFieldObjectType)
         %coverage = calcExplosionCoverage(%position, %targetObject,
                                        ($TypeMasks::InteriorObjectType |
                                         $TypeMasks::TerrainObjectType |
                                         $TypeMasks::VehicleObjectType));
      else
         %coverage = calcExplosionCoverage(%position, %targetObject,
                                        ($TypeMasks::InteriorObjectType |
                                         $TypeMasks::TerrainObjectType |
                                         $TypeMasks::ForceFieldObjectType |
                                         $TypeMasks::VehicleObjectType));


Step #8
// ------------------------------------------
// gameBase.cs
// ------------------------------------------
Change function ForceFieldBare::damage, to this:

function ForceFieldBare::damage(%this, %sourceObject, %position, %amount, %damageType)
{
   if (%this.getDataBlock().getName() $= "DeployedForceField2")
      %this.parent.getDataBlock().damageObject(%this.parent, %sourceObject, %position, %amount, %damageType);
}


Step #9
// ------------------------------------------
// DeployableForceField.cs
// ------------------------------------------
Create a file called DeployableForceField.cs in your packs directory. Add all this into it:

datablock StaticShapeData(DeployedForceField) : StaticShapeDamageProfile
{
   className = ForceField;
   shapeFile = "turret_muzzlepoint.dts";
   maxDamage = 4.0;
   destroyedLevel = 4.0;
   disabledLevel = 3.0;
   dynamicType = $TypeMasks::StaticShapeObjectType;
   deployedObject = true;
   cmdCategory = "DSupport";
   cmdIcon = CMDSensorIcon;
   cmdMiniIconName = "commander/MiniIcons/com_deploymotionsensor";
   targetNameTag = 'Force';
   targetTypeTag = 'Field';
   deployAmbientThread = true;
   heatSignature = 0;
};

datablock ForceFieldBareData(DeployedForceField2) : StaticShapeDamageProfile
{
   fadeMS = 1000;
   baseTranslucency = 0.5;
   powerOffTranslucency = 0.0;
   teamPermiable = true;
   otherPermiable = false;
   color            = "0.0 0.7 0.99";
   powerOffColor    = "0.0 0.0 0.0";
   targetTypeTag = 'ForceField';
   texture[0] = "skins/forcef1";
   texture[1] = "skins/forcef2";
   texture[2] = "skins/forcef3";
   texture[3] = "skins/forcef4";
   texture[4] = "skins/forcef5";
   framesPerSec = 10;
   numFrames = 5;
   scrollSpeed = 15;
   umapping = 1.0;
   vmapping = 0.15;
   deployedFrom = ForceFieldDeployable;
};

datablock ShapeBaseImageData(ForceFieldDeployableImage)
{
   mass = 20;
   emap = true;
   shapeFile = "Stackable1s.dts";
   item = ForceFieldDeployable;
   mountPoint = 1;
   offset = "0 0 0";
   deployed = DeployedForceField;
   heatSignature = 0;

   stateName[0] = "Idle";
   stateTransitionOnTriggerDown[0] = "Activate";

   stateName[1] = "Activate";
   stateScript[1] = "onActivate";
   stateTransitionOnTriggerUp[1] = "Idle";

   isLarge = true;
   maxDepSlope = 360; // 30
   deploySound = ItemPickupSound;

   minDeployDis = 0.5;
   maxDeployDis = 5.0;
};

datablock ItemData(ForceFieldDeployable)
{
   className = Pack;
   catagory = "Deployables";
   shapeFile = "Stackable1s.dts";
   mass = 5.0;
   elasticity = 0.2;
   friction = 0.6;
   pickupRadius = 1;
   rotate = true;
   image = "ForceFieldDeployableImage";
   pickUpName = "a force field";
   heatSignature = 0;
   emap = true;
};

function ForceFieldDeployable::onPickup(%this, %obj, %shape, %amount)
{
   // created to prevent console errors
}

function DeployedForceField::onDestroyed(%this, %obj, %prevState)
{
   $TeamDeployedCount[%obj.team, ForceFieldDeployable]--;
   %obj.field.pzone.schedule(480, "delete");
   %obj.field.schedule(490, "delete");
   %obj.schedule(500, "delete");
}

function ForceFieldDeployableImage::onDeploy(%item, %plyr, %slot)
{
   %mask = $TypeMasks::InteriorObjectType | $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType;
   %vec = %plyr.getEyeVector();
   %deplObj = Parent::onDeploy(%item, %plyr, %slot);
   %x1 = getWord(%vec, 0);
   %y1 = getWord(%vec, 1);
   %z1 = getWord(%vec, 2);
   %endpos =  VectorAdd(%item.surfacePt, "0 0 10");
   %res = containerRayCast(%item.surfacePt, %endpos, %mask, 0);
   if(%res)
      %zscale=VectorDist("0 0 " @ getword(%res,3),"0 0 " @ getword(%item.SurfacePt,2));
   else
      %zscale=10;
   %extra = %x1;
   %x2 = %y1;
   %y2 = %extra;
   %vec2 = %x2 * -1 SPC %y2 SPC 0;
   %vec3 = %x2 SPC %y2 * -1 SPC 0;
   %initpos = VectorAdd(%item.SurfacePt, "0 0 " @ (%zscale / 2.4));
   %endpos =  VectorAdd(%initpos, VectorScale(%vec2, 10));
   %res = containerRayCast(%initpos, %endpos, %mask, 0);
   if(%res)
      %left=VectorDist(getword(%res,1) SPC getword(%res,2) @ " 0", getword(%item.SurfacePt, 0) SPC getword(%item.SurfacePt, 1) @ " 0");
   else
      %left=10;
   %endpos =  VectorAdd(%initpos, VectorScale(%vec3, 10));
   %res = containerRayCast(%initpos, %endpos, %mask, 0);
   if(%res)
      %right=VectorDist(getword(%res,1) SPC getword(%res,2) @ " 0", getword(%item.SurfacePt, 0) SPC getword(%item.SurfacePt, 1) @ " 0");
   else
      %right=10;
   %wid = %left + %right + 0.2;
   %av = %wid * 2 / 3;
   %movepos = VectorAdd(%item.SurfacePt, VectorScale(%vec2, (%left * 1.4)));
   %centerpos = VectorAdd(%movepos, VectorScale(%vec3, %av));
   %centerpos = VectorAdd(%centerpos, "0 0 " @ (%zscale / 2));
   if ((%x1 > 0) && (%y1 >= 0))
   {
      %zone = 0;
      %rad = mAtan(%x1, %y1);
   }
   else if((%x1 >= 0) && (%y1 < 0))
   {
      %zone = 1;
      %y1 *= -1;
      %rad = mAtan(%y1, %x1);
   }
   else if((%x1 < 0) && (%y1 <= 0))
   {
      %zone = 2;
      %y1 *= -1;
      %x1 *= -1;
      %rad = mAtan(%x1, %y1);
   }
   else if((%x1 <= 0) && (%y1 > 0))
   {
      %zone = 3;
      %x1 *= -1;
      %rad = mAtan(%y1, %x1);
   }
   %angle = mRadtoDeg(%rad);
   if (%zone == 1)
      %angle += 90;
   else if (%zone == 2)
      %angle += 180;
   else if (%zone == 3)
      %angle += 270;

   %rot = " 0 0 1 " @ %angle;
   %pos = getWords(%deplObj.getTransform(), 0, 2);
   %deplObj.field = new ForceFieldBare()
   {
      position = %movepos;
      rotation = %rot;
      scale = %wid @ " 0.02 " @ %zscale;
      dataBlock = "DeployedForceField2";
      parent = %deplObj;
      team = %plyr.team;
   };
   %deplObj.field.active = true;
   %deplObj.field.setSelfPowered();
   MissionCleanup.add(%deplObj.field);
   %deplObj.setTransform(%centerpos);
   %deplObj.team = %plyr.client.team;
   %deplObj.field.team = %plyr.client.team;
   %deplObj.owner = %plyr.client;
   %deplObj.field.owner = %plyr.client;
   %deplObj.field.pzone.team = %plyr.client.Team;
   if(%deplObj.field.getTarget() != -1)
      setTargetSensorGroup(%deplObj.field.getTarget(), %plyr.client.team);
   %deplObj.zscale = %zscale / 2;
}

function DeployedForceField2::onAdd(%data, %obj)
{
   Parent::onAdd(%data, %obj);
   for (%i=0; %i < PZones.getCount(); %i++)
   {
      if (PZones.getObject(%i).ffield == %obj)
         %obj.pzone = PZones.getObject(%i);
   }
}

function DeployedForceField2::damageObject(%data, %targetObject, %sourceObject, %position, %amount, %damageType)
{
   %targetObject.parent.getDataBlock().damageObject(%targetObject.parent, %sourceObject, %position, %amount, %damageType);
}

function ForceFieldBare::isMounted()
{

}