Jump to content

[code] Code fixes, aka stuff we can't fix


CamDawg

Recommended Posts

This is a code-level issue, but we can work around it at least.

When an unnamed spell is cast via a trap script and uses a 324 vs. itself (e.g. for immunity to one of its effects) the game will crash, trying to find a source to use in the feedback string. @argent77 provided a bug report with a reliable repro case in this GH issue. Note also that 318s used in this fashion can cause crashes, but they're not a 100% crash as is the 324.

The simple workaround is to name spells used in these cases, as I've done in this commit (and the oopsie followup). Ideally this should be fixed at a code level, as this is something that can easily occur in mods as well.

Link to comment

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.

Link to comment

As you (notably @Bubb and @kjeron) probably know, AoE projectiles (f.i. "ARROWEX.PRO" – Arrow Exploding) only check for Weapon Immunity (opcode #120) on the attacked target, and use that result for all caught within their area of effect.

Is this a code level issue...? If not, is there a workaround...? I tried using op148 (Cast spell at point, target=Self) to deliver the 6d6 Fire damage, but it is not working...

Edited by Luke
Link to comment

The problem is that op120 operates during the swing of the weapon, not during the transferral of effects. If op120 blocks a ranged attack, what it actually does is strip all effects, (including ones generated by the engine), from the projectile.

So yes, it's a code level issue. Once op120 occurs the projectile is reduced to being visual-only.

Link to comment

There is a glaring engine bug in the SetGlobalTimer() script action in PST:EE. The script action computes expiration time based on the real time value instead of game time, which causes GlobalTimer[Not]Expired() triggers to return meaningless results. The timer has usually already expired by the next timer check. The effect is mostly apparent in mods. There are also several instances in the unmodded game, but none of them appear to be game-breaking.

To work around this issue it is possible to use the (only one) PSTEE-specific script action that is still based on game time:

SetGlobalTimerRandom(S:Name*,S:Area*,I:Min*GTimes,I:Max*GTimes)

This action is not without issues either. If executed with the same value for Min and Max from a dialog action block, the timer will compute a random value between 0 and Max instead. Using values that are one apart seems to work though.

Link to comment
On 2/7/2023 at 9:48 AM, argent77 said:

There is a glaring engine bug in the SetGlobalTimer() script action in PST:EE.

The behavior of SetGlobalTimer() appears intentionally altered when engine_mode=3:

if (actionID == 0x73) {
    /* SetGlobalTimer */
    if (CChitin::ENGINE_MODE == 3) {
        time = g_pBaldurChitin->m_pObjectGame->m_gameTime;
    }
    else {
        time = (g_pBaldurChitin->m_pObjectGame->m_worldTime).m_gameTime;
    }
    time = time + (this->m_curAction).m_specificID * 0xf;
}

This effectively makes SetGlobalTimer() behave as RealSetGlobalTimer(). I don't know why though the corresponding triggers aren't altered to check real time.

Link to comment

I observed the following saving throw bugs in BG2:EE v2.6.6.0, though I suspect they exist in all variants of the engine.

* Serious: The engine doesn't display the "Save vs. Type" feedback if a creature would have failed the saving throw before the following modifiers are applied:

1) .EFF [+0x44] - Effect save bonus          // Every spell with a positive save bonus has a chance of being silently saved against!
2) Mage specialist bonus vs. incoming spells // Every specialist mage has a chance of silently saving against spells of their school!
3) op346
4) op219

5) (v2.5) Legacy of Bhaal                    // Under LoB, every creature with an EA >= GOODCUTOFF has a chance
                                             //   of silently saving against spells!
                                             //   EDIT: Fixed in v2.6; only in v2.5.
Spoiler

Minsc with Save vs. Spell stat of 10. Blindness spell modified to have save bonus of +10. Notice how both casts are saved against, but only the first displays a message.

jtNOlHK.gif

* Multiple saving throw types can be selected simultaneously in the relevant effect bitfield. In this case, the engine uses the target's lowest saving throw stat to determine which of these saving throw types to roll against. Improved invisibility's bonus is applied as a -4 bonus to the target's saving throw stat during rolling, and this throws off the selection process. If improved invisibility is active and multiple saving throw types are selected, in order for the engine to switch to using a better saving throw type, the more effective type needs to be -4 better than the previously selected stat. This bug isn't a big deal since no vanilla spells use the multiple-saving-throw-types mechanic, though this might be relevant to mods.

* A saving throw stat value of 20 causes the engine to ignore that saving throw type while checking for a save. If no other saving throw type is used by the effect (with the relevant stat < 20), the engine uses a roll of 0 instead of the usual [1-20], almost guaranteeing the save will fail. If the creature has +20 in modifiers to make the nearly impossible save, it fails to display a success message. This "bug" might actually be intentional as an "always fail" value  though, from the limited Googling I have done, it seems 20 is a valid value in the normal AD&D 2E ruleset.

Edited by Bubb
Clarify that LoB is not a modifier in v2.6
Link to comment

If you're talking about saving throws ... got anything on how the Legacy of Bhaal save bonus breaks in 2.6? Take a high-level creature with one or more of their base saves less than 5. LoB is a 5-point bonus. They should always succeed on those saves unless the effect has a substantial penalty attached. Instead, they always fail; if you bring them into the party, their base save displays as 20.

It looks like an underflow error to me; that stat is treated as an unsigned integer and capped above at 20. Subtract from it without guarding properly, and if flips over to the other end.

Link to comment
43 minutes ago, jmerry said:

It looks like an underflow error to me; that stat is treated as an unsigned integer and capped above at 20. Subtract from it without guarding properly, and if flips over to the other end.

Correct. The nightmare upgrade subtracts 5 from the saving throw bytes in the .CRE, which are unsigned. The engine reads in the underflowed value as some large value, applies its [-20-20] guard to the stat, and now the creature's save stat is 20. And due to what I said above, a stat of 20 always fails.

Link to comment
18 hours ago, Bubb said:

A saving throw stat value of 20 causes the engine to ignore that saving throw type while checking for a save. If no other saving throw type is used by the effect (with the relevant stat < 20), the engine uses a roll of 0 instead of the usual [1-20], almost guaranteeing the save will fail. If the creature has +20 in modifiers to make the nearly impossible save, it fails to display a success message. This "bug" might actually be intentional as an "always fail" value  though, from the limited Googling I have done, it seems 20 is a valid value in the normal AD&D 2E ruleset.

If I had to guess, I would venture that this was not coded for PnP fidelity, but rather for sheer efficiency. I think people these days often forget how underpowered personal computers were back then. I played BG on a 200 MHz Pentium I with 16MB of RAM and 2MB of VRAM.

Link to comment

Actually, I'm on the side of the auto-fail value probably being intentional. For one example, consider trolls. If you shoot a fire arrow at a downed troll, you expect it to die, right? The arrow auto-hits because the downed troll is helpless. Then the fire is a save or none effect, with no modifier. Helpless creatures are allowed to make saves normally. Now (looking at the old implementation), a typical downed troll CRE (example: TROLIC02) has 1/N HP, 100% resistance to all damage types except fire and acid, and base saves of 20. Without the auto-fail, the troll would succeed on its save if it rolled a natural 20, surviving the arrow 5% of the time. With the auto-fail, the troll is guaranteed to die on that execution shot.

Is it the best way to do such things? No, because 20 still is a valid base save for an ordinary creature; a number of civilian CREs have base breath saves of 20. Raising the guard's upper bound would definitely work better, as long as side effects like downed troll vulnerabilities are addressed as well (current implementation: the TROLLREG spell sets base saves to 20). And it wouldn't fix the LOB underflow error; that needs a change to the order of operations so the subtraction is performed on a signed value.

Link to comment

As already stated somewhere else, op182 is bugged (see the IESDP for further details...)

This is a problem for items such as "blun38.itm" (Night Club +1).

In this particular example, the thac0 bonus it grants during the night is not immediately removed upon unequipping the club (but will instead persist for some time...)

It is possible to partially mitigate this issue by using op183... In so doing, the thac0 bonus will be immediately removed upon switching to any other weapon not flagged as "17|Maces" (offset 0x1C)... However, if the character equips another club (or mace), the effect will still persist for some time...

As a result, op182 would be the perfect solution for this kind of items... But unfortunately, it is bugged...

Edited by Luke
Link to comment
On 3/9/2023 at 10:58 AM, Bubb said:

Correct. The nightmare upgrade subtracts 5 from the saving throw bytes in the .CRE, which are unsigned. The engine reads in the underflowed value as some large value, applies its [-20-20] guard to the stat, and now the creature's save stat is 20. And due to what I said above, a stat of 20 always fails.

So, to make sure I understand, a high level wizard with base saving throws (Death/Wand/Polymorph/Breath/Spell) of 8/3/5/7/4 will have 3/20/0/2/20 and automatically fails to save vs wands or spells? A high level fighter or monster like a fire giant goes from 3/5/4/4/6 to 20/0/20/20/1 thus auto failing saves vs death, polymorph and breath? No wonder some players were saying LoB becomes a lot easier in late BG2 (personally never tried it).

ETA: In my tests setting THAC0 to -1 via opcode 54 (not coded directly into the creature's file) gave me a similar wraparound to 20 problem, incrementing by opcode 54 is ofc safe.

22 hours ago, jmerry said:

Actually, I'm on the side of the auto-fail value probably being intentional. For one example, consider trolls. If you shoot a fire arrow at a downed troll, you expect it to die, right? The arrow auto-hits because the downed troll is helpless. Then the fire is a save or none effect, with no modifier. Helpless creatures are allowed to make saves normally. Now (looking at the old implementation), a typical downed troll CRE (example: TROLIC02) has 1/N HP, 100% resistance to all damage types except fire and acid, and base saves of 20. Without the auto-fail, the troll would succeed on its save if it rolled a natural 20, surviving the arrow 5% of the time. With the auto-fail, the troll is guaranteed to die on that execution shot.

I too think it was intended, iirc besides downed trolls only zero level civilians and kobolds have base saves of 20 in any category, that being Breath Weapon, which would rarely be relevant in game, and all tables for player character classes start below 20 in each category.

I can confirm it was this way on the old engine too, noticed some years ago that any creature with a save vs spells of 20 is auto-killed by Chromatic Orbs from a 12th level caster, although the +6 bonus should grant a 35% chance of survival.

Edited by polytope
Link to comment
On 3/9/2023 at 9:52 PM, lynx said:

That's no excuse for this there, it's not really a performance improving bug.

You sure ? As in, most of the game is played at low relative levels, the values are level capped, for example Thac0 never goes to minus figures via levels etc, the whole programming is intended to solve this unseen red herring. Modify that and ouh, here we go-e, we got a bug that showels it's ugly head as ups negative 29 is indeed larger than zero and plus 24 is smaller than zero too, when capped between -20 and 20.
The solution is simple, set the borders to -127 and 128. There we go.

Edited by Jarno Mikkola
Link to comment

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...