Skip to content

SPLSTATE.ids and OpCode 326 help?

FailGeekFailGeek Member Posts: 50
Hey, I'm trying to make a kit that causes an additional effect if the target is under a unique status, but I can't seem to get it to work. What I've currently done using NearInfinity is:

1) Added a new line to SPLSTATE.ids (currently #1000)

2) Created a spell to use OpCode 328 to apply the State #1000 on the target for a 60 second duration.

3) Created another spell that uses OpCode 326 using Paramater 2 - 76 (SPLSTATE = specified value) and Paramater 1 - #1000 to cast yet another spell on the target if they have the custom state.

For some reason Step 3 isn't triggering if I use the added state. It works if I use any of the existing states, but stops working if I use the one I added to SPLSTATE.ids. Am I just not understanding how these OpCodes are supposed to interact, or is there an issue with OpCode 326 and additions to the ids file?
«13

Comments

  • GrammarsaladGrammarsalad Member Posts: 2,582
    ...it is possible that splstate.ids is hardocoded to not take custom entries. As far as I understand, this was not the case pre 2.0, which makes me think that if so, this is an oversight and should be reported to beamdog. Before doing so, however, perhaps it would be best to try a line below 255 (I think? Just try the very first blank line as a test).

    Oh, I seem to recall it being necessary to add certain text for every line up to the line that you are using. So, if you used line 1000, you would need to fill in all lines before that...It was a post on gibberlings regarding the new opcodes.. Anyway, to test, first try just using the very first available line
  • FailGeekFailGeek Member Posts: 50
    @Grammersalad

    Okay, it works if the unique splstate is < 255, which is annoying because I thought the upper bound of the ids file would be higher and makes future proofing the mod against patches and newer mods less possible but oh well. Thanks for the help!
  • GrammarsaladGrammarsalad Member Posts: 2,582
    FailGeek said:

    @Grammersalad

    Okay, it works if the unique splstate is < 255, which is annoying because I thought the upper bound of the ids file would be higher and makes future proofing the mod against patches and newer mods less possible but oh well. Thanks for the help!

    I could have sworn there was no upper limit... I'm seriously considering putting in a request for this
  • FailGeekFailGeek Member Posts: 50

    I could have sworn there was no upper limit... I'm seriously considering putting in a request for this

    Yeah, I just tested it with State #256. So there's around 120 slots left in the ids file between 126 WIZARD SHIELD and 249 PRONE (and 3 spare slots between 117 FLAMING FISTS and 120 PROTECTION_FROM_MAGICAL_WEAPONS which I consider a really random place for there to be a spot).
  • kjeronkjeron Member Posts: 2,367
    I can only assume its guess and check right now.
    Some numbers work, some numbers don't, but its not capped at 256.

    1000 does not work with the opcodes but does work with a script check.
    100000 works with both the opcode and script checks.
    1024 always returns true for both opcode and script checks, without setting it.
    GrammarsaladFailGeekGalactygonCrevsDaak
  • GrammarsaladGrammarsalad Member Posts: 2,582
    Hmmmm, I wonder if there is a pattern.

    1024 is... familiar.

    I wonder about 512, 256, 128, 64, 32, 16, 8, 4, 2, 1
    rapsam2003CrevsDaak
  • FailGeekFailGeek Member Posts: 50
    kjeron said:

    I can only assume its guess and check right now.
    Some numbers work, some numbers don't, but its not capped at 256.

    1000 does not work with the opcodes but does work with a script check.
    100000 works with both the opcode and script checks.
    1024 always returns true for both opcode and script checks, without setting it.

    So knowing there's no upper bound is good. Just wishing there's a way for it to be consistent. Good work!
    Grammarsalad
  • GrammarsaladGrammarsalad Member Posts: 2,582
    Yeah, line 100000!
  • GrammarsaladGrammarsalad Member Posts: 2,582
    I am going to abuse the spit out of this feature!

    One can have more than one state at a time, yes?
  • kjeronkjeron Member Posts: 2,367

    One can have more than one state at a time, yes?

    Yes.

    The only limitation to stacking them involves its interaction with opcode 335(Seven Eyes):
    Along with doing several other things, 335(Seven Eyes) sets the same States as opcode 328, however, Opcode 335 will not apply at all if the spell state is already set. Not an issue so long as you do not use the same State with both Opcodes 328 and 335.

    Extra:
    The 7EYES.2DA does not require using the Seven Eyes opcode. Any State defined in 7EYES.2DA will provide constant immunity(with feedback) to its list of opcode/resrefs while the state is set, regardless of whether it was set with opcode 328 or 335.
    GrammarsaladFailGeek
  • chimericchimeric Member Posts: 1,163
    I came across this topic as I was looking for a way to engineer my own spell. What I don't understand about his method is how to apply several state checks. I mean, I can put a new state in SPLSTATE and then have Opcode 326 look for that state - okay; but what if I need other conditions? Say, the state is called DUMB. I also want undead to be excluded as a target, even if they are DUMB. In the same Opcode 326 effect I can pick either !Undead from GENERAL.IDS or my DUMB state. How do I make both conditions apply? Do I make a further spell and put in the the "Resource" field so that this second spell will be cast only if the first check is passed, and so on? Successive if not simultaneous checking?

  • GalactygonGalactygon Member, Developer Posts: 412
    It's actually news to me that SPLSTATE.ids is not capped. That's really awesome!

    @Avenger_teambg I remember you mentioning there are reserved ids values for hardcoded states that cannot be set. Do you know what those are? It might explain why setting some ids values might not work.

    CrevsDaak
  • Avenger_teambgAvenger_teambg Member, Developer Posts: 5,862
    There are only 256 spell states. Anything higher will not work as expected. This may include crashes.
  • Avenger_teambgAvenger_teambg Member, Developer Posts: 5,862
    edited July 2016
    chimeric said:

    I came across this topic as I was looking for a way to engineer my own spell. What I don't understand about his method is how to apply several state checks. I mean, I can put a new state in SPLSTATE and then have Opcode 326 look for that state - okay; but what if I need other conditions? Say, the state is called DUMB. I also want undead to be excluded as a target, even if they are DUMB. In the same Opcode 326 effect I can pick either !Undead from GENERAL.IDS or my DUMB state. How do I make both conditions apply? Do I make a further spell and put in the the "Resource" field so that this second spell will be cast only if the first check is passed, and so on? Successive if not simultaneous checking?

    You need to create a custom spell protection (splprot.2da) entry.
    1. make sure you have existing splprot entries for your 2 simple states (undead already has this).
    2. build a new entry with the line combination code (0x103)

    So, your splprot.2da line will look like this
    DUMB [your dumb spell state check]
    NOTDUMB [your dumb spell state check negated]
    DUMBORUNDEAD 0x103 1 [your code for dumb]
    DUMBANDUNDEAD 0x104 2 [your code for not dumb]

    Alternatively, if this doesn't work out, you can put an opcode 326 into the spell applied by opcode 326, that will further narrow the target specification.
    CrevsDaakc4_angel
  • AquadrizztAquadrizzt Member Posts: 1,065
    edited August 2016
    @Avenger_teambg , is it possible to use opcode 328 as part of an item equipment effect?

    For example, if I have spell state "Armored Caster", could I add a check to a piece of armor that would only cast a spell (which disabled arcane casting) on creatures who equip the armor without the Armored Caster state?
    Post edited by Aquadrizzt on
    Anprionsa
  • kjeronkjeron Member Posts: 2,367
    edited December 2017
    Some interesting finds regarding spellstates:
    Spellstates 256-287 are set by STATE.IDS values.
    Spellstates 288-6239 are set by STATS.IDS values, with some exceptions:
    * Current Bardsong duration modifier is stored in Spellstates 1808 - 1823, (Default Value = 100).
    * Current Bardsong is stored in Spellstates 3968-4031, Default = "BARDSONG"
    * Current Backstab is stored in Spellstates 4032-4095, Default = (emtpy) / 0
    * Opcode 332 Stores its various damage type modifiers in Spellstates 4272 - 4447.
    * Opcode 346 Stores its various Save vs School modifiers in Spellstates 4448 - 4639.
    Spellstates 6240+ are dependent on the game campaign/version, read directly from specific offsets of the EXE. Pattern is 32(set) - 160(emtpy) - 32(set), and repeats semi-consistently up to at least 32767.
    These are all a one-way influence, they will set the spellstates, but the spellstates have no effect on the value used by them if you were to set them manually through opcode 328/335. Two partial exceptions are 262(STATE_FROZEN_DEATH) and 263(STATE_STONE_DEATH), which will generate the character-color overlay associated wit their death type, ice/blue and stone/beige.

    I still have not found any matches for these 3 STATS:
    • 61 IDENTIFYMODE
    • 146 CRITICALHITBONUS
    • 188 SUMMON_DISABLE_ACTION
    Or for these 64 Splstates:
    1664 - 1695 (These appear to be the old location of STATS LEVEL2 and LEVEL3.
    4224 - 4255 (I don't know why this gap exists)


    Some uses I've thought of so far:
    A Bitwise STAT check method for scripts, for example:
    CheckSpellState(Myself,3680) // This will check just the first bit of ExtraProficiency20 stat, useful if you are setting the latter bytes for other purposes.
    By adding an entry for spellstates 262 and 263 to 7eyes.2da, you can prevent Frozen and Stoned creatures from shattering.
    • An easy way to do this is to just block the 2 exploding deaths that they trigger, while letting anything else through:
      APPEND ~7EYES.2DA~	~FROZEN  262  %strref%  13*0x80~
      APPEND ~7EYES.2DA~	~STONED  263  %strref%  13*0x40~
    • %strref% is the feedback string that will be displayed whenever they would have exploded, so it should be something informing "Ineffective".
    • This still allows any other direct "Death" effect to kill them as it normally would, including dropping their inventory. This also includes using debugs "Ctrl+Y".
    • Cold damage is tricky though, because when it overkills it applies both the frozen and exploding_frozen deaths together, the exploding slips through before the spellstate is registered, but there is still a way to prevent it. Manually applying the spellstate for an instant after any cold damage is dealt:
      COPY_EXISTING_REGEXP	~.*\.\(spl\|itm\)~	override
      	LPF	CLONE_EFFECT
      		INT_VAR
      			match_opcode = 12	// Damage
      			match_parameter2 = (2 << 16)	// Cold
      			match_timing = 1	// Instant
      			opcode = 328
      			parameter2 = 262
      			dicenumber = 0
      			dice_size = 0
      			timing = 0
      			duration = 0
      			special = 1
      		STR_VAR
      			insert = ~below~
      	END
      	LPF	CLONE_EFFECT
      		INT_VAR
      			match_opcode = 12	// Damage
      			match_parameter2 = (2 << 16)	// Cold
      			match_timing = 4	// Delayed
      			opcode = 328
      			parameter2 = 262
      			dicenumber = 0
      			dice_size = 0
      			timing = 3
      			special = 1
      		STR_VAR
      			insert = ~below~
      	END
      BUT_ONLY

    • It's not necessary to add these spellstates to SPLSTATE.IDS, and they work in all 2.x games and v1.4 IWDEE. However, I think 7EYES.2da does not by default exist in the BG series, so it will need to be imported from IWDEE.
    • None of this has any effect on preventing party members from getting kicked from the group when they are stoned/frozen.
    A far simpler way to prevent poison from getting past Mirror Image than I previously posted elsewhere:
    APPEND ~7EYES.2DA~	~MIRROR_IMAGE 286  %strref%  25~
    No more poison(effect) getting past Mirror Image.

    A way to fake a STATE without setting it, such as for a Sightless creature, which should be immune to Blindness, but also immune to spells that require sight (such as IWDEE Color Spray, which only checks against STATE_BLIND).
    • By permanently setting SPLSTATE 274 on such a creature, and using opcode 324(Doesn't work for SPLPROT, only through 7eyes or scripts.) with a SPLSTATE=274 check in Color Spray, it could catch both naturally sightless and the unnaturally Blind.
    • Scripts would still check for STATE_BLIND when looking to remove Blindness, but could use SPLSTATE 274 to find valid targets for spells such as Color Spray.
    • This could already be done by adding a custom SPLSTATE for BLINDNESS and updating every resource that applies or removes it to account for it as well, but as SPLSTATE slots are limited, there is no need to waste them where its not necessary. It could not be done reliably for STATES which can end prematurely, such as SLEEPING/CHARMED/MIRRORIMAGE/INVISIBILITY, so they now have this option.
    Post edited by kjeron on
    AquadrizztGrammarsaladArunsun
  • c4_angelc4_angel Member Posts: 35
    @kjeron
    Hello kjeron, about the used SpellState by system beyond 6240, I make a test in my BG2EE v2.3.67.3.
    I cannot follow the pattern you mentioned in G3 forum or here, and I'm not familier with the EXE, so I'm not sure my idea is correct.
    The idea is:
    Repeatly EXTEND the following script block to DPLAYER3.bcs, then start a new game and save, get the saved variables from BALDUR.gam in a txt file.
    IF
    CheckSpellState(Myself,%x%)
    !Global("%x%","Global",1)
    THEN
    RESPONSE #100
    SetGlobal("%x%","Global",1)
    Continue()
    END

    Where x is 6240 to 32767.

    The resault is in the attached file. But I cannot conclude any pattern from it, maybe you would like to help me. Thanks.
  • kjeronkjeron Member Posts: 2,367
    The first set:
    6240 - 6271 (32):  6243, 6246, 6247, 6249, 6251, 6252, 6254, 6255, 6259, 6263
    6272 - 6431 (160) : (none)
    6432 - 6463 (32):  6433, 6435
    The first (32) represents the hex value 0x0088DAC8.
    The second (32) represents the hex value 0x0000000a (and has always shown this value within consistent sets as far as I've seen).
    Each of those (32)'s corresponds to a 4-byte section of the EXE, a different value in the EXE will alter which of those 32 spellstates get set. Each different version(2.0, 2.1, 2.2, 2.3, etc..) of each game that I could test has had different values, though BGEE(without SoD) and BG2EE did share some within the same version, SoD and IWDEE did not.

    the next set:
    6464 - 6495 (32):  6470, 6472, 6473, 6474, 6476, 6477, 6478, 6479, 6483, 6487
    6496 - 6655 (160) : (none)
    6656 - 6687 (32):  6657, 6659
    and the next:
    6688 - 6719 (32):  6690, 6692, 6693, 6696, 6697, 6698, 6700, 6701, 6702, 6703, 6707, 6711
    6720 - 6879 (160) : (none)
    6880 - 6911 (32):  6881, 6883
    But the pattern is not always consistent, such as the next section:
    6912 - 7231 (320): (none)
    7264 - 7295 (32): 7234, 7235, 7236, 7237, 7241, 7244, 7246, 7251, 7255
    7296 - 7455 (160): (none)
    These irregular sections were usually present in the EXE as well - the pattern would break in both places.

    Then it resumes again:
    7456 - 7487 (32): 7458, 7560, 7461, 7464, 7465, 7466, 7468, 7469, 7470, 7471, 7475, 7479
    7488 - 7647 (160): (none)
    7648 - 7679 (32): 7649, 7651
    
    7680 - 7711 (32): 7682, 7684, 7685, 7688, 7689, 7690, 7692, 7693, 7694, 7695, 7699, 7703
    7712 - 7871 (160): (none)
    7872 - 7904 (32): 7873, 7875
    Grammarsalad
  • c4_angelc4_angel Member Posts: 35
    kjeron said:


    Each of those (32)'s corresponds to a 4-byte section of the EXE, a different value in the EXE will alter which of those 32 spellstates get set. Each different version(2.0, 2.1, 2.2, 2.3, etc..) of each game that I could test has had different values, though BGEE(without SoD) and BG2EE did share some within the same version, SoD and IWDEE did not.

    So in general, costum spellstates (beyond 6240) are not reliable by now, unless set groups (large enough) of usable spellstates for each version of each game. That's a sad story...But thank you anyway.

  • argent77argent77 Member Posts: 3,431
    Just a note, according to a dev note from this feature request we can't expect to have more than 256 explicit spell states.
    Grammarsalad
  • c4_angelc4_angel Member Posts: 35
    argent77 said:

    Just a note, according to a dev note from this feature request we can't expect to have more than 256 explicit spell states.

    Oh......
  • The user and all related content has been deleted.
  • kjeronkjeron Member Posts: 2,367

    1) Should that be 3712 instead of 3680? In your attached image above it looks like 3680 is for ExtraProficiency19.

    The hex number on left is the first number of that row, the decimal number on right is the next number after that row. 3680 is the first number after Extraprof19, and the first number of Extraprof20. It might not be the best way to display it, I just needed a quick reference of both decimal and hex.

    2) Theoretically, if you could patch all scripts that check for the Detectable Spells stats in ExtraProficency2 through ExtraProficiency19 to instead check for the spellstate associated with their first bit, then all of the upper bytes of all of those proficiencies would be in play to use for other purposes. That's 456 stats to use with bitwise checks. I know a mod that could make very good use of those bits...

    Most of the current Detectable Spells would be better off using actual Spellstates, as they are just Boolean values, and they would more efficiently support multiple sources of the same stat.
    The extraprof's would require either unique sources for each stat, or one bit per source, since adding the same bit from two sources would equal the next bit, not the intended bit. Obviously this isn't always a loss, as this behavior has been quite useful for determining how many weapons are equipped, but that is more an exception than the norm. The other extraprof's would be better spent on stats that need actual values, rather than just true/false.
    It does enable being able to better detect the default proficiency stats, either because their upper bits are being used through "Increment" effects, or because they are dual-classed and have "original class" proficiency values, each of which screw up the CheckStat trigger.
  • [Deleted User][Deleted User] Posts: 0
    edited December 2017
    The user and all related content has been deleted.
  • kjeronkjeron Member Posts: 2,367

    Also: does this mean we can use opcode 328 to decrement proficiencies??? I've got something cooking that needs a spellstate to be set, and then later un-set. I was going to use somethign in the 4th byte of ExtraProf20, per my usual, but I realized I don't have the ability to zero it out again (short of opcode 337 which would mess up other stuff). But instead of using opcode 233 to increment ExtraProf20 by (4 <<24), maybe I could use opcode 328 to set Spellstate 3707, and then later undo it...? (Granted I could also just use a Spellstate, but I've had that bit reserved for this for a while.)</p>

    No, the Stats set Spellstates, but the Spellstates do not influence those Stats.
  • [Deleted User][Deleted User] Posts: 0
    edited December 2017
    The user and all related content has been deleted.
  • kjeronkjeron Member Posts: 2,367
    Those two are enough, but I would check all 3 bits of the proficiency each time just because, and necessary if you are taking proficiency up to 7 points anyway:
    IF ~
    	CheckSpellState(Myself,2240) 
    	CheckSpellState(Myself,2241)
    	!CheckSpellState(Myself,2242)
    ~ THEN REPLY @...
    Without the last, it would return true on both 3 and 7.
    Just always negate the check for bits you don't need, don't omit them.
    Checking '1' would need:
    IF ~
    	CheckSpellState(Myself,2240) 
    	!CheckSpellState(Myself,2241)
    	!CheckSpellState(Myself,2242)
    ~ THEN REPLY @...
    1= 1, 0, 0
    2 = 0, 1, 0
    3 = 1, 1, 0
    4 = 0, 0, 1
    5 = 1, 0, 1
    6 = 0, 1, 1
    7 = 1, 1, 1

    Still better than the 6-8 CheckStat()s needed for dualclasses.
    [Deleted User]
  • [Deleted User][Deleted User] Posts: 0
    edited December 2017
    The user and all related content has been deleted.
  • kjeronkjeron Member Posts: 2,367
    edited January 2018
    @subtledoctor
    The issue is with SPLPROT, it can only detect the first 255 spellstates when they are set by opcode 328.
    It can detect higher spellstates only when they are set indirectly through by other Stats(such as opcode 233 in this case).

    This limitation is exclusive to SPLPROT (edit - and Opcode 335*). The CheckSpellState() script trigger and the 7EYES.2da spellstate checks can check higher spellstates set either by opcode 328 or indirectly through Stats.

    *(Opcode 335 has no effect if it detects that it's specified spellstate is already set).
    Post edited by kjeron on
  • The user and all related content has been deleted.
Sign In or Register to comment.