Author Topic: Any ideas?  (Read 661 times)

Legacy_Terrorble

  • Sr. Member
  • ****
  • Posts: 370
  • Karma: +0/-0
Any ideas?
« on: February 24, 2015, 06:48:52 am »


               

This is a code snippet from my userdefined event handle for NPCs.  This particular NPC kills the player, walks up to them, takes a book, says stuff, walks off and disappears.  Except, none of that is happening.  They kill the player in normal combat, then stand there, and eventually disappear.


 


I have put in debug messages to confirm that all the code parts are running and returning expected values (I tell it to give me the name of the PC object stored on the NPC and it gives the correct PC name) but I can't seem to find why the NPC doesn't move to the PC, take the book, etc.  Frustrating thing is, I had it working a while back, then apparently thought I'd "improve" it.



    else if(nUser == EVENT_END_COMBAT_ROUND || GetUserDefinedEventNumber() == 1003)
    {
        if( GetLocalInt(OBJECT_SELF,"BOOK") == 1 )
        {
 
        object oPC = GetLocalObject(OBJECT_SELF,"PC");
 
        if( GetIsDead(oPC) )
        {
            effect eGhost = EffectCutsceneGhost();
            ApplyEffectToObject(DURATION_TYPE_PERMANENT,eGhost,OBJECT_SELF);
 
            object oBook = GetFirstItemInInventory(oPC);
            while( GetIsObjectValid(oBook) )
            {
                if( GetTag(oBook) == "LIBRARY1" )   break;
            oBook = GetNextItemInInventory(oPC);
            }
 
            ActionMoveToObject(oPC);
            ActionTakeItem(oBook,oPC);
            ActionSpeakString("It has the other book we want!");
            ActionPlayAnimation(ANIMATION_FIREFORGET_VICTORY1,1.0,6.0);
            ActionSpeakString("Let us take these to the artificers.");
            ActionMoveToObject(GetWaypointByTag("DST_TSD1"));
 
            DelayCommand(18.0, DestroyObject(OBJECT_SELF));
        }}


               
               

               
            

Legacy_MagicalMaster

  • Hero Member
  • *****
  • Posts: 2712
  • Karma: +0/-0
Any ideas?
« Reply #1 on: February 24, 2015, 07:33:34 am »


               

If you change the code to this, what happens?





    else if(nUser == EVENT_END_COMBAT_ROUND || GetUserDefinedEventNumber() == 1003)
    {
        SpeakString("Starting user defined stuff");
        if( GetLocalInt(OBJECT_SELF,"BOOK") == 1 )
        {
        SpeakString("In book section.");
        object oPC = GetLocalObject(OBJECT_SELF,"PC");
 
        if( GetIsDead(oPC) )
        {
            SpeakString("PC is dead!");
            effect eGhost = EffectCutsceneGhost();
            ApplyEffectToObject(DURATION_TYPE_PERMANENT,eGhost,OBJECT_SELF);
 
            object oBook = GetFirstItemInInventory(oPC);
            while( GetIsObjectValid(oBook) )
            {
                if( GetTag(oBook) == "LIBRARY1" )   break;
            oBook = GetNextItemInInventory(oPC);
            }
 
            ActionMoveToObject(oPC);
            ActionTakeItem(oBook,oPC);
            ActionSpeakString("It has the other book we want!");
            ActionPlayAnimation(ANIMATION_FIREFORGET_VICTORY1,1.0,6.0);
            ActionSpeakString("Let us take these to the artificers.");
            ActionMoveToObject(GetWaypointByTag("DST_TSD1"));
 
            DelayCommand(18.0, DestroyObject(OBJECT_SELF));
        }}


What messages does the NPC say?



               
               

               
            

Legacy_Proleric

  • Hero Member
  • *****
  • Posts: 1750
  • Karma: +0/-0
Any ideas?
« Reply #2 on: February 24, 2015, 07:33:55 am »


               

Is the PC death triggering this somehow? I'd need to see the code that invokes this script.


 


Working with dead objects is tricky - you might try moving to the PC's location instead.


 


Better to use ActionDoCommand (rather than DelayCommand) to DestroyObject at the end, but that probably doesn't fix everything.



               
               

               
            

Legacy_ehye_khandee

  • Hero Member
  • *****
  • Posts: 1415
  • Karma: +0/-0
Any ideas?
« Reply #3 on: February 24, 2015, 11:22:14 am »


               

Check your use of OBJECT_SELF it can be tricky.



               
               

               
            

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Any ideas?
« Reply #4 on: February 24, 2015, 01:43:47 pm »


               

Maybe this...


 


 


if(GetIsDead(oPC))

   {       

       ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneGhost(), OBJECT_SELF);

       object oBook = GetItemPossessedBy(oPC, "LIBRARY1");

 

       ActionMoveToObject(oPC);

       if(oBook != OBJECT_INVALID)

       {

          ActionSpeakString("It has the other book we want!");

          ActionTakeItem(oBook,oPC);

          ActionPlayAnimation(ANIMATION_FIREFORGET_VICTORY1,1.0,6.0);

          ActionSpeakString("Let us take these to the artificers.");          

       }

       else WriteTimeStampedLogEntry("object tagged : LIBRARY1 not found on player "+GetName(oPC)); // comment out if unused 

       ActionForceMoveToObject(GetWaypointByTag("DST_TSD1"));

       DelayCommand(18.0, DestroyObject(OBJECT_SELF));

   }

 

 

Kato


               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Any ideas?
« Reply #5 on: February 24, 2015, 06:25:11 pm »


               

What's the NPC doing before this?  You might try a ClearAllActions before all the actions.


 


Also, is oPC a object valid? You're pulling it out of a variable. I assume that's getting set some where but you may want to check.


 


You probably want to declare a local var to use for OBJECT_SELF in the delay command, but as Proleric said, that won't


effect the moving to the PC part.



               
               

               
            

Legacy_Terrorble

  • Sr. Member
  • ****
  • Posts: 370
  • Karma: +0/-0
Any ideas?
« Reply #6 on: February 25, 2015, 05:13:14 pm »


               
This is the OnEnter event for a trigger that creates the NPCs and sets the PC object on the NPCs.

 



void main()
{
    object oPC = GetEnteringObject();
    if( !GetIsPC(oPC) ) return;
    if( GetLocalInt(Getdbobj(oPC),"LIBRARY") == 3 )
    {
        effect eAppear = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3);
 
 
        //Get the waypoints to spawn the creatures at
        object oDR = GetWaypointByTag("DEMONRETRIEVER");
        object oMF = GetWaypointByTag("MFMASTER");
 
        //Apply the summon VFX for each
        ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eAppear,GetLocation(oDR));
        ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eAppear,GetLocation(oMF));
 
        //Create the monsters
        object o1 = CreateObject(OBJECT_TYPE_CREATURE,"demonretriever",GetLocation(oDR),FALSE,GetName(oPC)+"1");
        object o2 = CreateObject(OBJECT_TYPE_CREATURE,"mindflayermaster",GetLocation(oMF),FALSE,GetName(oPC)+"2");
 
        //Set the PC object on the monsters
        SetLocalObject(o1,"PC",oPC);
        SetLocalObject(o2,"PC",oPC);
 
        SetLocalInt(Getdbobj(oPC),"LIBRARY",5);
        AddJournalQuestEntry("LIBRARY",5,oPC,FALSE);
    }
}


 

 

That part works.  They spawn with the visual. 

 

 

MagicalMaster, on 24 Feb 2015 - 12:33 AM, said:

If you change the code to this, what happens?


    else if(nUser == EVENT_END_COMBAT_ROUND || GetUserDefinedEventNumber() == 1003) // END OF COMBAT
    {
        string sTag = GetTag(OBJECT_SELF);
        if( GetLocalInt(OBJECT_SELF,"BOOK") == 1 )
        {
AssignCommand(GetObjectByTag("SCREAMER"),ActionSpeakString("1 Marked with BOOK",TALKVOLUME_SHOUT));//DEBUG
SpeakString("1");
       
//I CHANGED HERE HOW I GET oPC
        //object oPC = GetLocalObject(OBJECT_SELF,"PC");
        object oPC = GetFirstPC();
 
 
AssignCommand(GetObjectByTag("SCREAMER"),ActionSpeakString("2 PC name is: "+GetName(oPC),TALKVOLUME_SHOUT));//DEBUG
SpeakString("2 "+GetName(oPC));
        if( GetIsDead(oPC) )
        {
AssignCommand(GetObjectByTag("SCREAMER"),ActionSpeakString("3 PC is dead",TALKVOLUME_SHOUT));//DEBUG
SpeakString("3 "+GetTag(OBJECT_SELF));
            effect eGhost = EffectCutsceneGhost();
            ApplyEffectToObject(DURATION_TYPE_PERMANENT,eGhost,OBJECT_SELF);
 
            object oBook = GetFirstItemInInventory(oPC);
            while( GetIsObjectValid(oBook) )
            {
                if( GetTag(oBook) == "LIBRARY1" ) {
AssignCommand(GetObjectByTag("SCREAMER"),ActionSpeakString("4 Book is in inventory",TALKVOLUME_SHOUT));//DEBUG
SpeakString("4");
                    break;
                }
            oBook = GetNextItemInInventory(oPC);
            }
 
            ActionMoveToObject(oPC);
AssignCommand(GetObjectByTag("SCREAMER"),ActionSpeakString("5 I should be moving to the person",TALKVOLUME_SHOUT));//DEBUG
SpeakString("5");
            ActionTakeItem(oBook,oPC);
            ActionSpeakString("It has the other book we want!");
            ActionPlayAnimation(ANIMATION_FIREFORGET_VICTORY1,1.0,6.0);
            ActionSpeakString("Let us take these to the artificers.");
            ActionMoveToObject(GetWaypointByTag("DST_TSD1"));
 
            //DelayCommand(18.0, DestroyObject(OBJECT_SELF));
        }}

What messages does the NPC say?

I added my changed code in the box above.  The NPCs say all the parts exactly how I'd expect.  Meaning, they spawn and attack the player.  While the player is still alive, the NPCs will say #1 (because they are marked to run end combat round events) and #2  with the correct name for the player (because they are getting the correct player object) at the end of each round.  **note that I changed how I was getting the oPC to GetFirstPC() since I'm testing with only one player on the server and wanted to rule out that the player object I set in the trigger OnEnter wasn't somehow wrong.

 

The NPCs don't say 3, 4 and 5 until I'm dead.  Which they do nicely right about the time the battle music quits after they've killed me.  But then they just stand there.  So it seems I've got the right oPC object, I've got the event firing and the code within firing too.  

 

Adding ClearAllActions(TRUE); before the ActionMoveToObject(oPC) doesn't make any difference either.  I was hopeful on this one.

 

 

Oh, I got something that worked!

 




    else if(nUser == EVENT_END_COMBAT_ROUND || GetUserDefinedEventNumber() == 1003) // END OF COMBAT
    {
        string sTag = GetTag(OBJECT_SELF);
        if( GetLocalInt(OBJECT_SELF,"BOOK") == 1 )
        {
        object oPC = GetLocalObject(OBJECT_SELF,"PC");
 
        if( GetIsDead(oPC) )
        {
            effect eGhost = EffectCutsceneGhost();
            ApplyEffectToObject(DURATION_TYPE_PERMANENT,eGhost,OBJECT_SELF);
 
            object oBook = GetFirstItemInInventory(oPC);
            while( GetIsObjectValid(oBook) )
            {
                if( GetTag(oBook) == "LIBRARY1" ) 
                    break;
 
            oBook = GetNextItemInInventory(oPC);
            }
 
            object oSelf;
            if( sTag == GetName(oPC)+"1" )
            {
                oSelf = GetObjectByTag(GetName(oPC)+"1");
 
                AssignCommand(oSelf,ActionMoveToObject(oPC));
                AssignCommand(oSelf,ActionTakeItem(oBook,oPC));
                AssignCommand(oSelf,ActionSpeakString("It has the other book we want!"));

                AssignCommand(oSelf,ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,4.0));
                AssignCommand(oSelf,ActionPlayAnimation(ANIMATION_LOOPING_TALK_LAUGHING,1.0,4.0));

                AssignCommand(oSelf,ActionSpeakString("Let us take these to the artificers."));
                AssignCommand(oSelf,ActionMoveToObject(GetWaypointByTag("DST_TSD1")));
            }
            else
            {
                oSelf = GetObjectByTag(GetName(oPC)+"2");
 
                AssignCommand(oSelf,ActionMoveToObject(oPC));
                AssignCommand(oSelf,ActionWait(8.0));
                AssignCommand(oSelf,ActionMoveToObject(GetWaypointByTag("DST_TSD1")));
            }
 
 
            DelayCommand(18.0, DestroyObject(OBJECT_SELF));
        }}



 

It looks like using AssignCommand worked.  I'm not entirely sure why I would have to assign the actions for it to work since this code is run from the UserDefined event handle on the NPC - the NPC is the object calling the code so ActionMoveToObject(oPC) should add the action to the queue of the object calling the script.  Hmm, well.  Hmm.

 

Thanks for the posts and ideas.  I was about to scrap this and y'all helped me stick with it long enough to get it working.


               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Any ideas?
« Reply #7 on: February 25, 2015, 07:02:21 pm »


               

Glad you got it working. I wonder if something else is clearing all the actions before the end of the event handling. Anyway, since you have oSelf defined now, you might as well stick it in here too:


 


DelayCommand(18.0, DestroyObject(oSelf));


               
               

               
            

Legacy_CaveGnome

  • Sr. Member
  • ****
  • Posts: 432
  • Karma: +0/-0
Any ideas?
« Reply #8 on: February 25, 2015, 10:35:01 pm »


               

Like Proleric said. Working with dead objects or dead creatures is tricky in Nwn. One thing to remember is that killed/destroyed objects are erased from the game after a few seconds including all scripts and actions they were running and sometimes you need a delay greater than the "after-death" running script persistance. In other words, if you use the dead body to execute a script or as a location reference, the program and its actions cease to work a few seconds after death or you can't get location info from the disapeared corpse. One way to mitigate this, is to link another script attached to another existing/created permanent object (ExecuteScript(sScript, oTarget)).