Howdy, Stranger!

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


Dark Dreams of Furiae - a new module for NWN:EE! Buy now
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.8.6-alpha)



  • CaedwyrCaedwyr Member Posts: 101
    I'm happy to see you are still around as well. The couple of small mods I put out in the day ended up being as slick as they were in large part to your help. The EE games certainly offer a lot of expanded modding capabilities that we all wanted for years back in the day. There's been some incredibly creative stuff created in the last decade since I have been away, so I'm jumping back in and sampling the best. My plan is to get a stable install and then go through the saga with some friends "book club" style. Play a chapter/set of quests and then discuss.

  • OlvynChuruOlvynChuru Member Posts: 2,579
    Bubb wrote: »
    OlvynChuru wrote: »
    It seems like right when a character finishes casting the spell, the data for the spell gets copied to somewhere else. Could you make hook that gives us the offset where the spell's data got copied to so that we could modify it?

    It has to do with the method of effect delivery. Spells that use projectiles first copy and shuffle along their effects to a projectile instance, then that projectile "delivers" the effect copies to anything it hits. The problem arises with non-projectile delivery, where the engine directly adds the effects to targeted actors. I'm looking into how to capture all these circumstances under one hook mechanism.

    I'd be fine with a hook like this even if for now it only worked with spells that use projectiles. I could still do things with this like change projectile area of effect size or projectile speed.

  • OlvynChuruOlvynChuru Member Posts: 2,579
    edited June 15
    @Bubb I sent you a pull request!

    New functions:

    EXCHARGE (for use with opcode 402) - Adds charges to an item in the character's inventory.


    EXMODAOE (for use with opcode 408) - Increases the area of effect of your spells.

    (Unfortunately, it doesn't make the area of effect indicator bigger; I don't know how to change that.)

    There's a problem with EXMODAOE: it changes the area of effect regardless of whether the projectile actually has an area of effect. This causes problems when it's used with single-target spells. How can I check whether the projectile has an area of effect?

  • BubbBubb Member Posts: 794
    Ok, well, figuring out the type of the projectile was harder than I thought. The engine doesn't store any type identifier on the projectiles, so I had to go crazy and manually find / match the projectile vftables. All of this is packaged up into EEex_IsProjectileOfType(), used like so:

    if EEex_IsProjectileOfType(projectileData, EEex_ProjectileType.CProjectileArea) then

    The EEex_ProjectileType constants match up with the internal projectile names, though some are unavailable due to not really existing in the engine anymore, (these are commented out in EEex_Pro.lua).

    Also, the Lua object template signature has changed:

    B3FIRE = {
        ["typeMutator"] = function(source, originatingEffectData, creatureData, projectileType)
        ["projectileMutator"] = function(source, originatingEffectData, creatureData, projectileData)
        ["effectMutator"] = function(source, originatingEffectData, creatureData, projectileData, effectData)

    The projectileData in effectMutator is new, and each function now has a source parameter. The source parameter is one of these constants:

    EEex_ProjectileHookSource = {
        ["SPELL"] = 0,
        ["SPELL_POINT"] = 1,
        ["FORCE_SPELL"] = 2,
        ["FORCE_SPELL_POINT"] = 3,
        ["UPDATE_AOE"] = 4,

    Note that the newly added UPDATE_AOE allows you to detect when the engine is previewing a projectile in order to display the AoE marker. If you limit your projectile mutations based on castings, make sure you don't let this mode count as a cast, (but still do the mutation so the engine displays your modifications).

    @OlvynChuru: Since I altered the Lua object template your pull request is now a little borked, once that is updated to match master I'll merge it, (also, I preemptively implemented your edit in EEex_Pro.lua, so it is no longer needed in the PR). I figured breaking the PR now and fixing it before merge was better than merging and immediately breaking it. Thanks for contributing, as always :)

  • nonlinearcoastnonlinearcoast Member Posts: 6
    Is there any way to find the RESref of a weapon where the damage is from the base weapon and not added by an effect?

    I know I can use EEex_DemandResData(parent_res, x) but it seems base weapon damage doesn't write a parent_res to its effects. Any workaround you clever guys have come up with?

  • BubbBubb Member Posts: 794
    @nonlinearcoast: Turns out that info isn't really kept-track of by the engine. I could do an EEex hook that puts something like "EEEX_DAM" into the parent resource field, and then fills Resource2 and Resource3 with the weapon resref and the launcher resref respectively - if that is sufficient and doesn't break some engine behavior somewhere.

  • nonlinearcoastnonlinearcoast Member Posts: 6
    @Bubb Thanks for your input that sounds like a good solution - What I'm trying to do is look up the flags on the weapon for example 'Silver/Iron' etc. and use that in the code for things like overcoming damage reduction.

  • BubbBubb Member Posts: 794
    edited June 18
    @nonlinearcoast: Alright, those fields are now filled in master! Example of how you access them via a Screen Effects opcode:

    function B3EFF(originatingEffectData, effectData, creatureData)
        local m_sourceRes = EEex_ReadLString(effectData + 0x90, 8)
        if m_sourceRes == "EEEX_DAM" then
            local curWeaponIn = EEex_ReadLString(effectData + 0x6C, 8)
            local pLauncher = EEex_ReadLString(effectData + 0x74, 8)
            print("curWeaponIn: '"..curWeaponIn.."'")
            print("pLauncher: '"..pLauncher.."'")

  • nonlinearcoastnonlinearcoast Member Posts: 6
    @Bubb, great it works really well thank you!

  • DavidWDavidW Member Posts: 781
    While I'm asking silly questions of people who know the game engine way better than I do:

    Is there any way to get information out of the CHARGEN screen? (Either with or without EEEx.) Presumably setting a global doesn't work because the game hasn't started; can one write to the game ini and then read it back in once the game starts?

  • BubbBubb Member Posts: 794
    @DavidW: What sort of info do you want to get out of the chargen screen? Some of it is accessible via the normal Lua environment, (since the engine has to display it). And interestingly, the GLOBAL's system actually does work in the chargen screen - if you set one via a C:SetGlobal() call, it appears ingame.

    EEex can grab additional values via memory reads, if it turns out you can't get to the info normally.

  • DavidWDavidW Member Posts: 781
    edited June 22
    Globals actually work?! I was sufficiently confident they wouldn't, I didn't think to check. (Is that with EEEx, or in the unmodded engine?)

    What I'd ideally like (thinking this through further) is a way to attach a stat or splstate to a character on character creation, though there's probably something I can do through GLOBAL.

  • fortysevenfortyseven Member Posts: 70
    Bubb wrote: »
    I've been working on tweaking the spell system for the past couple of days - EEex now allows traps / doors to be targetable via spells. With the addition of some new trap-manipulating functions, and Invoke Lua now functioning on triggers/doors/containers, it's possible to create a spell that disarms traps!

    For example, an Invoke Lua (Opcode 402) utilizing the following function can disarm any trap normally removable by a thief, (all the prerequisites to disarming are defined separately, so you can remove one/more of them if you wish):

    This is amazing! I have longed for this option for years. No more deadweight thiefs on my team! Yay! B)

  • fortysevenfortyseven Member Posts: 70
    Sorry if this is a dumb question, but how do I get NI to recognise EEex opcodes? For example for Opcode 402, how can I direct NI to the resource key?

  • OlvynChuruOlvynChuru Member Posts: 2,579
    @fortyseven Right-click the resource field and select "Edit as string."


  • fortysevenfortyseven Member Posts: 70
    Thank you Olvyn!

    Unfortunately, I can't get Bupp's new disarm trap lua to work. I have copied his B3Trap code into a lua file, placed it in override and now have linked it as Olvyn suggested. I was trying to add this onto the Knock spell. I have attached the files below if anyone can point me to what I am doing wrong.

  • BubbBubb Member Posts: 794
    @fortyseven: Rename "B3TRAP.lua" to "M_B3TRAP.lua", the engine ignores Lua files unless they are prefixed with "M_" :)

  • fortysevenfortyseven Member Posts: 70
    edited June 27
    Its working now. I was too stupid to use the correct EEex master!

  • nonlinearcoastnonlinearcoast Member Posts: 6
    @bubb do you now anything about enabling 8-9 priest spells? My ui knowledge is limited but it seems simply extending the existing code in and adding some buttons isn’t enough to get it to display these. Is there some hard coded limitation to the functions there?

  • Luke93Luke93 Member, Mobile Tester Posts: 1,369
    edited July 1

    A couple of other ideas:
    1. When an enemy goes invisible, all visual animations attached to it (via opcode #215, #204 and the like) should go invisible as well (and come back when it's no longer invisible). Note that this can already be done nowadays, but it's somewhat complicated / tricky...
    2. A new Spell() Action that can be used to cast a spell at a location offset from the target object point, i.e.: Spell(O:Target*,P:Offset*,I:Spell*Spell)

  • DavidWDavidW Member Posts: 781
    for (1) SCS does this already (perhaps that's what you're referring to?) But yes, it's complicated (and requires buy-in from the scripts).

  • Luke93Luke93 Member, Mobile Tester Posts: 1,369
    DavidW wrote: »
    (perhaps that's what you're referring to?)

    Yes, I was referring to your implementation (the only one available so far...? Actually, it's probably impossible to implement it in a different way... Anyway, it's so much needed...)

  • Luke93Luke93 Member, Mobile Tester Posts: 1,369
    Another one:

    The possibility to use "ANIMATE = specified value" with opcode #318, #324 and #326.

  • GalactygonGalactygon Member, Developer Posts: 382
    edited July 5
    DavidW wrote: »
    for (1) SCS does this already (perhaps that's what you're referring to?) But yes, it's complicated (and requires buy-in from the scripts).

    Currently that behavior is hardcoded into the minor globe, shield globe, and iirc the sanctuary opcodes if you leave the .vvc resource field blank. The animations disappear if the opponent disappears invisible and then resume playing when the opponent reappears even if 1/2 invisible with improved invsibility. The animations do not disappear at all if a party member playing them becomes invisible. It might be possible do outsource any persistant animations to external (repeating) effects/spells and then block them from playing while an opponent is invisible but it's a hacky solution at best.

    Imho it would make the most sense to have a .vvc flag possibly at 0x18 that hides the associating .bam while the target (if not allied) is completely invisible.

  • fortysevenfortyseven Member Posts: 70
    edited July 6
    @Bubb Would it ever be possible to make an opcode for EEex that can suppress sound and string effects without having to target a specific opcode, eff, vvc etc that they are used in but simply the specific sound resource key or string number. Essentially I want to block the engine from using specific sounds or strings in specific situations.

  • TheImpTheImp Member Posts: 5
    @Bubb can you add/edit some opcode so that it can set the .cre-ature files original class -flags ? I am talking about the files offset's 0x000c bits 3, 4, 5, 6, 7 and 8.

  • BubbBubb Member Posts: 794
    edited August 4
    @TheImp: EEex can set any field, given you know where it is in memory. Throw the following function into an M_*.lua file and put that in the override folder. Invoke it from a spell via the following:

    Opcode -> 402 (Invoke Lua)
    Parameter1 -> Original Class mask
    Parameter2 -> Mode (0 = unset, 1 = set)
    Resource -> B3OCLASS (capitalization matters)
    function B3OCLASS(effectData, creatureData)
        local param1 = EEex_ReadDword(effectData + 0x18)
        local param2 = EEex_ReadDword(effectData + 0x1C)
        local creFlags = EEex_ReadDword(creatureData + 0x424)
        if param2 == 0 then
            EEex_WriteDword(creatureData + 0x424, EEex_UnsetMask(creFlags, param1))
        elseif param2 == 1 then
            EEex_WriteDword(creatureData + 0x424, EEex_SetMask(creFlags, param1))

    Technically this can set any bit in the creature flags, given you use the correct mask.

    Note that the memory offset might change in future versions. But with v2.6 being a complete shift from 32bit to 64bit, EEex will have to be rebuilt from the ground up anyway.

Sign In or Register to comment.