I was aiming to make a kit called Weapon Master that would give to a creature specific bonuses on a single melee weapon and restrain every other weapon.
To make this work I was aiming to create one single kit for every Weapon of Choice: The player would create the character and use an ability that would call an invisible creature to open a dialogue where the player would pick his/hers Weapon of Choice - behind every choice would exist a AddKit (or AddSuperKit) to apply the kit that is related to the selected Weapon of Choice.
The problem: it would take too many rows for invisible kits - or I can skip the invisible creature thing and let the player select directly from the starting menu, but that would also pollute the screen.
Finally the question: is there something in EEex that helps me overcome that issue? Maybe altering the kit CLAB during the game or help the change the parameters of the opcodes of the effects listed at the CLAB so it would match the designed weapon.
I was aiming to make a kit called Weapon Master that would give to a creature specific bonuses on a single melee weapon and restrain every other weapon.
To make this work I was aiming to create one single kit for every Weapon of Choice: The player would create the character and use an ability that would call an invisible creature to open a dialogue where the player would pick his/hers Weapon of Choice - behind every choice would exist a AddKit (or AddSuperKit) to apply the kit that is related to the selected Weapon of Choice.
The problem: it would take too many rows for invisible kits - or I can skip the invisible creature thing and let the player select directly from the starting menu, but that would also pollute the screen.
Finally the question: is there something in EEex that helps me overcome that issue? Maybe altering the kit CLAB during the game or help the change the parameters of the opcodes of the effects listed at the CLAB so it would match the designed weapon.
If this thing exists, how would I use it?
Thanks.
By a single melee weapon, do you mean a single weapon type, or a specific item?
EEex definitely can allow CLAB spells, and in an extension their opcodes, to be modified at runtime to provide specific bonuses based on some sort of condition.
I am confused about the problem though. What sort of rows are we talking about? CLAB rows, dialog options, something else? And what limit is being hit?
@Raduziel, you don't need EEex or dummy kits for this. Check out opcode #183 (Apply Effect Itemtype). In parameter2 set weapon type of your choice. Add this opcode with timing = 9 depending on the weapon selection.
@OlvynChuru A single weapon type. Longsword or Warhammer or Quarterstaff.
@Bubb The amount of rows kitlist may have - DoF already bites a big chunk and I don't want other mod of mine to do the same.
@swit I'll send you a PM asking for details. But I think you misunderstood my issue/I expressed myself poorly. The weapon varies with the weapon of choice the player embraces. So it is something I can't previously set.
If—say—I wanted to throw together a Mac version, what should the Loader for it do? What are the technicalities of getting this to run? I took a quick look at the code for the Windows Loeader and it's mostly assembler so I'd rather ask before I start going over it (tomorrow; or at least after I've slept for a few hours).
How is the asm in the Lua code being processed (is it being injected with hooks or just being overwritten on memory?) and by what (is it the game's embedded version of Lua or?) is it being run? I know I might sound a bit silly and rather demanding asking things like this in such manner, but I honestly have no clue of where else to start. I don't really need detailed information right now, just an overall idea so I know where to start working.
The lua functions are using the EE game executable internal lua which is statically compiled into it. The raw bytecode (asm x86) EEex lua functions are added into the address space of the EE game executable, by allocating some memory (by the loader) for adding these functions. These EEex lua functions can then call any of the internal lua functions. The calling convention for these functions is C (cdecl), where the stack is adjusted by the caller, the code is the raw x86 assembler).
There is one hook installed by the loader, that redirects code from a call to LuaL_loadstring in the EE game executable to set up the memory for additional lua functions and to initialize and register the first EEex lua functions (EEex_Init, EEex_ExposeToLua, EEex_WriteByte) for use in the lua scripts (M__EEex.lua).
For Mac and other OS's I think the initial steps to porting this over would be to:
- How to load the EE game and inject or hook certain functions
- Search for function addresses for EE game functions and for global variables required by EEex and store this information (to allow the lua scripts access to this information)
- Hook the call to LuaL_loadstring or other candidate function/calls in the EE game, to redirect to our custom code.
- Allocate memory for EEex functions
- Code initial EEex lua functions in the bytecode for the platform adhering to the calling convention for that platform.
I'm not familiar with other OS's in regard to loading, injecting or hooking. Additionally the searching for functions is done based on the asm x86 bytecode found in the windows EE game exe, I'm not sure how that will work with other OS's, or if this technique will successfully apply. The calling convention and raw bytecode for other platform may allow this to work or may introduce cases where its not possible to search and map those function address required. I will defer to others that have more experience coding with these other OS's.
I've experimented with it (giving creatures without infravision penalties in dark places). RACEFEAT.2da does give creatures infravision, but it does not set STATE_INFRAVISION.
For some reason, EEex_GetActorRequiredDirection isn't working.
I was making a function to apply a spell to a creature that was looking at the caster. This is part of the function:
function MEGAZE(effectData, creatureData)
local targetID = EEex_ReadDword(creatureData + 0x34)
local sourceID = EEex_ReadDword(effectData + 0x10C)
if targetID == 0x0 or sourceID == 0x0 then return end
local sourceData = EEex_GetActorShare(sourceID)
local sourcex = EEex_ReadDword(sourceData + 0x8)
local sourcey = EEex_ReadDword(sourceData + 0xC)
Infinity_DisplayString(targetID)
Infinity_DisplayString(sourcex)
Infinity_DisplayString(sourcey)
local eyeContactDirection = EEex_GetActorRequiredDirection(targetID, sourcex, sourcey)
Infinity_DisplayString("ugu")
When a spell calls this function on a creature, the targetID, sourcex and sourcey get printed correctly, but ugu does not get printed.
This code had been working when I had been using a previous version of EEex, but now it isn't.
Just a heads up that I won't be able to access my main computer for the next week or so, so there will be a lull in development, and my availability, for that time.
Once I'm back, though, I'll have a ton of free time to devote to EEex!
How do we use EEex_Lua nowadays? I tried using the action hook example in EEEX_AHO.LUA and it didn't work. I copy and pasted the code into UI.MENU and gave a creature a script like this:
IF
See(Player1)
THEN
RESPONSE #100
EEex_Lua("B3SpellToPoint")
SpellNoDecRES("SPWI304",Player1)
END
The creature cast the fireball, but it did not change to target a point.
I also created my own function that should display a string, but it did not display a string when the function was called by a creature using EEex_Lua.
I need to work on documentation; things are getting kinda messy, as you can see.
EEex_Lua and EEex_LuaTrigger should be back to directly running Lua code embedded in the argument string, as this is the only way to pass args to the function without some trickery.
So,
EEex_Lua("B3SpellToPoint")
Should be:
EEex_Lua("B3SpellToPoint()")
The action hooks should still be functional, hopefully.
Which is the script trigger corresponding to opcode #282 (Modify script state)? For instance, let's consider IMMUNE1.itm => 'CheckStatGT([object],0,WIZARD_PROTECTION_FROM_NORMAL_WEAPONS' cannot detect it (i.e., it returns false.....)
Which is the script trigger corresponding to opcode #282 (Modify script state)? For instance, let's consider IMMUNE1.itm => 'CheckStatGT([object],0,WIZARD_PROTECTION_FROM_NORMAL_WEAPONS' cannot detect it (i.e., it returns false.....)
The stats listed for op282 are incorrect, #17-33 are one off, #34+ will be one off (less) depending on where you're looking and which game version you're running.
Which is the script trigger corresponding to opcode #282 (Modify script state)? For instance, let's consider IMMUNE1.itm => 'CheckStatGT([object],0,WIZARD_PROTECTION_FROM_NORMAL_WEAPONS' cannot detect it (i.e., it returns false.....)
The stats listed for op282 are incorrect, #17-33 are one off, #34+ will be one off (less) depending on where you're looking and which game version you're running.
Yep, you're right. IMMUNE1.itm sets #25 to 1, so you need to check for STAT (25-1)+156 = 180 (i.e., WIZARD_GREATER_MALISON). This does sound like a bug and should be fixed....
Also, why do STATs #176, #177, #178, #179, #180, #181 and #182 have two identifiers? For instance, STAT #180 is both 'WIZARD_GREATER_MALISON' and 'HIDEINSHADOWSMTPBONUS'....
Yep, you're right. IMMUNE1.itm sets #25 to 1, so you need to check for STAT (25-1)+156 = 180 (i.e., WIZARD_GREATER_MALISON). This does sound like a bug and should be fixed....
Nothing above #9 is officially supported by op282.
Also, why do STATs #176, #177, #178, #179, #180, #181 and #182 have two identifiers? For instance, STAT #180 is both 'WIZARD_GREATER_MALISON' and 'HIDEINSHADOWSMTPBONUS'....
HIDEINSHADOWSMTPBONUS and similar are the stats real purpose. The WIZARD_ were mods trying to hijack the stats for other purposes, while interfering with their original purpose, some of which made it into the EE's. The EE's have mostly replaced them with SPLSTATE references, but a few remain.
Equip "IMMUNE1" on a thief and you will see their Hide in Shadows skill increase by 1.
@OlvynChuru: Opcode #42 and Opcode #62 will now force the slot modification if the Special field is non-zero.
Also worthy to note that due to an early EEex change, Opcode #42 has been granting spell slots for levels that hadn't been unlocked yet by default; that is fixed now. EEex should never change vanilla behavior without it being opt-in, so if anyone finds another instance where it is doing that, please let me know.
EEex_IterateActorEffects(actorID, func) => Applies the function to each effect on the actor. The function takes one parameter, which is automatically set to offset 0x0 of each effect. The offsets for each effect are the same as in an EFF file. Here's an example:
EEex_IterateActorEffects(EEex_GetActorIDCursor(), function(eData)
local parameter1 = EEex_ReadDword(eData + 0x1C)
Infinity_DisplayString(parameter1)
end)
This will print the parameter1 of each effect on the actor.
EEex_GetSpellData(resref) => Returns offset 0x0 of the data for the spell. The data for a spell is the same data as in the SPL file. For example, offset EEex_GetSpellData("SPWI304") + 0x34 is 3, because the spell's level is stored at offset 0x34, and Fireball is a 3rd-level spell.
EEex_GetActorModalState(actorID) => Returns the modal state of the actor (from MODAL.IDS; e.g. Turn Undead = 4, no modal state = 0).
EEex_GetActorCurrentAction(actorID) => Returns the ID of the actor's current action (from ACTION.IDS). For example, if the actor is moving to a location, it will return 23, the ACTION.IDS number for MoveToPoint().
EEex_GetActorSpellRES(actorID) => Returns the resref of the spell the actor is either currently casting, cast most recently, or is about to cast (waiting for its aura to be cleansed). It works with both Spell and SpellRES - type actions.
EEex_GetActorDialogue(actorID) => Returns the resref of the actor's DLG file.
A few things to review, (because I still only know the bare basics of GitHub):
EEex_GetActorSpellRES =>
local spellIDS = EEex_ReadWord(EEex_GetActorShare(actorID) + 0x338, 0x0)
is reading the first integer param of the current script action; it can be unrelated to spell casting. This is a valid lookup if the current action is verified to be a spell cast, however.
local spellRES = EEex_ReadLString(EEex_GetActorShare(actorID) + 0x3596, 8)
This appears(?) to have something to do with the interface itself, as the overlying structure it is accessing is called m_currentUseButton. Should be verified that it works in relation to non-manual casts for both players and NPCs.
The reason for that - 0x4 is so that the offsets from the pointer are the same as the offsets in an EFF file. Otherwise, each offset differs by 0x4 from the offsets in an EFF file, requiring you, for example, to do offset + 0x44 to get the Special field rather than offset + 0x48, as it is in an EFF file.
I think basing it on the EFF file offsets is more convenient for people who are coming from normal Infinity Engine modding.
Ah, I see, you're simulating the Signature and Version space then; that actually works better. I guess I'm over here stuck in hex land.
BTW I'm not trying to be overly critical, I know how it is for someone to poke your code. All is good; you even document your code, one-upping me, heh.
Comments
I was aiming to make a kit called Weapon Master that would give to a creature specific bonuses on a single melee weapon and restrain every other weapon.
To make this work I was aiming to create one single kit for every Weapon of Choice: The player would create the character and use an ability that would call an invisible creature to open a dialogue where the player would pick his/hers Weapon of Choice - behind every choice would exist a AddKit (or AddSuperKit) to apply the kit that is related to the selected Weapon of Choice.
The problem: it would take too many rows for invisible kits - or I can skip the invisible creature thing and let the player select directly from the starting menu, but that would also pollute the screen.
Finally the question: is there something in EEex that helps me overcome that issue? Maybe altering the kit CLAB during the game or help the change the parameters of the opcodes of the effects listed at the CLAB so it would match the designed weapon.
If this thing exists, how would I use it?
Thanks.
By a single melee weapon, do you mean a single weapon type, or a specific item?
I am confused about the problem though. What sort of rows are we talking about? CLAB rows, dialog options, something else? And what limit is being hit?
@Bubb The amount of rows kitlist may have - DoF already bites a big chunk and I don't want other mod of mine to do the same.
@swit I'll send you a PM asking for details. But I think you misunderstood my issue/I expressed myself poorly. The weapon varies with the weapon of choice the player embraces. So it is something I can't previously set.
Thanks, everyone
How is the asm in the Lua code being processed (is it being injected with hooks or just being overwritten on memory?) and by what (is it the game's embedded version of Lua or?) is it being run? I know I might sound a bit silly and rather demanding asking things like this in such manner, but I honestly have no clue of where else to start. I don't really need detailed information right now, just an overall idea so I know where to start working.
There is one hook installed by the loader, that redirects code from a call to LuaL_loadstring in the EE game executable to set up the memory for additional lua functions and to initialize and register the first EEex lua functions (EEex_Init, EEex_ExposeToLua, EEex_WriteByte) for use in the lua scripts (M__EEex.lua).
For Mac and other OS's I think the initial steps to porting this over would be to:
- How to load the EE game and inject or hook certain functions
- Search for function addresses for EE game functions and for global variables required by EEex and store this information (to allow the lua scripts access to this information)
- Hook the call to LuaL_loadstring or other candidate function/calls in the EE game, to redirect to our custom code.
- Allocate memory for EEex functions
- Code initial EEex lua functions in the bytecode for the platform adhering to the calling convention for that platform.
I'm not familiar with other OS's in regard to loading, injecting or hooking. Additionally the searching for functions is done based on the asm x86 bytecode found in the windows EE game exe, I'm not sure how that will work with other OS's, or if this technique will successfully apply. The calling convention and raw bytecode for other platform may allow this to work or may introduce cases where its not possible to search and map those function address required. I will defer to others that have more experience coding with these other OS's.
I've experimented with it (giving creatures without infravision penalties in dark places). RACEFEAT.2da does give creatures infravision, but it does not set STATE_INFRAVISION.
I was making a function to apply a spell to a creature that was looking at the caster. This is part of the function:
When a spell calls this function on a creature, the targetID, sourcex and sourcey get printed correctly, but ugu does not get printed.
This code had been working when I had been using a previous version of EEex, but now it isn't.
I've manually added the CGameSprite::GetDirection pattern back into the db; should be working now
Could you let the Modify Priest Spells opcode add spells of levels the character can't cast yet? I was planning on using this in one of my mods.
Just a heads up that I won't be able to access my main computer for the next week or so, so there will be a lull in development, and my availability, for that time.
Once I'm back, though, I'll have a ton of free time to devote to EEex!
The creature cast the fireball, but it did not change to target a point.
I also created my own function that should display a string, but it did not display a string when the function was called by a creature using EEex_Lua.
EEex_Lua and EEex_LuaTrigger should be back to directly running Lua code embedded in the argument string, as this is the only way to pass args to the function without some trickery.
So,
Should be:
The action hooks should still be functional, hopefully.
Which is the script trigger corresponding to opcode #282 (Modify script state)? For instance, let's consider IMMUNE1.itm => 'CheckStatGT([object],0,WIZARD_PROTECTION_FROM_NORMAL_WEAPONS' cannot detect it (i.e., it returns false.....)
Yep, you're right. IMMUNE1.itm sets #25 to 1, so you need to check for STAT (25-1)+156 = 180 (i.e., WIZARD_GREATER_MALISON). This does sound like a bug and should be fixed....
Also, why do STATs #176, #177, #178, #179, #180, #181 and #182 have two identifiers? For instance, STAT #180 is both 'WIZARD_GREATER_MALISON' and 'HIDEINSHADOWSMTPBONUS'....
Equip "IMMUNE1" on a thief and you will see their Hide in Shadows skill increase by 1.
Also worthy to note that due to an early EEex change, Opcode #42 has been granting spell slots for levels that hadn't been unlocked yet by default; that is fixed now. EEex should never change vanilla behavior without it being opt-in, so if anyone finds another instance where it is doing that, please let me know.
As thanks for this, some time today I will send you a pull request with some of the new functions I've recently created for EEex.
New functions:
EEex_IterateActorEffects(actorID, func) => Applies the function to each effect on the actor. The function takes one parameter, which is automatically set to offset 0x0 of each effect. The offsets for each effect are the same as in an EFF file. Here's an example:
This will print the parameter1 of each effect on the actor.
EEex_GetSpellData(resref) => Returns offset 0x0 of the data for the spell. The data for a spell is the same data as in the SPL file. For example, offset EEex_GetSpellData("SPWI304") + 0x34 is 3, because the spell's level is stored at offset 0x34, and Fireball is a 3rd-level spell.
EEex_GetActorModalState(actorID) => Returns the modal state of the actor (from MODAL.IDS; e.g. Turn Undead = 4, no modal state = 0).
EEex_GetActorCurrentAction(actorID) => Returns the ID of the actor's current action (from ACTION.IDS). For example, if the actor is moving to a location, it will return 23, the ACTION.IDS number for MoveToPoint().
EEex_GetActorSpellRES(actorID) => Returns the resref of the spell the actor is either currently casting, cast most recently, or is about to cast (waiting for its aura to be cleansed). It works with both Spell and SpellRES - type actions.
EEex_GetActorDialogue(actorID) => Returns the resref of the actor's DLG file.
A few things to review, (because I still only know the bare basics of GitHub):
EEex_GetActorSpellRES =>
is reading the first integer param of the current script action; it can be unrelated to spell casting. This is a valid lookup if the current action is verified to be a spell cast, however.
This appears(?) to have something to do with the interface itself, as the overlying structure it is accessing is called m_currentUseButton. Should be verified that it works in relation to non-manual casts for both players and NPCs.
Edit: Removed comment about code I misunderstood.
I think basing it on the EFF file offsets is more convenient for people who are coming from normal Infinity Engine modding.
BTW I'm not trying to be overly critical, I know how it is for someone to poke your code. All is good; you even document your code, one-upping me, heh.
In a little while, I'll test EEex_GetActorSpellRES() at bit more.