GetAppearanceType()?

Got two scripts for you code monkeys to look at. My code-fu is dicey at best… :frowning:

Ok. I’ll try to make this succinct.
I want the script below to check the PC’s body size and then create some floaty text input.
That part of the script is firing well so far.

#include "x3_inc_string"


void ClearAndJumpToObject(object oDestination);
void ClearAndJumpToObject(object oDestination)
{
    ClearAllActions();
    JumpToObject(oDestination);
}


void main()
{
    effect eVFX;
    object oTarget;

    // Get the creature who triggered this event.
    object oPC = GetClickingObject();

    // Set a local integer.
    SetLocalInt(oPC, "APPEARANCE_SET__", 1);

    // If the PC is a certain class.
    if ( GetCreatureSize(oPC) == CREATURE_SIZE_LARGE  ||
         GetCreatureSize(oPC) == CREATURE_SIZE_MEDIUM )
    {
        // Have text appear over the PC's head.
        string sTalk = "It would appear you're too fat to fit through the creviced bramble...!";
        string sRGB = StringToRGBString(sTalk, STRING_COLOR_GREEN);
        FloatingTextStringOnCreature(sRGB, oPC, FALSE);
    }
    // Else, if the PC's appearance.
    else if ( GetAppearanceType(oPC) == APPEARANCE_TYPE_KOBOLD_B ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GOBLIN_B||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GNOME_NPC_FEMALE ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BAT ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BADGER||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_WILL_O_WISP)
    {
        // Find the location to which to teleport.
        oTarget = GetWaypointByTag("LOK_LOK");

        // Teleport the PC.
        eVFX = EffectVisualEffect(VFX_IMP_UNSUMMON);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oPC);
        DelayCommand(3.0, AssignCommand(oPC, ClearAndJumpToObject(oTarget)));
    }
}

and the second bit of code -

type or paste code here


void main()
{
    object oPC = GetPCSpeaker();
    SetLocalInt(OBJECT_SELF, GetName(oPC), TRUE);

    switch ( d6(1) )
    {
        if ( GetLocalInt(oPC, "DO_ONCE__" + GetTag(OBJECT_SELF)) )
             return;
             SetLocalInt(oPC, "DO_ONCE__" + GetTag(OBJECT_SELF), TRUE);

        case 1: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_KOBOLD_B); break;
        case 2: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_GOBLIN_B); break;
        case 3: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_GNOME); break;
        case 4: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_BAT); break;
        case 5: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_BADGER); break;
        case 6: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_WILL_O_WISP); break;
    }
}

It’s the next part where I check the conditional for the PC’s appearance that is holding everything up.

The idea is to check to see if the PC’s appearance is set to the desired effect. There is a second script where, from a conversation file the PC’s appearance is changed. All appearances types are of the small variety (I believe),

You didn’t explicitly state what’s failing, but I assume the PC isn’t jumping? The delay and assign might be causing issues together. Try putting the jump command into its own function like this and see if it has any effect. Does you vfx right before the jump command work correctly?

DelayCommand(3.0, ClearAndJumpToObject(oPC, oTarget));
void ClearAndJumpToObject(object oPC, object oDestination)
{
    AssignCommand(oPC, ClearAllActions(TRUE));
    AssignCommand(oPC, JumpToObject(oDestination));
}

Also, as an aside for your switch, does the code in the switch block before the first case run correctly? I know there are some limitations as to what will work correctly in that location, but can’t remember what they are off the top of my head. Might be better just to put it outside/above the switch construct.

Yeah. The PC’s isn’t jumping. I’ll give this a try. Thanks tinygiant!

This is the code now -

#include "x3_inc_string"

void ClearAndJumpToObject(object oPC, object oDestination)
{
    AssignCommand(oPC, ClearAllActions(TRUE));
    AssignCommand(oPC, JumpToObject(oDestination));
}

void main()
{
    effect eVFX;
    object oDestination;

    // Get the creature who triggered this event.
    object oPC = GetClickingObject();

    // Set a local integer.
    SetLocalInt(oPC, "APPEARANCE_SET__", 1);

    // If the PC is a certain class.
    if ( GetCreatureSize(oPC) == CREATURE_SIZE_LARGE  ||
         GetCreatureSize(oPC) == CREATURE_SIZE_MEDIUM )
    {
        // Have text appear over the PC's head.
        string sTalk = "It would appear you're too fat to fit through the creviced bramble...!";
        string sRGB = StringToRGBString(sTalk, STRING_COLOR_GREEN);
        FloatingTextStringOnCreature(sRGB, oPC, FALSE);
    }
    // Else, if the PC's appearance.
    else if ( GetAppearanceType(oPC) == APPEARANCE_TYPE_KOBOLD_B ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GOBLIN_B||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GNOME_NPC_FEMALE ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BAT ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BADGER||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_WILL_O_WISP)
    {
        // Find the location to which to teleport.
        oDestination = GetWaypointByTag("LOK_LOK");

        // Teleport the PC.
        DelayCommand(3.0, ClearAndJumpToObject(oPC, oDestination));
    }
}


After the visual transformation nothing happens. I get the floaty text even if the PC has changed appearance.

I’m not quite sure what you mean? Could you elaborate just a wee bit?

Try adding some debugging and it should tell you about where things are failing:

#include "x3_inc_string"

int DEBUG_ME = TRUE;
void _Debug(object oPC, string s)
{
    if (DEBUG_ME)
        SendMessageToPC(oPC, s);
}

void ClearAndJumpToObject(object oPC, object oDestination)
{
    _Debug(oPC, "attempting to jump " + GetName(oPC) + " to " + GetTag(oDestination));

    AssignCommand(oPC, ClearAllActions(TRUE));
    AssignCommand(oPC, JumpToObject(oDestination));
}

void main()
{
    effect eVFX;
    object oDestination;

    // Get the creature who triggered this event.
    object oPC = GetClickingObject();
    _Debug(oPC, "pc = " + GetName(oPC));

    // Set a local integer.
    SetLocalInt(oPC, "APPEARANCE_SET__", 1);

    _Debug(oPC, "  size = " + IntToString(GetCreatureSize(oPC)));
    _Debug(oPC, "  appearance = " + IntToString(GetAppearanceType(oPC)));

    // If the PC is a certain class.
    if ( GetCreatureSize(oPC) == CREATURE_SIZE_LARGE  ||
         GetCreatureSize(oPC) == CREATURE_SIZE_MEDIUM )
    {
        // Have text appear over the PC's head.
        _Debug(oPC, "    ... creature size is large or medium");
        string sTalk = "It would appear you're too fat to fit through the creviced bramble...!";
        string sRGB = StringToRGBString(sTalk, STRING_COLOR_GREEN);
        FloatingTextStringOnCreature(sRGB, oPC, FALSE);
    }
    // Else, if the PC's appearance.
    else if ( GetAppearanceType(oPC) == APPEARANCE_TYPE_KOBOLD_B ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GOBLIN_B||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GNOME_NPC_FEMALE ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BAT ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BADGER||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_WILL_O_WISP)
    {
        _Debug(oPC, "creature is small, attempting to jump...");

        // Find the location to which to teleport.
        oDestination = GetWaypointByTag("LOK_LOK");

        // Teleport the PC.
        DelayCommand(3.0, ClearAndJumpToObject(oPC, oDestination));
    }
    else
        _Debug(oPC, "  creature has not met any requirements; no action taken");
}

Just wasn’t sure if your DO_ONCE__ code was working or not. It’s more of an interest question for me as sometimes code in a switch block before the first case doesn’t execute. But I honestly don’t remember what works and what doesn’t. If it’s working for you, leave it be.

void main()
{
    object oPC = GetPCSpeaker();
    SetLocalInt(OBJECT_SELF, GetName(oPC), TRUE);

    if ( GetLocalInt(oPC, "DO_ONCE__" + GetTag(OBJECT_SELF)) )
        return;
    SetLocalInt(oPC, "DO_ONCE__" + GetTag(OBJECT_SELF), TRUE);

    switch ( d6(1) )
    {
        case 1: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_KOBOLD_B); break;
        case 2: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_GOBLIN_B); break;
        case 3: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_GNOME); break;
        case 4: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_BAT); break;
        case 5: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_BADGER); break;
        case 6: SetCreatureAppearanceType(oPC, APPEARANCE_TYPE_WILL_O_WISP); break;
    }
}

Cool. I’ve never learned to debug. I know, pretty bad. :slight_smile:

That’s just quick, hip-pocket debugging, definitely not a module-wide solution, but it works for resolving issues in scripts quickly, sometimes, and lets you turn it off and on pretty quickly.

Ok tiny, I’ve got it laid out like so now -

#include "x3_inc_string"

int DEBUG_ME = TRUE;
void _Debug(object oPC, string s)
{
    if (DEBUG_ME)
        SendMessageToPC(oPC, s);
}

void ClearAndJumpToObject(object oPC, object oDestination)
{
    AssignCommand(oPC, ClearAllActions(TRUE));
    AssignCommand(oPC, JumpToObject(oDestination));
}

void main()
{
    object oDestination;

    // Get the creature who triggered this event.
    object oPC = GetClickingObject();

    // If the PC is a certain class.
    if ( GetCreatureSize(oPC) == CREATURE_SIZE_LARGE  ||
         GetCreatureSize(oPC) == CREATURE_SIZE_MEDIUM )
    {
        // Have text appear over the PC's head.
        string sTalk = "It would appear you're too fat to fit through the creviced bramble...!";
        string sRGB = StringToRGBString(sTalk, STRING_COLOR_GREEN);
        FloatingTextStringOnCreature(sRGB, oPC, FALSE);
    }
    // Else, if the PC's appearance.
    else if ( GetAppearanceType(oPC) == APPEARANCE_TYPE_KOBOLD_B ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GOBLIN_B||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GNOME_NPC_FEMALE ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BAT ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BADGER||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_WILL_O_WISP )
    {
        // Find the location to which to teleport.
        oDestination = GetWaypointByTag("LOK_LOK");

        // Teleport the PC.
        DelayCommand(3.0, ClearAndJumpToObject(oPC, oDestination));
    }
}


If this is correct, I’m getting no feedback. Is there a step I’m missing?

@Nizidramaniit - As far as I can see you haven’t put any _Debug(oPC,s); inside your script anywhere, you’ve just made the function at the top of the script. Compare that to @tinygiant 's script where he/she puts that everywhere in the code when he/she wants to send a message to the player.

I’m uncertain how to put that into my code. I’ve tried putting it in a couple of different places but it wont compile?

I think that the function _Debug() is NwN2 only. It’s neither in the NwN Lexicon 1.69 (just use the search function and type debug into the search box) nor is it included in the wiki either (according to its search function anyway). @Shadooow has written a tutorial on using the built-in debugging engine (sorry I haven’t got a link). I just include SendMessageToPC(object, string) with information on the state of variables to narrow down where the problem lies.

TR

@Tarot_Redhand - Eh, this doesn’t make sense to me. You say to include SendMessageToPC, in other words that function exists in NWNEE? The function _Debug() is @tinygiant 's custom function that includes SendMessageToPC. Why wouldn’t it work? As far as I know, @tinygiant works with NWNEE and not NWN2.

EDIT: As I suspected, it DOES work. I fired up my old NWN Deluxe Edition toolset and put the script in there. It compiled just fine.

EDIT2: @Nizidramaniit - As soon as you want to check that something has fired in the script put the function afterwards. For example like this:

#include "x3_inc_string"

int DEBUG_ME = TRUE;
void _Debug(object oPC, string s)
{
    if (DEBUG_ME)
        SendMessageToPC(oPC, s);
}

void ClearAndJumpToObject(object oPC, object oDestination)
{
    AssignCommand(oPC, ClearAllActions(TRUE));
    AssignCommand(oPC, JumpToObject(oDestination));
}

void main()
{
    object oDestination;

    // Get the creature who triggered this event.
    object oPC = GetClickingObject();

    _Debug(oPC,"The GetClickingObject ran just fine.");

    // If the PC is a certain class.
    if ( GetCreatureSize(oPC) == CREATURE_SIZE_LARGE  ||
         GetCreatureSize(oPC) == CREATURE_SIZE_MEDIUM )
    {
        // Have text appear over the PC's head.
        string sTalk = "It would appear you're too fat to fit through the creviced bramble...!";
        string sRGB = StringToRGBString(sTalk, STRING_COLOR_GREEN);
        FloatingTextStringOnCreature(sRGB, oPC, FALSE);
    }
    // Else, if the PC's appearance.
    else if ( GetAppearanceType(oPC) == APPEARANCE_TYPE_KOBOLD_B ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GOBLIN_B||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GNOME_NPC_FEMALE ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BAT ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BADGER||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_WILL_O_WISP )
    {
        _Debug(oPC,"The GetAppearance code ran just fine.");

        // Find the location to which to teleport.
        oDestination = GetWaypointByTag("LOK_LOK");



        // Teleport the PC.
        DelayCommand(3.0, ClearAndJumpToObject(oPC, oDestination));

        _Debug(oPC,"oPC should have jumped to the destination.");

    }
}

Again, everything compiled just fine in the NWN toolset for me. @Nizidramaniit - You can of course do even more advanced sendmessages like in @tinygiant 's example, but you can just as easily just do it like I did. I do that all the time with NWN2 (Yes, I am an NWN2 guy, but as mentioned I checked that this worked in NWN1 now (ok, can’t check for NWNEE, but there they have just added new functions, to my knowledge) when checking for bugs.

EDIT3: You can even do it just like this too:

#include "x3_inc_string"

void ClearAndJumpToObject(object oPC, object oDestination)
{
    AssignCommand(oPC, ClearAllActions(TRUE));
    AssignCommand(oPC, JumpToObject(oDestination));
}

void main()
{
    object oDestination;

    // Get the creature who triggered this event.
    object oPC = GetClickingObject();

    SendMessageToPC(oPC,"The GetClickingObject ran just fine.");

    // If the PC is a certain class.
    if ( GetCreatureSize(oPC) == CREATURE_SIZE_LARGE  ||
         GetCreatureSize(oPC) == CREATURE_SIZE_MEDIUM )
    {
        // Have text appear over the PC's head.
        string sTalk = "It would appear you're too fat to fit through the creviced bramble...!";
        string sRGB = StringToRGBString(sTalk, STRING_COLOR_GREEN);
        FloatingTextStringOnCreature(sRGB, oPC, FALSE);
    }
    // Else, if the PC's appearance.
    else if ( GetAppearanceType(oPC) == APPEARANCE_TYPE_KOBOLD_B ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GOBLIN_B||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_GNOME_NPC_FEMALE ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BAT ||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_BADGER||
              GetAppearanceType(oPC) == APPEARANCE_TYPE_WILL_O_WISP )
    {
        SendMessageToPC(oPC,"The GetAppearance ran just fine.");

        // Find the location to which to teleport.
        oDestination = GetWaypointByTag("LOK_LOK");



        // Teleport the PC.
        DelayCommand(3.0, ClearAndJumpToObject(oPC, oDestination));

        SendMessageToPC(oPC,"oPC should have jumped to the destination.");

    }
}

I included debugging statements in my last code snippet. You should be able to copy and paste everything I sent to get valid feedback as to what’s happening. You can tell which branches are or are not firing depending on what messages you receive.

Edit: The code from Post#7 is the code I’m referring to. All I did was copy and paste your code and add some debugging statements, so you should be able to run it directly. It compiles and runs in nwnee. Sorry for the confusion.

I ran the code in Post #7 as-is and it worked in my test module. All debug lines were emitted and the character jumped to the appropriate waypoint. So there could be a few things going on here. Before we start guessing though, let us know what debug messages you receive. When I ran the code, here was my output:
image

Note: Your PC’s name and the tag of the destination waypoint will probably be different. The most important part is which messages are emitted, then we can worry about the actual message content. You can ignore the messages in my screenshot that start with [Module], those won’t appear in yours.

https://neverwintervault.org/article/tutorial/script-debugging-tutorial

I don’t think the native debugger works in EE. I use SendMessageToPC now, it is annoying, but the debugger never worked in nwserver-mode anyway and with EE I am now debugging stuff realtime via /development folder.

The native debugger was fixed in a previous patch (can’t remember which one). That being said, I still do not recommend anyone use it. In-game messages are a much more reliable, robust and easy method of debugging and, since the debugger pauses the game, including a running server, the game will eventually timeout and shutdown. Friends don’t let friends use the native debugger (in NWN1/EE).

It never worked (or I never figured out how) in multiplayer before. So I never ran into your issue with timeout. And I would even say it is a bug, why does it timeout or rather why does it act differently than classic pause from SPACE key? In singleplayer mode you can keep it inside debugger for hours, no problem.

So I highly disagree. In singleplayer mode, the native debugger is incomparable to manually debugging using SendMessageToPC or custom functions. Just one command and you can browse whole code and see all variables at all times including structs and it even shown subdata of effects and itemproperty types I think - but maybe I remember wrong…

There was only one drawback and that was delayed commands. To see what is happening in delay one had to put SpawnScriptDebugger(); inside the function it ran with delay as well. Not that big deal.

It is incomparably more time effective as long as you can debug it in singleplayer.