Putting the 'role' back in role-playing games since 2002.
Donate to Codex
Good Old Games
  • Welcome to rpgcodex.net, a site dedicated to discussing computer based role-playing games in a free and open fashion. We're less strict than other forums, but please refer to the rules.

    "This message is awaiting moderator approval": All new users must pass through our moderation queue before they will be able to post normally. Until your account has "passed" your posts will only be visible to yourself (and moderators) until they are approved. Give us a week to get around to approving / deleting / ignoring your mundane opinion on crap before hassling us about it. Once you have passed the moderation period (think of it as a test), you will be able to post normally, just like all the other retards.

BGScript sucks ass

SCO

Arcane
In My Safe Space
Joined
Feb 3, 2009
Messages
16,320
Shadorwun: Hong Kong
Dear blogdex

I have some findings from my research into bgscript from BG2:ToB version.

Following the well known classics for volatile memory variables:
"you can store them, but not perform arithmetic on them"
"you can store them, but not use them as arguments afterwards"
"you can store them, but can't reassign them"

I've went deeper into the rabbit hole and found gems such as:
"you can store them, but they only change in the next AI tick because we though evaluating conditionals seperatly from initiating the actions they guard was cool and setting a variable is a action (duh, you think we're dumb or something?)"

And now am analyzing the triggers (conditionals) themselves and found this:
"We have a NOT operator, only it's not really a operator, but a flag to the Conditional. This wouldn't make a difference if we weren't monkeys and "forget" about using the flag in some of the return values in some conditionals."

But they did and their !Something returns Something most of time (but not all of the time), for some values of "Something".
 

Alex

Arcane
Joined
Jun 14, 2007
Messages
8,750
Location
São Paulo - Brasil
Could the change of the memory only be processed in the next tick for concurrency reasons? Maybe they expected that concurrency was going to be important in the near future? Also could you expand a bit on the not non-operator? What kind of conditionals make it go haywire? Finally, any specific reason you are examining how BG works?
 

SCO

Arcane
In My Safe Space
Joined
Feb 3, 2009
Messages
16,320
Shadorwun: Hong Kong
The actual reason for only executing actions "in the next tick" (actually between them, and "at least after the current tick") is sound.
It's to decouple the execution of actions (some of them can be ongoing, like "follow this object") from the actual AI execution. If some action is still executing (the queue is not empty) it just adds them to the tail of the queue.
This helps in lots of things, probably running the gamut internally from multiplayer, player sync, to (theoretical, since i doubt they did it) multithreading. It probably helps with game logic such as disruption/mouseclick (clear the queue) too.

However, what's annoying me is that the statements that change volatile memory (ie: the only way to affect conditionals), are implemented as Actions - granted they are "instant" actions, which means they don't get added to the queue, but executed directly instead. However they still have to wait until the game is actually trying to add actions to the queue, ie: after the "Conditionals".
This means that for the script to "Actually" use the changes you have to change the variables, stop the AI, and only on the next AI tick use them.

If those statements were ... ahem... "Conditionals", this problem wouldn't exist.
Oh well, i actually need to wait a round to prevent double casting party wide spells so that's ok i guess.



The NOT ("!") has some internal bug in some code paths.
I gathered from reverse engineers wisdom (IESDP), that "Conditionals" (actually they are called "Triggers"), are all a single function (!) with multiple parameters that get ignored if they are not relevant (!!!)
So it's probably a big switch.

Anyway, like any good procedural program they used multiple returns.

It seems bioware either hacked some return because it was advantageous to ignore the ! operatorflag in some code flows but not others, or just plain forgot.

Result: some triggers like "Trigger(N)" say something while not prefixed by ! and say the same thing while prefixed by ! .... except if you actually press a keyboard key or it is the first round.
This is not the only one with these exact symptoms (HotKey(KEY) is the same, there are probably others). So the return(s) that didn't check the flag is probably shared.


I'd like my fucking NOT operator to actually be fucking disjoint.
 

SCO

Arcane
In My Safe Space
Joined
Feb 3, 2009
Messages
16,320
Shadorwun: Hong Kong
It looks like a triumph of the syntax over common sense to me.

Get this, they separated things into Actions and Triggers. "Logically" changing a variable is a "Action", so there it goes. However they need to get executed as soon as possible! They shouldn't be disrupted if the user clicked the mouse!

"I know" says the bioware codemonkey
"Lets create a category of "instant actions" that will be executed directly instead of added to the queue when adding the actions triggered this tick".

Genius. Pity the actions are only really added at the end of the AI tick, not incrementally.
 
Joined
Sep 4, 2009
Messages
3,520
You think that's bad? Now imagine that this is par for the course at most major banking firms and manufacturing facilities that all try to make their own custom solutions to things.
 

waywardOne

Arcane
Joined
Aug 28, 2010
Messages
2,318
So are you in the process of fixing this or is this just nerd butthurt? They were terrible at making use of the code that did work properly.
 

waywardOne

Arcane
Joined
Aug 28, 2010
Messages
2,318
Post an update if it gets fixed; what you're doing sounds like it could be expanded to set party AI based on enemy type even w/o using hotkeys (See vampire, cast NPP; etc) and avoid duplicate castings.
 

Jaesun

Fabulous Ex-Moderator
Patron
Joined
May 14, 2004
Messages
37,241
Location
Seattle, WA USA
MCA
Are you aware of the BG "wrapper" app someone is doing at Spellhold, which in theory could add all of these missing functions you are wanting?
 

SCO

Arcane
In My Safe Space
Joined
Feb 3, 2009
Messages
16,320
Shadorwun: Hong Kong
waywardOne said:
Post an update if it gets fixed; what you're doing sounds like it could be expanded to set party AI based on enemy type even w/o using hotkeys (See vampire, cast NPP; etc) and avoid duplicate castings.

Oh, that's easy (but slow).

Use ChangeAIScript. Make your changed script invariably return to one with the same name as the "AI" script on the directory BG2\scripts (COPY it in the weidu part the compiled script into BG2\scripts).

COPY is needed because ChangeAIScript needs a bcs file and the menu in the character record only displays bs files. But if it's the same prefix, it still shows as selected (even if it's actually using another file) so no problem there.

Anyway, your ChangedAIScript NEEDS to return to the original one, so the only tricky part is if you have to wait more than one turn. You can do with with a local variable, a unconditional increment and a check for the turn.

Avoiding duplicate party wide buffs "seems" like it will be easy if you wait a turn: all of your party members set a variable if they have the party wide scripts (and don't set the variables for the ones that one replaces) then you do this with the new "TriggerOverride" script from TobEx:

Code:
IF//party wide invisibility
  Trigger(MASS_INVISIBILITY_BUFF)
  OR(2)
    !TriggerOverride(Player1, Trigger(MASS_INVISIBILITY_BUFF))
    Detect(Player1)
  OR(2)
    !TriggerOverride(Player2, Trigger(MASS_INVISIBILITY_BUFF))
    Detect(Player2)
  OR(2)
    !TriggerOverride(Player3, Trigger(MASS_INVISIBILITY_BUFF))
    Detect(Player3) 
  OR(2)
    !TriggerOverride(Player4, Trigger(MASS_INVISIBILITY_BUFF))
    Detect(Player4) 
  OR(2)
    !TriggerOverride(Player5, Trigger(MASS_INVISIBILITY_BUFF))
    Detect(Player5)             
  OR(2)
    !TriggerOverride(Player6, Trigger(MASS_INVISIBILITY_BUFF))
    Detect(Player6) 
  Range(LastSeenBy(Myself),0)//it's me!  
THEN
  RESPONSE #100
    Spell(Myself,WIZARD_MASS_INVISIBILITY)
    Continue()
END
This works because if you wait a AI tick, every relevant party member that received the hotkey should have set the variables. And all of them are going to execute the same algorithm: if they have that spell; they will elect the last (i would prefer the first, and skip the rest, but bgscript sucks; duplicating the blocks will not be faster - and one of them will figure out the last is him (if alive anyway).
It's a very simple, very naive distributed programming technique when you have perfect information, but can't elect directly - just run a algorithm that only one can win.

It could be reworked to be much simpler (without the DPT) just by making the last guy in the previous tick to check for the spell save something that will identify.
However, bgscript sucks and i haven't found anything like that. Not the name, nor even save the position(order) on the team of the current guy (or check it).
Actually, SetTokenObject("MASS_INVI",Myself) would probably work...


I could probably put it working tomorrow if i wanted to use globals.

I wish bgscript had masks. I don't like using memory for useless shit like this (and found out triggers are implemented with a list bleh).

Jaesun said:
Are you aware of the BG "wrapper" app someone is doing at Spellhold, which in theory could add all of these missing functions you are wanting?
That's Ascension64.
 

SCO

Arcane
In My Safe Space
Joined
Feb 3, 2009
Messages
16,320
Shadorwun: Hong Kong
BTW, since i'm discussing this: can someone tells me what happens if haste is cast after improved haste?

Does haste replace the improved haste or does it have no effect? Just asking because i'm lazy and someone might know by heart.
 

Incantatar

Cipher
Joined
Jan 9, 2012
Messages
453
Does haste replace the improved haste or does it have no effect? Just asking because i'm lazy and someone might know by heart.
No effect. Boots of Speed otoh increase movement speed further.
 

ghostdog

Arcane
Patron
Joined
Dec 31, 2007
Messages
11,079
Also I suspect that if you have boots of speed it doesn't matter if you cast haste or improved haste, both give you improved haste.
 

Grunker

RPG Codex Ghost
Patron
Joined
Oct 19, 2009
Messages
27,385
Location
Copenhagen
Isn't ToBExtender pretty functional right now? And doesn't it address most of these issues?

I don't know shit about this stuff they just seem to coincide.
 

Piety

Shitpostin'
Joined
May 22, 2009
Messages
1,777
Location
Chicago
Codex 2012 Codex 2016 - The Age of Grimoire Torment: Tides of Numenera
I seem to recall reading an interview once with a BG developer in which he called BGScript an "abomination" and basically said it was hacked together by one guy in like a week. I'm sure at the time he'd have been mortified to think that modders might still be wrestling with his misbegotten ass-baby 13 years later.
 

As an Amazon Associate, rpgcodex.net earns from qualifying purchases.
Back
Top Bottom