Aller au contenu

Photo

Need Some Help With a Cutscene <<SOLVED>>


  • Veuillez vous connecter pour répondre
26 réponses à ce sujet

#1
andysks

andysks
  • Members
  • 1 645 messages
Hi all. I have a cutscene, where you meet a companion, and then you can fight some things with him. The fighting happens out of the scene, and he hasn't yet become your companion, but actually you fight together, since the monsters are hostile and he a defender.
Anyway, I managed for him to not die by making him immortal, and generally the fight goes fine.

The help I need is for after the fight. How can I make him initiate dialogue, so that I take away his immortality and make him offer himself as companion?

Modifié par andysks, 11 décembre 2013 - 02:21 .


#2
PJ156

PJ156
  • Members
  • 2 982 messages
You can do a number of things.

1. You can use a script which counts the enemies as they fall and starts a convo when they are all gone (group on death).
2. You can assume the PC will talk to the npc after the fight and just have the convo on them.
3. You can add the npc as a hechman for the fight and again assume the player will want tot talk to them.

The tidiest is #1 but I think 2 will work as well and is the most stable. Convos fired from group on death can be a problem depending on your death scripts. If you have a respawn script them you need a delay to allow pc and npcs who may be involved in the convo to get back up. If you have one of the more permanent death scripts running you have to be sure the player is still alive at the end before the script fires.

In all I would say #2 is the most stable and the least complex to manage. You can switch off imortality by script or you can depawn the temporary npc and spawn the companion from script when they join.

PJ

#3
Lugaid of the Red Stripes

Lugaid of the Red Stripes
  • Members
  • 955 messages
I would do a variation of #1.  The enemies each have a script hooked into their death scripts, that checks to see whether if the other bad guys are dead yet.  If they're all dead, it executes a second script on the NPC-Future companion.  This second script orders both the PC (+party) and NPC out of combat, and after a short delay (a second or two) orders the NPC to talk to the PC, with distance disables.  Then it would it try to start the conversation again after another delay, just in case something went wrong. 

Here's an example of a script that does it all in one (I just have the one PC, so no party functions, and I know my baddies' corpses are gonna stick around, so I don't worry about splitting up the scripts:

[nwscript]
/ generic_deathcheck
/*
    Description: Template for deathcheck scripts
   
*/
// Name_Date
void RestartConvo(object oPC, string sConvo) {
    if (!IsInConversation(oPC)) {
        AssignCommand(oPC, ClearAllActions(TRUE));
        DelayCommand(0.5,
            AssignCommand(oPC, ActionStartConversation(oPC, sConvo, TRUE, FALSE, TRUE)));
        }
    }

//Returns TRUE if oSolja is Dead, Invalid, Hidden, or OBJECT_SELF
int iCheckDeath(object oSolja) {
    if (oSolja == OBJECT_SELF) {return TRUE;}
    else if (!GetIsObjectValid(oSolja)) {return TRUE;}
    else if (GetIsDead(oSolja)) {return TRUE;}
    else if (GetScriptHidden(oSolja)) {return TRUE;}
    else {
        object oPC = GetFirstPC();
        //SendMessageToPC(oPC, GetTag(oSolja) + " still alive");
        return FALSE;}
    }

//Returns TRUE if all Creatures with sTag are dead   
int iCheckDeathByTag(string sTag) {
    int iReturn = TRUE;
    int iTer = 0;
    object oSolja = GetObjectByTag(sTag, iTer);
    while (GetIsObjectValid(oSolja) && (iReturn == TRUE)) {
        //If you find a live one, return FALSE
        if (iCheckDeath(oSolja) == FALSE) {iReturn = FALSE;}
        iTer++;
        oSolja = GetObjectByTag(sTag, iTer);
        }
    return iReturn;

    }


void main()
{
    object oPC = GetFirstPC();
    int iQuest = GetJournalEntry("quest_comingfury", oPC);
    if (iQuest == 1) {
        int iDead = 0;
        iDead = iDead + iCheckDeathByTag("MBEGob1");
        iDead = iDead + iCheckDeathByTag("MBEGob2");
        iDead = iDead + iCheckDeathByTag("MBEGob3");
       
        if (iDead >= 3) {
            AddJournalQuestEntry("quest_comingfury", 2, oPC);
            SetNoticeText(oPC, "The attackers have been slain, you must speak with Sava");
           
            object oSava = GetObjectByTag("MBESava");
            AssignCommand(oSava, ClearAllActions(TRUE));
            AssignCommand(oPC, ClearAllActions(TRUE));
            DelayCommand(0.5, AssignCommand(oSava, ActionStartConversation(oPC)));
            DelayCommand(3.5, AssignCommand(oSava, RestartConvo(oPC, "sava_macboru")));
            }
        }
}
[/nwscript]

#4
andysks

andysks
  • Members
  • 1 645 messages
The #2 option of PJ is certainly clean, but I wanted something more sophisticated, like the count of corpses, or tags of goblins destroyed like Lugaid said. Of course, if this option fails somehow, or I encounter a bug, then I will just assume and hope the PC will talk to the NPC after the battle. I mean... who wouldn't :)?

Lugaid, some questions on this script:
The second function tat checks if the companion is dead, do I need it if he is immortal? Assuming that the object oSolja is a companion in your work that is :).
You check 3 times for iDead for goblins with different tags. In my situation there are like 15 hobgoblins. Do I need to check 15 times, and give them separate tags?

And finally, I haven't tested it, but I tried to create one with Lilacs, that will increment a variable every time an enemy dies, as PJ said. What could cause problems with this, and you had to use a variation Lugaid?

void main()
{
object oCyril;
int nValue;

// Get the creature who triggered this event.
object oPC = GetLastKiller();

// We are really interested in the ultimate master of the killer.
while ( GetMaster(oPC) != OBJECT_INVALID )
oPC = GetMaster(oPC);

// Set a local integer.
nValue = GetLocalInt(oPC, "cyril_encounter_count") + 1;
SetLocalInt(oPC, "cyril_encounter_count", nValue);

// If the local int is exactly 15.
if ( GetLocalInt(oPC, "cyril_encounter_count") == 15 )
{
// Have "cyril" strike up a conversation with the PC.
oCyril = GetNearestObjectByTag("cyril", oPC);
AssignCommand(oCyril, ActionStartConversation(oPC, "cyril_encounter_finish", FALSE, FALSE, TRUE,FALSE));
}
}

#5
Lugaid of the Red Stripes

Lugaid of the Red Stripes
  • Members
  • 955 messages
That function is to check the dead enemies, not the NPC. If you'll parse the third function (iCheckDeathByTag) closely, you'll see that it checks whether that all creatures with that tag are dead or gone (invalid)*. So if you want, you could just give all your hobgoblins the same tag, and just check that one tag.

While the Lilac's script should work, it doesn't fail-safe. Everything has to add up to exactly 15, if one hobgoblin doesn't fire their script correctly, the whole thing fails. With my script, you just need the last dead hobgoblin to fire their script, or you can just add in the script in a convo with the NPC as a last-ditch safeguard. Basically, you don't want your scripts to depend on a whole series of things working exactly right, because that just means that they have so many more break points, ways to fail.

Also, it will take up to six seconds for the PC and NPC to cool-down after combat before they can talk, so some conversations will be aborted if they're started mid-combat round.

GetFirstPC vs. GetLastKiller is another debate altogether, but I would use GetFirstPC() in this case. What if your NPC (Cyril?) finishes off the last hobgoblin? That would make him the last killer, and he'd just talk to himself. Furthermore, the count is being kept as a local variable on the last killer, so it gets split between Cyril and the PC.


*the scripthidden bit is because in most situations in my mods, creatures will run away once they're seriously injured, and a trigger will set them to scripthidden once they make it to safety.

Pro tip: write 'nwscript' in brackets before your code, and then '/nwscript' in brackets afterwards to keep the tabs right in these posts.

Modifié par Lugaid of the Red Stripes, 07 décembre 2013 - 03:57 .


#6
andysks

andysks
  • Members
  • 1 645 messages
OK, that explanation did it. I guess scripts like that one can fail more times than I can imagine huh?
I will try yours later today or tomorrow, and will let you know how it went. Thanks.

#7
andysks

andysks
  • Members
  • 1 645 messages
It won't work, but the situation generally, not the script. Problem is, that the enemies are quite spread out, and if he is not a henchman he will not follow if battle stops and doesn't continue as a chain. So I guess for this case I have to make him a henchman first.
Script didn't fire, but I assume it was because he was too far away when I killed all the enemies. I mean really far! In any case, a workaround will be found. Thanks a lot for the script, it will come in handy for sure :).

#8
ColorsFade

ColorsFade
  • Members
  • 1 267 messages

PJ156 wrote...

1. You can use a script which counts the enemies as they fall and starts a convo when they are all gone (group on death).


This is the route I went. I have the exact same scenario early on in my module. The companion is level 1 and easily killed, so it makes sense to set their plot flag to TRUE and commence with the fight. 

I then use an OnDeath script for the group. When they are all dead, the conversation starts. 

#9
Tchos

Tchos
  • Members
  • 5 042 messages
This is a situation where it would be appropriate to use an Ipoint Speaker. You can just spawn one when combat begins, and let it do its job.

The job of an ipoint speaker is to sit there quietly and check every 6 seconds to see if the PC is still in combat. If so, do nothing. If combat is over, then check to see if the PC is currently able to speak (maybe the PC was paralysed or something during the combat). If necessary, it will remove those effects. When combat has ended and both the PC and the intended conversation NPC are able to speak, it begins the conversation and destroys itself.

The default ipoint speaker script has a lot of failsafes built in, but you'll probably want to create a special script for your purpose. You can create one that handles the enemy count as well, or does other tasks while waiting for the conversation to begin.

#10
andysks

andysks
  • Members
  • 1 645 messages
So Tchos, this is what you meant on another thread that the ipoint speaker has quite special functions? A normal ipoint would not do it? I will try this version as well.
I think Kaldor's script didn't work because I had a deathscript hooked on the creature's variables. So maybe it ignored the other one.

#11
Tchos

Tchos
  • Members
  • 5 042 messages
An ipoint speaker is a normal ipoint, but with a heartbeat script attached that performs the tasks I describe. To use it correctly, you must spawn it using the CreateIPSpeaker() function, which is in the ginc_ipspeaker include file. That will ensure that it deletes itself after it's finished. It has all of the parameters you need: namely, SpeakerTag and Conversation, though you must also provide a location (which can be the location of the PC).

Also, if you're using a module load script that includes this line:

// set up custom ipspeaker script
SetGlobalString(CAMPAIGN_STRING_CUSTOM_IPSPEAKER , "ka_get_party_leader");

Then you must make sure you have that script installed. I copied it from one of the official campaign folders (I don't remember which). Otherwise, the IP Speaker will not work. It might work if that line is simply not there, or commented out, but I'm not sure.

#12
PJ156

PJ156
  • Members
  • 2 982 messages
It's untidy I know but I leave ipoint speakers in game rather than spawning them. For me, each layer of scripting is another bit than can go wrong and cause frustration in testing.

I know its another heatbeat script to run but my machine seems butch enough for the task.

The slight downside to an ipoint is that every node must be assigned a person or the ipoint takes it. That may not be an issue if you are using cameras, but it can cause some odd looking graphics if you don't remember this.

PJ

#13
Tchos

Tchos
  • Members
  • 5 042 messages
You don't need to assign nodes to characters if you use the special function. The ipoint speaker will command the intended NPC to begin the conversation, not begin the conversation with the ipoint.

#14
PJ156

PJ156
  • Members
  • 2 982 messages
That's interesting. I have always given the converation to the ipoint and used the start convo script with self. That fires the conversation associated with the ipoint but make the ipoint the owner.

You're saying that, if I use the function, the ipoint will project the called conversation to the npc of my choice and they will own the conversation, therefore unnassigned nodes will be owned by the npc not the ipont? That does not make sense to me but my understanding of the way the toolset works is not good so that is no surprise :(

PJ

#15
Tchos

Tchos
  • Members
  • 5 042 messages
That is how it works. The ipoint speaker's script *assigns* the command to begin the conversation to the NPC that you tell it should be the speaker, so that NPC is the owner. The ipoint just makes sure it happens, without interference from the NPC's AI.

You must not have been using the ipoint speaker's built-in heartbeat script, because if you left them in the toolset from the beginning, it would perpetually be commanding the NPC to talk to the PC whenever the PC was not in combat. Or maybe it's because you didn't spawn it with the command, and so the necessary variables were not set on the created ipoint.

Note: when I say "ipoint speaker", I'm talking about the blueprint called "ipoint speaker", or any ipoint that was spawned with the CreateIpointSpeaker function.

Modifié par Tchos, 08 décembre 2013 - 11:03 .


#16
PJ156

PJ156
  • Members
  • 2 982 messages
Thank you, I will look into that with more care and see how I can imporve things.

I think I got away with the way I do it now because I treat the ipont as a virtual npc. It have the conversation applied to it as i might a placeable. When the time comes I generaly fire the command to start the convo off a trigger. So in many ways I am simply treating it as a placeable.

I need to do some more homework.

PJ

#17
Tchos

Tchos
  • Members
  • 5 042 messages
So, if you're actually commanding the ipoint to start the conversation, then you're not using its heartbeat script, and if you're using the actual ipoint speaker blueprint, then that means its heartbeat is always running and never gets used, because the variables it's looking for are never assigned to it, which is what the function does when it creates it. You could just use a generic ipoint instead, if you want to start the conversation manually.

Instead of starting the conversation with the trigger, make the trigger spawn the ipoint. You only want to spawn the ipoint when you want it to start trying to force the NPC to start the conversation, because once it exists, it will keep trying until it succeeds. I suggested spawning it at the beginning of the combat instead of at the end, because once it detects that combat has ended, it'll force the NPC to start the conversation.

#18
andysks

andysks
  • Members
  • 1 645 messages

PJ156 wrote...

Thank you, I will look into that with more care and see how I can imporve things.

I think I got away with the way I do it now because I treat the ipont as a virtual npc. It have the conversation applied to it as i might a placeable. When the time comes I generaly fire the command to start the convo off a trigger. So in many ways I am simply treating it as a placeable.

I need to do some more homework.

PJ


I do the same but with a normal ipoint. The only downside is that I have to assign speakers. I normally have an NPC owner though. The ipoint I use only when the "owner" needs to go in battle, or other things that might break a convo.

#19
andysks

andysks
  • Members
  • 1 645 messages
I spent some time reading on the OC. In the beginning I searched through Tavoric's Estate for clues, but didn't find anything. As I was going through some scripts, I found the gg_death_talk.
The gg_death_talk, has included the ginc_ipspeaker and ginc_group. Opened them as well. I will try to explain what I understood, and please correct me if anything is wrong :). Plus, I never thought a group death would be so "complicated" to achieve.
These are I think the important comments for usage of this thing.

ginc_group states at one point:
 add creatures to your group using the functions under the label *** Group creation ***

gg_death_talk comment reads as:
Creates an IPoint Speaker when all group members have been killed to begin a conversation.

ginc_ipspeaker:
The IPSpeaker is created and monitors the start of a conversation.

So, I get too little from all this, and I am also not certain how much better or less or more complicated this method is compared to previous stated in this thread... but hey, why not discuss it :wizard:.

What I understood here, is that a "group", is a faction. For example, if I create a faction named "hobs" for some hobgoblins, all creatures using this faction belong to this group. If they are just these 15, on this area, and the party kills them all, then GroupOnDeathBeginConversation is called and spawns an ipspeaker, which handles the speaker, convo and of course the group that died.

Assuming I undestood all this fine, there is a slight problem. The scripts don't state how to actually use them. Normally they say, put this OnDeath, or this is used with variables set on the creature and so on. These ones nothing.
Is it gg_dath_talk a user defines, as I used other specific damage and death scripts from this slot?
Or is it a deathscript variable on every creature of the specific group? Or simply an OnDeath event?

#20
kevL

kevL
  • Members
  • 4 056 messages
'gg_death_talk' looks like an onDeath script,


some notes ( disclaimer: 1st coffee )

try not to use GroupOnDeathBeginConversation, because it's shakey (don't know why). GroupOnDeathExecuteCustomScript is good.

Assign the enemy to a group, anywhere you like*. ( ps. It's a "group" not a "faction" which is something different.. )

use GroupOnDeathExecuteCustomScript script to
- ClearAllActions(TRUE) for all concerned.
- perhaps Jump the necessary parties together before the dialog starts.
- Make them conversable
- AssignCommand(... ActionStartConversation(...))

- or CreateIPSpeaker**



* am pretty sure they must exist IG
** which i believe does all that stuff

/1st coffee

Modifié par kevL, 08 décembre 2013 - 05:05 .


#21
Tchos

Tchos
  • Members
  • 5 042 messages

andysks wrote...
So, I get too little from all this, and I am also not certain how much better or less or more complicated this method is compared to previous stated in this thread... but hey, why not discuss it

It is both more and less complicated.  Like my quest scripts, they do a lot of complicated things behind the scenes so that you can lay it on and forget it.  To use an ipoint speaker, all you have to do is spawn it with the function, passing it the name of the intended speaking NPC and the name of the conversation.  That's all!  It does everything else automatically -- starting the conversation, finding out who the PC party leader is, doing all of the checks and failsafes, making the NPC walk to you, trying again if something interrupts the conversation, and destroying itself.

The only thing about them is that you have to actually put the function into a script, because there aren't any prepared on_death scripts or ga_ scripts that use it.

The "group" scripts work by setting global variables (again, behind the scenes, so that the user doesn't have to worry about it) with the names of groups and a list of their members.  Then you use other group scripts to access those lists and see who's in a group, add/delete members of a group, do something when they're all dead, etc.

#22
andysks

andysks
  • Members
  • 1 645 messages
I am afraid this ipoint speaker and group assets of the toolset and scripting are completely out of my league. So I will have to try PJ's first suggestions or try Lugaid's script one more time. It's interesting though, when I opened the Tavorik's estate in the toolset, no matter how much I searched, I couldn't find how they started the convo after the battle.

#23
kevL

kevL
  • Members
  • 4 056 messages
the script '20_ballard_downstairs' and its #include '20_inc_cyran'

fired from Ballard's dialog '20_ballard_downstairs', which is fired up from the onClientEnter event '2080_cliententer'


module 2000_Neverwinter, area 2080cyrandownstairs


If you look at case 1: and refer to the include you see SpawnCreatureTypeForWave() adds to the group, and they used GroupOnDeathBeginConversation()

(perhaps it's a lot more complicated there than it needs to be)

#24
andysks

andysks
  • Members
  • 1 645 messages
Many things in the OC are, but hey, they made the game so... :). Like in the same area, imps and succubi are placed, and I guess scripthidden in the beginning, while this wasn't necessary.

#25
Dann-J

Dann-J
  • Members
  • 3 161 messages
I find myself using the functions in ginc_group a lot these days. There are some handy functions in there to keep track of how many in a group are dead (or if they simply all are). All you have to do is get creatures into a group to start with.

I use two main methods to achieve that. I either give the creature blueprints or placed creatures OnSpawn scripts that add them to a group based on a local string stored of them, or I spawn an encounter and use EncounterToGroup(). The advantage of the encounter method is that it scales with the player, plus you get to randomise it so you never know exactly what number or mixture you'll get.

Another method is to give the creatures a custom faction, and use FactionToGroup(). I'm reluctant to create too many custom factions though, as the relationships between them can become complicated to keep up with.

At the start of Shaar Moan there is an optional fight, which triggers a conversation when they're all dead. I'm pretty sure I used the functions in ginc_group for that.

Modifié par DannJ, 09 décembre 2013 - 04:29 .