Jump to content
CamDawg

Toss your semi-useful WeiDU macros here

Recommended Posts

 

Based on the discussion over yonder about cloning spells, I used a new function when updating Sword and Fist. This will clone a spell, updating any opcodes in both the original and clone that self-reference as appropriate. It can optionally also convert the newly cloned spell to an innate spell, finally ending the need for this very old, very outdated bit of code from the mists of time*.

 

Since it can potentially need to update the source spell, it's an action function, not a patch function. Usage is simple, just provide a source and destination string and (if desired) set the make_innate variable to 1 (default is zero), e.g. here's a whole mess of spells being converted to innates for the Hexblade kit:

There's one more issue that wasn't mentioned:

Every other spell/item needs opcodes 321/206/318 of the original spell cloned for the new spell.

i.e. Remove Fear applies opcode 321 for the horror spell. Any duplicates of the Horror spell would need removal duplicated on every type of Remove/Resist Fear spell.

It think it would be more efficient to store all such changes in an array for later, then patch them all at once in a single COPY_EXISTING_REGEXP.

 

Also, 7eyes should check every entry, not just the defaults for the Seven Eyes spell.

 

Yeah, Galc and I chatted about this. I didn't want to have a full cre/itm/eff/spl regexp every time the function got invoked as it would just crush install time. We (modders collectively) would be better served just creating/updating a 2da with all of the clones, that other modders could read and adjust as appropriate and run the occasional regexp copy against.

Share this post


Link to post

I savagely mutilated some function (CLONE_EFFECT I think) to create a monster function that patches 206/318/321/324 effects... it's over here:

https://github.com/UnearthedArcana/Faiths_and_Powers/blob/master/faiths_and_powers/lib/spell_clone_effects.tpa

 

It ain't pretty. I did get the install time from ~90 minutes to ~2 minutes which is at least bearable... but still not great.

 

I ended up changing the clones that I was applying it to use 146/148 instead of being real clones, so I'm not actually using the function anymore (for which reason, no guarantees as to its reliability).

Share this post


Link to post

I didn't want to have a full cre/itm/eff/spl regexp every time the function got invoked as it would just crush install time. We (modders collectively) would be better served just creating/updating a 2da with all of the clones, that other modders could read and adjust as appropriate and run the occasional regexp copy against.

 

Inccidentally this is an excellent idea. I've been doing this with a few things lately - e.g. creating a table of arcane spells and the scrolls from which to learn them. It could also be useful for armor file -> armor type -> enchantment, since armor category and enchantment are not coded into .ITM files. Sky's the limit, really, and .2da files are easy to parse and involve basically zero overhead. It might be worth formalizing some drop-in code or function that modders can use to generate, or append to if pre-existing, arbitrary tables matching X files with Y characteristics...

Share this post


Link to post

 

I didn't want to have a full cre/itm/eff/spl regexp every time the function got invoked as it would just crush install time. We (modders collectively) would be better served just creating/updating a 2da with all of the clones, that other modders could read and adjust as appropriate and run the occasional regexp copy against.

 

Inccidentally this is an excellent idea. I've been doing this with a few things lately - e.g. creating a table of arcane spells and the scrolls from which to learn them. It could also be useful for armor file -> armor type -> enchantment, since armor category and enchantment are not coded into .ITM files. Sky's the limit, really, and .2da files are easy to parse and involve basically zero overhead. It might be worth formalizing some drop-in code or function that modders can use to generate, or append to if pre-existing, arbitrary tables matching X files with Y characteristics...

 

SCS does a lot of this automatically - for any spell I set a variable WIZARD_[sPELL] equal to the .spl file, and (if it exists) a variable WIZARD_[sPELL]_SCROLL equal to the scroll file.

 

The code is in stratagems/sfo/general/lib_macro.tpa, and you're welcome to borrow it, but I'm not sure how cleanly it lifts out from the rest of SCS's function environment (that's the usual reason I don't proactively donate functions and macros to this thread).

Share this post


Link to post

The appeal is more to the general case: formalize a method to 1) create a 2da file if it doesn't already exist, with a list of some files with some characteristics; or 2) if the 2da file already exists, append the desired information to it unless the information is already there.

 

Another example: gaze attacks. What if you want to make an item give immunity to Gaze attacks, or an extra saving throw or something... you could generate a list of .itm and .spl files to be considered.

 

Another possibility: how about a list of outer-planar creatures? Then mods that add such creatures could append them to the 2da file, and other mods that want to target "all outer-planar creatures" with some effect would be able to work from a complete list.

Share this post


Link to post

The appeal is more to the general case: formalize a method to 1) create a 2da file if it doesn't already exist, with a list of some files with some characteristics; or 2) if the 2da file already exists, append the desired information to it unless the information is already there.

 

On a technical level: this is the SCS method for doing things like that (minus a little bit of bespoke stuff)

 
<<<<<<<< …/stratagems-inline/blank
>>>>>>>>
 
DEFINE_ACTION_FUNCTION log_this
        STR_VAR file=""
                input=""
                repeat="yes"
BEGIN
        ACTION_IF !FILE_EXISTS ~%file%~ BEGIN
           COPY ~.../stratagems-inline/blank~ ~%file%~
        END
        ACTION_IF (~%repeat%~ STRING_COMPARE_CASE ~no~) || !FILE_CONTAINS_EVALUATED ("%file%" "%input%\($\|%WNL%\|%MNL%\|%LNL\)")BEGIN
           APPEND_OUTER ~%file%~ ~%input%~
        END
END

Then do

LAF log_this STR_VAR file="override/outerplanar.mrk" input="DEMGLAB 50 77 12" repeat=no END

to store "DEMGLAB 50 77 12" in override/outerplanar.mrk if it's not there already.

 

 

But on a conceptual level: I don't really trust the mod environment I'm installing into enough to assume that I can get my data from some 2da rather than collecting it myself...

Edited by DavidW

Share this post


Link to post

But on a conceptual level: I don't really trust the mod environment I'm installing into enough to assume that I can get my data from some 2da rather than collecting it myself...

You don't have to trust the environment. Each modder can generate their own full list when their mod is installed; overlap is okay. So if six mods all do this with six different lists of planar creatures, the result will be additive and the final list will contain all of them. So, if some NPC mod very early in the install order adds some custom fiends, and the modder wants to enable SCS or aTweaks or whatever to identify it as planar way later on, that would be possible. It would only take a bit of inter-mod coordination as far as the names and structures of the .2da files. (Which would pretty easily be managed in a forum thread.)

 

Of course there is still danger of false positives; an earlier modder could get something wrong, or apply different logic ("I consider basilisks to be planar monsters"). But IMHO the danger of that is low, and most of the inconsistencies players face is of the opposite type.

Share this post


Link to post

Not exactly a function, but this is a tool I use for debugging BCS scripts that I thought I'd put here in case anyone else wants it. Install it on a script and you get text telling you when each block in the BCS script fires. It's useful for long complicated combat scripts when I'm debugging/testing SCS.

 

It's just a micro-mod; set it up as usual, install component 0, and enter the name of the script you want to mark up at the command prompt. I generally haven't needed the ability to do multiple scripts simultaneously but it would be trivial to add.

 

BACKUP "stratagems_external/backup/dwlabel"
AUTHOR "DavidW"
AUTO_EVAL_STRINGS

BEGIN "Label script" DESIGNATED 0

PRINT "Enter script"
ACTION_READLN script
OUTER_SET block_count=1

COPY_EXISTING "%script%.bcs" "override"
  DECOMPILE_AND_PATCH BEGIN
    REPLACE_TEXTUALLY "RESPONSE #" "RESPONSE_#"
    READ_2DA_ENTRIES_NOW script_table 1
    FOR (i=0;i<script_table;i+=1) BEGIN
          READ_2DA_ENTRY_FORMER script_table i 0 entry
          SPRINT $output("%row_out%") "%entry%"
          PATCH_MATCH "%entry%" WITH
            "IF" BEGIN
               SET block_count +=1
               SET block_minor_count = 1
            END
            "RESPONSE.*" BEGIN
               SET line= RESOLVE_STR_REF("%script% Block %block_count%_%block_minor_count% firing")
               SET_2DA_ENTRY_LATER script_out i 0 "%entry%####DisplayString(Myself,%line%)"
               SET block_minor_count +=1
            END
            DEFAULT
            END
    END
    SET_2DA_ENTRIES_NOW script_out 0
    REPLACE_TEXTUALLY "RESPONSE_#" "RESPONSE #"
    REPLACE_TEXTUALLY "####" " "
  END
BUT_ONLY

Share this post


Link to post

Not exactly a function, but this is a tool I use for debugging BCS scripts that I thought

You know, there's also the LStest tool that I coded on bases of the_biggs work. It's more intrusive yes, as it break the in game scenematics... but seroiusly, during debugging who gives a darn about those ... unless it's the in game scinematic it self that has the bugs:

BACKUP ~LStest/backup~
AUTHOR ~Jarno Mikkola~

BEGIN ~With the G3'BGII Fixpack, this will do all the scripts.~
SUBCOMPONENT ~Test general causes of slowdown from the game scripts, v2.~ 
DESIGNATED 1

COPY_EXISTING_REGEXP ~.*\.bcs$~ ~override~ 
    SET x = 0 - 1
    DECOMPILE_BCS_TO_BAF 
        REPLACE_EVALUATE ~\(RESPONSE #[0-9]+\)~ BEGIN
                        x += 1
                END ~~~~~\1
        ActionOverride(Player1,DisplayString(Myself,~Running block %x% of %SOURCE_RES%.BCS~))~~~~~
  COMPILE_BAF_TO_BCS
BUT_ONLY

BEGIN ~Without the G3'BGII Fixpack, this will skip 11 scripts.~
SUBCOMPONENT ~Test general causes of slowdown from the game scripts, v2.~ 
DESIGNATED 2

//skipping the 11 originally broken scripts
COPY_EXISTING_REGEXP GLOB ~.*\.bcs$~ ~override~ 
  PATCH_IF NOT (~%SOURCE_RES%~ STRING_EQUAL_CASE ~RDOG~ OR
                ~%SOURCE_RES%~ STRING_EQUAL_CASE ~RDWARF~ OR
                ~%SOURCE_RES%~ STRING_EQUAL_CASE ~RETTER~ OR
                ~%SOURCE_RES%~ STRING_EQUAL_CASE ~RGIBBLER~ OR
                ~%SOURCE_RES%~ STRING_EQUAL_CASE ~RHALFLIN~ OR
                ~%SOURCE_RES%~ STRING_EQUAL_CASE ~RHOBGOBA~ OR
                ~%SOURCE_RES%~ STRING_EQUAL_CASE ~RHOBGOBF~ OR
                ~%SOURCE_RES%~ STRING_EQUAL_CASE ~RKOBOLD~ OR
                ~%SOURCE_RES%~ STRING_EQUAL_CASE ~ROGRE~ OR
                ~%SOURCE_RES%~ STRING_EQUAL_CASE ~RSIREN~ OR
                ~%SOURCE_RES%~ STRING_EQUAL_CASE ~RSIRINE~) THEN BEGIN
    SET x = 0 - 1
    DECOMPILE_BCS_TO_BAF 
        REPLACE_EVALUATE ~\(RESPONSE #[0-9]+\)~ BEGIN
                        x += 1
                END ~~~~~\1
        ActionOverride(Player1,DisplayString(Myself,~Running block %x% of %SOURCE_RES%.BCS~))~~~~~
  COMPILE_BAF_TO_BCS
END
BUT_ONLY
Yeah, and it still used the DECOMPILE --- RECOMPILE trick no one should be using any longer... but this is from 2010. Edited by Jarno Mikkola

Share this post


Link to post

LSTest is very nice but has a slightly different use case - if you don't know which scripts are causing trouble, for instance. It's not really practical for debugging / optimizing of a single complicated script, because it takes too long to reinstall.

Share this post


Link to post

It's not really practical for debugging/optimizing of a single complicated script, because it takes too long to reinstall.

A reinstall usually, in that case, is NOT optimal anyways. As you can do this using the already modified file, by altering it and recompiling it within Near Infinity. To then retest it. From a save without locked in .cre's etc. Which generally just needs to be saved before you move to the area ...

You of course have to then alter the mods source .baf, or what ever your mod uses to make the mod to reflect the changes made into .bcs... but that's about ones mod setup, not tool usage. But I can take your point in cases where the mod extends multiple .bcs files with the same logic and is then detected this way with a specific creature.

And if memory serves, we have gone through this discussion before. So there should be nothing surprising here.

Edited by Jarno Mikkola

Share this post


Link to post

 

It's not really practical for debugging/optimizing of a single complicated script, because it takes too long to reinstall.

A reinstall usually, in that case, is NOT optimal anyways. As you can do this using the already modified file, by alter it and recompiling it within Near Infinity.

 

Not if it's an SSL script! (I take your point: if it's not SSL then you probably won't be reinstalling. Although if you add new blocks it's a problem.)

And if memory serves, we have gone through this discussion before. So there should be nothing surprising here.

Not that I remember, actually.

Share this post


Link to post

Although if you add new blocks it's a problem.

To a debug game ?

You are obviously doing something horrific at that point. To yourself.

 

Yeah, I can understand if you build the .baf's from .ssl's, you might not make them into a .bcs'es before they need this kind of tweaking after which the .bcs'es are compiled.

By the way, it's funny how different the code between our mod, while it does almost the same thing. ... although, what happens to your code if the script has a three "alternative" outcomes:

IF

Detect([PC])

OR(3)

See("aewere4") // Fighter

See("aewere5") // Fighter

See("aewere6") // Fighter

THEN

RESPONSE #33

AttackReevaluate("aewere4",15) // Fighter

RESPONSE #33

AttackReevaluate("aewere5",15) // Fighter

RESPONSE #33

AttackReevaluate("aewere6",15) // Fighter

END

 

I ask, cause if I am reading yours correctly, it starts after the IF, while mine responds to the "RESPONSE #" ... and how manyeth response it is, is displayed at the dialog box, via the x.

All this without the need to replace textually the "RESPONSE #" by interim "RESPONSE_#" that gets reoverwritten back to the original form before the actual compilation.

Share this post


Link to post

 

Although if you add new blocks it's a problem.

To a debug game ?

You are obviously doing something horrific at that point. To yourself.

 

Not in SSL debugging. Adding or dropping a RequireBlock(xxx) or changing a targeting instruction can change the block structure.

 

And not in AI testing either, where you might want to rearrange the order of two chunks of code to see if it makes a difference to tactical efficacy.

Share this post


Link to post
Posted (edited)
On 6/29/2017 at 9:22 PM, Angel said:

replace_cre_script, find and replace a creature script

 

Written out of frustration when trying to give ankhegs and winter wolves different scripts for their special attacks and finding that almost every single version of the critters had it in a different slot.

 

 

  Reveal hidden contents

 



DEFINE_PATCH_FUNCTION replace_cre_script
  INT_VAR
  check_override    = 1
  check_class        = 1
  check_race        = 1
  check_general        = 1
  check_default        = 1
  STR_VAR
  old_script        = ""
  new_script        = ""
  RET
  found
BEGIN
  SET found = 0

  PATCH_IF check_override
  BEGIN
    READ_ASCII SCRIPT_OVERRIDE script

    PATCH_IF ("%script%" STRING_EQUAL_CASE "%old_script%")
    BEGIN
      WRITE_EVALUATED_ASCII SCRIPT_OVERRIDE "%new_script%"
      SET found = 1
    END
  END

  PATCH_IF check_class
  BEGIN
    READ_ASCII SCRIPT_CLASS script

    PATCH_IF ("%script%" STRING_EQUAL_CASE "%old_script%")
    BEGIN
      WRITE_EVALUATED_ASCII SCRIPT_CLASS "%new_script%"
      SET found = 1
    END
  END

  PATCH_IF check_race
  BEGIN
    READ_ASCII SCRIPT_RACE script

    PATCH_IF ("%script%" STRING_EQUAL_CASE "%old_script%")
    BEGIN
      WRITE_EVALUATED_ASCII SCRIPT_RACE "%new_script%"
      SET found = 1
    END
  END

  PATCH_IF check_general
  BEGIN
    READ_ASCII SCRIPT_GENERAL script

    PATCH_IF ("%script%" STRING_EQUAL_CASE "%old_script%")
    BEGIN
      WRITE_EVALUATED_ASCII SCRIPT_GENERAL "%new_script%"
      SET found = 1
    END
  END

  PATCH_IF check_default
  BEGIN
    READ_ASCII SCRIPT_DEFAULT script

    PATCH_IF ("%script%" STRING_EQUAL_CASE "%old_script%")
    BEGIN
      WRITE_EVALUATED_ASCII SCRIPT_DEFAULT "%new_script%"
      SET found = 1
    END
  END
END

 

 

Could you provide an example usage of this function? Can I use it to give all CREs that use, say, MAGE7.bcs my custom script? I guess I first need to COMPILE my custom script, right? Moreover, can I use the same name for %old_script% and %new_script%?

 

Oh, wait, I guess that a simple COMPILE instruction is everything I need (i.e., adding a couple of triggers to some existing scripts, overwriting them and keeping their original name).

Edited by Luke

Share this post


Link to post
Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...