/*
NOTES:
This is the making of a pretty unique trap that has no triggers or anything (of course you could link it to a trigger if you wanted). For a single PC that cannot kill one of these monsters rather quickly (less than BREED_STATE_MAX heartbeats), it will be viscious. For a group of players this could prove to be quite a fun "trap" to deal with. I suggest the monster(s) you attach this script to be on the easy to very-easy scale for the players you intend it for. Its completely adjustable. This could be adjusted so that there was one alpha-monster that when killed, every thing stopped breeding. In this example, however, they dont stop until you kill them all.

**WARNING**:
Its a good idea NOT to set so many creatures to spawn that it takes more than a heartbeat to spawn them, that could get NASTY. Its best to keep the number of creatures spawned VERY low, like 2. For example, with the BREED_AMOUNT set to the constant of 2, if no monsters are killed, but the spawn conditions are met and they are set to breed every heartbeat, 1 monster makes 2 more for a total of 3. Those 3 each make 2 more for a total of (3 + 3*2) 9. Those 9 each spawn 2 more, for a total of (9 + 9*2) = 27. The growth rate formula is as follows:

        n = starting number of creatures
        b = number of successful breeds thus far

        n * ((BREED_AMOUNT + 1)^b)

in the example above, BREED_AMOUNT is 2 and we started with 1 creature. So for the 3rd successful breeding we would get (assuming NONE died):

        1 * ((2+1)^3) = 1 * (3^3) = 27.

Continuing on with one more breeding in above example, you get:

        1 * ((2+1)^4) = 1 * (3^4) = 81.

And once more you get:

        1 * ((2+1)^5) = 1 * (3^5) = 243 (Yikes)

This is why i put the MAX_MONSTERS in the area so that it cant get out of hand. This is also why i put the BREED_STATE-- in when it cant successfully breed but the other conditions are met. This aleviates some of the race condition and explosive population growth. If the variables are not set correctly and with extreme care, the players will easily get into the situation where they cannot kill the monsters fast enough. This makes for an interesting situation, and will more than likely force the players to run or die.

INSTRUCTIONS:
- Create a monster (ideally a weak one) that has a tag and blueprint name that are the same (in my tests the monster tag was breeder_beetle as well as the blueprint res/ref)
- edit the scripts for this monster and place the appropriate code (below) in the corresponding scripts
- setup the variables (below) in the On User Defined Script
- Set the BREED_STATE_MAX = the number of successive heartbeats needed before the monster can call its Breed() function
- Set the BREED_AMOUNT = the number of creatures you want spawned when Breed() is called. This can be constant or random, you decide
   - ex: BREED_AMOUNT = 5 (This will spawn 5 every time Breed() is called)
   - ex: BREED_AMOUNT = d6() (this will spawn 1-6 every time Breed is called)
- Set the BREED_PERCENTAGE = the whole number percentage (1-100) chance you want this creature to have a successful breed when it gets the opportunity
   - ex: BREED_PERCENTAGE = 100 (100% chance)
   - ex: BREED_PERCENTAGE = 20 (20% chance)
- Set the MAX_MONSTERS = the total number of this creature with this tag that can exist in this area
- Set the MAX_DISTANCE = the total distance in meters (float value), that this creature will allow between him and oNearest before giving up the chase
   - ex: MAX_DISTANCE = 25.0 (NOTE: Each square on the grid in the toolset is 10.0 meters)

On Spawn:
        - uncomment the lines:
            SetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT);
            SetSpawnInCondition(NW_FLAG_DEATH_EVENT);
        - add line:
            SignalEvent(OBJECT_SELF, EventUserDefined(100));

On User Defined:
*/

//::///////////////////////////////////////////////
//:: Default: On User Defined
//:: NW_C2_DEFAULTD
//:: Copyright (c) 2002 Bioware Corp.
//:://////////////////////////////////////////////
/*
    Determines the course of action to be taken
    on a user defined event.
*/
//:://////////////////////////////////////////////
//:: Created By: Don Moar
//:: Created On: April 28, 2002
//:://////////////////////////////////////////////
void Breed(string tag, int amount);

void main()
{
    // enter desired behaviour here
    int nUser = GetUserDefinedEventNumber();

    object oObject; // objects in the area
    int nCounter = 0; // monster counter

    object oNearest;                    // the nearest alive enemy that i can see
    object area = GetArea(OBJECT_SELF); // the area we are in
    string tag = GetTag(OBJECT_SELF);   // my tag
    float MAX_DISTANCE = 25.0;          // in meters, if distance between monster and oNearest is greater than this, the monster will give up chasing
    int MAX_MONSTERS = 30;              // the total number of these creatures that can be in the area at once (to keep them from going forever)
    int BREED_AMOUNT = 1;               // the amount to breed each time
    int BREED_PERCENTAGE = 100;         // the % chance (as a whole number) that they have to breed
    int BREED_STATE_MAX = 10;            // number of successive heartbeats needed to breed
    int BREED_STATE = GetLocalInt(OBJECT_SELF, "BREED_STATE"); // the current breeding state of this monster

    switch (nUser) {
        case 100: // OnSpawn (100 in my example, but really its just whatever number you specified in the On Spawn script for this creature)
            //SetLocalInt(area, tag + "_TOTAL", GetLocalInt(area, tag + "_TOTAL") + 1); // increment the total

            oObject = GetFirstObjectInArea(area);
            while (oObject != OBJECT_INVALID)
            {
              if(GetTag(oObject) == GetTag(OBJECT_SELF)) {
                nCounter++;
              }
              oObject = GetNextObjectInArea(area);
            }
            SetLocalInt(area, tag + "_TOTAL", nCounter);
            SetLocalInt(area, tag + "_MAX", MAX_MONSTERS);                            // set the max for the heck of it, so we dont have the pass the max amount around
            SetLocalInt(OBJECT_SELF, "BREED_STATE", 1);                               // initialize the BREED_STATE to 1
            break;

        case 1001: // OnHeartBeat
            // give me the nearest enemy thats alive and that i can see
            oNearest = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_IS_ALIVE, TRUE, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);

            // SpeakString("DISTANCE = " + FloatToString(GetDistanceToObject(oNearest)));
            if (GetIsObjectValid(oNearest) && GetDistanceToObject(oNearest) <= MAX_DISTANCE) {
                BREED_STATE++;
                if (BREED_STATE >= BREED_STATE_MAX) {                       // are we ready to breed?
                    if (GetLocalInt(area, tag + "_TOTAL") < MAX_MONSTERS) { // is there any room?
                        if (Random(100) <= BREED_PERCENTAGE) {              // lets see if we are successful...
                            Breed(tag, BREED_AMOUNT);                       // lets make some babies!
                            BREED_STATE = 1;
                        }
                        else {             // darn it, better luck next time!
                            BREED_STATE--; // every time it cant breed, lower its state by 1
                                           // to keep them from all breeding at once when
                                           // being held up by other conditions
                        }
                    }
                    else {             // ugh too many of us, gotta wait cause we were told to
                        BREED_STATE--; // every time it cant breed, lower its state by 1
                                       // to keep them from all breeding at once when
                                       // being held up by other conditions
                    }
                }
            }
            else {             // too far away, gonna give up
                BREED_STATE--; // every time it cant breed, lower its state by 1
                               // to keep them from all breeding at once when
                               // being held up by other conditions
                ClearAllActions(); // give up
            }

            if (BREED_STATE < 1) { // just to make sure it doesnt go below 1
                BREED_STATE = 1;
            }
            SetLocalInt(OBJECT_SELF, "BREED_STATE", BREED_STATE); // remember the last BREED_STATE
            break;

        case 1007: // OnDeath
            SetLocalInt(area, tag + "_TOTAL", GetLocalInt(area, tag + "_TOTAL") - 1); // i died, so i can lower the total by 1
            break;

    }
}

void Breed(string tag, int amount) {
    object area = GetArea(OBJECT_SELF);
    int count = 1;
    int total = GetLocalInt(area, tag + "_TOTAL");
    int max = GetLocalInt(area, tag + "_MAX");

    while (count <= amount && total < max) {
        CreateObject(OBJECT_TYPE_CREATURE, tag, GetLocation(OBJECT_SELF));
        ApplyEffectAtLocation( DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_ACID), GetLocation(OBJECT_SELF));
        total = GetLocalInt(area, tag + "_TOTAL"); // dont have to increment total here, its done via OnSpawn
        count++;
    }
}
