Part of script not running for some reason

I have a script that runs as an activation of an item. When activating it, a henchman creature appears. I want the henchman to automatically level up if the PC has leveled up earlier. For some reason that part of the script doesn’t run. I’ve tried with a bunch of SendMessageToPC but get no message ingame. I wonder what I’m doing wrong here:

int GetCanLevelUp(object oPC, object oSprif)
{
    int nMasterLevel = GetHitDice(oPC);
    int nMyLevel = GetHitDice(oSprif);

    if (nMasterLevel >= (nMyLevel + 4))
    {
        return TRUE;
    }
    return FALSE;
}

void PrepForDestruction(object oTarget)
{
	SetPlotFlag(oTarget,FALSE);
    SetImmortal(oTarget,FALSE);
    AssignCommand(oTarget,SetIsDestroyable(TRUE,FALSE,FALSE));
}

void KillSprif(object oSprif)
{

	PrepForDestruction(oSprif);
	DestroyObject(oSprif);


}

void AddSprif(object oPC)
{

object oSprif = GetObjectByTag("sprif");

AddHenchman(oPC,oSprif);

}


void CheckLevel(object oPC)
{

	SendMessageToPC(oPC,"Check level script is running");

	object oSprif = GetObjectByTag("sprif");

	if (GetCanLevelUp(oPC, oSprif))
    {

		SendMessageToPC(oPC,"Sprif should have leveled up");
        LevelUpHenchman(oSprif,CLASS_TYPE_MAGICAL_BEAST,FALSE,PACKAGE_MAGICBEAST);
        //SendMessageToPC(oPC,"Sprif should have leveled up");
				
		int nLevel = GetLevelByClass(CLASS_TYPE_MAGICAL_BEAST,oSprif);
		string sLevel = IntToString(nLevel);
		SendMessageToPC(oPC,"Sprif has leveled up! Sprif's level is now (" + sLevel + ").");

	}
	
	else
	  SendMessageToPC(oPC,"Sprif can't level up for some reason.");

}

void main()
{

object oFreya = GetObjectByTag("freya");
object oSprif = GetObjectByTag("sprif");

object oPC = GetFirstPC();

	if(GetIsObjectValid(oSprif))
	{

			RemoveHenchman(oPC,oSprif);
			DelayCommand(0.2,KillSprif(oSprif));
			return;

	}

location lLocation = GetLocation(oFreya);

CreateObject(OBJECT_TYPE_CREATURE,"sprif",lLocation,TRUE);

DelayCommand(0.5,AddSprif(oPC));
DelayCommand(0.8,CheckLevel(oPC));

}

It’s the CheckLevel part of the script that doesn’t run at all.

@andgalf

Note deleted.

Actually, I think you are saying that sprif is created and added, but then simply fails to level, so let me take a closer look.

Actually, try just moving the CheckLevel function to run from inside the AddSprif function.

void AddSprif(object oPC)
{

object oSprif = GetObjectByTag("sprif");

AddHenchman(oPC,oSprif);

CheckLevel(oPC);

}

If I remove the return; the removing of Sprif won’t work.

Sprif is either in the world or not when this script is run. This script is run on an item with the tag “sprif_it”. The name of this script is “i_sprif_it_ac”. It activates when you activate the item. If Sprif is in the game world I want him gone, if he’s not then he’s to be spawned. When spawned I want Sprif to level up if the PC is at 4 levels higher than him. Everything works without issues except the levelling up.

I tried before you answered here to do the CheckLevel inside of the AddSprif function (but I actually wrote the whole function inside that function). I’ll try your way and see what happens.

@andgalf

You may or may not require a slight delay to that function being run from there too, as in, it may need …

void AddSprif(object oPC)
{

object oSprif = GetObjectByTag("sprif");

AddHenchman(oPC,oSprif);

DelayCommand(0.1,CheckLevel(oPC));

}

NB: Don’t forget that you will need to move the CheckLevel function above the AddSprif to work.

That is, make sure the CheckLevel function is above the AddSprif function, or it won’t compile.

I’ve tested your way and like before, nothing happens.

@andgalf

Let me take a closer look in the toolset for you. One minute.

Can you try this please … FINISHED EDITING!

EDIT: See updated script in post below.

Exactly like before with your new script here.

I’m thinking that somehow it’s something hardcoded that gets in the way. When I activate this item, I activate it by the companion. Maybe that somehow screws with things. Will see what happens if I activate the item with the PC instead.

EDIT: Nope. Made no difference.

Another odd thing…I have this script on the OnPlayerLevelUp on the module properties. This script fires and works everytime you level up with the PC. It’s almost the same code so I have idea what’s going on:

// k_mod_player_levelup
/*
    Module level up
*/
// ChazM 3/2/06

//::///////////////////////////////////////////////
//:: nw_O0_LevelUp.nss
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
 This script fires whenever a player levels up.
 If the henchmen is capable of going up a level, they do.
*/
//:://////////////////////////////////////////////
//:: Created By:     Brent
//:: Created On:     2002
//:://////////////////////////////////////////////

//#include "nw_i0_henchman_mod"
#include "nw_i0_generic"

int GetCanLevelUp(object oPC, object meLevel = OBJECT_SELF)
{
    int nMasterLevel = GetHitDice(oPC);
    int nMyLevel = GetHitDice(meLevel);

// * April 9 2002
// * Removed this so that if you are very high level
// * you can still ask your henchman to level up
//    if (nMasterLevel <=5 || nMasterLevel >= 16)
//    {
//        return FALSE;
//    }

    if (nMasterLevel >= (nMyLevel + 4))
    {
        return TRUE;
    }
    return FALSE;
}



void main()
{
    object oPC = GetPCLevellingUp();
	object oPC1 = GetFirstPC();
		
    if (GetIsObjectValid(oPC) == TRUE)
	{
	
		//SendMessageToPC(oPC1,"PC is levelling up");
	
       	object oSprif = GetObjectByTag("sprif");
	   
	   	int nMasterLevel = GetHitDice(oPC);
    	
		if(!GetFactionEqual(oPC1,oSprif)) return;
		
    	if (GetIsObjectValid(oSprif ) == TRUE)
		{
		
	    	//SendMessageToPC(oPC1,"Sprif is valid and in party");
		
            if (GetCanLevelUp(oPC, oSprif ) == TRUE)
            {
						
				//SendMessageToPC(oPC1,"Sprif can level up");
            	LevelUpHenchman(oSprif,CLASS_TYPE_MAGICAL_BEAST,FALSE,PACKAGE_MAGICBEAST);
            	//SendMessageToPC(oPC1,"Sprif should have leveled up");
				
				int nLevel = GetLevelByClass(CLASS_TYPE_MAGICAL_BEAST,oSprif);
				string sLevel = IntToString(nLevel);
				SendMessageToPC(oPC1,"Sprif has leveled up! Sprif's level is now (" + sLevel + ").");
				
             	
            }
			
        }
    }
}

EDIT: I mean, I guess I could run the CheckLevel stuff on the creature’s OnHeartbeat script, but heartbeat scripts can bog the game down so I don’t want to do that unnecessarily.

Another thing that might have something to do with anything is that I get a message that the companion Freya has activated the item twice:

screen

EDIT: Things are getting werider still. I added all the stuff to the Sprif creature’s OnHeartBeat with a SendMessageToPC to tell me that the script was running. The script isn’t running! What the heck is going on here?!? Darn NWN2! This is totally crazy!

@andgalf

OK, I tested the script I supplied (slightly edited - see below) and noted the following in my own tests … (Updated to work with any PC.)

  1. First, I tested via a placeable lever rather than an item at this stage, just to be sure the script worked with that.

  2. The script fired fine, but as I did NOT have valid freya in my world, nothing happened. QUESTION: You do have “freya” in the module, yes? If “yes”, then try changing the location of spawn to the PC like I do in this script. (Just to test for now.)

  3. I changed the script to use the location of the first PC instead, and the sprif created and added to the party fine. (Having Freya present should work if you want to go back to her location.)

  4. Yes, my henchman had the magical beast level added.

  5. Yes, the item worked too.

Here are the couple of minor edits I made to the above script:-

int GetCanLevelUp(object oPC, object oSprif)
{
    int nMasterLevel = GetHitDice(oPC);
    int nMyLevel = GetHitDice(oSprif);

    if (nMasterLevel >= (nMyLevel + 4))
    {
        return TRUE;
    }
	
    return FALSE;
}

void PrepForDestruction(object oTarget)
{
	SetPlotFlag(oTarget,FALSE);
    SetImmortal(oTarget,FALSE);
    AssignCommand(oTarget,SetIsDestroyable(TRUE,FALSE,FALSE));
}

void KillSprif(object oSprif)
{

	PrepForDestruction(oSprif);
	DestroyObject(oSprif);


}

void CheckLevel(object oPC, object oSprif)
{

	SendMessageToPC(oPC,"Check level script is running");
	

	if (GetCanLevelUp(oPC, oSprif))
    {

		SendMessageToPC(oPC,"Sprif should have leveled up");
        int nLevel = LevelUpHenchman(oSprif,CLASS_TYPE_MAGICAL_BEAST,FALSE,PACKAGE_MAGICBEAST);
        //SendMessageToPC(oPC,"Sprif should have leveled up");
				
		//int nLevel = GetLevelByClass(CLASS_TYPE_MAGICAL_BEAST,oSprif);
		string sLevel = IntToString(nLevel);
		SendMessageToPC(oPC,"Sprif has leveled up! Sprif's level is now (" + sLevel + ").");

	}
	
	else
	  SendMessageToPC(oPC,"Sprif can't level up for some reason.");

}

void AddSprif(object oPC, object oSprif)
{

AddHenchman(oPC,oSprif);

DelayCommand(0.1,CheckLevel(oPC, oSprif));

}


void main()
{

object oFreya = GetObjectByTag("freya");
object oSprif = GetObjectByTag("sprif");

object oPC = GetFirstPC(FALSE);

	if(GetIsObjectValid(oSprif))
	{
            object oMaster = GetMaster(oSprif);
			RemoveHenchman(oMaster, oSprif);			
			DelayCommand(0.2,KillSprif(oSprif));
			return;

	}

//location lLocation = GetLocation(oFreya);
location lLocation = GetLocation(oPC);

object oSprifNEW = CreateObject(OBJECT_TYPE_CREATURE, "sprif", lLocation,TRUE);

AddSprif(oPC, oSprifNEW);

}

UPDATED: This script now allows any companions usage.

Thank you @Lance_Botelle ! Now everything seems to be working.

I still find a lot of stuff really odd here. 'Cause now I noticed that all of a sudden Sprif’s heartbeat script was also running, which it didn’t do before. And the only thing that I can see that you did was to change the location to that of the PC. How could that have been of such great importance?!

I mean, the sprif item is cursed so it is always in Freya’s inventory, so spawning Sprif to her location should have worked just as well. I just don’t get this game sometimes. It’s so odd.

1 Like

Do you have any answers to my questions here perhaps?

Yep … :slight_smile:

You could try wrapping the GetLocation of Freya in a “CalcSafeLocation” … but I have not tried the script using Freya’s location since my other updates, so maybe that works now anyway?

Does using Freya’s location work in the updated version of my script above? Or, does it work if wrapped in a CalcSafeLocation? Let me know, as I would be interested to hear. (Unfortunately, I deleted the code my end so cannot check again.)

Also, did you reboot the game/toolset/computer between testing? That has made the difference for me sometimes.

I tried with using Freya’s location now instead. And now that works too?! What the heck?! What was it that I did in my code that made it not working? I don’t understand!

Maybe I should use the PC location after all but…no…if someone uses this in the middle of the fight and the companion and the PC is a bit separated it makes no sense that Sprif would turn up beside the PC.

EDIT: Is it something to do with you using object oSprifNew?

@andgalf

I was unsure why the original script I posted had not worked for you either. :thinking: This latest version is just a slightly more versatile version of that one.

As I say, did you do a toolset restart, a game restart or a computer reboot?

Other than that, maybe Freya was borked somehow, as that would have stopped the script running too.

If you find out, let me know. :slight_smile:

I had that in the original edit, so that original script should have worked too.

Hmmm, yeah, that’s true. This game is truly bonkers sometimes!

I did do a toolset restart but not a computer reboot, and I always, when testing (particularly now that I’m working in campaign mode with several modules to reduce CTD) run the game from the toolset. I know some have said that’s not always good to do, but to me that has ALWAYS worked and if I don’t do that here then it will start from the first module…unless I start the module instead of campaign from the main game perhaps…
When I’ll do a real playtest from the beginning later, then I always run the campaign from the main game and not the toolset.
Anyway, I don’t understand what all this was about in the end. Something must have gotten borked somehow, but I wonder what.

Yeh … I think you just discovered the reason not to rely on the toolset run-game situation, especially as you are requiring the module to update the objects available to find with the GetObjectByTag command.

I know it can be a bit of an extra step to take, but I always start the module from the actual game run - BUT I do have a couple of steps I remove from a normal game start to get into the testing quicker.

RECOMMEND: Stick with the way that works best for you, but if you ever experience an issue that makes no sense, test the module in the game rather than the toolset as a final check. You may start to find that just checking from the game itself will eventually be quicker than using the toolset, encountering an issue and then retesting via the game. That’s why I abandoned the toolset test button … like everything else, we need to reduce potential errors creeping in when we test.

Ok.

Trying to code the CalcSafeLocation into a function but I can’t seem to wrap my head around how to do this. I should be able to do it but…

location lLocation = GetLocation(oFreya);	
location lLocationSafe = CalcSafeLocation(oSprifNEW,lLocation,3.0,FALSE,FALSE);	

object oSprifNEW = CreateObject(OBJECT_TYPE_CREATURE, "sprif", lLocationSafe,TRUE);

However I do it, it doesn’t work. I need to define oSpiritNEW before lLocationSafe, but I need oSpiritNEW inside lLocationSafe (I think). Uurgh. How to code this?

EDIT: Can you do it like this or…feels a bit off to me:

location lLocation = GetLocation(oFreya);
object oSprifNEW;	
location lLocationSafe = CalcSafeLocation(oSprifNEW,lLocation,3.0,FALSE,FALSE);	

oSprifNEW = CreateObject(OBJECT_TYPE_CREATURE, "sprif", lLocationSafe,TRUE);

EDIT2: Searched here on the forums for an example of using this script and found something @kevL_s had written. So I tried my own version of that. Is this correct perhaps?

location lLocation = GetLocation(oFreya);

if (!GetIsLocationValid(lLocation))
    lLocation = CalcSafeLocation(oFreya, lLocation, 2.0, FALSE, FALSE);


object oSprifNEW = CreateObject(OBJECT_TYPE_CREATURE, "sprif", lLocation,TRUE);

In the description of the function it says:
oCreature - The creature to generate a safe location for
which I find a bit ambigous. Is oCreature oSprif or oFreya in this case?

@andgalf

Actually, I hope this still works - although, now you mention it, I have not tried this before in such a situation … but (if you want to) try this … if it does not work, then take it that you are correct, and perhaps you cannot do it this way.

My thinking is that we do not strictly have to use the creature we are calculating the safe position for … so we just use an existing creature object to get a safe location for something else. BUT, as I say, maybe I have not tried it this way myself yet. :thinking:

location lLocation = GetLocation(oFreya);
lLocation = CalcSafeLocation(oFreya,lLocation,3.0,FALSE,FALSE);	
object oSprifNEW = CreateObject(OBJECT_TYPE_CREATURE, "sprif", lLocation,TRUE);

If this does not work, then forget I said it. :wink: But, do let me know. :+1:

Ok, looking at your code it seems safer to use my code above, is it not? I mean, this one:

location lLocation = GetLocation(oFreya);

if (!GetIsLocationValid(lLocation))
    lLocation = CalcSafeLocation(oFreya, lLocation, 2.0, FALSE, FALSE);


object oSprifNEW = CreateObject(OBJECT_TYPE_CREATURE, "sprif", lLocation,TRUE);

That way we don’t change the location if it isn’t valid…Wait a minute…if oFreya’s location isn’t valid…uurgh…now I get a headache.

I’ll try your code ingame and see what happens.

I think we need @kevL_s now to straighten this out.