Kulyok Posted September 30, 2013 Share Posted September 30, 2013 I encountered a problem with UB, and I think it concerns our romance timers. In short: I believe that our romance timers, like XAROM_TIMER, get inserted where they shouldn't be inserted(for example, UB's Bodhi Hunt game-time timers, not real-time timers), and we're getting a stutter as a result. I think it's a bad thing. (More on the topic here: http://forums.gibberlings3.net/index.php?showtopic=25696 http://forums.pocketplane.net/index.php/topic,28632.msg332830.html#msg332830 ) There will be other mods with SetGlobalTimer command, and more potential compatibility issues. I would suggest getting rid of Gtimes.ids add-on entirely, and just set a variable for each romance's timer(like BGT/Tutu dialogue names), and compile all related files via an EVALUATE_BUFFER. Under no circumstances should our mod replace other mods' timers(and cause serious issues), I believe. If other mods are using this scheme with Gtimes.ids, too: please, reconsider. Link to comment
Kulyok Posted September 30, 2013 Author Share Posted September 30, 2013 (Mike and Kaeloree pointed out that it can be reasonable compiler behavior and my problem can be elsewhere. I'd still say %VARIABLES% are safer than NEW_TIMERS). Will update if I find the solution to my problem elsewhere. If only I had a working save game to check it out! Sigh. Link to comment
cmorgan Posted September 30, 2013 Share Posted September 30, 2013 I'm punting this back to Cam. Recoding the project from (for example) XAROM_TIMER to %XAROM_TIMER% and using EVALUATE_BUFFER is certainly another option; but since he came up with the shortcut, I'd appreciate his input. We use them within dialog files. I will go look and see if we also use them in script files, and compile a list. Link to comment
jastey Posted October 1, 2013 Share Posted October 1, 2013 Highly interested in this, as I use it in script for Ajantis BGII. So far, I didn't even really understood what is going wrong, even less how it can be solved. Link to comment
CamDawg Posted October 1, 2013 Share Posted October 1, 2013 This is going to be the post that contains the long explanation of how symbolic lookups work. If your eyes glaze over, you can skip ahead to the next post where I'll post an actual solution. So, BG2 has a bunch of IDS files that contain various symbolic lookups--racial entries are in race.ids, times in gimes.ids, spell names in spell.ids, etc. If you look at these files, they're lists of paired numbers and text like 1106 CLERIC_MAGIC_STONE (spell.ids) or 104 CARRIONCRAWLER (race.ids) or 7200 ONE_DAY (gtimes.ids). CARRIONCRAWLER is a symbol that can be used in place of the number 104--though it adds a layer of complexity, it makes triggers and actions human-readable. Look at a non-symbolized AI block: IF See(NearestEnemyOf(Myself)) HaveSpell(2302) !Range(NearestEnemyOf(Myself),12) See([2.0.0.1]) THEN RESPONSE #100 Spell([2.0.0.1],2302) END You'd never guess that it's casting dispel magic at PC mages. This is, however, how the engine understands it, which is why we have all of these IDS tables to facilitate human-readable code being compiled into engine-usable code. Let's look at a typical action from action.ids: 115 SetGlobalTimer(S:Name*,S:Area*,I:Time*GTimes) So, SetGlobalTimer takes three parameters. Each parameter begins with a letter to signify the type of input--s for string, i for integer (number), p for point, or o for object--then the name of the parameter, and then an asterisk followed by a lookup table, if appropriate. In this particular case, the parameter provided for the time is designated as I:Time*GTimes--this means the parameter must be an integer, and you can provide a number directly or get the engine to go look up a value from gtimes.ids. When you use an action like SetGlobalTimer("Mytimer","GLOBAL",ONE_DAY) it means nothing to the game sine ONE_DAY is not an integer--this is why when you compile any script with IDS references like this, WeiDU (or whatever you're using to compile) will go to gtimes.ids, look for ONE_DAY, and substitute the numerical value (in this case 7200) instead. If WeiDU can't find the symbol ONE_DAY in gtimes.ids, it will simply insert 0 as a default. These substitutions occur at compile time--if I compile my scripts and then go through and delete the ONE_DAY entry from gtimes.ids, it does not affect my compiled script since it's already using the numerical value. Hold on to this thought. Dialogues, however, never actually compile their actions and triggers. When the engine encounters SetGlobalTimer("Mytimer","GLOBAL",ONE_DAY) during a game dialogue, it looks up the values right then and there. So if I add a dialogue with this trigger and then later delete the ONE_DAY entry from gtimes.ids, it will affect my dialogue. WeiDU will also do its best when de-compiling scripts to substitute symbols to make your uncompiled scripts readable (same when you view a script in NI). So if I decompile a script that has a timer, and the value of the timer is 7200, WeiDU will substitute ONE_DAY instead of 7200 in the baf file. With all this in mind, there are a couple of potential pitfalls. The most common would be depending on an IDS entry that's not necessarily part of the core game. A lot of mods expect shoutids.ids entries, which is not necessarily present in SoA, or even the handful of Fixpack-added entries such as STATE_REALLY_DEAD in state.ids or even the new ETTIN racial entry. It's always handy to have a patched but unmodded install (preferable SoA and ToB) lying around to double-check symbols. If you happen to decompile a script on a game with a custom IDS entries, a potential problem arises--WeiDU will substitute those custom entries as appropriate in your uncompiled script. However, you have no way to guarantee that your players will have those custom entries short of adding them in your mod otherwise they'll get a value of zero instead of your intended value. Link to comment
CamDawg Posted October 1, 2013 Share Posted October 1, 2013 OK, so my previous wall of text aside, the practical problem and its solution. We got a little clever with the romance timer, mainly because I don't think we had EVALUATE_BUFFER when we encountered this problem (or I was just lazy). What we do is add a custom gtimes.ids entry based on the player's seclection of romance timer, e.g. XAROM_TIMER will be added to gtimes.ids with a value of 900 to 5400 depending on the player's choice. The scripts just use the XAROM_TIMER symbol and we compile them directly, so the player's choice gets substituted as the actual timer when WeiDU compiles them. What we should be doing is setting a variable to the selected time, and then using the variable name instead of a XAROM_TIMER in the scripts. (Since the scripts are already being compile against EVALUATE_BUFFER we don't need to add the step. For Xan's stuff we'd replace ACTION_IF ("xantimer" = 1) THEN BEGIN APPEND ~gtimes.ids~ ~3600 XAROM_TIMER~ PRINT @1109 END ACTION_IF ("xantimer" = 2) THEN BEGIN APPEND ~gtimes.ids~ ~2700 XAROM_TIMER~ PRINT @1110 END ACTION_IF ("xantimer" = 3) THEN BEGIN APPEND ~gtimes.ids~ ~1800 XAROM_TIMER~ PRINT @1111 END ACTION_IF ("xantimer" = 4) THEN BEGIN APPEND ~gtimes.ids~ ~900 XAROM_TIMER~ PRINT @1112 END ACTION_IF ("xantimer" = 5) THEN BEGIN APPEND ~gtimes.ids~ ~5400 XAROM_TIMER~ PRINT @1113 END with ACTION_IF ("xantimer" = 1) THEN BEGIN OUTER_SET XAROM_TIMER = 3600 PRINT @1109 END ACTION_IF ("xantimer" = 2) THEN BEGIN OUTER_SET XAROM_TIMER = 2700 PRINT @1110 END ACTION_IF ("xantimer" = 3) THEN BEGIN OUTER_SET XAROM_TIMER = 1800 PRINT @1111 END ACTION_IF ("xantimer" = 4) THEN BEGIN OUTER_SET XAROM_TIMER = 900 PRINT @1112 END ACTION_IF ("xantimer" = 5) THEN BEGIN OUTER_SET XAROM_TIMER = 5400 PRINT @1113 END Next, we just need to track down anything like RealSetGlobalTimer("X#XaFlirtsTalkTime","GLOBAL",XAROM_TIMER) in the scripts and replace that symbol with the variable: RealSetGlobalTimer("X#XaFlirtsTalkTime","GLOBAL",%XAROM_TIMER%) Link to comment
cmorgan Posted October 1, 2013 Share Posted October 1, 2013 That matches my knowledge (since you taught it to me); the original idea was to take advantage of the dialog "just look up the ids" loophole, but then we were talking about an environment where there were relatively few mods that were messing about with this. SmokeTest and DevSin both pushed at my learning curve early on suggesting use of the numbers rather than the IDS entries, too. And the solution is relatively easy to deal with. The key understanding for me is that while the dialog actions/triggers are not messed with, the script ones are - and in each case, someone messing with the .ids entries themselves can throw things off. So if I add a dialogue with this trigger and then later delete the ONE_DAY entry from gtimes.ids, it will affect my dialogue. With the number of folks actually using relatively advanced patching these days, it sounds like the safest bet is to completely dispense with this in dialog files, too. That way even if (when) an install's .ids files get FUBAR'd by some other mod or routine, the numbers are in place. For BG1NPC, I am pretty sure everything gets run through the E_B routine already, but I will check. Link to comment
Mike1072 Posted October 2, 2013 Share Posted October 2, 2013 Thanks for that explanation, Cam. I hadn't realized scripts and dialogues were treated differently in this regard. (Any idea why?) So if I add a dialogue with this trigger and then later delete the ONE_DAY entry from gtimes.ids, it will affect my dialogue. With the number of folks actually using relatively advanced patching these days, it sounds like the safest bet is to completely dispense with this in dialog files, too. That way even if (when) an install's .ids files get FUBAR'd by some other mod or routine, the numbers are in place. There's a point where you have to trust that nobody is going to do something that stupid intentionally. You need to weigh the effort to prevent a problem against the reasonable likelihood of that problem occurring. ONE_DAY is used extensively in BG2 and even a bit in BG1, so if some mod intentionally deletes it, they would also need to clean up the mess. If some mod unintentionally deletes it, well, someone will find the bug soon enough. Chances are nobody would ever bother changing or deleting this identifier because there's not much to gain and a lot to lose. Link to comment
cmorgan Posted October 2, 2013 Share Posted October 2, 2013 I agree, Mike1072 I am weighing the value of leaving dialog states that trigger on (in a dialog file) like this: ++ ~[PC] Why yes, I am using the .ids and creating an entry which works fine in dialog but adds to gtimes.ids and therefore may be subject to screwups because I have added a custom "C-ARANROM" that weidu may try to use or someone could delete and end up with everything running as if the timer is expired.~ DO ~RealSetGlobalTimer("c-aranbg2rom","GLOBAL",C-ARANROM)~ EXIT The reason I am still on the fence is that this is the first report we have had of this in any mod using the .ids entries in this fashion as far as I know, and the materials have been in the field for years now, working in several mods. But safer=better, so It seems smart to change the script ones at the very least. It probably is worth just plain setting aside the time and changing the behavior to match everything, thinking about it. Mass replace could do the job relatively quickly, and we already do this for the area checks for cross platform stuff. Link to comment
jastey Posted October 3, 2013 Share Posted October 3, 2013 Thank you, CamDawg. This was very helpful. Link to comment
CamDawg Posted October 3, 2013 Share Posted October 3, 2013 Thanks for that explanation, Cam. I hadn't realized scripts and dialogues were treated differently in this regard. (Any idea why?) No idea. This was something I discovered for the More Interjections tweak--I could simply re-define IVFPD's value in trigger.ids to InParty's value and all of the dialogues would just work without being touched. Scripts had to be decompiled, patched, and recompiled. And yeah, like Mike1072 said--if another mod wipes one of the expected values from an IDS file (like ONE_DAY) then that's on them. And I don't think BG1 NPC is to blame for the person reporting bugs to Kulyok either. However, it's a good idea in general to eschew the custom IDS entries for straight variables/values; though I'd make it a low priority since the odds of it causing a real-world problem are pretty long. Link to comment
Ardanis Posted October 8, 2013 Share Posted October 8, 2013 Dialogues, however, never actually compile their actions and triggers. When the engine encounters SetGlobalTimer("Mytimer","GLOBAL",ONE_DAY) during a game dialogue, it looks up the values right then and there. So if I add a dialogue with this trigger and then later delete the ONE_DAY entry from gtimes.ids, it will affect my dialogue. Sounds like a bug to me. Link to comment
Recommended Posts
Archived
This topic is now archived and is closed to further replies.