Here's a quick design decision: Should the EEex_MatchObject() trigger fail if it doesn't find an object? This functionality can easily be reproduced by adding an Exists(EEex_MatchObject) after said trigger.
I guess the real question is, would there be any reason for a script block to continue if an object match fails?
It should probably fail if it doesn't find an object. Having to include an Exists() line with it every time would at best cause more wordiness and at worst cause bugs if the modder forgets to put in the Exists() line.
Trigger version => Same as action version, + fails if it couldn't match a creature.
EEex_MatchObject is now per-creature => EEex_MatchObject is now stored individually, so each object can keep track of its own unique target.
Volatile fields => New functions that allow a modder to store temporary information on a creature, (not preserved on save/load or, for local creatures, area transition).
EEex_RegisterVolatileField(name, attributeTable) -> Registers a volatile field for later use. Example:
["construct"] = Function that is called whenever a creature is spawned. You should initialize the field's default value here.
["destruct"] = Function that is called whenever a creature is deleted. You should clean up any advanced structures here, (most likely you can omit this function).
["get"] = Function used to read the Lua-friendly value of the field from the specified address.
["set"] = Function used to write the specified Lua-friendly version of the value into the given address.
["size"] = Defines the amount of memory that will be allocated for the given field.
Note: Volatile fields should only be defined once + should be registered in a M_*.LUA file. A creature's EEex_MatchObject actorID can be retrieved from Lua by using the following:
local actorID = EEex_GetVolatileField(<actorID>, "EEex_MatchObject")
EEex_AccessVolatileField(actorID, name) -> Returns the start-address of the given field for the specified actor.
EEex_GetVolatileField(actorID, name) -> Returns the Lua-friendy version of the given field for the specified actor.
EEex_SetVolatileField(actorID, name, value) -> Sets the given field from the Lua-friendy value for the specified actor.
@swit: The following is an example that you provided:
Unfortunately it is impossible to make an Object version of EEex_MatchObject, as objects don't allow parameters to be passed in the same manner as other scripting elements.
The above block's functionality can be replicated with simple EEex_MatchObject trigger calls, (as it enforces LOS by default), but any nested trigger checks need to be implemented in the filter function itself. That could be done by either passing a trigger string to the filter function and subsequently evaluating it, or by hardcoding the additional checks into variants of the same filter function.
I guess the real question is, would there be any reason for a script block to continue if an object match fails?
I suppose that if you wanted to match several different objects, all at once (say, to make a script for an NPC to use the BG2 Wand of Lighting), it'd be useful if you could, in some way, prevent it from blocking the script block because it did not find one of the six targets it was looking for. Given that this is not the conventional usage, it's likely that what @OlvynChuru suggested is a better idea, and I think you can achieve what I'm saying by doing:
OR(2)
EEex_MatchObject()
True()
Which is good enough for such an uncommon use, and if there are any others, it probably covers them as well (unless you need it in another OR() block, although I think they nest alright. Haven't messed around with scripts in a while).
EEex_CompileBCS(scriptString) => Compiles a script in the uncompiled BAF syntax and returns the internal AI script representation. Use in conjunction with EEex_RunBCSAsActor(). NOTE: Compiling scripts is slow - try to compile scripts sparingly and attempt to reuse scripts that are already compiled.
Example:
local myScript = EEex_CompileBCS([[
IF
True()
THEN
RESPONSE #100
DisplayString(Myself,1)
END
]])
EEex_RunBCSAsActor(CAIScript, actorID) => Evaluates a single script-pass of the given AI script as if the specified actor was running it. Note that CAIScript is an internal script representation, returned from either EEex_FetchBCS() or EEex_CompileBCS().
^ Runs the shout script, fetched in an above example, on the currently selected character.
EEex_FreeBCS(CAIScript) => Frees the memory reserved for the given internal script object - note that the game will crash if you attempt to use an object after you've freed it.
Example:
EEex_FreeBCS(shoutScript)
^ Frees the memory occupied by the shout script, fetched in an above example. Note that this only frees your local copy - is has no effect on the rest of the game.
EEex_ParseTriggersString(string) => Compiles a string full of triggers into the internal engine representation. Use in conjunction with EEex_EvalTriggersAsActor().
Example:
local seeTrigger = EEex_ParseTriggersString("See([ANYONE])")
^ Compiles a See trigger for use in the following functions.
EEex_EvalTriggersAsActor(CAIScriptFile, actorID) => Runs a compiled triggers object as the specified actor. Returns true/false depending on whether the triggers succeeded in the normal BCS logic.
Example:
local result = EEex_EvalTriggersAsActor(seeTrigger, EEex_GetActorIDSelected())
^ Evaluates the compiled see trigger that we got in an above example as if it was run by the currently selected character, and returns true/false depending on if the trigger succeeded.
EEex_EvalTriggersStringAsActor(string, actorID) => Convenience function that calls EEex_ParseTriggersString() + EEex_EvalTriggersAsActor() + EEex_FreeTriggers(). Please use sparingly, as compiling triggers is slow.
Example:
local result = EEex_EvalTriggersStringAsActor("See([ANYONE])", EEex_GetActorIDSelected())
^ Evaluates the See trigger embedded in the given string as if it was being run by the currently selected character, and returns true/false depending on if the trigger succeeded.
EEex_FreeTriggers(CAIScriptFile) => Frees the memory reserved for the given internal triggers object - note that the game will crash if you attempt to use an object after you've freed it.
Example:
EEex_FreeTriggers(seeTrigger)
^ Frees the memory occupied by the internal see trigger object, fetched in an above example. Note that this only frees your local copy - is has no effect on the rest of the game.
A little request: could you make it so one of the flags in a SPL file changes which name is displayed when the spell is cast? If the flag is set, casting the spell should display the identified name (NAME2) of the spell rather than its general name (NAME1).
One thing we could do with this is prevent a spell from displaying its name when cast (by setting the flag and having the identified name strref be -1), while still showing its name in the tooltip and the spell description.
BIT31 of a SPL's "Flags" field will now force the engine to display the spell's Identified name in the combat log when cast. Also, the engine didn't skip log output for empty / invalid strings like you wanted, so I patched that in for STRREF_FEEDBACK_CASTING and STRREF_FEEDBACK_CASTS.
(I don't think BIT31 is being used for anything at the moment, but if it is I can change the check bit)
By the way, do you know if the "Identified name" (offset 0xC) field is used in the EE engine? I couldn't find any obvious references to it in the assembly.
@Bubb
Is there a way to assign the 'Shaman Dance' button via opcode404?
The documentation doesn't list it and none of the not listed numbers I've tried worked out either.
Am I right to assume that the 'Shaman Dance' is a special case and handled differently than the other buttons?
On a somewhat related note: I've noticed that button #9 is the (defunct) shapeshift ability. Would it be possible to assign a spell to that ability? That way custom buttons could be created by replacing the bam/stringref. (Would obviously only allow for one custom button, but still, if it could be done with relative easy, that would be useful to have..)
@Ulb: Shaman Dance is a special-cased Bard Song (2). The engine treats Bard Song as Shaman Dance when the character's class = 21. As such, it cannot be granted to non-shaman characters without additional hackery.
On the second note, I'd have to look into the exact actionbar mechanisms further. Actionbar functions are extremely complicated, so it's quite hard to decipher the actual functionality in a lot of cases. I'll take a stab at it of course - but with the semester starting back up it'll probably take me a while to get anything done.
@Ulb: Shaman Dance is a special-cased Bard Song (2). The engine treats Bard Song as Shaman Dance when the character's class = 21. As such, it cannot be granted to non-shaman characters without additional hackery.
Thank you, I suspected something like that would be the case.
I'll take a stab at it of course - but with the semester starting back up it'll probably take me a while to get anything done.
Don't stress yourself, at least not on my account. While your work is fantastic and very much appreciated, all I'm using it for is stupid kit mods no one needs.. and if I can't do one idea I'll just do something else.
@Bubb For a while, I've been experiencing crashes that happen when I click on a party member's portrait. It seems to happen at random when I load a game: sometimes when I load a game, the first time I click on a character's portrait causes a crash, but if it doesn't, I can play for an hour or two without it crashing from clicking on a portrait.
This likely isn't a problem with EEex by itself, but rather with some of the things I've added using EEex. In my game, there are two Screen Effects opcodes attached to every creature in every area (in addition to the party members), and the protagonist has a permanent Invoke Lua effect which runs some code whenever the game is loaded but doesn't do anything otherwise.
Specifically, that permanent Invoke Lua effect calls this function:
function MEONCREA(effectData, creatureData)
local sourceID = EEex_ReadDword(effectData + 0x10C)
if (sourceID == 0 or sourceID == -1) then
local targetID = EEex_ReadDword(creatureData + 0x34)
me_ghost_walk_positions = {}
me_ghost_walk_actors = {}
EEex_AlterActorEffect(targetID,{{"opcode",402},{"resource","MEONCREA"}}, {{"source_id",targetID}},1)
end
end
I suspect that the crashes are happening because of one of these things. However, I'm not sure why clicking on a party member's portrait would cause a crash. Could you look at the code that's run when a portrait is clicked and see what might be the problem?
Okay, I know it hasn't been officially released yet, and so there may be a missing component that is required to finalize the component, but I just had to try custom skills. As you may have guessed, I wasn't quite able to get it to work completely.
The only thing I did was uncomment the example lore skill before installing EEex in ExtendedSkills.tpa:
LAF ADD_EXTENDED_SKILL
INT_VAR
stat = 25 //Lore
name = RESOLVE_STR_REF(~Lore~)
description = RESOLVE_STR_REF(~LORE: The character's lore determines <PRO_HISHER> ability to identify the properties of magic items.~)
opcode = 21 //Modify Lore
visibility = 4 //Will not appear in character record screen (Lore's already there)
STR_VAR
class_include = ~{4, 9, 10, 13, 15}~ //Usable by thief, fighter/thief, fighter/mage/thief, mage/thief, and cleric/thief
kit_include = ~{0x4008}~ //Usable by stalker as well
kit_exclude = ~{0x400C, 0x4021}~ //Not usable by swashbuckler or shadowdancer
stat_exclude = ~{{38, 16, 2}, {39, 14, 2}}~ //Not usable if your Intelligence is less than 16 or your Wisdom is less than 14
END
I tested it in my GOG version of BG2EE, version 2.5.16.6 with no other mods installed.
It partially worked. I created an assassin (with the required attributes) and I was able to put points into 'Lore':
Now, this might be because 'visibility' is set to 4, but the new value didn't show up in the main character creation screen:
and the adjusted value did not show up on the character sheet once the game started (it should be 99 or thereabouts):
@Grammarsalad Lore might be the worst possible stat to attempt this with.
It's base value determined from LORE.2da and LOREBON.2da is either recalculated constantly or cannot be overwritten.
@Grammarsalad I was actually aware of those problems but I haven't gotten around to fixing them yet. I'll see if I can fix them today or tomorrow.
@kjeron That's actually not the issue (though it might be an issue). The issue is that I designed the custom skills feature in BG1:EE and some of the UI modifications currently don't work in BG2:EE. In BG1:EE I've tested putting points in Lore and it worked.
A ton of things happen when a portrait is clicked; it would be infeasible to guess what exactly is causing the issue. Could you please upload the crash dmp(s)? Also, any way to reproduce on my end would help tremendously.
@Bubb You won't believe this, but I think I accidentally fixed the source of the crashes. I sent you a pull request, in which I made it so EEex_IsSprite() will no longer crash the game if the actor doesn't exist anymore (e.g. if it had used DestroySelf). After I changed this, I played for another hour or two, with a lot of reloading, and I never saw it crash when I clicked on a party member's portrait.
I don't know if I've really fixed it, but I do know I've fixed at least one source of crashes.
@OlvynChuru: Thanks, merged! Indeed - if creatures are deleted, like what DestroySelf() does, they are no longer accessible and EEex_GetActorShare() will return 0x0.
I noticed that you added additional checks for death states. That's good, and is probably the desired result most of the time, though I just wanted to note that sprites still exist and can be accessed even though they are dead.
Okay, so I'm playing around with the new skill implementation. Oh man, I'm loving it! Okay, so I have a request to make it just a *bit* better: Could we get an opcode or 2da that allowed us to use spls as pseudo-thief skills for our new skills?
Okay, what do I mean? I see that effect 252 is hard coded to be tied to stat 28, such that, stat 28 determines, in some sense, the chance that a given 252 effect will properly trigger (and/or how likely a 'mishap' is to trigger). Could we get an opcode or 2da that allows us to couple particular spls with newly added stats? So, maybe a 2da that looks something like:
This file defines added skills
The first column is filled by the Stat that is associated with the spl, Opcode and/or modal. The value of this stat (of the targeted creature) determine's the % chance (maximum 99%) that the spl or opcode executes when activated.
The second column is filled by the model that is associated with the skill (ids match what is defined by EEex_ACTIONBAR_TYPE in M__EEex.lua). When the modal is activated, the creature will be targeted by the associated spl (again, with a % chance equal to stat). If the value is ****, then the spl/stat is not associated with any modal.
The third column is filled by the ResRef of the spl associated with the Stat. This spl will fail if the targeted creature(s) does not have sufficient points in the relevant stat.
The fourth column is fill by the Opcode that is associated with the stat. Any spl with this opcode will fail if the targeted creature does not have sufficient points in the relevant stat (BE CAREFUL WITH THIS ONE!)
The fifth column is filled by the ResRef of the spl that fires at the target if the character rolls a 'mishap' (determined with the same probability as the set snares spl). If the value is ****, then there is no mishap associated with this stat.
The above entries might act as examples. The first two are the normal set trap spl and the special bounty hunter set traps respectively. The third is a hypothetical 'use poison' skill that has a chance of poisoning the character on a mishap, and the fourth uses the Find Traps modal to implement the Paladin's Detect evil ability as a skill using the Find Traps modal.
Edit: or what if Opcode #401 could be used to associate a stat with a spl in this way at least for a given creature, perhaps with an applied 401 with the relevant spl in the resource.
@Grammarsalad
What about just altering op252 so it's parameters can be used to specify which stat it checks, and whether or not to apply the "Set Trap" restrictions (hostile in sight, trap limit). The critical failure spell is just "%resource%F".
@Grammarsalad
What about just altering op252 so it's parameters can be used to specify which stat it checks, and whether or not to apply the "Set Trap" restrictions (hostile in sight, trap limit). The critical failure spell is just "%resource%F".
I like that. So, resource would set the spl effect So, for example, if the resource was "spcl422" the the relevant stat would apply to the poison weapon ability to the creature?
Also, maybe special field could be used associate the stat with a modal?
Edit: Er, my sense is that that probably wouldn't work (maybe as an AP_ application in the clab? No idea
Anyway, *merely* an alteration to 252 as described would be Amazeballs
Would an externalized Invoke Lua implementation be fine? It's a little awkward to set up spell-wise, (there ends up being 3 levels of indirection ):
Spell does Opcode #177 (Use EFF File).
EFF calls Invoke Lua with an EEex-provided function, (or your own if you want to supplant the default behavior).
Resource2 would hold the actual spell file to fire - other arguments could be passed via remaining EFF v2.0 params.
It's possible to make a dedicated opcode that does all of this, but it seems a bit silly to hardcode the probability portion, which I'm just going to write in Lua anyway. Also, if I implement it as the above, the only new additions to EEex would be a few additional internal-function externalizations.
And, as a side note, Opcode #252 has some funky hardcodedness going on - it's easier to reimplement its functionality than to try to adapt it.
Would an externalized Invoke Lua implementation be fine? It's a little awkward to set up spell-wise, (there ends up being 3 levels of indirection ):
Spell does Opcode #177 (Use EFF File).
EFF calls Invoke Lua with an EEex-provided function, (or your own if you want to supplant the default behavior).
Resource2 would hold the actual spell file to fire - other arguments could be passed via remaining EFF v2.0 params.
It's possible to make a dedicated opcode that does all of this, but it seems a bit silly to hardcode the probability portion, which I'm just going to write in Lua anyway. Also, if I implement it as the above, the only new additions to EEex would be a few additional internal-function externalizations.
And, as a side note, Opcode #252 has some funky hardcodedness going on - it's easier to reimplement its functionality than to try to adapt it.
You're the expert. If that's is easier for you, I'm happy with it (heh, though an example would be really helpful-- I'm still intimidated by lua, and so I'm not envisioning how exactly this would work. One example would be all I need)
@Bubb I have another request. I was wondering if it was possible to change the calculation of distance between a creature and that creature's target to take into account differences in z position between them.
A while ago, you said the pseudocode for spell range was something like this:
a = (sprite x / 16) - (target x / 16)
b = (sprite y / 12) - (target y / 12)
c = spell range + 2
Spell Range Satisfied: a^2 + b^2 <= c^2
Could you turn it into something like this?
a = (sprite x / 16) - (target x / 16)
b = (sprite y / 12) - (target y / 12)
d = (sprite z / 16) - (target z / 16)
c = spell range + 2
Spell Range Satisfied: a^2 + b^2 + d^2 <= c^2
This would also have to be done for attack range.
Since creatures don't normally differ in z position, this shouldn't affect the game except when mods include ways of changing a creature's height.
Since creatures don't normally differ in z position, this shouldn't affect the game except when mods include ways of changing a creature's height.
Isn't the z-position used for visual effects (just a small offset for where the feet circle will be drawn) in-game? I was rather certain the height search map affected creatures' z-position.
Since creatures don't normally differ in z position, this shouldn't affect the game except when mods include ways of changing a creature's height.
Isn't the z-position used for visual effects (just a small offset for where the feet circle will be drawn) in-game? I was rather certain the height search map affected creatures' z-position.
I just did some testing, and it seems like the height map doesn't actually change the z position value in the actor data. It's always 0 regardless of the height map.
@OlvynChuru: The z-pos and the height map work independently - though they are both taken into consideration when rendering the sprite, as you can see.
Unfortunately, it appears the compiler has inlined the distance code over hundreds of calls. I can attempt to change just the attack + casting code, but the pathfinding system and other internal targeting mechanisms would probably get confused when they encounter a distance that can't be closed. I.E. if you target a creature flying high in the sky, the engine will just get stuck trying to walk to it, not realizing it can never reach the destination.
What you are asking most likely can't be done without resulting in some bugs - but if you are OK with these peculiarities, I can still attempt it.
I.E. if you target a creature flying high in the sky, the engine will just get stuck trying to walk to it, not realizing it can never reach the destination.
That's fine; that's actually what I wanted to happen.
@Bubb
OK, here's another one (if you think it makes sense of course):
Add the following modified version of 'WeaponCanDamage()' and 'WeaponEffectiveVS()':
WeaponEffectiveVs(O:Object*,I:WeaponNum*SLOTS)
// Returns true if the weapon specified in the 2nd parameter of the active creature can hit the target object specified in the 1st parameter.
WeaponCanDamage(O:Object*,I:WeaponNum*SLOTS)
// Returns true if the weapon specified in the 2nd parameter of the active creature can cause non-zero damage to the target object specified in the 1st parameter.
Comments
It should probably fail if it doesn't find an object. Having to include an Exists() line with it every time would at best cause more wordiness and at worst cause bugs if the modder forgets to put in the Exists() line.
Trigger version => Same as action version, + fails if it couldn't match a creature.
EEex_MatchObject is now per-creature => EEex_MatchObject is now stored individually, so each object can keep track of its own unique target.
Volatile fields => New functions that allow a modder to store temporary information on a creature, (not preserved on save/load or, for local creatures, area transition).
EEex_RegisterVolatileField(name, attributeTable) -> Registers a volatile field for later use. Example:
Note: Volatile fields should only be defined once + should be registered in a M_*.LUA file. A creature's EEex_MatchObject actorID can be retrieved from Lua by using the following:
EEex_AccessVolatileField(actorID, name) -> Returns the start-address of the given field for the specified actor.
EEex_GetVolatileField(actorID, name) -> Returns the Lua-friendy version of the given field for the specified actor.
EEex_SetVolatileField(actorID, name, value) -> Sets the given field from the Lua-friendy value for the specified actor.
@swit: The following is an example that you provided:
Unfortunately it is impossible to make an Object version of EEex_MatchObject, as objects don't allow parameters to be passed in the same manner as other scripting elements.
The above block's functionality can be replicated with simple EEex_MatchObject trigger calls, (as it enforces LOS by default), but any nested trigger checks need to be implemented in the filter function itself. That could be done by either passing a trigger string to the filter function and subsequently evaluating it, or by hardcoding the additional checks into variants of the same filter function.
Example: ^ Returns SHOUT.BCS's internal engine representation.
Example:
Example: ^ Runs the shout script, fetched in an above example, on the currently selected character.
Example: ^ Frees the memory occupied by the shout script, fetched in an above example. Note that this only frees your local copy - is has no effect on the rest of the game.
Example: ^ Compiles a See trigger for use in the following functions.
Example: ^ Evaluates the compiled see trigger that we got in an above example as if it was run by the currently selected character, and returns true/false depending on if the trigger succeeded.
Example: ^ Evaluates the See trigger embedded in the given string as if it was being run by the currently selected character, and returns true/false depending on if the trigger succeeded.
Example:
^ Frees the memory occupied by the internal see trigger object, fetched in an above example. Note that this only frees your local copy - is has no effect on the rest of the game.
A little request: could you make it so one of the flags in a SPL file changes which name is displayed when the spell is cast? If the flag is set, casting the spell should display the identified name (NAME2) of the spell rather than its general name (NAME1).
One thing we could do with this is prevent a spell from displaying its name when cast (by setting the flag and having the identified name strref be -1), while still showing its name in the tooltip and the spell description.
BIT31 of a SPL's "Flags" field will now force the engine to display the spell's Identified name in the combat log when cast. Also, the engine didn't skip log output for empty / invalid strings like you wanted, so I patched that in for STRREF_FEEDBACK_CASTING and STRREF_FEEDBACK_CASTS.
(I don't think BIT31 is being used for anything at the moment, but if it is I can change the check bit)
By the way, do you know if the "Identified name" (offset 0xC) field is used in the EE engine? I couldn't find any obvious references to it in the assembly.
Is there a way to assign the 'Shaman Dance' button via opcode404?
The documentation doesn't list it and none of the not listed numbers I've tried worked out either.
Am I right to assume that the 'Shaman Dance' is a special case and handled differently than the other buttons?
On a somewhat related note: I've noticed that button #9 is the (defunct) shapeshift ability. Would it be possible to assign a spell to that ability? That way custom buttons could be created by replacing the bam/stringref. (Would obviously only allow for one custom button, but still, if it could be done with relative easy, that would be useful to have..)
On the second note, I'd have to look into the exact actionbar mechanisms further. Actionbar functions are extremely complicated, so it's quite hard to decipher the actual functionality in a lot of cases. I'll take a stab at it of course - but with the semester starting back up it'll probably take me a while to get anything done.
Thank you, I suspected something like that would be the case.
Don't stress yourself, at least not on my account. While your work is fantastic and very much appreciated, all I'm using it for is stupid kit mods no one needs.. and if I can't do one idea I'll just do something else.
This likely isn't a problem with EEex by itself, but rather with some of the things I've added using EEex. In my game, there are two Screen Effects opcodes attached to every creature in every area (in addition to the party members), and the protagonist has a permanent Invoke Lua effect which runs some code whenever the game is loaded but doesn't do anything otherwise.
Specifically, that permanent Invoke Lua effect calls this function:
I suspect that the crashes are happening because of one of these things. However, I'm not sure why clicking on a party member's portrait would cause a crash. Could you look at the code that's run when a portrait is clicked and see what might be the problem?
Okay, I know it hasn't been officially released yet, and so there may be a missing component that is required to finalize the component, but I just had to try custom skills. As you may have guessed, I wasn't quite able to get it to work completely.
The only thing I did was uncomment the example lore skill before installing EEex in ExtendedSkills.tpa:
I tested it in my GOG version of BG2EE, version 2.5.16.6 with no other mods installed.
It partially worked. I created an assassin (with the required attributes) and I was able to put points into 'Lore':
Now, this might be because 'visibility' is set to 4, but the new value didn't show up in the main character creation screen:
and the adjusted value did not show up on the character sheet once the game started (it should be 99 or thereabouts):
It's base value determined from LORE.2da and LOREBON.2da is either recalculated constantly or cannot be overwritten.
@kjeron That's actually not the issue (though it might be an issue). The issue is that I designed the custom skills feature in BG1:EE and some of the UI modifications currently don't work in BG2:EE. In BG1:EE I've tested putting points in Lore and it worked.
A ton of things happen when a portrait is clicked; it would be infeasible to guess what exactly is causing the issue. Could you please upload the crash dmp(s)? Also, any way to reproduce on my end would help tremendously.
I don't know if I've really fixed it, but I do know I've fixed at least one source of crashes.
I noticed that you added additional checks for death states. That's good, and is probably the desired result most of the time, though I just wanted to note that sprites still exist and can be accessed even though they are dead.
(Yesterday I made custom skills work in BG2EE as well but I didn't mention it here; @Bubb already merged this into EEex).
Yup. And boy is it cool
Okay, what do I mean? I see that effect 252 is hard coded to be tied to stat 28, such that, stat 28 determines, in some sense, the chance that a given 252 effect will properly trigger (and/or how likely a 'mishap' is to trigger). Could we get an opcode or 2da that allows us to couple particular spls with newly added stats? So, maybe a 2da that looks something like:
The first column is filled by the Stat that is associated with the spl, Opcode and/or modal. The value of this stat (of the targeted creature) determine's the % chance (maximum 99%) that the spl or opcode executes when activated.
The second column is filled by the model that is associated with the skill (ids match what is defined by EEex_ACTIONBAR_TYPE in M__EEex.lua). When the modal is activated, the creature will be targeted by the associated spl (again, with a % chance equal to stat). If the value is ****, then the spl/stat is not associated with any modal.
The third column is filled by the ResRef of the spl associated with the Stat. This spl will fail if the targeted creature(s) does not have sufficient points in the relevant stat.
The fourth column is fill by the Opcode that is associated with the stat. Any spl with this opcode will fail if the targeted creature does not have sufficient points in the relevant stat (BE CAREFUL WITH THIS ONE!)
The fifth column is filled by the ResRef of the spl that fires at the target if the character rolls a 'mishap' (determined with the same probability as the set snares spl). If the value is ****, then there is no mishap associated with this stat.
The above entries might act as examples. The first two are the normal set trap spl and the special bounty hunter set traps respectively. The third is a hypothetical 'use poison' skill that has a chance of poisoning the character on a mishap, and the fourth uses the Find Traps modal to implement the Paladin's Detect evil ability as a skill using the Find Traps modal.
Edit: or what if Opcode #401 could be used to associate a stat with a spl in this way at least for a given creature, perhaps with an applied 401 with the relevant spl in the resource.
Whatever is easiest
What about just altering op252 so it's parameters can be used to specify which stat it checks, and whether or not to apply the "Set Trap" restrictions (hostile in sight, trap limit). The critical failure spell is just "%resource%F".
I like that. So, resource would set the spl effect So, for example, if the resource was "spcl422" the the relevant stat would apply to the poison weapon ability to the creature?
Also, maybe special field could be used associate the stat with a modal?
Edit: Er, my sense is that that probably wouldn't work (maybe as an AP_ application in the clab? No idea
Anyway, *merely* an alteration to 252 as described would be Amazeballs
It's possible to make a dedicated opcode that does all of this, but it seems a bit silly to hardcode the probability portion, which I'm just going to write in Lua anyway. Also, if I implement it as the above, the only new additions to EEex would be a few additional internal-function externalizations.
And, as a side note, Opcode #252 has some funky hardcodedness going on - it's easier to reimplement its functionality than to try to adapt it.
You're the expert. If that's is easier for you, I'm happy with it (heh, though an example would be really helpful-- I'm still intimidated by lua, and so I'm not envisioning how exactly this would work. One example would be all I need)
A while ago, you said the pseudocode for spell range was something like this:
Could you turn it into something like this?
This would also have to be done for attack range.
Since creatures don't normally differ in z position, this shouldn't affect the game except when mods include ways of changing a creature's height.
I just did some testing, and it seems like the height map doesn't actually change the z position value in the actor data. It's always 0 regardless of the height map.
Unfortunately, it appears the compiler has inlined the distance code over hundreds of calls. I can attempt to change just the attack + casting code, but the pathfinding system and other internal targeting mechanisms would probably get confused when they encounter a distance that can't be closed. I.E. if you target a creature flying high in the sky, the engine will just get stuck trying to walk to it, not realizing it can never reach the destination.
What you are asking most likely can't be done without resulting in some bugs - but if you are OK with these peculiarities, I can still attempt it.
Go for it!
That's fine; that's actually what I wanted to happen.
OK, here's another one (if you think it makes sense of course):
Add the following modified version of 'WeaponCanDamage()' and 'WeaponEffectiveVS()':