andysks Posted August 9, 2016 Share Posted August 9, 2016 Hi all. When I started modding I had much trouble with the stock conversation trigger. gtr_speak_node it's called I think. There are some things it does good, but the general functionality the way people want to mod nowdays is below par. The hang of the controlled companion if the player moves with him, the jump of the PC in the front and so on. So I wrote a script, then KevL took it and perfected it. After that, I made additions to it. The idea is to have a trigger with variables. When the party, any member, enters start convo no matter who is controlled. Check condition state, auto face target etc. Here it is for whoever feels like using it, adding things to it or whatever. // 'dialog_tr' // /******************************************************************************* Andy for Return of the Exile 22.1.2016 kevL rework 28.1.2016 To be used by a trigger's onEnter event. Starts a dialog. See TRIGGER VARIABLES below. Works with both SoZ-style. Works with an i-point placeable as owner as well. ------------- Additions ------------- 30.1.2016 : Added a party face target. Note that this adresses the start of the dialogue If the party moves or the NPC moves, we still need to adjust the facing using the ga_party_face 30.1.2016 : Added a bPCTalk option. For cutscenes that NEED to happen, but where the NPC only needs to talk to the PC. Instead of the idiotic warp, the main PC stays where he is but control switches to him. 4.2.2016 : Added a method for required creatures in order to start the dialogue. Good to have 4.2.2016 : Commented out the required creatures because of too much complexity. Perhaps in the future another trigger could be made for it, and all these function in a library. If this is ever added, remember to change the if (!GetLocalInt(oTrig, "bCondition")) with if (!GetLocalInt(oTrig, "bCondition") && checkRequiredTalkers(GetLocalString(oTrig, "sTalkers"))) ------------- TODO ------------- Add a bForce option that makes party/oSpeaker conversable. Add an option to use fade-in/fade-outs. Add an option to delay the conversation start. Possibly implement a heartbeat like CreateIPSpeaker() uses. Add an option to disable cutscene bars. Add a variable to check for item ------------- TRIGGER VARIABLES --------- bCondition - Default 0. Set it to 1 so that the trigger won't fire if we go inside. If it needs to fire further in the game, set a local int on the trigger called bCondition = 0. sQuestCond - Default "". The tag of the quest if a QuestCondition is needed. iQuestCond - Default 0. The ID of the quest if a QuestCondition is needed. sSpeaker - Default "". The tag of the creature to be speaking to the party. sConvo - Default "". Name of the conversation file. bDestroySelf - Default 0. Set to 1 if the trigger should get destroyed after it's done its job. bParty - Default 0. Set to 1 if the conversation is an internal party dialog. Checks if the companions needed (speaker) is in party. bPCTalk - Default 0. Set to 1 if Speaker is supposed to talk to the PC only. Note: Leave bParty default FALSE. sTalkers - Default "". A list of tags for required participants excluding PC and Speaker (comma-separated, no spaces). This is not used at the moment. *******************************************************************************/ //__________________ // ** PROTOTYPES *** // Checks if target can talk. int getConversable(object oTarget, int bFaction = FALSE); // Checks if an effect prevents dialog. int hasEffectSpeechless(object oTarget); // Makes party face the speaker void PartyFace(object oFacer, object oFaced); // Checks if required talkers are present and conversable. //int checkRequiredTalkers(string sTalkers); //____________ // ** MAIN *** void main() { object oTrig = OBJECT_SELF; if (!GetLocalInt(oTrig, "bCondition")) { object oPlayer = GetEnteringObject(); if (GetIsPC(oPlayer) && getConversable(oPlayer, TRUE)) { string sQuestCond = GetLocalString(oTrig, "sQuestCond"); if (sQuestCond == "" || GetJournalEntry(sQuestCond, GetOwnedCharacter(oPlayer)) == GetLocalInt(oTrig, "iQuestCond")) { object oSpeaker = GetNearestObjectByTag(GetLocalString(oTrig, "sSpeaker")); if (GetIsObjectValid(oSpeaker)) { int bParty = GetLocalInt(oTrig, "bParty"); if (bParty || getConversable(oSpeaker)) { if (bParty || GetLocalInt(oTrig, "bPCTalk")) oPlayer = SetOwnersControlledCompanion(oPlayer); if (!bParty || GetFactionEqual(oPlayer, oSpeaker)) { AssignCommand(oSpeaker, ClearAllActions()); AssignCommand(oPlayer, ClearAllActions()); PartyFace(oPlayer, oSpeaker); DelayCommand(0.25f, AssignCommand(oSpeaker, ActionStartConversation( oPlayer, GetLocalString(oTrig, "sConvo"), FALSE, FALSE, TRUE, FALSE))); if (GetLocalInt(oTrig, "bDestroySelf")) DelayCommand(3.0f, DestroyObject(oTrig)); } } } } } } } //_________________ // ** FUNCTIONS *** // Set the facing of the party to the speaker. // oFacer - the PC or companion // oFaced - the speaker // It happens by default. No need for any trigger variable here. void PartyFace(object oFacer, object oFaced) { object oFM = oFacer; vector vTarget = GetPosition(oFaced); oFacer = GetFirstFactionMember(oFM, FALSE); while(GetIsObjectValid(oFacer)) { AssignCommand(oFacer, ActionDoCommand(SetFacingPoint(vTarget, FALSE))); AssignCommand(oFacer, ActionWait(0.5f)); oFacer = GetNextFactionMember(oFM, FALSE); } } // Checks if target can talk. // oTarget - creature to check // bFaction - true to check target's faction (default FALSE) int getConversable(object oTarget, int bFaction = FALSE) { if (bFaction) { object oFaction = GetFirstFactionMember(oTarget, FALSE); while (GetIsObjectValid(oFaction)) { if (GetIsDead(oFaction) || GetIsInCombat(oFaction) || IsInConversation(oFaction) || hasEffectSpeechless(oFaction)) { return FALSE; } oFaction = GetNextFactionMember(oTarget, FALSE); } } else if (GetIsDead(oTarget) || GetIsInCombat(oTarget) || IsInConversation(oTarget) || hasEffectSpeechless(oTarget)) { return FALSE; } return TRUE; } // Checks if required talkers are present and conversable. // sTalkers - a comma-separated list of creature-tags (spaces *not* allowed) /*int checkRequiredTalkers(string sTalkers) { string sTalker; object oTalker; int iSeparator = 0; while (GetStringLength(sTalkers) > 0 && iSeparator != -1) { iSeparator = FindSubString(sTalkers, ","); if (iSeparator == -1) sTalker = sTalkers; else sTalker = GetStringLeft(sTalkers, iSeparator); oTalker = GetNearestObjectByTag(sTalker); if (!GetIsObjectValid(oTalker) || !getConversable(oTalker)) return FALSE; sTalkers = GetStringRight(sTalkers, GetStringLength(sTalkers) - iSeparator - 1); } return TRUE; }*/ // Checks if an effect prevents dialog. // oTarget - creature to check int hasEffectSpeechless(object oTarget) { int iEffect; effect eEffect = GetFirstEffect(oTarget); while (GetIsEffectValid(eEffect)) { iEffect = GetEffectType(eEffect); if ( iEffect == EFFECT_TYPE_CONFUSED || iEffect == EFFECT_TYPE_CUTSCENE_PARALYZE || iEffect == EFFECT_TYPE_CUTSCENEGHOST // || iEffect == EFFECT_TYPE_CUTSCENEIMMOBILIZE || iEffect == EFFECT_TYPE_DAZED || iEffect == EFFECT_TYPE_DEAF || iEffect == EFFECT_TYPE_DOMINATED // || iEffect == EFFECT_TYPE_ENTANGLE // || iEffect == EFFECT_TYPE_FRIGHTENED // || iEffect == EFFECT_TYPE_GREATERINVISIBILITY || iEffect == EFFECT_TYPE_INSANE // || iEffect == EFFECT_TYPE_INVISIBILITY // || iEffect == EFFECT_TYPE_JARRING || iEffect == EFFECT_TYPE_MESMERIZE || iEffect == EFFECT_TYPE_PARALYZE || iEffect == EFFECT_TYPE_PETRIFY // || iEffect == EFFECT_TYPE_POLYMORPH || iEffect == EFFECT_TYPE_SILENCE || iEffect == EFFECT_TYPE_SLEEP || iEffect == EFFECT_TYPE_STUNNED) // || iEffect == EFFECT_TYPE_TURNED { return TRUE; } eEffect = GetNextEffect(oTarget); } return FALSE; } Link to comment Share on other sites More sharing options...
Sabranic Posted August 16, 2016 Share Posted August 16, 2016 Thanks for posting this - Appreciate you and Kev's work! Link to comment Share on other sites More sharing options...
Tchos Posted August 17, 2016 Share Posted August 17, 2016 It's important to note that even with this script, as I understand it, the switch to the main character will still occur unless the object to be talked to has "Can talk to non-player owned creatures" set to true in the object's properties. Link to comment Share on other sites More sharing options...
andysks Posted August 18, 2016 Author Share Posted August 18, 2016 Yes Tchos. The script was kinda directed to my campaign where every NPC has the property TRUE. Therefore I just check the PCOnly and instead of a jump only control switches. We experimented with the jumps and switches of party members and I cannot remember if there is an actual way for the jump to not happen and the conversation to fire. I think even the i-point speaker scripts, the reason they don't make a switch is because the convo keeps trying to fire and aborts if the companion is leading... right? Link to comment Share on other sites More sharing options...
Tchos Posted August 18, 2016 Share Posted August 18, 2016 I'm not sure what you're saying there, but I'm saying that if you want the controlled companion to speak to the object without switching to the first-created PC, then ipoints and any other placeables also need their "Can talk to non-player owned creatures" property set to true, if you're using them as the speaker. When properly scripted and configured, no conversation ever needs to forcibly switch to the main PC, and the main PC is never required to be controlled for the conversation to fire. Link to comment Share on other sites More sharing options...
andysks Posted August 18, 2016 Author Share Posted August 18, 2016 Yeah I guess I didn't phrase it good. I meant that if the player controls a companion AND the NPC has the property FALSE then it is tough (or impossible?) to make it so that the PC Won't get a jump to the front. Anyway, as you say on your last sentence this is not the case. How would you do it so that a false CanTalkToNonPlayerCharacters makes no jump? Link to comment Share on other sites More sharing options...
Tchos Posted August 18, 2016 Share Posted August 18, 2016 Possibly the easiest way to do it would be to add a line to the speaking script that sets the property on the intended NPC, since it can be done by script. I think that setting it in the On Used script would set the property before the On Conversation script switches the controlled character, if that's where it happens. If not, it would work on the second attempt for sure. But to do it definitively, you could just use the On Module Loaded or Start script to cycle through every object in the module and set the property to true before anyone ever encounters them. Link to comment Share on other sites More sharing options...
andysks Posted August 18, 2016 Author Share Posted August 18, 2016 Ah yes. But if left FALSE and not changed via script there is no way to avoid the jump, is there? Not that any sane modder would leave it FALSE :). Just brainstorming here. Link to comment Share on other sites More sharing options...
Tchos Posted August 19, 2016 Share Posted August 19, 2016 Yes, I think that if you leave it as FALSE, and do not change it either with a scripted command or in the properties itself, a conversation with such an object will switch to the first created PC regardless of other factors. But depending on whether the switch happens in the On Conversation event or not, there may still be another way to prevent it. I'm not sure, but I don't think it would work, since placeables don't even have scripts in their On Conversation slots and it still happens with them. Link to comment Share on other sites More sharing options...
Recommended Posts