Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Neverwinter Nights: Enhanced Edition has been released! Visit nwn.beamdog.com to make an order. NWN:EE FAQ is available.
Soundtracks for BG:EE, SoD, BG2:EE, IWD:EE, PST:EE are now available in the Beamdog store.
Attention, new and old users! Please read the new rules of conduct for the forums, and we hope you enjoy your stay!

General mod Questions thread

1373840424361

Comments

  • Luke93Luke93 Member, Mobile Tester Posts: 1,181
    kjeron said:

    Luke93 said:

    What do you mean exactly with 'OR() blocks'? Are you saying that, e.g., See([regexp.HUMANOID]) should be put in an OR() block together with !CheckSpellState([regexp],DUMMY_SPLSTATE) ? But this cannot work because I am HUMANOID (if I don't use opcode #72), so the See trigger returns true ---> the OR() block returns true and WIZARD_HOLD_PERSON is wasted.....

    If See([0.HUMANOID]) is already in an OR() block, REPLACE_TEXTUALLY will break that OR() block, because it will put !CheckSpellState(object,DUMMY_SPLSTATE) into that OR() block. Unlike !General(), it is normal for See() to be in an OR() block.

    As @Ardanis said, we could use REFACTOR_TRIGGER: it basically duplicates the OR() block ---> there will be one OR() block containing See([0.HUMANOID]) (plus what was there before) and another one containing !CheckSpellState(object,DUMMY_SPLSTATE) (plus what was there before).

    This solution works but what about in-game performance? I expect the game to be somewhat laggy with all those checks, especially if the OR() block has 15+ triggers (like in BDLICH01.bcs). What do you think?

  • kjeronkjeron Member Posts: 1,965
    REFACTOR_TRIGGER has it's own issues.
    It does not allow matching only 'Trigger()' or '!Trigger()', it always matches both, and it does not properly handle matching '!Trigger()' outside of an OR() block.

  • ArdanisArdanis Member Posts: 1,580
    Luke93 said:


    Yes, sure, there is still the possibility that some spells will be wasted in any case (if the AI doesn't check for those splstates), but, after a quick look at some scripts, this seems to be intentional, right ( Ardanis ?)

    I'm perfectly fine with AI ignoring immunity buffs and wasting spells on those. And as far as I could judge by various playthroughs posted on this forum it wasn't negatively affecting the difficulty.

  • Luke93Luke93 Member, Mobile Tester Posts: 1,181
    edited January 7
    kjeron said:

    Luke93 said:

    Oh, wait, there may be an alternative: what about giving the creature weapon some key splstates/stats via opcode #328 or opcode #233 as equipping effects (timing mode = 2)? For example: RESIST_FEAR (to counter opcode #24), CHAOTIC_COMMAND (to counter opcodes #39, #5, #128), CLERIC_FREE_ACTION (to counter opcodes #175, #109) (am I missing something?)

    That will work, except you will still be triggering them to cast Remove Magic, as it assumes those stats/states accompany dispellable effects.
    After a closer look at the scripts, it seems that either "CheckStatGT(LastSeenBy(Myself),0,STONESKINS)" or HasItemEquiped("MELFMET",LastSeenBy(Myself)) (Melf's Minute Meteor) are required for the enemy to cast Remove Magic, so everything should be fine on that front (i.e., the spell is only partially wasted, which is fine......). Moreover, I also added the stat WIZARD_PROTECTION_FROM_NORMAL_WEAPONS.

    The only problems seem to be related to BDDROWMA, BDDROWCL, BDCRUSMA, BDMAGE28: those scripts don't check for RESIST_FEAR and CLERIC_CHAOTIC_COMMANDS (but this may be intentional). OK, I can live with that......

    Post edited by Luke93 on
  • marcosmarcos Member Posts: 62
    edited January 9
    Never mind. Figured it out!

    "How do you manipulate lore?

    Blades have their lore halved, and some mod kits have lore increased, but I can't quite see how they do it. I've tried playing with the Lore Modifier effect, but that seems like a one-off thing, ideal for an object. How do you change lore for a class or kit for each level?"

    Post edited by marcos on
  • ArunsunArunsun Member Posts: 1,581
    Long time no see, I have been pretty busy and as it turns out when your job's coding things all day, you don't really wanna code more things when you get home :smiley:

    But I still have mods I put on the back back back burner and I want to finish them properly.

    I am facing a small issue with one of them, as it adds a map to the worldmap, and I have issues understanding the BP-BGT-Worldmap mod.
    I have read the readme and I roughly got how it works (adds your map to a list of map etc... and then install all at once at the end of the installation) but I would like to make my mod available as a standalone and compatible with worldmap.
    However, since it's installed after my mod, I can't use MOD_IS_INSTALLED as a condition to either execute the worldmap-less code or the worldmap-installed code. So, how do I handle things? The only solution I could think of is asking the player whether they are going to use Worldmap before installing the component, and that does not seem like a clean solution.

    Thank you guys in advance!

  • fortysevenfortyseven Member Posts: 63
    edited January 19
    Is it possible to modify how the sound elements of the school based casting animations are handled? Is there a general animation file for these that defines visuals and sounds? So far I have not been able to find one. If this is handled differently would someone be able to shed some light on this? Many thanks!

  • RatatoskrRatatoskr Member Posts: 336
    edited January 23
    Does anyone know where I can find detailed instructions on adding Tob epilogues for a new NPC? Most of the older tutorials either seem to be gone or don't say anything about the epilogues. I've been using other mods as examples but I must be missing something because mine refuses to work.

    I have the Ar6200 script file, the 2da file, and my code in the set up file, but it still refuses to play.

    Post edited by Ratatoskr on
  • RaduzielRaduziel Member Posts: 4,458
    edited February 4
    Q1) If I give Lay on Hands to a kit do I need to APEND layhands.2da with something?

    Q2) Is there a way to make a good/neutral cleric Command Undead or make an evil cleric Turn them?

    Thanks in advance.

    Post edited by Raduziel on
  • BubbBubb Member Posts: 641

    Q1) layhands.2da is loaded, but completely ignored by the engine. Probably something left over from an older engine version...

    Q2) This is hopelessly hardcoded, with no way to change it.

    Raduzielsemiticgod
  • RaduzielRaduziel Member Posts: 4,458
    @Bubb

    Thanks. You broke my heart but enlighted my mind.

  • RaduzielRaduziel Member Posts: 4,458
    edited February 4
    Another question.

    I have a spell with 26 headers. I just want one of them.

    Currently, I'm using the following when copying the spell:

    LPF DELETE_SPELL_HEADER INT_VAR min_level = 6 END

    The first header has "Required Level 1". The second one, 6; the third one, 7 and so it goes.

    Apparently, the code I'm using does nothing. What am I doing wrong?

    Thanks.

  • kjeronkjeron Member Posts: 1,965
    edited February 4
    LPF DELETE_SPELL_HEADER INT_VAR header_type = ~-1~ min_level = 6 END
    According to it's documentation, but I can't test ATM.

  • RaduzielRaduziel Member Posts: 4,458
    edited February 4
    kjeron said:
    LPF DELETE_SPELL_HEADER INT_VAR header_type = ~-1~ min_level = 6 END
    According to it's documentation, but I can't test ATM.


    Here is my text, the forum is crazy: I was just testing exactly this and that solves indeed. I've misinterpreted the document. Apparently I have to input a different command header by header.

    Now the code looks like this:

    LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 2 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 3 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 4 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 5 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 6 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 7 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 8 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 9 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 10 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 11 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 12 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 13 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 14 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 15 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 16 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 17 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 18 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 19 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 20 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 21 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 22 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 23 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 24 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 25 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 26 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 27 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 28 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 29 END LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = 30 ENDNot pretty, but works.

    Thanks!

  • ArunsunArunsun Member Posts: 1,581
    @Raduziel you definitely should use a for-loop here. I don't have the exact syntax here for WeiDU but it should be something like:
    FOR (level = 6; level < 31; level += 1) BEGIN
    LPF DELETE_SPELL_HEADER INT_VAR silent = 1 header_type = ~-1~ min_level = level END
    END

    Makes the code a lot clearer and less tedious to write

    Raduziel
  • RaduzielRaduziel Member Posts: 4,458
  • subtledoctorsubtledoctor Member Posts: 11,136
    edited February 10
    Anyone know if something like this can work?
    DEFINE_ACTION_FUNCTION ~array_function~
      STR_VAR
        function_array = ~~
    BEGIN
      ACTION_PHP_EACH %sphere_array% AS k => v BEGIN
        [do stuff]
      END
    END
    
    ACTION_DEFINE_ASSOCIATIVE_ARRAY this_array BEGIN
      key1 => value1
      key2 => value2
    END
    
    LAF array_function BEGIN
      STR_VAR function_array = ~this_array~
    END
    
    ACTION_DEFINE_ASSOCIATIVE_ARRAY that_array BEGIN
      key3 => value3
      key4 => value4
    END
    
    LAF array_function BEGIN
      STR_VAR function_array = ~that_array~
    END
    

    The part I'm most worried about is:
    ACTION_PHP_EACH %sphere_array% AS k => v BEGIN
    

    Can PHP_EACH take a variable for the name of the array it's going to process?

  • RaduzielRaduziel Member Posts: 4,458
    I have a general modding question.

    I want to reproduce for a kit the specialist wizard save penalty. I know the damn thing is hardcoded.

    So what's the workaround and how do I do it:

    1) patch the kit somehow

    2) patch every spell of a specific school somehow

    Thanks!

  • GrammarsaladGrammarsalad Member Posts: 2,465
    edited February 12
    Raduziel wrote: »
    I have a general modding question.

    I want to reproduce for a kit the specialist wizard save penalty. I know the damn thing is hardcoded.

    So what's the workaround and how do I do it:

    1) patch the kit somehow

    2) patch every spell of a specific school somehow

    Thanks!

    I would patch every spell of the relevant school (that targets a creature, etc) with a 326 effect that targets the caster (i.e. 'self'). This will cast the resource based on caster rather than target attributes, but it casts the spell at the original target.

    Looking at iesdp, it looks like you cannot use kit.ids--bummer--so you will need to use a custom spell state applied in the clab. The 326 effect needs to be the first effect of each affected spell and needs to apply the relevant save penalty (I would just use a 1 second #325 to be sure)

    Edit: this is a bit more complicated, but is a working example:

    https://github.com/Grammarsalad/Proficiencies/blob/master/proficiency/lib/heal.tpa

    (It casts different spls at the Target based on the values of certain proficiencies and wisdom of the caster--for what you are doing, you really only need the first 'level'--say up to line 21 which checks the Prof--in your case the spellatate-- and casts the spl if the value matches)

    Post edited by Grammarsalad on
  • RaduzielRaduziel Member Posts: 4,458
    edited February 12
    Raduziel wrote: »
    I have a general modding question.

    I want to reproduce for a kit the specialist wizard save penalty. I know the damn thing is hardcoded.

    So what's the workaround and how do I do it:

    1) patch the kit somehow

    2) patch every spell of a specific school somehow

    Thanks!
    Looking at iesdp, it looks like you cannot use kit.ids--bummer--so you will need to use a custom spell state applied in the clab. The 326 effect needs to be the first effect of each affected spell and needs to apply the relevant save penalty (I would just use a 1 second #325 to be sure)

    Can you explain this part like I was a 6 yo who just found on his mom's phone pictures of his gym teacher naked?

    Thanks

    Grammarsalad
  • GrammarsaladGrammarsalad Member Posts: 2,465
    edited February 12
    Raduziel wrote: »
    Raduziel wrote: »
    I have a general modding question.

    I want to reproduce for a kit the specialist wizard save penalty. I know the damn thing is hardcoded.

    So what's the workaround and how do I do it:

    1) patch the kit somehow

    2) patch every spell of a specific school somehow

    Thanks!
    Looking at iesdp, it looks like you cannot use kit.ids--bummer--so you will need to use a custom spell state applied in the clab. The 326 effect needs to be the first effect of each affected spell and needs to apply the relevant save penalty (I would just use a 1 second #325 to be sure)

    Can you explain this part like I was a 6 yo who just found on his mom's phone pictures of his gym teacher naked?

    Thanks

    Lol, Aahh! This is going to be something of a blind leading the blind scenario. I'm like your 10 year old brother that "knows everything". I'm sure there is a better way to do this, but here goes. Please also note that there are a lot of moving parts here, and I haven't had my coffee yet. So, I might forget something. Also, time is a bit limited but I'll answer questions as I get time during the day.

    I have a better example here (up to line 59):

    https://github.com/Grammarsalad/Casting_Attributes/blob/master/B_Attributes/data/components/Setup_sorcerer_charisma.tpa

    I'm using--er, misusing--a utility provided by @CamDawg here:

    https://www.gibberlings3.net/forums/topic/28834-bg2-modder-resource-effect-batch-macros/?page=1

    (Basically, I'm dumb and I don't know another way to ensure that an effect will be first).

    Edit: weidu documentation says this:
    STR_VAR insert to the relative position the cloned effect should be inserted at. A value of ’below’ puts the new, cloned effect immediately below the matched effect. Values of ’first’ or last’ will put the new effect at the top or bottom of the effect stack, respectively. All other values will default to ’above’, where the effect is added immediately before the matched effect (default is ’above’).

    Something else to experiment with. Cams function probably won't be needed

    Here is my modified effect batch thingy:

    https://github.com/Grammarsalad/Casting_Attributes/blob/master/B_Attributes/lib/bg2fp_effect_batches_attributes.tpa

    If you look at the first one, b_sor_cha_grease_arrays:

    https://github.com/Grammarsalad/Casting_Attributes/blob/master/B_Attributes/lib/bg2fp_effect_batches_attributes.tpa#L45

    Any spell that has a grease effect will have a 326 effect added as the first effect (er, a few of them, but you will only need one). Ah, another thing: where you see "cha_ls" or "cha_eq"--that will choke unless you replace textually to change that to a number.

    That's what this line is for:

    https://github.com/Grammarsalad/Casting_Attributes/blob/master/B_Attributes/data/components/Setup_sorcerer_charisma.tpa#L30

    (Up to 35)

    Gha, I have to get back to this. Haven't had my coffee yet.

    Now, you will need to add your custom spellstate (this is from @kjeron )
    DEFINE_ACTION_FUNCTION ADD_SPLSTATE STR_VAR label = ~~ RET new_ids BEGIN
    OUTER_SET new_ids = ~-1~
    ACTION_IF FILE_CONTAINS_EVALUATED (~SPLSTATE.IDS~ ~^.+[ %TAB%]%label%\b~) BEGIN
    COPY_EXISTING ~SPLSTATE.IDS~ override
    COUNT_2DA_ROWS 2 rows
    FOR (i = 0; i < rows; ++i) BEGIN
    READ_2DA_ENTRY i 1 2 state_label
    PATCH_IF ~%state_label%~ STRING_EQUAL_CASE ~%label%~ BEGIN
    READ_2DA_ENTRY i 0 2 state_id
    SET new_ids = state_id
    END
    END
    BUT_ONLY
    END ELSE BEGIN
    OUTER_FOR (i = 0; i < 256; ++i) BEGIN
    OUTER_SET $occupied_spell_state(~%i%~) = 0
    END
    ACTION_IF (~%label%~ STRING_EQUAL ~~) BEGIN FAIL ~Missing Spell State label~ END ELSE BEGIN
    ACTION_IF ((~%label%~ STRING_CONTAINS_REGEXP ~ ~) = 0) BEGIN FAIL ~Spell State lable cannot have spaces~ END ELSE BEGIN
    COPY_EXISTING ~SPLSTATE.IDS~ override
    COUNT_2DA_ROWS 2 rows
    FOR (i = 0; i < rows; ++i) BEGIN
    READ_2DA_ENTRY i 0 2 state_id
    SET $occupied_spell_state(~%state_id%~) = 1
    END
    FOR (i = 0; i < 256; ++i) BEGIN
    PATCH_IF $occupied_spell_state(~%i%~) = 0 BEGIN
    SET new_ids = i
    SET i = 256
    PATCH_IF new_ids <= rows BEGIN
    INSERT_2DA_ROW new_ids 2 ~%new_ids% %label%~
    END ELSE BEGIN
    INSERT_2DA_ROW new_ids 2 ~%new_ids% %label%~
    END
    END
    END
    PATCH_IF (new_ids = ~-1~) BEGIN PATCH_FAIL ~No available Spell States~ END
    BUT_ONLY
    END
    END
    END
    END

    Sorry it's not indented. You would call this function like so:

    LAF ADD_SPLSTATE STR_VAR label = ~CUSTOM_STATE~ RET new_ids END

    Note that CUSTOM_STATE is just the name of your state.

    Now, I haven't actually used this code except to verify that is does create a new splstate--like there was any doubt--kjeron--but I think that new_ids allows you to call the state later as a variable.

    Gha.
    I'll actually have to play with it later tonight to see how it works and I'll then have to get back to you. I've never actually created and put to use a new spell state so I'll have to experiment with it a bit and report back so I don't mislead you

    I'll also be editing this post as I do more research on the topic

    Post edited by Grammarsalad on
    Raduziel
  • RaduzielRaduziel Member Posts: 4,458
    Thanks, @Grammarsalad . I'll try to make the thing work and will get back to you to inform the results.

    ---

    I want to completely ban a school of magic from a wizard kit. The easy way to do so is to ban the scrolls (no scroll = no spell added. I think.), the problem are the spells picked at char gen

    Any ideas, guys and girls?

    Thanks!

  • kjeronkjeron Member Posts: 1,965
    Raduziel wrote: »
    I want to completely ban a school of magic from a wizard kit. The easy way to do so is to ban the scrolls (no scroll = no spell added. I think.), the problem are the spells picked at char gen
    For BG: The kits unusability flags - add the value used by the specialist that is banned from that schoool.
    For IWD: The above only works to block either Invocation or Conjuration, as the other specialist are barred from 2 schools each:
    Alteration + Illusion
    Necromancy + Abjuration
    Divination + Conjuration
    Illusion + Enchantment

    Raduziel
  • subtledoctorsubtledoctor Member Posts: 11,136
    edited February 12
    Raduziel wrote: »
    I have a general modding question.

    I want to reproduce for a kit the specialist wizard save penalty. I know the damn thing is hardcoded.

    So what's the workaround and how do I do it:

    1) patch the kit somehow

    2) patch every spell of a specific school somehow

    Don't know if this is helpful - it's not the simplest code - but I patched all spells of each school adding extra headers with special capabilities for specialists of schools that match the spell. This is for Tome & Blood's "spontaneous specialist casting" component. The code is here, from lines 119 through 167:
    https://github.com/subtledoctor/TomeAndBlood/blob/master/TomeAndBlood/comp/setup_specialists.tpa
    I would patch every spell of the relevant school (that targets a creature, etc) with a 326 effect that targets the caster (i.e. 'self'). This will cast the resource based on caster rather than target attributes, but it casts the spell at the original target.

    Looking at iesdp, it looks like you cannot use kit.ids--bummer--so you will need to use a custom spell state applied in the clab.

    Wait, why not? You can append a line to SPLPROT.2DA that checks for a match to entries in KIT.IDS, and point the 326 effect there. No need for a spellstate. Here's what I do:
    ADD_KIT ~D5_BARD~
    [yadda yadda yadda]
    
    COPY_EXISTING ~kit.ids~ ~override~
      COUNT_2DA_COLS cols 
      READ_2DA_ENTRIES_NOW rows cols 
      FOR (row = 1; row < rows; ++row) BEGIN 
        READ_2DA_ENTRY_FORMER rows row 1 ~kit~ 
        PATCH_IF ~%kit%~ STRING_EQUAL_CASE ~D5_BARD~ BEGIN
          SET bard_row = %row%
          READ_2DA_ENTRY_FORMER rows bard_row 0 nu_bard_code
        END
      END
    BUT_ONLY
    
    APPEND ~splprot.2da~ ~D5_KIT_IS%TAB%152%TAB%-1%TAB%1~
    
    COPY_EXISTING ~splprot.2da~ ~override~
      COUNT_2DA_COLS cols
      READ_2DA_ENTRIES_NOW rows cols
      FOR (row = 1; row < rows; ++row) BEGIN
        READ_2DA_ENTRY_FORMER rows row 0 ~stat~
        PATCH_IF ~%stat%~ STRING_EQUAL_CASE ~D5_KIT_IS~ BEGIN
          SET kit_is_row = %row%
        END
      END
    BUT_ONLY
    
    COPY ~might_and_guile/lib/d5_base.spl~ ~override/d5bsong.spl~
      LPF ADD_SPELL_EFFECT INT_VAR insert_point = 0 opcode = 326 target = 2 parameter1 = %nu_bard_code% parameter2 = %kit_is_row% timing = 1 STR_VAR resource = ~d5bd01~ END
    
    Raduziel wrote: »
    I want to completely ban a school of magic from a wizard kit. The easy way to do so is to ban the scrolls (no scroll = no spell added. I think.), the problem are the spells picked at char gen

    It's worse than that. Even if a scroll is unusable - i.e. unequippable - by your kit, you can still have the scroll in your inventory and then you can right-click and learn the spell. The availability of the spell is determined solely by the exclusion flags in 0x1e-0x21 of the .SPL file. We don't have nice things like opcode 180/181/319 to customize it, the way we can with items.

    And, last I heard, not all of those exclusion flags actually work. And they are not all documented - the IESDP says
    bit 15 - 29: Unused
    

    And Near Infinity shows those as being "unknown" (bits 15-22, 29) or representing races (bits 23-28) But actually, some of those correspond with spellcasting kits from the cleric/druid/bard classes. And the bard kit exclusion flags do work and they are unused in the vanilla game. Of course, it's just like using the unused cleric item usability bits: there are only three, so any use of them creates some serious inter-mod compatibility issues. In Might & Guile, I set all bards to use the Skald usability flag, and then set a bunch of Necromancy/Conjuration/Evocation spells to exclude Skalds. I don't think anyone is doing this with the Blade or Jester flags, so you could maybe appropriate one of those... but remember, the way you apply this to your kit is to use that exclusion flag, which means it will apply to items as well. (I don't think the game has any items excluded from Jesters or Blades, but I'm not totally sure, and I don't know about mods.)

    tl;dr: Excluding spells from being learned from scrolls is not an easy task.

    GrammarsaladRaduziel
  • GrammarsaladGrammarsalad Member Posts: 2,465
    edited February 12
    Raduziel wrote: »
    I have a general modding question.

    I want to reproduce for a kit the specialist wizard save penalty. I know the damn thing is hardcoded.

    So what's the workaround and how do I do it:

    1) patch the kit somehow

    2) patch every spell of a specific school somehow

    Don't know if this is helpful - it's not the simplest code - but I patched all spells of each school adding extra headers with special capabilities for specialists of schools that match the spell. This is for Tome & Blood's "spontaneous specialist casting" component. The code is here, from lines 119 through 167:
    https://github.com/subtledoctor/TomeAndBlood/blob/master/TomeAndBlood/comp/setup_specialists.tpa
    I would patch every spell of the relevant school (that targets a creature, etc) with a 326 effect that targets the caster (i.e. 'self'). This will cast the resource based on caster rather than target attributes, but it casts the spell at the original target.

    Looking at iesdp, it looks like you cannot use kit.ids--bummer--so you will need to use a custom spell state applied in the clab.

    Wait, why not? You can append a line to SPLPROT.2DA that checks for a match to entries in KIT.IDS, and point the 326 effect there. No need for a spellstate. Here's what I do:
    ADD_KIT ~D5_BARD~
    [yadda yadda yadda]
    
    COPY_EXISTING ~kit.ids~ ~override~
      COUNT_2DA_COLS cols 
      READ_2DA_ENTRIES_NOW rows cols 
      FOR (row = 1; row < rows; ++row) BEGIN 
        READ_2DA_ENTRY_FORMER rows row 1 ~kit~ 
        PATCH_IF ~%kit%~ STRING_EQUAL_CASE ~D5_BARD~ BEGIN
          SET bard_row = %row%
          READ_2DA_ENTRY_FORMER rows bard_row 0 nu_bard_code
        END
      END
    BUT_ONLY
    
    APPEND ~splprot.2da~ ~D5_KIT_IS%TAB%152%TAB%-1%TAB%1~
    
    COPY_EXISTING ~splprot.2da~ ~override~
      COUNT_2DA_COLS cols
      READ_2DA_ENTRIES_NOW rows cols
      FOR (row = 1; row < rows; ++row) BEGIN
        READ_2DA_ENTRY_FORMER rows row 0 ~stat~
        PATCH_IF ~%stat%~ STRING_EQUAL_CASE ~D5_KIT_IS~ BEGIN
          SET kit_is_row = %row%
        END
      END
    BUT_ONLY
    
    COPY ~might_and_guile/lib/d5_base.spl~ ~override/d5bsong.spl~
      LPF ADD_SPELL_EFFECT INT_VAR insert_point = 0 opcode = 326 target = 2 parameter1 = %nu_bard_code% parameter2 = %kit_is_row% timing = 1 STR_VAR resource = ~d5bd01~ END
    
    Raduziel wrote: »
    I want to completely ban a school of magic from a wizard kit. The easy way to do so is to ban the scrolls (no scroll = no spell added. I think.), the problem are the spells picked at char gen

    It's worse than that. Even if a scroll is unusable - i.e. unequippable - by your kit, you can still have the scroll in your inventory and then you can right-click and learn the spell. The availability of the spell is determined solely by the exclusion flags in 0x1e-0x21 of the .SPL file. We don't have nice things like opcode 180/181/319 to customize it, the way we can with items.

    And, last I heard, not all of those exclusion flags actually work. And they are not all documented - the IESDP says
    bit 15 - 29: Unused
    

    And Near Infinity shows those as being "unknown" (bits 15-22, 29) or representing races (bits 23-28) But actually, some of those correspond with spellcasting kits from the cleric/druid/bard classes. And the bard kit exclusion flags do work and they are unused in the vanilla game. Of course, it's just like using the unused cleric item usability bits: there are only three, so any use of them creates some serious inter-mod compatibility issues. In Might & Guile, I set all bards to use the Skald usability flag, and then set a bunch of Necromancy/Conjuration/Evocation spells to exclude Skalds. I don't think anyone is doing this with the Blade or Jester flags, so you could maybe appropriate one of those... but remember, the way you apply this to your kit is to use that exclusion flag, which means it will apply to items as well. (I don't think the game has any items excluded from Jesters or Blades, but I'm not totally sure, and I don't know about mods.)

    tl;dr: Excluding spells from being learned from scrolls is not an easy task.

    Oh, you can reference kit.ids?!? I didn't see it in iesdp, but there it is. This is a much easier way to do it.

    Just fyi, I'm pretty sure this works if you want to add and use spell state:

    //add as a function (or just before you do the COPY_X) Note, I'm doing COPY_EXISTING, but for something like this you need to do some kind of COPY_EXISTING_REGEXP GLOB .
    DEFINE_ACTION_FUNCTION ADD_SPLSTATE STR_VAR label = ~~ RET new_ids BEGIN
    OUTER_SET new_ids = ~-1~
    ACTION_IF FILE_CONTAINS_EVALUATED (~SPLSTATE.IDS~ ~^.+[ %TAB%]%label%\b~) BEGIN
    COPY_EXISTING ~SPLSTATE.IDS~ override
    COUNT_2DA_ROWS 2 rows
    FOR (i = 0; i < rows; ++i) BEGIN
    READ_2DA_ENTRY i 1 2 state_label
    PATCH_IF ~%state_label%~ STRING_EQUAL_CASE ~%label%~ BEGIN
    READ_2DA_ENTRY i 0 2 state_id
    SET new_ids = state_id
    END
    END
    BUT_ONLY
    END ELSE BEGIN
    OUTER_FOR (i = 0; i < 256; ++i) BEGIN
    OUTER_SET $occupied_spell_state(~%i%~) = 0
    END
    ACTION_IF (~%label%~ STRING_EQUAL ~~) BEGIN FAIL ~Missing Spell State label~ END ELSE BEGIN
    ACTION_IF ((~%label%~ STRING_CONTAINS_REGEXP ~ ~) = 0) BEGIN FAIL ~Spell State lable cannot have spaces~ END ELSE BEGIN
    COPY_EXISTING ~SPLSTATE.IDS~ override
    COUNT_2DA_ROWS 2 rows
    FOR (i = 0; i < rows; ++i) BEGIN
    READ_2DA_ENTRY i 0 2 state_id
    SET $occupied_spell_state(~%state_id%~) = 1
    END
    FOR (i = 0; i < 256; ++i) BEGIN
    PATCH_IF $occupied_spell_state(~%i%~) = 0 BEGIN
    SET new_ids = i
    SET i = 256
    PATCH_IF new_ids <= rows BEGIN
    INSERT_2DA_ROW new_ids 2 ~%new_ids% %label%~
    END ELSE BEGIN
    INSERT_2DA_ROW new_ids 2 ~%new_ids% %label%~
    END
    END
    END
    PATCH_IF (new_ids = ~-1~) BEGIN PATCH_FAIL ~No available Spell States~ END
    BUT_ONLY
    END
    END
    END
    END
    
    COPY_EXISTING ~SPWI101.spl~ ~override~  
      LPF CLONE_EFFECT INT_VAR match_opcode = 158 opcode = 326 target = 1 timing = 0 duration = 1 parameter1 = EVAL ~%new_ids%~  parameter2 = 0x112 savingthrow = 0 STR_VAR insert = ~first~ resource = EVAL ~TEST02~  END
    BUT_ONLY
    
    

    //The AP_Spell that will be in the clab will have a 328 effect, and be ALTERED like so
    
    COPY ~splpath/spl.spl~ ~override~
      LPF ALTER_EFFECT INT_VAR match_opcode = 328 parameter2 = EVAL ~%new_ids%~ STR_VAR END
    
    
    

    You want to do this sparingly as there are only so many possible spellstates that can be added...

  • RaduzielRaduziel Member Posts: 4,458
    @kjeron It is not possible to use the exclusion flag thing in IWD or it will cancel two schools? I don't mind excluding two, as I want to reproduce a specialist mage anyway

  • kjeronkjeron Member Posts: 1,965
    Raduziel wrote: »
    @kjeron It is not possible to use the exclusion flag thing in IWD or it will cancel two schools? I don't mind excluding two, as I want to reproduce a specialist mage anyway
    It works, it just blocks the two schools instead of one, because those specialists are barred from two schools in IWD.

  • GrammarsaladGrammarsalad Member Posts: 2,465
    edited February 12
    kjeron wrote: »
    Raduziel wrote: »
    @kjeron It is not possible to use the exclusion flag thing in IWD or it will cancel two schools? I don't mind excluding two, as I want to reproduce a specialist mage anyway
    It works, it just blocks the two schools instead of one, because those specialists are barred from two schools in IWD.

    Yeah, the only way to change this would be to change which schools exclude which specialist.

    IIRC, you can combine two exclusion flags in BGEE by assigning a usabiity flag that combines two specialists (by literally adding the hex values in a hex calculator and assigning that value to your kit):

    https://www.calculator.net/hex-calculator.html

    i.e. so you exclude the same schools in all engines

  • subtledoctorsubtledoctor Member Posts: 11,136
    kjeron wrote: »
    Raduziel wrote: »
    I want to completely ban a school of magic from a wizard kit. The easy way to do so is to ban the scrolls (no scroll = no spell added. I think.), the problem are the spells picked at char gen
    For BG: The kits unusability flags - add the value used by the specialist that is banned from that schoool.

    Yes but this will only work as long as the player doesn't mess with the vanilla opposition schools. If a mod does something crazy like all specialists to cast spells from all schools (*ahem*) then this kit won't have any restrictions.

    If the idea is "this kit can cast whatever spells Evokers can cast" then that's fine. But if the idea is more independent - like "this kit cannot cast spells from the schools of Enchantment, Divination, or Alteration" - then hijacking an unused exclusion flag would be more reliable.

  • RaduzielRaduziel Member Posts: 4,458
    Thanks to everyone involved, I love each and every one of you guys and girls.

    I'm about to reach the part where I'll put everything discussed here for testing but before a maybe dumb question:

    What's the timing that I need to use to make an effect permanent until rest? 1?

Sign In or Register to comment.