Adjusting Z axis on placeables using a lever or button?

I’ve seen this and wondering if there is anything other than destroy / replace that can be used? I’m at a loss on how to do this.

Placeable is on the table, lets say it is Z 1.07 and then that is put on a variable on the lever or button. Then you drop that plc down below the tile. So when you pull the lever, it will raise the plc back up onto the table. Pulling the lever again, will get it to go back to its original position.

Anyone help me here? My son can’t seem to figure it out. I don’t want to put these plcs in the pallette for destroy/ replace.

1.69, or EE?

I am afraid the only way doing something like this with NWN 1.69 is destroying/creating placeables at different places, but my script knowledge is far from perfect. With EE, that is a different story, because you got specific new instructions to move or transform creatures or placeables.

You could try placing two separate instances of the placeable, one at the top, and one at the bottom, and apply and remove a cutscene invisibility effect when the lever gets pulled. The placeables would both be there, one of them would just be invisible.

Mind, something somewhere somewhen (like area OnEnter) will need to turn the second placeable invisible before the player first sees them.

What is ‘the placeable’, out of curiosity, and why do you want the lever to control it? In other words, what effect are you trying to achieve in your story? The player sees a lever, and pulls it, and a placeable is raised up from the floor to the tabletop? Or is the placeable hidden below the floor, and it’s brought up into view by the lever?

Cutscene invisibility is a good technique. You need to work around a known bug - when there are no players in the area, the effect is permanently baked, and cannot be removed. Store the current up/down status on the area or placeables (a local int for SP, data base entry I guess for PW). When the first player enters the area, apply the effect. When a player pulls the lever, toggle the effect. When the last player leaves the area, remove the efffect.

1 Like

This is 1.69
Lets say I have a bunch of plates of food on a table. Or maybe a bunch of plates as well as a platter of chicken? Well, they would not be seen until some sort of “activation” (lever) to make them appear. Uses tag “A”. Now dinner is gone and maybe have another lever bring up a bunch of desserts? Using tag “B”.
I’ve had some experience on another server and yes, JFK… where the plc is below the tile and using a lever is brought up to the table top into view. How is this done? Can’t be in the palette? Don’t want to make an SQL.
This is also a nice trick in maybe opening curtains. To lower closed curtains and bring up open curtains. It uses a variable in the Z axis of the plc.
Its really quite useful, if we can figure out how its done?
Proleric - not sure what you are trying to tell me.

Proleric is expanding on the cutscene invisibility method, pointing out a bug it has, as well as how to work around it.

Wrote a quick test function to demonstrate the method.
// Toggles visibility of all objects with a specific tag in a radius around the source object.
// If fRadius is -1.0, the radius is unlimited.
// oSource is the effect creator of the invisibility effect and is used to identify the effect when removing it again, so always use the same source object when toggling.
void MassToggleVisibility(string sTag, object oSource, int nVisible=TRUE, float fRadius=-1.0);
void MassToggleVisibility(string sTag, object oSource, int nVisible=TRUE, float fRadius=-1.0)
{
    int nDone, i=1;
    object oTarget = GetNearestObjectByTag(sTag, oSource, i);
    while (!nDone && GetIsObjectValid(oTarget))
        {
        // If the radius is limited,
        // and the distance between the target and the source is greater than the radius, abort.
        if (fRadius != -1.0 && GetDistanceBetween(oTarget, oSource) > fRadius)
            {
            nDone = TRUE;
            }
        else
            {
            // The target is currently flagged invisible...
            if (GetLocalInt(oTarget, "CUTSCENE_INVISIBLE"))
                {
                // ... and we don't want it to be invisible...
                if (nVisible)
                    {
                    // ... so the cutscene invisibility ends.
                    DeleteLocalInt(oTarget, "CUTSCENE_INVISIBLE");

                    effect eEffect = GetFirstEffect(oTarget);
                    while (GetIsEffectValid(eEffect))
                        {
                        if (GetEffectCreator(eEffect) == oSource)
                            RemoveEffect(oTarget, eEffect);

                        eEffect = GetNextEffect(oTarget);
                        }
                    }
                }
            // The target is not currently flagged invisible...
            else
                {
                // ... and we want it to be invisible...
                if (!nVisible)
                    {
                    // ... apply cutscene invisibility.
                    SetLocalInt(oTarget, "CUTSCENE_INVISIBLE", TRUE);
                    AssignCommand(oSource, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY), oTarget));
                    }
                }
            }

        oTarget = GetNearestObjectByTag(sTag, oSource, ++i);
        }
}

Going with Proleric’s tip, to avoid the cutscene invisibility becoming permanent, make sure to remove it when the last player leaves the area.

I still don’t understand but will see what my son says. He’s the scriptor.
Thank you so much for the help!!

1 Like

Okay!! Now I understand, Proleric!!! Son explained to me in using some of the examples that I want to try and he’s going to test this. He said its similar to his “shower” lever but backwards. The shower is on, and you use the lever to “cutscene” it off. The Area-On-Exit was something he didn’t think of. Now we can have the shower off upon entering, and use the lever to turn the shower on. Or fountain. Or food on table. This is going to be very useful !!

Thank you for the script, Barbarian!

The following are now the code my son came up with taking your cutscene suggestion and these work for us!!

2 Likes

AREA ENTER SCRIPT… this is in a loop checking every object in the area:
else if (FindSubString(GetTag(oWP), “TogglePlc”) != -1)
{
if (GetLocalInt(oWP, “PlcToggleDoOnce”) == FALSE)
{
string sTag = GetLocalString(oWP, “PLC_SET”);
MassToggleVisibility(sTag, oWP, FALSE, RADIUS_SIZE_LARGE);
SetLocalInt(oWP, “bActive”, FALSE);
SetLocalInt(oWP, “PlcToggleDoOnce”, TRUE);
}
}

AREA EXIT SCRIPT - Does the same thing but removes cutscene invisible which will only apply if no players in the area:

    else if (FindSubString(GetTag(oTrash), "TogglePlc") != -1)
    {
        SetLocalInt(oTrash, "bActive", FALSE);
        ExecuteScript("ds_lvr_toggleplc", oTrash);
        DeleteLocalInt(oTrash, "PlcToggleDoOnce");
    }

HERE IS THE SCRIPT FOR THE LEVER :slight_smile:

#include “ds_inc”
void main()
{
object oSelf = OBJECT_SELF;
string sTag = GetLocalString(oSelf, “PLC_SET”); // tag of placeables to toggle
int bVisible = GetLocalInt(oSelf, “bActive”) ? FALSE : TRUE;

MassToggleVisibility(sTag, oSelf, bVisible, RADIUS_SIZE_LARGE); // 5.0f
SetLocalInt(oSelf, "bActive", bVisible);

}

MINOR CHANGES TO YOUR FUNCTION IN AN INCLUDE FILE:

// Toggles visibility of all objects with a specific tag in a radius around the source object.
// If fRadius is -1.0, the radius is unlimited.
// oSource is the effect creator of the invisibility effect and is used to identify the effect when removing it again, so always use the same source object when toggling.
// Credit: Proleric and TheBarbarian
void MassToggleVisibility(string sTag, object oSource, int nVisible=TRUE, float fRadius=-1.0);
void MassToggleVisibility(string sTag, object oSource, int nVisible=TRUE, float fRadius=-1.0)
{
// If no valid objects to draw from, we simply exit
if (sTag == “” || !GetIsObjectValid(oSource)) return;
int i = 1;
object oTarget = GetNearestObjectByTag(sTag, oSource, i);
while (GetIsObjectValid(oTarget))
{
// If the radius is limited,
// and the distance between the target and the source is greater than the radius, abort.
if (fRadius != -1.0 && GetDistanceBetween(oTarget, oSource) > fRadius) break;
switch (nVisible)
{
case TRUE: { // End the invisibility effect
// … Remove if only already applied
if (GetLocalInt(oTarget, “CUTSCENE_INVISIBILITY”)) {
DeleteLocalInt(oTarget, “CUTSCENE_INVISIBILITY”);
effect eEffect = GetFirstEffect(oTarget);
while (GetIsEffectValid(eEffect)) {
if (GetEffectCreator(eEffect) == oSource)
RemoveEffect(oTarget, eEffect);
eEffect = GetNextEffect(oTarget);
}
}
} break;
case FALSE: { // Apply the invisibility effect
if (!GetLocalInt(oTarget, “CUTSCENE_INVISIBILITY”)) {
AssignCommand(oSource, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY), oTarget));
SetLocalInt(oTarget, “CUTSCENE_INVISIBILITY”, TRUE);
}
} break;
default: return;
}
oTarget = GetNearestObjectByTag(sTag, oSource, ++i);
}
}

In our case… Lever has the tag “TogglePlc” and the variable on the lever named
PLC_SET (string) (value is tag of the placeable to toggle)

Means as long as all the placeables have the same tag, the lever will activate to show / hide them all. Can use more than one lever.

Just a reminder. See this thread for how to get the best (mechanics i.e. what does what) out of these forums. This includes how to post code so that it is colourised and your layout isn’t trashed.

Using the instructions in that thread the code of that function (last bit of code above) looks like this -

// Toggles visibility of all objects with a specific tag in a radius around the source object.
// If fRadius is -1.0, the radius is unlimited.
// oSource is the effect creator of the invisibility effect and is used to identify the effect
// when removing it again, so always use the same source object when toggling.
// Credit: Proleric and TheBarbarian

void MassToggleVisibility(string sTag, object oSource, int nVisible=TRUE, float fRadius=-1.0);

void MassToggleVisibility(string sTag, object oSource, int nVisible=TRUE, float fRadius=-1.0)
{
    // If no valid objects to draw from, we simply exit

    if (sTag == "" || !GetIsObjectValid(oSource))
        return;

    int i = 1;
    object oTarget = GetNearestObjectByTag(sTag, oSource, i);

    while (GetIsObjectValid(oTarget))
    {
        // If the radius is limited,
        // and the distance between the target and the source is greater than the radius, abort.

        if (fRadius != -1.0 && GetDistanceBetween(oTarget, oSource) > fRadius)
            break;

        switch (nVisible)
        {
            case TRUE: // End the invisibility effect
                       // … Remove if only already applied

                    if (GetLocalInt(oTarget, "CUTSCENE_INVISIBILITY"))
                    {
                        DeleteLocalInt(oTarget, "CUTSCENE_INVISIBILITY");
                        effect eEffect = GetFirstEffect(oTarget);

                        while (GetIsEffectValid(eEffect))
                        {
                            if (GetEffectCreator(eEffect) == oSource)
                                RemoveEffect(oTarget, eEffect);

                            eEffect = GetNextEffect(oTarget);
                        }
                    }
                    break;

            case FALSE: // Apply the invisibility effect

                    if (!GetLocalInt(oTarget, "CUTSCENE_INVISIBILITY"))
                    {
                        AssignCommand(oSource, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY), oTarget));
                        SetLocalInt(oTarget, "CUTSCENE_INVISIBILITY", TRUE);
                    }

                    break;

            default: return;
        }
        oTarget = GetNearestObjectByTag(sTag, oSource, ++i);
    }
}

TR

1 Like

Ah okay. Sorry about that. I will read that.
But I’ve included it all so in case anyone else wants it.
Thank you for your help

1 Like

No need to apologise. But there is an even more important reason for posting your code in the manner shown in that thread. There is a built-in feature to these threads that “prettifies” certain things -

Outside of a code block

sTag == “”

inside

sTag == ""

Notice the "" becomes “”. That can really screw things up for anyone who copies and pastes your code in order to use it.

TR

1 Like