Skip to content

[MOD] EEex (v0.10.2-alpha)

1323335373848

Comments

  • GrammarsaladGrammarsalad Member Posts: 2,582
    edited November 2020
    Nevermind. Something is borked on my install.
    Post edited by Grammarsalad on
  • FlashburnFlashburn Member Posts: 1,847
    Is it possible to add another extended stat to STATS.IDS to make it so spells cast by a character ignore a certain amount of magic resistance? It'd be nice to simulate Spell Penetration feats because its always a pain to go up against mobs with high MR.
  • EclaTriompheEclaTriomphe Member Posts: 4
    edited January 2021
    English is not my mother-tongue, so there could be awkward expressions that I'm sorry.
    ---
    vs Melissan

    <Vanilla (2.5.16.6)> *I mean vanilla for no mod at all
    She uses Stoneskin ▶ We use Breach ▶ and Greater-whirlwind ▶ Victory

    <EEex.exe with no any other mod(even your Spell Menu)> still 2.5.16.6 of course
    Breach doesn't work anywhere
    (Chat log says it worked, though)
    She gets no damage from any physical attack
    and uses stoneskin again and again with very short term consistently

    But!
    If we use Pierce Magic(or Ruby Ray of Reversal, Khelben's Warding Whip or so),
    chat log would say dispelled *twice*
    and then our physical attacks could get to her own skin,
    and she will not use stoneskin anymore
    ---
    I'm sorry if what I've written is already known issue,
    but I'm not fluent English user so that I couldn't read all the comments of this article
    (slow reader)

    Happy 2021
    Post edited by EclaTriomphe on
  • LogiteksLogiteks Member Posts: 21
    edited January 2021
    Flashburn wrote: »
    Is it possible to add another extended stat to STATS.IDS to make it so spells cast by a character ignore a certain amount of magic resistance? It'd be nice to simulate Spell Penetration feats because its always a pain to go up against mobs with high MR.

    while I don't know how to do it via global hook (if it's even possible) you could achieve it using following weidu patching on all castable spells, using Invoke Lua opcode:
    LPF ADD_SPELL_EFFECT INT_VAR opcode = 402 target = 2 insert_point = 0 STR_VAR resource = "MYFUNC" END
    
    and than create MYFUNC function that will alter magic resistance (EEex_ApplyEffectToActor, opcode 166, timing 0, duration 0) based on stat value. It will be called before other spell effects are applied, so I'm pretty sure the spell resistance change will affect them. You need to know Lua language and study EEEX code to write stuff like this tho.
    Post edited by Logiteks on
  • LogiteksLogiteks Member Posts: 21
    Huh, looks like my message somehow disappeared so I'm reposting the message:

    I have some questions regarding EEEX usage:
    1. Does anyone know offset to read currently equipped launcher resource name? (or slot occupied by it) As a test I've adopted EEex_IterateActorItems code so that it returns equipped slot res:
    local equippedWeaponSlot = EEex_ReadByte(share + 0xB1C, 0x0)
    local invItemData = EEex_ReadDword(share + 0xA80 + equippedWeaponSlot * 4)
    if invItemData > 0 then
    	local itemRES = EEex_ReadLString(invItemData + 0x8, 8)
    	print(itemRES)
    end
    

    but if the currently equipped weapon is launcher that requires ammo, the printed message is the ammo RES instead of launcher RES. I could iterate all 4 weapon slot and check if they are launchers but that wouldn't be accurate if there is more than 1 launcher of the same type equipped.

    2. Is there a list of all possible action IDs returned by EEex_GetActionID?

    3. Any way to hook a lua function that would trigger when cre has target set with intention to attack, but before making weapon attack rolls?

    4. Is it possible to fool the engine into thinking that particular effect applied by EEEX comes from currently equipped item? I've tried something like this with timing = 2:
    EEex_ApplyEffectToActor(targetID, {
    	["opcode"] = 401, --Set Extended Stat
    	["target"] = 1,
    	["parameter1"] = 666,
    	["parameter2"] = 1,
    	["timing"] = 2, --Instant/While equipped
    	["special"] = 666,
    	["restype"] = 2,
    	["parent_resource"] = "SW1H01",
    })
    
    But this effect does not go away when the SW1H01 is unequipped. It's not saved directly on character when save file is viewed in Near Infinity, which leads me to believe that maybe it's some flag that is missing here or something like that.
  • TressetTresset Member, Moderator Posts: 8,268
    @Logiteks Your post was caught by the forum's automated spam filter. I have verified you so that this should not happen again.
  • OlvynChuruOlvynChuru Member Posts: 3,079
    Logiteks wrote: »
    2. Is there a list of all possible action IDs returned by EEex_GetActionID?

    Yes: there is ACTION.IDS.
    Logiteks wrote: »
    3. Any way to hook a lua function that would trigger when cre has target set with intention to attack, but before making weapon attack rolls?

    Yes.
    EEex_AddActionHookGlobal("ONATTACK", function(actionData, creatureData)
    	local actionID = EEex_GetActionID(actionData)
    	local sourceID = EEex_ReadDword(creatureData + 0x34)
    	local targetID = EEex_ReadDword(actionData + 0x20)
    	if actionID == 3 or actionID == 94 or actionID == 98 or actionID == 105 or actionID == 134 then 
    		-- Your code here
    	end
    end)
    
  • LogiteksLogiteks Member Posts: 21
    This is even better implementation than I expected. Global hook like this opens so much modding opportunities when it comes to altering hardcoded gameplay mechanics. Thanks for the sample code!
    Yes: there is ACTION.IDS.
    :o great.
  • LogiteksLogiteks Member Posts: 21
    edited January 2021
    regarding question 1. I wasn't able to find the exact offset to reliably read equipped launcher res, but there is another way to get the res name - iterating through effects applied to cre with timing = 2 (Instant/While equipped) and reading the sourceslot of these effects. Here is a function that returns both mainhand and offhand weapon res (stored in a table) in case someone else needs this (code adopted from @OlvynChuru's spells mod - gold mine when it comes to EEex lua scripts)
    function getWeaponRes(id)
    	local t = {"", ""}
    	EEex_IterateActorEffects(id, function(eData)
    		if EEex_ReadDword(eData + 0x24) == 2 then --timing: Instant/While equipped
    			local sourceslot = EEex_ReadDword(eData + 0xA4)
    			if sourceslot == 10 or (sourceslot >= 35 and sourceslot <= 38) then --SLOT_FIST / SLOT_WEAPON
    				t[1] = EEex_ReadLString(eData + 0x94, 8)
    			elseif sourceslot == 9 then --SLOT_SHIELD
    				t[2] = EEex_ReadLString(eData + 0x94, 8)
    			end
    		end
    	end)
    	return t
    end
    
    To make it 100% reliable weidu patching all weapons with some dummy timing = 2 effect is needed (otherwise some weapons with 0 on equip effects won't be detectable).

    edit: question 4 is no longer relevant because the same thing can be already achieved using opcode 407 (Cast spell on effect remove) with timing mode set to 2 (while equipped), which casts spell the moment item is unequipped.
    Post edited by Logiteks on
  • LogiteksLogiteks Member Posts: 21
    edited January 2021
    bug report:
    using EEex_2DALoad more than once crashes the engine. Example (tested by pasting in plain M_ file)
    local xplevel = EEex_2DALoad("XPLEVEL")
    local xpcap = EEex_2DALoad("XPCAP")
    
    works fine when only 1 2da file is loaded.

    feature request:
    a way to disable hardcoded spell interruption on taking damage. Existing CONCENTR.2DA modes are not flexible enough (according to kjeron and Bubb, mode = 1 is also bugged, so the only option is either 100% chance or using static 15 in formula).
    When disabled completely I think we would be able to write custom formula using existing EEex functionality (detecting damage opcode, interrupting spell as needed via forced hurt animation)
    Post edited by Logiteks on
  • LogiteksLogiteks Member Posts: 21
    edited February 2021
    thanks, 2da loading works correctly now!

    Did I mention that EEex is awesome? :P
    Anything I do now is effectively pointless, (as the 64-bit jump ensures that any hooks I write will be obsolete in the next executable), and I can't start work on v2.6 until the PDB is dropped with its full release.
    If there will be problems with porting EEex to v2.6, I will stay with 2.5 forever, that's for sure. It's incredible how much EEex opens up modding possibilities.


    btw. ignore the above feature request - it's already possible to make spell uninterruptable by hit thanks to EEex_AddScreenEffectsGlobal.

    edit:

    After some further testing having CONCENTR.2DA working opposite way to mode = 0 (none of the attacks interrupting spellcasting) would be preferable. Implementing it by blocking damage opcode via EEex_AddScreenEffectsGlobal requires to directly modify target's HP, display Damage string etc. (since opcode 12 can't be used for this purpose). Doing it this way would require taking tons of factors into account (rolling, flags, damage reduction, resistances etc.) So yeah, the original feature request is still valid.
    Post edited by Logiteks on
  • MrBaquanMrBaquan Member Posts: 42
    Is there a Mac version of this?
  • LogiteksLogiteks Member Posts: 21
    MrBaquan wrote: »
    Is there a Mac version of this?
    no


    question: does anyone knows roughly what EEex_GetDistanceIsometric value is an equivalent of 1 feet and default visual range?
  • BubbBubb Member Posts: 1,005
    edited February 2021
    Logiteks wrote: »
    question: does anyone knows roughly what EEex_GetDistanceIsometric value is an equivalent of 1 feet and default visual range?

    The engine hardcodes 0x1C0 (or 448) as the default visual range. No idea what it considers a foot, though if there's a known value (in feet) for the visual range you should be able to figure it out.
  • kjeronkjeron Member Posts: 2,368
    Bubb wrote: »
    The engine hardcodes 0x1C0 (or 448) as the default visual range. No idea what it considers a foot, though if there's a known value (in feet) for the visual range you should be able to figure it out.
    Horizontal: 16 = 1 foot
    Vertical: 12 = 1 foot
    Default visual Range = 28 ft
  • BubbBubb Member Posts: 1,005
    kjeron wrote: »
    Horizontal: 16 = 1 foot
    Vertical: 12 = 1 foot
    Default visual Range = 28 ft

    Thanks, it's been a while since I worked with this stuff, that rings a bell.

    For Logitek: Note that EEex_GetDistanceIsometric() will consider 1 foot = 16, it uses the horizontal-scale.
  • nonlinearcoastnonlinearcoast Member Posts: 11
    I'm using screeneffects to look at income damage effects and then run some code. However if an actor has a mirror image effect, that damage sometimes actually gets cancelled as it doesn't really 'hit'. Is there anyway to check if if an effect is going to get through the mirror image or not?

    I thought maybe I can just change the incoming effect flag to ignore mirror image and then replicate the effects of mirror image in my code, but that seems a bit overkill. any ideas?

    Thanks
  • BubbBubb Member Posts: 1,005
    edited February 2021
    I'm using screeneffects to look at income damage effects and then run some code. However if an actor has a mirror image effect, that damage sometimes actually gets cancelled as it doesn't really 'hit'. Is there anyway to check if if an effect is going to get through the mirror image or not?

    I thought maybe I can just change the incoming effect flag to ignore mirror image and then replicate the effects of mirror image in my code, but that seems a bit overkill. any ideas?

    Thanks

    Not easily; ScreenEffects kicks in right after probabilities have been rolled, (and passed), but before all the other checks. The damage effect essentially forces a successful save, (even if it didn't allow one), when it hits a mirror image. I might co-opt the special field of ScreenEffects to allow you to specify where in the application process it intercepts the effect, (I.E. after probability, after save checks, etc.) - that should allow you to do what you want.
  • nonlinearcoastnonlinearcoast Member Posts: 11
    @Bubb Thanks, that would seem like a really useful solution. I'm sure it would expand the flexibility and usefulness of screeneffects for other uses too.

    Whilst on the subject of saves and checks, is there currently a way to customise the saving throw rolls, or attack rolls? For example if you wanted to change the way saving throws worked or how attack rolls are calculated?

    What I am thinking about is trying to implement different 'types' of bonuses. e.g. AC bonus but actors can have different types (natural armor/deflection etc.), some of which stack and some don't. (I would specify the 'type' in some bit of AC bonus opcode, then LUA can iterate and calculate the final AC as I want).

    Thoughts very welcome.

    Thanks,
  • LogiteksLogiteks Member Posts: 21
    edited February 2021
    @nonlinearcoast, for saves and other things that are checked after opcode is screened (once a hit is successful and probability rolls passed) you should be able to modify that stuff directly during screening, for example: (untested but something like this should work)
    function MYFUNC(originatingEffectData, effectData, creatureData)
    	local targetID = EEex_GetActorIDShare(creatureData)
    	local opcode = EEex_ReadDword(effectData + 0xC)
    	if opcode == 12 then --Damage
    		local saveBonus = EEex_ReadDword(effectData + 0x40)
    		EEex_WriteDword(effectData + 0x40, saveBonus + 10) --adding 10 to save throw bonus of this effect
    	end
    end
    
    I'm pretty sure that if you use EEex_ApplyEffectToActor with timing 0 and duration 0 to modify saving throws on targetID during screening, they will be taken into account too.

    As for the AC and/or attack bonus, it's a bit more tricky since you need to apply it before attack rolls. So using EEex_AddActionHookGlobal and applying effects based the current action and various factors may be needed. It would be costly solution though, performance wise, I think, and it requires cleaning bonuses once they are no longer needed, so not sure if this is the right approach.
    Post edited by Logiteks on
  • nonlinearcoastnonlinearcoast Member Posts: 11
    @logiteks yes that does work for saves that are checked after screening, and you can make things like a save vs opcode bonus, or save vs fire damage etc. So yes it is possible to have full control of saves by screening all effects and modifying the save bonuses as you see fit (or you can just screen and remove all saves then include custom code). I was just thinking it would be even better if we just had full access to replace/override the coding the engine uses when a save happens.

    For attacks rolls I don’t really see an easy solution, as there is no effect to screen before the roll is successful. Maybe you can screen actions and when an actor attacks run all your own code to complete the attack, then cancel the engines attack? I assume you would need to code everything from running the attack animation etc, which seems like too much work...

    or perhaps just detect an attack and apply bonuses to AC/thaco etc (which Is what I think you are suggesting?). But as you say you’d need to remove them again after the attack is done. Not sure if there are easy ways to apply bonuses just for the next attack for example. So in the case of attack rolls it really would be useful to be able to hook those and replace their coding.
  • LogiteksLogiteks Member Posts: 21
    edited February 2021
    about this timer visualization feature that was not implemented after all:
    xwshsmby22uq.gif
    Could anyone please point to offsets (structure and names used in EEex docs) where this timer data is stored? (round, modal actions, spell intervals, spell cooldown, possibly attacks, although these were not mentioned in Bubb's post)
    Post edited by Logiteks on
  • FlashburnFlashburn Member Posts: 1,847
    @Logiteks
    My best guess is to look at M__EEex.lua, B3_Timer.lua, and B3_Timer.menu.
  • LogiteksLogiteks Member Posts: 21
    edited February 2021
    Flashburn wrote: »
    @Logiteks
    My best guess is to look at M__EEex.lua, B3_Timer.lua, and B3_Timer.menu.

    Thanks. Indeed, there are even dedicated functions to read this data already:
    EEex_GetActorModalTimer
    EEex_GetActorSpellTimer
    EEex_GetActorCastTimer
  • nonlinearcoastnonlinearcoast Member Posts: 11
    Is anyone able to use extended skills correctly?

    I can add new skills and these show up in game, but having issues in the level up screen. During char generation, i can add points to extended skills but not remove them again (the minus button does nothing). Also on level up screen there is a curious effect where adding or removing points from extended skills also increases/decreases a normal thief skill in the list above it (so the points are 'used' twice).

    My skills with UI are not good enough to see where this is going wrong. Anyone else had this issue?
  • nonlinearcoastnonlinearcoast Member Posts: 11
    Okay, for anyone interested I've managed to fix it.
    To fix the minus button not working for extended skills, I removed:
    "chargen.levelingUp" from the below chunk, which stops the minus button working in the char gen screen but works okay in the level up screen. Im not sure what the rationale for that is but works fine with it removed for me.
    if chargen.levelingUp and currentChargenThiefSkill > firstExtendedSkillIndex then
    		if  chargen.thief_skill[currentChargenThiefSkill].value > extendedSkills[exIndex].base then
    			chargen.thief_skill[currentChargenThiefSkill].value = chargen.thief_skill[currentChargenThiefSkill].value - 1
    			extendedSkills[exIndex].value = extendedSkills[exIndex].value - 1
    			chargen.extraSkillPoints = chargen.extraSkillPoints + 1
    			createCharScreen:OnThiefSkillPlusMinusButtonClick(chargen.thief_skill[currentChargenThiefSkill].id, false)
    			displayExtendedSkills()
    		end
    	else
    		createCharScreen:OnThiefSkillPlusMinusButtonClick(chargen.thief_skill[currentChargenThiefSkill].id, false)
    		displayExtendedSkills()
    end
    

    Then to fix the wierd behaviour with two skills incrementing up, I revised the below:
    (... = firstExtendedSkillIndex + i + 1) rather than -1
    function displayExtendedSkills()
    	if firstExtendedSkillIndex ~= nil then
    		for i = 1, #extendedSkills, 1 do
    			local skill = extendedSkills[i]
    			chargen.thief_skill[firstExtendedSkillIndex + i] = {['description'] = skill.description, ['name'] = skill.name, ['value'] = skill.value, ['id'] = firstExtendedSkillIndex + i + 1}
    		end
    	end
    end
    
    
    
  • OlvynChuruOlvynChuru Member Posts: 3,079
    edited March 2021
    @nonlinearcoast
    Okay, for anyone interested I've managed to fix it.
    To fix the minus button not working for extended skills, I removed:
    "chargen.levelingUp" from the below chunk, which stops the minus button working in the char gen screen but works okay in the level up screen. Im not sure what the rationale for that is but works fine with it removed for me.
    if chargen.levelingUp and currentChargenThiefSkill > firstExtendedSkillIndex then
    		if  chargen.thief_skill[currentChargenThiefSkill].value > extendedSkills[exIndex].base then
    			chargen.thief_skill[currentChargenThiefSkill].value = chargen.thief_skill[currentChargenThiefSkill].value - 1
    			extendedSkills[exIndex].value = extendedSkills[exIndex].value - 1
    			chargen.extraSkillPoints = chargen.extraSkillPoints + 1
    			createCharScreen:OnThiefSkillPlusMinusButtonClick(chargen.thief_skill[currentChargenThiefSkill].id, false)
    			displayExtendedSkills()
    		end
    	else
    		createCharScreen:OnThiefSkillPlusMinusButtonClick(chargen.thief_skill[currentChargenThiefSkill].id, false)
    		displayExtendedSkills()
    end
    

    The reason that chargen.levelingUp condition is there is to prevent a worse bug. In certain games (like BG2EE), if you use the minus button to subtract from an extended skill during chargen, it decrements the skill without refunding the skill points. This doesn't happen during level up. It also doesn't happen in BG1EE, I don't think.
  • fortysevenfortyseven Member Posts: 96
    edited March 2021
    Logiteks wrote: »
    Did I mention that EEex is awesome? :P
    Anything I do now is effectively pointless, (as the 64-bit jump ensures that any hooks I write will be obsolete in the next executable), and I can't start work on v2.6 until the PDB is dropped with its full release.
    If there will be problems with porting EEex to v2.6, I will stay with 2.5 forever, that's for sure. It's incredible how much EEex opens up modding possibilities.
    100% agreed. I can no longer play this game without EEex. Would feel like going back to the stone age.
    I reckon porting EEex to 64-bit will be a hell of a project in itself. Would it even be reasonable to do at all? I wonder what @Bubb's thoughts are on this with the 2.6 beta having been released now.
  • BubbBubb Member Posts: 1,005
    I'm planning on reimplementing everything I've done so far once v2.6 is released. It's just a waiting game at this point, since I need the symbols that come with a full release to start work on any 64-bit conversion.
Sign In or Register to comment.