Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

New Premium Module: Tyrants of the Moonsea! Read More
Attention, new and old users! Please read the new rules of conduct for the forums, and we hope you enjoy your stay!

Getting the most out of Opcodes 318 and 177(EFFs).

kjeronkjeron Member Posts: 2,130
Apparently, Opcode 318 is able to block EFF files based on their parent resource field, which I only fully realized after suggesting using it as such here.

Easily Suppressing Arcane Spell Failure:

Patch all items to disable wizard spell casting through an external EFF:
COPY_EXISTING_REGEXP ~^.+\.itm$~ override
	LPF ALTER_EFFECT
		 INT_VAR
			match_opcode = 145
			match_parameter2 = 0
			match_timing = 2
			opcode = 177
			parameter2 = 2
		STR_VAR
			resource = (EXTEFF)
	END
BUT_ONLY
CREATE EFF ~(EXTEFF)~
	WRITE_SHORT	0x10 145
	WRITE_LONG	0x2c 100
	WRITE_EVALUATED_ASCII	~(ARCFAIL)~

Then add the following effect to any CLAB/Feat/etc... that you want to ignore arcane spell failure from armor:
opcode=318, target=2, timing=9, probability1=100, resource = (ARCFAIL). Alternatively, create a separate EFF for each armor tier (ARCFAIL1, ARCFAIL2, ARCFAIL3, etc...), and grant immunity to only those tiers that you want them to ignore. Could work just as well for casting failure % instead of disabled casting.

Accurately granting immunity to just one form of an opcode:

For example: Opcode 39 (Sleep). It is used for: Sleep, Unconsciousness, Knockdown, Hopelessness, and Nausea(Poison).
So:
  • Take all related effects in every sleep spell and move them to external EFF files, giving them all the same parent resource (EFFECT_SLEEP). Most of these spells could share EFF's, as the variations (saving throws, min/max hd/level, magic resistance, power, probability, etc...) would be put in opcode 177, not the EFF.
    The EFF file would mainly have: Opcode, parameter1/2/3(as appropriate), resource1/2/3(if necessary), special, probability1=100, parent_resource=(EFFECT_[TYPE]). All other fields would be zero/empty.
  • For creatures that should be immune to "Sleep", replace Opcode 102/Parameter2=39 (Immunity to effect: opcode 39) with the following effect:
    opcode=318, target=2, timing=9, probability1=100, resource = (EFFECT_SLEEP).
  • Do the same for Unconsciousness, Knockdown, Hopelessness, and Nausea(Poison).
    Note: Opcode 39 is still bugged some of in the v2.5 betas (and the v2.5 IWDEE release, though significantly less so), so I advise against testing this specific one in the beta patches.
  • The undead rings, for example, would end up with:
    opcode=318, target=2, timing=9, probability1=100, resource = (EFFECT_SLEEP). opcode=318, target=2, timing=9, probability1=100, resource = (EFFECT_UNCONSCIOUS). opcode=318, target=2, timing=9, probability1=100, resource = (EFFECT_HOPELESS). opcode=318, target=2, timing=9, probability1=100, resource = (EFFECT_POISON). This way they would remain vulnerable to knockdown, such as from Wing Buffet.
  • Similarly, the EFF's for any effects (even damage) that operate through poison (Stinking Cloud, Cloudkill, Poison) would use the (EFFECT_POISON) parent resource.
    While items that grant Poison Immunity would just use:
    opcode=318, target=2, timing=9, probability1=100, resource = (EFFECT_POISON).No complication with Disease and Poison dealing the same damage type, or needing to list every spell individually with opcode 206.
  • Most every related spell would share the same EFF files, since all variation will be in the opcode 177 effect that calls them (saving throws, min/max hd/level, magic resistance, power, probability, etc...), not in the EFF (these fields should be left blank/zero in the EFF). Two sleep spells would use mostly the same EFFs, while a color spray would use another batch of EFF's (for unconsciousness). Some effects would have extras or alternates (mostly visual/audio/lighting effects for different spells).
  • Because all "Display String" effects would use the same parent resource for a given purpose, there would be no need to look up string references for each game, or make sure every variation is blocked when granting immunity. Just select the EFF with the correct string for use in a spell, or block all appropriate variations with opcode 318 when granting immunity.
Limitations:
  • EFF's called through opcodes 248, 249, and 272 would have to remain separate from these.
  • Opcode 337 (remove effects by opcode) would falter against these, but all other effect removal would continue to work as they currently do
  • Unlike opcode 337, direct effect removal effects (cure sleep, remove paralysis) do detect those effects in external EFF files.
  • Spell school/type protection removal would still look at the school/type in opocde 177, not the EFF.
  • Opcode 321 would still remove effects based on the parent resource of opcode 177, not the custom one defined in the EFF.
  • Deflection/Reflection would not change, with the exception of opcode 198 (reflect specified effect), which was never really viable specifically because these opcodes have multiple purposes.
  • This could be a small(addition) for some effects or require complete(replacement) overhaul for others.

SPLPROT based equipped effects:

On the item:
opcode 318, target=1, parameter1/2=(SPLPROT), timing=2, resource=(CUSTOM)
opcode 177, target =1, timing=2, resource=(EXTEFF)
EXTEFF: opcode/parameters=(whatever), parent resource=(CUSTOM)
The (SPLPROT) should be a match against anyone who should not get the effect.
The (SPLPROT) will only update when the item is equipped (same as opcode 177), so it would only be useful for mostly-static checks.

For example, you could properly restrict the Wizard Slayer from all magical weapons, then grant them an enchantment level equal to their proficiency level with any weapon they use (with or without the bonus to hit/damage). Maybe even a THAC0 bonus for zero-proficiency weapons so to offset the non-proficiency penalty so they retain a non-magical option against PfMW.
This specific idea would take a LOT of SPLPROT entries (dual-class mechanics force using a bit-wise check for proficiency), but they are not particularly in limited supply like SPLSTATEs. When dual-wielding, it would apply to all weapons of the same category, as the relative opcode(345) can't be more selective than that, and the +hit/damage can't be selective at all.

Or, if you were doing some type of 3E conversion:
Full Plate:
opcode 318, target=1, parameter1/2=(Armor Proficiency>2), timing=2, resource=(CUSTOM)
opcode 177, target =1, timing=2, resource=(EXTEFF1)
opcode 177, target =1, timing=2, resource=(EXTEFF2)
opcode 177, target =1, timing=2, resource=(EXTEFF3)
EXTEFF1: opcode=278, parameter1=~-6~, parent resource=(CUSTOM) //THAC0
EXTEFF2: opcode=44, parameter1=~-3~, parent resource=(CUSTOM) // Strength
EXTEFF3: opcode=15, parameter1=~-3~, parent resource=(CUSTOM) // Dexterity
// Armor Check Penalty for non-proficiency with armor
// SPLPROT could either be for an actual proficiency stat, re-purposed for Armor, or SPLSTATEs for each armor tier.

semiticgodAquadrizztGrammarsaladArunsunGalactygonLuke93Raduziellolien
«1

Comments

  • subtledoctorsubtledoctor Member Posts: 11,460
    edited May 2018
    Very nice.
    kjeron said:

    Easily Suppressing Arcane Spell Failure:

    Patch all items to disable wizard spell casting through an external EFF
    If someone wants to see a working example of this, I have published a little meta-mod that moves arcane casting disabling into .EFF files, letting you use different methods to get around it and give a kit armored casting:

    https://github.com/UnearthedArcana/armored_casting

    This puts the opcode 145 effects into three different .EFF files (one each for light/medium/heavy armors), and adds .EFF/.SPL files that provide immunity against each of the 145 effects. So you can:

    - Apply a spell in your kit's CLAB table that protects you against the .EFFs. This is how the Magus works in Tome & Blood.

    - Add protection via 318 or 177 in the armor's .ITM file, ahead of the spell-disabling effects (LPF ADD_ITEM_EQEFFECT INT_VAR insert_point = 0 ...). This lets you carve out a whole class of users for any particular items you want to patch. This is how bards can cast in leather armor in Might & Guile. And because both mods use this function to convert the effects to .EFFs, they are completely compatible. (If anyone wants to make a kit with some level of armored casting, feel free to use this.)

    As you can see in kjeron's post, the further possibilities - and opportunity for fine-tuning - are pretty endless.

    Post edited by subtledoctor on
  • subtledoctorsubtledoctor Member Posts: 11,460
    edited May 2018
    kjeron said:

    There are at least a few other opcodes that utilize this anti-stacking mechanism, so if you do ever find it not working, try switching to (parent_resource_type ="None/Item") and Opcode 318.

    Unfortunately, for some reason neither 206 nor 318 is blocking my new .EFFs...




    Eh, I'm too tired to debug it now. I'll look at it again tomorrow...

    Oh, and the 172 effect is indeed necessary. Spells added via these .EFFs are added permanently. Could be something in the nature of the wizard spellbook. I think 171 can be done with a duration for innate abilities...

  • kjeronkjeron Member Posts: 2,130
    I can't see anything wrong in the screenshots, but I know it works with opcode 171.

    Though it shouldn't be the cause - you should alter opcode 318 to use timing mode 9, otherwise it will be removed by the various "Limited Effect" removals (death, export/pregen, Ctrl+R, opcode 17/BIT17[param2]).

  • subtledoctorsubtledoctor Member Posts: 11,460
    edited May 2018
    I can't get it to work at all.
    - 206/timing 9 at level 1 => the EFF is not blocked, grants the spell when it should not
    - 318/timing 9 at level 1 => the EFF is not blocked
    - 318 in the item ability, preceding the EFF => the EFF is not blocked
    - 326 in the item ability instead of 177, casting a spell with 171 => the 214 item effect doesn't pick it up

    The only way I've gotten it to work is via 335. And that doesn't work on the 2.5 patch.

    Permanent 206 against an EFF works for sure when the EFF is an equipping effect... the armored casting mod I linked to earlier has been thoroughly tested.

    Of course this is all going through an item ability. Maybe this would work via a spell, but there's something about item abilities that makes such EFFs unblockable? Is it simulating ReallyForceSpell, or something like that? Isn't that why casting spells from scrolls is uninterruptible? Maybe this is related.

    Last test, I'll see if the EFFs can be blocked when triggered by a spell instead of by an item. If that doesn't work I'm giving up.

  • kjeronkjeron Member Posts: 2,130
    @subtledoctor I think I found the problem - you have to capitalize all letters in the parent resource field of the EFF file for it to be blocked. It's the same issue as opcode 256.

    * NI always shows (and saves) the parent resource field as capitalized (reason I didn't catch in it screenshots).

    lolien
  • subtledoctorsubtledoctor Member Posts: 11,460
    edited May 2018
    *smacks head*

    I think I actually knew that, or at least read it somewhere. It sounds familiar anyway. Good catch, thanks!

    EDIT - yup, it works now. :smiley:

    Post edited by subtledoctor on
  • subtledoctorsubtledoctor Member Posts: 11,460
    Now the big question is: is it worth the trouble to completely externalize the spellcasting system, making everyone spontaneous casters, and do a big 3.5E or 5E conversion mod?

    Or, alternatively, only do that for bards?

  • subtledoctorsubtledoctor Member Posts: 11,460
    edited May 2018
    Btw here is another example of cool stuff you can do with 318/177: give someone an extra saving throw to avoid the effects of a spell effect.

    The best-known example is IWDEE's Evasion ability that lets thieves avoid damage form Fireballs. But it can be extended to different cases. Turn various immunities or resistances into an extra chance to save. Give wizard specialists an extra saving throw against spells in their own school. Give bards an extra saving throw against sound-based attacks. Etc.

    Post edited by subtledoctor on
  • Luke93Luke93 Member, Mobile Tester Posts: 1,299
    @kjeron

    I have a question (let's consider Suppressing Arcane Spell Failure as an example): what is exactly ~ARCFAIL~? An ITM or a SPL (can't be an EFF for sure...)?

  • subtledoctorsubtledoctor Member Posts: 11,460
    edited January 2019
    It's the nonexistent .SPL resource that the .EFF file is masquerading as.  The EFF doesn't have to have the same filename as the .SPL resource in its parent resource field... I just always do that for the sake of my own sanity.  The parent resource written in 0x94 of the .EFF file.  (The spoilered code in the first post leaves out the offset for the WRITE_EVALUATED_ASCII command... also, it can simply use WRITE_ASCII if the content is not a variable.)

    <a href="https://github.com/UnearthedArcana/armored_casting/blob/master/d5_armored_casting.tpa">See here</a> for a working implementation of this, specifically note "d5arcal," "d5arcac," and "d5arcap."

    EDIT - what's going on with the forum post formatting lately...?

  • Luke93Luke93 Member, Mobile Tester Posts: 1,299
    @subtledoctor

    OK, thanks for clarifying, I think I understood now......
    So, it's correct that resource is non-existent....

    Now, speaking of your spell evasion:
    1) I noticed that the parent resource (located at offset 0x94) of your EFFs is a SPL, while the resource (located at offset 0x30) of your 318 effects is an ITM -----> this doesn't seem to be a problem, but wanted to point it out in any case.....

    2) You should tweak your code and remove opcode #318 (param1 = 0, param2 = 0) ----> you don't need this since you already have opcode #318 (param1 = STATE_NORMAL, param2 = STATE bit_eq specified value). Put here the Save vs. Breath and you're done :)
    Otherwise, if you keep both this and EA >= ANYONE (Save vs. Breath), it may happen that a HELPLESS creature takes damage (correct) upon a successful Save vs. Breath (weird)

    Tl;dr ----> EA >= ANYONE returns true even if the targeted CRE is HELPLESS ;)

  • kjeronkjeron Member Posts: 2,130
    Luke93 said:
    @subtledoctor OK, thanks for clarifying, I think I understood now...... So, it's correct that resource is non-existent.... Now, speaking of your spell evasion: 1) I noticed that the parent resource (located at offset 0x94) of your EFFs is a SPL, while the resource (located at offset 0x30) of your 318 effects is an ITM 
    The resource for opcode 318/324 doesn't have a type.  NI just displays the extension to help find a match among existing resources, it displays ITM by default, likely because it's alphabetically before SPL.
    Luke93 said:
    2) You should tweak your code and remove opcode #318 (param1 = 0, param2 = 0) ----> you don't need this since you already have opcode #318 (param1 = STATE_NORMAL, param2 = STATE bit_eq specified value). Put here the Save vs. Breath and you're done :) Otherwise, if you keep both this and EA >= ANYONE (Save vs. Breath), it may happen that a HELPLESS creature takes damage (correct) upon a successful Save vs. Breath (weird) Tl;dr ----> EA >= ANYONE returns true even if the targeted CRE is HELPLESS ;)
    I'm not seeing a STATE_NORMAL check in the linked evasion code, just plenty of other state checks which could be combined.  Checking STATE_NORMAL would be terrible, it would either match anything or nothing, depending on which comparison you use.

  • Luke93Luke93 Member, Mobile Tester Posts: 1,299
    @kjeron

    Aren't STATEs mutually exclusive? If you're STUNNED, then you're not NORMAL, right?

    I mean, you're allowed a Save vs Breath if your state is NORMAL ----> if you fail it, then you're protected against the EFF...... Otherwise (e.g., your state is SLEEPING), you're allowed no save and are protected against the EFF.....

    Am I missing something?

  • kjeronkjeron Member Posts: 2,130
    Luke93 said:
    @kjeron Aren't STATEs mutually exclusive?
    No, states are cumulative.
    STATE_NORMAL is just the absence of every other STATE.

    If you check for STATE_NORMAL (0x00000000):
    • with bit_eq, it will never return true, as there are no bits to check.
    • with bit_uneq, it will always return true, as there are no bits to check.
    • with exact equality, it will only return true if you have no STATE set, including HASTE, LUCK, DUHM, BLESS, CHANT, BLUR, MIRRORIMAGE, AID, INVISIBLE, IMPROVEDINVISIBLE
    • with exact inequality, it will return true if any STATE is set.

    Luke93
  • Luke93Luke93 Member, Mobile Tester Posts: 1,299
    edited January 2019
    kjeron said:
    I'm not seeing a STATE_NORMAL check in the linked evasion code, just plenty of other state checks which could be combined.
    If you install the relevant component of Scales_Of_Balance, you'll see it.....

    kjeron said:
    No, states are cumulative.
    STATE_NORMAL is just the absence of every other STATE.
    So, if that's the case, then do you think that another relation (e.g., binary less/binary more) can solve the issue?

  • kjeronkjeron Member Posts: 2,130
    Luke93 said:
    If you install the relevant component of Scales_Of_Balance, you'll see it.....
    Okay, I saw it, that's a bug, he's using a negative value with CLONE_EFFECT, so it's not working correctly, it should be STATE_CONFUSION (0x80000000).
    Luke93 said:
    So, if that's the case, then do you think that another relation (e.g., binary less/binary more) can solve the issue?
    oh yes, you could block the saving throw feedback in the same manner as the evasion:
    Opcode 318: STATE bit_eq 0x8015602f, resource: "EFF1"

    0x8015602f is just the cumulative value of all states checked by his evasion code.
    If any are set, it will block both immunity effects, preventing the savingthrow display and the evasion.

    Luke93
  • Luke93Luke93 Member, Mobile Tester Posts: 1,299
    edited January 2019
    @kjeron

    Thank you very much! You basically need to use two EFFs, where the first one must protect you from the real immunity to "Sourcespell" upon a failed Save vs. Breath.

    So, to sum up (let's consider Fireball as an example):
    COPY_EXISTING ~SPWI304.spl~ ~override~ LPF ADD_SPELL_EFFECT INT_VAR insert_point = 0 opcode = 318 target = 2 parameter1 = 0x8015602f parameter2 = 138 duration = 1 STR_VAR resource = ~EFF1~ END

    LPF ADD_SPELL_EFFECT INT_VAR insert_point = 1 opcode = 318 target = 2 parameter1 = 0x8015602f parameter2 = 138 duration = 1 STR_VAR resource = ~EFFSUB~ END LPF ADD_SPELL_EFFECT INT_VAR insert_point = 2 opcode = 177 target = 2 parameter2 = 2 duration = 1 STR_VAR resource = ~EXTEFF~ END LPF ADD_SPELL_EFFECT INT_VAR insert_point = 3 opcode = 177 target = 2 parameter2 = 2 duration = 1 STR_VAR resource = ~EXTEFF1~ END BUT_ONLY CREATE EFF ~EXTEFF~ WRITE_LONG 0x10 318 WRITE_LONG 0x14 2 WRITE_LONG 0x1c 252 // EVASION WRITE_LONG 0x20 110 // SPLSTATE = specified value WRITE_LONG 0x28 1 WRITE_SHORT 0x2c 100 WRITE_ASCII 0x030 ~EFFSUB~ #8 WRITE_LONG 0x040 BIT1 // Save vs. Breath WRITE_LONG 0x90 1 // Resource type: spell WRITE_ASCII 0x94 ~EFF1~ #8 // Parent resource CREATE EFF ~EXTEFF1~ WRITE_LONG 0x10 324 WRITE_LONG 0x14 2 WRITE_LONG 0x1c 252 // EVASION WRITE_LONG 0x20 110 // SPLSTATE = specified value WRITE_LONG 0x28 1 WRITE_SHORT 0x2c 100 WRITE_ASCII 0x030 ~SPWI304~ #8 WRITE_LONG 0x90 1 // Resource type: spell WRITE_ASCII 0x94 ~EFFSUB~ #8 // Parent resource
    It should be OK, right?

    Moreover, how can I define my custom 0x8015602f? I guess I first need to add that entry to STATE.ids, right? I tried in this way but it's not working....


    /**
     * Adds a new entry to a specified IDS file and returns its IDS value.
     * 
     * INT_VAR minValue       Minimum IDS value to consider. (Default: 0)
     * INT_VAR maxValue       Maximum IDS value to consider. (Default: 255)
     * INT_VAR preferredValue Try this IDS value first if available. (Default: unset)
     * INT_VAR hexadecimal    Set to nonzero to add IDS value in hexadecimal notation. (Default: 0)
     * STR_VAR idsFile        The IDS file to add the entry to.
     * STR_VAR identifier     The identifier name for the IDS value. Must not contain whitespace.
     * RET value              The IDS value if entry has been added successfully. -1 if entry could not be added.
     */
    DEFINE_ACTION_FUNCTION ADD_IDS_ENTRY
    INT_VAR
      minValue        = 0
      maxValue        = 255
      preferredValue  = "-1"
      hexadecimal     = 0
    STR_VAR
      idsFile         = ""
      identifier      = ""
    RET
      value
    BEGIN
      OUTER_SET value = "-1"
    
      ACTION_IF (minValue < 0) BEGIN OUTER_SET minValue = 0 END
      ACTION_IF (maxValue < minValue) BEGIN OUTER_SET maxValue = minValue END
    
      ACTION_IF (~%idsFile%~ STRING_MATCHES_REGEXP ~.+\..+~ = 0) BEGIN
        OUTER_PATCH_SAVE idsFile ~%idsFile%~ BEGIN REPLACE_TEXTUALLY ~\(.+\)\.[^.]+~ ~\1~ END
      END
    
      ACTION_IF (FILE_EXISTS_IN_GAME ~%idsFile%.ids~) BEGIN
        // Try preferred value first
        OUTER_PATCH ~~ BEGIN
          PATCH_IF (preferredValue >= minValue AND preferredValue <= maxValue) BEGIN
            LOOKUP_IDS_SYMBOL_OF_INT retVal ~%idsFile%~ preferredValue
            PATCH_IF (~%retVal%~ STRING_EQUAL ~%preferredValue%~) BEGIN
              SET value = preferredValue
            END
          END
        END
        
        // Looking for available IDS slot
        ACTION_IF (value = "-1") BEGIN
          OUTER_PATCH ~~ BEGIN
            FOR (v = minValue; v <= maxValue; v += 1) BEGIN
              LOOKUP_IDS_SYMBOL_OF_INT retVal ~%idsFile%~ v
              PATCH_IF (~%retVal%~ STRING_EQUAL ~%v%~) BEGIN
                SET value = v
                SET v = maxValue + 1
              END
            END
          END
        END
    
        // Falling back to preferred value if no free slot found
        ACTION_IF (value = "-1" AND preferredValue >= minValue AND preferredValue <= maxValue) BEGIN
          OUTER_SET value = preferredValue
        END
    
        // Adding new entry
        ACTION_IF (value != "-1") BEGIN
          ACTION_IF (hexadecimal) BEGIN
            LAF TO_HEX_NUMBER INT_VAR value = value RET hexNumber END
            OUTER_TEXT_SPRINT idsValue ~0x%hexNumber%~
          END ELSE BEGIN
            OUTER_TEXT_SPRINT idsValue ~%value%~
          END
    
          APPEND ~%idsFile%.ids~ ~%idsValue% %identifier%~ UNLESS ~%identifier%~
          OUTER_SET value = IDS_OF_SYMBOL (~%idsFile%~ ~%identifier%~)
          ACTION_IF (value < minValue OR value > maxValue) BEGIN
            OUTER_SET value = "-1"
          END
        END
      END
    END
    
    /**
     * Converts any decimal number into a hexadecimal number
     */
    DEFINE_ACTION_FUNCTION TO_HEX_NUMBER
    INT_VAR
      value     = 0   // the decimal number
      minDigits = 1   // min. number of digits in return value (not counting sign)
      prefix    = 0   // whether to return number with "0x" prefix
    RET
      hexNumber       // returned as string without prefix
    BEGIN
      ACTION_IF (minDigits < 1) BEGIN OUTER_SET minDigits = 1 END
      ACTION_IF (minDigits > 8) BEGIN OUTER_SET minDigits = 8 END
      OUTER_TEXT_SPRINT hexNumber ~~
      ACTION_DEFINE_ARRAY digit BEGIN ~0~ ~1~ ~2~ ~3~ ~4~ ~5~ ~6~ ~7~ ~8~ ~9~ ~a~ ~b~ ~c~ ~d~ ~e~ ~f~ END
    
      ACTION_IF (value < 0) BEGIN
        OUTER_SET signed = 1
        OUTER_SET value = 0 - value
      END ELSE BEGIN
        OUTER_SET signed = 0
      END
    
      OUTER_WHILE (value != 0) BEGIN
        OUTER_SET curDigit = value BAND 0xf
        OUTER_SET value = value BLSR 4
        OUTER_TEXT_SPRINT hexDigit $EVAL digit(~%curDigit%~)
        OUTER_TEXT_SPRINT hexNumber ~%hexDigit%%hexNumber%~
      END
    
      OUTER_WHILE (STRING_LENGTH ~%hexNumber%~ < minDigits) BEGIN
        OUTER_TEXT_SPRINT hexNumber ~0%hexNumber%~
      END
    
      ACTION_IF (prefix) BEGIN
        OUTER_TEXT_SPRINT hexNumber ~0x%hexNumber%~
      END
    
      ACTION_IF (signed) BEGIN
        OUTER_TEXT_SPRINT hexNumber ~-%hexNumber%~
      END
    END
    
    DEFINE_PATCH_FUNCTION TO_HEX_NUMBER
    INT_VAR
      value     = 0
      minDigits = 1
      prefix    = 0
    RET
      hexNumber
    BEGIN
      INNER_ACTION BEGIN
        LAF TO_HEX_NUMBER INT_VAR value = value minDigits = minDigits prefix = prefix RET hexNumber END
      END
    END
    
    
    
    OUTER_SET my_custom_state = 0x00000001 BOR 0x00000002 BOR 0x00000004 BOR 0x00000008
    
    LAF ADD_IDS_ENTRY
    INT_VAR
    	hexadecimal = my_custom_state
    STR_VAR
    	idsFile = ~STATE~
    	identifier = ~MY_CUSTOM_STATE~
    END
    
    OUTER_SET my_custom_state = IDS_OF_SYMBOL(~STATE~ ~MY_CUSTOM_STATE~)



    Post edited by Luke93 on
  • kjeronkjeron Member Posts: 2,130
    @Luke93
    sorry, the forum is currently making it a PITA to read formatted posts, but the first part looks good.
    You don't need to add anything to STATE.IDS unless you are just wanting it to display in NI.  An integer/hex is just as valid as a label.  However, that function won't work for STATEs, it's not that kind of file.
    This is all you need:
    OUTER_SET my_custom_state = 0x00000001 BOR 0x00000002 BOR 0x00000004 BOR 0x00000008
    LAF TO_HEX_NUMBER INT_VAR value = my_custom_state RET hexNumber END // optional
    It's okay for this file to have duplicate entries.  The hex number is optional for consistency, but an integer will work just as well.

  • Luke93Luke93 Member, Mobile Tester Posts: 1,299
    kjeron said:
    @Luke93
    sorry, the forum is currently making it a PITA to read formatted posts, but the first part looks good.
    I fixed the first part by putting some spaces, it's hopefully more readable now.....

    kjeron said:
    @Luke93
    You don't need to add anything to STATE.IDS unless you are just wanting it to display in NI.  An integer/hex is just as valid as a label.  However, that function won't work for STATEs, it's not that kind of file.
    This is all you need:
    OUTER_SET my_custom_state = 0x00000001 BOR 0x00000002 BOR 0x00000004 BOR 0x00000008
    LAF TO_HEX_NUMBER INT_VAR value = my_custom_state RET hexNumber END // optional
    It's okay for this file to have duplicate entries.  The hex number is optional for consistency, but an integer will work just as well.
    OK, good to know :)  I tweaked your code via adding prefix = 1 when launching TO_HEX_NUMBER; in so doing, NI no longer says that STATE.ids is corrupted (or something like that......)

  • kjeronkjeron Member Posts: 2,130
    Luke93 said:
    OK, good to know :)  I tweaked your code via adding prefix = 1 when launching TO_HEX_NUMBER; in so doing, NI no longer says that STATE.ids is corrupted (or something like that......)
    Yeah, I just copied this:
    LAF TO_HEX_NUMBER INT_VAR value = value RET hexNumber END
    without seeing the line below it
    OUTER_TEXT_SPRINT idsValue ~0x%hexNumber%~

  • subtledoctorsubtledoctor Member Posts: 11,460
    edited January 2019
    kjeron said:
    Luke93 said:
    If you install the relevant component of Scales_Of_Balance, you'll see it.....
    Okay, I saw it, that's a bug, he's using a negative value with CLONE_EFFECT, so it's not working correctly, it should be STATE_CONFUSION (0x80000000).
    The code is:
            PATCH_IF %evasion_spellstate% = 252 BEGIN    
              LPF DELETE_EFFECT INT_VAR match_opcode = 318 match_parameter2 = 136 END
              LPF CLONE_EFFECT INT_VAR match_opcode = 318 match_duration = 1 match_savingthrow = %evasion_save% parameter1 = 2 parameter2 = %state_row% savingthrow = 0 STR_VAR insert = ~first~ END         // berserk
              LPF CLONE_EFFECT INT_VAR match_opcode = 318 match_duration = 1 match_savingthrow = %evasion_save% parameter1 = 262144 parameter2 = %state_row% savingthrow = 0 STR_VAR insert = ~first~ END    // blind
              LPF CLONE_EFFECT INT_VAR match_opcode = 318 match_duration = 1 match_savingthrow = %evasion_save% parameter1 = 8192 parameter2 = %state_row% savingthrow = 0 STR_VAR insert = ~first~ END     // charmed
              LPF CLONE_EFFECT INT_VAR match_opcode = 318 match_duration = 1 match_savingthrow = %evasion_save% parameter1 = 0x80000000 parameter2 = %state_row% savingthrow = 0 STR_VAR insert = ~first~ END // confused
              LPF CLONE_EFFECT INT_VAR match_opcode = 318 match_duration = 1 match_savingthrow = %evasion_save% parameter1 = 1048576 parameter2 = %state_row% savingthrow = 0 STR_VAR insert = ~first~ END    // feebleminded
              LPF CLONE_EFFECT INT_VAR match_opcode = 318 match_duration = 1 match_savingthrow = %evasion_save% parameter1 = 32 parameter2 = %state_row% savingthrow = 0 STR_VAR insert = ~first~ END         // helpless
              LPF CLONE_EFFECT INT_VAR match_opcode = 318 match_duration = 1 match_savingthrow = %evasion_save% parameter1 = 4 parameter2 = %state_row% savingthrow = 0 STR_VAR insert = ~first~ END         // panicked
              LPF CLONE_EFFECT INT_VAR match_opcode = 318 match_duration = 1 match_savingthrow = %evasion_save% parameter1 = 1 parameter2 = %state_row% savingthrow = 0 STR_VAR insert = ~first~ END         // sleeping
              LPF CLONE_EFFECT INT_VAR match_opcode = 318 match_duration = 1 match_savingthrow = %evasion_save% parameter1 = 65536 parameter2 = %state_row% savingthrow = 0 STR_VAR insert = ~first~ END     // slowed
              LPF CLONE_EFFECT INT_VAR match_opcode = 318 match_duration = 1 match_savingthrow = %evasion_save% parameter1 = 8 parameter2 = %state_row% savingthrow = 0 STR_VAR insert = ~first~ END         // stunned
            END
    How is Confusion turning negative? 

    At first I used "2147483648" instead of "0x80000000" and I <i>did</i> notice that the value went negative.  I thought using the hex value in its place fixed the issue.

    Is there something about being the last bit of the last byte that makes it go wrong?  I noticed a long time ago, when I was busy coopting proficiencies for my mods, that using the last bit of the stat did not work.  I simply restricted myself to bits 1-7 and stopped worrying about it.  But thinking about it now, it is something like, the last bit resolves to 256, but the values can only range from 0 to 255, so 256 is converted into a negative? 

    EDIT - WHO IS MESSING WITH POST FORMATTING ON THESE DAMN FORUMS?

    EDIT 2 - yeah, just ran the code, and when I put "0x8000000" into the CLONE_EFFECT function, it spits out STATE_NORMAL instead of STATE_CONFUSED.

    Which, perhaps ironically, leaves me STATE_CONFUSED.

    EDIT 3 - just so I'm clear, the whole point of this is about suppressing the text feedback about the saving throw when someone is disabled, right?  Like, hit a sleeping foe with a Fireball and it might say "save vs. Breath successful, but they won't evade the damage?  So the result is correct, but the saving throw is unnecessary (but who really cares) and its text feedback is distracting and confusing (which is annoying)...?

    EDIT 4 - yeah, just tried with the combined value "0x8015602f" and it turns into some negative.  I'm just leaving out STATE_CONFUSED until I figure out the problem. ("0x0015602f" seems to work just fine.)

    Post edited by subtledoctor on
  • kjeronkjeron Member Posts: 2,130
    @subtledoctor
    Yes, the discussion has mainly been about suppressing the distracting saving throw feedback when it's not necessary.

    As for STATE_CONFUSED, IIRC there is no way to set it's value with CLONE_EFFECT or ALTER_EFFECT, as it will always result in a negative value.

  • subtledoctorsubtledoctor Member Posts: 11,460
    edited January 2019
    Ditto ADD_SPELL_EFFECT.  Which, I don't mean to be pedantic; I raise it because it is from a different generations of Weidu functions, and has some substantive differences vs. the newer ALTER/CLONE/DELETE_EFFECT functions.  But in this regard they are alike.

    I've updated the general Evasion function:

    Now it uses two .EFF files to achieve the Evasion, and if the spellstate is 252, it adds two 318 effects beforehand to disable both .EFFs.  Theoretically it would be ice to add variables the user could set to exempt alternate STATEs, for different kinds of evasion.  In the future, perhaps.

    Using two .EFFs means using an extra digit in the filenames, which means this can only run on 999 spells and items, max.  That's probably fine.

    EDIT - I just realized that the function purports to work with items, but will not actually affect them.  Okay, so, more work to do.  Sigh.

  • kjeronkjeron Member Posts: 2,130
    Using two .EFFs means using an extra digit in the filenames, which means this can only run on 999 spells and items, max.  That's probably fine.
    You can extend it by converting the index to hex (000 to FFF = 0 to 4095), or even base36 (000 to ZZZ = 0 to 46655).

  • Luke93Luke93 Member, Mobile Tester Posts: 1,299
    edited January 2019

    EDIT - I just realized that the function purports to work with items, but will not actually affect them.  Okay, so, more work to do.  Sigh.

    Guess we need to put their effects into a 146 (Cast Spell) like Item Revisions does (I'm talking about Potion of Explosion and the like......) After that, everything should be fine......

  • kjeronkjeron Member Posts: 2,130
    edited January 2019
    Luke93 said:
    Guess we need to put their effects into a 146 (Cast Spell) like Item Revisions does...... After that, everything should be fine......  
    I suspect that it's just not patching them, it should work with them just fine (granted ADD_SPELL_EFFECT -> ADD_ITEM_EFFECT).  He's got an array of items, but the code only cycles through the spell arrays.

  • subtledoctorsubtledoctor Member Posts: 11,460
    edited January 2019
    The function actually looks for IF ~%RES%.spl~ EXISTS_IN_GAME. So I need to check for ~%RES%.itm~ as well, and then patch them with ADD_ITEM_EFFECT. Not rocket science; just need to find time. Bonus: it will allow patching 999 spells and 999 items separately.

    It can work fine with item abilities, no need to convert to 146's (a project I definitely don't have time for). It's a little ham-fisted; if there was an item that cast Fireball and also panicked those affected, this would evade both the Fireball and Fear effects, rather than just the Fireball. But realistically, the set of items we're dealing with - Wand Of Fire et al. - are not like that. I'm okay doing this the ham-fisted way. :)

    Post edited by subtledoctor on
  • Luke93Luke93 Member, Mobile Tester Posts: 1,299
    kjeron wrote: »
    As for STATE_CONFUSED, IIRC there is no way to set it's value with CLONE_EFFECT or ALTER_EFFECT, as it will always result in a negative value.

    Is this issue related to WeiDU?

  • subtledoctorsubtledoctor Member Posts: 11,460
    edited March 2019
    Luke93 wrote: »
    kjeron wrote: »
    As for STATE_CONFUSED, IIRC there is no way to set it's value with CLONE_EFFECT or ALTER_EFFECT, as it will always result in a negative value.

    Is this issue related to WeiDU?

    It's something about setting the last bit of a stat. I have noticed a similar thing with opcode 233. (I was setting it with Weidu though so not sure if it's a Weidu issue or an engine issue.)

  • kjeronkjeron Member Posts: 2,130
    Luke93 wrote: »
    Is this issue related to WeiDU?
    More specifically it's those two functions, they treat negative values as "no change".
    The last bit of a signed integer determines if it is positive or negative, which just happens to be STATE_CONFUSED.
    It can be patched to check STATE_CONFUSED, just not with those functions.

Sign In or Register to comment.