Author Topic: Finding The Death Of A Specific Unit  (Read 1564 times)

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Finding The Death Of A Specific Unit
« on: March 24, 2009, 03:15:18 PM »
Unfortunately, OP2 doesn't seem to have a "specific unit died" trigger.  That said, certain Dynamix missions (using Eden 11 as an example) clearly can check for this kind of stuff - you have to scan several Advanced Labs and then destroy them afterwards.  While I'm still convinced there must be a neater way to do this, I've been experimenting with some ideas of my own:

Code: [Select]
//Excerpt from MT2Eden04.cpp

// Start by creating a bogus failure condition in InitProc
SD.CCDead = CreateCountTrigger(1, 1, -1, mapAny, mapAny, 0, cmpGreaterEqual, "None");
// Note that this will always be true (it checks if all players own at least zero units)

...

// Now, in AIProc, we check if the unit is still alive, and if not, we activate that dummy failure condition (but only if the objective you need it for hasn't been completed yet; after that we don't care about it)
void AIProc()
{
    if ( (SD.AICC.IsLive() == false) && (SD.CCObjDone == false) )
    {
        CreateFailureCondition(1, 0, SD.DummyFailure, "None");
    }
}

...

// However, if the player has completed the objective, they can safely destroy the unit
SCRIPT_API CCScan()
{
    SD.AICC.ClearSpecialTarget();
    TethysGame::AddMessage(1600, 576, "Data transmitted from the Command Center!", 0, sndSavnt201);
    SD.CCObjDone = true;    // Prevents AIProc from failing the player if the unit is destroyed after it is no longer vital to the mission
    return 1;
}

The drawback to this method is that it uses a lot of variables.  That and using AIProc tends to make me nervous that something horrible will happen.
« Last Edit: March 24, 2009, 03:18:39 PM by Sirbomber »
"As usual, colonist opinion is split between those who think the plague is a good idea, and those who are dying from it." - Outpost Evening Star

Outpost 2 Coding 101 Tutorials

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Finding The Death Of A Specific Unit
« Reply #1 on: March 25, 2009, 01:45:34 AM »
Just a thought, but if the building type is unique, can't you add a trigger for the number of that buiding? Then deal with the scanning through it's corresponding triggers.

I can look up how it's done in the original level if you remind me on the weekend.
 

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Finding The Death Of A Specific Unit
« Reply #2 on: March 25, 2009, 06:40:45 AM »
Yes, I thought of that, but how often is that true?  AIs often have several redundant structures, and with players you have no way of knowing what they have and haven't built.  And what if you change something later, and add or remove a structure of the same type?  Then the trigger is broken.  The only way it could work is if you scan through each structure in AIProc and update the trigger, and even then there are issues with it.  Say the player in question (assumed to be an AI) has three Advanced Labs, and you destroy one of them.  The trigger would be something like this:
Code: [Select]
CreateCountTrigger(1, 1, (player #), mapAdvancedLab, mapAny, 3, cmpLower, "None");
(Note that I use "None" instead of "NoResponseToTrigger" as it's easier to type).
So now the trigger will fire if one of the Advanced Labs is destroyed, but how do we know if the "specific" Lab was destroyed?  Instead, we'd need something like this:
Code: [Select]
CreateCountTrigger(1, 1, (player #), mapAdvancedLab, mapAny, 3, cmpLower, "OneLabDead");

...

SCRIPT_API void OneLabDead()
{
    if ([special unit variable].IsLive() == false)
    {
         (code here)
    }
}

Which is starting to look a lot like the code I originally posted.  Also note that we'll then need multiple triggers to check after each Advanced Lab is destroyed; which presents problems if we have more than we started with (this isn't a problem with the method I posted earlier as the code checks if a specific unit is still alive, rather than checking if a unit type has less than a minimum number we've assigned, as we're looking for here).

Perhaps we could instead set up a trigger that repeats itself and fires after only one Lab is destroyed:

Code: [Select]
CreateCountTrigger(1, 0, (player #), mapAdvancedLab, mapAny, 3, cmpLower, "LabDead");

In the response to that trigger, you could then add IsLive checks for the objective-vital structure(s) you need.  But at that point you might as well just set it up in AIProc, and it's almost identical to the code I posted early (but a lot harder to implement).

And yeah, feel free to look into how Dynamix did it if you get the chance.
"As usual, colonist opinion is split between those who think the plague is a good idea, and those who are dying from it." - Outpost Evening Star

Outpost 2 Coding 101 Tutorials

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Finding The Death Of A Specific Unit
« Reply #3 on: March 28, 2009, 02:22:28 PM »
The code from Eden mission #11 seems to look something like this:

Code: [Select]
struct ScriptGlobal{
  Unit lab1;
  Trigger lab1DeadCheck;
};
ScriptGlobal scriptGlobal;

InitProc()
{
  // Create the lab
  TethysGame::CreateUnit(scriptGlobal.lab1, mapAdvancedLab, ...);

  // Initialize variables to check if the lab is dead before being scanned
  scriptGlobal.lab1DeadCheck = CreateTimeTrigger(true, false, 20, "Lab1Dead"); // Trigger to periodically check if Lab #1 has died

  // Setup trigger that marks the lab as safe to kill
  // ...  (GeneBankCaptured)
}

Export Lab1Dead()
{
  // Check if the lab was destroyed
  if (!scriptGlobal.lab1.IsLive())
  {
    // Mission failure
    Trigger& failIn1Tick = CreateTimeTrigger(true, true, 1, "NoResponseToTrigger");
    CreateFailureCondition(true, true, failIn1Tick, "");
  }
}


Export GeneBankCaptured()
{
  TethysGame::AddMessage(-1, -1, "Gene Bank Captured!", -1, 0);

  // Bunch of capturing code here ...
  // GetSpecialTargetData
  // SetTruckCargo
  // CreateTimeTrigger to reinforce

  // Make sure we haven't already disabled the lab death check
  if (scriptGlobal.lab1DeadCheck.IsInitialized())
  {
    // Disable checking for lab death and failure
    scriptGlobal.lab1DeadCheck.Disable();
  }

  // Setup new failure checks here?
  // CreateTimeTrigger(true, false, 40, "CheckForLostBank");

  // Mark the lab as targettable
  scriptGlobal.lab1.SetOppFiredUpon(true);
}
« Last Edit: March 28, 2009, 02:23:57 PM by Hooman »