Jump to content

How to trigger arbitrary cutscene scripts directly by spell effect


Recommended Posts

Normally there is no way to execute cutscene scripts directly by spell effect. You are either forced to summon an invisible helper creature or have to use variables in conjunction with a global script to initiate a cutscene. In both cases there is a small chance that scripting can be interrupted or delayed by external events.

However, opcode 298 allows you to execute the hardcoded cutscene script CUT250A.BCS. This effect is normally used to trigger the "Teleport to the Pocket Plane" cutscene in BG2-ToB, but it basically functions in all EE games (even in PST:EE). It is possible to hook into CUT250A.BCS and extend it to allow execution of arbitrary cutscene content. It only works in EE games however, since it makes use of the StartCutSceneEx() script action.

The actual scripting would look like this:

Spoiler

CUT250A.BCS (hardcoded cutscene script executed by opcode 298):

// Calls another cutscene script with activated trigger evaluation
IF
  True()
THEN
  RESPONSE #100
    CutSceneId(Player1)
    StartCutSceneEx("CUT250B",TRUE)
END

CUT250B.BCS (new script with the actual cutscene content):

// Ensures that the cutscene script is left in a valid state
IF
  True()
THEN
  RESPONSE #100
    CutSceneId(Player1)
    SetGlobal("CUT250","GLOBAL",0)
END

// Execution of the original "teleport to pocket plane" script
IF
  Global("CUT250","GLOBAL",0)
THEN
  RESPONSE #100
    CutSceneId(Player1)
    // ...
    EndCutSceneMode()
END

// Append custom scripting here:
// Each new cutscene should use a unique Global("CUT250","GLOBAL") value.
IF
  Global("CUT250","GLOBAL",1)
THEN
  RESPONSE #100
    CutSceneId(Player1)
    // ...custom cutscene content...
    EndCutSceneMode()
END

 

To make your own custom cutscene work you have to retrieve a free Global("CUT250","GLOBAL") value and use it in the cutscene, as shown above. Additionally you have to set the variable (e.g. via opcode 365) in the SPL, ITM or EFF resource along with opcode 298 to trigger the desired cutscene.

The attached zip archive contains a WeiDU library with a function that largely automates the process. All you need is to provide the cutscene script and a way to execute the spell effect.

This WeiDU example script for BGEE/BG2EE/EET adds a new ring ("myring.itm") to the game that can be used to trigger a cutscene without the use of helper creatures or global scripting:

Spoiler
BACKUP "weidu_external/backup/Cutscene-Example"
AUTHOR "Argent77"

BEGIN "Example: Cutscene triggered by spell effect"
REQUIRE_PREDICATE (GAME_IS "bgee bg2ee eet") "BGEE, BG2EE or EET required."

INCLUDE "%MOD_FOLDER%/lib/a7-cutscene_customization.tph"

// Our cutscene script.
// Trigger section can be empty if "CUT250" guard variable is the only condition.
<<<<<<<< .../inlined/cutscene.baf
IF
THEN
  RESPONSE #100
    CutSceneId(Player1)
    MoveViewObject(Myself,INSTANT)
    DisplayStringHead(Myself,~Cutscene triggered by a spell effect.~)
    Wait(4)
    EndCutSceneMode()
END
>>>>>>>>

// Installs the cutscene for use with opcode 298
LAF EXTEND_CUT250
  STR_VAR baf_file = ".../inlined/cutscene.baf"
  RET value  // can be used later to set the required global variable
END

// Cutscene is triggered by an item ability (reusing Sandthief's Ring)
COPY_EXISTING "ring05.itm" "override/myring.itm"
  SAY NAME2 "Cutscene Ring"
  SAY IDENTIFIED_DESC "Executes a cutscene when used."
  WRITE_SHORT 0x42 0 // remove Lore requirement

  // Discarding old effects
  LPF DELETE_SPELL_EFFECT INT_VAR opcode_to_delete = "-1" END

  // Setting required variable Global("CUT250","GLOBAL",%value%)
  LPF ADD_ITEM_EFFECT
    INT_VAR
      opcode = 265        // Modify global variable
      target = 1          // Self
      parameter1 = value  // Variable is set to the result of the EXTEND_CUT250 function
      timing = 9          // Instant/Permanent
    STR_VAR
      resource = "CUT250" // Variable name
  END

  // Adding cutscene trigger
  LPF ADD_ITEM_EFFECT
    INT_VAR
      opcode = 298        // Pocket Plane
      target = 1          // Self
      timing = 1          // Instant/Permanent until death
  END

 

Note: This feature can potentially interfere with the return location from the Pocket Plane if it is used while the party is present in the Pocket Plane. That's why I recommend to use it only for events where the party is not currently present in the Pocket Plane. Otherwise, this issue can be worked around using script actions StorePartyLocations() and RestorePartyLocations() in place of the ExitPocketPlane() action.

a7-cutscene_customization-v1.zip

Edited by argent77
Added compatibility note
Link to comment

Very interesting!

I would recommend creating, or if it already exists appending to, a simple .2DA table that lists which values have already been used for the ("CUT250","GLOBAL") variable. In fact it would probably make sense to write a little function that either creates this .2DA file or finds the next unused value for the variable. That way any number of mods could do this and they would not get in each others' way.

Link to comment
On 4/18/2023 at 7:01 PM, argent77 said:

CUT250A.BCS (hardcoded cutscene script executed by opcode 298):

// Calls another cutscene script with activated trigger evaluation
IF
  True()
THEN
  RESPONSE #100
    CutSceneId(Player1)
    StartCutSceneEx("CUT250B",TRUE)
END

StartCutSceneMode() is also included there right? I'm wondering if I can execute with this script without entering cutscene mode.

Link to comment
1 hour ago, marchitek said:

One more question from my side. Browsing IESDP I came up on ExitPocketPlane action. Is it somehow interfere with this solution?

Yes, that can indeed interfere if a cutscene is triggered this way inside the Pocket Plane itself. I have added a note about it to the opening post.

The issue can be worked around by using the StorePartyLocations()/RestorePartyLocations(), but that's not completely foolproof either. It's best to limit this feature to events that don't happen inside the Pocket Plane.

Link to comment

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...