Author Topic: Dealing With Lots Of Guard Posts  (Read 2988 times)

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Dealing With Lots Of Guard Posts
« on: October 29, 2008, 05:20:04 PM »
I'm working on a map with 50+ AI Guard Posts that I want idled until a player's units approaches it (see E/P4 for an example).  So...

How does (unit).isDiscovered work (if at all)?
Will I need to create unit variables for all 50 Guard Posts, or is there a better way to do this?

I'm sure I'll need to know more as I work on this more, but that's all for now.
"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 Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Dealing With Lots Of Guard Posts
« Reply #1 on: October 30, 2008, 07:02:08 AM »
Unless you can make it the other way around, as in if the unit discovered the GP and not the other way around, then you can dynamically assign a limited amount of unit handles for the GPs. Of course, you could still end up having all handles in use unless you idle the GPs again after no player has been around them and re-assign the handles.

This best works if each handled unit has a standard code for it, or several larger groups, otherwise it will not work very well.
« Last Edit: October 30, 2008, 07:03:13 AM by Hidiot »
"Nothing from nowhere, I'm no one at all"

Offline Eddy-B

  • Hero Member
  • *****
  • Posts: 1186
    • http://www.eddy-b.com
Dealing With Lots Of Guard Posts
« Reply #2 on: October 30, 2008, 01:04:04 PM »
It's been a while since i've coded renegades, but if you want each GP to respond when it gets "discovered" then you WILL need 50 variables.

Now, the vars are not the problem, you can virtually create limitless variables (i'd use an array in this case). The problem is: you have only a limited amount of triggers available (ScStub's). What you could do is create events using my event system (InRectEvent) to determine if an enemy has entered a certain area.

I forgot how IsDiscovered works (if it does at all, since there is no fog-of-war in OP2).
Rule #1:  Eddy is always right
Rule #2: If you think he's wrong, see rule #1
--------------------

Outpost : Renegades - Eddy-B.com - Electronics Pit[/siz

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Dealing With Lots Of Guard Posts
« Reply #3 on: October 30, 2008, 01:35:02 PM »
Will not dynamically attributing a variable for each GP each time the GP needs its state changed work?

On seconds thoughts, it would have to be done in a kind of rect check, but one might want to make the check more of a circle-like check, not a rectangular one that you can commonly do. Which couldprobably be done by verifying a circle of individual tiles. But, it would imply much more work and more variable.
So I guess it's not such a viable solution after all.
"Nothing from nowhere, I'm no one at all"

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Dealing With Lots Of Guard Posts
« Reply #4 on: October 30, 2008, 03:30:25 PM »
Oh yes, I forgot about IUnit entirely.  I'll just check for player units entering the GP's area and turning the GPs on as needed.  Of course, I'll have to set up rects and triggers and yuckiness.  Guess there's no easy solution, unless I attract Hooman's attention (though that would more involve confirming there is no easy solution, rather than providing one).

You'd like to think that isDiscovered would check if there were any enemy units in the unit's line of sight (or the unit in question was in something else's line of sight), but sadly it doesn't appear work that way.
« Last Edit: October 30, 2008, 03:31:15 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
Dealing With Lots Of Guard Posts
« Reply #5 on: October 30, 2008, 05:14:49 PM »
Quote
Guess there's no easy solution, unless I attract Hooman's attention (though that would more involve confirming there is no easy solution, rather than providing one).

Haha!


Anyways, Unit.isDiscovered() is only for Wreckage units. It will return false for anything else.


I would have just setup a rect trigger or maybe a few if you didn't want a single perfectly rectangular region. You can always set all the regions to have the same callback if you want them to function the same. If anything enters that rect, then use an Enum to iterate over all the guard posts and tell them to turn on. That way you only need about 2 local variables, and 1 trigger.

Or did you want the GPs to have independent activation regions? Do you want the GPs to turn off when no units are around?
 

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3238
Dealing With Lots Of Guard Posts
« Reply #6 on: October 30, 2008, 08:29:43 PM »
No, I want the GPs to turn on individually (in most cases; sometimes there are a few grouped together).

They will not turn off after being discovered and left alone for awhile.
« Last Edit: October 30, 2008, 08:29:58 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 Eddy-B

  • Hero Member
  • *****
  • Posts: 1186
    • http://www.eddy-b.com
Dealing With Lots Of Guard Posts
« Reply #7 on: October 31, 2008, 03:05:58 PM »
Quote
Anyways, Unit.isDiscovered() is only for Wreckage units. It will return false for anything else.
Sounds about right to me..  as i said: it's been too damn long for me!
 
Rule #1:  Eddy is always right
Rule #2: If you think he's wrong, see rule #1
--------------------

Outpost : Renegades - Eddy-B.com - Electronics Pit[/siz

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Dealing With Lots Of Guard Posts
« Reply #8 on: October 31, 2008, 05:28:28 PM »
Ok, so create a bunch of rect triggers, each of which turns on some GP(s). There are two ways I can se this working. One is to just create a bunch of different callbacks that would turn on the GPs in some region, and set each rect trigger callback accordingly.

The other would be to reuse the same callback for each rect trigger, but then to figure out which trigger fired yourself. That's one of the weaknesses of the trigger system. The callback isn't passed any information about which trigger caused it to be called. If you kept around a global array of triggers, and trigger rects, then this would allow you to iterate over all the GPs in that region and turn them on if the trigger has fired.


The second way is probably more complicated from a source code perspective, and less efficient from a runtime perspective, but more easily extensible. It would be possible to get the second way to work without hardcoding a bunch of things. Plus, you could also setup the triggers in an automated way. Such as using an enum to find all GPs for that player, and for each one found (that is turned off), it can generate a rect trigger around that region, and mark which unit that region turns on.


The system might work something like this (untested code):
Code: [Select]
struct GpActivateStruct
{
  Trigger activateTrigger;
  Unit gp;
};

struct ScriptGlobal
{
  GpActivateStruct gpActivate[32];  // ** Set appropriate array size **
  int numActivateGp;
};
ScriptGlobal scriptGlobal;

int InitProc()
{
  Unit unit;
  LOCATION loc;
  PlayerBuildingEnum buildingEnum(aiPlayer, mapGuardPost);
  int i = 0;

  while (buildingEnum.GetNext(unit))
  {
    // ** Might want to add a debug check here to ensure the end of the array isn't passed, and possibly warn the level designer **
    //if (i >= numof(scriptGlobal.gpActivate)) ...
    // Should probably check the GP is disabled here (using an extension library)
    scriptGlobal.gpActivate[i].gp = unit;
    loc = unit.Location();
    scriptGlobal.gpActivate[i].activateTrigger = CreateRectTrigger(true, true, playerNum, loc.x-10, loc.y-10, 20, 20, "EnableGP");  // ** Set approptiate Rect size. This sets the rect to be 10 tiles in any direction from the GP **
    i++;
  }
  scriptGlobal.numActivateGp = i;
}

SCRIPT_API void EnableGP()
{
  int i;

  // Find out which GPs need to be activated
  for (i = 0; i < scriptGlobal.numActivateGp; i++)
  {
    if (scriptGlobal.gpActivate[i].activateTrigger.HasFired(playerNum))
    {
      scriptGlobal.gpActivate[i].gp.DoUnIdle();
      // Delete the trigger and unit, so we can free ScStubs, and don't accidentally call DoUnidle on a different unit if the GP is destroyed and another unit is built that uses the same unit index
      scriptGlobal.gpActivate[i].activateTrigger.Destroy();  // Free ScStub
      // If not last item in list, swap current item with last item
      if (i != scriptGlobal.numActivateGp)
      {
        scriptGlobal.gpActivate[i] = scriptGlobal.gpActivate[scriptGlobal.numActivateGp-1];
        i--;  // Need to recheck current slot, since it contains a new value now
      }
      scriptGlobal.numActivateGp--;  // Dump the last item on the list
    }
  }
}

You of course need to define aiPlayer, and playerNum yourself. You might also need to write the numof macro, which was written in Hooville (BaseData.h) like this:
Code: [Select]
#define numof(array) (sizeof(array)/sizeof(array[0]))
« Last Edit: October 31, 2008, 07:43:41 PM by Hooman »