Gestalt Cutscene Scripting question(s)

Hi all,

I’ve been trying to learn the ropes for the Gestalt Cutscene Scripting system by using the tutorial, etc.). I’ve come across a couple of issues (like wonky timing problems with fade to and from black, etc. - as others have previously pointed out).

My main issue is this: when engaging “cutscene mode”, I can still scroll the camera in and out with the mouse wheel. Particularly when including camera coordinates/parameters, it causes a “jitter” like I’m wrestling with the scripted camera. In other words, the player’s control of camera does not seem fully locked and seems like it can still be “wrestled with” - not making for a very good cutscene.

Any tips on how to resolve this issue? I’m still in the learning phase just sticking to the basic script examples in the tutorial - nothing fancy - yet I’m still encountering this problem.

I know GCS was developed mainly for NWN1, so maybe there is an issue there? I would open the example module he included, but it’s for NWN and not NWN2).

Should I give up on using this third-party tool and just stick to the native NWN2 cutscene functions to avoid weird issues? Any other tips to make this work well in NWN2? Help!

Just a question: Do you use the NWN1 style of conversation for the cutscene? 'Cause if you use the NWN2 cinematic dialogue you have full control of the camera (at least I’m fairly certain of that).

Hey andgalf, the current GCS cutscene I created doesn’t trigger any conversation file (and thus no style of dialogue per se). The only spoken lines are included as text strings in the script. I’ve used the NWN2-style dialogue to create cutscenes elsewhere, and it works pretty well.

Do you suggest I stick to that feature & those functions and just avoid GCS altogether for NWN2 modding? Does it allow for pretty much all of the same functionality & results as GCS? Is there a hybrid solution using both or would that be uneccessarily complicated?

For my work, I use NWN2 dialog style for cutscene and real dialog.

I use NWN1 dialog style for events, actions on placeables, choice on devices, area transitions and probably a little more.

1 Like

Those are great tips, Shallina - thank you! That overall approach makes sense and I’ll use it moving forward (so bye bye to GCS for me).

Can you elaborate on what using NWN1 dialog style for “events” means precisely?

I understand the use in terms of placeables, choice selections, area transitions - but unclear on what you mean by “event” in this context.

Mostly something that require a choice from the player, but isn’t a “conversation with someone” but rather an intereaction with something.

But for complexe cutscene with NPC and so on, I always use NWN2 style.

To make it simple my approach is :

“someone” = NWN2 style
“something” = NWN1 style

2 Likes

I’ve never seen this GCS system in action, so to speak, so I don’t know exactly what it does (only read some of what it does on the vault here) so I’m not sure if the NWN2 style dialogue would cover for everything.

In my own case, I mix a bit of NWN1 and NWN2 dialogue. I prefer NWN2 dialogue since I like the cinematic style very much, so with companion dialogue I tend to use NWN2 style, and when speaking to certain NPCs to get smaller quests I often use the NWN1 style. If I really want a cutscene (I’ve never done that much advanced stuff) I mostly use NWN2 style. Since you can do a lot with static cameras, it’s a great way of making sure the player looks in the right places. I think you can actually do quite a lot with NWN2 style dialogue cutscenes. I’ve played many modules in the past where I’ve seen pretty advanced stuff happening…

EDIT: Here’s a NWN2 style cutscene made in Baldur’s Gate 2: Shadows of Amn Reloaded that looks pretty advanced (don’t know who made it exactly or how it was scripted, but maybe you get an idea of what this style can do):

1 Like

That’s the mod I am working on, Drew Rechner made most of that cutscene, and a wonderfull cutscene framework that I use a lot, I did some work on it as well, mainly on how it connects to the game. Drew is the cutscene specialist :slight_smile: of our team.

2 Likes

Alright then. @aeliop - Then @Shallina will be able to help you if have any questions about how it’s done. I could never do anything as advanced as this, I believe, and I don’t know if GCS does things like this.

EDIT: I would actually be interested in the framework you’re talking about @Shallina , if you are willing to share, that is. I would guess it’s still too advanced for me. :slightly_smiling_face:

EDIT2: @Tsongo - I doubt there are any tiny kobolds involved in this framework, but it would surely be cooler if it was, right? :wink:

@andgalf @Shallina - thanks for this great info & methodology. Really helpful! I’ll definitely loop back on this forum as more questions invariably come up.

The SOAR cutscene is excellent by the way, I too would be curious to hear more about the framework though I’m sure it’s above my head currently. Cheers and well wishes for 2022.

1 Like

That framework use the “rewritten” library I did from NWN2 and many little usefull functions I did, It would require a big directory upload with many check on depedencies for it to be functionnal, it’s completly tied to our campaign. But I can I can give you the core as exemple :


//dmr081520: Various things to assist with making cutscenes

void playAnimation(object oTarget, string sAnim, int nLoop=FALSE)
{
	PlayCustomAnimation(oTarget, sAnim, nLoop);
}

float conjureAnimDelay()
{
	return 1.1;
}

float castAnimDelay()
{
	return 2.1;
}

float castDelay()	//Delay before the projectile is spawned
{
	return 0.7;
}

int vfx_teleport()
{
	return 1059;
}	

int vfx_bloodspurt()
{
	return 1060;
}

int vfx_abjuration_conjure()
{
	return 1061;
}

int vfx_abjuration_cast()
{
	return 1062;
}

int vfx_sonic_conjure()
{
	return 1063;
}

int vfx_sonic_cast()
{
	return 1064;
}

int vfx_wailofbanshee()
{
	return 1065;
}

int vfx_evocation_conjure()
{
	return 1066;
}

int vfx_evocation_cast()
{
	return 1067;
}

int vfx_evocation_aoe()
{
	return 1068;
}

int vfx_transmutation_conjure()
{
	return 1069;
}

int vfx_transmutation_cast()
{
	return 1070;
}

int vfx_fire_conjure()
{
	return 1071;
}

int vfx_fire_cast()
{
	return 1072;
}

int vfx_fire_aoe()
{
	return 1073;
}

int vfx_cacophonicburst()
{
	return 1074;
}

int vfx_ice_aoe()
{
	return 1075;
}

int vfx_lightning_conjure()
{
	return 1076;
}

int vfx_lightning_cast()
{
	return 1077;
}

int vfx_fire_hit()
{
	return 1078;
}

int vfx_sonic_hit()
{
	return 1079;
}

int vfx_acid_hit()
{
	return 1080;
}

int vfx_necromancy_conjure()
{
	return 1081;
}

int vfx_necromany_cast()
{
	return 1082;
}

int vfx_meteorswarm_impact()
{
	return 1083;
}

int vfx_enchantment_conjure()
{
	return 1084;
}

int vfx_enchantment_cast()
{
	return 1085;
}

int vfx_stone_explosion()
{
	return 1086;
}

int vfx_screenshake_short()
{
	return 1087;
}

int vfx_magicmissile_impact()
{
	return 1088;
}

int vfx_conjuration_conjure()
{
	return 1089;
}

int vfx_conjuration_cast()
{
	return 1090;
}

int vfx_glacialwrath_effect()
{
	return 1091;
}

int vfx_stoneskin_effect()
{
	return 1092;
}

int vfx_glacialwrath_cone()
{
	return 1093;
}

int vfx_ambient_fade()
{
	return 1096;
}

The Idea is to have all the animations and timers/delay associated with them so you won’ t have to manually put the right number each time.

#include "fct_cutscene_anim"
#include "fct_soarscript"

void main()
{
	object oIrenicus = GetObjectByTag("csiren");
	object oImoen = GetObjectByTag("csimoen");
	object oCowled1 = GetObjectByTag("ccowled1");
	object oCowled2 = GetObjectByTag("ccowled2");
	object oCowled3 = GetObjectByTag("ccowled3");
	object oCowled4 = GetObjectByTag("ccowled4");
	location lIrenicus = GetLocation(oIrenicus);
	location lImoen = GetLocation(oImoen);
	location lCowled1 = GetLocation(oCowled1);
	location lCowled2 = GetLocation(oCowled2);
	location lCowled3 = GetLocation(oCowled3);
	location lCowled4 = GetLocation(oCowled4);
	float fAnimBuffer = 0.5;
	effect eAbjConjure = EffectVisualEffect(vfx_abjuration_conjure());
	effect eAbjCast = EffectVisualEffect(vfx_abjuration_cast());
	effect eConConjure = EffectVisualEffect(vfx_conjuration_conjure());
	effect eConCast = EffectVisualEffect(vfx_conjuration_cast());
	effect eLigConjure = EffectVisualEffect(vfx_lightning_conjure());
	effect eLigCast = EffectVisualEffect(vfx_lightning_cast());
	effect eTraConjure = EffectVisualEffect(vfx_transmutation_conjure());
	effect eTraCast = EffectVisualEffect(vfx_transmutation_cast());
	
	/*****************************************************************/
	
	//IRENICUS begins to cast Wail of the Banshee
	object oBansheeTarget = GetWaypointByTag("wp_BansheeTarget");
	location lBansheeTarget = GetLocation(oBansheeTarget);
	effect eConjure = EffectVisualEffect(vfx_sonic_conjure());
	effect eCast = EffectVisualEffect(vfx_sonic_cast());
	object oSFXBanshee = GetObjectByTag("sound_cutscene_banshee");
	
	playAnimation(oIrenicus, "mjr_conjure", FALSE);
	ApplyEffectToObject(DURATION_TYPE_INSTANT, eConjure, oIrenicus);
	DelayCommand(conjureAnimDelay(), playAnimation(oIrenicus, "mjr_cast", FALSE));
	DelayCommand(conjureAnimDelay(), ApplyEffectToObject(DURATION_TYPE_INSTANT, eCast, oIrenicus));
	DelayCommand(conjureAnimDelay() + castDelay(), SpawnSpellProjectile(oIrenicus, oBansheeTarget, lIrenicus, lBansheeTarget, SPELL_WAIL_OF_THE_BANSHEE, PROJECTILE_PATH_TYPE_HIGH_BALLISTIC));
	DelayCommand(conjureAnimDelay() + castDelay(), SoundObjectPlay(oSFXBanshee));
	DelayCommand(conjureAnimDelay() + castAnimDelay(), playAnimation(oIrenicus, "idleM", TRUE));
	
	/*****************************************************************/
	
	//COWLED 1 and 4 are killed by Wail of the Banshee
	float fDelay = GetProjectileTravelTime(lIrenicus, lBansheeTarget, PROJECTILE_PATH_TYPE_HIGH_BALLISTIC, SPELL_WAIL_OF_THE_BANSHEE);
	fDelay = fDelay + conjureAnimDelay() + castDelay();
	effect eProjHit = EffectVisualEffect(VFX_HIT_SPELL_WAIL_OF_THE_BANSHEE);
	effect eImpact = EffectVisualEffect(VFX_HIT_SPELL_NECROMANCY);
	effect eDeath = EffectDeath(FALSE, FALSE, TRUE, FALSE);
	
	DelayCommand(fDelay, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eProjHit, lBansheeTarget));
	fDelay = fDelay + 0.5;
	DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oCowled1));
	DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oCowled4));
	DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oCowled1));
	DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oCowled4));
	
	/*****************************************************************/
	
	//COWLED1 play animations to being combat
	float fDelayC1 = 0.8;
	
	DelayCommand(fDelayC1, playAnimation(oCowled1, "idleM", TRUE));
	fDelayC1 = fDelayC1 + fAnimBuffer;
	DelayCommand(fDelayC1, playAnimation(oCowled1, "def_conjure"));
	DelayCommand(fDelayC1, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eAbjConjure, lCowled1));
	
	/*****************************************************************/
	
	//COWLED2 play animations to being combat
	float fDelayC2 = 2.0;
	
	DelayCommand(fDelayC2, playAnimation(oCowled2, "idleM", TRUE));
	fDelayC2 = fDelayC2 + fAnimBuffer;
	DelayCommand(fDelayC2, playAnimation(oCowled2, "atk_conjure"));
	DelayCommand(fDelayC2, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eTraConjure, lCowled2));
	fDelayC2 = fDelayC2 + conjureAnimDelay();
	DelayCommand(fDelayC2, playAnimation(oCowled2, "atk_cast"));
	DelayCommand(fDelayC2, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eTraCast, lCowled2));
	
	/*****************************************************************/
	
	//COWLED3 play animations to being combat
	float fDelayC3 = 1.7;
	
	DelayCommand(fDelayC3, playAnimation(oCowled3, "idleM", TRUE));
	fDelayC3 = fDelayC3 + fAnimBuffer;
	DelayCommand(fDelayC3, playAnimation(oCowled3, "atk_conjure"));
	DelayCommand(fDelayC3, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eLigConjure, lCowled3));
	fDelayC3 = fDelayC3 + conjureAnimDelay();
	DelayCommand(fDelayC3, playAnimation(oCowled3, "atk_cast"));
	DelayCommand(fDelayC3, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eLigCast, lCowled3));
	
	/*****************************************************************/
	
	//COWLED4 play animations to being combat
	float fDelayC4 = 1.0;
	
	DelayCommand(fDelayC4, playAnimation(oCowled4, "idleM", TRUE));
	fDelayC4 = fDelayC4 + fAnimBuffer;
	DelayCommand(fDelayC4, playAnimation(oCowled4, "gen_conjure"));
	DelayCommand(fDelayC4, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eConConjure, lCowled4));
	
	/*****************************************************************/
	
	//IMOEN casts Orb of Sound at IRENICUS
	effect eOrbConjure = EffectVisualEffect(vfx_conjuration_conjure());
	effect eOrbCast = EffectVisualEffect(vfx_conjuration_cast());
	float fDelay2 = 2.0;
	
	DelayCommand(fDelay2, playAnimation(oImoen, "atk_conjure", FALSE));
	DelayCommand(fDelay2, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eOrbConjure, lImoen));
	fDelay2 = fDelay2 + conjureAnimDelay();
	DelayCommand(fDelay2, playAnimation(oImoen, "atk_cast", FALSE));
	DelayCommand(fDelay2, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eOrbCast, lImoen));
}

the approach we are using is of many scripts that are tied together with a conversation, where each line is an event of the cutscne with a static camera to shows it.

You don’ t do this in one go, you start to set the stage, then the first event, and so on. and you finish the last event and release/clean the stage.

And after, you come back at it to fix things that aren’t as you wish them to be or don 't behave as you want. It’s a lot of work. Also NWN2 tools aren’t that great for cutscenes when you compare them to dragon age origin for exemple. NWN2 is more powerfull for game events, but less powerfull for “visuals”.

For that mod we also have the luck to be 2 able to script, it allows “multiple pass” with ideas that complete each others.

4 Likes