Skip to content

[MOD] EEex (v0.10.2-alpha)

1131416181948

Comments

  • OlvynChuruOlvynChuru Member Posts: 3,075
    I've found places where the game stores the coordinates an actor is moving to, regardless of whether or not they are targeting another actor.

    To get the X coordinate, do:

    EEex_ReadDword(EEex_GetActorShare(actorID) + 0x3404)

    To get the Y coordinate, do:

    EEex_ReadDword(EEex_GetActorShare(actorID) + 0x3408)

    Also, if the actor is targeting another actor, the particular action the former is doing to the latter is sometimes stored in:

    EEex_ReadDword(EEex_GetActorShare(actorID) + 0x350)

    ^ This will return 0 if the actor is initiating dialogue, it will return 1 if the actor is attacking, and it will probably return other numbers if the actor is guarding, pickpocketing, etc., but I haven't checked. The problem is that this is not very reliable. Sometimes this space stores something completely different, usually a very large number.
  • SeritySerity Member Posts: 16
    edited May 2019
    Dang, you're a monster, Bubb, so quick. Great work.

    Seems like there's some sort of delay on IsActorInCombat before it actually resolves to false, yet you can still rest/save. Still, it's good enough for my purposes, but I thought I'd let you know :P
    54xtR9C.png
    (it's false before combat and false shortly after this though)
    I assume it has something to do with that longest label in the entire Infinity Engine :P

    edit: Also, thank you for the .name/.description <3
    Post edited by Serity on
  • David77David77 Member Posts: 30
    This thread is a little bit amazing no? Anyone fancy sharing how to 'activate' the timer aspect Bubbz's mod allows - i have the latest version with B3_Timer installed but am a Lua/mod noob.
  • BubbBubb Member Posts: 1,001
    Sorry for the delay guys, was gone yesterday.

    @David77: All the code for the timer visualizations is there, I just have to finish up the graphical elements. Color me sidetracked... actually managed to get sidetracked for close to a month. Oops.

    @Serity: It appears that the action triggers that I copied the behavior from intentionally have a delay after combat ends, (that's what the label is :p). I'll just throw that weird delay behind a boolean and call it good...

    @OlvynChuru: So, there are multiple ways of getting "target" pos, and all of them have slightly different behaviors. The one currently in master, (0x3568 and 0x356C), only pertains to walking-ground destinations. The ones you have found, (0x3404 and 0x3408), work with both ground destinations and actor-targeted destinations.

    The one I have in EEex updates immediately. The one you have found takes 1 tick of time to get filled, though I think characters only start pathing to actors after some amount of time has passed, so that's unavoidable.

    And there is yet another at 0x31D4, 0x31D8. Don't know what the differences are yet. More testing is needed :)
  • David77David77 Member Posts: 30
    edited May 2019
    You know any function via near infinity and hotkey to forget all spells from a character? Or maybe this is the place to ask if it can be created? Thank you
  • SeritySerity Member Posts: 16
    edited May 2019
    David77 wrote: »
    You know any function via near infinity and hotkey to forget all spells from a character? Or maybe this is the place to ask if it can be created? Thank you
    If you mean in terms of memorization, EEex has these functions:
    function EEex_UnmemorizeWizardSpell(actorID, level, index)
    function EEex_UnmemorizeClericSpell(actorID, level, index)
    function EEex_UnmemorizeInnateSpell(actorID, index)
    
    Combined with a loop through EEex_GetMemorizedClericSpells(actorID) (/WizardSpells/InnateSpells[1]) it should probably get you near what you want.

    If you mean in terms of "wiping what has been learned" (from scrolls etc) then I'm not sure about that.


    edit: vvvvv gah that's what I get for skimming through the function list too fast
    Post edited by Serity on
  • BubbBubb Member Posts: 1,001
    function EEex_UnlearnWizardSpell(actorID, level, resref)
    function EEex_UnlearnClericSpell(actorID, level, resref)
    function EEex_UnlearnInnateSpell(actorID, resref)
    

    Are the spell book variants. (notice resref instead of index)
  • BubbBubb Member Posts: 1,001
    edited May 2019
    And a few more things are in master:
    • C:Eval(actionString, actorID) => Can now be used to directly target the evaluating object.
      (0 <= actorID <= 5) => uses the character in that portrait slot.
      (actorID = -1) => Uses the current game area, or the creature under the cursor if exists.
      (actorID = 6+) => Uses the current game area if actorID is invalid - uses actor if valid...

    • EEex_GetActorCurrentHP(actorID) => Gets the actor's current HP
    • EEex_GetActorCurrentDest(actorID) => Gets the actor's current destination, (1-tick delay)
    • EEex_GetActorPosDest(actorID) => Gets the actor's current destination, (unknown difference)

    • EEex_IsActorInCombat(actorID, includeDeadZone) => When includeDeadZone is true, acts exactly like combat triggers. When false, immediately resolves combat status.
  • BubbBubb Member Posts: 1,001
    @OlvynChuru: Merged! :)
  • BubbBubb Member Posts: 1,001
    I'm thinking about somehow allowing opcode parameters to be mutated by the Lua environment, to allow for dynamic effects.

    One way of doing it would be to allow the Lua environment itself to construct and apply opcodes to creatures. Doing it this way would require an Invoke opcode in the place of the normal opcode inside of the spell, and since Invoke can't take Lua params, every dynamic opcode would need its own Lua function.

    The ability to apply opcodes from Lua would theoretically allow for whole spells to consist of a single Invoke opcode, which leads down a rabbit-hole of Lua-created effects. The main question here would be if Lua is fast enough to construct these opcodes on the fly without slowing down the game.

    Any thoughts?
  • kjeronkjeron Member Posts: 2,367
    I assume the purpose would be similar to how op333 (Static Charge) can overwrite the dice values of op12 effects in the spell it casts? I think it would be better to keep this approach - put all the opcodes in a subspell, and have the Invoke Lua apply that spell while overriding various fields of the necessary opcodes.

    Something else, partially related - possibility of altering opcodes that are already attached to a creature, similar to how op329 (Slow Poison) functions on op25 (Poison).
  • OlvynChuruOlvynChuru Member Posts: 3,075
    Bubb wrote: »
    I'm thinking about somehow allowing opcode parameters to be mutated by the Lua environment, to allow for dynamic effects.

    One way of doing it would be to allow the Lua environment itself to construct and apply opcodes to creatures. Doing it this way would require an Invoke opcode in the place of the normal opcode inside of the spell, and since Invoke can't take Lua params, every dynamic opcode would need its own Lua function.

    The ability to apply opcodes from Lua would theoretically allow for whole spells to consist of a single Invoke opcode, which leads down a rabbit-hole of Lua-created effects. The main question here would be if Lua is fast enough to construct these opcodes on the fly without slowing down the game.

    Any thoughts?

    If you could let Lua functions apply effects to creatures, that would be great! I'm not sure what we'd need a special Invoke opcode for; couldn't we use opcode 402 to pass parameters to a Lua function that then applies an effect based on the parameters and on other things?
  • RaduzielRaduziel Member Posts: 4,714
    Stupid

    Sixteen pages and I still didn't understand what is a Lua.

    /Stupid

    Carry on, please.
  • RaduzielRaduziel Member Posts: 4,714
    @Serity Thanks for the enlightenment :)
  • BubbBubb Member Posts: 1,001
    New function in master:

    EEex_ApplyEffectToActor(actorID, args) => Constructs a new effect based on the args table and instantly applies said effect to the actor. Valid arg keys are:
    effectID
    targetType
    spellLevel
    effectAmount
    dwFlags
    durationType
    dispelType
    duration
    probabilityUpper
    probabilityLower
    res
    numDice
    diceSize
    savingThrow
    saveMod
    special

    These args directly mirror the effect structure defined in .SPL files. All args should be a number, (with the exception of res, which is a string). Normal effect field limitations still apply, and the corresponding args will be treated as such.

    Example:
    function B3TestEffect()
        local actorID = EEex_GetActorIDSelected()
        if actorID == 0x0 then return end
        EEex_ApplyEffectToActor(actorID, {
            ["effectID"] = 0x8B,
            ["effectAmount"] = 1
        })
    end
    

    @OlvynChuru: Could you please test this function? It is more complex than most, and it's always a good thing to have another set of eyes on something.
  • OlvynChuruOlvynChuru Member Posts: 3,075
    Thank you! :)

    I tested the function with opcodes 12 (damage), 146 (cast spell) and 326 (apply effects list). The damage opcode works fine. The cast spell opcode works only when the spell is cast normally. When the spell is supposed to be cast instantly, the opcode doesn't work and the spell isn't cast. The apply effects list opcode doesn't work.
  • kjeronkjeron Member Posts: 2,367
    Blind guess:
    op146(instant)/op326: unable to generate a caster level for the spell?
  • OlvynChuruOlvynChuru Member Posts: 3,075
    kjeron wrote: »
    Blind guess:
    op146(instant)/op326: unable to generate a caster level for the spell?

    I'm not sure. I was using opcode 146 with parameter1 > 0 and parameter2 = 1 and it didn't work.
  • switswit Member, Translator (NDA) Posts: 495
    edited May 2019
    OlvynChuru wrote: »
    Thank you! :)

    I tested the function with opcodes 12 (damage), 146 (cast spell) and 326 (apply effects list). The damage opcode works fine. The cast spell opcode works only when the spell is cast normally. When the spell is supposed to be cast instantly, the opcode doesn't work and the spell isn't cast. The apply effects list opcode doesn't work.

    In case it helps - during work on implementing IWD2 style Cleric domains magic system I've noticed that Cast instantly parameter changes how the resource spell "Self" target works:
    param2=0 Self target effect is applied to the caster.
    param2=1 or 2 Self target affects destination cre, not caster.

    As for the function itself - fantastic work, Bubb. There is one thing missing here that I think would be usefull - from the description it looks like the function doesn't set "parent resource" field (engine sets it in destination cre based on the spell name), so the effects can't be properly cleaned out using opcode 321.

    edit: the naming convention used here is a little unusual. I assume effectAmount and dwFlags means parameter1 and parameter2? (based on the list order, I've never seen those names used before). For consistency sake with weidu conventions I think it would be better to use the same names as weidu functions:
    opcode: opcode
    target: target type
    power: power
    parameter1: first parameter
    parameter2: second parameter
    timing: timing type
    resist_dispel: magic resistance/dispel type
    duration: duration
    probability1: probability 1 (default 100)
    probability2: probability 2
    resource: resource (8 chars max)
    dicenumber: number of dices to be thrown
    dicesize: size of dices to be thrown
    savingthrow: type of savingthrow to be allowed against the effect
    savebonus: saving throw bonus
    special: the special parameter
    
    Post edited by swit on
  • kjeronkjeron Member Posts: 2,367
    swit wrote: »
    param2=0 Self target effect is applied to the caster.
    param2=1 or 2 Self target affects destination cre, not caster.
    For op146, only p2=2 does that, not p2=1.
    p2=1 targets the same as p2=0.
    p2=2 targets the same way as op326.
  • BubbBubb Member Posts: 1,001
    edited May 2019
    @swit: The unusual names are what the engine calls the fields internally. I've changed them to the WeiDU counterparts you provided, and have added the parent_resource key as well. Here's the updated list of keys:
    opcode
    target
    power
    parameter1
    parameter2
    timing
    resist_dispel
    duration
    probability1
    probability2
    resource
    dicenumber
    dicesize
    savingthrow
    savebonus
    special
    parent_resource

    In addition to those, I've added a couple that aren't directly used in the V1 effect, but are required for some opcodes to function:
    source_target => I assume this is the actorID of the source's target. Unknown when this is used.

    target_x => The x value of the effect. Usually filled by the spell, but since we are applying effects directly, this will have to be manually filled for some opcodes to function.

    target_y => Same as above, but for y.

    source_id => The actorID of the effect source. Might be how the engine figures out the casters level; most certainly used for other things as well.

    source_x => The x value of the source. Unknown which opcodes use this field.

    source_y => Same as above, but for y.

    @OlvynChuru: Thank you for testing them out. The situations you were attempting might have required some of the new fields listed above; what code were you using for these tests?
  • OlvynChuruOlvynChuru Member Posts: 3,075
    edited May 2019
    I'm trying the function now, and something's going wrong. Even the damage opcode, which worked previously, isn't working now. It seems like the function is causing some kind of error because the print statement I put after it is not printing anything (indicating that the function ended prematurely).

    I had been aiming on giving Kagain an effect that gives him bonuses based on the party's gold, but I changed things temporarily to test EEex_ApplyEffectToActor(). Here's the code:
    function MEGOLDAB(effectData, creatureData)
    	local targetID = EEex_ReadDword(creatureData + 0x34)
    	if targetID == 0x0 then return end
    	Infinity_DisplayString(characters[id].gold)
    	Infinity_DisplayString(EEex_ReadDword(effectData + 0x18))
    	local me_gold_ability_count = math.floor((characters[id].gold / EEex_ReadDword(effectData + 0x18)) + 1)
    	Infinity_DisplayString(me_gold_ability_count)
    	EEex_ApplyEffectToActor(targetID, {
    ["opcode"] = 12,
    ["target"] = 1,
    ["parameter1"] = 1,
    ["parameter2"] = 0,
    ["timing"] = 1,
    ["duration"] = 100,
    ["source_target"] = targetID,
    ["source_id"] = targetID
    })
    	Infinity_DisplayString(me_gold_ability_count)
    end
    

    The first three Infinity_DisplayString statements work, but the last one does not.

    I tried removing various things like the "source_target" and "source_id" lines, but it still didn't work.
  • BubbBubb Member Posts: 1,001
    edited May 2019
    @OlvynChuru: It was a silly mistake on my part. Omitting a resref arg, which should fall back to a default value, was throwing an error. In all of my testing I always explicitly defined the resrefs, even when they were empty. Should be fixed in master...
  • OlvynChuruOlvynChuru Member Posts: 3,075
    edited May 2019
    I got it to work now! The cast spell opcode now works with parameter2 > 0.

    Here's something else. I've found that the game has some way of changing an actor's height above its selection circle. Normally it depends on the actor's sprite, but there is one time when the game changes it regardless of the actor's sprite: when the actor is chunked. If you look carefully when a creature is chunked, it bounces up and down for a second or two.

    If a creature has an opcode 53 effect (modify animation) with parameter2 = 2 and timing = permanent after death, the creature will retain its animation when chunked, and it will still bounce up and down.

    I had an ogre brought back to life immediately after being chunked. It bounced up, as shown in the screenshot below:

    kvz5lmkl2far.png

    Could we create an opcode that modifies the target's height above their selection circle, or makes them move up or down at a specified speed, without killing them?

    If this is any help, I found something that may be relevant while snooping around the debug symbols file:

    CGameChunk::CGameChunk ƒ
    :üÿÿÿ “ this ! animationID 04 colorRangeValues
    1401 sSoundChunk ß pArea 61301 pos 6 posDelta posZ 16 24 posZDelta ( duration , durationFade 9¨8- ‡) 9U9-   > ì ¤ ” ˆh 9-

    posZ and posZDelta sound like they have something to do with changing the creature's height.
  • BubbBubb Member Posts: 1,001
    @OlvynChuru: How does an animation change the creature's height? It would be the best bet for a manual change, as the creature's normal "z" position is used by the bounce logic you described earlier. You can set it manually, but the engine will then take over and bounce the character around.
  • RaduzielRaduziel Member Posts: 4,714
    @Bubb Wait a minute... if it is possible to change a creature's height could we alter a creature's size? Let's say enlarge it by x %?

    I was working on an Enlarge spell but I had to make lots of BAMs for it and the spells + BAMs got with almost 200mB... a little too much for a single spell.

    Thanks.
  • kjeronkjeron Member Posts: 2,367
    Bubb wrote: »
    @OlvynChuru: How does an animation change the creature's height?
    OlvynChuru might be refering to the height for "casting" - the height at which projectiles start/end depending on the caster and target.
Sign In or Register to comment.