Author Topic: Stubborn deer  (Read 1120 times)

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« on: November 22, 2012, 04:18:24 pm »


                <refusing to be driven crazy...>

Background for those who haven't been following the bouncing ball: I'm incorporating Failed.Bard's dynamic forest system into the Regional Mod. A good part of that is the creation (and destruction) of the ambient vegetation, prey and predators (and possibly landmark features when I get the time).

The creation works the way I want... in poor nodes, starving, weak creatures are spawned. In rich nodes, powerful, healthy creatures are spawned. The creatures have default (yucky) scripting on them, but they work. And they can be killed. They spawn where and when I want them to, and in the proper number.

The problem: They refuse to be destroyed. Transition away and the "reg_node_sleep" script is dropped on the exiting area with a delay (currently set to 10 seconds for debugging). Reg_node_sleep check to be sure there are no PCs in the area (not in use) then destroys all the node-specific ambients (tagged reg_veg, reg_pry and reg_prd) and unsets the isNode identifier (freeing the area for reuse).

It all works except the destroy part.

The destroy part should be as simple as:


DestroyObjectsInAreaByTag( "reg_pry", OBJECT_SELF );

Except it doesn't work.

Hmmm... Ok. Perhaps the objects aren't coming back as valid for some reason?

Tried all kinds of loops with all kinds of delays.  Here is the latest:


  oObject = GetFirstObjectInArea( OBJECT_SELF);

//   DestroyObjectsInAreaByTag( "reg_veg", OBJECT_SELF );

// Loop through all "reg_pry" tags in area - Destroy 
iIndex = 0; 
oTarget = GetNearestObjectByTag( "reg_pry", oObject); 
while (oTarget != OBJECT_INVALID) {     
   if (GetIsObjectValid(oTarget)) {
       sMessage = "Pry "+IntToString(iIndex)+" is a valid object type "+IntToString(GetObjectType(oTarget))+ " (creature is type "+IntToString(OBJECT_TYPE_CREATURE)+")";
       SendMessageToPC( oPC, sMessage );
   }     
   nPC = 0;  // Just reusing var as counter     
   while (oTarget != OBJECT_INVALID ) { 
      sMessage = IntToString(nPC++)+" Trying to destroy pry " + IntToString( iIndex);
      SendMessageToPC( oPC, sMessage );   
      DestroyObject( oTarget, 0.01f );   
   }     
   oTarget = GetNearestObjectByTag( "reg_pry", OBJECT_SELF, iIndex++ );
}

And a dump of the debug messages...


 Pry Table is pry_tempforest
 Max Pry # 5
 Stage is 6
 Pry chain is 1
 Alpha Prey is reg_deer_06
 Beta is reg_deer_04
 Beta is reg_deer_04
 Beta is reg_deer_04
 Beta is reg_deer_04
 Beta is reg_deer_04
 Beta is reg_deer_04
 Stage is 6
 Pry chain is 4
 Alpha Prey is reg_deer_06
 Beta is reg_deer_04
 Beta is reg_deer_04
 Beta is reg_deer_04
 Beta is reg_deer_04
 Beta is reg_deer_04
 Beta is reg_deer_04
 [Server] You are now in a No PVP area.
 [Server] You are now in a No PVP area.
 Putting node to sleep...
 Pry 0 is a valid object type 1 (creature is type 1)
 0 Trying to destroy pry 0
 1 Trying to destroy pry 0
 2 Trying to destroy pry 0
 ...
 < snip >
 ...
 6234 Trying to destroy pry 0
 Script reg_node_sleep, OID: 800000ee, Tag: , ERROR: TOO MANY INSTRUCTIONS
 Script reg_area_exit, OID: 800000ee, Tag: , ERROR: TOO MANY INSTRUCTIONS

Note that the object is valid and a creature. The only creatures in that area are ambients with the tag "reg_pry". So it is getting the right object, the object is valid... but it never destroys it. 
And I have tried it with various delays...

Those stubborn deer have stumped me. 

Edit: And yes, I realize the base object oObject will be destroyed in the middle of that loop, self destructing the whole thing. But "Destroy" has to work before that can happen :-P 
Then I can use "DestroyObjectsInAreaByTag" ;-P

<...'cuz he can walk from here>
               
               

               


                     Modifié par Rolo Kipp, 22 novembre 2012 - 04:25 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Stubborn deer
« Reply #1 on: November 22, 2012, 04:34:17 pm »


               You may have made the creatures undestroyable by either leaving a lootable corpse or making them raisable. 

Try:
...
AssignCommand(oTarget,SetIsDestroyable(TRUE));
DestroyObject( oTarget, 0.01f );
... 

 
EDIT:

Edit: And yes, I realize the base object oObject will be destroyed in the middle of that loop


False,  Objects are not destroyed untill after the script finishes.  
               
               

               


                     Modifié par Lightfoot8, 22 novembre 2012 - 04:38 .
                     
                  


            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #2 on: November 22, 2012, 04:41:49 pm »


               <pulling hard...>

The blueprint is standard creature (not lootable, no inventory, etc...) but...
Ok.
And...
No change. Same result.

Edit: Added:

   while (GetObjectType(oObject) != OBJECT_TYPE_WAYPOINT ) {
       oObject = GetNextObjectInArea( OBJECT_SELF );
   }

So loop doesn't self destruct. Same result.

<...on his least favorite pipe>
               
               

               


                     Modifié par Rolo Kipp, 22 novembre 2012 - 04:47 .
                     
                  


            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #3 on: November 22, 2012, 04:49:49 pm »


               <The light dawns...>

Lightfoot8 wrote...
False,  Objects are not destroyed untill after the script finishes.  

Ah-HA!

And the script wont end until the objects are destroyed! Got it.

*Knew* it was something simple and stupid :-/

Thanks, LF. Luv ya, man! Er, Kitty. Grumpy kitty.

<...dim and flickering, but it dawns>
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Stubborn deer
« Reply #4 on: November 22, 2012, 04:50:57 pm »


               Are the scripts that destroy the animal running on the animal? What event calls them? Or are they called by OnAreaExit? Etc...

I ran into a problem when depending on Creature AI scripts after all PC's left the area. The rate of execution goes way way down, and this appears to be a hardcoded feature.

Anyway... just somewhere to look.

Another Idea....
Use OTR's deer. '<img'>
               
               

               


                     Modifié par henesua, 22 novembre 2012 - 04:52 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Stubborn deer
« Reply #5 on: November 22, 2012, 04:53:58 pm »


               Yep,  you found it.   Just so everyone else can see it. 

void main()
{
  oObject = GetFirstObjectInArea( OBJECT_SELF);
  //   DestroyObjectsInAreaByTag( "reg_veg", OBJECT_SELF );
  // Loop through all "reg_pry" tags in area - Destroy
  iIndex = 0;
  oTarget = GetNearestObjectByTag( "reg_pry", oObject);
  while (oTarget != OBJECT_INVALID)
  {
    if (GetIsObjectValid(oTarget))
    {
       sMessage = "Pry "+IntToString(iIndex)
         +" is a valid object type "
         +IntToString(GetObjectType(oTarget))
         + " (creature is type "+IntToString(OBJECT_TYPE_CREATURE)+")";
       SendMessageToPC( oPC, sMessage );
    }
    nPC = 0;  // Just reusing var as counter
    while (oTarget != OBJECT_INVALID )
    {
      sMessage = IntToString(nPC++)
       +" Trying to destroy pry "
       + IntToString( iIndex);
      SendMessageToPC( oPC, sMessage );
      DestroyObject( oTarget, 0.01f );
    }

   oTarget = GetNearestObjectByTag( "reg_pry", OBJECT_SELF, iIndex++ );
  }

An endless loop was created on the first object since it was not destroyed during the script and was always valid.
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #6 on: November 22, 2012, 04:55:57 pm »


               <sighing...>

Nope. Destroyed them all (back to "DestroyAllHumans...er, ObjectsInAreaByTag") and let the script end... and they're still there. Doubled in fact, since they respawn when returning to the node...

<...a vast sigh of the put-upon>
               
               

               


                     Modifié par Rolo Kipp, 22 novembre 2012 - 05:07 .
                     
                  


            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #7 on: November 22, 2012, 05:01:50 pm »


               <trying to make up in quantum physics...>

henesua wrote...
Are the scripts that destroy the animal running on the animal? What event calls them? Or are they called by OnAreaExit? Etc...

I ran into a problem when depending on Creature AI scripts after all PC's left the area. The rate of execution goes way way down, and this appears to be a hardcoded feature.

The area onExit executes the reg_node_sleep script on the exiting area after a delay. That part works fine. I get starting and ending messages letting me know the script fired and completed (now that it's not an endless loop).

Anyway... just somewhere to look.

Another Idea....
Use OTR's deer. '<img'>

I thought about it (and certainly will for Amethyst!) But this is for the CCC and I really don't want to include other, previously released content to bloat the hak :-P So all the blueprints are simply modified bioware original. Makes finding diversity a real challenge for the biomass chains :-/

Trust me, better trees, prey animals, predators (and especially the alpha creatures!) are a must with this.

<...what he lacks in quality>
               
               

               


                     Modifié par Rolo Kipp, 23 novembre 2012 - 11:24 .
                     
                  


            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Stubborn deer
« Reply #8 on: November 22, 2012, 05:02:26 pm »


               Did you put a debug notifier in their death script to let you know when they died?
I usually do something like print out "DEATH" + GetName + Object ToString

-- and you should rename them "Mule Deer" in  stubborness.
               
               

               


                     Modifié par henesua, 22 novembre 2012 - 05:05 .
                     
                  


            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #9 on: November 22, 2012, 05:08:40 pm »


               <tying notes...>

henesua wrote...
Did you put a debug notifier in their death script to let you know when they died?
I usually do something like print out "DEATH" + GetName + Object ToString

-- and you should rename them "Mule Deer" in  stubborness.

Good ideas, both...
brb

<...to the legs of frisky deer>
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Stubborn deer
« Reply #10 on: November 22, 2012, 05:15:35 pm »


               It will not solve the current problem, But I did notice that your loop is getting the first creature twice. 

iIndex++  will return the curent value of  iIndex to a calling function and increase its value after.
++iIndex will increase the value first and return the new value.

so change :  oTarget = GetNearestObjectByTag( "reg_pry", OBJECT_SELF, iIndex++ );


To:  oTarget = GetNearestObjectByTag( "reg_pry", OBJECT_SELF, ++iIndex );
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #11 on: November 22, 2012, 05:30:27 pm »


               <willing to be proved...>

Lightfoot8 wrote...
It will not solve the current problem, But I did notice that your loop is getting the first creature twice.  

iIndex++  will return the curent value of  iIndex to a calling function and increase its value after.
++iIndex will increase the value first and return the new value.
...

I may be wrong, but I call it first outside the loop with the first object (index 0).
This gives it a valid object for the loop.
Operations are done on object 0, and object 0 is the object handed off to "Destroy". *Then* iIndex is incremented to object 1 .... Ah! *after* the GetObject grabs object 0 again. I see :-)

Thanks :-)

Ah-HA! again... Inside the loop I use OBJECT_SELF (area) to get next object... should be oObject.
And... it works :-)

<...slightly off kilter>
               
               

               
            

Legacy_Zarathustra217

  • Sr. Member
  • ****
  • Posts: 322
  • Karma: +0/-0
Stubborn deer
« Reply #12 on: November 24, 2012, 08:19:49 am »


               GetNearestObjectByTag takes 1 as the nearest object, so by...

oTarget = GetNearestObjectByTag( "reg_pry", oObject, iIndex++ );

... I imagine you'd get an OBJECT_INVALID, ending the loop after first run. Using ++iIndex instead would indeed solve part of it, but you still have to have your iIndex initialize as 1.

Alternatively, since GetFirstObjectInArea might be one of your deers, you could pass that in as the first target,

replacing the

object oTarget = GetNearestObjectByTag( "reg_pry", oObject);

with:

object oTarget = oObject;

Then you can initialize iIndex as 0 or keep iIndex++ rather than ++iIndex.
               
               

               


                     Modifié par Zarathustra217, 24 novembre 2012 - 08:56 .
                     
                  


            

Legacy_Zarathustra217

  • Sr. Member
  • ****
  • Posts: 322
  • Karma: +0/-0
Stubborn deer
« Reply #13 on: November 24, 2012, 09:05:58 am »


               Hmm, realising I might have come off a bit confusing, let me try to show how I propose to change the code:

object oObject = GetFirstObjectInArea( OBJECT_SELF);

// Loop through all "reg_pry" tags in area - Destroy
iIndex = 1;
oTarget = oObject; //First loop, we'll use the first object in the area.
while (oTarget != OBJECT_INVALID) {    
   if (GetIsObjectValid(oTarget)) {
       sMessage = "Pry "+IntToString(iIndex)+" is a valid object type "+IntToString(GetObjectType(oTarget))+ " (creature is type "+IntToString(OBJECT_TYPE_CREATURE)+")";
       SendMessageToPC( oPC, sMessage );
   }    
   nPC = 0;  // Just reusing var as counter    
   //Z217 - not really sure why you want to have the nPC variable here?
   sMessage = IntToString(nPC++)+" Trying to destroy pry " + IntToString( iIndex);
   SendMessageToPC( oPC, sMessage );  
   DestroyObject( oTarget, 0.0 );   //Z217 removed delay, unneeded, DestroyObject is always executed after the script ends.
   oTarget = GetNearestObjectByTag( "reg_pry", oObject, iIndex++ );
}

               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #14 on: November 24, 2012, 04:18:53 pm »


               <grabbing a towel...>

The nPC was just a reused variable left over from the endless loop LF highlighted in red above.
Likewise the delay was a legacy of me going nuts trying to figure out why they weren't destroyed.

And, actually, the original question remains unanswered. Although I got the loop-through to destroy what I want when I want, why didn't DestroyObjectsInAreaByTag() work? It takes the same area (OBJECT_SELF) and the same tag "reg_pry" I used in the loop...

The final version (in use now) is:
Edit: oObject is initialized to the first WP in the area. It's just a base from which to count.
But you're right about the index. Was 1. Why'd I set it to 0? *shakes head sadly*

// Loop through all "reg_pry" tags in area - Destroy
iIndex = 1;
oTarget = GetNearestObjectByTag( "reg_pry", oObject);
while (oTarget != OBJECT_INVALID) {
   sMessage = "Destroying pry " + GetName(oTarget)+" "+IntToString( iIndex);
   SendMessageToPC( oPC, sMessage );
   DestroyObject( oTarget );
   oTarget = GetNearestObjectByTag( "reg_pry", oObject, ++iIndex );
}


<...to clean up the mess>
               
               

               


                     Modifié par Rolo Kipp, 24 novembre 2012 - 04:31 .