//---------------------------------------------------------------------------
// File: svr_scenario.cs
//
//
// Author: Michael Felice
//---------------------------------------------------------------------------

/*
   Scenario:

   // maps   
   if (mapName is true)
   {
      mapMain = map to load
   
      // resources
      if (stack is true)
      {
         resourceExperience = startXP keepXP
         resourceGold = startGold keepGold
         resourceWood = startWood keepWood
         resourceFood = startFood keepFood
         resourceWater = startWater keepWater
         resourceHappiness = startHappiness keepHappiness
      }
   }
   
   // disasters
   disasterAnimalData = new SLAnimalAttackData
   disasterBanditData = new SLBanditAttackData
   disasterDroughtData = new SLDroughtData
   disasterEarthquakeData = new SLEarthquakeData
   disasterFamineData = new SLFamine
   disasterFireData = new SLFire
   disasterPlagueData = new SLPlague
   disasterTornadoData = new SLTornado
   disasterAnimalRate = "frequencyPool respawningTime"
   disasterBanditRate = "frequencyPool respawningTime"
   disasterDroughtRate = "frequencyPool respawningTime"
   disasterEarthquakeRate = "frequencyPool respawningTime"
   disasterFamineRate = "frequencyPool respawningTime"
   disasterFireRate = "frequencyPool respawningTime"
   disasterPlagueRate = "frequencyPool respawningTime"
   disasterTornadoRate = "frequencyPool respawningTime"
   addDisasterNode = "experienceMarker time maxDisasters"
   
   // carry-over characters
   niceLawmen = carryOverNiceLawmen
   toughLawmen = carryOverToughLawmen
   neutralLawmen = carryOverNeutralLawmen
   niceGunslinger = carryOverNiceGunslinger
   toughGunslinger = carryOverToughGunslinger
   neutralGunslinger = carryOverNeutralGunslinger
   minCitizen = carryOverMinCitizenCount
   maxCitizen = carryOverMaxCitizenCount
   partCitizen = percentageOfCitizensToCarryOver
*/

$SaveManager = new SLSaveManager();

// this function is used to reload the last scenario that was created
// (in the event that the game is on the main map and not a satellite
// map, this function does nothing)
function ReloadScenario()
{
   // do not try to load a scenario if we are on the main map
   %count = $ResourceStack.getStackCount();
   if (%count == 0)
   {
      return;
   }
   
   %file = slgGetSaveScenarioPath();
   %file = filePath(%file) @ "/" @ fileBase(%file) @ ".restart";
   if (slgFileExists(%file @ ".dso") == false) return;
   if (slgFileExists(%file @ ".sav") == false) return;
   LoadScenarioGame(%file, "slgUnpauseGame", true);
}

// when the reload scenario button is selected
function ReloadScenarioButton::buttonSelect(%button)
{
   ReloadScenario();
}

// this function is used to reload the main map from a satellite map
// (in the event that the game is on the main map already, this function
// does nothing)
function QuitScenario()
{
   // do not try to load a scenario if we are already on the main map
   %count = $ResourceStack.getStackCount();
   if (%count == 0)
   {
      return;
   }
   
   // clear out the carry back group
   $CarryBackCount = 0;
   
   %file = slgGetSaveScenarioPath();
   %file = filePath(%file) @ "/" @ fileBase(%file) @ ".temp";
   if (slgFileExists(%file @ ".dso") == false) return;
   if (slgFileExists(%file @ ".sav") == false) return;
   LoadScenarioGame(%file, "QuitScenarioLoad", true);
}

function QuitScenarioLoad()
{
   // pop any disasters that were added to the disaster stack
   DisasterManager.popAll();
   
   // pop any resources that have been added to the stack
   while ($ResourceStack.getStackCount() > 0)
   {
      $ResourceStack.pop();
   }
   
   if ($QuitScenarioCallback !$= "")
   {
      // call the quit scenario callback function
      call($QuitScenarioCallback);
   }
   
   slgUnpause();
}

// when the quit scenario button is selected
function QuitScenarioButton::buttonSelect(%button)
{
   QuitScenario();
}

// this function is used to load a new scenario
// %clearCallback is called directly before loading the mission and
// should be used to turn off tasks that should not be enabled on
// the satellite map
$ClearScenarioCallback = "";
// %loadCallback is called the first time a new scenario map is loaded,
// and should be used to create tasks for the that scenario and
// initialize any objects or states for the scenario (this is called
// before the scenario is saved for reloading satellite purposes)
$LoadScenarioCallback = "";
// %quitCallback is used when the quit satellite feature is selected,
// and can be used to reactivate the task that triggered the scenario
// to get to the satellite in the event that the satellite does not
// have to be completed on first attempt
$QuitScenarioCallback = "";
function LoadScenario(%scenario, %clearCallback, %loadCallback, %quitCallback)
{
   $LoadScenario = %scenario;
   $LoadFile = "";
   $PopResources = false;
   $UpdateResource = false;
   $LoadGameObjects = false;
   %client = ClientGroup.getObject(0);
   
   // clear command target state and detach any buildings that may
   // be attached to the cursor
   csClearTargetState();

   // cleanup scenario information
   MissionCleanup.remove(%scenario);
   MissionGroup.remove(%scenario);
   %scenario.cleanup();
   
   // update the disaster stack
   if (%scenario.disasterStack == $DisasterStack::Push)
   {
      $DisasterManager.push();
   }
   else if (%scenario.disasterStack == $DisasterStack::Pop)
   {
      $DisasterManager.popAll();
   }
   
   // if a new map is going to be loaded, we need to load it before
   // updating resources and disasters
   if (isFile(%scenario.mapName) == true || %scenario.stack == false ||
      isFile(%scenario.mapName @ ".dso") == true)
   {
      $ClearScenarioCallback = %clearCallback;
      $LoadScenarioCallback = %loadCallback;
      $QuitScenarioCallback = %quitCallback;
   
      // find out which objects will move to the next map
      UpdateCarryBackList();
      GetCarryForwardList(%scenario);
      
      $LoadSlot = slgLastLoadedSave();
      $LoadMission = %scenario.mapName;
      $UpdateResource = true;

      // if we are loading a new main map, everything on the stack
      // needs to be popped, and the new map needs to be loaded
      if (%scenario.mapMain == true)
      {
         $PopResources = true;
         if ($ClearScenarioCallback !$= "")
         {
            call($ClearScenarioCallback);
         }
         LoadMainScenario("OnNewScenarioLoaded");
      }
      // if the scenario has been set to push on the stack, then
      // resources will change in a push fashion
      else if (%scenario.stack == true)
      {
         // check if the game needs to be saved
         if ($ResourceStack.getStackCount() == 0)
         {
            if ($UpdateResource == true)
            {
               GameResourceStack.push(%scenario.resourceExperience,
                  %scenario.resourceGold, %scenario.resourceWood,
                  %scenario.resourceFood, %scenario.resourceFoodMax,
                  %scenario.resourceWater, %scenario.resourceWaterMax,
                  %scenario.resourcePeople,
                  %scenario.resourceHappiness);
            }
            
            // save out a temporary file
            %tempMission = slgGetSaveScenarioPath();
            %tempMission = filePath(%tempMission) @ "/" @ fileBase(%tempMission) @ ".temp";
            SaveScenario(%tempMission, "OnMainScenarioSaved");
         }
         // otherwise, the scenario can be loaded without saving
         else
         {
            if ($UpdateResource == true)
            {
               GameResourceStack.push(%scenario.resourceExperience,
                  %scenario.resourceGold, %scenario.resourceWood,
                  %scenario.resourceFood, %scenario.resourceFoodMax,
                  %scenario.resourceWater, %scenario.resourceWaterMax,
                  %scenario.resourcePeople,
                  %scenario.resourceHappiness);
            }
            
            if ($ClearScenarioCallback !$= "")
            {
               call($ClearScenarioCallback);
            }
            LoadCurrentScenario("OnNewScenarioLoaded");
         }
      }
      // return to the main map
      else
      {
         $PopResources = true;
         $UpdateResource = false;
         $LoadGameObjects = true;
         $LoadMission = slgGetSaveScenarioPath();
         $LoadMission = filePath($LoadMission) @ "/" @ fileBase($LoadMission) @ ".temp.dso";
         if ($ClearScenarioCallback !$= "")
         {
            call($ClearScenarioCallback);
         }
         LoadCurrentScenarioGame("OnMainScenarioLoaded");
      }
      
      return;
   }
   
   $PopResources = false;
   updateScenario(%scenario);
}

// this function is called when the main game is saved (which is
// needed when a new scenario with a map is added as a side quest
// to the current mission/scenario)
function OnMainScenarioSaved()
{
   // once the main scenario has been saved, the next thing to do
   // is to load the current scenario
   if ($ClearScenarioCallback !$= "")
   {
      call($ClearScenarioCallback);
   }
   LoadCurrentScenario("OnNewScenarioLoaded");
}

// this function is called when a new main scenario needs to be loaded
function LoadMainScenario(%function)
{
   $HeroHealth = HeroCharacter.health;
   if (isObject(HeroCharacter) == true)
   {
      HeroCharacter.DeleteObject();
   }
   
   $ReloadExperience = false;
   serverChangeMission($LoadMission, %function);
   
   // initialize the train to use no train
   slgTrain_ActivateTrain($TrainType::NoTrain);
   $CSUP_VALUES[$CSUP_TRACK] = false;
   $CSUPCPY_VALUES[$CSUP_TRACK] = false;
}

// this loads a scenario and calls the function specified when
// the scenario is finished loading
function LoadCurrentScenario(%function)
{
   // remove the hero from the scenario (this needs to be done
   // to ensure that the hero's health is maintained when
   // loading scenarios, only when the scenarios are pushed
   // because the hero needs to be maintained and placed;
   // otherwise, the hero already exists in the save file)
   if ($PopResources == false)
   {
      if (MissionGroup.isMember(HeroCharacter))
      {
         MissionGroup.remove(HeroCharacter);
      }
      if (MissionCleanup.isMember(HeroCharacter))
      {
         MissionCleanup.remove(HeroCharacter);
      }
   }

   $ReloadExperience = false;
   $HeroHealth = HeroCharacter.health;
   if (isObject(HeroCharacter) == true)
   {
      HeroCharacter.DeleteObject();
   }

   serverChangeMission($LoadMission, %function);
}

// this loads a scenario and calls the function specified when
// the scenario is finished loading (when returning to the main map)
function LoadCurrentScenarioGame(%function)
{
   // remove the hero from the scenario (this needs to be done
   // to ensure that the hero's health is maintained when
   // loading scenarios, only when the scenarios are pushed
   // because the hero needs to be maintained and placed;
   // otherwise, the hero already exists in the save file)
   if ($PopResources == false)
   {
      if (MissionGroup.isMember(HeroCharacter))
      {
         MissionGroup.remove(HeroCharacter);
      }
      if (MissionCleanup.isMember(HeroCharacter))
      {
         MissionCleanup.remove(HeroCharacter);
      }
   }
   
   $ReloadExperience = false;
   $HeroHealth = HeroCharacter.health;
   if (isObject(HeroCharacter) == true)
   {
      HeroCharacter.DeleteObject();
   }

   LoadGame(-1, $LoadMission, %function, !$PopResources);
}

// sets up the mission to be changed on the server and then calls the client to
// start mission change
function serverChangeMission(%mission, %function, %ignoreWait)
{
   // call client change mission method (for now, make it a "hard" call instead
   // of over the network)
   changeMission(%mission, %function, %ignoreWait);   
}

// when a main map is loaded (not the first main map load)
function OnMainScenarioLoaded()
{
   OnScenarioDoneLoading();
}

// when a new map is loaded (the first it has ever loaded)
function OnNewScenarioLoaded()
{
   // clear out all tasks that are not global tasks
   slgClearGeneralTasks();
   
   // initialize the general tasks that should be loaded for every new map
   // TOMBSTONE TASKS:
   //Tombstone 
   slgActivateTask("TombstoneTask");
   TaskModifier.strMarkVertex("TombstoneTask", "Tombstone_cemetery", $TSV_AVAIL);
   // GENERAL STORE TASKS:
   slgActivateTask("GeneralStore");
   TaskModifier.strMarkVertex("GeneralStore", "GeneralStoreInit", $TSV_AVAIL);
   // GENERAL BADGE TASKS:
   slgActivateTask("Badgetasksgeneral");
   TaskModifier.strMarkVertex("Badgetasksgeneral", "BadgeStartGeneral", $TSV_AVAIL);   
   
   // reset tech tree
   GameTechManager.resetTech(ClientGroup.getObject(0));
   
   // reset the building resource production rates
   SetBuildingGoldRate(1);
   SetBuildingWoodRate(1);
   SetBuildingFoodRate(1);
   SetBuildingWaterRate(1);
   
   // clear out the quest log
   InitializeQuestGui();
   
   LoadStartButtons();
   OnScenarioDoneLoading();
}

// once a new scenario is loaded, this function is called
function OnScenarioDoneLoading()
{
   // reload the hero
   if (isObject(HeroCharacter) == false)
   {
      %client = ClientGroup.getObject(0);
      slgSelectHero(%client, $SLGHERO_CURRENT);
   }
   
   // initialize the minimap
   if ($LoadScenario.mapMinimap !$= "")
   {
      minimap.path = $LoadScenario.mapMinimap;
   }
   
   // recreate task system server data
   tsRecreateServerTaskData();
   
   // initialize fog of war
   InitializeFOW();
   
   // maintain the character's health between scenarios
   HeroCharacter.health = $HeroHealth;
   
   // check if carry back objects need to be placed
   PlaceCarryBackList($LoadScenario);
   
   // add all objects that need to be loaded to this map from the
   // previous map/s
   PlaceCarryForwardList();
   
   // clear the carry back list
   ClearCarryBackList($LoadScenario);

   // after a scenario has been loaded, updated the scenario
   updateScenario($LoadScenario);

   // once a new scenario is loaded, we need to save the last
   // state for fast mission restarting
   if ($PopResources == false)
   {
      // find the position for the hero
      %heroCount = slgGetSpawnCount($Point::Hero);

      // if there are no hero spawn points, spawn the hero at this position
      if (%heroCount == 0)
      {
         %hero.setPosition(-379.5, -377.5);
      }
      // otherwise, randomly pick a hero spawn point to spawn at from
      // the list of hero spawn points that have been created
      else
      {
         %heroIndex = getRandom(0, %heroCount - 1);
         %heroPt = slgGetSpawnPt($Point::Hero, %heroIndex).position;
         HeroCharacter.setPosition(getWord(%heroPt, 0), getWord(%heroPt, 1));
      }
      
      // call the load scenario callback function
      if ($LoadScenarioCallback !$= "")
      {
         call($LoadScenarioCallback);
      }
      
      %tempMission = slgGetSaveScenarioPath();
      %tempMission = filePath(%tempMission) @ "/" @ fileBase(%tempMission) @ ".restart";
      SaveScenario(%tempMission, "LoadGameActions");
      return;
   }
   
   LoadGameActions();

   // call the load scenario callback function
   if ($LoadScenarioCallback !$= "")
   {
      call($LoadScenarioCallback);
   }
   
   // if we are returning from a scenario, load the game file
   if ($LoadGameObjects == true)
   {
   }
   
   metrics("fps");
}

// this updates the current game based on the scenario that is sent
// to the function (updates resources and disaster settings)  NOTE:
// the scenario passed to this function is deleted before the
// function returns
function updateScenario(%scenario)
{
   // check if the resources need to be popped from the stack
   if ($PopResources == true)
   {
      %count = $ResourceStack.getStackCount();
      for (%index = 0; %index < %count; %index++)
      {
         GameResourceStack.pop();
      }
   }
   
   if ($UpdateResource == true)
   {
      %experience = getWord(%scenario.resourceExperience, 0);
      %gold = getWord(%scenario.resourceGold, 0);
      %wood = getWord(%scenario.resourceWood, 0);
      %food = getWord(%scenario.resourceFood, 0);
      %water = getWord(%scenario.resourceWater, 0);
      %people = %scenario.resourcePeople;
      %happiness = getWord(%scenario.resourceHappiness, 0);
      
      %resource = GameResourceStack.getResource();
      if (%scenario.resourceFoodMax != -1) %resource.getFood().setMax(%scenario.resourceFoodMax);
      if (%scenario.resourceWaterMax != -1) %resource.getWater().setMax(%scenario.resourceWaterMax);
      if (%experience != -1) %resource.getExperience().setCount(%experience);
      if (%gold != -1) %resource.getGold().setCount(%gold);
      if (%wood != -1) %resource.getWood().setCount(%wood);
      if (%food != -1) %resource.getFood().setCount(%food);
      if (%water != -1) %resource.getWater().setCount(%water);
      if (%people != -1) %resource.getPeople().setLimit(%people);
      if (%happiness != -1) %resource.getHappiness().setCount(%happiness);
   }
   /*
   // check if the resources need to be pushed onto the stack
   else if ($UpdateResource == true)
   {
      GameResourceStack.push(%scenario.resourceExperience,
         %scenario.resourceGold, %scenario.resourceWood,
         %scenario.resourceFood, %scenario.resourceFoodMax,
         %scenario.resourceWater, %scenario.resourceWaterMax,
         %scenario.resourcePeople,
         %scenario.resourceHappiness);
   }
   */

   // update the disaster nodes for the disaster manager
   if (%scenario.hasDisasterNode() == true)
   {
      $DisasterManager.clearDisasterNodes();
      %count = %scenario.getDisasterNodeCount();
      for (%index = 0; %index < %count; %index++)
      {
         %node = %scenario.getDisasterNode(%index);
         $DisasterManager.addDisasterNode = %node;
      }
   }
   
   // update the animal attack disaster
   if (%scenario.hasAnimalScenario() == true)
   {
      %animal = %scenario.getAnimalScenario();
      %datablock = $DisasterManager.getData($Disaster::Animal);
      copyScenarioToDatablock(%animal, %datablock);
   }
   if (%scenario.disasterAnimalRate !$= "")
   {
      $DisasterManager.setRate($Disaster::Animal, %scenario.disasterAnimalRate);
   }
   
   // update the bandit attack disaster
   if (%scenario.hasBanditScenario() == true)
   {
      %bandit = %scenario.getBanditScenario();
      %datablock = $DisasterManager.getData($Disaster::Bandit);
      copyScenarioToDatablock(%bandit, %datablock);
   }
   if (%scenario.disasterBanditRate !$= "")
   {
      $DisasterManager.setRate($Disaster::Bandit, %scenario.disasterBanditRate);
   }
   
   // update the drought disaster
   if (%scenario.hasDroughtScenario() == true)
   {
      %drought = %scenario.getDroughtScenario();
      %datablock = $DisasterManager.getData($Disaster::Drought);
      copyScenarioToDatablock(%drought, %datablock);
   }
   if (%scenario.disasterDroughtRate !$= "")
   {
      $DisasterManager.setRate($Disaster::Drought, %scenario.disasterDroughtRate);
   }
   
   // update the earthquake disaster
   if (%scenario.hasEarthquakeScenario() == true)
   {
      %earthquake = %scenario.getEarthquakeScenario();
      %datablock = $DisasterManager.getData($Disaster::Earthquake);
      copyScenarioToDatablock(%earthquake, %datablock);
   }
   if (%scenario.disasterEarthquakeRate !$= "")
   {
      $DisasterManager.setRate($Disaster::Earthquake, %scenario.disasterEarthquakeRate);
   }
   
   // update the famine disaster
   if (%scenario.hasFamineScenario() == true)
   {
      %famine = %scenario.getFamineScenario();
      %datablock = $DisasterManager.getData($Disaster::Famine);
      copyScenarioToDatablock(%famine, %datablock);
   }
   if (%scenario.disasterFamineRate !$= "")
   {
      $DisasterManager.setRate($Disaster::Famine, %scenario.disasterFamineRate);
   }
   
   // update the fire disaster
   if (%scenario.hasFireScenario() == true)
   {
      %fire = %scenario.getFireScenario();
      %datablock = $DisasterManager.getData($Disaster::Fire);
      copyScenarioToDatablock(%fire, %datablock);
   }
   if (%scenario.disasterFireRate !$= "")
   {
      $DisasterManager.setRate($Disaster::Fire, %scenario.disasterFireRate);
   }
   
   // update the plague disaster
   if (%scenario.hasPlagueScenario() == true)
   {
      %plague = %scenario.getPlagueScenario();
      %datablock = $DisasterManager.getData($Disaster::Plague);
      copyScenarioToDatablock(%plague, %datablock);
   }
   if (%scenario.disasterPlagueRate !$= "")
   {
      $DisasterManager.setRate($Disaster::Plague, %scenario.disasterPlagueRate);
   }
   
   // update the tornado disaster
   if (%scenario.hasTornadoScenario() == true)
   {
      %tornado = %scenario.getTornadoScenario();
      %datablock = $DisasterManager.getData($Disaster::Tornado);
      copyScenarioToDatablock(%tornado, %datablock);
   }
   if (%scenario.disasterTornadoRate !$= "")
   {
      $DisasterManager.setRate($Disaster::Tornado, %scenario.disasterTornadoRate);
   }
   
   // delete the scenario
   %scenario.delete();
}

function SLDisasterScenario::RemoveCleanup(%disasterScenario)
{
   if (MissionCleanup.isMember(%disasterScenario))
   {
      MissionCleanup.remove(%disasterScenario);
   }
}
