CamDawg Posted August 30, 2018 Author Share Posted August 30, 2018 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. Quote Link to comment
subtledoctor Posted August 31, 2018 Share Posted August 31, 2018 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). Quote Link to comment
subtledoctor Posted August 31, 2018 Share Posted August 31, 2018 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... Quote Link to comment
DavidW Posted August 31, 2018 Share Posted August 31, 2018 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). Quote Link to comment
subtledoctor Posted September 1, 2018 Share Posted September 1, 2018 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. Quote Link to comment
DavidW Posted September 1, 2018 Share Posted September 1, 2018 (edited) 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 September 1, 2018 by DavidW Quote Link to comment
subtledoctor Posted September 1, 2018 Share Posted September 1, 2018 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. Quote Link to comment
DavidW Posted September 16, 2018 Share Posted September 16, 2018 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 Quote Link to comment
Jarno Mikkola Posted September 16, 2018 Share Posted September 16, 2018 (edited) Not exactly a function, but this is a tool I use for debugging BCS scripts that I thoughtYou 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 September 16, 2018 by Jarno Mikkola Quote Link to comment
DavidW Posted September 16, 2018 Share Posted September 16, 2018 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. Quote Link to comment
Jarno Mikkola Posted September 16, 2018 Share Posted September 16, 2018 (edited) 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 September 16, 2018 by Jarno Mikkola Quote Link to comment
DavidW Posted September 16, 2018 Share Posted September 16, 2018 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. Quote Link to comment
Jarno Mikkola Posted September 20, 2018 Share Posted September 20, 2018 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. Quote Link to comment
DavidW Posted September 20, 2018 Share Posted September 20, 2018 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. Quote Link to comment
Luke Posted January 8, 2019 Share Posted January 8, 2019 (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 January 8, 2019 by Luke Quote Link to comment
Recommended Posts
Join the conversation
You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.