Jump to content

Bubb

Modders
  • Posts

    199
  • Joined

Everything posted by Bubb

  1. UI.MENU has Infinity_PressKeyboardButton() to emulate keypresses, but I think it only accepts "escape", "space", and single-character strings. So, no sending a "CTRL" character. The LockScroll() action sets the same internal field as CTRL+P. The difference is that LockScroll() locks the viewport to the creature that executes the action, and CTRL+P uses whatever creature is currently under the cursor. C:Eval() appends its action to the action queue of a creature, normally the creature currently under the cursor, though if a second parameter of [0-5] is given, it instead adds the action to the player in that portrait index. ActionOverride() clears any actions on the target creature that weren't from another ActionOverride(). Emulating CTRL+P with EEex is as simple as: function LockScroll() local id = EEex_GameObject_GetUnderCursorID() if not EEex_GameObject_IsSpriteID(id) then id = -1 end EngineGlobals.g_pBaldurChitin.m_pEngineWorld.m_scrollLockId = id end
  2. You should be able to check the local variables directly. Note that mazed creatures can only be targeted via script name or a static-ish OBJECT.IDS reference. Actions that "target" creatures (i.e. make the target's marker change) are specifically disallowed from seeing mazed creatures. ActionOverride() should be able to get a mazed creature to do an instant action. Triggers seem to evaluate normally, e.g. the following works: TriggerOverride(PartySlot1,Global("B3MAZE","LOCALS",1)) The reason why spell states can't be detected during maze / imprisonment is that the engine stops applying opcodes to the creature, except for #212 (0xD4) Protection: Freedom, #213 (0xD5) Spell Effect: Maze, and #233 (0xE9) Stat: Proficiency Modifier.
  3. The engine names the two fields as: .CRE [+0x46] - m_armorClass .CRE [+0x48] - m_armorClassBase I see no evidence that m_armorClass is used in any meaningful way. It is accessed by: op74 (State: Blindness) — duration type = 1 — modifies m_armorClass. The LoB upgrade / downgrade routines — modifies m_armorClass. Action 370 (ChangeStat) — Stat = 2 — modifies m_armorClass. Notice how the engine never actually uses it.
  4. See the attached file - I think everything works correctly. You want to look at B3_RNDBASE_GET_AT and B3_RNDBASE_SET_AT. B3_RNDBASE.tph
  5. 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.
  6. 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. * 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.
  7. 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.
  8. For the record, that assertion is thrown when a casting effect attempts to use targeting mode 2 (preset target) on the classic engine. The EEs just ignore it.
  9. It works fine in oBG2. For example, putting the following at the top of AR0602.BCS: IF Global("B3SetLocal","GLOBAL",1) THEN RESPONSE #100 SetGlobal("B3SetLocal","GLOBAL",0) ActionOverride("Imoen",SetGlobal("B3Test","LOCALS",1)) Continue() END And executing the following in the console: CLUAConsole:SetGlobal("B3SetLocal","GLOBAL",1) -- Wait for Imoen to execute the action CLUAConsole:GetGlobal("B3Test","LOCALS") -- While hovering cursor over Imoen Are you sure that the block with the ActionOverride() is actually being executed, that Imoen is available to execute the action, and that her action queue isn't being cleared by something else, (player commands, ClearActions())?
  10. 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.
  11. I can confirm that the engine doesn't check op341 if a hit is blocked by op120.
  12. oIWD's op284 does the following: If the target creature has Race = 108 (GHOUL), 115 (SKELETON), or 167 (UNDEAD), the chance of being destroyed is based on the target creature's LEVEL1: Level < 4: 100% Level = 5: 95% Level = 6: 80% Level = 7: 65% Level = 8 or Level = 9: 50% Level = 10: 35% Level > 10: 20% Can you see the bug? Hint: Level = 4 isn't handled, and thus has a 0% chance of being destroyed. Race = 164 (TANARI) has a flat 5% chance of being destroyed. I see no mechanism that enables the mace's "Double damage against undead and outer planar creatures." claim.
  13. That's an engine problem. When the engine is formatting the feedback string, it omits "Casts" if the spell was an innate, but still appends the space as if it was there.
  14. I'm late, but here's all the PROJECTL.IDS values that are hardcoded in PST:EE, so you can avoid using their ids: Add one to these values to get the projectile ids used in spells.
  15. v4.5.3 - Fixed thieving hotkey opening the spell menu. This also fixes a bad interaction with Dragonspear UI++'s permanent thieving button. Note: This release requires a recent EEex version: v0.9.16-alpha+.
  16. Yep, the hotkey directly invokes EquipMostDamagingMelee() without going through the action system, which is also why it doesn't interrupt the current action.
  17. The answer to "why doesn't an opcode do X" is pretty much that the devs never intended for it to be used that way. And yeah, I can confirm that op45 has no Special field functionality; it will continuously apply STATDESC.2DA["BAM_FILE", 55] while the target is alive. Edit: And I don't think you can clear that cell to remove the icon. The engine falls back to [STATES.BAM, sequence=row+65, frame=0] when it encounters a default value.
  18. You're right, it's modified by [+0x50] of the area header, "Lightning probability." This field only observes four different tiers: 0 => Disabled. [1, 32] => 2% chance to attempt a lightning strike every 150 + [0, 999] ticks. [33, 65] => 2% chance to attempt a lightning strike every 100 + [0, 699] ticks. [65, +] => 2% chance to attempt a lightning strike every 45 + [0, 199] ticks. There's also some randomness in how intense the storm is and how loud the thunder sound is. The engine only attempts a lightning strike when it decides the thunder's volume should be above 85%. So, realistically, it's a lot rarer than I initially thought.
  19. Areas have a 2% chance each tick (default 30tps) to attempt a lightning strike, (approximately 1 strike attempt every ~2.2 seconds). It randomly selects a creature from m_lVertSort, which includes all the non-flying living creatures. If the selected creature is currently on-screen, the chance to strike it is determined by their armor's animation: (Anything) => 30% Chain mail => 65% Plate mail => 100% So lightning can pretty much hit any creature as long as it's on-screen.
  20. local nMaxDamageSlot = -1 local nMaxDamageAbility = -1 local nMaxDamageSeenSoFar = 0 for nCurWeaponSlot = 35, 38 do for nCurAbilityIndex, ability in ipairs(<every weapon ability>) do if ability.type == 1 then -- [+0x0], MELEE local damageDice = ability.damageDice -- [+0x16] local damageDiceCount = ability.diceSize -- [+0x18] local damageDiceBonus = ability.damageBonus -- [+0x1A] if (ability.flags & 5) ~= 0 then -- [+0x26], Strength bonus on "Add strength bonus(0)" or "EE: Damage strength bonus(2)" damageDiceBonus = damageDiceBonus + STRMOD.2DA["DAMAGE", this.m_nSTR] + STRMODEX.2DA["DAMAGE", this.m_nSTRExtra] end for abilityEffect in <every ability effect> do if abilityEffect.m_effectId == 318 or abilityEffect.m_effectId == 324 then break end if abilityEffect.m_effectId == 12 then damageDice = abilityEffect.m_diceSize -- [+0x20] damageDiceCount = abilityEffect.m_numDice -- [+0x1C] damageDiceBonus = abilityEffect.m_effectAmount -- [+0x4] break end end local nTotalDamage = damageDice * damageDiceCount + damageDiceBonus + STYLBONU.2DA["DAMAGE_RIGHT", <resolved style prof level>] + WSPECIAL.2DA["DAMAGE", <resolved weapon prof level>] & 0xFFFF if nMaxDamageSeenSoFar <= nTotalDamage then nMaxDamageSlot = nCurWeaponSlot nMaxDamageAbility = nCurAbilityIndex nMaxDamageSeenSoFar = nTotalDamage; end end end end local nSlotToSelect local nAbilityToSelect if nMaxDamageSlot == -1 and nMaxDamageAbility == -1 then nSlotToSelect = 10 -- SLOT_FIST nAbilityToSelect = 0 else nSlotToSelect = nMaxDamageSlot nAbilityToSelect = nMaxDamageAbility end this:SelectWeaponAbility(nSlotToSelect, nAbilityToSelect, true, true) The first damage effect on an item ability overrides the ability's base values. Hitting either op318 or op324 stops the search for a damage effect on an item ability. The strength bonus is thrown away if it finds and uses a damage effect. Ties are broken by the item with the highest slot index.
  21. That's only applicable to the "attempt to call global" errors, and, like I noted earlier in the thread, other problems can also cause that type of error. "EEex not active" is a low-level problem that means EEex_Main.lua didn't finish executing. Either the game wasn't started with InfinityLoader.exe, InfinityLoader.exe failed to inject EEex, or there was a Lua error in EEex_Main.lua. Running InfinityLoader.exe through the command prompt should show any errors that were logged.
  22. It looks like LOCALS survive export. There's a bug though - if you: Set a LOCALS on a creature Don't save the game since the LOCALS was set Export the character => The LOCALS is not saved on the exported character. Using op187 directly with timing mode 9, special=1 will probably work.
  23. This is fixed in EEex v0.9.9-alpha. I have no idea how I overlooked something that glaringly wrong.
  24. v4.5.2 - Added French translation, (thanks @JohnBob!).
×
×
  • Create New...