Jump to content

Zed Nocear's Trigger-Simulations for BG1


Recommended Posts

Current version from 01/14th/2012

Zed Nocear's BG1 Trigger-Simulations
This tutorial presents the simulations of BGII triggers for original BG (with or without the Add-on Tales of the Sword Coast) as defined by Zed Nocear. They are already successfully used in two BG1 mods: Zed Nocear's TWM ("Mysteries of the Sword Coast", currently only in Polish), and jastey's Ajantis BG1 Expansion Mod. The tutorial is open for discussion. If you have suggestions, corrections or other ideas please share them!

Content
1. Detection of AreaType and simulating AreaCheck()
2. Detection of "Party rested"
3. Simulating CombatCounter()


1. Detection of AreaType and simulating AreaCheck()
To simulate the AreaType() check known from BGII, all area scripts are patched to set the appropriate variables. There are two sets of scripts for patching: One for the master areas, and one for all areas that are not listed as master areas. Note: The code transfers all content of the actual area.bcs to a script that has the area name. Hence, if the area script did not have the same number/name as the area before, the name will be changed by this script.
The patching code in the tp2 is the following:

<<<<<<<< .../BG1TriggerEmulation-inlined/Z!EmulAreaCheck.BAF
IF
Delay(2)
ActionListEmpty()
THEN
RESPONSE #100
SetGlobal("Z!EmulAreaCheck","GLOBAL",%Area_Number%)
SetGlobal("Z!EmulAreaType","GLOBAL",%Area_Flags%)
SetGlobal("Z!EmulAreaOutdoor","GLOBAL",%Variable_Outdoor%)
SetGlobal("Z!EmulAreaCity","GLOBAL",%Variable_City%)
SetGlobal("Z!EmulAreaForest","GLOBAL",%Variable_Forest%)
SetGlobal("Z!EmulAreaDungeon","GLOBAL",%Variable_Dungeon%)
SetGlobalTimer("Z!EmulAreaNotMaster","GLOBAL",4)
END
>>>>>>>>

<<<<<<<< .../BG1TriggerEmulation-inlined/Z!EmulAreaCheck1.BAF
IF
!Global("Z!EmulAreaCheck","GLOBAL",%Area_Number%)
!GlobalTimerNotExpired("Z!EmulAreaNotMaster","GLOBAL")
ActionListEmpty()
THEN
RESPONSE #100
SetGlobal("Z!EmulAreaCheck","GLOBAL",%Area_Number%)
SetGlobal("Z!LastMasterArea","GLOBAL",%Area_Number%)
SetGlobal("Z!EmulAreaType","GLOBAL",%Area_Flags%)
SetGlobal("Z!EmulAreaOutdoor","GLOBAL",%Variable_Outdoor%)
SetGlobal("Z!EmulAreaCity","GLOBAL",%Variable_City%)
SetGlobal("Z!EmulAreaForest","GLOBAL",%Variable_Forest%)
SetGlobal("Z!EmulAreaDungeon","GLOBAL",%Variable_Dungeon%)
END
>>>>>>>>

COPY_EXISTING ~AR2612.ARE~ ~override~ // two areas in BG1 have wrong flag "Outdoor"
~AR3317.ARE~ ~override~
WRITE_BYTE 0x48 0
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING_REGEXP GLOB ~.*\.ARE~ ~override~ // for all areas in game proper script name and file
SPRINT area_name ~%SOURCE_RES%~
READ_ASCII 0x94 ~old_script_name~
WRITE_EVALUATED_ASCII 0x94 ~%SOURCE_RES%~
INNER_ACTION BEGIN
ACTION_IF !(~%old_script_name%~ STRING_EQUAL_CASE ~%area_name%~)
AND (FILE_EXISTS_IN_GAME ~%old_script_name%.bcs~)
THEN BEGIN COPY_EXISTING ~%old_script_name%.bcs~ ~override/%area_name%.bcs~ END
END
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING_REGEXP GLOB ~.*\.ARE~ ~override~ // adds AreaCheck emulation block to the area script
READ_ASCII 0x94 ~Script_Name~
PATCH_IF (~%SOURCE_RES%~ STRING_MATCHES_REGEXP ~AR[0-9][0-9][0-9][0-9]~) = 0
THEN BEGIN READ_ASCII 0x96 ~Area_Number~ (4) END
ELSE BEGIN SPRINT ~Area_Number~ ~0~ END
READ_BYTE 0x48 ~Area_Flags~
INNER_ACTION BEGIN
ACTION_IF (NOT FILE_CONTAINS_EVALUATED(~%Script_Name%.BCS~ ~Z!EmulAreaCheck~)) // area script not already patched
THEN BEGIN
OUTER_SET Variable_Outdoor = ((~%Area_Flags%~ BAND 0b1) = 0b1)
OUTER_SET Variable_City = ((~%Area_Flags%~ BAND 0b1000) = 0b1000)
OUTER_SET Variable_Forest = ((~%Area_Flags%~ BAND 0b10000) = 0b10000)
OUTER_SET Variable_Dungeon = ((~%Area_Flags%~ BAND 0b100000) = 0b100000)
ACTION_IF (FILE_CONTAINS_EVALUATED(~MASTAREA.2DA~ ~%Script_Name%~))
THEN BEGIN EXTEND_BOTTOM ~%Script_Name%.BCS~ ~.../BG1TriggerEmulation-inlined/Z!EmulAreaCheck1.BAF~ EVALUATE_BUFFER END //area is "master area" as in mastarea.2DA
ELSE BEGIN EXTEND_BOTTOM ~%Script_Name%.BCS~ ~.../BG1TriggerEmulation-inlined/Z!EmulAreaCheck.BAF~ EVALUATE_BUFFER END //area is not "master area"
END
END
BUT_ONLY_IF_IT_CHANGES

Now, including the tpa into your mod, installation only needs the following line in the tp2:
INCLUDE ~%PatchInMyMod%/BG1AreaCheck_emulation.tpa~


"Z!EmulAreaType" gives the sum of all flags (value of the offset 0x48) of the according ARE-Datei.
The triggers AreaType() and AreaCheck() can be simulated:

AreaType():
OUTDOOR: "Global("Z!EmulAreaOutdoor","GLOBAL",1)"
CITY: "Global("Z!EmulAreaCity","GLOBAL",1)"
FOREST: "Global("Z!EmulAreaForest","GLOBAL",1)"
DUNGEON: "Global("Z!EmulAreaDungeon","GLOBAL",1)"

AreaCheck()
For simulating AreaCheck(), the variable "Z!EmulAreaCheck" can be used: For the original BG areas, the value of the variable is equal to the "ARxxxx" number. For (mod) areas that are not named like the standard "ARxxxx", the variable is equal to "0".
For example, now the Area AR2600 can be detected via the trigger "Global("Z!EmulAreaCheck","GLOBAL",2600)".


2. Detection of "Party rested"
To simulate the "PartyRested()" trigger known from BGII, the FATIGUE state of the Player1 will be used. Directly after rest, this stat has the value "0". During the game, it increases until the character reached a state of fatigue. For detection of the rest, the FATIGUE value will be checked. If it is "0", the custom spell "Z!FATIG1" sets the FATIGUE value to "1", along with the setting of the needed timers for the after-rest dialogues.

(Note: Theoretically, this means that the character will fatigue faster in the game (4 hours earlier). So far, this could not be detected in the game while playing with this party rested detection installed, though.)

For this, dplayer3.bcs is patched with the following script block. The example is for the Ajantis romance in the BG1 Ajantis expansion modification. Own variables and timers have to be inserted in your mod, accordingly:
//dplayer3_add.baf
IF
CheckStat(Player1,0,FATIGUE)
THEN
RESPONSE #100
ApplySpellRES("Z!FATIG1",Player1)
IncrementGlobal("X#AjantisRomanceRestCounter","GLOBAL",1)
SetGlobalTimer("X#AjantisRomanceRestAfterTimer","GLOBAL",30)
END

Thus, the needed triggers for the dialogues will be given after the rest, i.e. if the FATIFUE value was at "0". For a short period after wake-up, the timer "X#AjantisRomanceRestAfterTimer" runs and can be used to trigger morning dialogues.


For the Ajantis morning dialogue, the triggering script block looks like this:

/* dialogue activation */
IF
InParty(Myself)
!StateCheck(Myself,CD_STATE_NOTVALID) //custom state from CamDawg
!StateCheck(Player1,CD_STATE_NOTVALID)
Detect(Player1)
!See([ENEMY])
!GlobalTimerNotExpired("Z!EnemySeenPeriod","GLOBAL") //simulation of CombatCounter(0), see below
!Global("X#AjantisRomanceActive","GLOBAL",3)
Global("X#AjantisRomanceMatch","GLOBAL",1)
GlobalGT("X#AjantisRomanceRestCounter","GLOBAL",1) //greater as 1: the first time the variable is incremented is directly after the installation!
!GlobalTimerExpired("X#AjantisRomanceRestAfterTimer","GLOBAL") //timer runs: dialogue triggers shortly after wake-up
Global("X#AjantisRomanceStars","GLOBAL",1)
THEN
RESPONSE #100
SetGlobal("X#AjantisRomanceStars","GLOBAL",3)
END

/* dialogue triggering */
IF
InParty(Myself)
!StateCheck(Myself,CD_STATE_NOTVALID)
!StateCheck(Player1,CD_STATE_NOTVALID)
Global("X#AjantisRomanceStars","GLOBAL",3)
THEN
RESPONSE #100
SetGlobalTimer("X#AjantisRomance","GLOBAL",TWO_DAYS)
Dialogue(Player1)
END

Now the crucial part: Making the PartyRested() simulation compatible with other mods. For this, a distinction of cases has to be put into the tp2-files. With this disctinction, the above posted patching of the dplayer3.bcs will only happen, if no other mod already patched the application of the spell. If another mod already did so, patching of the appropriate script block is not only sufficient for your mod, but the only way to keep the mods compatible.

So, the tp2 section looks like this:
APPEND ~action.ids~ ~160 ApplySpellRES(S:ResRef*,O:Target*)~ UNLESS ~ApplySpellRES~

ACTION_IF (FILE_CONTAINS_EVALUATED (~dplayer3.BCS~ ~"Z!FATIG1"~))
THEN BEGIN
COPY_EXISTING ~dplayer3.BCS~ ~override~
DECOMPILE_BCS_TO_BAF
REPLACE_TEXTUALLY ~ApplySpellRES("Z!FATIG1",Player1)~
~ApplySpellRES("Z!FATIG1",Player1)
IncrementGlobal("X#AjantisRomanceRestCounter","GLOBAL",1)
SetGlobalTimer("X#AjantisRomanceRestAfterTimer","GLOBAL",30)~
COMPILE_BAF_TO_BCS
END
ELSE BEGIN
EXTEND_TOP ~dplayer3.BCS~ ~C#AjantisRomance_BG1/TriggerSimulations/dplayer3_add.BAF~
COPY ~TWM_Pack/00RESTcheck/Z!FATIG1.SPL~ ~override~
END

The spell can be downloaded here: Download Ajantis BG1 Expansion
The mod contains the spell inside the folder BG1_Triggersimulations, which has to be copied to the override folder.


3. Simulating CombatCounter()
To simulate the trigger "CombatCounter(0)" known from BGII, the override scripts of the NPCs, the dplayer3.bcs (for the PC), and dplayer2.bcs (for mod-NPCs that do not use the enemy detection in their scripts) are patched with a script block that runs a timer as soon as one of the NPCs see an enemy. Note: dplayer2.bcs only gets executed, if the AI is turned on in the game. The override script of an NPC is the only one that gets executed with tuned off AI.

The script for patching is the following (in the following referred to as "CombatTimer_add.BAF"):
IF
Global("Z!EnemyAlreadySeen","LOCALS",0)
InParty(Myself)
See([ENEMY])
ActionListEmpty()
THEN
RESPONSE #100
SetGlobal("Z!EnemyAlreadySeen","LOCALS",1)
END

IF
Global("Z!EnemyAlreadySeen","LOCALS",0)
InParty(Myself)
Died([ENEMY])
THEN
RESPONSE #100
SetGlobal("Z!EnemyAlreadySeen","LOCALS",1)
END

IF
InParty(Myself)
!See([ENEMY])
Global("Z!EnemyAlreadySeen","LOCALS",1)
THEN
RESPONSE #100
SetGlobal("Z!EnemyAlreadySeen","LOCALS",0)
SetGlobalTimer("Z!EnemySeenPeriod30","GLOBAL",30) // halbe Minute, halbe Tour im Spiel
SetGlobalTimer("Z!EnemySeenPeriod60","GLOBAL",60) //eineMinute, volle Tour im Spiel
SetGlobalTimer("Z!EnemySeenPeriod150","GLOBAL",150) //reale 2,5 Minuten, halbe Stunde im Spiel
SetGlobalTimer("Z!EnemySeenPeriod900","GLOBAL",900) // drei Stunden im Spiel
SetGlobalTimer("Z!EnemySeenPeriod7200","GLOBAL",7200) // Tag und Nacht im Spiel
END

Now the BGII trigger "CombatCounter(0)" can be simulated using the trigger

"!See([ENEMY])
!GlobalTimerNotExpired("Z!EnemySeenPeriodX","GLOBAL")"

for the relevant NPC, with "X" being the wanted time interval: 60, 150, 900, 7200.

For patching, it is useful to check whether the script blocks were already added. For Ajantis override script, this would look like this:
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~ajantis.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~ajantis.BCS~ ~AjantisBG1/BG1_TriggerSimulations/combatcounter.baf~
END
in the .tp2.

Note: Not every BioWare BG1 NPCs have override scripts.
NPCs who do not have override scripts are: Alora, Branwen, Faldorn, Garrick, Imoen, Skie, and Xan.

Imoen.bcs is used for the imoen.cre (the "Imoen" the PC meets in Candlekeep). If patching the joinable "Imoen" creature files, this one should be left out.
Alora*.cres use "alora.bcs" as class script, which additionally has faulty script blocks that would block any mod script blocks that get added via EXTEND_BOTTOM. Class scripts can get deactivated by turning off the AI in the game. To have a standard concerning "override scripts of the NPC have the name of the NPC", it is suggested 1. to patch the alora.bcs as override script and 2. to correct the faulty script blocks (deleting them).

The code for the tp2-patching to achieve all this would look like this:
//Give BioWare NPCs override scripts
COPY_EXISTING_REGEXP GLOB ~^alora[0-9]*\.cre~ ~override~
WRITE_ASCII SCRIPT_OVERRIDE ~alora~
READ_ASCII SCRIPT_CLASS ~Class_Script_Name~
PATCH_IF ( ~%Class_Script_Name%~ STRING_EQUAL_CASE ~alora~ ) //only class script ~Alora~ will be deleted

THEN BEGIN
WRITE_LONG 0x250 0x00000000
WRITE_LONG 0x254 0x00000000
END
BUT_ONLY_IF_IT_CHANGES
COPY_EXISTING ~alora.BCS~ ~override~
REPLACE_BCS_BLOCK ~Modfolder/alora_old.baf~ ~Modfolder/alora_new.baf~ //delete bad blocks
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING_REGEXP GLOB ~^branwe[0-9]*\.cre~ ~override~
WRITE_ASCII SCRIPT_OVERRIDE ~branwen~
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING_REGEXP GLOB ~^faldor[0-9]*\.cre~ ~override~
WRITE_ASCII SCRIPT_OVERRIDE ~faldorn~
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING_REGEXP GLOB ~^garric[0-9]*\.cre~ ~override~
WRITE_ASCII SCRIPT_OVERRIDE ~garrick~
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING_REGEXP GLOB ~^imoen[0-9]+\.cre~ ~override~ // imoen1,2,4,6.CRE but not imoen.CRE
WRITE_ASCII SCRIPT_OVERRIDE ~imoen~
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING_REGEXP GLOB ~^skie[0-9]*\.cre~ ~override~
WRITE_ASCII SCRIPT_OVERRIDE ~skie~
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING_REGEXP GLOB ~^xan[0-9]*\.cre~ ~override~
WRITE_LONG 0x248 0x00000000
WRITE_LONG 0x250 0x00000000
WRITE_ASCII SCRIPT_OVERRIDE ~xan~
BUT_ONLY_IF_IT_CHANGES

//patching der Skripte für die CombatCounter() simulation
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~dplayer3.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~dplayer3.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~dplayer2.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~dplayer2.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~ajantis.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~ajantis.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~alora.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~alora.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~branwen.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~branwen.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~coran.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~coran.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~dynaheir.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~dynaheir.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~edwin.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~edwin.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~eldoth.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~eldoth.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~faldorn.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~faldorn.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~garrick.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~garrick.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~imoen.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~imoen.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~jaheira.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~jaheira.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~khalid.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~khalid.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~kagain.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~kagain.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~kivan.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~kivan.BCS~ ~Modfolder/Z!CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~minsc.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~minsc.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~montaron.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~montaron.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~quayle.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~quayle.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~safana.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~safana.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~sharteel.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~sharteel.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~skie.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~skie.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~tiax.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~tiax.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~viconia.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~viconia.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~xan.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~xan.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~xzar.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~xzar.BCS~ ~Modfolder/CombatTimer_add.BAF~
END
ACTION_IF (NOT FILE_CONTAINS_EVALUATED (~yeslick.BCS~ ~Z!EnemyAlreadySeen~))
THEN BEGIN
EXTEND_BOTTOM ~yeslick.BCS~ ~Modfolder/CombatTimer_add.BAF~
END

With alora_old.baf:

IF
TimeOfDay(DAY)
THEN
RESPONSE #100
Activate(Myself)
END

IF
TimeOfDay(DAY)
THEN
RESPONSE #100
Deactivate(Myself)
END

And the alora_new.baf being an empty file.
Link to comment
I wonder, is it interruptable? If it is, then I guess a cutscene?
Would you explain what exactly interruptable means in this context. I never really understood that. Do you mean the script execution, where all the variables and times are set after throwing the spell could be interrupted before all variables got set?

 

Icendoan: You mean ReallyForceSpell() the "morning" spell? I have little experience with spell actions, does this really use a spell that is memorized?

Link to comment
Guest jastey*

Then it is not useful for the "morning detection" spell casting, since the whole point is about detecting whether the PC has a certain memorized spell available or not.

If it's available, it means the PC rested (i.e. all spells are freshed up). It gets cast, and all variables and timers for possible NPC morning actions get set in the dplayer3.bcs, and can be used as triggers in the NPC's scripts.

Link to comment

Zed Nocear found out, that the detection spell for the "resting detection" is multiplaying itself by exporting and importing the PC. He changed the version of the spell SPIN796.SPL that applies the spell on the PC, so that earlier version(s) will be removed. The download is updated, please make sure you have the current version if you want to use it in your mod.

Link to comment

Some of this sounds interesting. I've had to do my own work arounds for the BG Fixpack, due to the lack of AreaCheck(). Would it be acceptable to include the AreaCheck()/AreaType() 'triggers' in the BG Fixpack with/without totsc? By appearances it looks as if future installs of the same code would do a file by file check and add the needed script blocks if an added area did not have them.

 

However, I do see a potential issue (if there are any areas like the Crooked Crane in BG2). The area script reference should be read and checked to see if it exists prior to assigning a new name, just in case an area should have an existing script that doesn't match the area name. It's simple to do, but every following mod would need to read the script ref and use that, or blindly go with the script matches area name method instead of blindly doing what they saw in the default game. However, I don't remember if any bg1 areas are like the Crooked Crane.

 

Here's an example of what I mean;

COPY_EXISTING_REGEXP GLOB ~.*\.ARE~ ~override~
SPRINT filename ~%SOURCE_RES%~
READ_ASCII 0x94 ~script_name~
//go ahead and write because matching names will still match
WRITE_EVALUATED_ASCII 0x94 ~%SOURCE_RES%~ 
//see if odd named script file exists, if so copy to correct name.
INNER_ACTION BEGIN
ACTION_IF !(~%script_name%~ STRING_EQUAL_CASE ~%filename%~)
	  AND (FILE_EXISTS_IN_GAME ~%script_name%.bcs~) THEN BEGIN
COPY_EXISTING ~%script_name%.bcs~ ~override/%filename%.bcs~
END
END
//read new for rest of patch
READ_ASCII 0x94 ~script_name~ 
/* do the rest of the patch */
BUT_IF_ONLY_IT_CHANGES

Link to comment

Including these checks would be cool! (I hope this doesn't start a discussion about what the scope of a fixpack is, though).

I am sure Zed Nocear would agree to it, too.

 

I know what you mean with the patching, your code is more general. I think I understand what it does. I'll ask you again how I'd have to change the above code to make it as general as yours if I had the time to look at it more closely.

Link to comment
Including these checks would be cool! (I hope this doesn't start a discussion about what the scope of a fixpack is, though).

I am sure Zed Nocear would agree to it, too.

I know how to avoid some of the 'discussions' that might arise.

1) There are things within the game that could be properly done with an area check. (don't have to be, but could be)

2) Provide code as an optional install after all "true fixes" have been installed.

3) Start a public thread about how these are needed for certain mods and that if they were included in the "Fixpack" or in a "Companion to the Fixpack" (which would require being installed second) then other mods could take advantage of the new trigger methods provided.

 

Sounds to me like we've already got all that here. As long as Zed is fine with it, I'll put a copy of it at the 'END' of the Fixpack. If there is still an issue with some people, I've got no problem putting it into a companion mod (distributed with the fixpack)

 

I know what you mean with the patching, your code is more general. I think I understand what it does. I'll ask you again how I'd have to change the above code to make it as general as yours if I had the time to look at it more closely.
When you've got the time, don't hesitate to ask. I may not have the time then, but I'd get back as quickly as I could.

 

I can explain it real simple (as clear as mud even) :laugh: :

1) read the script reference you want to change

2) check to see if it exists

3) if it does not exist assign the name you want

4) if it does exists and doesn't match the name you want, copy the script and give it the name you want. This ensures that any previous code gets carried over to the new script. With one caveat, any mods installed after would need to read the reference value rather than assuming that whatever was previously in that field is correct. All mods should do this, but we are lazy and don't program it.

5) re read the script reference so the new value is fresh in weidu memory

6) do the rest of the patch.

Link to comment

I agree to both issues. It means however, that we must again change the code for Ajantis BG1 mod, MotSC (TWM) and in Tutorial.

 

Maybe this part of planab's code will be more easy to understend in tutorial with small cosmetic changes of variables names:

COPY_EXISTING_REGEXP GLOB ~.*\.ARE~ ~override~
SPRINT area_name ~%SOURCE_RES%~
READ_ASCII 0x94 ~old_script_name~
//go ahead and write because matching names will still match
WRITE_EVALUATED_ASCII 0x94 ~%SOURCE_RES%~ 
//see if odd named script file exists, if so copy to correct name.
INNER_ACTION BEGIN
ACTION_IF !(~%old_script_name%~ STRING_EQUAL_CASE ~%area_name%~)
	  AND (FILE_EXISTS_IN_GAME ~%old_script_name%.bcs~) THEN BEGIN
COPY_EXISTING ~%old_script_name%.bcs~ ~override/%area_name%.bcs~
END
END
//read new for rest of patch
READ_ASCII 0x94 ~script_name~ 
/* do the rest of the patch */
BUT_IF_ONLY_IT_CHANGES

Link to comment

Archived

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

×
×
  • Create New...