//------------------------------------------------------------
// Copyright Sandlot Games, 2007
// author: Michael Felice
// file: svr_prop.cs
// brief:
//    This handled prop initialization, updating, and
//    removal.  In particular, resource udpates should happen
//    on the server side in order to propagate the same values
//    and changes to the client.
//------------------------------------------------------------



//*************************************************************
//                SERVER-SIDE PROP STATES
//*************************************************************

// this function is called once when a prop is created for
// the first time (not when it is loaded from a mission file,
// only when it is newly created)
function PropServer::onInitialize(%this, %input)
{
   %object = getWord(%input, 0);
   %component = getWord(%input, 1);
   %datablock = %component.getDataBlock();

   // initialize the prop's gold pool   
   if (%datablock.initGold)
   {
      %wood = getRandom(%datablock.initGoldMin, %datablock.initGoldMax);
      %component.setGoldPool(%wood);
   }
   else %component.setGoldPool(%datablock.poolGold);

   // initialize the prop's wood pool   
   if (%datablock.initWood)
   {
      %wood = getRandom(%datablock.initWoodMin, %datablock.initWoodMax);
      %component.setWoodPool(%wood);
   }
   else %component.setWoodPool(%datablock.poolWood);
   
   // initialize the prop's water pool   
   if (%datablock.initWater)
   {
      %wood = getRandom(%datablock.initWaterMin, %datablock.initWaterMax);
      %component.setWaterPool(%wood);
   }
   else %component.setWaterPool(%datablock.poolWater);
   
   // initialize the prop's food pool   
   if (%datablock.initFood)
   {
      %wood = getRandom(%datablock.initFoodMin, %datablock.initFoodMax);
      %component.setFoodPool(%wood);
   }
   else %component.setFoodPool(%datablock.poolFood);
   
   // initialize the prop's happiness pool   
   if (%datablock.initHappiness)
   {
      %wood = getRandom(%datablock.initHappinessMin, %datablock.initHappinessMax);
      %component.setHappinessPool(%wood);
   }
   else %component.setHappinessPool(%datablock.poolHappiness);
   
   // Modify object as necessary
   osModifySLGameObject(%object);
}

// this is called when the prop is added on the server-side
function PropServer::onAdd(%this, %input)
{
   %object = getWord(%input, 0);
   %component = getWord(%input, 1);
   %datablock = %component.getDataBlock();

   // check if the prop has a decal
   if (%datablock.decal)
   {
      // add the prop decal
      %decal = startSelectron(%object, %datablock.decal.selectionTypeStyle);
      if (%decal != 0)
      {
         %decal.decalScale = %datablock.shadowScale;
         %decal.addConstraint(%object, "decal");
      }

      // temporary selectron variable is used to remove the decal later
      %component.decal = %decal;
   }
}

// this function is called once on every tick for the
// server-side prop object
function PropServer::onUpdate(%this, %input)
{
   %object = getWord(%input, 0);
   %component = getWord(%input, 1);
   %datablock = %component.getDataBlock();
   
   if ($MissionLoaded == true && %object.ghosted == false)
   {
      %client = ClientGroup.getObject(0);
      %ghostID = %client.getGhostID(%object);
      if (%ghostID != -1)
      {
         %object.ghosted = true;

         // check if the object should have a special effect started on it
         if (%component.isPickUpProp() == true ||
            %component.isJobProp() == true ||
            %object.getDataBlock().idleEffectSpecial == true)
         {
            startEffect(%object, "special");
         }
      }
   }

   // update the prop's shadow
   %object.updateShadow();
}

// this function is called when the prop object is removed
function PropServer::onRemove(%this, %input)
{
   %component = getWord(%input, 0);
   %datablock = %component.getDataBlock();

   // remove the decal if there is one there.
   if (isObject(%component.decal) == true)
   {
      %component.decal.stopSelectron();
      %component.decal = 0;
   }
}



// this function should be called for every prop that should be deleted
// (it will run through the prop death animation and fading sequences)
// this function starts the death animation and leads into the fading
function SLGameObj::onDestroy(%object)
{
   %datablock = %object.getDataBlock();
   
   // if the object is already being destroyed, do nothing
   if (isObject(%object.destroyTimer) == true)
   {
      return;
   }
   
   // Send out destruction message
   if ($PlayingGame == true && slgIsBuilding(%object) == false &&
      slgIsCharacter(%object) == false) 
   {
      slgSendObjDestroyMsgLocal(%object);
   }
   
   // check if the object should have a special effect turned off
   if (%object.runningEffect("special") == true)
   {
      stopEffect(%object, "special");
   }
   
   // check if the object should play the death sound
   if (%datablock.deathSound !$= "")
   {
      %count = ClientGroup.getCount();
      for (%i = 0; %i < %count; %i++)
      {
         %client = ClientGroup.getObject(%i);
         commandToClient(%client, 'PlaySFXSound', %datablock.deathSound);
      }
   }
   
   // check if the object should have the timber death effect played
   if (%datablock.deathEffectTimber == true &&
      %object.runningEffect("timber") == false)
   {
      startEffect(%object, "timber");
   }
   // check if the object should have the dynamite death effect played
   if (%datablock.deathEffectDynamite == true &&
      %object.runningEffect("dynamite") == false)
   {
      startEffect(%object, "dynamite");
   }
   
   if (%datablock.deathInvisible == true)
   {
      %object.showMesh(false);
   }
	
	// find out how many death props could be created and clear the
	// list that identifies which props will be created
	%propCount = getWordCount(%datablock.deathProp);
	if (%object.noDeathProps == true)
	{
	   %propCount = 0;
	   %ignoreCount = true;
	}
	else
	{
	   %ignoreCount = (%datablock.deathPropMin == 0 && %datablock.deathPropMax == 0);
	}
	
   for (%index = 0; %index < %propCount; %index++)
   {
      %deathPropList[%index] = %ignoreCount;
   }
   
   // if there is an unknown number of death props to create, find
   // out how many should be created and create that many
   if (%ignoreCount == false)
   {
      // pick the number of props to create and make that many props
      %desiredCount = getRandom(%datablock.deathPropMin, %datablock.deathPropMax);
      for (%index = 0; %index < %desiredCount; %index++)
      {
         // if we have exceeded the total possible props that can be
         // created, we are done
         %endValue = %propCount - %index - 1;
         if (%endValue < 0) break;
         
         // randomly pick a remaining prop to place
         %desiredIndex = getRandom(0, %propCount - %index - 1);
         for (%checkIndex = 0; %checkIndex < %propCount; %checkIndex++)
         {
            // place this prop
            if (%desiredIndex == 0)
            {
               %deathPropList[%checkIndex] = true;
               break;
            }
            
            %desiredIndex--;
         }
      }
   }
   
   // place the death props
   %posCount = getWordCount(%datablock.deathLocation) / 2;
   for (%index = 0; %index < %propCount; %index++)
   {
      if (%deathPropList[%index] == false)
      {
         continue;
      }
      
      %propName = getWord(%datablock.deathProp, %index);
      %newDatablock = nameToId(%propName);
      if (isObject(%newDatablock) == true)
      {
         %position = %object.getPosition();
         %posX = getWord(%position, 0);
         %posY = getWord(%position, 1);
         if (%index < %posCount)
         {
            %newIndex = %index * 2;
            %posX += getWord(%datablock.deathLocation, %newIndex);
            %posY += getWord(%datablock.deathLocation, %newIndex + 1);
         }
         
         %newObject = CreateSaveObject(%newDatablock, "", $OST_NEUTRAL);
         %newObject.health = %newObject.getMaxHealth();
         %newObject.setPosition(%posX, %posY);
         %newObject.startFade(%datablock.deathFade * 1000, 0, false);
         PlaceObject(%newObject);
      }
   }
   
   if (%datablock.deathAnimation $= "")
   {
      // fading is removed because it does not function consistently
      %object.FadeOut();
      return;
   }
   
   // handle animation here
   %object.stopThread(0);
   %object.playThread(0, %datablock.deathAnimation);
   %duration = %object.getSequenceDuration(%datablock.deathAnimation);
   
   %timer = new SLTimer()
   {
      time = %duration + %datablock.deathWait;
   };
   %timer.notifyOnFire(FadeOut, %object);
   %object.destroyTimer = %timer;
   %object.destroyFunc = "FadeOut";
}

// this function starts fading out the object and fades in the death
// object (or replacement object).  this is used for putting a stump
// where a tree falls down, for example.
function SLGameObj::FadeOut(%object)
{
   %datablock = %object.getDataBlock();

   // do not destroy a building this way
   if (slgIsBuilding(%object) == true)
   {
      // check if the object should have the timber death effect played
      if (%datablock.deathEffectTimber == true)
      {
         stopEffect(%object, "timber");
      }
      // check if the object should have the dynamite death effect played
      if (%datablock.deathEffectDynamite == true)
      {
         stopEffect(%object, "dynamite");
      }

      return;
   }

   %timer = new SLTimer()
   {
      time = %datablock.deathFade;
   };
   %timer.notifyOnFire(DestroyObject, %timer);
   %timer.object = %object;
   %object.destroyTimer = %timer;
   %object.destroyFunc = "DestroyObject";
   %object.showMesh(false);

  // %object.startFade(%datablock.deathFade * 1000, 0, true);
}

// this function is called when the prop needs to be destroyed, removing
// the props footprint from the scene and deleting the prop
function SLTimer::DestroyObject(%timer)
{
   %object = %timer.object;
   if (isObject(%object) == false)
   {
      return;
   }
   
   %datablock = %object.getDataBlock();

   if (isObject(%object) == true)
   {
      // check if the object should have the timber death effect played
      if (%datablock.deathEffectTimber == true)
      {
         stopEffect(%object, "timber");
      }
      // check if the object should have the dynamite death effect played
      if (%datablock.deathEffectDynamite == true)
      {
         stopEffect(%object, "dynamite");
      }
      
      RemoveObject(%object);
      %object.DeleteObject();
   }
}
