Skip to content

(flavor text) How to (and best way) to put a message when the PC steps into a certain location?

So I am sure this is pretty simple... digging around the toolset for a feature but not sure where to look :smile:

All I want to do is send a message either in the dialog box, or could be above the PC's head... with some flavor text - IE, "you have entered what looks to be an ancient barracks, now in ruin"

What would be the nicest/best way (and how to) do this? thanks!!

Comments

  • WilliamDracoWilliamDraco Member Posts: 175
    Combat log or floating are both simple, depending on your preference.
    This goes into the OnEnter script for either the Area or a trigger that your draw. Fortunately the script is the same!

    To the combat-log
    SendMessageToPC(GetEnteringObject(), "Put your message in Speech Marks Here");
    

    To floating text
    FloatingTextStringOnCreature("Put your message in Speech Marks Here", GetEnteringObject(), FALSE);
    

    If you have any issues or questions, Ask away.
    ListenMirndt
  • Old_GithOld_Gith Member Posts: 152
    If you want something a bit more robust, and if you think it would be handy to just have one script handle all your calls for various flavor descriptions, then you could make your own custom trigger and add it to your Custom Trigger Palette. In the OnEnter event, place the script I have detailed below. Then, add three variables to the trigger (found on the Advanced Tab). You'll have two integer variables and one string variable. The string is where you will actually place your flavor text. The two integer variables are just to determine if your want the messages to be public (whole party) or private. I'll paste a picture of what that might look like below. Once done, now you can simply paint this trigger wherever you want, as often as you want, and the only thing you have to modify is the string variable (your actual flavor text).
    // OnEnter script for flavor triggers -- it will float the contents of the
    // trigger's local string "FloatingText" over anyone who enters (once per PC).
    // This will be private text unless the local integer "FloatingPublic" is set
    // on the trigger.
    
    void main()
    {
        object oEnterer = GetEnteringObject();
        object oSelf = OBJECT_SELF;
    
        // Only fire for PCs.
        if ( !GetIsPC(oEnterer) )
            return;
    
        // See if there is a message to display.
        string sMessage = GetLocalString(oSelf, "FloatingText");
        if ( sMessage == "" )
            // Nothing to do!
            return;
    
        // Only fire once per creature.
        if ( GetLocalInt(oSelf, "FloatingText_DoOnce_" + ObjectToString(oEnterer)) )
            return;
        SetLocalInt(oSelf, "FloatingText_DoOnce_" + ObjectToString(oEnterer), TRUE);
    
        // Float the message.
        FloatingTextStringOnCreature(sMessage, oEnterer, GetLocalInt(oSelf, "FloatingPublic"));
    }
    

    And:
    9zvkc6mohyr7.jpg

    Sylvus_MoonbowDerpCity
  • ListenMirndtListenMirndt Member Posts: 24
    WilliamDraco, thank you so much!
    And Old_Gith... that's incredibly helpful - screenshots and everything? you kind of rock! <3
  • ListenMirndtListenMirndt Member Posts: 24
    Further... Old_Gith, you actually even answered my followup questions before I even asked them (public/private doOnce)... <3 Thaaaank you!! sooo much
  • TarotRedhandTarotRedhand Member Posts: 1,481
    In that picture the trigger is showing as a 3D box. My experience is if you see that in a module you're building, chances are the trigger won't actually fire. For some reason it needs to be just a flat polygon.

    TR
  • TarotRedhandTarotRedhand Member Posts: 1,481
    For a generic speak once script that is only for a single player module we can simplify that script a little. As there is just the one PC there is an alternative way of making sure that the message only appears the once.
    // Alternative generic fire-once flavour text routine
    // for single-player modules only
    //
    // Place this function in the OnEnter event slot of a generic trigger
    // To use create a local string variable on the trigger with the name
    // "MySpeech" (without the quotes) and populate it with the flavour
    // text you want displayed at that point.
    
    void main(()
    {
        object oPC = GetEnteringObject(); // PC Object
        string sSpeakThis; // will hold flavour/error text
        
        if(GetIsPC(oPC))
        {
            sSpeakThis = GetLocalString(OBJECT_SELF, "MySpeech"); // Get actual text to speak
            
            if(sSpeakThis == "") // Oooops! You either forgot to create the local variable or it is empty
                sSpeakThis = "Debug message - Nothing to say"; // so give an error message instead
                
            AssignCommand(oPC, SpeakString(sSpeakThis)); // speak it
            
            DestroyObject(OBJECT_SELF, 1.0); // permanently remove the trigger - 
                                             // removes possibility for flavour text to show more than once
        }
    }
    

    Hope you find this useful.

    TR
    DerpCity
  • Pixel_MayhemPixel_Mayhem Member Posts: 61
    edited August 2019
    Wow... you guys always over complicate things, I always use....
    void main()
    {
    	object oPC = GetEnteringObject();
    	{
    	if(GetIsPC(oPC))
    		{
    		if(GetLocalInt(OBJECT_SELF, "DO_ONCE") != 1)
    			{
    			FloatingTextStringOnCreature("FlavorText", oPC);
    			SetLocalInt(OBJECT_SELF, "DO_ONCE", 1);	
    			}
    		else return;
    		}
    	else return;
    	}
    }
    

    Super basic and simple but it works, of course I create a template of this and add it all over the place only thing I need to do then is change the flavor text itself. Keep in mind though this is only good for single player mods, all the more complicated ones above probably best for multi player mods :D

    Post edited by Pixel_Mayhem on
  • TarotRedhandTarotRedhand Member Posts: 1,481
    edited August 2019
    @Pixel_Mayhem The difference is that whereas both my script and @Old_Gith's can be reused for any number of triggers, you have to create a new script for each trigger which tends to bloat a module unnecessarily. Testing your script in the toolset confirms what I thought. As you present it here your script will not compile because you are treating
    object oPC = GetEnteringObject()
    
    as though it is an if statement (line not terminated with a ; and enclosing the rest of the code between { & }). Also your else return statements are redundant. After cleaning it up your code would look like -
    void main()
    {
        object oPC = GetEnteringObject();
    
        if(GetIsPC(oPC))
        {
            if(!(GetLocalInt(OBJECT_SELF, "DO_ONCE")))
            {
    	    FloatingTextStringOnCreature("FlavorText", oPC);
    	    SetLocalInt(OBJECT_SELF, "DO_ONCE", TRUE);	
            }
        }
    }
    

    Question - Did you even bother to read the code, including the comments, that @Old_Gith and I posted or did you just count the number of lines?

    TR
    Post edited by TarotRedhand on
    DerpCity
  • ProlericProleric Member Posts: 1,269
    edited August 2019
    If the message is important, a conversation can be much clearer than floating text, which is easily missed. To prevent the conversation being cancelled by player actions, assign the following function to the PC:
    void zTalk();
    {
        ClearAllActions(TRUE);
        ActionStartConversation(oPC, sConversation, FALSE, FALSE);
        ActionDoCommand(SetCommandable(TRUE));
        SetCommandable(FALSE);
    }
    

    At the moment, this is especially important in the Android version, where floating text is not displayed at all if the highlight button is on and the menu buttons are toggled over the log window (which is my normal mode of play). I guess that could be a bug, which might be fixed one day, but still...
    TarotRedhand
  • Pixel_MayhemPixel_Mayhem Member Posts: 61
    edited August 2019
    @Pixel_Mayhem The difference is that whereas both my script and @Old_Gith's can be reused for any number of triggers, you have to create a new script for each trigger which tends to bloat a module unnecessarily. Testing your script in the toolset confirms what I thought. As you present it here your script will not compile because you are treating
    object oPC = GetEnteringObject()
    
    as though it is an if statement (line not terminated with a ; and enclosing the rest of the code between { & }). Also your else return statements are redundant. After cleaning it up your code would look like -
    void main()
    {
        object oPC = GetEnteringObject();
    
        if(GetIsPC(oPC))
        {
            if(!(GetLocalInt(OBJECT_SELF, "DO_ONCE")))
            {
    	    FloatingTextStringOnCreature("FlavorText", oPC);
    	    SetLocalInt(OBJECT_SELF, "DO_ONCE", TRUE);	
            }
        }
    }
    

    Question - Did you even bother to read the code, including the comments, that @Old_Gith and I posted or did you just count the number of lines?

    TR

    Well it compiles for me so not sure why it doesn't for you? Maybe I put a typo in the example above and if you copy pasted it... You get the idea (having looked at it I see I did make an error, oops my bad) ;) And yes I did read yours and Giths examples and I still think they are overly complicated. I was just offering a simpler version for novices to scripting like me. By the way I really like the way you cleaned up my example.

    As for my method bloating a module... Well, fair point but is that really a concern for the hardware of today?
  • TarotRedhandTarotRedhand Member Posts: 1,481
    edited August 2019
    Actually your script can be simplified further. Because mine was designed for sp, I destroy the trigger once it fires the script (it is a fire once for PC trigger after all) so applying that to your script we get
    void main()
    {
        object oPC = GetEnteringObject();
    
        if(GetIsPC(oPC))
        {
    	FloatingTextStringOnCreature("FlavorText", oPC);
            
            DestroyObject(OBJECT_SELF, 1.0);
        }
    }
    

    Using DestroyObject() in this way removes the need for your second if and also the need to get and set a local variable.

    TR
  • Pixel_MayhemPixel_Mayhem Member Posts: 61
    So many ways to do one thing, I'm truly amazed and learning more than I would have thought :D
  • ZwerkulesZwerkules Member Posts: 112
    In that picture the trigger is showing as a 3D box. My experience is if you see that in a module you're building, chances are the trigger won't actually fire. For some reason it needs to be just a flat polygon.

    TR

    Do you have any examples? I don't find this very likely.
    As long as the triggers are on flat ground there is no need for them to be 3d, but once the ground is uneven they even have to be 3d to not disappear under the terrain in places (and have always worked reliably for me).
  • Old_GithOld_Gith Member Posts: 152
    They work for me if slightly 3d, but encounter triggers seem to be a bit pickier about dimensions.
  • Pixel_MayhemPixel_Mayhem Member Posts: 61
    I always paint my triggers flat and as a perfect square or rectangle all the time, I'm just pedantic like that :p
  • Carlo_OneCarlo_One Member Posts: 77
    As a builder, I've used Abaddon's Descriptive Triggers for a long time: https://neverwintervault.org/project/nwn1/script/abaddons-descriptive-triggers

    Two versions, one fires on a PC only once, the other every time. Description goes in the name field of the trigger, so that's the only typing that you absolutely have to do each time, although it's good to change the trigger tag to something descriptive.
Sign In or Register to comment.