Official RPG Codex Discord Server

  1. 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.
    Dismiss Notice

BGScript sucks ass

Discussion in 'Codex Workshop' started by SCO, Dec 12, 2011.

  1. SCO Arcane In My Safe Space

    SCO
    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".
     
    ^ Top  
  2. Alex Arcane

    Alex
    Joined:
    Jun 14, 2007
    Messages:
    6,257
    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?
     
    ^ Top  
  3. SCO Arcane In My Safe Space

    SCO
    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.
     
    ^ Top  
  4. shihonage Subscribe to my OnlyFans Patron

    shihonage
    Joined:
    Jan 10, 2008
    Messages:
    7,157
    Location:
    location, location
    Bubbles In Memoria
    Man, this makes my ShelterScript sound intuitive and accessible.
     
    ^ Top  
  5. SCO Arcane In My Safe Space

    SCO
    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.
     
    ^ Top  
  6. Overweight Manatee Scholar

    Overweight Manatee
    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.
     
    ^ Top  
  7. waywardOne Arcane

    waywardOne
    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.
     
    ^ Top  
  8. SCO Arcane In My Safe Space

    SCO
    Joined:
    Feb 3, 2009
    Messages:
    16,320
    Shadorwun: Hong Kong
    I annoyed Ascension64 about it.
     
    ^ Top  
  9. waywardOne Arcane

    waywardOne
    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.
     
    ^ Top  
  10. Jaesun Fabulous Moderator

    Jaesun
    Joined:
    May 14, 2004
    Messages:
    36,920
    Location:
    Seattle, WA USA
    Torment: Tides of Numenera Divinity: Original Sin 2 BattleTech
    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?
     
    ^ Top  
  11. SCO Arcane In My Safe Space

    SCO
    Joined:
    Feb 3, 2009
    Messages:
    16,320
    Shadorwun: Hong Kong
    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).

    That's Ascension64.
     
    ^ Top  
  12. SCO Arcane In My Safe Space

    SCO
    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.
     
    ^ Top  
  13. Incantatar Cipher

    Incantatar
    Joined:
    Jan 9, 2012
    Messages:
    441
    No effect. Boots of Speed otoh increase movement speed further.
     
    ^ Top  
  14. ghostdog Prestigious Gentleman Arcane Patron

    ghostdog
    Joined:
    Dec 31, 2007
    Messages:
    10,632
    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.
     
    ^ Top  
  15. Grunker RPG Codex Ghost Patron

    Grunker
    Joined:
    Oct 19, 2009
    Messages:
    23,160
    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.
     
    ^ Top  
  16. Piety Shitpostin'

    Piety
    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.
     
    ^ Top  

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