Jump to content

Modding chapter transitions and dream sequences in BG:EE? [EDITED]


Recommended Posts

Perhaps this should be in 'General Mod Discussion'; apologies in advance if I've posted in the wrong sub-forum.

Anyway, I'm hoping someone can confirm for me whether it's possible to mod the chapter transitions in BG:EE to the extent I want to mod them. I'm currently only at the stage where I'm poking about using NearInfinity and the IESDP to gain a rudimentary understanding of how things work, but I'm wondering if some of what I want to do is hardcoded.

By 'chapter transitions', I mean the cut-scene (with image, text screen, and audio) that plays after the player completes a specific task, the creation of a new section in CHARNAME's journal, the dream sequence (again with image, text screen, and audio), and the award of a new innate ability. And what I'm looking to do is allow the player to complete the three tasks that trigger the transitions in Chapters 2-3, 3-4, and 4-5 (kill Mulahey; steal Tazok's letters; kill Davaeorn) in any order they choose, with the completion of each task triggering a chapter transition and all that goes with it. Put differently, I want a game in which all of the following 6 pathways to progress the game are valid ones, instead of only the topmost one:

Path 1 - Ch2: (CLW/LMD) Nashkel Mines - Ch3: (CLW/LMD) Bandit Camp - Ch4: (SP/H) Cloakwood Mines - Ch5: (SP/H) Baldur's Gate.
Path 2 - Ch2: (CLW/LMD) Nashkel Mines - Ch3: (CLW/LMD) Cloakwood Mines - Ch4: (SP/H) Bandit Camp - Ch5: (SP/H) Baldur's Gate.
Path 3 - Ch2: (CLW/LMD) Bandit Camp - Ch3: (CLW/LMD) Nashkel Mines - Ch4: (SP/H) Cloakwood Mines - Ch5: (SP/H) Baldur's Gate.
Path 4 - Ch2: (CLW/LMD) Bandit Camp - Ch3: (CLW/LMD) Cloakwood Mines - Ch4: (SP/H) Nashkel Mines - Ch5: (SP/H) Baldur's Gate.
Path 5 - Ch2: (CLW/LMD) Cloakwood Mines - Ch3: (CLW/LMD) Nashkel Mines - Ch4: (SP/H) Bandit Camp - Ch5: (SP/H) Baldur's Gate.
Path 6 - Ch2: (CLW/LMD) Cloakwood Mines - Ch3: (CLW/LMD) Bandit Camp - Ch4: (SP/H) Nashkel Mines - Ch5: (SP/H) Baldur's Gate.

In order for the alternative paths to make sense, I envisage creating 12 or 15 alternative cut-scenes to replace the existing 3 (without audio, or with a few phrases/sentences of the existing audio spliced together). I don't want to make any changes to the content of the dream sequences, but the specific dream that occurs will in effect need to be linked to the specific task completed (kill Mulahey; steal Tazok's letters; kill Davaeorn) rather than to an increment of the chapter. Finally, the specific innate ability awarded after a dream would ideally need to be de-linked from the dreams with which they are associated.

Take for example a game that follows Path 5. I want the game to advance forward one chapter, which means that I want the game:

(a) to choose and play a specific alternative cutscene with content recognising that CHARNAME has killed Davaoern, but has not yet killed Mulahey OR stolen Tazok's letters;
(b) to create a new section in CHARNAME's journal titled 'Chapter Three' (not Chapter Five);
(c) to play the existing dream sequence currently associated with killing Davaeorn and moving onto Chapter Five;
(d) to give CHARNAME a second helping of CLW/LMD, which is consistent with what they currently receive for moving to Chapter Three, but not consistent with what they currently receive for killing Davaeorn (which would be SP/H).

If in the next game I follow Path 1, I want the chapter transition after killing Davaeorn to happen more or less as it does in the vanilla game. I hope all of this makes sense?

Using the Cloakwood Mines as an example, I see that the change in chapter after killing Davaeorn is triggered with IncrementChapter("CHPTXT5"), which points at a 2DA file with stringrefs for the name of the chapter and the content of the text screen (CHPTXT5.2DA). I see a similar 2DA file relating to the dream sequence (DRMTXT5.2DA), which also references the new innate ability to be awarded (SPIN102/SPIN105). I see the .WAV files and the .MOS files providing audio and image for the cut-scene (CHAPTER4.WAV and GUICHP5A.MOS) and the dream sequence (DREAM4G/E.WAV and GUIDRM5.MOS). Finally, I am aware from the .GAM files that there is a Dream Global Variable.

But what I can't see is any script in which the game tells itself what .WAV and .MOS files to access, or how it tells itself to look at DRMTXT5.2DA, or makes any reference whatsoever to the Dream Global Variable. I'm hoping this is just because I don't yet know what I'm doing, rather than because what I eventually want to do cannot be done! Any clarifications will be very much appreciated.

Edited by The_Baffled_King
Link to comment

Open a saved game in NI and have a look at globals that are set there. There is a CHAPTER global, this is what scripts check. And the script that looks for these things is generally BALDUR.BCS itself, when it's not something in the area script (Sarevok's death at the temple leads to the game's end only because of the area script there.) That's all I'll say about the technical aspect, but the real obstacle here is getting such plot shortcuts to make sense in the game - this is one, and make sure they enrich and not diminish the experience - this is two. I'm all for an open-world concept where it can be had, but if the player simply bypasses the Bandit Camp, not only is that going to require a lot of rewriting, in letters, conversations and everywhere (one of the voice-overs for the MOS intros also specifically mentions Tazok), but a sizeable chunk of the world will fall out. Going back to the bandit camp after the Cloakwood mines may be possible, but is it going to be satisfying? The enemies will be too easy, unless you take a special effort to increase the difficulty in the event of such a choice. But you would have to do big and small adjustments across the board. That's something that really takes a company, it's too much work for a single person. BG was never planned as a Morrowind or even, say, Faery Tale Adventure 2 or the Ultima games.

Trust me, you don't want to pour a year of your life into this. Lovely hand-drawn sprites and music, simple pleasures lure us and keep us, but this is just one game of very many. I don't want to sound jaded, but after years of sitting at these games' engine I have realized that no matter what I do, with my resources, I'm not going to turn these games into something completely different, nor force players to take the role-playing aspect seriously. Give them something a little different to do than hack-and-slash, yes, new activities, rewrite some situations where role-playing and open choices should have been but weren't, yes, but any bigger effort that you can mount should be poured into a new game. If you feel the designer's itch, reach out to independent developers out there, maybe even make your own company. Don't waste your time and strength here. I wish I knew this before.

Link to comment

Thanks for taking the time to respond @temnix ; it’s very much appreciated.

On the technical side of things, I’m aware of the CHAPTER global and can see references to it governing the likes of Teven, Raiken, Tranzig, and Officer Vai. As for the chapter transitions themselves, I can see where conditions for triggering the transitions are checked and the IncrementChapter function is used. For example, with the Chapter 2-3 transition, I can see that both AR5404.BCS and AR5405.BCS check for Mulahey’s death and/or whether the party has SCRL2V.ITM. As far as BALDUR.BCS is concerned, I see IncrementChapter used on the CHAPTER global only for the Chapter 3-4 transition (together with a check for SCRL2Z.ITM).

The confusion on my part, as I tried to make clear in my intial post, is over the location of any of the scripting regarding the DREAM global, and where the game tells itself specifically to look for the audio and visual accompaniment for the text screen when incrementing the CHAPTER global (edit: or indeed for any text screen). For example, with the Chapter 4-5 transition, after using IncrementChapter(“CHPTEXT5”), how does the game know to display GUICHP5A.MOS and to play CHAPTER4.WAV?

It is from opening a saved game and looking at its globals that I was able to see that there is a DREAM global. But for one reason or another, whenever I try including a .GAM file in any kind of search, I end up with a recurring error message “Error reading BALDUR.GAM null”. and I have to restart NearInfinity. So I’m just lost at the moment, really.

As for the rest of your points, they’re substantive and you/your points deserve an answer, but I’m going to hold off on that for a little while to see if anybody is willing to chime in on the technical side of things.

Edited by The_Baffled_King
Link to comment
1 hour ago, The_Baffled_King said:

For example, with the Chapter 4-5 transition, after using IncrementChapter(“CHPTEXT5”), how does the game know to display GUICHP5A.MOS and to play CHAPTER4.WAV?

(Examples from BGSoD)

CHPTEXT5.2DA, second column of "DEFAULT" row: 15839

String #15839 (in dialog.tlk) has "CHAPTER4.WAV" specified as it's associated sound.

Chapter and Dream Background images are defined in "BGEE.LUA":

chapterBackgrounds = {}
chapterBackgrounds[0] = "GUICHP0A"
chapterBackgrounds[1] = "GUICHP1A"
chapterBackgrounds[2] = "GUICHP2A"
chapterBackgrounds[3] = "GUICHP3A"
chapterBackgrounds[4] = "GUICHP4A"
chapterBackgrounds[5] = "GUICHP5A"
chapterBackgrounds[6] = "GUICHP6A"
chapterBackgrounds[7] = "GUICHP7A"
chapterBackgrounds[8] = "GUICHP1B"
chapterBackgrounds[9] = "GUICHP2B"
chapterBackgrounds[10] = "GUICHP3B"
chapterBackgrounds[11] = "GUICHP4B"
chapterBackgrounds[12] = "GUICHP5B"
chapterBackgrounds[13] = "GUICHP6B"

chapterBackgrounds[20] = "BPEND"

chapterBackgrounds[52] = "GUIDRM2"
chapterBackgrounds[53] = "GUIDRM3"
chapterBackgrounds[54] = "GUIDRM4"
chapterBackgrounds[55] = "GUIDRM5"
chapterBackgrounds[56] = "GUIDRM6"
chapterBackgrounds[57] = "GUIDRM7"
chapterBackgrounds[58] = "ARRIVE"
chapterBackgrounds[59] = "LEAVE"

chapterBackgrounds[100] = "GUICHP6B"

0 - 19 are likely directly linked to their chapter, but I've no idea how 20, 52-59, or 100 are linked to those events.

Link to comment

I started a thread here https://www.gibberlings3.net/forums/topic/32579-discussion-on-modding-bgee-so-that-the-main-plot-is-more-flexible/ to reply to Temnix and split any general discussion away from the specific problems I'm trying to solve. Hopefully that's not too greedy... All input on that thread is welcomed : )

@kjeron thanks for the clarifications; they are much appreciated. I feel a bit stupid for overlooking that the audio for the text screens is dealt with in the same way as any other audio associated with a text string. I kind of had a tunnel vision on the idea of it being hard-coded because I couldn't find any scripting for the dreams. Never mind.

The way that the backgrounds are specified in BGEE.LUA is a bit weird. It's fine for the chapter transitions and dreams because its consistent, in that line 2 of the 2DA is blank, and BGEE.LUA has the details of the .MOS. It gets a bit weird with "ARRIVE" and "LEAVE" (these are the ones for the Isle of Balduran). Unlike the chapter and dream text screens, these text-screens are triggered with the normal TextScreen action, and there is a reference to the MOS in both BGEE.LUA AND line 2 of the 2DA. The references in the 2DA are, respectively, "8" and "9", which sort of corresponds to [58] and [59] in BGEE.LUA, but... why not "58" and "59" in the 2DA files? And why is any reference needed at all in the 2DA, if it is specified in BGEE.LUA, and the chapter and dream text screens can get away without only a reference in BGEE.LUA? Confusing. To me, at least.

I think I've solved most of my scripting problems, but probably badly, and now there are new ones. I'll post what I have fairly shortly.

Edited by The_Baffled_King
Link to comment

Right. I’ve poked about some more, and I have “solved” my problem. Sort of. The code works within the game. But there is probably a lot wrong with the language I’ve used, and my solution is unsatisfactory in some respects, so any help is greatly appreciated.

Before posting my code, I should note that I’m operating on a number of assumptions which could be wrong, so it would be great if anyone can tell me if they are wrong. The assumptions are spoilered:

Spoiler

(1) In order to have a functioning journal system advancing as it does in the vanilla game, with a separate section for each chapter, I have to use the CHAPTER global.

(2) It seems easier, and better, to advance the CHAPTER global via IncrementGlobal action rather than SetGlobal, and there doesn’t appear to be any downside to doing so.

(3) From Chapter 2 onwards, the game is hard-coded to play the dreams when the DREAM global is less than the CHAPTER globlal.

(4) If I cannot adapt the existing dream content and DREAM variable to fit my purposes, I have to effectively disable it by advancing the DREAM global when I advance the CHAPTER global.

(5) It is to some extent relatively easy to use the existing dream content and DREAM variable in the manner I want to use it (to recap: killing Mulahey, stealing Tazok’s papers, killing Davaeorn all advance the Chapter – and thus the CHAPTER global – as in the vanilla game, but can be done in any order, and the resulting dream content must refer to what the player did in order to trigger the dream). I just have to set the DREAM global to the necessary number as and when required.

(6) To provide an example for the previous point: if the order of the game is such that the player is advancing to Chapter 5 by stealing Tazok’s papers in the Bandit Camp, the DREAM global needs to be set to 3 in the same script sequence that advances the CHAPTER global to 5. As required, the player will then dream about the Bandit Camp (hole in the earth, etc) despite it being Chapter 5, at which point the DREAM global advances to 4.

(7) One downside of doing this without any change to the existing DRMTEXTX.2DA is that the player would sometimes get Slow Poison/Horror as their second innate ability, or a second instance of Cure Light Wounds/Larloch’s Minor Drain as their fourth innate ability. Not sure how easy it is to script around that? If it was the only downside that would be fine.

(8) In the example given, I don’t know how easy it would be to reliably script for the game to set the DREAM global back to 5 after the dream about the Bandit Camp. If this cannot be done, I believe that the player also ends up with a second instance of the Cloakwood dream (tide of blood; etc) and associated special ability, long after they dealt with Davaeorn, as the game will ensure that a DREAM global at 4 is incremented to match the CHAPTER global at 5.

(9) I didn’t spend much time thinking about the previous example, because I think that everything goes to hell with this method unless the player advances the game in a rigid order: Chapter, Dream; Chapter, Dream; etc, only performing the task that gets them to the next chapter once they have the dream for the chapter they are currently in.

(10) On the basis of the prior assumptions, it seems I have to create my own global variable to manage the dreams, and disable the DREAM global as described above. Am I right?

Given the assumptions I’ve made, I’ve written the following code (within spoilers). As I said, it does work. The journal works as in the vanilla game and advances through Chapters 2-5 regardless of the order in which the player (a) kills Mulahey; (b) steals Tazok’s papers; (c) kills Davaeorn. The player gets no more than one dream per night, and no more than one dream for each chapter, but can dream multiple times in one chapter if they need to ‘catch up’. The image, text screen, and audio matches whatever the player did to trigger the chapter transition. The ability awarded matches the player’s Rep when the dream happens. And the abilities are awarded in the same order as in the vanilla game (so CLW; CLW; Slow Poison; Slow Poision if ‘good’ throughout).

 

Oh, a few quick questions/clarifications:

(A) At multiple places my script has IncrementChapter("") then TextScreen("") on consecutive lines. The 2DAs to be referenced don't yet exist, but I obviously won't be using CHPTXT3.2DA and so on. I think this should end up as IncrementGlobal("Chapter","GLOBAL",1) then TextScreen("2DAFILEOFCHOICEONCESTRINGSMADE")? Given that I won't be using the 2DAs that the game would expect from IncrementChapter, might I be inviting trouble to try to use that action?

(B) The 2DA files used in my dream scripting are the existing DRMTXT.2DA files (a) copied; (b) renamed; (c) with the MOS specified in line 2 so it doesn't go looking at BGEE.LUA and do something I don't understand. This was just for convenience while testing, but then I noticed something...

(C) ... I noticed that using TextScreen on the existing DRMTXT.2DA files, as described above, preserves the existing functionality from the DRMTXT.2DA whereby the Rep of the player is detected and the correct string (and audio) is used. However, the award of the innate ability was not preserved. In theory, this is good, as it allows me to just use the one .2DA file for each dream (rather than needing two; one for Good Rep, one for Evil Rep). But... I don't understand why part of the functionality was preserved. Anyone? And should the lines for Good_Power etc be deleted, if they aren't doing anything?

(D) The triggers used to begin a new chapter are identical to the vanilla game. Nothing needs checking there.

(E) Text strings and quests relating to AddJournalEntry are irrelevant. I just left it in the script so I had visual feedback that things were working as I tested it.

(F) I deleted innumerable EraseJournalEntry actions for brevity (from the script and/or what I'm posting here).

(G) I've used the prefix BK_ in front of my global variables. BK_Dream works much like DREAM. BK_NMines_Done has values of 0 and 1, for whether CHARNAME has or has not killed Mulahey and taken his letters. BK_NMines has values of 2, 3, or 4, which correspond to the value of the CHAPTER global immediately before Mulahey was killed and his letters taken. Cloakwood and Bandit Camp are treated in exactly the same way. Everything else has descriptive names and should I think be understood as it is read in context.

 

Phew. So, here it is (sorry, written with actual Notepad):

At the beginning of the game (in ch1cut04.BCS):

Spoiler

        IncrementChapter("Chptxt1")
        AddJournalEntry(16190,INFO)  // You awake with the realization ... etc
        EraseJournalEntry(31438)  // Find Gorion Gorion, my foster father, ... etc
        AddJournalEntry(31439,QUEST)  // Go to the Friendly Arm Inn ... etc
        MoveViewObject(Player1,INSTANT)
        FadeFromColor([4.0],0)
        SetGlobal("BK_Dream","GLOBAL",1)
        EndCutSceneMode()
        SmallWait(4)
        SetGlobal("BD_Chapter_Save","GLOBAL",1)
        SaveGame(11)
        SaveGame(0)
END

(Bit I added is in bold. This is the last of the Gorion cutscenes at the end of the Prologue. I think that this is needed somewhere so my code doesn't try to play dreams in Chapter 1. Is it better placed somewhere else?)

 

On entering Nashkel to trigger Chapter 2 (in AR4800.BCS):

Spoiler

IF
    Global("Chapter","GLOBAL",1)
    !InPartyAllowDead("Xzar")  // Xzar
    !InPartyAllowDead("Montaron")  // Montaron
    !InPartyAllowDead("Jaheira")  // Jaheira
    !InPartyAllowDead("Khalid")  // Khalid
THEN
    RESPONSE #100
        StartMovie("NASHKELL")
        BreakInstants()
        IncrementChapter("")
        SetGlobal("Dream","GLOBAL",2)
        AddJournalEntry(15836,INFO)  // With your hurried flight from Candlekeep ... etc
        AddJournalEntry(31442,QUEST)  // Speak to the Mayor of Nashkel ... etc
END

(Bit I added is in bold. In theory the dream in Chapter 2 can be done by the unmodded game, but letting that happen and having the player begin Chapter 3 without having dreamt is hassle, as you end up juggling two dream globals at the same time. In contrast, the code for the modded flexible sequence can already handle this scenario, so it's better if the modded code also handles the Chapter 2 dream. Note that I aware that I need similar code elsewhere in AR4800.BCS, in the scripts for the Nashkel Carnival and the Nashkel Mines exterior; there's just no point in posting (or writing) it right now. If it is theoretically possible to reach them during Chapter 1, I will need something similar in the Bandit Camp and Cloakwood Mines exterior.

 

Killing Mulahey in Nashkel Mines to trigger a new chapter (in AR5405.BCS):

Spoiler

IF
    Global("CDLetterCheckscrl2v","GLOBAL",0)
    PartyHasItem("SCRL2V")  // Letter
THEN
    RESPONSE #100
        SetGlobal("CDLetterCheckscrl2v","GLOBAL",1)
END

IF
    !ActuallyInCombat()
    Global("CDLetterCheckscrl2v","GLOBAL",1)
    Global("BK_NMines_Done","GLOBAL",0)
    Global("BK_BCamp_Done","GLOBAL",0)
    Global("BK_CWood_Done","GLOBAL",0)
THEN
    RESPONSE #100
        Wait(2)
        SetGlobal("BK_NMines_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15837,INFO)  // It is certain that the death of Mulahey will relieve the fears of the terrorized folk of Nashkel ... etc
        SetGlobal("Dream","GLOBAL",3)
        SetGlobal("BK_NMines","GLOBAL",2)
END

IF
    !ActuallyInCombat()
    Global("CDLetterCheckscrl2v","GLOBAL",1)
    Global("BK_NMines_Done","GLOBAL",0)
    Global("BK_BCamp_Done","GLOBAL",1)
    Global("BK_CWood_Done","GLOBAL",0)
THEN
    RESPONSE #100
        Wait(2)
        SetGlobal("BK_NMines_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15837,INFO)  // It is certain that the death of Mulahey will relieve the fears of the terrorized folk of Nashkel ... etc
        SetGlobal("Dream","GLOBAL",4)
        SetGlobal("BK_NMines","GLOBAL",3)
END

IF
    !ActuallyInCombat()
    Global("CDLetterCheckscrl2v","GLOBAL",1)
    Global("BK_NMines_Done","GLOBAL",0)
    Global("BK_BCamp_Done","GLOBAL",0)
    Global("BK_CWood_Done","GLOBAL",1)
THEN
    RESPONSE #100
        Wait(2)
        SetGlobal("BK_NMines_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15837,INFO)  // It is certain that the death of Mulahey will relieve the fears of the terrorized folk of Nashkel ... etc
        SetGlobal("Dream","GLOBAL",4)
        SetGlobal("BK_NMines","GLOBAL",3)
END

IF
    !ActuallyInCombat()
    Global("CDLetterCheckscrl2v","GLOBAL",1)
    Global("BK_NMines_Done","GLOBAL",0)
    Global("BK_BCamp_Done","GLOBAL",1)
    Global("BK_CWood_Done","GLOBAL",1)
THEN
    RESPONSE #100
        Wait(2)
        SetGlobal("BK_NMines_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15837,INFO)  // It is certain that the death of Mulahey will relieve the fears of the terrorized folk of Nashkel ... etc
        SetGlobal("Dream","GLOBAL",5)
        SetGlobal("BK_NMines","GLOBAL",4)
END

IF
    Global("Chapter","GLOBAL",5)
    Global("BK_To_Baldur's_Gate","GLOBAL",0)
THEN
    RESPONSE #100
        SetGlobal("BK_To_Baldur's_Gate","GLOBAL",1)
        RevealAreaOnMap("AR0900")  // Wyrm's Crossing (bridge to BG, Tenya, Quayle)
END

(No point in showing script for AR5404.BCS as well, but I know it needs similar lines)

 

Stealing Tazok's letters in the Bandit Camp to trigger a new chapter (in BALDUR.BCS):

Spoiler

IF
    Global("CDLetterCheckscrl2z","GLOBAL",1)
    !ActuallyInCombat()
    Global("BK_NMines_Done","GLOBAL",0)
    Global("BK_BCamp_Done","GLOBAL",0)
    Global("BK_CWood_Done","GLOBAL",0)
THEN
    RESPONSE #100
        Wait(2)
        SetGlobal("BK_BCamp_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15838,INFO)  // Mulahey and Tazok have proven to be nothing more than puppets ... etc
        AddJournalEntry(31451,QUEST)  // Cloakwood The investigation of the bandit camp has directed me to Cloakwood ... etc
        SetGlobal("Dream","GLOBAL",3)
        SetGlobal("BK_BCamp","GLOBAL",2)
END

IF
    Global("CDLetterCheckscrl2z","GLOBAL",1)
    !ActuallyInCombat()
    Global("BK_NMines_Done","GLOBAL",1)
    Global("BK_BCamp_Done","GLOBAL",0)
    Global("BK_CWood_Done","GLOBAL",0)
THEN
    RESPONSE #100
        Wait(2)
        SetGlobal("BK_BCamp_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15838,INFO)  // Mulahey and Tazok have proven to be nothing more than puppets ... etc
        AddJournalEntry(31451,QUEST)  // Cloakwood The investigation of the bandit camp has directed me to Cloakwood ... etc
        SetGlobal("Dream","GLOBAL",4)
        SetGlobal("BK_BCamp","GLOBAL",3)
END

IF
    Global("CDLetterCheckscrl2z","GLOBAL",1)
    !ActuallyInCombat()
    Global("BK_NMines_Done","GLOBAL",0)
    Global("BK_BCamp_Done","GLOBAL",0)
    Global("BK_CWood_Done","GLOBAL",1)
THEN
    RESPONSE #100
        Wait(2)
        SetGlobal("BK_BCamp_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15838,INFO)  // Mulahey and Tazok have proven to be nothing more than puppets ... etc
        AddJournalEntry(31451,QUEST)  // Cloakwood The investigation of the bandit camp has directed me to Cloakwood ... etc
        SetGlobal("Dream","GLOBAL",4)
        SetGlobal("BK_BCamp","GLOBAL",3)
END

IF
    Global("CDLetterCheckscrl2z","GLOBAL",1)
    !ActuallyInCombat()
    Global("BK_NMines_Done","GLOBAL",1)
    Global("BK_BCamp_Done","GLOBAL",0)
    Global("BK_CWood_Done","GLOBAL",1)
THEN
    RESPONSE #100
        Wait(2)
        SetGlobal("BK_BCamp_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15838,INFO)  // Mulahey and Tazok have proven to be nothing more than puppets ... etc
        AddJournalEntry(31451,QUEST)  // Cloakwood The investigation of the bandit camp has directed me to Cloakwood ... etc
        SetGlobal("Dream","GLOBAL",5)
        SetGlobal("BK_BCamp","GLOBAL",4)
END

IF
    Global("Chapter","GLOBAL",5)
    Global("BK_To_Baldur's_Gate","GLOBAL",0)
THEN
    RESPONSE #100
        SetGlobal("BK_To_Baldur's_Gate","GLOBAL",1)
        RevealAreaOnMap("AR0900")  // Wyrm's Crossing (bridge to BG, Tenya, Quayle)
END

(I just stuck this where the existing lines were in BALDUR.BCS. Note that SetGlobal("CDLetterCheckscrl2z","GLOBAL",1) happens in AR1901.BCS)

 

Killing Davaeorn in Cloakwood to trigger a new chapter (in AR1803.BCS):

Spoiler

IF
    Dead("Davaeorn")  // Davaeorn
    Global("BK_NMines_Done","GLOBAL",0)
    Global("BK_BCamp_Done","GLOBAL",0)
    Global("BK_CWood_Done","GLOBAL",0)
THEN
    RESPONSE #100
        SetGlobal("BK_CWood_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15839,INFO)  // You have dealt a great blow to the organization known as the Iron Throne  .... etc
        SetGlobal("Dream","GLOBAL",3)
        SetGlobal("BK_CWood","GLOBAL",2)
END

IF
    Dead("Davaeorn")  // Davaeorn
    Global("BK_NMines_Done","GLOBAL",1)
    Global("BK_BCamp_Done","GLOBAL",0)
    Global("BK_CWood_Done","GLOBAL",0)
THEN
    RESPONSE #100
        SetGlobal("BK_CWood_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15839,INFO)  // You have dealt a great blow to the organization known as the Iron Throne .... etc
        SetGlobal("Dream","GLOBAL",4)
        SetGlobal("BK_CWood","GLOBAL",3)
END

IF
    Dead("Davaeorn")  // Davaeorn
    Global("BK_NMines_Done","GLOBAL",0)
    Global("BK_BCamp_Done","GLOBAL",1)
    Global("BK_CWood_Done","GLOBAL",0)
THEN
    RESPONSE #100
        SetGlobal("BK_CWood_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15839,INFO)  // You have dealt a great blow to the organization known as the Iron Throne .... etc
        SetGlobal("Dream","GLOBAL",4)
        SetGlobal("BK_CWood","GLOBAL",3)
END

IF
    Dead("Davaeorn")  // Davaeorn
    Global("BK_NMines_Done","GLOBAL",1)
    Global("BK_BCamp_Done","GLOBAL",1)
    Global("BK_CWood_Done","GLOBAL",0)
THEN
    RESPONSE #100
        SetGlobal("BK_CWood_Done","GLOBAL",1)
        IncrementChapter("")
        TextScreen("")
        AddJournalEntry(15839,INFO)  // You have dealt a great blow to the organization known as the Iron Throne .... etc
        SetGlobal("Dream","GLOBAL",5)
        SetGlobal("BK_CWood","GLOBAL",4)
END

IF
    Global("Chapter","GLOBAL",5)
    Global("BK_To_Baldur's_Gate","GLOBAL",0)
THEN
    RESPONSE #100
        SetGlobal("BK_To_Baldur's_Gate","GLOBAL",1)
        RevealAreaOnMap("AR0900")  // Wyrm's Crossing (bridge to BG, Tenya, Quayle)
END

(There is another script, ENDCHA4.BCS, that also advances the chapter upon the death of Davaeorn. However, I don’t think it’s possible to trigger the code… I think it is orphan code that used to be attached to the lift in BG1, but I’m not sure. Anyone know about this?)

Is it just me, or is RevealAreaOnMap("AR0900")  // Wyrm's Crossing pointless script? I'm sure my unmodded game begins with Wyrm's Crossing already revealed... Either way, it was in AR1803.BCS, and it's a useful stand in for "action that needs to happen when my flexible plot merges with the rigid plot" (if Chapter 5 is the point in the game for that to happen).

 

Tracking and triggering the dreams and award of innate abilities (in BALDUR.BCS):

Spoiler

IF
    PartyRested()
    GlobalsLT("BK_Dream","Chapter")
THEN
    RESPONSE #100
        SetGlobal("BK_Dream_Text_Screen","GLOBAL",1)
        FadeToColor([35.0],0)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream_Rep","GLOBAL",0)
    ReputationGT(Player1,9)
THEN
    RESPONSE #100
        SetGlobal("BK_Dream_Rep","GLOBAL",1)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream_Rep","GLOBAL",0)
    ReputationLT(Player1,10)
THEN
    RESPONSE #100
        SetGlobal("BK_Dream_Rep","GLOBAL",2)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream","GLOBAL",1)
THEN
    RESPONSE #100
        TextScreen("BK_DrmC2")
        SetGlobal("BK_Dream_Text_Screen","GLOBAL",0)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream","GLOBAL",2)
    Global("BK_NMines","GLOBAL",2)
THEN
    RESPONSE #100
        TextScreen("BK_DrmNM")
        SetGlobal("BK_Dream_Text_Screen","GLOBAL",0)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream","GLOBAL",2)
    Global("BK_BCamp","GLOBAL",2)
THEN
    RESPONSE #100
        TextScreen("BK_DrmBC")
        SetGlobal("BK_Dream_Text_Screen","GLOBAL",0)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream","GLOBAL",2)
    Global("BK_CWood","GLOBAL",2)
THEN
    RESPONSE #100
        TextScreen("BK_DrmCW")
        SetGlobal("BK_Dream_Text_Screen","GLOBAL",0)
END

IF
    Global("BK_Dream_Rep","GLOBAL",1)
    OR(2)
        Global("BK_Dream","GLOBAL",1)
        Global("BK_Dream","GLOBAL",2)
THEN
    RESPONSE #100
        SetGlobal("BK_Dream_Rep","GLOBAL",0)
        IncrementGlobal("BK_Dream","GLOBAL",1)
        ActionOverride(Player1,AddSpecialAbility("SPIN101"))  // Cure Light Wounds
        FadeFromColor([40.0],0)
END

IF
    Global("BK_Dream_Rep","GLOBAL",2)
    OR(2)
        Global("BK_Dream","GLOBAL",1)
        Global("BK_Dream","GLOBAL",2)
THEN
    RESPONSE #100
        SetGlobal("BK_Dream_Rep","GLOBAL",0)
        IncrementGlobal("BK_Dream","GLOBAL",1)
        ActionOverride(Player1,AddSpecialAbility("SPIN104"))  // Larloch's Minor Drain
        FadeFromColor([40.0],0)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream","GLOBAL",3)
    Global("BK_NMines","GLOBAL",3)
THEN
    RESPONSE #100
        TextScreen("BK_DrmNM")
        SetGlobal("BK_Dream_Text_Screen","GLOBAL",0)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream","GLOBAL",3)
    Global("BK_BCamp","GLOBAL",3)
THEN
    RESPONSE #100
        TextScreen("BK_DrmBC")
        SetGlobal("BK_Dream_Text_Screen","GLOBAL",0)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream","GLOBAL",3)
    Global("BK_CWood","GLOBAL",3)
THEN
    RESPONSE #100
        TextScreen("BK_DrmCW")
        SetGlobal("BK_Dream_Text_Screen","GLOBAL",0)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream","GLOBAL",4)
    Global("BK_NMines","GLOBAL",4)
THEN
    RESPONSE #100
        TextScreen("BK_DrmNM")
        SetGlobal("BK_Dream_Text_Screen","GLOBAL",0)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream","GLOBAL",4)
    Global("BK_BCamp","GLOBAL",4)
THEN
    RESPONSE #100
        TextScreen("BK_DrmBC")
        SetGlobal("BK_Dream_Text_Screen","GLOBAL",0)
END

IF
    Global("BK_Dream_Text_Screen","GLOBAL",1)
    Global("BK_Dream","GLOBAL",4)
    Global("BK_CWood","GLOBAL",4)
THEN
    RESPONSE #100
        TextScreen("BK_DrmCW")
        SetGlobal("BK_Dream_Text_Screen","GLOBAL",0)
END

IF
    Global("BK_Dream_Rep","GLOBAL",1)
    OR(2)
        Global("BK_Dream","GLOBAL",3)
        Global("BK_Dream","GLOBAL",4)
THEN
    RESPONSE #100
        SetGlobal("BK_Dream_Rep","GLOBAL",0)
        IncrementGlobal("BK_Dream","GLOBAL",1)
        ActionOverride(Player1,AddSpecialAbility("SPIN102"))  // Slow Poison
        FadeFromColor([40.0],0)
END

IF
    Global("BK_Dream_Rep","GLOBAL",2)
    OR(2)
        Global("BK_Dream","GLOBAL",3)
        Global("BK_Dream","GLOBAL",4)
THEN
    RESPONSE #100
        SetGlobal("BK_Dream_Rep","GLOBAL",0)
        IncrementGlobal("BK_Dream","GLOBAL",1)
        ActionOverride(Player1,AddSpecialAbility("SPIN105"))  // Horror
        FadeFromColor([40.0],0)
END

(Script is written as if the game stops at Chapter 5. I either need a line to shut off my dream cycle, or I need to allow my dream cycle to handle the Chapter 6 and Chapter 7 dreams. The latter is probably better. Seems easy enough)

 

I really have no idea if the dream script in particular is any good. Also, there are two specific issues I can identify:

(1) BALDUR.BCS already uses a PartyRested() action, which I deleted while testing my dream script:

Spoiler

IF
    PartyRested()
THEN
    RESPONSE #100
        SmallWait(1)
END

I'm not 100% on the best way to re-enable this functionality with my dream script, and whether to change SmallWait at all given the additional code.

 

(2) The dreams do not trigger as smoothly as I would like.

In the vanilla game, when a dream triggers, the dream text screen replaces the on-rest movie. With my current implementation, the on-rest movie plays, then the screen returns to normal, and then the dream text screen plays. I really don't mind the on-rest movie playing first (I may actually even prefer that). But I hate, hate, HATE having a noticeable return to the post-rest screen in between the on-rest movie and the dream text screen!

The sequence looks particularly bad when resting at an inn, because you "wake" to the inn's rooms menu. That is behaviour from the vanilla game that I would like to see removed. Can this be done? The FadeToColor and FadeFromColor was my first attempt at addressing the overall problem, and it is not great. The FadeFromColor helps a little, but should probably be slower. The FadeToColor is terrible, although I haven't tried slowing that down as well.

I was also wondering if it is possible to either (a) have the rest action always implement a FadetoColor; or (b) dynamically disable the on-rest movie during a game when a dream is due to play, and re-enable the on-rest movie afterwards? In the latter case, note that my script has a dream happen 100% of the time when my BK_Dream global is lower than the CHAPTER global, so that probably helps matters somewhat.

Edited by The_Baffled_King
Clarified meaning of Globals used
Link to comment

I've gone back to the issue of the dreams not triggering smoothly from a visual standpoint, and it is now sorted to an acceptable standard (I've edited the code in the spoiler second from bottom in my previous post to reflect the changes).

Previously, the sequence was:

Rest Movie ---> FadeToColor([0.0],0) ---> Dream Text Screen ---> FadeFromColor([20.0],0) ---> Wake up with the rooms menu open (if resting at an inn).

It is now:

Rest Movie ---> FadeToColor([35.0],0) ---> Dream Text Screen ---> FadeFromColor([40.0],0) ---> Wake up with the rooms menu closed (the store as a whole is closed).

The FadeToColor at 35 makes the switch from dark colours (rest movie), to lighter colours (the normal screen), and back to dark colours (the dream itself) far easier on the eye, and the subsequent FadeFromColor basically mirrors the previous FadeToColor.

But getting rid of the rooms menu on waking really makes the sequence look far, far better. Note that the change means that clicking the "Rest" button at an inn (on the screen where it asks "are you sure you wish to rest?") will always close the store, regardless of whether a dream is queued up. This seems like a feature, not a bug; I bet that countless hours have been wasted by players the world over being forced to click to close the store the morning after resting. How does this all sound to other people?

I'm still curious about whether it's possible to disable and re-enable the on-rest movie mid-game with BCS script, but that seems less important now. I am far more interested in the general robustness, or otherwise, of the code I've used and the assumptions made. All input is appreciated!

Link to comment
On 3/31/2021 at 7:41 PM, The_Baffled_King said:

One downside of doing this without any change to the existing DRMTEXTX.2DA is that the player would sometimes get Slow Poison/Horror as their second innate ability, or a second instance of Cure Light Wounds/Larloch’s Minor Drain as their fourth innate ability. Not

FWIW getting special abilities out of order really doesn’t bother me at all. 

Link to comment
11 hours ago, subtledoctor said:

FWIW getting special abilities out of order really doesn’t bother me at all. 

Seems like a worthwhile sacrifice to me too, if it comes to that. At the moment I'm more concerned that stuff can happen that stops the code following the PartyRested() trigger from firing. If that screws up, it seems like a bad thing. Eh, on the plus side, at least it looks nice for now : )

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...