Author Topic: Stubborn deer  (Read 1121 times)

Legacy_Zarathustra217

  • Sr. Member
  • ****
  • Posts: 322
  • Karma: +0/-0
Stubborn deer
« Reply #15 on: November 24, 2012, 10:55:43 pm »


               Where did you pull the DestroyObjectsInAreaByTag from?
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Stubborn deer
« Reply #16 on: November 25, 2012, 12:00:28 am »


               

Rolo Kipp wrote...

 
 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...



It is hard to answer the original question,  The code posted in the original post did not work because of the TMI.   Nothing happened in the script except in the first itteration of the loop where you hit your TMI on the inner loop. 

After that I never seen any Non working code posted, So it is hard to answer the question.
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #17 on: November 25, 2012, 02:59:21 pm »


               <a bigger fan...>

Zarathustra217 wrote...
Where did you pull the DestroyObjectsInAreaByTag from?

From x0_io_destroy (SoU):


//:://////////////////////////////////////////////////
//:: X0_I0_DESTROY
/*
Small include library to handle destroying multiple objects
with the same tag. Also has some utility functions for
handling multiple objects with the same tag.
 */

//:://////////////////////////////////////////////////
//:: Copyright (c) 2002 Floodgate Entertainment
//:: Created By: Naomi Novik
//:: Created On: 11/11/2002
//:://////////////////////////////////////////////////


/**********************************************************************
 * CONSTANTS
 **********************************************************************/

string INVISIBLE_OBJECT_RESREF = "plc_invisobj";

/**********************************************************************
 * FUNCTION PROTOTYPES
 **********************************************************************/

// Destroy all the objects in the area with a given tag.
// If nLimit is > 0, this will be the maximum number of things
// destroyed with the given tag.
void DestroyObjectsInAreaByTag(string sTag, object oCenter=OBJECT_SELF, int nLimit=0);

/**********************************************************************
 * FUNCTION DEFINITIONS
 **********************************************************************/

// Destroy all the objects in the area with a given tag.
// If nLimit is > 0, this will be the maximum number of things
// destroyed with the given tag.

void DestroyObjectsInAreaByTag(string sTag, object oCenter=OBJECT_SELF, int nLimit=0)
{
    object oDestroyer = CreateObject(OBJECT_TYPE_PLACEABLE,
                                     INVISIBLE_OBJECT_RESREF,
                                     GetLocation(oCenter));
    int nObjects = CountAllObjectsInAreaByTag(sTag, oDestroyer);
    if (nLimit == 0) {
        nLimit == nObjects;
    }
    int i=0;
    float fDelay=0.0;
    for (i=0; i < nObjects && i < nLimit; i++) {
        fDelay += 0.2;
        AssignCommand(oDestroyer,
                      DestroyNearestObjectByTag(sTag, oDestroyer, fDelay));
    }
    fDelay = 1.0 * nObjects;
    AssignCommand(oDestroyer, DestroyObject(oDestroyer, fDelay));
}

And the called functions are in there to (count & destroy nearest).
Just don't know why it didn't work the simple way :-P

@ LF: I mentioned it in the OP:

The destroy part should be as simple as:

DestroyObjectsInAreaByTag( "reg_pry", OBJECT_SELF );

Except it doesn't work.


<...of her books>
               
               

               


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


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Stubborn deer
« Reply #18 on: November 25, 2012, 04:46:10 pm »


               My misunderstanding.  I thought DestroyObjectsInAreaByTag  was the function you where writing.

So the question is then what was OBJECT_SELF when you called the function?  (or oCenter)

DestroyObjectsInAreaByTag( "reg_pry", OBJECT_SELF );

The first line in the function attempts to create a Placable at the location of oCenter.  If oCenter is the Area or ANY OBJECT NOT IN AN AREA the location will be invalid and then function will fail.
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #19 on: November 25, 2012, 05:39:56 pm »


               <shakes head sadly...>

Of course. And since I pass the tag and the area (Script is run on the area), it doesn't work.

So DestroyObjectsInAreaByTag does *not* work if you do not seed it with an object in the area.
Should have been written to get the first object in area if oCenter was an area. My opinion...

Well. Good to know.

Thanks for the dissection, LF :-) It was bugging me.

<...and waggles a finger at naomi>
               
               

               
            

Legacy_Zarathustra217

  • Sr. Member
  • ****
  • Posts: 322
  • Karma: +0/-0
Stubborn deer
« Reply #20 on: November 25, 2012, 06:08:19 pm »


               I'd honestly recommend you didn't use that function since cycling by GetNearestObjectByTag is (particularly) slow when you have a lot of objects with the same tag in an area. Based on my own tests, I believe you would get the most effective solution by using GetFirst/NextObjectInShape that covers the entire area.

Code for such a function would be:



void DestroyAllObjectsInAreaByTag(object oArea, string sTag, int nObjectFilter=OBJECT_TYPE_CREATURE)
{
    location lCenter=Location(oArea, Vector(), 0.0);
    object oTemp=GetFirstObjectInShape(SHAPE_CUBE, 400.0, lCenter, nObjectFilter);
    while(oTemp!=OBJECT_INVALID)
    {
        if(GetTag(oTemp)==sTag)
        {
            DestroyObject(oTemp);
        }
        oTemp=GetNextObjectInShape(SHAPE_CUBE, 400.0, lCenter, nObjectFilter);
    }
}


               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #21 on: November 25, 2012, 06:44:30 pm »


               <scribbling madly...>

I like it, thanks Z :-)
Hmmm... That 400.0... meters? "half the length of the sides of the cube".. A cube 800m on a side? Overkill?

And did anyone actually do any profiling on GetObjectInShape vs. Get ObjectInArea? I saw Funky state an opinion on it, but I don't remember anyone actually looking at the numbers...

<...with invisible ink>
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Stubborn deer
« Reply #22 on: November 25, 2012, 06:55:54 pm »


               I myself would just use GetFirst/NextObjectInArea.  

1)  No distance checks
2) no checks to see if it in in the shape.

Draw back.  There will be more VM instructions, since you will have to Filter for the Object type in the script.

With your system what you are really looking at is the trade off of number of VM instructions vs. speed.

What I really do not like about the function from the bioware Include is the fact that it counts all of the objects in the area, Most likely using GetNeareastObject in the iCountAllObjectsInAreaByTag  function.   This basicly means that the function uses the slowest function twice on all objects with that tag.   A major waste in my book.
               
               

               
            

Legacy_Zarathustra217

  • Sr. Member
  • ****
  • Posts: 322
  • Karma: +0/-0
Stubborn deer
« Reply #23 on: November 25, 2012, 07:14:16 pm »


               Well, I profiled it at some point and it turned out that if you were looking for just one object type, using the GetFirst/NextObjectInShape was faster than cycling with GetFirst/NextObjectInArea. The difference was rather marginal though, but my main point is really that I think it's easy to overrate how much performance is lost in simple geometrical tasks in NWN.

But then, we are splitting hairs here. To Rolo, I simply used 400.0 meters to make sure every object in the area gets included. I expect that the GetFirst/NextObjectInShape function doesn't work by drawing out any actual cube but calculate per object if it'll be within the range.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Stubborn deer
« Reply #24 on: November 25, 2012, 08:59:15 pm »


               First I am not arguing, Just giving my opinion.   Since I am not going to the length of looking at the functions, nothing is definitive. 

Quote
Zarathustra217 wrote...

Well, I profiled it at some point and it turned out that if you were looking for just one object type, using the GetFirst/NextObjectInShape was faster than cycling with GetFirst/NextObjectInArea. The difference was rather marginal though,...

I can see it being both slower and faster.  It is all dependent on how many items are in the area and the mix/ratio of object types.  Both functions are itterators so will not have the same major drag as GetNearestObject.  The main advantage of  GetFirst/NextObjectInShape is the "type filter" as you stated.  Being handled by the function in bulding the list allows it to happen much faster then the VM instruction equivalent.  I myself would go with First/NextInArea but that is just my prefferance.



[/quote] ...but my main point is really that I think it's easy to overrate how much performance is lost in simple geometrical tasks in NWN.[/quote]
I agree with that 100%,  I myself would still use GetNearestObjectByTag, If I was just looking for the closest single object.  I would not however use it to itterare through objects since it builds and destroys its distance chart every time the function runs. ( I know we all agree on that one.)   The problem with that function is not that it does a simple geometrical tasks, It is that it does a simple geometrical tasks way to often, along with allocating/deallocating memory on every itteration just to rebuild the same list again.. and again. ( Again Im beating a dead horse.)  

Quote
But then, we are splitting hairs here. To Rolo, I simply used 400.0 meters to make sure every object in the area gets included. I expect that the GetFirst/NextObjectInShape function doesn't work by drawing out any actual cube but calculate per object if it'll be within the range.


I would guess you are right.   I view the function as a wrapper around GetFirst/NextInArea with a distance Location check. does not really matter how it was done though since it is an itterator,  Meaning that the Checks only have to be done once per object,  reguardless of the number of itterations.  

P.S. and after reading the mess i wrote above, I should have just said; Apples and Oranges, Both functions will work. Just pick one.      
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Stubborn deer
« Reply #25 on: November 25, 2012, 10:20:38 pm »


                 And just to muddy the waters a little more, there's this way of doing it as well:

void DestroyObjectByTagInArea (string sTag, object oArea = OBJECT_SELF)
{
  int i;
  object oTarget;

  while (GetIsObjectValid (oTarget = GetObjectByTag (sTag, i++)))
        {
          if (GetArea (oTarget) == oArea)
                {
                  DestroyObject (oTarget);
                }
        }

               
               

               
            

Legacy_Zarathustra217

  • Sr. Member
  • ****
  • Posts: 322
  • Karma: +0/-0
Stubborn deer
« Reply #26 on: November 25, 2012, 10:27:35 pm »


               

Lightfoot8 wrote...
...


All agreed '<img'>

And sorry for barging in on your topic like this Rolo.
               
               

               


                     Modifié par Zarathustra217, 25 novembre 2012 - 10:29 .
                     
                  


            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #27 on: November 25, 2012, 10:45:50 pm »


               <waving off...>

I like that, too, FB. Wish I could see your posts in my feed - I'd "like" more of them :-P

Hmmm, but wouldn't putting the assignment inside GetIsObjectValid make it test whether "oTarget = GetObjectByTag (sTag, i++)" is a valid object?

@ Z217: I'm not sorry :-) I don't post to read my own drivel, I post to read *other's* <that came out wrong, boss>
You think so? <yup>
*shrugs*

Anyway, went with a modification of Z's using Get*ObjectInArea instead of shape. Partly because I'm destroying more than one type of object and partly because it was less typing =)

<...any apologies>
               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Stubborn deer
« Reply #28 on: November 27, 2012, 10:01:07 pm »


               

Rolo Kipp wrote...
Hmmm, but wouldn't putting the assignment inside GetIsObjectValid make it test whether "oTarget = GetObjectByTag (sTag, i++)" is a valid object?



No. An assignment statement will evaluate to the value assigned.

int x,y;
x = y = 0;


Cheers,

Meaglyn
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Stubborn deer
« Reply #29 on: November 28, 2012, 03:01:10 am »


               

meaglyn wrote...

Rolo Kipp wrote...
Hmmm, but wouldn't putting the assignment inside GetIsObjectValid make it test whether "oTarget = GetObjectByTag (sTag, i++)" is a valid object?



No. An assignment statement will evaluate to the value assigned.

int x,y;
x = y = 0;


Cheers,

Meaglyn


not 100% true with the default nwn compiler.   If it was True, your x = y = 0;   statment would compile in nwn script.  It however does not compile with the default compiler.    x = ( y = 0);  will compile though.    The fact that  x = y = 0;  does not compile implies that y = 0 does not evalulate to anything.   The fact that x = ( y = 0);  works implies that that it does evalulte to an intenger.     confused yet? 

The truth is that  =  does not evalulate.    The uses that do work are examples of side effect  programing that take advantage of a value that  is not yet removed from the top of the stack.