Jump to content

Need help with REPLACE_TEXTUALLY


jastey

Recommended Posts

DECOMPILE_AND_PATCH with REPLACE_TEXTUALLY is a highly fragile thing, so I learned. Normally, I try to apply it and the patches are not applied. This time, I don't even get it to compile. The error message is

 

[bdcut65.bcs.BAF] ERROR at line 18 column 1-115
Near Text:
Failure("lexing: empty token")
ERROR: parsing [bdcut65.bcs.BAF]: Failure("lexing: empty token")
ERROR: [bdcut65.bcs] -> [override] Patching Failed (COPY) (Failure("lexing: empty token"))
Stopping installation because of error.

(bdcut65.bcs is a game script from SoD. So I don't even know whether it's an error on my side.)

 

I also tried to use the [%tab% %lnl%%mnl%%wnl%]+ thingie but this didn't compile with another error message about no matching group or similar error message.

 

 

This is my tp2-code currently. I would be very grateful if someone with more knowledge tells me how to specify this so it a) compiles and b) actually patches (SoD and EET, only).

/* Breagar is kicked in hell dimension - teleport to other areas */

COPY_EXISTING ~bdcut59b.bcs~ ~override~
  DECOMPILE_AND_PATCH BEGIN
REPLACE_TEXTUALLY ~\(ActionOverride("voghiln",Face(NW)) END\)~


~\1
IF
	Global("ACBreagar_kicked_bd4700","global",1)
	!Dead("ACBre")  
	!InParty("ACBre")  
THEN
	RESPONSE #100
		CutSceneId(Player1)
		MoveGlobal("bd4300","ACBre",[600.320])  
		ActionOverride("ACBre",Face(N))
END

IF
	Global("ACBreagar_kicked_bd4700","global",0)
	!Dead("ACBre")  
	!InParty("ACBre")  
THEN
	RESPONSE #100
		CutSceneId(Player1)
		MoveGlobal("bd4300","ACBre",[690.1254])  
		ActionOverride("ACBre",Face(NW))
END~
  END
BUT_ONLY_IF_IT_CHANGES


COPY_EXISTING ~bdcut58.bcs~ ~override~
  DECOMPILE_AND_PATCH BEGIN
REPLACE_TEXTUALLY ~\(ActionOverride("voghiln",Face(NE)) END\)~
~\1 \2

IF
	Global("ACBreagar_kicked_bd4700","global",1)
	!Dead("ACBre")  
	!InParty("ACBre")  
THEN
	RESPONSE #100
		CutSceneId(Player1)
		MoveGlobal("bd4400","ACBre",[1170.1240])  
		ActionOverride("ACBre",Face(NE))
END~
  END
BUT_ONLY_IF_IT_CHANGES

/* End of SoD - Breagar follows to abduction site */
COPY_EXISTING ~bdcut65.bcs~ ~override~
  DECOMPILE_AND_PATCH BEGIN
    REPLACE_TEXTUALLY ~\(DisableAI(Player6,TRUE)\)~
~\1 DisableAI("ACBre",TRUE)~

    REPLACE_TEXTUALLY ~\(ActionOverride(Player6,LeaveAreaLUA("bd6100","",\[470\.270\],SE))\)~
~\1 ActionOverride("ACBre",LeaveAreaLUA("bd6100","",\[480\.260\],SE))~

    REPLACE_TEXTUALLY ~\(ActionOverride(Player6,MoveToPoint(\[780\.765\]))\)~
~\1 ActionOverride("ACBre",MoveToPoint(\[770\.790\]))~

  END
BUT_ONLY_IF_IT_CHANGES

/* End of SoD - Abduction */

COPY_EXISTING ~bd6100.bcs~ ~override~
  DECOMPILE_AND_PATCH BEGIN
    REPLACE_TEXTUALLY ~\(ActionOverride(Player6,JumpToPoint([795.825]))\)~
~\1 ActionOverride("ACBre",JumpToPoint([760.800]))~

    REPLACE_TEXTUALLY ~\(ActionOverride(Player6,Face(SW))\)~
~\1 ActionOverride("ACBre",Face(SW))~

    REPLACE_TEXTUALLY ~\(ActionOverride(Player6,SetSequence(SEQ_SLEEP))\)~
~\1 ActionOverride("ACBre",SetSequence(SEQ_SLEEP))~

REPLACE_TEXTUALLY ~ApplySpellRES("bdfinal",Player6) Continue() END\)~
~\1 \2 \3 
IF
	Global("ACBreSoD_sleep","bd6100",0)
	StateCheck("ACBre",STATE_SLEEPING)
THEN
	RESPONSE #100
		SetGlobal("ACBreSoD_sleep","bd6100",1)
		ActionOverride("ACBre",MakeUnselectable(3600000))
		ApplySpellRES("bdfinal","ACBre")  // No such index
		Continue()
END

IF
	Global("ACBre_SoD_down","bd6100",0)
	OR(2)
		StateCheck("ACBre",STATE_REALLY_DEAD)
		TriggerOverride("ACBre",Global("bd_final","locals",1))
THEN
	RESPONSE #100
		SetGlobal("ACBre_SoD_down","bd6100",1)
		SetGlobalTimer("bd_sleep_timer","bd6100",THREE_MINUTES)
		Continue()
END
~

REPLACE_TEXTUALLY ~ApplySpellRES("bdsleep",Player6) END~
~\1 \2 

IF
	Global("bd_finale","bd6100",4)
	Global("ACBre_SoD_down","bd6100",0)
	!GlobalTimerNotExpired("bd_sleep_timer","bd6100")
THEN
	RESPONSE #100
		SetGlobalTimer("bd_sleep_timer","bd6100",THREE_MINUTES)
		ApplySpellRES("bdsleep","ACBre")  // No such index
END
~
  END
BUT_ONLY_IF_IT_CHANGES



May I also point out that making transitions of non-party members via cutscenes (that terminate themselves so there is no variable to work with for a mod NPC) is an evil thing to do of game developpers. Also, if someone solved this "move NPCs around in SoD" without having to patch cutscenes I am all ears.

Link to comment
May I also point out that making transitions of non-party members via cutscenes (that terminate themselves so there is no variable to work with for a mod NPC) is an evil thing to do of game developpers.

 

While I readily accept all the scorn I had earned with my sloppy scripting, I do feel the need to point out that SoD wasn't very "BGish" in terms of player's freedom, it had one too many "cinematic"-like railroading moments that the engine was never designed for.

That said, what do you mean about the lack of variable? You can just append the block to the area script, it should work the same.

Link to comment

 

May I also point out that making transitions of non-party members via cutscenes (that terminate themselves so there is no variable to work with for a mod NPC) is an evil thing to do of game developpers.

 

While I readily accept all the scorn I had earned with my sloppy scripting, I do feel the need to point out that SoD wasn't very "BGish" in terms of player's freedom, it had one too many "cinematic"-like railroading moments that the engine was never designed for.

That said, what do you mean about the lack of variable? You can just append the block to the area script, it should work the same.

 

I have coded my NPC to follow or not follow the PC through the journey of SoD. There was no need to tweak cutscenes nor was there a lack of variables to make the right things happen at the right time. So where is the problem?

A bit more detail of what is failing would help, a general *SoD bad coding* gives little clue.

Especially the BIG Global("bd_plot","global") that scripts most of SoD progress is quite helpful here.

Edited by Roxanne
Link to comment

I aplogize if my phrasing offended, they were much more drastic than I meant it.

 

I am convinced there is a better way to make NPC follow the events in SoD without tweaking cutscenes, just because I'm not the brightest candle if it comes to scripting and stuff. The cutscenes I tweaked above are for the NPC not being part of the group, therefore not being covered by Player2-Player6 general actions and my impression that the time for moving started with begin of the cutscene and ended with the cutscene (i.e. by a quest character initiating dialogue at the end on another area).

 

One example:

 

The first script blocks in bd6200.bcs moves the (canon) NPCs to the area bd6200.bcs. I EXTEND_TOP here with my NPC - that was easy enough.

Now, at the end of bd6200.bcs the last scriptblock lets the NPCs move inside the area to certain locations and then starts the cutscene bdcut64x.bcs. In my understanding of scripts and cutscenes, I have to patch this script block and can't just append with a block for a mod NPC. Am I wrong here? Do get both scripts be executed equally if conditions match?

 

bdcut64x.bcs circles through the canon NPCs and sets some variables about the size of the group etc., then calls cutscene bdcut65.bcs at its end.

 

bdcut65.bcs is the cutscene transporting the party to the abduction site. It starts with Player1 being the CutSceneID then following all the teleporting etc. and ends with Imoen initiating dialogue. Inbetween the area script gets set to something else (something SoD does a lot and which confuses me much - as interesting as it is to see that this is actually possible). All this happens for the same variable, the one in bd6200.bcs which triggered first the moving along the area and then the cutscenes. Giving me the impression there is no variable available that tells my mod's script block when to let the mod NPC walk along the area and when to start teleporting. Also, my impression was that I can't EXTEND_TOP to a cutscene and EXTEND_BOTTOM is out of the question here, leaving only patching in the "middle" as I attempted with REPLACE_TEXTUALLY.

 

Looking at it now I see that it might be just as good to EXTEND_TOP with a True() block having the mod NPC being the CutScebeID and doing all the teleporting etc there. But as I said, my knowledge about scripts and cutscenes is not very good, so this didn't occur to me as a possibility. Also, I lack motivation to optimize my mod's script blocks in a way that they match the game's cutscenes in a timely fashion, i.e. make the mod NPC move and teleport at the same time and not sooner or later. Having no trigger variables patching the cut scene directly is the only way I know of how to achieve this.

Link to comment

Just to understand your intention

- Braegar was forced leaving party when the murder is detected in Dragonspear Castle?

- he stays out of the picture during the trial, escape etc?

- when you escape via the waterfall and come out into the open (bd6200), your Braegar is not in the party?

- you make him instead wait with the canon group waiting there where Imoen leads you?

- still not joining, he is supposed to move with the party to the south?

- the hidden transition to bd6100 takes place and he is supposed to be there as well?

- the party is ambushed overwhelmed and kidnapped - Braegar with them to awake in Irenicus Dungeon?

Link to comment

So basically, you want to add a "canon" character, not just a regular joinable. Yes, that indeed is more problematic because of some "cinematic" scenes like in the ending.

 

Now, at the end of bd6200.bcs the last scriptblock lets the NPCs move inside the area to certain locations and then starts the cutscene bdcut64x.bcs. In my understanding of scripts and cutscenes, I have to patch this script block and can't just append with a block for a mod NPC. Am I wrong here? Do get both scripts be executed equally if conditions match?

 

For the movement part itself, you can just EXTEND_TOP the bd6200.bcs with this

IF
  Global("bd_plot","global",670)
  Global("ACBre_move_to_exit","bd6200",0)
THEN
  RESPONSE #100
    SetGlobal("ACBre_move_to_exit","bd6200",1)
  //  StartCutsceneMode() // optional - there should be no delays to warrant it, but neither should it cause harm
    ActionOverride("ACBre",MoveToPoint([1410.1410]))
    Continue()
END

For the actual transition, yes, I don't see a way without hijacking the cutscene script directly, at least if you want to preserve the visual consistency when the party arrives into BD6100 area - the characters walking to the center of area before Imoen starts dialog. Although you can make your NPC to pop up after it ends by appending the top of bd6100.bcs.

 

Like I said, SoD has quite a number of "cinematic" transitions between cutscene mode and normal gameplay, something that you'd find often in later games, e.g. Dragon Age, but not in the old BG. So if you want to incorporate your content into those, expect it to be less pleasant than traditional modding... At least you can simply inject you actions into pre-existing QA-tested scripts - I had to build them from the scratch while making compromises between storyboard, engine limitations and player's experience (and sometimes the area art as well, lol) :D

 

Looking at it now I see that it might be just as good to EXTEND_TOP with a True() block having the mod NPC being the CutScebeID and doing all the teleporting etc there.

 

Yep, that should work fine.

In fact, a lot of vanilla IWD transitions had party members to transition themselves individually, instead of having Player1 do the work for them. However, during the EE development there were discovered problems with multiplayer where other party members would sometimes fail to transition on their own.

So, unless you expect your mod to be used frequently in multiplayer, I don't think there should be any issues (and I'm not sure if it relates to any actor or just party members). At the very worst, he simply won't be present in bd6100.

 

Inbetween the area script gets set to something else (something SoD does a lot and which confuses me much - as interesting as it is to see that this is actually possible).

 

That's the skippable cutscene stuff.

 

SetCutSceneBreakable() enables/disables the skippable mode, where pressing Esc will stop the cutscene in progress, dropping all the actions queued, and execute the cleanup script in area's override slot (if any exists). It's possible that aborting the scene in the middle may e.g. leave the party in an area resered for dream cutscenes, so there'd be no way out of there - this is what the cleanup script is for, to complete the critical actions like transitions between areas or spawning/de-spawning actors while skipping all the visual fluff.

To keep this a manageable framework, we dedicated cutskip.bcs to do the cleaning work in SoD (cutskip2.bcs in BG2EE), and used BD_CUTSCENE_BREAKABLE global to Switch() between the responses in that script. This is all customizable, so for your mod cutscenes you can use your own cleanup file with or without the switch for ease of use, or even none at all if interrupting the scene in the middle won't break anything crucial.

 

I aplogize if my phrasing offended, they were much more drastic than I meant it.

I don't think there'd be a need for apology even if I did get offended.

Edited by Ardanis
Link to comment

Just to understand your intention

- Braegar was forced leaving party when the murder is detected in Dragonspear Castle?

- he stays out of the picture during the trial, escape etc?

- when you escape via the waterfall and come out into the open (bd6200), your Braegar is not in the party?

- you make him instead wait with the canon group waiting there where Imoen leads you?

- still not joining, he is supposed to move with the party to the south?

- the hidden transition to bd6100 takes place and he is supposed to be there as well?

- the party is ambushed overwhelmed and kidnapped - Braegar with them to awake in Irenicus Dungeon?

 

 

So basically, you want to add a "canon" character, not just a regular joinable. Yes, that indeed is more problematic because of some "cinematic" scenes like in the ending.

 

Now, at the end of bd6200.bcs the last scriptblock lets the NPCs move inside the area to certain locations and then starts the cutscene bdcut64x.bcs. In my understanding of scripts and cutscenes, I have to patch this script block and can't just append with a block for a mod NPC. Am I wrong here? Do get both scripts be executed equally if conditions match?

 

For the movement part itself, you can just EXTEND_TOP the bd6200.bcs with this

IF
  Global("bd_plot","global",670)
  Global("ACBre_move_to_exit","bd6200",0)
THEN
  RESPONSE #100
    SetGlobal("ACBre_move_to_exit","bd6200",1)
  //  StartCutsceneMode() // optional - there should be no delays to warrant it, but neither should it cause harm
    ActionOverride("ACBre",MoveToPoint([1410.1410]))
    Continue()
END

For the actual transition, yes, I don't see a way without hijacking the cutscene script directly, at least if you want to preserve the visual consistency when the party arrives into BD6100 area - the characters walking to the center of area before Imoen starts dialog. Although you can make your NPC to pop up after it ends by appending the top of bd6100.bcs.

 

Like I said, SoD has quite a number of "cinematic" transitions between cutscene mode and normal gameplay, something that you'd find often in later games, e.g. Dragon Age, but not in the old BG. So if you want to incorporate your content into those, expect it to be less pleasant than traditional modding... At least you can simply inject you actions into pre-existing QA-tested scripts - I had to build them from the scratch while making compromises between storyboard, engine limitations and player's experience (and sometimes the area art as well, lol) :D

 

Looking at it now I see that it might be just as good to EXTEND_TOP with a True() block having the mod NPC being the CutScebeID and doing all the teleporting etc there.

 

Yep, that should work fine.

In fact, a lot of vanilla IWD transitions had party members to transition themselves individually, instead of having Player1 do the work for them. However, during development there were discovered problems with multiplayer where other party members would sometimes fail to transition on their own.

So, unless you expect your mod to be used frequently in multiplayer, I don't think there should be any issues (and I'm not sure if it relates to any actor or just party members). At the very worst, he simply won't be present in bd6100.

 

Inbetween the area script gets set to something else (something SoD does a lot and which confuses me much - as interesting as it is to see that this is actually possible).

 

That's the skippable cutscene stuff.

 

SetCutSceneBreakable() enables/disables the skippable mode, where pressing Esc will stop the cutscene in progress, dropping all the actions queued, and execute the cleanup script in area's override slot (if any exists). It's possible that aborting the scene in the middle may e.g. leave the party in an area resered for dream cutscenes, so there'd be no way out of there - this is what the cleanup script is for, to complete the critical actions like transitions between areas or spawning/de-spawning actors while skipping all the visual fluff.

To keep this a manageable framework, we dedicated cutskip.bcs to do the cleaning work in SoD (cutskip2.bcs in BG2EE), and used BD_CUTSCENE_BREAKABLE global to Switch() between the responses in that script. This is all customizable, so for your mod cutscenes you can use your own cleanup file with or without the switch for ease of use, or even none at all if interrupting the scene in the middle won't break anything crucial.

 

I aplogize if my phrasing offended, they were much more drastic than I meant it.

I don't think there'd be a need for apology even if I did get offended.

If the interpretation of what you want to achieve here is correct, one idea in order to make things easier and safer would be not to use the actual continuous Braegar creature here but a strawman copy just for use in these scenes. As long as he looks like your NPC and has his name, there is no way to tell the difference and you just have a cutscene puppet you can show and move here. You can even give him display overhead text if you want. And any globals you may want to set will work even if he is not really there. (I have used this trick for the BG1 to BG2 transition of Sandrah in old BGT - she was moved invisibly to BG2 after Belt's dialogue and in the BGT transition cutscene was simulated by a copy.)

Edited by Roxanne
Link to comment

Thank you so much both for the ideas and insights! This is very valuable help.

Now, finally, I understand what the skippable cutscene is about (I mean the traces I saw in the scripts) - I was totally unaware that cutscenes can be skipped in SoD! As a player, I think this is awesome!

As a modder, it frightens me a bit. :)

 

EDIT: Roxanne: Yes, this is the behavior I intended for Breagar.

Edited by jastey
Link to comment
As a modder, it frightens me a bit. :)

 

As long as you don't make huge scenes several hundreds lines long with lots of screen action, with multiple script files looping under varying conditions, it should be quite simple.

Just copy the skippable block into the cleaner script, then delete all the waits, displays, visuals, replace MoveToPoint() with JumpToPoint() and you'll be already 80% done.

Link to comment

Just to understand your intention

- Braegar was forced leaving party when the murder is detected in Dragonspear Castle?

- he stays out of the picture during the trial, escape etc?

- when you escape via the waterfall and come out into the open (bd6200), your Braegar is not in the party?

- you make him instead wait with the canon group waiting there where Imoen leads you?

- still not joining, he is supposed to move with the party to the south?

- the hidden transition to bd6100 takes place and he is supposed to be there as well?

- the party is ambushed overwhelmed and kidnapped - Braegar with them to awake in Irenicus Dungeon?

EDIT: Roxanne: Yes, this is the behavior I intended for Breagar.

 

Consider this

1. BD6100 and BD6200 are only used this one time in the whole game, they never appear again and they are not accessible in any way but via these transition scripts, I.e. you need not care for clean-up or side affects.

2. Your *real* NPC has left the party and you let him re-appear in ar0602 with a MoveGlobal

3. Any script used here is only needed for EET but not for other platforms, so keep it separated from the rest

4- What happens in these two areas is just cinema - other than in BGT of old, the transition is not really performed here (Breagar goes from SoD into baldur.gam from where MoveGlobal retrieves him into ar0602). So all you need are some visual simulations, nothing that has any game effect.

 

Based on this

- create a BraegarX.cre strawman with a dedicated override script

- create this guy via area script(s) at the location where the party waits

- put all the actions (e.g MoveToObjectFollow("Imoen2") he is supposed to perform into his script based on the triggers used by the main scene

- this way you separate your scripts from the original and no need to tweak them. Your *real* Breagar is not affected by this at all.

 

I have not used this in my mod transition because my NPC's scenario is a different one, but I have used similar techniques in various large cutscenes in the game when I did not want to touch a big original script for my purpose. The *light* cutscene mode here allows a cre's override script actions to be executed while the cutscene is running as you use the same triggers.

You can also use the area scripts directly instead of the creatures override script but that again is more complex.

Edited by Roxanne
Link to comment

 

As a modder, it frightens me a bit. :)

As long as you don't make huge scenes several hundreds lines long with lots of screen action, with multiple script files looping under varying conditions, it should be quite simple.

Just copy the skippable block into the cleaner script, then delete all the waits, displays, visuals, replace MoveToPoint() with JumpToPoint() and you'll be already 80% done.

 

Indeed. Thank you! This sounds simple enough.

 

 

Consider this

1. BD6100 and BD6200 are only used this one time in the whole game, they never appear again and they are not accessible in any way but via these transition scripts, I.e. you need not care for clean-up or side affects.

2. Your *real* NPC has left the party and you let him re-appear in ar0602 with a MoveGlobal

3. Any script used here is only needed for EET but not for other platforms, so keep it separated from the rest

4- What happens in these two areas is just cinema - other than in BGT of old, the transition is not really performed here (Breagar goes from SoD into baldur.gam from where MoveGlobal retrieves him into ar0602). So all you need are some visual simulations, nothing that has any game effect.

 

Based on this

- create a BraegarX.cre strawman with a dedicated override script

- create this guy via area script(s) at the location where the party waits

- put all the actions (e.g MoveToObjectFollow("Imoen2") he is supposed to perform into his script based on the triggers used by the main scene

- this way you separate your scripts from the original and no need to tweak them. Your *real* Breagar is not affected by this at all.

 

I have not used this in my mod transition because my NPC's scenario is a different one, but I have used similar techniques in various large cutscenes in the game when I did not want to touch a big original script for my purpose. The *light* cutscene mode here allows a cre's override script actions to be executed while the cutscene is running as you use the same triggers.

You can also use the area scripts directly instead of the creatures override script but that again is more complex.

Very good idea. I already coded it using the original cre now but it's a smart idea I'll keep in mind for similar events.
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...