Jump to content

A family of BCS-editing functions


Recommended Posts

I've been irritated for a while by how difficult it is to do fine-grained editing of existing BCS files. There are no very good options:

- REPLACE_BCS_BLOCK is brittle, breaks easily, and only allows for wholesale replacement

- Search-and-replace is insensitive to the file structure and often too crude

- SSL is fine for writing complex scripts from scratch, but no good for editing existing scripts.

This collection of five functions is an attempt to solve that problem. I'll describe them one at a time in the thread below. The library is alter_script.tpa, and can be found here in the current SCS repo.

Link to comment

DELETE_SCRIPT_BLOCK (INT_VAR only_once (default=0), STR_VAR script, match, match1, match2, match3, match4, match5)

Set 'script' to the script you want to edit. Set 'match' to some string that appears only in the blocks you want to delete, and all blocks containing that string will be deleted. (Set only_once to 1 and only the first block will be deleted.) If you want finer-grained identification, set any of match1-match5 to some string; the only blocks deleted will be those that match all strings that you set.

Example: VAMPANO.bcs contains a rudimentary use of vampire Domination, which it's convenient to remove on SCS.

LAF DELETE_SCRIPT_BLOCK STR_VAR script=vampano match=VAMPIRE_DOMINATION END

Link to comment

ALTER_SCRIPT_BLOCK (INT_VAR only_once, STR_VAR match,match1-match5, swap_out, swap_in, swap_out1-swap_in5, swap_in1-swap_in5)

Blocks are matched as in DELETE_SCRIPT_BLOCK. Then swap_out is replaced with swap_in (and swap_out1 with swap_in1, etc) in any block that's matched.

Example: the EE summons AI script bdsum00 has a bug that causes it to stutter whenever its target goes invisible, because its attack blocks don't contain a See(LastSeenBy(Myself)) check. 

LAF ALTER_SCRIPT_BLOCK STR_VAR script=bdsum00 match="AttackOneRound" swap_out="THEN" swap_in="See(LastSeenBy(Myself)) THEN" END

Link to comment

INSERT_SCRIPT_BLOCK (INT_VAR insert_above (default=0), only_once, STR_VAR script match, match1-match5, insert)

'insert' needs to be a path to a BAF file. Blocks are matched as in DELETE_SCRIPT_BLOCK. The BAF code in 'insert' is then inserted below any block that matches. (Set insert_above=1 to have it inserted above instead.)

Example: Suppose (recapitulating Ascension) that you want to add a 'reinforcements' block to the area script of Gromnir's throne room, to appear above the block that grants XP. 

<<<<<<<< .../ascension-inline/gromnir_insert.baf
[the script]
>>>>>>>>

   LAF INSERT_SCRIPT_BLOCK
     INT_VAR insert_above=1
     STR_VAR script=ar5002
            match=~SetGlobal("AddXP","AR5002",1)~
            insert=".../ascension-inline/gromnir_insert.baf"
   END

Link to comment

REPLACE_SCRIPT_BLOCK (INT_VAR only_once, STR_VAR script, match, match1-match5, insert)

'insert' needs to be a path to a BAF file. Blocks are matched as in DELETE_SCRIPT_BLOCK. The BAF code in 'insert' then replaces any matched blocks.

 

Link to comment

CLONE_SCRIPT_BLOCK (INT_VAR only_once, insert_above, STR_VAR script, match, match1-match5, swap_in, swap_in1-swap_in5, swap_out, swap_out1-swap_out5, original_swap_in, original_swap_in1-original_swap_in5, original_swap_out, original_swap_out1-original_swap_out5)

Blocks are matched as in DELETE_SCRIPT_BLOCK. Matched blocks are copied, then text swaps are carried out on the new block as per ALTER_SCRIPT_BLOCK, and on the old block as per ALTER_SCRIPT_BLOCK but using original_swap_in and original_swap_out.

Example (again, recapitulating Ascension): suppose you want to alter the epilogues so that Sarevok gets different epilogues depending on his alignment. 

   LAF CLONE_SCRIPT_BLOCK
      STR_VAR script=ar6200
              match=~"sarevnd"~
              swap_out=~Global("SarevokBio","GLOBAL",0)~
              swap_in=~Alignment("Sarevok",MASK_EVIL)Global("SarevokBio","GLOBAL",0)~
              swap_out1=~"sarevnd"~
              swap_in1=~"sarevnd2"~
              original_swap_out=~Global("SarevokBio","GLOBAL",0)~
              original_swap_in=~!Alignment("Sarevok",MASK_EVIL)Global("SarevokBio","GLOBAL",0)~
   END

Link to comment

For advanced users: you can also do functional matching and patching.

- All these functions take an additional STR_VAR argument, 'match_function'. Set this to the name of a PATCH_FUNCTION that operates on the decompiled block as if it were a text file, and returns 'value'. A match is found if value=1 (and if all conventional 'match' variables also match).

- ALTER_SCRIPT_BLOCK takes an additional STR_VAR argument, 'functionpatch'. Set this to the name of a PATCH_FUNCTION which operates on the decompiled contents of any matched block as if it were a text file.

- CLONE_SCRIPT_BLOCK takes two additional STR_VAR arguments, 'functionpatch' and 'patch_original_function', which work as for ALTER_SCRIPT_BLOCK applied to the new and old blocks respectively.

Link to comment

Do you know why INSERT_SCRIPT_BLOCK fails to correctly insert the following script block?

Spoiler

IF
	AttackedBy([ANYONE],DEFAULT)
	Allegiance(Myself,NEUTRAL)
	OR(2)
		SpellCastOnMeRES("",[ANYONE])
		SpellCastOnMe([ANYONE],0)
THEN
	RESPONSE #100
		Enemy()
END

 

Your function inserts it as

Spoiler

IF
	AttackedBy([ANYONE],DEFAULT)
	Allegiance(Myself,NEUTRAL)
	OR(2)
		SpellCastOnMe([ANYONE],0)	// Where is the RES version?
		SpellCastOnMe([ANYONE],0)
THEN
	RESPONSE #100
		Enemy()
END

 

 

Link to comment
8 minutes ago, DavidW said:

I'm pretty sure SpellCastOnMeRES("",[ANYONE]) and SpellCastOnMe([ANYONE],0) compile to the same BCS code, so they're just notational variants of each other. Try compiling and decompiling your code and see what you get.

Yeah, I obtain the same result with a simple COMPILE..... And it decompiles into two SpellCastOnMe([ANYONE],0)...

Anyway, are those two triggers really equivalent? I mean, I expect the non-RES version to trigger only with spells listed in SPELL.ids... Am I right?

Link to comment

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.

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...