Navigation

    City of Arabel

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    Random Encounters

    Scripting
    2
    3
    2285
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • S
      Sethroy last edited by

      Was working on this for my own purposes, but figured I'd share in case folks were looking for something similar to CoA's CARES.

      /////////////Escape From Underdark Randomized-Encounters (EFURY)
      /////////////Author : RavenBlackRose/Seth Carter
      /////////////Date: 07/10/2005
      /////////////Updated for Isles of Elysium
      ////////////////////////////////////////////////////
      /////////////New Version Akylonor 2010, d100 Odds.
      /////////////Called From:Area OnEnter
      
      void SpawnEncounter(string sSpawn, location lSpawn)
      {
          string sDebugSpawn = "Encounter String:'" + sSpawn + "', ";
          string sSubstring;
          string sCritter;
          //string reading function
          int iPositionInString = 0;
          int iStringLength = GetStringLength(sSpawn);
          int iPositionInSubString = 0;
          int iSubStringLength;
          int iLastStop = 0;
          int iMultipleCreatures;
          int iCounter;
          int iFoundInSubstring;
          //read through the string
          while(iPositionInString != iStringLength)
          {
              //stop at |
              if(GetSubString(sSpawn, iPositionInString, 1) == "|")
              {
                  //get the creature substring
                  sSubstring = GetSubString(sSpawn, iLastStop, iPositionInString-iLastStop);
                  sDebugSpawn += "Creature Substring: '" + sSubstring +"', ";
                  iLastStop = iPositionInString+1; //move the stop to the character after "|"
                  iMultipleCreatures = 1; //reset the check for a multiple creatures
                  //read through the substring
                  iPositionInSubString = 0;
                  iSubStringLength = GetStringLength(sSubstring);
                  iFoundInSubstring = 0;
                  while(iPositionInSubString != iSubStringLength)
                  {
                      if(GetSubString(sSubstring, iPositionInSubString, 1) == "*")
                      {
                          sCritter = GetSubString(sSubstring, 0, iPositionInSubString);
                          iMultipleCreatures = StringToInt(GetSubString(sSubstring, GetStringLength(sCritter)+1, GetStringLength(sSubstring)-(GetStringLength(sCritter)+1)));
                          iFoundInSubstring =1;
                      }
                      else
                      {
                          if(iFoundInSubstring != 1)
                          {
                              sCritter = sSubstring;
                          }
                      }
      
                      iPositionInSubString++;
                  }
                   //spawning function (complex, ain't it)
                      if(iMultipleCreatures == 1)
                      {
                         CreateObject(OBJECT_TYPE_CREATURE, sCritter, lSpawn, FALSE);
                      }
                      else
                      {
                          for(iCounter = 0; iCounter < iMultipleCreatures; iCounter++)
                          {
                             CreateObject(OBJECT_TYPE_CREATURE, sCritter, lSpawn, FALSE);
                          }
                      }
              }
              iPositionInString ++;
          }
          WriteTimestampedLogEntry(sDebugSpawn);
      }
      
      void main()
      {
          string sLocationDebug;
          //load area, and dice
          object oArea = OBJECT_SELF;
          object oPC = GetEnteringObject();
          int iLocationDice = GetLocalInt(oArea, "efury_spawnpoints");
          int iSpawnDice = d100(1);
          int iCondition = iLocationDice;
          int iCounter = 0;
          int iEncounterOdds;
          int nOddsCounter;
          int iEncounterChosen = 0;
          //avoid bombarding parties
          if(GetLocalInt(oArea, "RecentSpawned") == 0)
          {
          if(GetIsPC(oPC)) //prevents multispawns from companions, other monsters, DM's wandering about, etc
          {
              //run for as many times as there are possible spawnpoints
              iCounter = 1;
              while(iCounter <= iLocationDice)
              {
                  string sLocation = "efury_spawnpoint_" + IntToString(iCounter);
                  sLocationDebug = "Area:'" + GetName(oArea) + "', " + "Location: '" + sLocation + "', ";
                  object oSomethingInArea = GetFirstObjectInArea(oArea);
                  object oSpawnPoint = GetNearestObjectByTag(sLocation, oPC);
                  location lToSpawn = GetLocation(oSpawnPoint);
                  //check around for creatures already spawned or PCs, so we don't doublespawn or drop on their heads
                  object oNearby = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lToSpawn, TRUE, OBJECT_TYPE_CREATURE);
                  int iAnyoneAround = 0;
                  if(oNearby == OBJECT_INVALID) //no creatures/PCs in radius
                  {
                      nOddsCounter = 1;
                      iEncounterOdds = GetLocalInt (oArea, "efury_enc_chance_" + IntToString(nOddsCounter));
                      iEncounterChosen = 0;
                      iSpawnDice = d100(1); WriteTimestampedLogEntry("Spawn Roll =" + IntToString(iSpawnDice));
                      while(iEncounterOdds > 0 && iEncounterOdds < 101 && iEncounterChosen != 1)
                      {
                          if(iSpawnDice <= iEncounterOdds)
                          {
                              string sEncounter = "efury_encounter_" + IntToString(nOddsCounter);
                              sEncounter = GetLocalString(oArea, sEncounter);
                              if(sEncounter != "null" && sEncounter != "")
                              {
                                  SpawnEncounter(sEncounter, lToSpawn);
                              }
                              else
                              {
                                  sLocationDebug += "Encounter '" + sEncounter + "' is null, blank, or missing";
                                  if(sEncounter == "null")
                                  {
                                      iEncounterChosen = 1;
                                  }
                              }
                              iEncounterChosen = 1;
                          }
                          nOddsCounter = nOddsCounter +1;
                          iEncounterOdds = GetLocalInt (oArea, "efury_enc_chance_" + IntToString(nOddsCounter));
                      }
                  }
                  else
                  {
                      sLocationDebug += "Encounter not spawned due to creatures already present.";
                  }
                  iCounter = iCounter +1;
                  WriteTimestampedLogEntry(sLocationDebug);
                  SetLocalInt(oArea, "RecentSpawned", 1);
                  //2 minute delay before it will spawn another
                  DelayCommand(120.0, ActionDoCommand(SetLocalInt(oArea, "RecentSpawned", 0)));
              }
          }
          }
      }
      
      

      The below picture shows set area variables for 12 possible spawn points, with a trio of bugbears (25% 1-25 roll) guarding a shaman, a pair of ravens (35%, 26-60 roll), a family of wyverns (10%, 61-70), and a lone mountain giant (10%, 71-80) as possibles (and a 20% chance of nothing spawning).

      The syntax is```
      (RESREF)*(Number of them)|(next creature type in encounter)|(next creature)|

      Waypoints tagged "efury_spawnpoint_XX" where XX is relevant number serve as spawn positions. ![](http://img715.imageshack.us/img715/8021/efury.jpg)
      
      Modifying it to look at 2das isn't too hard if one wishes broad category tables over specific area dynamics either.

      Tigil Travelback: [Talk] Ah, good, Scarlet, came to save us from the dragon?
      Joe Scarlet: [Talk] well how powerful is this dragon?
      Ash Finorfarhard: [Talk] It's a dragon for Tymora's sake!

      1 Reply Last reply Reply Quote
      • B
        Black Rose last edited by

        Yeah, I advanced this further, later on. (2 posts here, doesn't all fit in one)

        I'll put the script block in a second post, since it's a relatively large one. It's a system I made (as can be seen in the notes) for Escape from the Underdark eons and eons ago, though its altered vastly from that primitive work.

        Essentially, you can either tie the system to an Area OnEnter, or a Trigger OnEnter (or both, if you really want). When these are fired, it goes through waypoints in the area tagged as "WP_spawnpoint_" with a number on the end (1 to whatever your system can handle before timing out, or the end of integers I suppose, but its unlikely any area has enough spawns for either case)

        On each of these waypoints, are stored a variable list, as shown in this picture (This may seem a lot of work, but you can cut and paste them through an area fast if its similar, or even make Pre-Made Tables by creating them in the pallette for use all over the place)

        To dissect this down.

        "respawn_time" is the time in seconds it will take before the script will zap through again. Keeps parties from flooding over and such. Although its on the waypoints (for future use), it presently affects the entire area (the last waypoint will be the used setting).

        "encounter_#" is a defined encounter. The semi-gibberish there is four orcs with a shaman, 3 wolves, a mixed spiders/ettercap, a great wyvern, and "null" denotes a blank encounter, used for odds of nothing whatsoever spawning. The syntax used is

        <resref>*<number to="" spawn="">|
        ^ A resref is not a tag. You can find it under the Advanced Tab of creature properties (for Default NWN monsters, put one down in an area, then check, as Edit Copy will alter it)</number></resref> 
        ```. Even for singles you need the *1, and the | has to follow each creature, even the last.
        
        ""enc_chance_#" is the odds assigned to an encounter. For efficiencies sake, you start with your largest chance encounter (you don't have to order them at all, but its helpful). The odds aren't percantile, due to the script logic, but rather reflect a range on a d100\. 1-(enc_chance_1) will give you encounter_1\. enc_chance_1 plus 1 through to enc_chance_2's odds will give you encounter_2, and so on.
        
        In the sample case, the orcs spawn on a roll of 1-25 (25%), the wolves on a roll of 26-50(25%), the spider group on a roll of 51-70,(20%), the wyvern on a roll of 71-80 (10%), and no monsters on a roll of 81-100 (20%)
        
        For efficiency and organization, you should cover all 100 odds, lead with the largest chance (since that'll avoid extra script loops, though I've tried it with 25 encounters on a spawn point to no noticeable lag) and work your way down to the minute ones, but the script has limits throughout (denoted in comments) to avoid nasty TMIs from that double loop used)
        
        You also don't need to have a null encounter at all, if you want to cover all 100 possibilities with various monsters, something will always spawn.

        [14:52] <moloch_>Half the DMs don't know what's going on because they don't read the plot forums.</moloch_>

        1 Reply Last reply Reply Quote
        • B
          Black Rose last edited by

          /////////////Seth's Random Encounters
          /////////////Author : BlackRose/Seth Carter
          /////////////Date: 07/10/2005, Update May 2007, Update August 2010, Update Jan 2011
          /////////////If this wasn't posted or directly distributed to you, it ain't yours. To date including Escape From The Underdark, Isles of Elysium, Bid For Transcendence, Akrylonor, Cormyr & Dales
          /////////////New Version 2010, d100 Odds.
          /////////////Called From:Area or Trigger OnEnter
          
          void SpawnEncounter(string sSpawn, location lSpawn)
          {
              string sDebugSpawn = "Encounter String:'" + sSpawn + "', ";
              string sSubstring;
              string sCritter;
              //string reading function
              int iPositionInString = 0;
              int iStringLength = GetStringLength(sSpawn);
              int iPositionInSubString = 0;
              int iSubStringLength;
              int iLastStop = 0;
              int iMultipleCreatures;
              int iCounter;
              int iFoundInSubstring;
              //read through the string
              while(iPositionInString != iStringLength)
              {
                  //stop at |
                  if(GetSubString(sSpawn, iPositionInString, 1) == "|")
                  {
                      //get the creature substring
                      sSubstring = GetSubString(sSpawn, iLastStop, iPositionInString-iLastStop);
                      sDebugSpawn += "Creature Substring: '" + sSubstring +"', ";
                      iLastStop = iPositionInString+1; //move the stop to the character after "|"
                      iMultipleCreatures = 1; //reset the check for a multiple creatures
                      //read through the substring
                      iPositionInSubString = 0;
                      iSubStringLength = GetStringLength(sSubstring);
                      iFoundInSubstring = 0;
                      while(iPositionInSubString != iSubStringLength)
                      {
                          if(GetSubString(sSubstring, iPositionInSubString, 1) == "*")
                          {
                              sCritter = GetSubString(sSubstring, 0, iPositionInSubString);
                              iMultipleCreatures = StringToInt(GetSubString(sSubstring, GetStringLength(sCritter)+1, GetStringLength(sSubstring)-(GetStringLength(sCritter)+1)));
                              iFoundInSubstring =1;
                          }
                          else
                          {
                              if(iFoundInSubstring != 1)
                              {
                                  sCritter = sSubstring;
                              }
                          }
          
                          iPositionInSubString++;
                      }
                       //spawning function (complex, ain't it)
                          if(iMultipleCreatures == 1)
                          {
                             CreateObject(OBJECT_TYPE_CREATURE, sCritter, lSpawn, FALSE);
                          }
                          else
                          {
                              for(iCounter = 0; iCounter < iMultipleCreatures; iCounter++)
                              {
                                 CreateObject(OBJECT_TYPE_CREATURE, sCritter, lSpawn, FALSE);
                              }
                          }
                  }
                  iPositionInString ++;
              }
              WriteTimestampedLogEntry(sDebugSpawn);
          }
          
          void main()
          {
          ///    string sLocationDebug; DEBUG ONLY
              //load area, and initialize dice
              object oArea;
              //// If I'm a Trigger, get my area, else I should be the area
              if(GetObjectType(OBJECT_SELF) == OBJECT_TYPE_TRIGGER) { oArea = GetArea(OBJECT_SELF); } else { oArea = OBJECT_SELF; }
              object oPC = GetEnteringObject();
              int iLocationDice = GetLocalInt(oArea, "Number_Of_Spawnpoints"); // Not strictly necessary, but putting this variable on the area will stop it at that many points, and avoid a very rare TMI
              int iSpawnDice = d100(1);
              int iCondition = iLocationDice;
              int iCounter = 0;
              int iEncounterOdds;
              int nOddsCounter;
              int iEncounterChosen = 0;
              //avoid bombarding the place when a group enters and don't spawn stuff if a DM turned encounters off
              if(GetLocalInt(oArea, "RecentSpawned") == 0 && GetLocalInt(oArea, "DMENCOFF") == 0)
              {
              if(GetIsPC(oPC) && GetIsDM(oPC) == FALSE) //prevents multispawns and potential TMIS and massive lags from companions, other monsters, DM's wandering about, etc
                                  //////Strangely, a DM will register as a PC without this second check
              {
                  //run for as many times as there are possible spawnpoints
                  iCounter = 1; // Initialize Counter
                  string sLocation = "WP_spawnpoint_" + IntToString(iCounter); // Start with the first spawnpoint
                  object oSpawnPoint = GetNearestObjectByTag(sLocation, oPC); // Grab our first waypoint, for added accuracy (cause nwn is occasionally random about it, start from the PC triggering)
                  while(iCounter <= iLocationDice)
                  {
                      sLocation = "WP_spawnpoint_" + IntToString(iCounter); //Redundant the first time around, but increments to the next spawnpoint
                      //////sLocationDebug = "Area:'" + GetName(oArea) + "', " + "Location: '" + sLocation + "', "; ////MORE DEBUGGING
                      //////object oSomethingInArea = GetFirstObjectInArea(oArea); I Have no clue what this is for. I think its from a prior iteration and was used to confirm the area
                      oSpawnPoint = GetNearestObjectByTag(sLocation, oPC);  ///Grabbing the relavent spawn point
                      location lToSpawn = GetLocation(oSpawnPoint);   ///// Where to spawn stuff
                      //check around for creatures already spawned or PCs, so we don't doublespawn or drop on their heads
                      object oNearby = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lToSpawn, TRUE, OBJECT_TYPE_CREATURE);   ///Check for existing spawns, or PCs where we're looking to throw stuff
                      ///// int iAnyoneAround = 0; Another Legacy line I'm pretty sure.
                      if(oNearby == OBJECT_INVALID) //IF the spawns are still there from a prior firing, or if a PC's there, don't spawn (Avoid doubling, and infamous MONSTERONHEAD Syndrome
                      {
                          nOddsCounter = 1;
                          iEncounterOdds = GetLocalInt (oSpawnPoint, "enc_chance_" + IntToString(nOddsCounter)); // Get the odds assigned to enc_chance_1, or enc_chance_2, or enc_chance_3, etc
                          iEncounterChosen = 0; // We have not yet chosen an ecnounter
                          iSpawnDice = d100(1); /////WriteTimestampedLogEntry("Spawn Roll =" + IntToString(iSpawnDice)); DEBUG STUFF
                          while(iEncounterOdds > 0 && iEncounterOdds < 101 && iEncounterChosen != 1 && GetLocalString(oSpawnPoint, "encounter_" + IntToString(nOddsCounter)) != "")
                          /// IF it's below 0, somethings really weird, and probably missing variables. Odds only go to 100.Stop once we've found the encounter we want.
                          ////If it hits a sudden blank encounter string stop cause its probably gone past the encounter list.
                          {
                              if(iSpawnDice <= iEncounterOdds)        ///If the dice roll is lower then the odds of the encounter (The logic is a bit mathematical and confusing, but is explained in external documentation)
                              {
                                  string sEncounter = "encounter_" + IntToString(nOddsCounter);   //Get the encounter string with the corresponding number
                                  sEncounter = GetLocalString(oSpawnPoint, sEncounter);           //
                                  if(sEncounter != "null" && sEncounter != "")        /// If it's "" it's an invalid string, if it's null, it's a blank spawn
                                  {
                                      SpawnEncounter(sEncounter, lToSpawn);       /// Use that giant block of code way up there to decode that gibberish of resrefs
                                  }
                                  else
                                  {
                                  ////    sLocationDebug += "Encounter '" + sEncounter + "' is null, blank, or missing"; /// MORE DEBUGGING
                                      if(sEncounter == "null")
                                      {
                                          iEncounterChosen = 1;   //// null indicates a deliberate blank encounter, and is thus an chosen
                                      }
                                  }
          
          

          [14:52] <moloch_>Half the DMs don't know what's going on because they don't read the plot forums.</moloch_>

          1 Reply Last reply Reply Quote
          • 1 / 1
          • First post
            Last post