Skip to content

[MOD] EEex (v0.10.2-alpha)

14243444648

Comments

  • AgerioAgerio Member Posts: 76
    Are there any plans of porting EEex to Android?
  • EndarireEndarire Member Posts: 1,519
    What would be involved in porting the IWDII opcode to double a creature's size to EEex for use in other Infinity Engine games?

    Thankee!
  • BubbBubb Member Posts: 1,005
    Agerio wrote: »
    Are there any plans of porting EEex to Android?
    Not at the moment. I'm not even sure if it's possible.


    Endarire wrote: »
    What would be involved in porting the IWDII opcode to double a creature's size to EEex for use in other Infinity Engine games?
    It's not an opcode - it's a hack that IWD2 includes to render the inventory sprite at 2x size on large resolutions. IWD2:EE (the mod) can manually toggle the hack for regular sprites in the world. There's no equivalent in the EEs as the classic renderer was discarded and rebuilt nearly from scratch.
  • EndarireEndarire Member Posts: 1,519
    Thankee!
  • p6kockap6kocka Member Posts: 66
    edited August 2023
    I have heard that it is possible to zoom the ui with EEex. How to do it pls?
    P.S. I have found it. By pressing F11
    Post edited by p6kocka on
  • kaiiakkaiiak Member Posts: 20
    edited August 2023
    hi @Bubb -
    I dont see Override/B3Hotkey.lua after installing the feature of advanced hotkey.
    I tried to use the old M_Hotkey.lua but EEX yells at me on B3HotkeyPressedListener function . Would you mind pasting the sample B3Hotkey.lua ?

    EDIT:NVM, found it

    EDIT2 : it's not working for me ,even the default '`' key does not print . is there anything else I should be doing ?
    Post edited by kaiiak on
  • EndarireEndarire Member Posts: 1,519
    @Bubb
    Could we get an EEex update to ensure dead party members and creatures controlled by players ("7th" party members like Brandock and Grey the Dog) don't drop their inventories upon death? I didn't like how inconvenient raising a dead character was due to all the inventory sorting and normally just reloaded instead.

    Thankee!
  • AllbrotherAllbrother Member Posts: 261
    Bubb wrote: »
    Bubb_StoreObjectStat(S:Variable*,O:Object*,I:Stat*STATS) - Stores the provided stat from the given object in the defined LUA variable.

    This appears to have been removed at some point? How would I accomplish this with the latest build?
  • BubbBubb Member Posts: 1,005
    Allbrother wrote: »
    Bubb wrote: »
    Bubb_StoreObjectStat(S:Variable*,O:Object*,I:Stat*STATS) - Stores the provided stat from the given object in the defined LUA variable.

    This appears to have been removed at some point? How would I accomplish this with the latest build?

    Just the "storing a stat in a variable" part? That can be done like this:
    EEex_LuaTrigger("myXP = EEex_LuaTrigger_Object:getStat(44); return true")
    

    If you need to fetch the stat from another object, (not the script runner), it gets more complicated. One way is to call out to a Lua function:
    EEex_LuaTrigger("Player1XP = EEex_Object_EvalStringAsAIBase('Player1', EEex_LuaTrigger_Object):getStat(44); return true")
    

    This is inefficient, verbose, and ignores AI immunities. TriggerOverride() is better, but still ignores AI immunities:
    TriggerOverride(Player1,EEex_LuaTrigger("Player1XP = EEex_LuaTrigger_Object:getStat(44); return true"))
    

    EEex_SetTarget() should probably have a trigger variant. This would allow resolving an arbritrary target, (subject to AI immunities), which can then be used in subsequent triggers.
  • AllbrotherAllbrother Member Posts: 261
    edited September 2023
    Thanks, AI immunities are not relevant for my purposes so this should work for me but ahh... Is the way to then set something to the variable also changed or am I doing it wrong? It was maxing the stats I was trying to store and then manipulate so I tried the below (appended to baldur.bcs) to test it out:
    IF
    	Global("test1","GLOBAL",1)
    	EEex_LuaTrigger("eeextest = EEex_Object_EvalStringAsAIBase('Player1', EEex_LuaTrigger_Object):getStat(40); return true")
    THEN
    	RESPONSE #100
    		EEex_LuaAction("intOverride0 = eeextest")
    		SetGlobal("test2","GLOBAL",-1)
    END
    

    But that just set the test2 global to -1, it did not change it to the character dex stat (value of the eeextest variable) like with the xp example on the first page
    mnyyhmc2ndmn.png
  • BubbBubb Member Posts: 1,005
    edited September 2023
    The override variables don't exist anymore. You can set the globals from Lua, e.g.:
    IF
        Global("test1","GLOBAL",1)
        // Fetch stat 40
        EEex_LuaTrigger("eeextest = EEex_Object_EvalStringAsAIBase('Player1', EEex_LuaTrigger_Object):getStat(40); return true")
    THEN
        RESPONSE #100
            // Set LOCALS
            EEex_LuaAction("EEex_LuaAction_Object:setLocalInt('test2', eeextest)")
            // Set GLOBAL
            EEex_LuaAction("EEex_GameState_SetGlobalInt('test2', eeextest)")
            // Fetch stat 40 and set GLOBAL all in one line
            EEex_LuaAction("EEex_GameState_SetGlobalInt('test2', EEex_Object_EvalStringAsAIBase('Player1', EEex_LuaAction_Object):getStat(40))")
            SetGlobal("test1","GLOBAL",-1)
    END
    
  • AllbrotherAllbrother Member Posts: 261
    edited September 2023
    Bubb wrote: »
    // Fetch stat 40 and set GLOBAL all in one line

    That's actually really cool. But what I was hoping to do was set the integer in a vanilla script action to the value of a variable (after I've saved a stat into that variable). I just used SetGlobal (and stat 40 for that matter) as it was an easy one to check ingame.
    Is that still possible?

    Specifically, for my current use case I need to save a stat into a variable (namely Fatigue, stat 30), perform an action (namely apply a spell with a rest effect) and then change the same stat to the value of the variable. I also imagine there'd be a lot of other uses for using a variable as an integer in other script actions.

    So from what I've gathered so far, the block would look something like this
    IF
    	// conditions
    THEN
    	RESPONSE #100
    		EEex_LuaAction("EEex_GameState_SetGlobalInt('test2', EEex_Object_EvalStringAsAIBase('Player1', EEex_LuaAction_Object):getStat(30))")
    		ApplySpellRES(spell,Player1)
    		EEex_LuaAction("something to achieve the effect of ChangeStat(Player1,FATIGUE,"test2",SET)")?
    END
    


    And just so this isn't entirely me asking to be spoonfed code, I've got a couple of other (probably silly) questions

    1.Would it be possible to raise or remove the limit of 8 characters who can clear fog of war through EEex?

    2.Would it be possible to mimic the vanilla Lock() action, but with additional parameters to set a difficulty and allow the newly locked door/chest to be picked (the vanilla action makes the object unpickable) through EEex?
  • paradoxxparadoxx Member Posts: 12
    I’d like to make a request. I can see on the GitHub page it’s been a while since Bubb posted a bigger update for EEex and I understand if he has moved on to other projects. I see he’s still poking his head in here from time to time, so I will give it a stab.

    It’s been suggested by several others before and relates to the select spell opcode 214. I’d like it to be able to select from learned spells for the different spell levels.

    This was described really well here:
    https://forums.beamdog.com/discussion/62550/select-spell-opcode-214-expansion

    I know it’s also been requested a few times in this thread, even if I can’t find the relevant posts right now.

    I reckon the reason it’s never been added is because it’s not easily done. Still, it would seriously help with the mod I’m working on. At the moment, I’m having to update the 2da spell lists for each spell level when playing the game and then reload. It’s very awkward and unsatisfying.

    So, if it could be added to EEex it would be amazing.
  • fortysevenfortyseven Member Posts: 96
    edited September 2023
    Hi @paradoxx, I think you might be referring to me. I have badgered Bubb several times about this very request. Even though it is a few years ago, I am still very keen to see it happen, as it would unlock a number of Kits I have been working on.

    From what I remember, Bubb had partially implemented this in the pre 0.9 version of EEEx. Unfortunately, I only ever saw it working for one spell level at a time. The way it worked, I believe, is that you had a list of spell ResRefs (essentially a 2da file like the ones you are using now) for a given spell level (or it could be a spell school or whatever grouping your fancied). It would check which spell resrefs your character had learnt and they got returned for opcode 214 to select from. However, it could only handle a single 2da which was identified through one specific lua file. Therefore, I believe it was only ever a test balloon.

    It is interesting that this was being requested even before EEEx was a thing. Given how ancient this game is now and everyone jumping ship for BG3, there might not be much of a crowd following this anymore. But regardless, it would certainly make me very happy if Bubb ever got round to it.

    edit
    I found the old code that directed towards the 2da spell resref file:

    if test2DA then test2DA:free() end
    test2DA = EEex_Wrap2DA("01SPL")
    
    function B3FILT(effectData, creatureData)
    
        local actorID = EEex_GetActorIDShare(creatureData)
        if not EEex_IsSprite(actorID) then return end
    
        local selectedActors = EEex_GetAllActorIDSelected()
        if #selectedActors ~= 1 or selectedActors[1] ~= actorID then return end
    
        local internalList = EEex_GetClearInternalList(creatureData)
    
        local knownSpells = {}
        EEex_ProcessKnownWizardSpells(actorID, function(resrefLocation)
            local resref = EEex_ReadString(resrefLocation)
            knownSpells[resref] = true
        end)
    
        local typeColumn = test2DA:findColumnLabel("Type")
        test2DA:iterateColumnLabel("ResRef", function(y, resref)
    
            if not knownSpells[resref] then return end
            local type = test2DA:getAtPoint(typeColumn, y)
    
            local spellData = EEex_GetSpellData(resref)
            local spellAbility = EEex_GetSpellAbilityData(creatureData, resref)
            local CButtonData = EEex_ConstructButtonData(resref, spellData, spellAbility, type)
            EEex_AddTail(internalList, CButtonData)
        end)
    
        EEex_SetActionbarState(0x6F)
    
    end
    

    The issue was that the B3FILT could only be addressed to a single 2DA file ("01SPL") in this case or whatever you wanted to name it. However, it could not handle any additional 2DAs and EEEx would only accept the B3FILT as the .lua prompt for the 214 opcode. The code above is defunct now and I never learnt if it would have been possible to expand it further.
    Post edited by fortyseven on
  • MasterGimliMasterGimli Member Posts: 14
    paradoxx wrote: »
    select spell opcode 214. I’d like it to be able to select from learned spells for the different spell levels.
    I just want to add that I think this is a fantastic proposal.
    fortyseven wrote: »
    Given how ancient this game is now and everyone jumping ship for BG3, there might not be much of a crowd following this anymore.
    Speak for yourself matey. Personally, I couldn’t give a fig about BG3 and hope Infinity will continue to inspire the modding community for years to come!

    It seems to me, if I get the gist of your post, this was pretty much working. Not just that, but it was even more flexible than what paradoxx suggests. It looks like you could make any kind of predefined selection of spells that known spells could check against. What a neat system. It would let you make some very interesting new kits I think. It just needed a little extra tweaking.

    Wouldn’t that mean it could be brought back without too much trouble?
  • fortysevenfortyseven Member Posts: 96
    @MasterGimli, you might be underestimating what is involved. 2.6 changed the game from 32-bit to 64-bit completely changing the underlying code. This module harks back to the 32-bit era and getting it to work would require coding it from scratch, as far as I understand. In addition, it was not finished. You could only target one 2DA file of predefined resrefs. Maybe @Bubb will share his thoughts, but he has not followed up on this request in several years.
  • BubbBubb Member Posts: 1,005
    It's possible via op402 (InvokeLua) combined with a Lua function, similar to before. However, some new engine bindings are required, so it can't be done in the current version of EEex. I'm looking into it, though I'm pretty busy right now, so no guarantees.
  • paradoxxparadoxx Member Posts: 12
    Bubb wrote: »
    It's possible via op402 (InvokeLua) combined with a Lua function, similar to before. However, some new engine bindings are required, so it can't be done in the current version of EEex. I'm looking into it, though I'm pretty busy right now, so no guarantees.

    Dear Bubb that would be amazing and thank you for respoding so quickly. I'm grateful for any time you can give to this.
  • fortysevenfortyseven Member Posts: 96
    edited September 2023
    Bubb wrote: »
    It's possible via op402 (InvokeLua) combined with a Lua function, similar to before. However, some new engine bindings are required, so it can't be done in the current version of EEex. I'm looking into it, though I'm pretty busy right now, so no guarantees.

    @Bubb thank you for all your efforts!

    Of course it was done via invoke Lua, sorry it’s been so long I was talking gibberish. Nevertheless, the Lua you wrote was essentially copying the function of opcode 214.

    If you are adding these additional engine bindings, would that make it possible to make multiple 214 type spells that invoke Lua, but each Lua can be a slightly different version each linking to a different 2DA? That was the bit I could not get to work last time, as 402 only seemed to recognise B3FILT and any other name was ignored as I presume it was bound via the name to EEex?

    That would allow to check learnt spells against multiple spell schools or spell levels etc. and make it possible to design entire Kits around this.
    Post edited by fortyseven on
  • MasterGimliMasterGimli Member Posts: 14
    fortyseven wrote: »
    If you are adding these additional engine bindings, would that make it possible to make multiple 214 type spells that invoke Lua, but each Lua can be a slightly different version each linking to a different 2DA? That was the bit I could not get to work last time, as 402 only seemed to recognise B3FILT and any other name was ignored as I presume it was bound via the name to EEex?

    @fortyseven are you sure about this?

    Opcode 402 tells the game to read a Lua script. While there might be a certain naming convention for the Lua files (or not), I’d be surprised if precise file names are predefined. I mean that would be very limiting and for what benefit?

    When Bubb is talking about engine bindings, I understand that he is referring to hooking particular Lua functions to his executable. That is about what can be coded and read in Lua files. It wouldn’t have anything to do with the file name.

    I’m no programmer, so take everything I say with a grain of salt, but your take just doesn’t make much sense to me. No offense intended.
  • fortysevenfortyseven Member Posts: 96
    @MasterGimli, say what you like and I certainly do not claim I understand the coding side very well. However, I know what I experienced.

    I tried everything I could to invoke differently named .lua files. Unfortunately, it just did not work in this case. The moment I changed, removed or added a single letter or numeral to the file name “B3FILT” it stopped working thus limiting it to a single list of spells. It was entirely possible to change the name of the 2DA file inside B3FILT.lua but not the name of the lua file itself.

    If you say this is odd, maybe there was some sort of bug, I do not know. In the end it did not work and I think it is important Bubb knows that.
  • BubbBubb Member Posts: 1,005
    @fortyseven: The old code should've been able to handle functions other than B3FILT, but in any case, I've implemented a new system :)



    New op214-like behavior is in master.

    op214 param2 now accepts 3 as a new mode. When param2 == 3 the resource field specifies a Lua function name, (must be ALL CAPS and 8 or less characters). This Lua function should return an iterator of CButtonData objects that are to be displayed in a typical op214 spell selection menu.

    Examples:

    Displaying all known mage spells of levels 1-5:
    function B3MAG5(effect, sprite)
        return EEex_Actionbar_GetOp214ButtonDataItr(EEex_Utility_SelectItr(3, 
            sprite:getKnownMageSpellsWithAbilityIterator(1, 5)
        ))
    end
    

    Displaying all known mage / priest necromancy spells:
    function B3NECRO(effect, sprite)
        return EEex_Actionbar_GetOp214ButtonDataItr(EEex_Utility_SelectItr(3, EEex_Utility_FilterItr(
            EEex_Utility_ChainItrs(
                sprite:getKnownMageSpellsWithAbilityIterator(1, 9),
                sprite:getKnownPriestSpellsWithAbilityIterator(1, 7)
            ),
            function(spellLevel, knownSpellIndex, spellResRef, spellHeader, spellAbility)
                return spellHeader.school == 7
            end
        )))
    end
    

    Displaying a typical op214 2DA:
    function B32DA(effect, sprite)
    	return sprite:getSpellButtonDataIteratorFrom2DA("SPWI510")
    end
    

    If you need help implementing a specific behavior let me know. I think the code speaks for itself somewhat, except maybe EEex_Utility_SelectItr(): This is adapting the known-spell iterator return values (spellLevel, knownSpellIndex, spellResRef, spellHeader, spellAbility) into just (spellResRef, spellHeader, spellAbility), as that's the input EEex_Actionbar_GetOp214ButtonDataItr() expects.
  • fortysevenfortyseven Member Posts: 96
    edited September 2023
    @Bubb, I'm incredible grateful that you have tackled this!

    I'm having some difficulty implementing it though.
    I have created a .spl that utilises op214. I have written 3 as a number in what Nearinifianty refers to as "Show" which I presume is param2. I have made a file called SPAMA.lua which I have written into the resource field.

    I have used
    function B3MAG5(effect, sprite)
        return EEex_Actionbar_GetOp214ButtonDataItr(EEex_Utility_SelectItr(3, 
            sprite:getKnownMageSpellsWithAbilityIterator(1, 1)
        ))
    end
    

    To make it check for known level 1 mage spells. Which simply called all known mage spells regardless of level.

    I then tried
    function B32DA(effect, sprite)
    	return sprite:getSpellButtonDataIteratorFrom2DA("01SPL")
    end
    

    Where 01SPL is a 2da resref list like the ones typically referenced by op214 using the same format. It included all the resrefs for lvl 1 mage spells. Unfortunately it also called all the mage spells the character knew irrespective of level.

    When I reloaded the .spl file in Nearinfinity, the op214 element reference had changed from SPAMA.lua to SPAMA.2da, eventhough ,I had asked it to reference a LUA file in Nearinfinity when I first specified the file.

    I'm sure I'm making a simple mistake but I can't pin point it. I presume I'm naming the LUA file incorrectly (somehow that always confuses me!)

    Many thanks!
  • BubbBubb Member Posts: 1,005
    edited September 2023
    @fortyseven: The resource field references the function name, not the Lua file. You should put the functions in a M_*.lua file so the engine automatically loads them on startup. Also, Near Infinity expects the resource field to be a 2DA, so that's why it lists it as such - it works all the same.

    If param2 == 3 still brings up all known mage spells, most likely you aren't running master. I've attached a packaged version with the usual WeiDU binary.
    Post edited by Bubb on
  • fortysevenfortyseven Member Posts: 96
    Thank you for the explanation @Bubb!

    Would it make sense to put all of these functions in a single M_*.lua file or would I need a seperate one for each?

    Furthermore, is the function name the bit in red at the start of your examples? The bit after function i.e. B3MAG5 in the first example, B3NECRO in the second and so on? Does that mean I can define any kind of name for these functions as long as they are less than 8 characters and written in caps?

    Thank you!
  • BubbBubb Member Posts: 1,005
    @fortyseven: Putting all of the functions in a single M_*.lua works well. And yes, when the syntax highlighter is working correctly the red part is the function name, (the text after "function", and before the opening parenthesis). You can use any function name as long as you follow the restrictions, (8 or less characters, ALL CAPS).
  • fortysevenfortyseven Member Posts: 96
    edited September 2023
    @Bubb
    I have goten the spell level based one to work and it works just the way you said. And it is brilliant, have wanted to get this to work for such a long time!

    However, if I use the 2DA based function example it will simply give access to all the spells on the 2DA list irrespective if the character has already learnt them or not. Looking at the wording of the function I guess that is what it is telling EEex to do. I can't see an instruction to check the 2DA against spells that are known unlike the other two examples you gave.

    Is there a way to combine the known spells check function as seen in the necromancy example with a bespoke 2DA list instead of a spell school?

    Something like:
    function B32DA(effect, sprite)
        return EEex_Actionbar_GetOp214ButtonDataItr(EEex_Utility_SelectItr(3, EEex_Utility_FilterItr(
            EEex_Utility_ChainItrs(
                sprite:getKnownMageSpellsWithAbilityIterator(1, 9),
                sprite:getKnownPriestSpellsWithAbilityIterator(1, 7)
            ),
    	function (effect, sprite)
    		return sprite:getSpellButtonDataIteratorFrom2DA("01SPL")
        )))
    end
    
  • BubbBubb Member Posts: 1,005
    edited September 2023
    @fortyseven: That's a bit more complicated. Try the following with the latest master version (attached):
    function B32DA(effect, sprite)
    
        local array = EEex_Resource_Load2DA("01SPL")
    
        local knownSpells = EEex_Utility_MapItrValues(3, EEex_Utility_ChainItrs(
            sprite:getKnownMageSpellsItr(1, 9),
            sprite:getKnownPriestSpellsItr(1, 7)
        ))
    
        local savedCastType
        return EEex_Utility_MutateItr(
            EEex_Actionbar_GetOp214ButtonDataItr(sprite:getValidSpellsWithAbilityItr(EEex_Utility_FilterItr(
                EEex_Utility_ApplyItr(array:getRowColumnsItr(nil, 0, 1), function(spellResRef, castType)
                    savedCastType = castType
                    return spellResRef
                end),
                function(spellResRef)
                    return knownSpells[spellResRef:upper()] ~= nil
                end
            ))),
            function(buttonData)
                buttonData.m_abilityId.m_itemType = tonumber(savedCastType) or 3
            end
        )
    end
    

    Edit: Fixed spells not being displayed if the 2DA didn't list the resrefs in UPPERCASE.
  • paradoxxparadoxx Member Posts: 12
    Dear @Bubb,
    I just wanted to thank you for making this available and so quickly too. I have tried all the different functions you have suggested and they work perfectly. I can now overhaul the spell and ability system and upgrade it to more modern editions as well as make a variety of new kits. If I release anything down the line I will be sure to reference your amazing input!
  • MasterGimliMasterGimli Member Posts: 14
    edited September 2023
    Just wanted to confirm that the new functions are all working for me as well. Massive thanks @Bubb. Really impressed how you overdelivered on the intial request and made the functions so broadly flexible. I will have a lot of fun with this!

    Odd bug I noticed, Armor of Faith doesn't show up with the 2DA function. But I think that isn't related to EEex but is related to the base game. It does show up with the level based function. All other spells included modded ones I have tested (which is hundreds) all work just right.

    I will mention your additions in the Nearinfinity thread. Maybe op214 can be amended to include these changes like some of the other EEex functions.
Sign In or Register to comment.