Author Topic: Some Heartbeat Script Help  (Read 371 times)

Legacy_Xanodus

  • Newbie
  • *
  • Posts: 8
  • Karma: +0/-0
Some Heartbeat Script Help
« on: October 26, 2010, 06:32:22 am »


               Hey Guys, so i've been around for awhile and messing with the toolset but i never really got too serious about scripting until recently.  I've been attempting to duplicate a server I made a couple years ago but rather with the scripting help of the generous and kind people on the NWN forums.

My goal is to create a script that spawns creatures in an area based on the average levels of the Players in that area.  The script only fires once every, lets say 12 or 18 seconds (since heartbeats are in 6 second intervals), and does not actually run if there are no Players in the area.  Or rather thats how it SHOULD work in the end. 

The problem is when i load up the module it seems to be fine then after a few seconds it runs the message ERORR: TOO MANY INSTRUCTIONS.  Any help?  Not to mention, is there any way i could simplify this code to a more efficient method?

EDIT: I'm also not too sure if my method of counting the number of players in the area & their average levels is correct.  I'm quite new to this so please point out any and all errors that i've made

Heres my current attempt (i hope the quote boxes help a little to differentiate):


This is the initial heartbeat that counts up 18 seconds & then fires the next phase

csu_heartbeat


#include "nw_i0_generic"

void main()
{
    int nCounter = GetLocalInt( GetArea(OBJECT_SELF), "Timer");
    SetLocalInt( GetArea(OBJECT_SELF), "Timer", ( nCounter + 6));
    nCounter += 6;

    if (nCounter >= 18)
    {
        ExecuteScript ("spawncheck", OBJECT_SELF);
        SetLocalInt( GetArea(OBJECT_SELF), "Timer", ( nCounter - 18));
    }
}


The main function involved in the process.  It spawns based on the average level

spawncheck

//********************************
//  Created By: Xanodus          *
//  Last Edit: October 25, 2010  *
//********************************
//  Function: Heartbeat Script   *
//                               *
//  Description: Spawns enemies  *
//  based on average lvl to area *
//********************************

#include "nw_i0_generic"
#include "csu_spawninc"

void main ()
{
    int nMonsters = GetLocalInt( GetArea(OBJECT_SELF), "Monsters");

    int nSpawnCheck;
    int nPlayers, nPCLvl;
    int nTotLvl, nLvlBonus;

    object PC = GetFirstPC();
    object NextPC;

    if (!GetIsPC(PC))
        return;

    while (NextPC != PC)
    {
        nPlayers += 1;

        nPCLvl = GetHitDice( PC);
        nTotLvl += nPCLvl;

        NextPC = GetNextPC();
    }

if (nPlayers >= 1 && nMonsters <= 30)
{
    nLvlBonus = ( nPlayers / 5);
    nSpawnCheck = ( nTotLvl / nPlayers) + nLvlBonus;

    switch (nSpawnCheck)
    {
        case 1:     case 2:
                SpawnCreatures (CREATURE_GOBLIN_FOOTPAD, 2);
                SpawnCreatures (CREATURE_GOBLIN_SCOUT, 1);
                RareCreatures (5);
                break;
        case 3:
                SpawnCreatures (CREATURE_GOBLIN_FOOTPAD, 1);
                SpawnCreatures (CREATURE_GOBLIN_FIGHTER, 1);
                SpawnCreatures (CREATURE_GOBLIN_SCOUT, 1);
                RareCreatures (5);
                break;
        case 4:
                SpawnCreatures (CREATURE_GOBLIN_FIGHTER, 2);
                SpawnCreatures (CREATURE_GOBLIN_SCOUT, 1);
                RareCreatures (5);
                break;
        case 5:
                SpawnCreatures (CREATURE_GOBLIN_FIGHTER, 2);
                SpawnCreatures (CREATURE_GOBLIN_ARCHER, 1);
                RareCreatures (5);
                break;
        case 6:
                SpawnCreatures (CREATURE_GOBLIN_FIGHTER, 1);
                SpawnCreatures (CREATURE_GOBLIN_ARCHER, 1);
                SpawnCreatures (CREATURE_GOBLIN_ELITE, 1);
                RareCreatures (8);
                break;
        case 7:     case 8:
                SpawnCreatures (CREATURE_ORC_WARRIOR, 2);
                SpawnCreatures (CREATURE_ORC_BOWMAN, 1);
                RareCreatures (8);
                break;
        case 9:
                SpawnCreatures (CREATURE_ORC_WARRIOR, 1);
                SpawnCreatures (CREATURE_ORC_SWORDSMAN, 1);
                SpawnCreatures (CREATURE_ORC_BOWMAN, 1);
                RareCreatures (8);
                break;
        case 10:
                SpawnCreatures (CREATURE_ORC_SWORDSMAN, 2);
                SpawnCreatures (CREATURE_ORC_BOWMAN, 1);
                RareCreatures (8);
                break;
        case 11:
                SpawnCreatures (CREATURE_ORC_SWORDSMAN, 2);
                SpawnCreatures (CREATURE_ORC_MARKSMAN, 1);
                RareCreatures (11);
                break;
        case 12:        case 13:
                SpawnCreatures (CREATURE_ORC_SWORDSMAN, 1);
                SpawnCreatures (CREATURE_ORC_MARKSMAN, 1);
                SpawnCreatures (CREATURE_ORC_ELITE, 1);
                RareCreatures (11);
                break;
        case 14:        case 15:
                SpawnCreatures (CREATURE_ORC_ELITE, 2);
                SpawnCreatures (CREATURE_ORC_MARKSMAN, 1);
                SpawnCreatures (CREATURE_OGRE_BERSERK, 1);
                RareCreatures (11);
                break;
        case 16:        case 17:
                SpawnCreatures (CREATURE_GNOLL_DUELIST, 2);
                SpawnCreatures (CREATURE_GNOLL_RANGER, 1);
                SpawnCreatures (CREATURE_OGRE_ELITE, 1);
                RareCreatures (14);
                break;
        case 18:        case 19:
                SpawnCreatures (CREATURE_GNOLL_DUELIST, 1);
                SpawnCreatures (CREATURE_GNOLL_RANGER, 1);
                SpawnCreatures (CREATURE_GNOLL_SURVIVALIST, 1);
                SpawnCreatures (CREATURE_OGRE_LORD, 1);
                RareCreatures (14);
                break;
        case 20:        case 21:
                SpawnCreatures (CREATURE_GNOLL_LORD, 2);
                SpawnCreatures (CREATURE_GNOLL_SORCEROR, 1);
                SpawnCreatures (CREATURE_OGRE_REAVER, 1);
                RareCreatures (17);
                break;
        case 22:
                SpawnCreatures (CREATURE_GIANT_HILL, 2);
                SpawnCreatures (CREATURE_OGRE_MAGE, 1);
                RareCreatures (17);
                break;
        case 23:
                SpawnCreatures (CREATURE_GIANT_MTN, 2);
                SpawnCreatures (CREATURE_OGRE_MAGE, 1);
                RareCreatures (17);
                break;
        case 24:
                SpawnCreatures (CREATURE_GIANT_FIRE, 2);
                SpawnCreatures (CREATURE_GIANT_FROST, 1);
                RareCreatures (17);
                break;
        case 25:        case 26:
                SpawnCreatures (CREATURE_GIANT_ELITE, 2);
                SpawnCreatures (CREATURE_GIANT_MAGE, 1);
                RareCreatures (20);
                break;
        case 27:        case 28:        case 29:
                SpawnCreatures (CREATURE_GIANT_BEHEMOTH, 2);
                RareCreatures (20);
                break;
        default:
                SpawnCreatures (CREATURE_GIANT_TITAN, 2);
                RareCreatures (20);
                break;

    }
}
}


Then lastly is my include file with some side functions used in the function above.

csu_spawninc

#include "nw_i0_generic"

void SpawnCreatures (string sCreatureTag, int nCount);
void RareCreatures (int nChance);

const string CREATURE_GOBLIN_FOOTPAD = "csu_goblin1";
const string CREATURE_GOBLIN_SCOUT = "csu_goblin2";
const string CREATURE_GOBLIN_FIGHTER = "csu_goblin3";
const string CREATURE_GOBLIN_ARCHER = "csu_goblin4";
const string CREATURE_GOBLIN_ELITE = "csu_goblin5";
const string CREATURE_GOBLIN_SHAMAN = "csu_goblin6";

const string CREATURE_ORC_WARRIOR = "csu_orc6";
const string CREATURE_ORC_BOWMAN = "csu_orc7";
const string CREATURE_ORC_SWORDSMAN = "csu_orc9";
const string CREATURE_ORC_MARKSMAN = "csu_orc10";
const string CREATURE_ORC_ELITE = "csu_orc12";
const string CREATURE_ORC_SHAMAN = "csu_orc13";

const string CREATURE_OGRE_BERSERK = "csu_ogre12";
const string CREATURE_OGRE_ELITE = "csu_ogre14";
const string CREATURE_OGRE_LORD = "csu_ogre16";
const string CREATURE_OGRE_REAVER = "csu_ogre18";
const string CREATURE_OGRE_MAGE = "csu_ogre20";

const string CREATURE_GNOLL_DUELIST = "csu_gnoll15";
const string CREATURE_GNOLL_RANGER = "csu_gnoll16";
const string CREATURE_GNOLL_SURVIVALIST = "csu_gnoll17";
const string CREATURE_GNOLL_LORD = "csu_gnoll18";
const string CREATURE_GNOLL_SORCEROR = "csu_gnoll19";

const string CREATURE_GIANT_APPRENTICE = "csu_giant20m";
const string CREATURE_GIANT_HILL = "csu_giant20";
const string CREATURE_GIANT_MTN = "csu_giant22";
const string CREATURE_GIANT_FIRE = "csu_giant24a";
const string CREATURE_GIANT_FROST = "csu_giant24b";
const string CREATURE_GIANT_MAGE = "csu_giant25";
const string CREATURE_GIANT_ELITE = "csu_giant26";
const string CREATURE_GIANT_SPELLSLINGER = "csu_giant27";
const string CREATURE_GIANT_BEHEMOTH = "csu_giant28";
const string CREATURE_GIANT_TITAN = "csu_giant30";
const string CREATURE_GIANT_COLOSSUS = "csu_giant32";

void SpawnCreatures (string sCreatureTag, int nCount)
{
    int x;
    object oSpawn;

    location WP_ONE = GetLocation( GetWaypointByTag( "WP_SpawnOne"));
    location WP_TWO = GetLocation( GetWaypointByTag( "WP_SpawnTwo"));

    for (x = 0; x < nCount; x++)
    {
        oSpawn = CreateObject (OBJECT_TYPE_CREATURE, sCreatureTag, WP_ONE, FALSE, "CreatureSpawnA");
        oSpawn = CreateObject (OBJECT_TYPE_CREATURE, sCreatureTag, WP_TWO, FALSE, "CreatureSpawnB");
    }
}

void RareCreatures (int nChance)
{
    int x = d100();
    int y = d100();
    int z, nCount = 1;
    object oSpawn;
    string sCreatureTag;
    location WP_FIVE = GetLocation( GetWaypointByTag( "WP_SpawnFive"));

    switch (nChance)
    {
            case 1:     case 2:
                    sCreatureTag = CREATURE_GOBLIN_FIGHTER;
                    nCount = 1;
                    break;
            case 3:     case 4:
                    sCreatureTag = CREATURE_GOBLIN_ELITE;
                    nCount = 1;
                    break;
            case 5:     case 6:
                    sCreatureTag = CREATURE_GOBLIN_SHAMAN;
                    nCount = 1;
                    break;
            case 7:     case 8:     case 9:
                    sCreatureTag = CREATURE_ORC_SWORDSMAN;
                    nCount = 1;
                    break;
            case 10:     case 11:
                    sCreatureTag = CREATURE_ORC_ELITE;
                    nCount = 1;
                    break;
            case 12:    case 13:
                    sCreatureTag = CREATURE_ORC_SHAMAN;
                    nCount = 1;
                    break;
            case 14:    case 15:
                    sCreatureTag = CREATURE_ORC_SHAMAN;
                    nCount = 2;
                    break;
            case 16:    case 17:
                    sCreatureTag = CREATURE_GNOLL_SORCEROR;
                    nCount = 1;
                    break;
            case 18:    case 19:
                    sCreatureTag = CREATURE_GNOLL_SORCEROR;
                    nCount = 2;
                    break;
            case 20:    case 21:    case 22:
                    sCreatureTag = CREATURE_GIANT_APPRENTICE;
                    nCount = 1;
                    break;
            case 23:    case 24:
                    sCreatureTag = CREATURE_GIANT_MAGE;
                    nCount = 1;
                    break;
            case 25:   case 26:     case 27:
                    sCreatureTag = CREATURE_GIANT_SPELLSLINGER;
                    nCount = 1;
                    break;
            case 28:   case 29:     default:
                    sCreatureTag = CREATURE_GIANT_COLOSSUS;
                    nCount = 1;
                    break;
    }

    for (z = 0; z < nCount; z++)
    {
        if (nChance >= x)
        {
            oSpawn = CreateObject (OBJECT_TYPE_CREATURE, sCreatureTag, WP_FIVE, FALSE, "CreatureSpawnA");
        }
        if (nChance >= y)
        {
            oSpawn = CreateObject (OBJECT_TYPE_CREATURE, sCreatureTag, WP_FIVE, FALSE, "CreatureSpawnB");
        }
    }
}


Thankyou for your valuable time
 ~ Xanodus
               
               

               


                     Modifié par Xanodus, 26 octobre 2010 - 05:52 .
                     
                  


            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Some Heartbeat Script Help
« Reply #1 on: October 26, 2010, 07:32:53 am »


               I have learned the hard way that TMI's are usually caused by bad loops. And one you have in your code looks suspect:

object PC = GetFirstPC();
    object NextPC;

    if (!GetIsPC(PC))
        return;

    while (NextPC != PC)
    {
        nPlayers += 1;

        nPCLvl = GetHitDice( PC);
        nTotLvl += nPCLvl;

        NextPC = GetNextPC();
    }

Particularly the line that is highlighted. When you use GetFirst/NextPC, when it gets to the point that there are no more PCs, it will return OJBECT_INVALID. So the way you are using this loop, when it gets to no more PCs you are saying "while OBJECT_INVALID is not = to the first PC then keep going. Therefore it will never end and cause a TMI error. So when using the GetFirst/NextPC it is best just to do a loop like so:

object oPC = GetFirstPC();

while (GetIsObjectValid(oPC))
{
    //do stuff
    //do other stuff
    //etc...
    oPC = GetNextPC();
}

Eventually it will get to the point where there are no more players, return OBJECT_INVALID, and end.

And this is just a matter of preference really, but for your HB script, instead of keeping track of actual seconds I would just track the beats themselves. Maybe something like so?:

void main()
{
SetLocalInt(OBJECT_SELF, "BEATS", GetLocalInt(OBJECT_SELF, "BEATS") + 1);
int iBeats = GetLocalInt(OBJECT_SELF, "BEATS");
if (iBeats == 3)
    {
    ExecuteScript ("spawncheck", OBJECT_SELF);
    SetLocalInt(OBJECT_SELF, "BEATS", 0);
    }
}


Hopefully that helps fix things. I could be wrong though. I still got a lot to learn. Good luck.
               
               

               


                     Modifié par GhostOfGod, 26 octobre 2010 - 06:33 .
                     
                  


            

Legacy_Xanodus

  • Newbie
  • *
  • Posts: 8
  • Karma: +0/-0
Some Heartbeat Script Help
« Reply #2 on: October 26, 2010, 09:30:27 am »


               W00t! That fixed it =) Thanks so much man.  But I also resulted in another question.  Now that it actually works, the script runs whether or not players are actually in the area.  Is there any way to  limit that?



Or can someone provide me with a way to count the number of players in an area, and perhaps a way to total and average the levels of the players in the are.  That would be amazing! Especially since I kinda seem to be failing at it right now lol.
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Some Heartbeat Script Help
« Reply #3 on: October 26, 2010, 05:05:41 pm »


               Could do something like this to start your "spawncheck" script. Pretty close to what you were already doing:


void main()
{
int iPCs;
int iLevels;
object oPC = GetFirstPC();
while (GetIsObjectValid(oPC))
    {
    //if the player is in the area and is not a dm then count him and add level
    if (GetArea(oPC) == OBJECT_SELF && !GetIsDM(oPC))
        {
        iPCs++;
        iLevels += GetHitDice(oPC);
        }
    oPC = GetNextPC();
    }

int iAverageLevel = iLevels / iPCs;

//if there are players in the area(> 0)...
if (iPCs > 0)
    {
    //switch (iAverageLevel)
    //...do everything else in here.
    }
}

I saw that you had some monster checking going on too but I didn't add that to this at all.

Hope that helps. Good luck.
               
               

               


                     Modifié par GhostOfGod, 26 octobre 2010 - 04:15 .