Jump to content

Bubb

Modders
  • Posts

    199
  • Joined

Posts posted by Bubb

  1. Here's a fun one I helped @morpheus562 investigate. Repo steps:

    1) Blind a party member.

    2) Kill them with Magic Missile.

    Minor Bug: The game restores their visual range and reenables their ability to clear the FoW, even though they are dead.

    Serious Bug: The area's character counter is now off it thinks two party members died when only one did. If you then kill everyone but charname, the engine believes no characters exist in the area and forces the viewport to the master area. Charname becomes unselectable and the game is softlocked.

  2. 9 hours ago, Luke said:

    For @Bubb: apparently, EFF files applied by op283 can bypass / ignore op101. Bug or Feature...? Something else to know about it...?

    I can't tell you if it's intended, but of all the opcodes that use EFF files:

    op177 - CGameEffectApplyEffect              - Checks for immunities to EFF
    op182 - CGameEffectApplyEffectEquipItem     - Does not check for immunities to EFF
    op183 - CGameEffectApplyEffectEquipItemType - Does not check for immunities to EFF
    op248 - CGameEffectMeleeEffect              - Checks for immunities to EFF
    op249 - CGameEffectRangeEffect              - Checks for immunities to EFF
    op272 - CGameEffectRepeatingApplyEffect     - Checks for immunities to EFF
    op283 - CGameEffectCurseApplyEffect         - Does not check for immunities to EFF

    You might be able to abuse the bugged op182; if you supply an empty ITM resref it should apply 100% of the time.

  3. 1 hour ago, jmerry said:

    On targeting by circle size ... OK, that's an option for a 324 effect. There are presets for "greater than 3" or "less than 4". Though I don't actually know enough about how the game works here.

    SPLPROT.2DA => STAT == 0x102 checks against the animation INI field "personal_space", or whatever value the creature currently has it set to.

    1 hour ago, jmerry said:

    And as for what it takes to block a wing buffet, the IESDP is even less helpful. "Note: Some animations are immune to this effect".

    The following animations are hardcoded to be immune to op235, (given that the target isn't a party member, I.E has a portrait slot):

    Spoiler
    0x1100 TANARRI
    0x1200 DRAGON_RED
    0x1201 DRAGON_BLACK
    0x1202 DRAGON_SILVER
    0x1203 DRAGON_GREEN
    0x1204 DRAGON_AQUA
    0x1205 DRAGON_BLUE
    0x1206 DRAGON_BROWN
    0x1207 DRAGON_MULTICOLOR
    0x1208 DRAGON_PURPLE
    0x1300 DEMOGORGON
    0x7300 ELEMENTAL_EARTH
    0x7302 SHAMBLING_MOUND
    0x7310 ELEMENTAL_FIRE
    0x7312 ELEMENTAL_FIRE_PURPLE
    0x7314 BURNING_MAN
    0x7320 ELEMENTAL_AIR
    0x7F2E RAVER
    0x7F32 SLAYER
    0x7F3B SOLAR
    0x7F3C DEVA_MONADIC
    0x7F3D MELISSAN
    0x7F3E GIANT_FIRE
    0x7F3F GIANT_YAGA-SHURA
    0xE0F0 GOLEM_ICE

    The opcode also has this weird block:

    if (this->m_sourceRes.startsWith("SP")) {
        this->m_effectAmount = (100 - pSprite->m_derivedStats.m_nResistMagic) / 100 * (float)this->m_effectAmount;
        if (this->m_effectAmount == 0) {
            return 0; // Terminate
        }
    }

    It's attempting to dampen the knockback speed with the target's magic resistance, but it fails at casting the first division to a float. If the spell resref starts with "SP" any positive magic resistance will make the speed parameter 0, causing the opcode to immediately terminate.

  4. The mod uses EEex to pull data directly from the actionbar, so yes, anything that displays via the actionbar's "cast spell" menu will be handled. All spells are displayed unless one of the filters is used, which can limit the view to either Cleric or Mage spells, or by matching a search string.

  5. Please Note: EEex is required to use this mod — EEex is (at the time of writing) only available on Windows platforms.

    Overview:

    This mod seeks to replace the standard actionbar spell selection with an alternative that is more convenient for the player. The primary enhancements over the default spell selection include:

    • Displaying all available spells at once, (categorized by level). No more endlessly clicking the right-arrow to get to your 9th level spells!
    • A searchable spell list. Know which spell you want to cast? Just type the first couple of characters and press enter.
    • The ability to narrow view to only Mage or Cleric spells; useful for Mage/Clerics.

    Screenshots:

    Spoiler

    BG:EE (no SoD) :

    bgee.thumb.png.2fd0736950d44decfd5ea8b2f6da5f15.png

    BG:EE (with SoD) :

    sod.thumb.png.715f7b2b055c3127b161e2e1c6104b97.png

    BG2:EE :

    bg2ee.thumb.png.e257507a72ddfb6aacc4795054d3609e.png

    IWD:EE :

    iwdee.thumb.png.aec1c147c06c4a0bf3e38bd1ba166595.png

    Options screen :

    options_screen.thumb.png.62cf71cff0aad64eaa7934afd5f510d5.png

    Overlay Mode :

    zigaC8i.gif

    Installation:

    Download: Here

    1. Install EEex (forum).
    2. Download the zip file above and copy the contents into your game's base folder.
    3. Run setup-bubb_spell_menu.exe and follow the prompts to install.
    4. Make sure to run the game with InfinityLoader.exe after installing EEex.

    Mod Compatibility:

    Compatible with the following UI overhauls, (when installed after):

    • Dragonspear UI++, (at the time of writing, the latest version can be found in this comment by artyfox; this version is required for compatibility)
    • EET, EET_GUI
    • Infinity UI++
    • LeUI, LeUI-BG1EE, LeUI-IWDEE, LeUI-SoD

    UI tweaks can go anywhere in the installation order relative to this mod.

  6. That error usually happens if you've manually gone and downloaded the outdated InfinityLoader release from GitHub. As EEex's readme says:

    Quote

    Please note: The following links are NOT intended to be used for installing EEex; the loaders are bundled in their respective EEex versions and will be automatically installed alongside EEex.

    Just install EEex — don't worry about the loader, it'll install as a part of setup-EEex.exe.

  7. 1 hour ago, argent77 said:

    However, I'm not sure if this string is actually shown in BG:EE when you talk to a character without valid dialog.

    The engine displays it when:

    Action #139 PlayerDialog():
        [ Dialog forced because MoveToObject() failed, (I haven't observed this ever happening)
          AND Fails to enter dialog window
        ]
        OR
        [ Fails to enter dialog window
          AND SPEECH.2DA => EXISTANCE has no valid entries on target cre
          AND SPEECH.2DA => SELECT_COMMON has no valid entries on target cre
          AND [ target EA != ENEMY || SPEECH.2DA => HOSTILE_DIALOG has no valid entries on target cre ]
        ]

    The string gets trimmed when being displayed so it doesn't really matter if that leading space is there or not.

  8. 0xF00041 doesn't have a leading space in my BG2:EE installs: "has nothing to say to you."

    0xF00070 and 0xF000C5, ("Find Trap Mode " and "Turn Undead Mode "), appear unused — the engine doesn't reference them.

    0xF0010F and 0xF00110, ("Party AI Off " and "Party AI On"), as lefreut says, are only referenced in UI.MENU by their real strref:

    function getPartyAITooltip()
        if aiButtonToggle == 1 then
            return Infinity_FetchString(15918)
        else
            return Infinity_FetchString(15917)
        end
    end

    Kinda defeats the point of the enginest entry.

  9. Ok, I'll attempt to explain how op272's Type=3 works and why it's buggy. First, some things you need to know before I get to the opcode:

    • The main engine loop ticks along at the set FPS value, normally 30tps. I will call this an "engine tick".
    • Creature AI ticks at random mutiples of the engine ticks based on the object's internal ID. Normal creatures tick every other engine tick, Hastened creatures tick every engine tick, Slowed creatures tick every 4 engine ticks.
    • The persistent effect list is updated every AI tick as long as the game is unpaused. 15 of these updates constitute a period. Note how AI ticks can occur at 15tps, 30tps, or 7.5tps given the state of the creature.
    • "world time" ticks every other engine tick while the game is unpaused; spells use world time for duration.

    Now, how op272 Type=3 works:

    1) The world time the effect is decoded at is stored at .EFF +0x6C. This decode happens when the effect is added to the projectile, (I.E. at the end of casting), NOT when the effect is applied to the target.

    2) When the effect is applied to the target the engine decides how long it will wait until applying op272's resref field. It does this via:

    m_periodCounter = (<current world time> - <decode time>) / 15 % m_period // where m_period is Param1 when using type Param2=3

    3) Remember how a period is 15 AI ticks? The persisent effect list keeps track of a creature-wide count of how many times it has been ticked. Every 15 AI ticks of this creature-wide counter => m_periodCounter increments and op272 checks if it should apply its resref. For type Param2=3, the resref is applied once the following is satisfied:

    ++m_periodCounter >= m_period

    Once op272's resref is applied the process starts over from step 2.

     

    Let's step through a real example to see how the above works, Param2=3, Param1=2:

    Spoiler
    op272 decoded on worldTime: 5453054
    op272 applying on worldTime: 5453062, m_periodCounter: 0
    op272 applying on worldTime: 5453063, m_periodCounter: 0
        15th AI Update on worldTime 5453065, m_periodCounter: 1
        15th AI Update on worldTime 5453080, m_periodCounter: 2
        Repeating effect applied [+26 from decode]
    op272 applying on worldTime: 5453081, m_periodCounter: 1
        15th AI Update on worldTime 5453095, m_periodCounter: 2
        Repeating effect applied [+15 from last apply]
    op272 applying on worldTime: 5453096, m_periodCounter: 0
        15th AI Update on worldTime 5453110, m_periodCounter: 1
        15th AI Update on worldTime 5453125, m_periodCounter: 2
        Repeating effect applied [+30 from last apply]
    op272 applying on worldTime: 5453126, m_periodCounter: 0
        15th AI Update on worldTime 5453140, m_periodCounter: 1
        15th AI Update on worldTime 5453155, m_periodCounter: 2
        Repeating effect applied [+30 from last apply]
    op272 applying on worldTime: 5453156, m_periodCounter: 0
        15th AI Update on worldTime 5453170, m_periodCounter: 1
        15th AI Update on worldTime 5453185, m_periodCounter: 2
        Repeating effect applied [+30 from last apply]
    ...

    The system works OK at normal AI speed. However, if a creature is hastened it sneaks in extra applications. Consider:

    Spoiler
    op272 decoded on worldTime: 5453044
    op272 applying on worldTime: 5453054, m_periodCounter: 0
    op272 applying on worldTime: 5453054, m_periodCounter: 0
        15th AI Update on worldTime 5453054, m_periodCounter: 1
        15th AI Update on worldTime 5453062, m_periodCounter: 2
        Repeating effect applied [+18 from decode]
    op272 applying on worldTime: 5453062, m_periodCounter: 1
        15th AI Update on worldTime 5453069, m_periodCounter: 2
        Repeating effect applied [+7 from last apply]
    op272 applying on worldTime: 5453070, m_periodCounter: 1
        15th AI Update on worldTime 5453077, m_periodCounter: 2
        Repeating effect applied [+8 from last apply]
    op272 applying on worldTime: 5453077, m_periodCounter: 0
        15th AI Update on worldTime 5453084, m_periodCounter: 1
        15th AI Update on worldTime 5453092, m_periodCounter: 2
        Repeating effect applied [+15 from last apply]
    op272 applying on worldTime: 5453092, m_periodCounter: 1
        15th AI Update on worldTime 5453099, m_periodCounter: 2
        Repeating effect applied [+7 from last apply]
    op272 applying on worldTime: 5453100, m_periodCounter: 1
        15th AI Update on worldTime 5453107, m_periodCounter: 2
        Repeating effect applied [+8 from last apply]
    op272 applying on worldTime: 5453107, m_periodCounter: 0
        15th AI Update on worldTime 5453114, m_periodCounter: 1
    ...

    Slow appears to work OK most of the time, though maybe I've missed something:

    Spoiler
    op272 applying on worldTime: 5453113, m_periodCounter: 0
        15th AI Update on worldTime 5453141, m_periodCounter: 1
        15th AI Update on worldTime 5453171, m_periodCounter: 2
        Repeating effect applied [+67 from decode]
    op272 applying on worldTime: 5453173, m_periodCounter: 0
        15th AI Update on worldTime 5453201, m_periodCounter: 1
        15th AI Update on worldTime 5453231, m_periodCounter: 2
        Repeating effect applied [+60 from last apply]
    op272 applying on worldTime: 5453233, m_periodCounter: 0
        15th AI Update on worldTime 5453261, m_periodCounter: 1
        15th AI Update on worldTime 5453291, m_periodCounter: 2
        Repeating effect applied [+60 from last apply]
    op272 applying on worldTime: 5453293, m_periodCounter: 0
        15th AI Update on worldTime 5453321, m_periodCounter: 1
        15th AI Update on worldTime 5453351, m_periodCounter: 2
        Repeating effect applied [+60 from last apply]
    ...

     

    And remember that pausing while op272 is active still double-counts a worldTime tick, causing additional problems.

  10. It's complicated.

    The general idea is that the persistent effects list is checked every 15 AI ticks. Spell duration works on "world time", and when you pause the game "world time" is reversed by 1 tick. So, you get a situation where a single "world time" tick is processed multiple times:

    1. worldTime increases to 1, everything in the game is processed.
    2. I pause the game, worldTime is reverted to 0, everything in the game is processed.
    3. I unpause the game, worldTime increases to 1, everything in the game is processed.

    Oops, worldtime=1 was processed twice, which ticked the AI twice in a single "world time" tick... this is why pausing speeds up op272's next evaluation.

    As for op272 happening multiple times in a single tick, I don't know. It's theoretically possible if the effects list is ticked 15+ times in a single update while the game is unpaused, but I have no idea what would cause that. Do you have an example?

    And no, there's no way to fix the interval being inconsistent, it's a design flaw of the engine.

  11. 1 hour ago, jastey said:

    I'll be blunt: Is what @argent77 posted less save to use or would you strongly recommend using your EEx approach?

    For this specific case argent's suggestion is more elegant. My solution is more generalized -- it should work for all symbol names and should continue to function even if a mod decided to go crazy with whitespace.

    Edit: Argent's solution also needs to be tweaked slightly:

    APPEND ~gtimes.ids~ ~3600 AJROM_TIMER~ UNLESS ~[ %TAB%]AJROM_TIMER%MNL%*$~

    Without that %MNL%* WeiDU doesn't match the EOL anchor when Windows-style newlines are being used, (a source of much agony in the Discord).

  12. Slightly overkill, but EEex uses something like this:

    DEFINE_ACTION_FUNCTION B3_ESCAPE_STRING
        STR_VAR
            str = ~~
        RET
            escaped_str
    BEGIN
        ACTION_DEFINE_ASSOCIATIVE_ARRAY to_escape BEGIN ~$~ => 1 ~^~ => 1 ~.~ => 1 ~*~ => 1 ~+~ => 1 ~?~ => 1 ~[~ => 1 ~]~ => 1 ~\~ => 1 END
        OUTER_PATCH_SAVE escaped_str ~%str%~ BEGIN
            limit = BUFFER_LENGTH
            FOR (i = 0; i < limit; ++i) BEGIN
                READ_ASCII i character (1)
                PATCH_IF VARIABLE_IS_SET EVAL ~to_escape_%character%~ BEGIN
                    INSERT_BYTES i 1
                    WRITE_ASCII i ~\~
                    ++i
                    ++limit
                END
            END
        END
    END
    
    DEFINE_ACTION_FUNCTION B3_APPEND_UNIQUE_IDS
        STR_VAR
            file_name = ~~
            column_one = ~~
            column_two = ~~
    BEGIN
        LAF B3_ESCAPE_STRING STR_VAR str = EVAL ~%column_one%~ RET column_one_escaped = escaped_str END
        LAF B3_ESCAPE_STRING STR_VAR str = EVAL ~%column_two%~ RET column_two_escaped = escaped_str END
        APPEND ~%file_name%.IDS~ ~%column_one% %column_two%~ UNLESS ~^[ %TAB%]*%column_one_escaped%[ %TAB%]+%column_two_escaped%[ %TAB%]*%MNL%*$~
    END

    This appends an entry only if there isn't an exact match already present in the file, (barring whitespace). Used like:

    LAF B3_APPEND_UNIQUE_IDS STR_VAR file_name = ~GTIMES~ column_one = ~3600~ column_two = ~AJROM_TIMER~ END
    LAF B3_APPEND_UNIQUE_IDS STR_VAR file_name = ~GTIMES~ column_one = ~3600~ column_two = ~C#AJROM_TIMER~ END

    (I started writing this before argent commented so I'm still posting it🤷‍♂️)

  13. Well, it works in my tests, and I've stepped through the game in a debugger to confirm that. Make sure you:

    1) Are installing it on the latest IWD2 patch version, v2.01.

    2) That the option is under the [Game Options] section.

    3) That the INI value didn't get reset from last time.

    4) That there's only one instance of Suppress Extra Difficulty Damage in the INI.

    If it still isn't working, could you upload your INI for me to test.

  14. ...And since PROFICIENCY2WEAPON is what applies the penalties for dual-wielding, having a weapon created by op111 removes the thac0 penalties for dual-wielding all together.

    @RoyalProtector The thac0 difference between your character's main-hand and off-hand are from the different enchantment levels of the weapons. Since BBoD is created by op111 Two-Weapon Style is completely ignored, including any penalties it would have otherwise applied.

×
×
  • Create New...