So right now I'm trying to make my mods work with the new EEex, and I'm having quite a lot of trouble. How exactly do I get offset 0 of a creature's data? In the old version of EEex, I could simply do EEex_GetActorShare(EEex_GetActorIDSelected()). But now, if I do EEex_GameObject_Get(EEex_Sprite_GetSelectedID()), it doesn't return the same thing. Am I just using the wrong function?
The new EEex model is to use field names instead of memory offsets. Memory offsets are prone to changing between versions, which was a big part of why v2.6 broke old-EEex. New-EEex uses a bindings layer to access the correct offsets behind the scenes.
For example, see the following old-EEex function:
function EEex_GetActorClass(actorID)
if not EEex_IsSprite(actorID, true) then return 255 end
return EEex_ReadByte(EEex_GetActorShare(actorID) + 0x24, 0x3)
end
and a comparable version using new-EEex:
function B3GetClass(sprite)
if not EEex_GameObject_IsSprite(sprite, true) then return 255 end
return sprite.m_typeAI.m_Class
end
To migrate old code, you can look at the x86 reference to figure out what field(s) you were accessing using offsets. Note that offset 0 is often a baseclass represented as a field; these baseclass "fields" should be omitted when accessing one of their underlying fields. The x64 reference clearly defines which fields are a baseclass.
If you are unsure which engine type has been returned by a new EEex function, you can use EEex_GetUT() for a string representation of the type name. If for any reason you need to cast a userdata object to another usertype, you can use EEex_CastUD(), (usually you don't need to worry about this, EEex tries to return the most specific type). For example, to cast a CGameObject userdata into a CGameSprite userdata:
local sprite = EEex_CastUD(gameObject, "CGameSprite")
If you really want to get a raw memory address in new-EEex, you can use EEex_UDToPtr() on a returned userdata object, and use the following functions to read/write relative to it:
Okay that helps. I didn't previously realize that the names of object properties were exactly the same as the names of fields in the EEex documentation. I was looking at, for example, the function EEex_Sprite_GetModalState and wondering where "sprite.m_nModalState" was defined; I did a search for "m_nModalState" in all Lua files and could not find any other references to it.
@Bubb
REQUEST IF NOT ALREADY IMPLEMENTED: Add an option to ignore the need to gather our party before venturing forth to a different map. Instead, moving one character from the party to a map edge would be enough to move the entire party to the overworld.
I tried to install the mod on top of several others using Project Infinity, but the game crashes once I either click new game or load a save, any ideas why this is the case ?
@Bubb I can't find any .dmp file, neither in the game folder nor in my documents folder (alongside the saves and Baldur.lua files), it is supposed to be located there right ?
To note, I have copied the game folder from steamapps to "D:\Games" (and my document folder is also on D drive).
@Bubb I don't know why, but I don't have dmp file for the crash mentionned (only dmp files from a previous install one year ago). Anyway, the new EEex you posted fixed the issue.
Hi Bubb, I have a report though not %100 sure if it's related to EEex. Whenever I open inventory, I start getting info messages like this:
INFO: [string "menu"]:143: attempt to index field '?' (a nil value)
stack traceback:
return debug.traceback():1: in main chunk
=[C]: in function '__index'
menu:143: in function 'getItemSlot2'
function valid000000000411EA70 () return getItemSlot2(4).valid end:1: in function <[string "function valid000000000411EA70 () return getI..."]:1>
Of course there are no issues with getting info messages and it doesn't crash the game, however, it constantly writes these messages in a loop endlessly for all Item Slots. There is a huge feed of messages and it only stops printing these messages if I exit the inventory screen. I'm using Dragonspear UI ++ mod as well, maybe it's related to that?
I tried the latest 0.9.18 version and it's still like this. Thanks.
REQUEST: Allow players to issue movement commands in areas concealed by the blackness AKA undiscovered areas. Other games at the time like StarCraft allowed this, and this helps players by saving time.
REQUEST: Allow players to issue movement commands in areas concealed by the blackness AKA undiscovered areas. Other games at the time like StarCraft allowed this, and this helps players by saving time.
Thankee!
On that note, I'd also like to request some way to enable movement commands to points that are normally not occupiable (this is so flying characters can fly to those points).
Icewind Dale 2 actually has this feature already: if you select a character and click on a non-occupiable point, they receive an action telling them to move to that exact point.
Normally they immediately give up and don't actually reach their destination, but if I give them the ability to fly, I can make them move to that point correctly.
In Beamdog's EEs however, as far as I recall, if you select a character and click on a non-occupiable point, they either won't receive any action or their move action will target the nearest occupiable point. This means I can't make flyers fly to those points, and I'd like them to be able to.
On a similar note, I'd also like to be able to cast spells or use abilities in black-covered areas because maybe there's something in that area worth using these abilities on.
All EEex modules let you change which key(s) they use at the top of the relevant file. For example, the time step module (B3TimeStep.lua) defines B3TimeStep_Key = EEex_Key_GetFromName("d"). I admit it's not overly user friendly, but it's there.
At this point, I am about 75% of the way to getting my mods to work with the current version of EEex. I only have a couple more requests:
1. The current EEex still does not seem to have an equivalent of the EEex_HookAction function from the old EEex (which is called every time someone starts doing an action). My metamagic system requires this, as do several spells I've made.
2. I really liked the hook for opcode 280 (trigger wild surge on spell cast) which made it so it would always do the wild surge specified in parameter1, and it could suppress the wild surge graphics and string. I used this to make Enoll Eva's Duplication (all spells trigger Wild Surge: Spell cast twice), Spellshaping: Fireball (all spells trigger Wild Surge: Fireball), and Mass Cast (the next spell triggers Wild Surge: Area effect).
3. I'd just like to know how to call the internal function that teleports a creature to a target point without applying an effect or requiring an action (simply setting the X and Y coordinates of the creature doesn't work right). I need this in order to reimplement the flying mechanic in my mods.
Never mind, I figured out a way to do this.
4. On that note, how do I call the internal function you showed years ago that shatters a creature into a million pieces?
I actually used this function at multiple points in one of my mods.
REQUEST FOR BUBB: Allow thieving skills (pick pocketing, etc.), trap placement (normal traps, Bounty Hunter traps, etc.), container manipulation (unlocking, opening, putting items in a container from inventory, and removing items from said container into a PC's inventory), and picking up items from the ground (if a character has inventory space) to be done from any distance so long as the party has sight to the destination, without moving the target character. This is meant to simulate telekinesis.
The new EEex model is to use field names instead of memory offsets. Memory offsets are prone to changing between versions, which was a big part of why v2.6 broke old-EEex. New-EEex uses a bindings layer to access the correct offsets behind the scenes.
For example, see the following old-EEex function:
function EEex_GetActorClass(actorID)
if not EEex_IsSprite(actorID, true) then return 255 end
return EEex_ReadByte(EEex_GetActorShare(actorID) + 0x24, 0x3)
end
and a comparable version using new-EEex:
function B3GetClass(sprite)
if not EEex_GameObject_IsSprite(sprite, true) then return 255 end
return sprite.m_typeAI.m_Class
end
To migrate old code, you can look at the x86 reference to figure out what field(s) you were accessing using offsets. Note that offset 0 is often a baseclass represented as a field; these baseclass "fields" should be omitted when accessing one of their underlying fields. The x64 reference clearly defines which fields are a baseclass.
If you are unsure which engine type has been returned by a new EEex function, you can use EEex_GetUT() for a string representation of the type name. If for any reason you need to cast a userdata object to another usertype, you can use EEex_CastUD(), (usually you don't need to worry about this, EEex tries to return the most specific type). For example, to cast a CGameObject userdata into a CGameSprite userdata:
local sprite = EEex_CastUD(gameObject, "CGameSprite")
If you really want to get a raw memory address in new-EEex, you can use EEex_UDToPtr() on a returned userdata object, and use the following functions to read/write relative to it:
To get a field like a sprite's current HP, you look at the EEex documentation and find the name of the particular field. If you have an object called sprite then their current HP would be accessed by
sprite.m_baseStats.m_hitPoints
If you'd like to print the current hit points of the party member you have selected (make sure to only select one party member), enter this into the console:
I'm currently trying to get my metamagic system to work, and I'm encountering a problem. What exactly is being passed to the "projectile" parameter of EEex_Projectile_Hook_BeforeAddEffect? It doesn't seem like it's actually being passed the projectile object. If I insert "Infinity_DisplayString(projectile.m_projectileType)" into that function and have my character cast a fireball, it prints 19456 when it should probably print 233 (the PROJECTL.IDS index of the projectile), which is what it does print if the same print statement is put in the earlier function EEex_Projectile_Hook_OnAfterDecode.
Also, where exactly are errors supposed to be logged in the new EEex? I can't find EEex.log in my game folder. Is the file named something different or put in a different location?
Start the game via a bat file or from the console and you get out the debug info. I was also surprised on it on the other day.
I tried starting the game from the Command Prompt after inserting some code that would cause a Lua error during the game, and I didn't see any error message after running that code.
I'm currently trying to get my metamagic system to work, and I'm encountering a problem. What exactly is being passed to the "projectile" parameter of EEex_Projectile_Hook_BeforeAddEffect? It doesn't seem like it's actually being passed the projectile object. If I insert "Infinity_DisplayString(projectile.m_projectileType)" into that function and have my character cast a fireball, it prints 19456 when it should probably print 233 (the PROJECTL.IDS index of the projectile), which is what it does print if the same print statement is put in the earlier function EEex_Projectile_Hook_OnAfterDecode.
This should be fixed. Instead of reading a projectile you were reading the game's code; how fun!
I tried starting the game from the Command Prompt after inserting some code that would cause a Lua error during the game, and I didn't see any error message after running that code.
That should work. I personally use this command to both log and display the output:
InfinityLoader.exe > log.txt 2>&1
Can you give an example of something that isn't logging? EEex might be eating the error message, though I thought I eliminated all those cases.
Ok, I met and get through the EEex_UDToPtr() function,
now I m blocked by the EEex_Sprite_ForAllOfTypeStringInRange() / EEex_Sprite_GetAllOfTypeInRange() mainly because of the aiObjectTypeString / aiObjectType parameters
local canSeeTarget = false
local targetID = sprite.m_curAction.m_acteeID.m_Instance
if targetID > 0 then
EEex_Sprite_ForAllOfTypeStringInRange(sprite, "[ANYONE]", 600, function(object)
if object.m_id == targetID then
canSeeTarget = true
end
end, true, false)
end
This code checks if sprite can see the target of their current action. This is kind of slow code, though, and I suspect there's a better way to do this.
Comments
For example, see the following old-EEex function:
and a comparable version using new-EEex:
To migrate old code, you can look at the x86 reference to figure out what field(s) you were accessing using offsets. Note that offset 0 is often a baseclass represented as a field; these baseclass "fields" should be omitted when accessing one of their underlying fields. The x64 reference clearly defines which fields are a baseclass.
If you are unsure which engine type has been returned by a new EEex function, you can use EEex_GetUT() for a string representation of the type name. If for any reason you need to cast a userdata object to another usertype, you can use EEex_CastUD(), (usually you don't need to worry about this, EEex tries to return the most specific type). For example, to cast a CGameObject userdata into a CGameSprite userdata:
If you really want to get a raw memory address in new-EEex, you can use EEex_UDToPtr() on a returned userdata object, and use the following functions to read/write relative to it:
Edit: These tutorial pages might also help.
Okay that helps. I didn't previously realize that the names of object properties were exactly the same as the names of fields in the EEex documentation. I was looking at, for example, the function EEex_Sprite_GetModalState and wondering where "sprite.m_nModalState" was defined; I did a search for "m_nModalState" in all Lua files and could not find any other references to it.
REQUEST IF NOT ALREADY IMPLEMENTED: Add an option to ignore the need to gather our party before venturing forth to a different map. Instead, moving one character from the party to a map edge would be enough to move the entire party to the overworld.
Thankee!
Most of the mods installed are the ones in the EET from morpheus562 shared on github here https://github.com/morpheus562/Baldurs-Gate-Install-Order-List-Repository, on a 2.6 BGEE version.
Many thanks !
To note, I have copied the game folder from steamapps to "D:\Games" (and my document folder is also on D drive).
I also fixed a crash earlier today. Might be a longshot, but could you try the attached version and see if the crash still occurs?
Many thanks for your help
v0.9.18-alpha:
Fixed:
- A serious crash in the projectile mutator code; commonly observed shortly after starting/loading a game.
v0.9.17-alpha:Readded:
- Time step module. Press 'd' while the game is paused to advance time by 1 tick, or hold to make time flow until the key is released.
For modders:stack traceback:
return debug.traceback():1: in main chunk
=[C]: in function '__index'
menu:143: in function 'getItemSlot2'
function valid000000000411EA70 () return getItemSlot2(4).valid end:1: in function <[string "function valid000000000411EA70 () return getI..."]:1>
Of course there are no issues with getting info messages and it doesn't crash the game, however, it constantly writes these messages in a loop endlessly for all Item Slots. There is a huge feed of messages and it only stops printing these messages if I exit the inventory screen. I'm using Dragonspear UI ++ mod as well, maybe it's related to that?
I tried the latest 0.9.18 version and it's still like this. Thanks.
Thankee!
On that note, I'd also like to request some way to enable movement commands to points that are normally not occupiable (this is so flying characters can fly to those points).
Icewind Dale 2 actually has this feature already: if you select a character and click on a non-occupiable point, they receive an action telling them to move to that exact point.
Normally they immediately give up and don't actually reach their destination, but if I give them the ability to fly, I can make them move to that point correctly.
In Beamdog's EEs however, as far as I recall, if you select a character and click on a non-occupiable point, they either won't receive any action or their move action will target the nearest occupiable point. This means I can't make flyers fly to those points, and I'd like them to be able to.
Thankee!
I mention this also because Diablo2 Kits have the D and N keys reserved.
Thankee!
1. The current EEex still does not seem to have an equivalent of the EEex_HookAction function from the old EEex (which is called every time someone starts doing an action). My metamagic system requires this, as do several spells I've made.
2. I really liked the hook for opcode 280 (trigger wild surge on spell cast) which made it so it would always do the wild surge specified in parameter1, and it could suppress the wild surge graphics and string. I used this to make Enoll Eva's Duplication (all spells trigger Wild Surge: Spell cast twice), Spellshaping: Fireball (all spells trigger Wild Surge: Fireball), and Mass Cast (the next spell triggers Wild Surge: Area effect).
3. I'd just like to know how to call the internal function that teleports a creature to a target point without applying an effect or requiring an action (simply setting the X and Y coordinates of the creature doesn't work right). I need this in order to reimplement the flying mechanic in my mods.
Never mind, I figured out a way to do this.
4. On that note, how do I call the internal function you showed years ago that shatters a creature into a million pieces?
I actually used this function at multiple points in one of my mods.
(PS: That animation was a pleasant surprise!)
REQUEST FOR BUBB: Allow thieving skills (pick pocketing, etc.), trap placement (normal traps, Bounty Hunter traps, etc.), container manipulation (unlocking, opening, putting items in a container from inventory, and removing items from said container into a PC's inventory), and picking up items from the ground (if a character has inventory space) to be done from any distance so long as the party has sight to the destination, without moving the target character. This is meant to simulate telekinesis.
Thankee!
Well, it's very embarrassing but I cannot make it after hours of tries
Can you show how, for example, one should read a sprite current HP ?
Explain me as if I am a 3 years old child, please...
To get a field like a sprite's current HP, you look at the EEex documentation and find the name of the particular field. If you have an object called sprite then their current HP would be accessed by
sprite.m_baseStats.m_hitPoints
If you'd like to print the current hit points of the party member you have selected (make sure to only select one party member), enter this into the console:
Infinity_DisplayString(EEex_Sprite_GetSelected().m_baseStats.m_hitPoints)
So simple and nothing related to EEex_CastUD() or EEex_GetUT() ...
Thanks for reimplementing the action hooks!
I'm currently trying to get my metamagic system to work, and I'm encountering a problem. What exactly is being passed to the "projectile" parameter of EEex_Projectile_Hook_BeforeAddEffect? It doesn't seem like it's actually being passed the projectile object. If I insert "Infinity_DisplayString(projectile.m_projectileType)" into that function and have my character cast a fireball, it prints 19456 when it should probably print 233 (the PROJECTL.IDS index of the projectile), which is what it does print if the same print statement is put in the earlier function EEex_Projectile_Hook_OnAfterDecode.
Also, where exactly are errors supposed to be logged in the new EEex? I can't find EEex.log in my game folder. Is the file named something different or put in a different location?
I tried starting the game from the Command Prompt after inserting some code that would cause a Lua error during the game, and I didn't see any error message after running that code.
This should be fixed. Instead of reading a projectile you were reading the game's code; how fun!
That should work. I personally use this command to both log and display the output:
Can you give an example of something that isn't logging? EEex might be eating the error message, though I thought I eliminated all those cases.
now I m blocked by the EEex_Sprite_ForAllOfTypeStringInRange() / EEex_Sprite_GetAllOfTypeInRange() mainly because of the aiObjectTypeString / aiObjectType parameters
Anyone has a dumb example ?
This code checks if sprite can see the target of their current action. This is kind of slow code, though, and I suspect there's a better way to do this.