How to Create a Talk-Fight-Talk Sequence
This tutorial covers how to use dialog to initiate combat and then how to get combat to reinitiate dialog.
Create your dialog using KotOR Tool or DLGEditor. Think of your dialog in two parts: before fighting and after fighting. These two branches should attach to the root of the dialog tree.
Put the "After fighting" branch first in the dialog tree. Create a conditional script for this branch. The conditional script should look something like this:
int StartingConditional() {
int nResumeTalk = GetLocalBoolean(OBJECT_SELF,0);
return nResumeTalk;
}
Put the "Before fighting" branch on the dialog tree coming off the Root node, but below the "After fighting" node. Do not attach a conditional script. By doing this, you are telling the dialog to first check to see whether you've fought, and if not, then follow this branch.
Attach a script to fire at the point in the dialog where you want to make the NPC fight you. This script should at minimum look like this:
void main() {
// make main NPC go hostile
object oNPC=GetObjectByTag("npc_tag");
ChangeToStandardFaction(oNPC, 1);
// and if there are any thugs to fight...
object oThug1 = GetObjectByTag("npc1_tag");
object oThug2 = GetObjectByTag("npc2_tag");
object oThug3 = GetObjectByTag("npc3_tag");
// make them hostile
ChangeToStandardFaction(oThug1, 1);
ChangeToStandardFaction(oThug2, 1);
ChangeToStandardFaction(oThug3, 1);
// give them kick to make them start attacking you
ExecuteScript("k_ai_master",oNPC,1005);
}
That should do it for the dialog file. Now you'll need to modify the NPC .utc file.
Open the .utc in GFF editor or KotOR Tool and change the Min1HP value to 1. (This prevents death from occurring before we can talk again.)
Make sure the .utc Faction is set to 5 (neutral) so that you can talk without fighting first!
Now change the ScriptSpawn field to point to a new script file that contains the following:#include "k_inc_generic"
void main()
{
//This will make our user-defined event fire
GN_SetSpawnInCondition(SW_FLAG_EVENT_ON_DAMAGED);
GN_SetDayNightPresence( AMBIENT_PRESENCE_ALWAYS_PRESENT);
GN_SetListeningPatterns();
GN_WalkWayPoints();
}
Finally, the ScriptUserDefine field should point to a script containing:[size=1]
void main()
{
int nCurrentHP;
int nUser = GetUserDefinedEventNumber();
if(nUser == 1006) // DAMAGED
{
nCurrentHP=GetCurrentHitPoints();
if (nCurrentHP<10) {
CancelCombat (OBJECT_SELF);
ClearAllActions();
ChangeToStandardFaction(OBJECT_SELF, 5);
//record that we have fought
SetLocalBoolean(OBJECT_SELF,0,TRUE);
//Turn off the imortality
SetMinOneHP(OBJECT_SELF,FALSE);
object oPC=GetFirstPC();
ActionDoCommand(ActionStartConversation(oPC));
}
}
}
Now, when the conversation begins, you'll get the dialog that causes the fight. You'll fight and just before you deal the death blow, the NPC will stop fighting. The LocalBoolean function will let the dialog file know that you've already fought and should initiate the "after fighting" dialog.
This sequence can be useful for recruitment mods where the recruit starts off as hostile and needs to be shown who's tougher. (eg. Bandon recruitment mod)
The order of your StartingList is important in determining how the dialog is evaluated.
Here is how a .dlg might look within GFFEditor.
StartingList
- 0
- - Active: havefought
- - Index: 1
- 1
- - Active: blank
- - Index: 0
EntryList
- 0
- - Text: Let's fight!
- - RepliesList
- - - 0
- - - - Index: 0
- 1
- - Text: You are too strong for me
- - RepliesList
- - - 0
- - - - Index: 1
ReplyList
- 0
- - Script: beginfight
- - Text: Bring it on.
- 1
- - Text: And don't you forget it, Xavier2.
In DLGEditor it would look like this (with indices, conditionals, and scripts displayed)
my.dlg
- <havefought>[E1]You are to strong for me.<>
- - <>[R1]And don't you forget it, Xavier2.<>
- <>[E0]Let's fight!<>
- -<>[R0]Bring it on!<beginfight>
Note how the 'after-fighting' dialog is listed first, so that the havefought script can be evaluated. If they haven't fought, the dialog will fall through to the next entry in the StartingList until it finds one that doesn't have a condition or one that evaluates to TRUE.
I need to do the talk fight talk thing but I want it to be one of my party members to fight (not me). How could I do this?
You can accomplish this by using different Faction values in the ChangeToStandardFaction function.
In the script that initates combat, set your party member(s) faction to
STANDARD_FACTION_PREDATOR
and the NPC's faction to STANDARD_FACTION_PREY (or vice versa).
This will make them hostile to each other but neutral to everyone else. Just remember to set your party members' factions back to 2 (friendly) in the UserDefine script for the NPC.
Example:
//Fight script
void main() {
object oNPC=GetObjectByTag("npc_tag");
object oCarth=GetObjectByTag("carth");
// don't let Carth die...
SetMinOneHP(oCarth,1);
ChangeToStandardFaction(oNPC, STANDARD_FACTION_PREY);
ChangeToStandardFaction(oCarth, STANDARD_FACTION_PREDATOR);
// and if there are any thugs to fight...
object oThug1 = GetObjectByTag("npc1_tag");
object oThug2 = GetObjectByTag("npc2_tag");
object oThug3 = GetObjectByTag("npc3_tag");
ChangeToStandardFaction(oThug1, STANDARD_FACTION_PREY);
ChangeToStandardFaction(oThug2, STANDARD_FACTION_PREY);
ChangeToStandardFaction(oThug3, STANDARD_FACTION_PREY);
ExecuteScript("k_ai_master", oNPC, 1005);
ExecuteScript("k_ai_master", oCarth,1005);
}
//ScriptUserDefine for npc.utc
void main()
{
int nCurrentHP;
int nUser = GetUserDefinedEventNumber();
if(nUser == 1006) // DAMAGED
{
nCurrentHP=GetCurrentHitPoints();
if (nCurrentHP<10) {
CancelCombat (OBJECT_SELF);
ClearAllActions();
ChangeToStandardFaction(OBJECT_SELF, 5);
ChangeToStandardFaction(GetObjectByTag("carth"), 2);
//record that we have fought
SetLocalBoolean(OBJECT_SELF,0,TRUE);
//Turn off the imortality
SetMinOneHP(OBJECT_SELF,FALSE);
SetMinOneHP(GetObjectByTag("carth"),FALSE);
object oPC=GetFirstPC();
ActionDoCommand(ActionStartConversation(oPC));
}
}
}