Jump to content

Cutscenes


Bardess

Recommended Posts

Sim's scripting guide features a short section that deals with cutscenes, then simply look at any cutscene scripts already in the game (CUT*.bcs). They shouldn't be too hard to understand but if you're having trouble with something specific I'd be glad to help. Writing a tutorial on something like cutscenes is hard, there are hundreds of things you can do so the best way to learn is by example.

Link to comment

I'm looking at them and trying to write something, but it will be hard to test... Now I have to add a new area where it happens and am currently stuck again.

 

Um, how do I make the party go to a new area? ;)

Link to comment

And remember, if you are going to do a CutSceneId(Player1), all Player1 actions should be without ActionOverride, or they won't work.

 

That is, JumpToPoint([12.13]), not ActionOverride(Player1,JumpToPoint([12.13]))

 

(*Everybody* makes this mistake. Self included).

 

I usually pick and copy game cutscenes using Infinity Explorer.

Link to comment

By the time I've reformatted this, I'm going to regret posting it.....

 

Cutscene Scripts By Max a.k.a Potencius

 

(Tutorial tidied up by Yovaneth).

 

Preface

 

Cutscene scripts are what you see in the game when the screen becomes unclickable. During cutscenes, characters and items can perform actions without fear of interruption by the player. This is just a general overview and covers some things that might give you trouble.

 

How a Cutscene is Built

 

The following is the general shape that a cutscene takes. It involves two or more scripts. The first script will always have the following actions at the end that initiate the REAL cutscene.

 

IF
 <CutsceneTriggers()> 
THEN
 RESPONSE#100 
ClearAllActions() 			// See Note #1 
StartCutSceneMode() 		// See Note #2 
StartCutScene("SCRIPT") 		// See Note #3 
END

 

Note 1. This is optional but recommended. It makes sure that actions being done by characters or creatures are cancelled before the cutscene starts.

Note 2. This action removes the game GUI and so makes the screen unclickable by the player.

Note 3. This action references the script which actually performs the cutscene actions.

 

This is the the general format of the script which actually performs the cutscene actions.

 

IF 
 True() 					// See Note #4 
THEN 
 RESPONSE#100 
CutSceneID(<Object>) 		// See Note #5 
<CutsceneActionsHere()> 
EndCutSceneMode() 			// See Note #6 
END

 

Note 4. This trigger is always True(). Anything else is ignored and treated as if it were the trigger True().

Note 5.This action must be specified at the beginning of a cutscene script. It signifies who is performing the actions that follow it.

Note 6. This ends the cutscene and replaces the game GUI on screen.

 

 

Actions

 

Actions in cutscene scripts can appear to be illogical in how they work. I'll try to explain as best I can.

 

First, I'll go over the most frequently used nesting action in cutscene scripts, ActionOverride(). ActionOverride() specifies an actor and tells that actor to perform an action. So, a cutscene script might look like this.

 

IF 
 True() 
THEN 
 RESPONSE#100 
CutSceneID(Player1) 
ActionOverride("TROLL",Kill(Myself)) // See Note #7 
EndCutSceneMode() 
END

 

Note 7. This action has Player1 (the one in control of the cutscene) tell "TROLL" to kill himself.

 

Now, ActionOverride() can also be a bad thing to use. For example, the PlayDead() action is one that you don't want to use in conjunction with ActionOverride(). Here's why:

 

IF 
 True() 
THEN 
 RESPONSE#100 
CutSceneID(Player1) 
ActionOverride("TROLL",PlayDead(180)) // See Note #8 
MoveToObject("TROLL") 			// See Note #8 
END

 

Note 8. In this script, right after Player1 tells "TROLL" to play dead, he should move to "TROLL." However, he does not. With this combination, Player1 will only move to "TROLL" after the PlayDead() action is completed. This is because Player1 must control both the actions of "TROLL" and himself.

 

So you ask how to fix this? It's really pretty simple. Multiple CutSceneID() IF-THEN statements. Here's how it would look...

 

IF 
 True() 
THEN 
 RESPONSE#100 
CutSceneID("TROLL") 
PlayDead(180) 
END 

IF 
 True() 
THEN 
 RESPONSE#100 
CutSceneID(Player1) 
MoveToObject("TROLL") 
END

 

This combination of statements make "TROLL" play dead while Player1 moves to him at the same time. It works by assigning the first part of the cutscene to TROLL and then reassigning the cutscene to Player1.

 

 

Example

 

Okay, now let's get down to it. Here's where we make a quick cutscene script that transports your party to a given area.

 

Here is what we want as a final result. We want to warp to an area without interruption. The screen will fade to black, and all the players will be warped to the area simultaneously. If it is not simultaneous, then the cutscene will not work properly. Once there, the screen will fade from black back to normal.

 

So, here we go...

 

First, we need a statement that will begin the cutscene script. This should be placed in something like an area script, a creature script, or whatever. As long as the right conditions are met, it should work.

 

IF 
 Trigger() 
THEN 
 RESPONSE#100 
ClearAllActions() 
StartCutSceneMode() 
StartCutScene("CUTMOVE") 
END

 

Here's the second script. This performs the area movement. Once it is done, compile it as CUTMOVE.bcs (for the example). In here, I'm allowing you to pick your own area, coordinates, and facing direction. So find an area and pick some random coordinates if you don't have a lot of time.

 

IF 
 True() 
THEN 
 RESPONSE#100 
CutSceneID(Player1) 
FadeToColor([20.0],0) // fades to black 
Wait(2) 					// See Note #9 
LeaveAreaLUA("AREA","",[x.y],FACE) 	// See Note #10 
Wait(2) 
FadeFromColor([20.0],0) 
Wait(2) 
EndCutSceneMode() 
END 

IF 
 True() 
THEN 
 RESPONSE#100 
CutSceneID(Player2) 
Wait(2) 
LeaveAreaLUA("AREA","",[x.y],FACE) 
END 

IF 
 True() 
THEN 
 RESPONSE#100 
CutSceneID(Player3) 
Wait(2) 
LeaveAreaLUA("AREA","",[x.y],FACE) 
END 

IF 
 True() 
THEN 
 RESPONSE#100 
CutSceneID(Player4) 
Wait(2) 
LeaveAreaLUA("AREA","",[x.y],FACE) 
END 

IF 
 True() 
THEN 
 RESPONSE#100 
CutSceneID(Player5) 
Wait(2) 
LeaveAreaLUA("AREA","",[x.y],FACE) 
END 

IF 
 True() 
THEN 
 RESPONSE#100 
CutSceneID(Player6) 
Wait(2) 
LeaveAreaLUA("AREA","",[x.y],FACE) 
END

 

Note 9. Wait() is used here for a few seconds to allow the screen to fade to black (that action takes about second, so we give two just to make sure).

 

Note 10. I'll just explain the parameters of this action:-

"AREA" = The area's filename that you are moving to.

 

"" = This actually controls which picture (parchment or mosiac, depending on the game) pops up on the loading screen. If you don’t supply a parameter specifying a picture, the choice is made randomly by the game engine.

 

[x.y] = The X and Y coordinates of the point the character is warping to on the new map.

 

FACE = This is a numerical value from 0 to 15. 0 faces south and the other numbers are ordered in a clockwise direction.

 

GENERAL NOTE: Now, you'll notice that all the main actions are put in Player1's statement. This is because Player1 is always in the game and a few of the actions don't need to be performed twice.

Link to comment

In the last piece of code above, I'd rather have all actions in one block (just to make the script a bit shorter) ie

IF

True()

THEN

RESPONSE#100

CutSceneID(Player1)

FadeToColor([20.0],0)

Wait(2) // See Note #1

ActionOverride(Player2,LeaveAreaLUA("AREA","",[x.y],FACE))

ActionOverride(Player3,LeaveAreaLUA("AREA","",[x.y],FACE))

ActionOverride(Player4,LeaveAreaLUA("AREA","",[x.y],FACE))

ActionOverride(Player5,LeaveAreaLUA("AREA","",[x.y],FACE))

ActionOverride(Player6,LeaveAreaLUA("AREA","",[x.y],FACE))

Wait(1) // See Note #2

LeaveAreaLUA("AREA","",[x.y],FACE)

Wait(2)

FadeFromColor([20.0],0)

Wait(2) // See Note #1

EndCutSceneMode()

END

 

Note 1. (just for the sake of accuracy) Actually, Wait(1) gives enough time for FadeToColor()/FadeFromColor() to complete

Note 2. I doubt this Wait() is truly needed, rather a better-safe-than-sorry thing (actually, I usually put SmallWait(3) here; not that it's very important, though)

 

And remember, if you are going to do a CutSceneId(Player1), all Player1 actions should be without ActionOverride, or they won't work.

 

That is, JumpToPoint([12.13]), not ActionOverride(Player1,JumpToPoint([12.13]))

Are you sure that it won't work with ActionOverride() here, Kulyok?

I've never tested it, but ActionOverride() mustn't affect anything in this case, logically speaking (being totally useless though, sure enough)

I usually pick and copy game cutscenes using Infinity Explorer
I doubt that Infinity Explorer window allows you to copy-paste scripts. Or is there a newer version of Infinity Explorer (mine is 1.80, if I'm not mistaken)?
Link to comment
In the last piece of code above, I'd rather have all actions in one block (just to make the script a bit shorter) ie

 

Whichever one works. I had instances when one or another was working (ie spell effects worked with separate blocks for Player1 throughg PLayer 6, and the LUA - with the Override's single block. Go figure, but then again, I mod IWD2, so I suppose, I deserve my fine wtf moments.

Link to comment

Eek! Something went wrong. I was testing my quest and in the cutscene, when the NPC needs to say something, he starts a lovetalk. ;) Can you tell me a good way to avoid this? WEIGHT? Something else? ;)

Maybe I should include a list of my quest's GLOBALs that can't be true in every lovetalk? That's a lot of globals. ;)

Link to comment

If you're using one quest variable throughout, and one lovetalk variable throughout, and one cutscene dialogue variable, you should be fine.

 

Example:

 

Global("Z_Quest","GLOBAL",0) = quest not started

...1 = timer started

...2 = trigger for first quest dialogue

...3 = closed during first dialogue, timer set during same dialogue

...4 = trigger for second quest dialogue

...5 = closed during second dialogue, timer set during same dialogue

 

Ditto with the lovetalks, but for that, you'd use Global("Z_Love","GLOBAL",#)

 

The cutscenes are a little trickier. You set the global up before the cutscene, then use it to trigger the after-cutscene dialogue.

 

CHAIN ~Z_FiarsJ~ BeforeCutscene
~Now we do this really cool cutscene.~
DO ~SetGlobal("Z_Cut","GLOBAL",1) ClearAllActions() StartCutSceneMode() StartCutScene("CutScrip")~
EXIT

 

Then, you do your cutscene, with the filename CutScrip.baf.

IF
True()
THEN
RESPONSE #100
CutsceneID(Player1)
Actions
ActionOverride("Z_Fiars",StartDialogueNoSet(Player1))
END

 

And your dialogue:

CHAIN
IF ~Global("Z_Cut","GLOBAL",1)~ THEN ~Z_FiarsJ~ AfterCutscene
~So, wasn't that a cool cutscene?~
DO ~SetGlobal("Z_Cut","GLOBAL",2)~
END
++ ~Hells, yeah!~ EXIT
++ ~Whatever.~ EXIT

Link to comment

So, he has to say something before the cuscene?

I'm afraid something will go wrong this way, too, because the prerequisites for the lovetalk (or worse, a banter??) are met independently from this quest talk ;)

Link to comment

No, you don't have to do it that way, but that's one way to do it. You could start it in the script, off a timer, or whatever, although I should probably point out that if the cutscene starts out of the blue, it will probably be quite surprising for the player.

 

Hang on, I think you lost me somewhere.

 

What all hinges on this cutscene? It sounds like you've got a lovetalk, a quest, and a banter all hanging on it.

 

Why don't you write out the sequence of what you want to happen. (no spoilers, if you want to avoid it)

Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...