Author Topic: oddly enough, another constant query:  (Read 805 times)

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
oddly enough, another constant query:
« on: May 08, 2012, 09:25:45 pm »


               I am working to store specific VFX light effects color and size for each 'light' object as a local var*, and ran into a bit of trouble with it and ran out of time last night:
Retrieving a string from a local var, no problem
making said string be recognized as a constant for an effect... not happening.

I was thinking I could just store the int value of the constant as a local var, and plug that in, skipping the constant. That should be much simpler. I am not able to verify this until later, but before I get that far, is this a good way to go about this?


*The goal is a reusable script on a switch or trigger that can turn on as many lights as I set, all with different colors and radii to be assigned when the light objects are placed. I would rather drive complexity out of the switch script and keep the light information localized to the objects, if at all possible.
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #1 on: May 08, 2012, 10:03:05 pm »


               <fielding one...>

Shouldn't be a problem. By the time the script is compiled those "constants" are replaced with their integer equivalent. So a constant defined as 2 somewhere in an include is replaced with the number 2 everywhere that constant is mentioned.

So a function that asks for func(CONSTANT_NUMBER) can be passed an int variable as easily as an int constant.

Hmmm, Lightfoot or WhiZard can explain it better, but you shouldn't have a problem replacing the constant with variables, so long as the variable is the same type as the constant and has a valid value.

<...from left field>
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #2 on: May 08, 2012, 10:18:59 pm »


               Leurnid,
I did the same thing. I used a local string for color, and a local int for radius. Then created a function that took those two pieces of data and returned the integer value representing the light vfx. The function nests the data, first checking for color then embedding a switch for radius (each unit is equal to 5' radius) to return the actual value of the light vfx.

I used a string for color, because it is easier for a builder to write "green" than it is to guess at a random integer representing green. The only problem with this approach is that you need to pre-process the string to be all lowercase so you eliminate the issues with humans and their inconsistent use of capitalization.

[edit]
And I wanted to add... you could also contnue with your first method AND have a local string which  "looks" like the constant string. However, when you do this, you need to create a function that converts this string into the VFX value. You'd have a longer sequence of if/then statements to pass thorugh before arriving at the VFX value, but it works. I've done this for my "disease trigger" which takes a string and converts it to a disease to give the person who enters.

Either way you need a function which converts the local variable into the integer value represented by the constant.

The third way of course is to have the 2da next to you (the builder), as TAD mentioned alsewhere, and simply enter that into the local integer on the object. I'm too lazy as a builder for that however. I prefer to be able to look at local vars on an object and understand what is happening.
               
               

               


                     Modifié par henesua, 08 mai 2012 - 09:25 .
                     
                  


            

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #3 on: May 08, 2012, 10:26:01 pm »


               Well, I used the lexicon to look up the value for VFX_DUR_LIGHT_YELLOW_5, which it says is 157... plugged that into the previously working script to replace the constant, ran a test of the module, and bang! All my light sources made some electrical sounds and started pulsing blue.

Me thinks my copy of the lexicon is wrong.

Nope, I am an idiot, forgot to include my 'n' prefix when I set the local variable, lol.

               
               

               


                     Modifié par Leurnid, 08 mai 2012 - 09:32 .
                     
                  


            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #4 on: May 08, 2012, 10:46:32 pm »


               Check the 2da.
               
               

               
            

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #5 on: May 08, 2012, 10:53:04 pm »


               

henesua wrote...

Leurnid,
I did the same thing. I used a local string for color, and a local int for radius. Then created a function that took those two pieces of data and returned the integer value representing the light vfx. The function nests the data, first checking for color then embedding a switch for radius (each unit is equal to 5' radius) to return the actual value of the light vfx.

I used a string for color, because it is easier for a builder to write "green" than it is to guess at a random integer representing green. The only problem with this approach is that you need to pre-process the string to be all lowercase so you eliminate the issues with humans and their inconsistent use of capitalization.

[edit]
And I wanted to add... you could also contnue with your first method AND have a local string which  "looks" like the constant string. However, when you do this, you need to create a function that converts this string into the VFX value. You'd have a longer sequence of if/then statements to pass thorugh before arriving at the VFX value, but it works. I've done this for my "disease trigger" which takes a string and converts it to a disease to give the person who enters.

Either way you need a function which converts the local variable into the integer value represented by the constant.

The third way of course is to have the 2da next to you (the builder), as TAD mentioned alsewhere, and simply enter that into the local integer on the object. I'm too lazy as a builder for that however. I prefer to be able to look at local vars on an object and understand what is happening.


That is mind-bogglingly impressive, but way more complicated than my addled brain and I want to get.

I dabated going the way you did when I was setting up my conceal and cover trigger script. Using the descriptive column values versus the hard effect values. I opted to use the hard effect values to a: avoid confusion (the conceal hard effect is a percent, but so is the description, so 25% concealment is a 10% concealment bonus... wtg wotc) and b: avoid work converting values around, and c:  give greater capability to a builder, who maybe wants an intermediate value not on the standard table (20% concealment, for a 8% bonus).

When I was thinking I could use a string as the constant, I was thinking that stringing together strings to build the name of the VFX effect would let me do what you describe, but when I realized that it wasn't going to, I knew that even if I figured out a way to convert a string to a constant, it was going to be way more work than I wanted.  I would rather just include a commented list of the VFX_DUR_LIGHT values in the switch script.

My preceeding mistake taught me another fun lesson too though... if I just use locally stored numbers, I can have one of my light objects do something like emit darkness or flicker blue and make an electric buzz ':lol:'
               
               

               
            

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #6 on: May 08, 2012, 10:59:17 pm »


               

henesua wrote...

...

And I wanted to add... you could also contnue with your first method AND have a local string which  "looks" like the constant string. However, when you do this, you need to create a function that converts this string into the VFX value. You'd have a longer sequence of if/then statements to pass thorugh before arriving at the VFX value, but it works. I've done this for my "disease trigger" which takes a string and converts it to a disease to give the person who enters.


I forgot to mention... I would love to see how you did that!

I was all over the lexicon and google trying to get a clue about how to pull something like that off... it was the end of the day, but even with a fresh start, I don't think I was going to get anywhere close to that solution.
               
               

               
            

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #7 on: May 08, 2012, 11:03:05 pm »


               OK, grrr..  

I have non emitter candles that just have the flame animation... they will pulse blue and flicker, but won't produce the VFX area light effect?
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #8 on: May 08, 2012, 11:24:09 pm »


               

Leurnid wrote...

OK, grrr..  

I have non emitter candles that just have the flame animation... they will pulse blue and flicker, but won't produce the VFX area light effect?

  Some placeables can't emit light.


  As for how you'd do colour/size, that'd be easy.

153     VFX_DUR_LIGHT_BLUE_5
154     VFX_DUR_LIGHT_BLUE_10
155     VFX_DUR_LIGHT_BLUE_15
156     VFX_DUR_LIGHT_BLUE_20
157     VFX_DUR_LIGHT_YELLOW_5
158     VFX_DUR_LIGHT_YELLOW_10
159     VFX_DUR_LIGHT_YELLOW_15
160     VFX_DUR_LIGHT_YELLOW_20
161     VFX_DUR_LIGHT_PURPLE_5
162     VFX_DUR_LIGHT_PURPLE_10
163     VFX_DUR_LIGHT_PURPLE_15
164     VFX_DUR_LIGHT_PURPLE_20
165     VFX_DUR_LIGHT_RED_5
166     VFX_DUR_LIGHT_RED_10
167     VFX_DUR_LIGHT_RED_15
168     VFX_DUR_LIGHT_RED_20
169     VFX_DUR_LIGHT_ORANGE_5
170     VFX_DUR_LIGHT_ORANGE_10
171     VFX_DUR_LIGHT_ORANGE_15
172     VFX_DUR_LIGHT_ORANGE_20
173     VFX_DUR_LIGHT_WHITE_5
174     VFX_DUR_LIGHT_WHITE_10
175     VFX_DUR_LIGHT_WHITE_15
176     VFX_DUR_LIGHT_WHITE_20
177     VFX_DUR_LIGHT_GREEN_5
178     VFX_DUR_LIGHT_GREEN_10
179     VFX_DUR_LIGHT_GREEN_15
180     VFX_DUR_LIGHT_GREEN_20

Sizes for the colours in that range are done nicely by grouping, so when you store a variable for light radius, you'd make 5' radius equal 0, 10' = 1, 15' = 2, 20' = 3, and add that to your base colour stored int (153, 157, 161, 165, 169, 173, or 177) to get your vfx number.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #9 on: May 09, 2012, 05:21:23 am »


               

Leurnid wrote...
...Retrieving a string from a local var, no problem
making said string be recognized as a constant for an effect... not happening.


Ok,  Rolo has already said all of this, I am just going to say it a little different.  

To explain why it does not work, lets look at the declaration of a Constant with an explaination of each part.  


const int  VFX_DUR_LIGHT_BLUE_5 = 153;
const DataType  Lable  =  ImmediateConstant;  



DataType:  The data type of the ImmediateConstant
Lable: The Lable that we want the compiler to recognize in place of the ImmediateConstant
ImmediateConstant: Yep the NWN compiler will only take Immediate Constants as the value for the lable. This simply means that you can not use an expression to set the value.  Even if the expression evalulates to a constant, it is still not allowed within NWN script.

The main problem you are running into is that the Lable  for the constant is an instruction to the compiler.   All Lables are replaced with there values within the compiled code( unless they are external, something we just can not do within nwscript).   So once the script is compiled there is simply no way to know that 153 was once know as the Lable  VFX_DUR_LIGHT_BLUE_5.  


...I was thinking I could just store the int value of the constant as a local var, and plug that in, skipping the constant. That should be much simpler. I am not able to verify this until later, but before I get that far, is this a good way to go about this?


Yes, you can do that.  You are however not skipping the constant,  153 is the constant its value never changes.  
VFX_DUR_LIGHT_BLUE_5 is just a compile time Lable that someone gave to the constant 153.

henesua wrote...
Either way you need a function which converts the local variable into the integer value represented by the constant.(Constant's Lable)

Leurnid wrote....
I forgot to mention... I would love to see how you did that!


int ConvertLableToConstant( string sContLable)
{
 if ( sContLable == "VFX_DUR_LIGHT_BLUE_5") return VFX_DUR_LIGHT_BLUE_5;
 if ( sContLable == "VFX_DUR_LIGHT_BLUE_10") return VFX_DUR_LIGHT_BLUE_10;
 if ( sContLable == "VFX_DUR_LIGHT_BLUE_15") return VFX_DUR_LIGHT_BLUE_15;
 if ( sContLable == "VFX_DUR_LIGHT_BLUE_20") return VFX_DUR_LIGHT_BLUE_20;
 if ( sContLable == "VFX_DUR_LIGHT_YELLOW_5") return VFX_DUR_LIGHT_YELLOW_5;
 if ( sContLable == "VFX_DUR_LIGHT_YELLOW_10") return VFX_DUR_LIGHT_YELLOW_10;
 if ( sContLable == "VFX_DUR_LIGHT_YELLOW_15") return VFX_DUR_LIGHT_YELLOW_15;
 if ( sContLable == "VFX_DUR_LIGHT_YELLOW_20") return VFX_DUR_LIGHT_YELLOW_20;
 if ( sContLable == "VFX_DUR_LIGHT_PURPLE_5") return VFX_DUR_LIGHT_PURPLE_5;
 if ( sContLable == "VFX_DUR_LIGHT_PURPLE_10") return VFX_DUR_LIGHT_PURPLE_10;
 if ( sContLable == "VFX_DUR_LIGHT_PURPLE_15") return VFX_DUR_LIGHT_PURPLE_15;
 if ( sContLable == "VFX_DUR_LIGHT_PURPLE_20") return VFX_DUR_LIGHT_PURPLE_20;
 // ect
 return -1;
}
               
               

               


                     Modifié par Lightfoot8, 09 mai 2012 - 04:24 .
                     
                  


            

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #10 on: May 09, 2012, 06:59:36 am »


               Figures, I just got done banging it out the hard way based on my interpretation of Henesua and Failed.Bard's comments, and you come in with a  much cleaner solution.

Just so, here is what I have right now, and it works, but LF's solution would tighten it up a bit:


void main()
{
    object oArea = GetArea(OBJECT_SELF);
    string sLights = (GetTag(OBJECT_SELF)+"_light");
    object oObject = GetFirstObjectInArea(oArea);
    effect eLight;
    int nVFXType = VFX_DUR_LIGHT_PURPLE_5; //defaults VFX setting if no override later

    if (GetLocalInt(OBJECT_SELF,"iAmOn") == 0)  //is it off?
    {
        ActionPlayAnimation(ANIMATION_PLACEABLE_ACTIVATE);  //animates switch click
        SetLocalInt(OBJECT_SELF,"iAmOn",1); //sets local var to 'on'

        while(GetIsObjectValid(oObject))    // Loop all objects in the area
        {
            if (GetTag(oObject) == sLights )    // is it a light object?
            {
                if (GetLocalInt(oObject, "iStandardLight") == 1)    // is it a std light?
                {
                    AssignCommand(oObject, ActionPlayAnimation(ANIMATION_PLACEABLE_ACTIVATE));
                    SetPlaceableIllumination(oObject, TRUE);    //turns on std light
                }
                else  //then it must be a light object for VFX
                {
                    if (GetLocalInt(oObject,"iHaveVFX"))  //is light object is flagged for color?
                    {
                        string sCol = GetStringLeft(GetStringLowerCase(GetLocalString(oObject,"sColor")),1); //get the lowercase first letter of the sColor stringon the light object
                        int nSize = GetLocalInt(oObject,"nSizer");  //get the size modifier off the light object: 0=5', 1=10', 2=15', 3 =20'

                        if (sCol == "b")
                        {
                            nVFXType = (153 + nSize);
                        }
                        else if (sCol == "y")
                        {
                            nVFXType = (157 + nSize);
                        }
                        else if (sCol == "p")
                        {
                            nVFXType = (161 + nSize);
                        }
                        else if (sCol == "r")
                        {
                            nVFXType = (165 + nSize);
                        }
                        else if (sCol == "o")
                        {
                            nVFXType = (169 + nSize);
                        }
                        else if (sCol == "g")
                        {
                            nVFXType = (177 + nSize);
                        }
                        else //sCol == "w" or any other value defaults to white
                        {
                            nVFXType = (173 + nSize);
                        }
                    }
                    else //if no local variables are on the light object
                    {
                        if (GetLocalInt(OBJECT_SELF, "nVFXdefault"))  //get default on switch (uses raw VFX int)
                        {
                            nVFXType = (GetLocalInt(OBJECT_SELF, "nVFXdefault"));
                        }
                    }
                    effect eLight = EffectVisualEffect(nVFXType);
                    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLight, oObject);
                    //applies applicable VFX to current light object
                }
            }

        oObject = GetNextObjectInArea(oArea);
        }
    }
    else //It's on; lights off!
    {
        ActionPlayAnimation(ANIMATION_PLACEABLE_DEACTIVATE);
        SetLocalInt(OBJECT_SELF,"iAmOn",0);

        while(GetIsObjectValid(oObject)) //check all objects
        {
            if (GetTag(oObject) == sLights )
            {
                if (GetLocalInt(oObject, "iStandardLight") == 1)
                {
                AssignCommand(oObject, ActionPlayAnimation(ANIMATION_PLACEABLE_DEACTIVATE));
                SetPlaceableIllumination(oObject, FALSE);
                }
                effect eEffect = GetFirstEffect(oObject);
                while (GetIsEffectValid(eEffect) == TRUE)
                    {
                    if (GetEffectType(eEffect) == EFFECT_TYPE_VISUALEFFECT)
                        RemoveEffect(oObject, eEffect);
                    eEffect = GetNextEffect(oObject);
                    }
            }
            oObject = GetNextObjectInArea(oArea);
        }
    }
    DelayCommand(1.2,RecomputeStaticLighting(GetArea(OBJECT_SELF)));
}


The foundation of this was a script by Nereng, I cleaned it up some, then got it all messy with my chaos.

While I don't mind the 'smart' color and size routine, my first thought is to just pull it back out and use the constant's int values and save myself some fuss all around.
               
               

               


                     Modifié par Leurnid, 09 mai 2012 - 06:10 .
                     
                  


            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #11 on: May 09, 2012, 02:56:22 pm »


               I wrote up a little example script, playing around with FindSubString now that I know what a useful function it is.

 For this script, you use a single string variable with the color at the start, and the radius at the end.  As an example, Green 05, or red 15.  Case doesn't matter, but with the 5' version it's best to put it as 05, and not just 5.

// (5/9/2012) Failed Bard
// Alternate placeable light system
// Playing around with FindSubString.

void main()
{
string sColors = "blu yel pur red ora whi gre";

string sColor = GetLocalString (OBJECT_SELF, "LIGHT");
int    nColor = FindSubString (sColors, GetStringLowerCase( GetStringLeft (sColor, 3)));

int    nBrightness = (StringToInt (GetStringRight (sColor, 2)) / 5) - 1;
if (nBrightness < 0) nBrightness = 0;
else if (nBrightness > 3) nBrightness = 3;

int nLight = 153 + nColor + nBrightness;

effect eLight = EffectVisualEffect (nLight);
ApplyEffectToObject (DURATION_TYPE_TEMPORARY, eLight, OBJECT_SELF, 10.0);
}
               
               

               
            

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #12 on: May 09, 2012, 04:40:16 pm »


               Ah, you went with the 3 letter designation so that with the space for padding, each one past the first would add 4 to the primary value. To slick for me, I am still brute-forcing these things.

For the lighting effects, you don't seem to need the float for duration... for whatever reason. I can't find a detailed reason why, but it works without.

*edit*
What I am finding is that if the objects being lit up are byond about 4 tiles from the player(s), the lighting update doesn't effect them, and while the animation may toggle on or off, the cast light is unpredictable.  I had one standard light in a long hall that seemed to be casting off darkness, when I was under it while testing, the hall was pitch black!
               
               

               


                     Modifié par Leurnid, 09 mai 2012 - 04:23 .
                     
                  


            

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #13 on: May 09, 2012, 07:03:15 pm »


               Incorporating F.B's routine and removing some more of my stupid, I get:


void main()
{
    object oArea = GetArea(OBJECT_SELF);
    string sLights = (GetTag(OBJECT_SELF)+"_light");
    object oLight = GetFirstObjectInArea(oArea);
    effect eLight;

    if (GetLocalInt(OBJECT_SELF,"iAmOn") == 0)  //is it off?
    {
        ActionPlayAnimation(ANIMATION_PLACEABLE_ACTIVATE);  //animates switch click
        SetLocalInt(OBJECT_SELF,"iAmOn",1); //sets local var to 'on'

        while(GetIsObjectValid(oLight))    // Loop all objects in the area
        {
            if (GetTag(oLight) == sLights )    // is it a light object?
            {
                if (GetLocalInt(oLight, "iStandardLight"))    // is it a std light?
                {
                    AssignCommand(oLight, ActionPlayAnimation(ANIMATION_PLACEABLE_ACTIVATE));
                    SetPlaceableIllumination(oLight, TRUE);    //turns on std light
                }
                else  //then it must be a light object for VFX
                {
                    string sColor = "Blue 10"; //default light color
                    if (GetLocalInt(oLight,"iHaveVFX"))
                    {
                        sColor = (GetLocalString (oLight, "sColor"));
                    }
                    else if (GetLocalInt(OBJECT_SELF,"iHaveVFX"))
                    {
                        sColor = (GetLocalString (OBJECT_SELF, "sColor"));
                    }

                    //F.B's simplified check routine:
                    string sColors = "blu yel pur red ora whi gre";
                    int nColor = FindSubString (sColors, GetStringLowerCase( GetStringLeft (sColor, 3)));
                    int nSize = (StringToInt (GetStringRight (sColor, 2)) / 5) - 1;
                    if (nSize < 0) nSize = 0;
                    else if (nSize > 3) nSize = 3;
                    int nVFXType = 153 + nColor + nSize;

                    effect eLight = EffectVisualEffect(nVFXType);
                    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLight, oLight);
                }
            }

        oLight = GetNextObjectInArea(oArea);
        }
    }
    else //It's on; lights off!
    {
        ActionPlayAnimation(ANIMATION_PLACEABLE_DEACTIVATE);
        SetLocalInt(OBJECT_SELF,"iAmOn",0);

        while(GetIsObjectValid(oLight)) //check all objects
        {
            if (GetTag(oLight) == sLights )
            {
                if (GetLocalInt(oLight, "iStandardLight") == 1)
                {
                AssignCommand(oLight, ActionPlayAnimation(ANIMATION_PLACEABLE_DEACTIVATE));
                SetPlaceableIllumination(oLight, FALSE);
                }
                effect eEffect = GetFirstEffect(oLight);
                while (GetIsEffectValid(eEffect) == TRUE)
                    {
                    if (GetEffectType(eEffect) == EFFECT_TYPE_VISUALEFFECT)
                        RemoveEffect(oLight, eEffect);
                    eEffect = GetNextEffect(oLight);
                    }
            }
            oLight = GetNextObjectInArea(oArea);
        }
    }
    DelayCommand(1.2,RecomputeStaticLighting(GetArea(OBJECT_SELF)));
}


Instead of putting an int on the switch for a switch default, and a constant in the script for a script default color, I smoothed out my garbled logic so F.B's color checking routine could also handle the switch and script defaults, allowing for consistent definition without extra routines, in fact, this trimmed some fat out of the script.
               
               

               


                     Modifié par Leurnid, 09 mai 2012 - 06:09 .
                     
                  


            

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
oddly enough, another constant query:
« Reply #14 on: May 09, 2012, 08:09:40 pm »


               This script, and several like it that I already use, check to see if there are local variables to use looking for a local int value; ( iHaveVFX ) in this case.
It would be just as easy to check to see of the string value I am really there looking for has a value stored  ( sColor != "" )..
The advantage of using the int-flag, is I can keep the effect's value on the object, and toggle it on or off via the integer.  whereas checking for the string value is lean and clean...

I figure this comes down to personal preference, but if anybody has opinions about this, I would love to here em.