Howdy, Stranger!

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

Categories

Neverwinter Nights: Enhanced Edition has been released! Visit nwn.beamdog.com to make an order. NWN:EE FAQ is available.
Soundtracks for BG:EE, SoD, BG2:EE, IWD:EE, PST:EE are now available in the Beamdog store.
Attention, new and old users! Please read the new rules of conduct for the forums, and we hope you enjoy your stay!

[MOD] EEex (v0.6.0-alpha)

1235724

Comments

  • kjeronkjeron Member Posts: 1,965
    I was incorrect earlier, it's not just setActionbarButton() that is crashing, both of these crash as well:
    getActorClass() getActorKit()
    I managed to get a message by deleting the both the class and kit check:

    buttonIndex: 0x5
    EEex
    buttonType: 0x2
    EEex
    step1: 0x36E0FF0
    EEex
    step2: 0x775D878
    EEex
    step3: 0x0
    EEex
    step4: 0x0

  • kjeronkjeron Member Posts: 1,965
    edited January 2
  • BubbBubb Member Posts: 641
    edited January 2
    Something is very, very wrong.

    getActorClass() and getActorKit() are about as simple as functions can get. All they do is call 1 internal function, and read 1 value from memory. If they are crashing, either something is going on with the actorID parameter, or the very core of the program, (reading memory and calling subroutines), is broken.

    Perhaps _B3WriteAssembly is malfunctioning and writing broken code, or somehow the memory offsets for the beamdog executable are different. I don't own the game through beamdog... so I can't verify firsthand.

    I was really hoping it was just a setActionbarButton() quirk on your system, but it seems to be much more serious than that.

    Let's delve a little deeper:

    1. Run the attached tool on the game with EEex installed, and then on a clean installation. This will test for loader integrity, string integrity, hash integrity, and .rdata integrity. Please post the results here.

    2. Your actionbar listener should have a getActorIDSelected() call. Please put the following line after it and record the result:
    EEex_MessageBox("actorID: "..toHex(actorID))
    BTW, thanks for helping me debug :)

  • kjeronkjeron Member Posts: 1,965
    Bubb said:

    1. Run the attached tool on the game with EEex installed, and then on a clean installation. This will test for loader integrity, string integrity, hash integrity, and .rdata integrity. Please post the results here.


    Installing [EEex_Cert] [1.0]
    Copying and patching 1 file ...
    [EEex_Hash.txt] loaded, 88 bytes

    Hash is unknown: CertUtil: WsResetMetadata
    Copying and patching 1 file ...
    [Baldur.exe] loaded, 5718016 bytes

    EEex Loader Signature Present:

    68 0E 6C 93 00 68 F0 F0 89 00 E8 0A 00 00 00 E8 30 91 C1 FF E9 20 77 C7 FF 55 8B EC 6A 00 FF 75 08 FF 35 0C 01 94 00 E8 58 6A C1 FF 83 C4 0C FF 75 0C FF 35 0C 01 94 00 E8 87 6D C1 FF 83 C4 08 5D C2 08 00 55 8B EC 68 18 6C 93 00 68 55 F1 89 00 E8 C3 FF FF FF 68 27 6C 93 00 68 8B F1 89 00 E8 B4 FF FF FF 68 38 6C 93 00 FF 15 D8 01 8A 00 68 41 6C 93 00 50 FF 15 00 02 8A 00 6A 40 68 00 30 00 00 68 00 10 00 00 6A 00 FF D0 50 DB 04 24 83 EC 04 DD 1C 24 3E FF 75 08 E8 15 68 C1 FF 83 C4 0C B8 01 00 00 00 5D C3 55 8B EC 6A 00 6A 01 FF 75 08 E8 6C 63 C1 FF 83 C4 0C E8 54 D2 FB FF 8B F8 6A 00 6A 02 FF 75 08 E8 56 63 C1 FF 83 C4 0C E8 3E D2 FB FF 88 07 B8 00 00 00 00 5D C3 55 8B EC 6A 00 6A 01 FF 75 08 E8 36 63 C1 FF 83 C4 0C E8 1E D2 FB FF 6A 00 50 FF 35 0C 01 94 00 E8 80 69 C1 FF 83 C4 0C 6A 00 6A 02 FF 75 08 E8 51 65 C1 FF 83 C4 0C 50 FF 35 0C 01 94 00 E8 A2 6C C1 FF 83 C4 08 B8 00 00 00 00 5D C3

    EEex Strings Signature Present:

    00 42 33 65 78 5F 49 6E 69 74 00 42 33 65 78 5F 57 72 69 74 65 42 79 74 65 00 42 33 65 78 5F 45 78 70 6F 73 65 54 6F 4C 75 61 00 4B 65 72 6E 65 6C 33 32 00 56 69 72 74 75 61 6C 41 6C 6C 6F 63 00
    Copying and patching 1 file ...
    [EEex_Cert\rdata_verify.txt] loaded, 12154 bytes
    Copying and patching 1 file ...
    [Baldur.exe] loaded, 5718016 bytes

    There were 0 .rdata mismatches.

    Copying and patching 1 file ...
    [EEex_Hash.txt] loaded, 88 bytes

    Hash is unknown: CertUtil: WsResetMetadata
    Copying and patching 1 file ...
    [Baldur.exe] loaded, 5718016 bytes

    EEex Loader Signature Invalid:

    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

    EEex Strings Signature Invalid:

    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    Copying and patching 1 file ...
    [EEex_Cert\rdata_verify.txt] loaded, 12154 bytes
    Copying and patching 1 file ...
    [Baldur.exe] loaded, 5718016 bytes

    There were 0 .rdata mismatches.
    Bubb said:

    2. Your actionbar listener should have a getActorIDSelected() call. Please put the following line after it and record the result:

    Actor ID: 0x594144
    Bubb said:

    BTW, thanks for helping me debug :)

    Thank you for all your hard work.

    GrammarsaladBubb
  • GrammarsaladGrammarsalad Member Posts: 2,467
    edited January 3
    kjeron said:

    @bubb
    Sorry, I'm not seeing any messages, either in-game or by running game in command prompt. It just immediately pops up the "Error. There was an Error. A crash dump was saved to:" window.
    It doesn't always crash with that extra bit though, but it's also not changing the button when it doesn't crash either, and no messages when it doesn't crash.

    Hmm, I got something similar, but this was with Beamdog v2.3.67.3. I assumed that it was because it was an earlier build. I also have a fully updated gog version of bg2ee, and when I switched to that it worked with no problems.

    I'm on windows 10. I can update my beamdog version and try it out if you think that will help.

  • kjeronkjeron Member Posts: 1,965
    edited January 3
    @bubb
    I added more feedback messages so it would print out every time I selected any character and here is what I got:
    Randomly, per restarting the game, one of 4 different values would always be returned for 'getActorIDSelected()'.
    0x0 // Saw this occasionally. When this value showed up, remained the same for every character I selected.
    0x1A69AD8C // Saw this only once, remained the same for every character I selected.
    0x594144 // This was the most common result. When this value showed up, it remained the same for every character I selected.
    0x5B005B // Saw this occasionally. When this value showed up, it changed per character, and was always identical to the 'id' variable for that character.

    However, regardless of which value it had, it still crashed after the step 4 message when running 'setActionbarButton'.
    Step 1 and Step 2 always returned similar, though different numbers every time. Step 1 was always around 0x36##### and Step 2 was always around 0x76#####-0x77#####.
    Step 3 and Step 4 always return '0x0'.

  • BubbBubb Member Posts: 641
    @kjeron:
    Regarding setActionbarButton():

    My newfound symbols help with deciphering what exactly these values mean...
    • step1 = g_pBaldurChitin (CBaldurChitin) => Good
    • step2 = m_pObjectGame (CInfGame) => Good
    • step3 = m_visibleArea (byte) => OK - This is the index of the area you are currently in. It should be > 0 if you are not in a master area
    • step4 = m_gameAreas[m_visibleArea] (CGameArea) => ERROR - This is the address of the area you are currently in
    The area array lookup is retrieving a NULL when it shouldn't. What area are you testing the hook in? Does anything change based on what area you are in?

    Updated setActionbarButton() debug statements to use symbols and include an extra NULL check that the engine does in some places:
    function setActionbarButton(buttonIndex, buttonType)

    if buttonIndex < 0 or buttonIndex > 11 then
    error("buttonIndex out of bounds", 2)
    end

    local g_pBaldurChitin = rdword(0x93FDBC) -- (CBaldurChitin)
    EEex_MessageBox("g_pBaldurChitin: "..toHex(g_pBaldurChitin))

    local m_pObjectGame = rdword(g_pBaldurChitin + 0xD14) -- (CInfGame)
    EEex_MessageBox("m_pObjectGame: "..toHex(m_pObjectGame))

    local m_visibleArea = rbyte(m_pObjectGame + 0x3DA0, 0) -- (byte)
    EEex_MessageBox("m_visibleArea: "..toHex(m_visibleArea))

    -- m_gameAreas[m_visibleArea]
    local m_gameArea = rdword(m_pObjectGame + m_visibleArea * 4 + 0x3DA4) -- (CGameArea)
    EEex_MessageBox("m_gameAreas[m_visibleArea]: "..toHex(m_gameArea))

    if m_gameArea ~= 0x0 then

    local m_pGame = rdword(m_gameArea + 0x204) -- (CInfGame)
    EEex_MessageBox("m_pGame: "..toHex(m_pGame))

    local m_cButtonArray = m_pGame + 0x2654 -- (CInfButtonArray)
    EEex_MessageBox("m_cButtonArray: "..toHex(m_cButtonArray))

    -- => m_buttonTypes[buttonIndex]
    local m_cButton = m_cButtonArray + 0x1440 + buttonIndex * 0x4 -- (dword)
    EEex_MessageBox("ptr m_buttonTypes[buttonIndex]: "..toHex(m_cButton))

    wdword(m_cButton, buttonType)
    end
    end


    Regarding getActorIDSelected():

    Every result except 0x5B005B is completely invalid and should not have been returned.

    getActorIDSelected() including debug statements with symbols:
    function getActorIDSelected()

    local g_pBaldurChitin = rdword(0x93FDBC) -- (CBaldurChitin)
    EEex_MessageBox("g_pBaldurChitin: "..toHex(g_pBaldurChitin))

    local m_pObjectGame = rdword(g_pBaldurChitin + 0xD14) -- (CInfGame)
    EEex_MessageBox("m_pObjectGame: "..toHex(m_pObjectGame))

    -- Direct access of subfield :
    -- => m_group [+3E48] (CAIGroup)
    -- => m_memberList [+8] (CTypedPtrList)
    -- => m_pNodeHead [+4] (dword)
    local m_pNodeHead = rdword(m_pObjectGame + 0x3E54)
    EEex_MessageBox("m_pNodeHead: "..toHex(m_pNodeHead))

    if m_pNodeHead ~= 0x0 then
    local actorID = rdword(m_pNodeHead + 0x8)
    EEex_MessageBox("actorID: "..toHex(actorID))
    return actorID
    else
    EEex_MessageBox("actorID: NULL")
    return 0x0
    end
    end

    In either case, I cannot see how these functions would be returning different results for you, especially regarding globals that are vital to the program. Could you open a cmd window in your game's directory, and run the following command on an EEex install, and then a clean install?
    certutil -hashfile Baldur.exe
    Just want to make sure we are working with the same stuff here...

    One day we will find the cause, we just gotta believe :wink:

  • kjeronkjeron Member Posts: 1,965
    edited January 3
    Bubb said:

    The area array lookup is retrieving a NULL when it shouldn't. What area are you testing the hook in? Does anything change based on what area you are in?

    Primarily the Pocket Plane, but I have tested in other areas and SoA as well.
    I tried moving to a new location through normal transition and through the console after loading, before testing, and it changes the results significantly, now:
    - both areas are '0x1'
    - or the game crashes without any error window.
    - or the first is '0x1' and the second is (I've seen '0x7EE2AC0', '0x1E21DB28', and '0x8058C78' so far, it changes, even for the same area.)

    The last result also proceeds past that step with more feedback messages:
    Most common:
    • m_pGame: 0x0
    • m_cButtonArray: 0x2654 // same value each time it got this far
    • ptr m_buttonTypes[buttonIndex]: 0x3AA8 // same value each time it got this far
    • crash
    I once got this result:
    • m_pGame: 0x6B7D400
    • crash
    I once got this result:
    • g_pBaldurChitin: 0x3622A28
    • m_pObjectGame: 0x77263C8
    • mvisibleArea: 0x1
    • m_gameAreas[m_visibleArea: 0x7E70690
    • m_pGame: 0x6B9A380
    • m_cButtonArray: 0x6B9C9D0
    • ptr m_buttonTypes[buttonIndex]: 0x6B9DE20
    • no crash, but also no button change
    • this would repeat the same values each time it I selected the character
    For these tests, because getActorIDSelected() could not consistently get a valid result, I had the actorID set to 'id' before running setActionbarButton() if it wasn't already a valid number. I will test the getActorIDSelected() with debug when I get home later today.
    Bubb said:

    In either case, I cannot see how these functions would be returning different results for you, especially regarding globals that are vital to the program. Could you open a cmd window in your game's directory, and run the following command on an EEex install, and then a clean install?
    certutil -hashfile Baldur.exe
    Just want to make sure we are working with the same stuff here...

    With EEex:
    a5 cf bc 1a a8 cb f8 43 d2 42 c0 7c 3c 13 d0 a3 a8 4f ce 4c Without EEex:
    cd dc e5 62 06 f2 7d 27 02 84 ab 07 4a 5d 95 8d fc 32 c1 3c

  • BubbBubb Member Posts: 641
    edited January 3
    Wall of text incoming, brace yourselves -

    @kjeron: Ok, the hashes confirm that our executables are completely identical. Now that that's confirmed...

    I was thinking that it might be some sort of weird load order between the .lua files, but that should result in LUA firing an error about nil functions, and not the game crashing.

    We need to verify that EEex's dynamic code is being written properly into memory. It would make a lot of sense if it is getting corrupted somehow, but, that should most certainly cause a crash, not return odd values.

    I've attached a new version which includes the relevant debug statements, along with a new rdword function that prints exactly what it is doing to the err stream. I also edited out the two places EEex was making gameplay changes by itself, (Blades had full thieving enabled / hover tooltips were disabled).

    You should remove any of the versions of EEex functions I provided earlier from your code; they are now all included in M__EEex.lua. Your core listener code should be all that remains, (the debug statements are now in the EEex functions by default, for this build).

    Try opening Baldur.exe from the cmd using this command:
    Baldur.exe 2> log.txt

    Avoid crashing the the game for now. Run EEex_DumpDynamicCode() from the CLUAConsole, (just paste it in as if you were going to call it in UI.MENU). Close the game normally, and inspect the created log.txt. Please post the results starting at "INFO: LUA: EEex => Dynamic Code"

    After that, try triggering setActionbarButton() again. rdword will print out where it is reading the values from and what it grabbed into the cmd window. Please record both the cmd rdword debugs, and the MessageBox values up until the game inevitably crashes.

    It also wouldn't hurt if you did this for the getActorClass() / getActorKit() functions, (these will only display the cmd rdword debugs).

    If all of these results align with the other debugging stuff, I am seriously coming to the end of what could be going wrong. These are the facts so far:

    1. The loader and game integrity are 100%. Your game matches mine in every single way.
    2. The basic functions rdword and EEex_WriteByte() seem to be running without raising fatal exceptions.
    3. More complex functions are crashing because of invalid return values from rdword. Or, the game is simply in an "impossible" state.

    I'm thinking of some possibilities so far:
    • While your *game* executable is the same as mine, the windows dlls have different signatures, and are somehow leaving the stack / registers in an unexpected state.
    • rdword() or EEex_WriteByte() are not crashing, but have errors in their logic. Though, they are so simple that I can't see how this would be the case.
    • _B3WriteAssembly() is not functioning correctly, and is writing invalid code. Again, though, this should crash the game instantly, not cause these shadow-bugs.
    • The engine is running in a different state than expected. Not necessarily impossible, maybe the timing of your computer is highlighting a race condition.
    • Your computer is possessed by the devil. >:)

    Edit: Also, thanks for taking the time to compile all of the debug statements. I am looking at them, I just can't see how they are coming to be. The fact that the EEex code does the right thing *some* of the time is very confusing.

  • kjeronkjeron Member Posts: 1,965
    Bubb said:

    Your computer is possessed by the devil. >:)
    I can neither confirm nor deny this statement.
    Bubb said:


    Edit: Also, thanks for taking the time to compile all of the debug statements. I am looking at them, I just can't see how they are coming to be. The fact that the EEex code does the right thing *some* of the time is very confusing.

    This behavior actually reminds of back when I was testing specific high value (256+) kit ID's that where exact combinations of Mage Specialists. (0x4800, 0x4c00, 0x4400, 0x4440, etc...). Every time I restarted the game, the spell-school restrictions applied to the kit were randomized, if it didn't crash.
    Beginning tests...

  • kjeronkjeron Member Posts: 1,965
    edited January 3
    Almost every time, as soon as I load game, I sometimes get message popups about several characters, then it immediately crashes in one of 3 ways: Error popup, this program has stopped running popup, or it just hangs indefinitely.

    The few times I did manage to actually get in-game, it crashed similarly if I selected a character.
    I managed to get in-game once and run EEex_DumpDynamicCode(), and this is as far as it got:
    
    1
    	1
    		Entry Address: 0x58D0000
    		Entry Size: 0xB8
    		Entry Reserved: true
    // hangs indefinetely at this point.
    I'm still trying...

    I've commented out some of the MessageBox feedback and it's allowed me to actually get in-game more consistently, to run EEex_DumpDynamicCode(), and it still does the same thing, hangs after those 5 lines.

    edit - I've only been loading games that don't have Paladin's in the party, to avoid the button code from triggering.

  • kjeronkjeron Member Posts: 1,965
    Okay, I finally managed to get EEex_DumpDynamicCode() to run all the way through:
    INFO: LUA: EEex => Dynamic Code
    INFO: LUA: 1
    INFO: LUA: 1
    INFO: LUA: Entry Address: 0x38B0000
    INFO: LUA: Entry Size: 0xB8
    INFO: LUA: Entry Reserved: true
    INFO: LUA: 55 8B EC 53 51 52 56 57 6A 02 FF 75 08 E8 9E 57 C0 FC 83 C4 08 85 C0 74 3C 8B F8 BE 01 00 00 00 56 6A 02 FF 75 08 E8 15 5D C0 FC 83 C4 0C 6A 00 6A FF FF 75 08 E8 96 54 C0 FC 83 C4 0C E8 7E C3 FA FC 50 6A FE FF 75 08 E8 73 50 C0 FC 83 C4 08 46 3B F7 7E CB 6A 00 6A 03 FF 75 08 E8 6F 54 C0 FC 83 C4 0C E8 57 C3 FA FC 50 6A 00 6A 01 FF 75 08 E8 5A 54 C0 FC 83 C4 0C E8 42 C3 FA FC 59 FF D0 50 DB 04 24 83 EC 04 DD 1C 24 FF 75 08 E8 CD 58 C0 FC 83 C4 0C 6A 00 6A 04 FF 75 08 E8 2E 54 C0 FC 83 C4 0C E8 16 C3 FA FC 03 E0 B8 01 00 00 00 5F 5E 5A 59 5B
    INFO: LUA: 2
    INFO: LUA: Entry Address: 0x38B00B8
    INFO: LUA: Entry Size: 0x49
    INFO: LUA: Entry Reserved: true
    INFO: LUA: 55 8B EC 53 51 52 56 57 6A 00 6A 01 FF 75 08 E8 04 54 C0 FC 83 C4 0C E8 EC C2 FA FC 8B F8 6A 00 6A 02 FF 75 08 E8 2E 56 C0 FC 83 C4 0C 8B F0 8A 06 88 07 46 47 80 3E 00 75 F5 C6 07 00 B8 00 00 00 00 5F 5E 5A 59
    INFO: LUA: 3
    INFO: LUA: Entry Address: 0x38B0101
    INFO: LUA: Entry Size: 0x8F
    INFO: LUA: Entry Reserved: true
    INFO: LUA: C3 55 8B EC 53 51 52 56 57 6A 00 6A 01 FF 75 08 E8 BB 53 C0 FC 83 C4 0C E8 A3 C2 FA FC FF 30 50 68 A0 FF E8 06 FF 75 08 E8 E3 5A C0 FC 83 C4 08 DB 04 24 83 EC 04 DD 1C 24 FF 75 08 E8 1F 58 C0 FC 83 C4 0C FF 34 24 DB 04 24 83 EC 04 DD 1C 24 FF 75 08 E8 08 58 C0 FC 83 C4 0C 6A 00 6A 00 6A 00 6A 00 6A 02 FF 75 08 E8 83 62 C0 FC 83 C4 18 DB 04 24 83 EC 04 DD 1C 24 FF 75 08 E8 DF 57 C0 FC 83 C4 0C B8 01 00 00 00 5F 5E 5A 59 5B
    INFO: LUA: 4
    INFO: LUA: Entry Address: 0x38B0190
    INFO: LUA: Entry Size: 0x34
    INFO: LUA: Entry Reserved: true
    INFO: LUA: 55 8B EC 53 51 52 56 57 6A 00 6A 01 FF 75 08 E8 2C 53 C0 FC 83 C4 0C E8 14 C2 FA FC 50 FF 75 08 E8 8B 58 C0 FC 83 C4 08 B8 01 00 00 00 5F 5E 5A 59 5B 5D
    INFO: LUA: 5
    INFO: LUA: Entry Address: 0x38B01C4
    INFO: LUA: Entry Size: 0x36
    INFO: LUA: Entry Reserved: true
    INFO: LUA: 55 8B EC 53 51 52 56 57 6A 01 FF 75 08 E8 6A 56 C0 FC 83 C4 08 50 DB 04 24 83 EC 04 DD 1C 24 FF 75 08 E8 75 57 C0 FC 83 C4 0C B8 01 00 00 00 5F 5E 5A
    INFO: LUA: 6
    INFO: LUA: Entry Address: 0x38B01FA
    INFO: LUA: Entry Size: 0x34
    INFO: LUA: Entry Reserved: true
    INFO: LUA: EC 53 51 52 56 57 6A 00 6A 01 FF 75 08 E8 C2 52 C0 FC 83 C4 0C E8 AA C1 FA FC 50 FF 75 08 E8 D1 59 C0 FC 83 C4 08 B8 01 00 00 00 5F 5E 5A 59 5B 5D C3
    INFO: LUA: 7
    INFO: LUA: Entry Address: 0x38B022E
    INFO: LUA: Entry Size: 0x5F
    INFO: LUA: Entry Reserved: true
    INFO: LUA: 5D C3 3D D8 01 00 00 74 02 EB 51 FF B6 44 03 00 00 FF 35 0C 01 94 00 E8 C8 59 C0 FC 83 C4 08 FF 76 28 DB 04 24 83 EC 04 DD 1C 24 FF 35 0C 01 94 00 E8 FE 56 C0 FC 83 C4 0C 6A 00 6A 00 6A 00 6A 00 6A 01 FF 35 0C 01 94 00 E8 76 61 C0 FC 83 C4 18 EB 00 66 BB FF FF E9 9C 9D C8 FC E9 7F 9D
    INFO: LUA: 8
    INFO: LUA: Entry Address: 0x38B028D
    INFO: LUA: Entry Size: 0x53
    INFO: LUA: Entry Reserved: true
    INFO: LUA: FC FF 34 24 89 4C 24 04 E8 F7 CC C4 FC 68 98 5C FF 06 FF 35 0C 01 94 00 E8 67 59 C0 FC 83 C4 08 DB 04 24 83 EC 04 DD 1C 24 FF 35 0C 01 94 00 E8 A0 56 C0 FC 83 C4 0C 6A 00 6A 00 6A 00 6A 00 6A 01 FF 35 0C 01 94 00 E8 18 61 C0 FC 83 C4 18 E9 4D 7A
    INFO: LUA: 9
    INFO: LUA: Entry Address: 0x38B02E0
    INFO: LUA: Entry Size: 0x5F
    INFO: LUA: Entry Reserved: true
    INFO: LUA: 8B 45 08 48 83 F8 71 77 4A 0F B6 80 0C 98 61 00 50 68 58 5D FF 06 FF 35 0C 01 94 00 E8 0F 59 C0 FC 83 C4 08 DB 04 24 83 EC 04 DD 1C 24 FF 35 0C 01 94 00 E8 48 56 C0 FC 83 C4 0C 6A 00 6A 00 6A 00 6A 00 6A 01 FF 35 0C 01 94 00 E8 C0 60 C0 FC 83 C4 18 8B CF E8 36 96 D6 FC E9 39 94 D6
    INFO: LUA: 10
    INFO: LUA: Entry Address: 0x38B033F
    INFO: LUA: Entry Size: 0x3C
    INFO: LUA: Entry Reserved: true
    INFO: LUA: 45 04 A3 A0 5D FF 06 8B 86 78 14 00 00 A3 A4 5D FF 06 89 35 A8 5D FF 06 C7 45 04 64 03 8B 03 E9 D9 62 D6 FC FF 35 A4 5D FF 06 8B 0D A8 5D FF 06 E8 EB 7D D6 FC FF 25 A0 5D FF 06
    INFO: LUA: 11
    INFO: LUA: Entry Address: 0x38B037B
    INFO: LUA: Entry Size: 0x55
    INFO: LUA: Entry Reserved: true
    INFO: LUA: C0 1B E9 06 FF 35 0C 01 94 00 E8 85 58 C0 FC 83 C4 08 6A 00 6A 00 6A 00 6A 01 6A 00 FF 35 0C 01 94 00 E8 4D 60 C0 FC 83 C4 18 6A 00 6A FF FF 35 0C 01 94 00 E8 1B 51 C0 FC 83 C4 0C E8 03 C0 FA FC 50 6A FE FF 35 0C 01 94 00 E8 F5 4C C0 FC 83 C4 08
    INFO: LUA: 12
    INFO: LUA: Entry Address: 0x38B03D0
    INFO: LUA: Entry Size: 0x6F
    INFO: LUA: Entry Reserved: true
    INFO: LUA: 0F 84 40 24 EE FC 81 7D 8C 00 03 00 00 75 0D 80 7D 99 00 75 55 68 28 60 FF 06 EB 0E 81 7D 8C 01 03 00 00 75 45 68 80 5F FF 06 FF 35 0C 01 94 00 E8 0B 58 C0 FC 83 C4 08 FF 75 A0 DB 04 24 83 EC 04 DD 1C 24 FF 35 0C 01 94 00 E8 41 55 C0 FC 83 C4 0C 6A 00 6A 00 6A 00 6A 00 6A 01 FF 35 0C 01 94 00 E8 B9 5F C0 FC 83 C4 18 E9 B3 17 EE
    INFO: LUA: 13
    INFO: LUA: Entry Address: 0x38B043F
    INFO: LUA: Entry Size: 0x61
    INFO: LUA: Entry Reserved: true
    INFO: LUA: 68 A0 22 E9 06 FF 35 0C 01 94 00 E8 C0 57 C0 FC 83 C4 08 6A 00 6A 00 6A 00 6A 01 6A 00 FF 35 0C 01 94 00 E8 88 5F C0 FC 83 C4 18 6A FF FF 35 0C 01 94 00 E8 58 52 C0 FC 83 C4 08 50 6A FE FF 35 0C 01 94 00 E8 37 4C C0 FC 83 C4 08 58 85 C0 59 0F 85 C5 FF E4 FC E8 E5 F6 E4 FC E9 B5 FF
    INFO: LUA: 14
    INFO: LUA: Entry Address: 0x38B04A0
    INFO: LUA: Entry Size: 0xB60
    INFO: LUA: Entry Reserved: false

    Bubb
  • BubbBubb Member Posts: 641
    @kjeron: Aha! We got it on the run now!

    That code is corrupted, (or the debug dump function screwed out... which also means the code is corrupted). Several of the subroutines don't even have ret statements :no_mouth:

    Now we just have to figure out when they get corrupted. This is almost certainly in the write process; override your version of M__EEex.lua with the one I've attached.

    When the game boots it will print out what bytes it attempted to write to the cmd. Please post that here, and if it matches what EEex_DumpDynamicCode() returned, we will finally have a solid lead.

  • kjeronkjeron Member Posts: 1,965
    @bubb They indeed look similar.
    INFO: scanning:(13) C:/Users/William/Documents/Baldur's Gate II - Enhanced Edition/movies
    INFO: LUA:
    Writing Assembly at 0x3850000 => 55 8B EC 53 51 52 56 57 6A 02 FF 75 08 E8 9E 57 C6 FC 83 C4 08 85 C0 74 3C 8B F8 BE 01 00 00 00 56 6A 02 FF 75 08 E8 15 5D C6 FC 83 C4 0C 6A 00 6A FF FF 75 08 E8 96 54 C6 FC 83 C4 0C E8 7E C3 00 FD 50 6A FE FF 75 08 E8 73 50 C6 FC 83 C4 08 46 3B F7 7E CB 6A 00 6A 03 FF 75 08 E8 6F 54 C6 FC 83 C4 0C E8 57 C3 00 FD 50 6A 00 6A 01 FF 75 08 E8 5A 54 C6 FC 83 C4 0C E8 42 C3 00 FD 59 FF D0 50 DB 04 24 83 EC 04 DD 1C 24 FF 75 08 E8 CD 58 C6 FC 83 C4 0C 6A 00 6A 04 FF 75 08 E8 2E 54 C6 FC 83 C4 0C E8 16 C3 00 FD 03 E0 B8 01 00 00 00 5F 5E 5A 59 5B 5D C3

    INFO: LUA:

    Writing Assembly at 0x38500B8 => 55 8B EC 53 51 52 56 57 6A 00 6A 01 FF 75 08 E8 04 54 C6 FC 83 C4 0C E8 EC C2 00 FD 8B F8 6A 00 6A 02 FF 75 08 E8 2E 56 C6 FC 83 C4 0C 8B F0 8A 06 88 07 46 47 80 3E 00 75 F5 C6 07 00 B8 00 00 00 00 5F 5E 5A 59 5B 5D C3

    INFO: LUA:

    Writing Assembly at 0x3850101 => 55 8B EC 53 51 52 56 57 6A 00 6A 01 FF 75 08 E8 BB 53 C6 FC 83 C4 0C E8 A3 C2 00 FD FF 30 50 68 28 E7 ED 06 FF 75 08 E8 E3 5A C6 FC 83 C4 08 DB 04 24 83 EC 04 DD 1C 24 FF 75 08 E8 1F 58 C6 FC 83 C4 0C FF 34 24 DB 04 24 83 EC 04 DD 1C 24 FF 75 08 E8 08 58 C6 FC 83 C4 0C 6A 00 6A 00 6A 00 6A 00 6A 02 FF 75 08 E8 83 62 C6 FC 83 C4 18 DB 04 24 83 EC 04 DD 1C 24 FF 75 08 E8 DF 57 C6 FC 83 C4 0C B8 01 00 00 00 5F 5E 5A 59 5B 5D C3

    INFO: LUA:

    Writing Assembly at 0x3850190 => 55 8B EC 53 51 52 56 57 6A 00 6A 01 FF 75 08 E8 2C 53 C6 FC 83 C4 0C E8 14 C2 00 FD 50 FF 75 08 E8 8B 58 C6 FC 83 C4 08 B8 01 00 00 00 5F 5E 5A 59 5B 5D C3

    INFO: LUA:

    Writing Assembly at 0x38501C4 => 55 8B EC 53 51 52 56 57 6A 01 FF 75 08 E8 6A 56 C6 FC 83 C4 08 50 DB 04 24 83 EC 04 DD 1C 24 FF 75 08 E8 75 57 C6 FC 83 C4 0C B8 01 00 00 00 5F 5E 5A 59 5B 5D C3

    INFO: LUA:

    Writing Assembly at 0x38501FA => 55 8B EC 53 51 52 56 57 6A 00 6A 01 FF 75 08 E8 C2 52 C6 FC 83 C4 0C E8 AA C1 00 FD 50 FF 75 08 E8 D1 59 C6 FC 83 C4 08 B8 01 00 00 00 5F 5E 5A 59 5B 5D C3

    INFO: LUA:

    Writing Assembly at 0x385022E => 3D D8 01 00 00 74 02 EB 51 FF B6 44 03 00 00 FF 35 0C 01 94 00 E8 C8 59 C6 FC 83 C4 08 FF 76 28 DB 04 24 83 EC 04 DD 1C 24 FF 35 0C 01 94 00 E8 FE 56 C6 FC 83 C4 0C 6A 00 6A 00 6A 00 6A 00 6A 01 FF 35 0C 01 94 00 E8 76 61 C6 FC 83 C4 18 EB 00 66 BB FF FF E9 9C 9D CE FC E9 7F 9D CE FC

    INFO: LUA:

    Writing Assembly at 0x536B75 => B5 96 31 03

    INFO: LUA:

    Writing Assembly at 0x385028D => FF 34 24 89 4C 24 04 E8 F7 CC CA FC 68 08 BE FF 06 FF 35 0C 01 94 00 E8 67 59 C6 FC 83 C4 08 DB 04 24 83 EC 04 DD 1C 24 FF 35 0C 01 94 00 E8 A0 56 C6 FC 83 C4 0C 6A 00 6A 00 6A 00 6A 00 6A 01 FF 35 0C 01 94 00 E8 18 61 C6 FC 83 C4 18 E9 4D 7A EE FC

    INFO: LUA:

    Writing Assembly at 0x737D28 => E9 60 85 11 03

    INFO: LUA:

    Writing Assembly at 0x38502E0 => 8B 45 08 48 83 F8 71 77 4A 0F B6 80 0C 98 61 00 50 68 B8 E5 68 03 FF 35 0C 01 94 00 E8 0F 59 C6 FC 83 C4 08 DB 04 24 83 EC 04 DD 1C 24 FF 35 0C 01 94 00 E8 48 56 C6 FC 83 C4 0C 6A 00 6A 00 6A 00 6A 00 6A 01 FF 35 0C 01 94 00 E8 C0 60 C6 FC 83 C4 18 8B CF E8 36 96 DC FC E9 39 94 DC FC

    INFO: LUA:

    Writing Assembly at 0x385033F => 8B 45 04 A3 B0 BE FF 06 8B 86 78 14 00 00 A3 B4 BE FF 06 89 35 B8 BE FF 06 C7 45 04 64 03 85 03 E9 D9 62 DC FC FF 35 B4 BE FF 06 8B 0D B8 BE FF 06 E8 EB 7D DC FC FF 25 B0 BE FF 06

    INFO: LUA:

    Writing Assembly at 0x619771 => E9 6A 6B 23 03

    INFO: LUA:

    Writing Assembly at 0x61716C => 3F 03 85 03

    INFO: LUA:

    Writing Assembly at 0x385037B => 68 E8 17 EE 06 FF 35 0C 01 94 00 E8 85 58 C6 FC 83 C4 08 6A 00 6A 00 6A 00 6A 01 6A 00 FF 35 0C 01 94 00 E8 4D 60 C6 FC 83 C4 18 6A 00 6A FF FF 35 0C 01 94 00 E8 1B 51 C6 FC 83 C4 0C E8 03 C0 00 FD 50 6A FE FF 35 0C 01 94 00 E8 F5 4C C6 FC 83 C4 08 58 C3

    INFO: LUA:

    Writing Assembly at 0x616D5C => 1B 96 23 03

    INFO: LUA:

    Writing Assembly at 0x38503D0 => 0F 84 40 24 F4 FC 81 7D 8C 00 03 00 00 75 0D 80 7D 99 00 75 55 68 38 C1 FF 06 EB 0E 81 7D 8C 01 03 00 00 75 45 68 90 C0 FF 06 FF 35 0C 01 94 00 E8 0B 58 C6 FC 83 C4 08 FF 75 A0 DB 04 24 83 EC 04 DD 1C 24 FF 35 0C 01 94 00 E8 41 55 C6 FC 83 C4 0C 6A 00 6A 00 6A 00 6A 00 6A 01 FF 35 0C 01 94 00 E8 B9 5F C6 FC 83 C4 18 E9 B3 17 F4 FC

    INFO: LUA:

    Writing Assembly at 0x791BEC => E9 DF E7 0B 03

    INFO: LUA:

    Writing Assembly at 0x792812 => BA DB 0B 03

    INFO: LUA:

    Writing Assembly at 0x385043F => 51 68 88 24 EE 06 FF 35 0C 01 94 00 E8 C0 57 C6 FC 83 C4 08 6A 00 6A 00 6A 00 6A 01 6A 00 FF 35 0C 01 94 00 E8 88 5F C6 FC 83 C4 18 6A FF FF 35 0C 01 94 00 E8 58 52 C6 FC 83 C4 08 50 6A FE FF 35 0C 01 94 00 E8 37 4C C6 FC 83 C4 08 58 85 C0 59 0F 85 C5 FF EA FC E8 E5 F6 EA FC E9 B5 FF EA FC

    INFO: LUA:

    Writing Assembly at 0x700450 => E9 EA FF 14 03

    INFO: LUA: UI string not found: Recent events text will go here.

  • GrammarsaladGrammarsalad Member Posts: 2,467
    I don't want to interrupt any bug squashing, but I just wanted to say that I'm having a blast playing around with this! My mods are going to be much better because of this project!

    Bubb
  • OlvynChuruOlvynChuru Member Posts: 2,187
    edited January 7
    You can make new opcodes? OOOOOOOOOOOHHHH YESSSS! :)

    Here are some of my ideas:

    * Could we make an opcode that makes spells of a specific school cast by a character require more difficult saving throws (like the hardcoded specialist mage bonuses)? This would open the possibility of a lot of cool new items.

    * Would it be possible to unhardcode the special wild surge possibilities that alter your spell (e.g. spell cast twice, spell cast as an area of effect) and make an opcode that makes the next spell you cast (or all the spells you cast for the duration, depending on the parameters) trigger one of these alterations (another parameter would determine which alteration)? This would make it possible, for example, to implement Enoll Eva's Duplication in BG2:EE (and a lot of other things).

    * Would it be possible to make a version of the Use EFF File opcode that applies an effect if the target satisfies a SPLPROT.2DA condition? This would make it much simpler to create equipment that applies different effects depending on the character's stats.

    * Could we make a version of the Apply Spell on Movement opcode which, instead of casting the spell on the caster, casts the spell at the point the character is moving to? This would allow me to create a ghost PC who can move through walls by wing buffeting toward their destination (currently, even if a character has the Ignore Collision Detection opcode enabled, their pathfinding doesn't let them go through walls). I'm also considering making a mod that turns birds into normal creatures that can be interacted with. That alone I can do without EEEx, but with this opcode a charmed bird could fly around the map just by moving around!

    If we could implement any of these, that would be so awesome! :)

    GrammarsaladBubb
  • GrammarsaladGrammarsalad Member Posts: 2,467
    edited January 7
    All great ideas, but I particularly like this one:


    * Would it be possible to make a version of the Use EFF File opcode that applies an effect if the target satisfies a SPLPROT.2DA condition? This would make it much simpler to create equipment that applies different effects depending on the character's stats



    Can you alter existing opcodes?

    I would like to be able to change:

    * Alter #42 (0x2A) Spell: Wizard Spell Slots Modifier and #62 (0x3E) Spell: Priest Spell Slots Modifier so that they add spell slots regardless of whether or not the target actually has slots of that level. So, for example, even if you added a 1st level wizard slot to a single class fighter, they would gain a first level slot.

    * #323 (0x143) Stat:Turn Undead Level. I think it would be cool if #323 could add turn levels to creatures that do not already have them. So, again, if we applied this effect to a fighter, they would gain (say) one level of turn undead.

    * #214 expansion described here:
    https://forums.beamdog.com/discussion/62550/select-spell-opcode-214-expansion#latest

    New opcodes ideas:

    * Change Turn Undead Effect: something like change bard song. Maybe this would be two or more opcodes (I don't know how the ability works in the engine). Maybe one could change the type of creature affected, perhaps with values taken from splprot.2da. So, druids might be able to turn animals, for example. A second one might change the actual effects (e.g. from turn/destroy to paralysis/charm for our druid character, or from rebuke/dominate to cure/heal for an evil death cleric. A third one might change the effect based on the characteristics of the user, perhaps also using splprot.2da (so, say elfs 'turn' while non elfs 'rebuke', again, with 'turn' and 'rebuke' each potentially being defined by the second opcode above and the kind of creature affected being potentially defined by the first one...or something like that.)

    * Can't use spell: something like #180 (0xB4) Item: Can't Use Item, but for individual spells. My hope would be that this would prevent said spell from being memorizeable or selectable at character creation by a particular class or kit (say with this effect in their clab)

    * Proficiency points modification: an opcode that adds or subtracts proficiency points when applied by clab (so e.g. you could have a kit that has a bonus proficiency point or has fewer points or gets extra at level up, etc.)

    * Just because I'm here: Attributes. Is it possible to externalize them? Maybe increase the max number, and change what the values themselves represent. I would love to, e.g., give bonus proficiencies for high intelligence, save bonuses for high wisdom* and do... Something with charisma

    *Yeah, I can more or less do this now, but boni proficiencies for high int would be amazing--actually, that reminds me

    OlvynChuruBubb
  • kjeronkjeron Member Posts: 1,965

    * Would it be possible to make a version of the Use EFF File opcode that applies an effect if the target satisfies a SPLPROT.2DA condition? This would make it much simpler to create equipment that applies different effects depending on the character's stats.

    You can do this to an extent by combining opcodes 318+177. However, neither opcode 177 or the SPLPROT opcodes perform a constant check - they check once when it's first applied and if true will last until unequipped. To contrast, opcode 183 does perform a constant check to see whether or not the specified item type is equipped.


    * Proficiency points modification: an opcode that adds or subtracts proficiency points when applied by clab (so e.g. you could have a kit that has a bonus proficiency point or has fewer points or gets extra at level up, etc.)

    I'm not sure this would be feasible, if only because proficiencies are selected before the CLAB is applied during the level-up process. Extending "PROF.2DA" to support Kits might be an alternative though, or a new 2da to list levels with "bonus" proficiencies.

    GrammarsaladOlvynChuruBubb
  • GrammarsaladGrammarsalad Member Posts: 2,467
    edited January 7
    kjeron said:

    ...


    * Proficiency points modification: an opcode that adds or subtracts proficiency points when applied by clab (so e.g. you could have a kit that has a bonus proficiency point or has fewer points or gets extra at level up, etc.)

    I'm not sure this would be feasible, if only because proficiencies are selected before the CLAB is applied during the level-up process. Extending "PROF.2DA" to support Kits might be an alternative though, or a new 2da to list levels with "bonus" proficiencies.
    Insightful as always. I'm perfectly happy with an extendable prof.2da, etc.

    That does remind me: as far as I remember, kits cannot select proficiencies that are not selectable by the base class. This may be fixable already with lua, but if not, could that be implemented? (i.e. so that kits could select proficiencies barred to the base class at character creation and level up)

    AquadrizztBubb
  • OlvynChuruOlvynChuru Member Posts: 2,187
    edited January 7
    More ideas:

    * Could we make an opcode that temporarily replaces one of the target's scripts with a script of our choice (resetting the script after the effect ends)? This would let us make a lot of cool new enchantment spells (like one that forces the target to spin in place for the duration).

    * Could we make an opcode that modifies properties of the target object (e.g. the lock difficulty of a door, or the flags of a region)? Special would determine which property of the object would be modified; Parameter1 would determine by/to how much; Parameter2 would determine whether to add, set, multiply, set bits, or unset bits. The opcode would determine which object type to modify; if the effect were to target a different object type, it wouldn't do anything (these are just my ideas for parameters; they don't have to be arranged this way). This would allow us, for instance, to make a spell or ability that hijacks traps so that they trigger on enemies.

    * Could we make a version of the Pocket Plane opcode that lets us execute a script of our choice?

    * Would it be possible to make an opcode that applies a spell on the target depending on whether the target has its back to the caster? (If Special = 0 then apply the spell if the target has its back to the caster; if Special = 1 then apply the spell if the target doesn't have its back to the caster). This would allow us to make weapons have extra effects when they hit someone in the back (whether or not it's a backstab). It would also allow us to mod gaze abilities to not work if the target has their back turned.

    * Could we make a version of the Image Projection opcode that does not erase the scripts of the image? This would make it much easier to have enemies use Project Image or Simulacrum correctly. Also, could we make it so that this new opcode applies a spell of our choice (placed in the resource slot) to the image, rather than applying one of the special spells like MISLEAD.SPL? With this I could, for example, make a version of Mirror Image that creates up to 8 controllable Mislead-esque clones without having to change MISLEAD.SPL.

    Also, could we make new string tokens that give specific stats of the creature displaying the string? That would allow us to make new divination spells that display the stats of a creature (i.e. as an actual game mechanic to give the character information about the creature, rather than a debug thing). Or is it already possible to make new tokens like this?

    Would it be possible to make it so that there could be more than 255 spell states (say, up to 65535)? Currently, if you give a creature a spell state of 4000 and use Apply Effects List checking if the creature has spell state 4000, it doesn't work quite right.

    GrammarsaladAquadrizztBubbCrevsDaak
  • subtledoctorsubtledoctor Member Posts: 11,137
    Bubb said:

    So, anything else you guys want done? The sky is the limit.

    I've been longing for years for an opcode or action that ticks the 'OriginalClass' bit(s) - I think they are at offset 0x10 of the .CRE file. I once did it with NI I think: leveled up a multiclass demihuman fighter/cleric, then changed the .CRE file in the savegame to flip the 'OriginalClass:fighter' bit. Loaded up the modified save, and the game saw the character as a dual-class, and I only proceeded as a cleric thereafter.

    I have a whole mod concept designed around this, starting as multi and changing to dual. There is an OriginalClass trigger in the game, but no corresponding actions... :(

    OlvynChuruBubbGrammarsalad
  • BubbBubb Member Posts: 641
    All great ideas everyone. I'll get to work; though it will take a while to get them all done. I've replied to each one and inserted my own musings; a madman's way of keeping track of everything. :D

    Open at your own peril. I am not responsible for any damages caused by rogue walls of text.

    ------------------------------------------------------------

    * Could we make an opcode that makes spells of a specific school cast by a character require more difficult saving throws (like the hardcoded specialist mage bonuses)? This would open the possibility of a lot of cool new items.

    - Most definitely. I've located where the engine hardcodes these bonuses, I'd just have to externalize their behavior. In order for an opcode to affect this check, I'll have to change it from the harcoded bonus to polling a new STATS.IDS / SPLSTATE.IDS entry. Fun fact: stats and spell states both reside in CDerivedStats.

    * Would it be possible to unhardcode the special wild surge possibilities that alter your spell (e.g. spell cast twice, spell cast as an area of effect) and make an opcode that makes the next spell you cast (or all the spells you cast for the duration, depending on the parameters) trigger one of these alterations (another parameter would determine which alteration)? This would make it possible, for example, to implement Enoll Eva's Duplication in BG2:EE (and a lot of other things).

    - Opcode #280 forces a surge by setting bForceSurge in CDerivedStatsTemplate. Another stat / spell state will be needed to store which wild surge id to use. Alternatively, bForceSurge could instead be broken up into two 2 byte stats; the first of which forces the surge, second of which, when non-zero, forces the given id.

    * Would it be possible to make a version of the Use EFF File opcode that applies an effect if the target satisfies a SPLPROT.2DA condition? This would make it much simpler to create equipment that applies different effects depending on the character's stats.

    - I don't see why not. Though, isn't opcode #326 similar to what you are describing? I apologize; I am not as well versed as I'd like to be in "opcode land".

    * Could we make a version of the Apply Spell on Movement opcode which, instead of casting the spell on the caster, casts the spell at the point the character is moving to? This would allow me to create a ghost PC who can move through walls by wing buffeting toward their destination (currently, even if a character has the Ignore Collision Detection opcode enabled, their pathfinding doesn't let them go through walls). I'm also considering making a mod that turns birds into normal creatures that can be interacted with. That alone I can do without EEEx, but with this opcode a charmed bird could fly around the map just by moving around!

    - The engine uses CGameEffect::FireSpell() to cast the spell when the opcode is ticked. There is no point variant that resides in CGameEffect.

    CGameAIBase::FireSpellPoint is the closest I can find. The engine will treat the spell as if it was cast by the character, and the projectile originates from the character's position.


    ------------------------------------------------------------

    * Can you alter existing opcodes?

    - It's actually easier than making new ones.

    * Alter #42 (0x2A) Spell: Wizard Spell Slots Modifier and #62 (0x3E) Spell: Priest Spell Slots Modifier so that they add spell slots regardless of whether or not the target actually has slots of that level. So, for example, even if you added a 1st level wizard slot to a single class fighter, they would gain a first level slot.

    - It's easy to remove the "at least one slot" check from the opcode. The problem is that the engine still doesn't expect the character to be able to cast spells. You have to edit several places to enable the spell book, and then the game still reads the character's "casting level" as 0. When it's 0, the engine greys out all spellcasting of that type. So, it's doable, just more involved than simply changing the opcode.

    * #323 (0x143) Stat:Turn Undead Level. I think it would be cool if #323 could add turn levels to creatures that do not already have them. So, again, if we applied this effect to a fighter, they would gain (say) one level of turn undead.

    - Interestingly enough, it already does. The button is simply disabled if the character's base turn undead level is 0. Should be simple enough to fix.

    * #214 expansion described here:
    https://forums.beamdog.com/discussion/62550/select-spell-opcode-214-expansion#latest


    - Just have to add a level check to the existing code; easy.

    * Change Turn Undead Effect: something like change bard song. Maybe this would be two or more opcodes (I don't know how the ability works in the engine). Maybe one could change the type of creature affected, perhaps with values taken from splprot.2da. So, druids might be able to turn animals, for example. A second one might change the actual effects (e.g. from turn/destroy to paralysis/charm for our druid character, or from rebuke/dominate to cure/heal for an evil death cleric. A third one might change the effect based on the characteristics of the user, perhaps also using splprot.2da (so, say elfs 'turn' while non elfs 'rebuke', again, with 'turn' and 'rebuke' each potentially being defined by the second opcode above and the kind of creature affected being potentially defined by the first one...or something like that.)

    - I could hook into CGameSprite::TryToTurn() and then have it cast a spell if it succeeds. Would have to mimic the bard song externalization, but it's not impossible. I think all of the other effects could be handled in the secondary spells? (I.E. they don't need new opcodes?)

    * Can't use spell: something like #180 (0xB4) Item: Can't Use Item, but for individual spells. My hope would be that this would prevent said spell from being memorizeable or selectable at character creation by a particular class or kit (say with this effect in their clab)

    - Possible, but hard to implement. It would have to be a system written from scratch

    * Proficiency points modification: an opcode that adds or subtracts proficiency points when applied by clab (so e.g. you could have a kit that has a bonus proficiency point or has fewer points or gets extra at level up, etc.)

    - A quick modification of opcode #233 should do the trick.

    * Just because I'm here: Attributes. Is it possible to externalize them? Maybe increase the max number, and change what the values themselves represent. I would love to, e.g., give bonus proficiencies for high intelligence, save bonuses for high wisdom* and do... Something with charisma

    - Attributes are so hard coded that it would be infeasible to externalize them.

    *Yeah, I can more or less do this now, but boni proficiencies for high int would be amazing--actually, that reminds me

    - I think you forgot to finish what you were saying! :)

    ------------------------------------------------------------

    * Could we make an opcode that temporarily replaces one of the target's scripts with a script of our choice (resetting the script after the effect ends)? This would let us make a lot of cool new enchantment spells (like one that forces the target to spin in place for the duration).

    - ?Should? be possible to edit opcode #82 to store the previous script in Param3, and then restore it when it expires.

    * Could we make an opcode that modifies properties of the target object (e.g. the lock difficulty of a door, or the flags of a region)? Special would determine which property of the object would be modified; Parameter1 would determine by/to how much; Parameter2 would determine whether to add, set, multiply, set bits, or unset bits. The opcode would determine which object type to modify; if the effect were to target a different object type, it wouldn't do anything (these are just my ideas for parameters; they don't have to be arranged this way). This would allow us, for instance, to make a spell or ability that hijacks traps so that they trigger on enemies.

    - Should be possible to store previous value in Param3+ and modify existing ones; restoring previous values when the opcode expires.

    * Could we make a version of the Pocket Plane opcode that lets us execute a script of our choice?

    - Honestly, this is so easy I really don't know why the devs didn't do this in the first place.

    * Would it be possible to make an opcode that applies a spell on the target depending on whether the target has its back to the caster? (If Special = 0 then apply the spell if the target has its back to the caster; if Special = 1 then apply the spell if the target doesn't have its back to the caster). This would allow us to make weapons have extra effects when they hit someone in the back (whether or not it's a backstab). It would also allow us to mod gaze abilities to not work if the target has their back turned.

    Funny you should ask - my investigations here uncovered an internal visual arc function. Should be fun to implement -

    * Could we make a version of the Image Projection opcode that does not erase the scripts of the image? This would make it much easier to have enemies use Project Image or Simulacrum correctly. Also, could we make it so that this new opcode applies a spell of our choice (placed in the resource slot) to the image, rather than applying one of the special spells like MISLEAD.SPL? With this I could, for example, make a version of Mirror Image that creates up to 8 controllable Mislead-esque clones without having to change MISLEAD.SPL.

    - Yep and yep.

    Also, could we make new string tokens that give specific stats of the creature displaying the string? That would allow us to make new divination spells that display the stats of a creature (i.e. as an actual game mechanic to give the character information about the creature, rather than a debug thing). Or is it already possible to make new tokens like this?

    - It's possible to set tokens from the Lua environment, but that's about it. Should be easy enough to map new tokens to their internal values.

    Would it be possible to make it so that there could be more than 255 spell states (say, up to 65535)? Currently, if you give a creature a spell state of 4000 and use Apply Effects List checking if the creature has spell state 4000, it doesn't work quite right.

    - I was looking into this, and I think it's possible. This would be the only modification that would require a major change to an internal structure. I would have to extend the spell state storage space from 8 dwords... to, uh, 2048 dwords, if you wanted 65535 states. The problem? The CDerivedStats structure isn't a pointer, it's actually inlined into CGameSprite. That means expanding its size throws off EVERYTHING.

    I think the best solution would be to go about this in a different way. Instead of expanding the CDerivedStats structure, I could expand the CGameSprite structure by a dword. This dword would point to a structure of arbritrary length... theoretically allowing for infinite spell states. It would also require a new dynamic structure in .CRE files, kind of like how Known Spells are stored, but for spell states.


    ------------------------------------------------------------

    * I've been longing for years for an opcode or action that ticks the 'OriginalClass' bit(s) - I think they are at offset 0x10 of the .CRE file. I once did it with NI I think: leveled up a multiclass demihuman fighter/cleric, then changed the .CRE file in the savegame to flip the 'OriginalClass:fighter' bit. Loaded up the modified save, and the game saw the character as a dual-class, and I only proceeded as a cleric thereafter.

    I have a whole mod concept designed around this, starting as multi and changing to dual. There is an OriginalClass trigger in the game, but no corresponding actions... :(


    - You got it boss. One question: do you want the opcode to permanently flip the bit, (as in a direct-write to the bit with the opcode then being destroyed), or allow the opcode to attach to the creature and bit toggled back when it expires?

    ------------------------------------------------------------

    OlvynChuruGrammarsaladfortyseven
  • OlvynChuruOlvynChuru Member Posts: 2,187
    More ideas:

    * Could we make a SPLPROT.2DA condition that checks the value of a creature's circle size? The current conditions that NearInfinity says check a creature's circle size actually check the creature's personal space. I would prefer for effects that function differently for "large creatures" to do it based on circle size rather than personal space, because creatures with high personal space tend to get stuck in narrow passageways.

    * Currently the Modify Visual Range opcode can only increase the target's visual range by a max of 15. Would it be possible to allow this opcode to increase the target's visual range further?

    * Would it be possible to unhardcode the falling cow projectile's property of falling straight down (as opposed to the Comet projectile, which falls from an angle) and turn it into a projectile flag? I could use this flag to make a hook horror or beholder spawn after falling from the ceiling (similar to the way beholders spawn in Neverwinter Nights).

    * Could we unhardcode the list of casting glows and sounds for a spell? That seems like the kind of thing that should be in a 2DA.

    * Is there any way it could be made possible for a character to backstab with missile weapons (aside from long-range melee weapons like IWD Mordenkainen's Sword)?

    * Could we make it so that a weapon can use a non-physical damage type as its base damage type? This way, the Moonblade in Icewind Dale could deal more magic damage via the character's Strength modifier or other damage bonuses. This would also mean that the weapon would ignore the AC bonuses suits of armor grant against specific physical damage types, but then again, that's fitting for a non-physical damage type. ;)

    GrammarsaladfortysevenBubb
  • GrammarsaladGrammarsalad Member Posts: 2,467
    edited January 8
    Response to your response (for a few of my requests)

    Bubb said:

    ...

    Re: change turn undead opcode(s)

    - I could hook into CGameSprite::TryToTurn() and then have it cast a spell if it succeeds. Would have to mimic the bard song externalization, but it's not impossible. I think all of the other effects could be handled in the secondary spells? (I.E. they don't need new opcodes?)


    Heh, thinking about it, I might already be able to do all of this with the bard song. Normally, a 326 where the effect itself targets the caster, but where the spell targets another creature, will cast only if the caster meets those requirements. As such, you can have multiple 326s to account for any Attributes you care about with the caster.

    Then, the sec spells can then check the targets, again with multiple 326s (or 318 or 324 if you only care about one attribute), and cast the final spell as needed. So, with this you could have good clerics heal non undead, and damage undead with their 'turn' ability. Or, you could have a cleric that 'turns' undead and demons, etc. (Yeah, balance with the deal dam thing--the spl could protect against the spl and then disable the button for a time... Something like that)

    I guess the benefit of a similar opcode for turn would be for a character that might make use of both buttons... may not be worth it if it's too much trouble.

    Re: Can't use spell opcode

    - Possible, but hard to implement. It would have to be a system written from scratch


    Mmm. I'm mainly trying to find options to give unique spell lists to different kits and/or classes in a way that doesn't look too 'hacky'. The main issue is restricting particular actors from particular spells. Is a 2da more feasible?


    Me: * Proficiency points modification: an opcode that adds or subtracts proficiency points when applied by clab (so e.g. you could have a kit that has a bonus proficiency point or has fewer points or gets extra at level up, etc.)

    - A quick modification of opcode #233 should do the trick.


    That could be done? That wouldn't run into the issue that @kjeron brought up, that is, the character would not be able to 'spend' the proficiency point at level up? If so, I could easily simulate bonus proficiencies for intelligence!

    ...

    - I think you forgot to finish what you were saying! :)


    Lol. nope. It reminded me to ask about bonus proficiencies so I could simulate bonus proficiencies myself!

    Bubb
  • fortysevenfortyseven Member Posts: 63
    edited January 8
    This might be slightly off-topic but I would be interested to know if you can externalise other aspects of the interface with your method @Bubb. For example for a long time I have wanted to have access to mapping game commands including spells and special abilities to combined keyboard inputs (i.e. combining modifier keys like shift/alt/ctrl (and combinations thereof like shift+ctrl etc.) with alphanumeric/symbol keys.

    This would allow controlling the game much more efficiently through the keyboard. This was possible to an extent in the original game via the key mapping options that allowed combinations with shift but has been diminished to only single key assignments in EE. This means that only about 20% of all possible game commands can be mapped to the keyboard at any given time which I find very limiting.

    Extending this further, many abilities cannot be mapped at all at the moment as they aren't listed in the in-game key mapping menu. This relates in particular to innate skills and to skills and abilities added through modding. Therefore would it maybe be possible to map skills via an ID list of spells and abilities which can be expanded freely as well as a modifiable list of keys available for mapping?

    GrammarsaladFlashburnBubb
  • BubbBubb Member Posts: 641
    edited January 9
    @fortyseven: Hmm, after looking a the EE's keybind system, it's quite... interesting.

    The engine only uses 500 dwords to store keybinding data in memory - meaning, the game can only keep track of 500 unique keybind actions. The reason it doesn't show modded spells is because it's completely impossible for it to do so.

    The main keybind list ("keybindings") is stored in BGEE.LUA. The action the engine takes when a keybind is pressed is determined by the first column of this structure. Values 67 and below have hardcoded miscellaneous actions, while 68+ are bound to readying spells.

    The engine uses the 4th column of the spell keybinding structure to grab the spell's name. It then iterates through all of the currently selected character's spell buttons, and readies one if the tooltip, (the raw one, without keybinding text), matches. It's not testing for resrefs, or even strrefs, it's testing against TEXT...

    ...combined keyboard inputs (i.e. combining modifier keys like shift/alt/ctrl (and combinations thereof like shift+ctrl etc.) with alphanumeric/symbol keys... Extending this further, many abilities cannot be mapped at all at the moment as they aren't listed in the in-game key mapping menu. This relates in particular to innate skills and to skills and abilities added through modding...

    The EE keybinding system is inadequate in both regards; it will have to be a completely new system. I've already gotten key pressed / key released detection done, so it should just be a matter of implementing all of the actions again, and making a new graphical interface.

    GrammarsaladfortysevenCrevsDaak
  • subtledoctorsubtledoctor Member Posts: 11,137
    Bubb said:


    * I've been longing for years for an opcode or action that ticks the 'OriginalClass' bit(s) - I think they are at offset 0x10 of the .CRE file. I once did it with NI I think: leveled up a multiclass demihuman fighter/cleric, then changed the .CRE file in the savegame to flip the 'OriginalClass:fighter' bit. Loaded up the modified save, and the game saw the character as a dual-class, and I only proceeded as a cleric thereafter.

    I have a whole mod concept designed around this, starting as multi and changing to dual. There is an OriginalClass trigger in the game, but no corresponding actions... :(


    - You got it boss. One question: do you want the opcode to permanently flip the bit, (as in a direct-write to the bit with the opcode then being destroyed), or allow the opcode to attach to the creature and bit toggled back when it expires?

    I'm not sure how well the engine would really deal with this - last time I tested was on BGT - so best to make it as simple as possible. For my purposes, this would be permanent and irreversible. (Hint: it involves something like actually implementing 2E racial level limits :sunglasses: )
    Bubb said:


    * Proficiency points modification: an opcode that adds or subtracts proficiency points when applied by clab (so e.g. you could have a kit that has a bonus proficiency point or has fewer points or gets extra at level up, etc.)

    - A quick modification of opcode #233 should do the trick.

    Really?? That was asking for more points to spend on the level-up screen, not an ability to alter existing prof values. (Opcode 233 can already apply negative modifiers to proficiencies.)

    Bubb
Sign In or Register to comment.