Author Topic: FUNCTION use & variables  (Read 4969 times)

Offline plainab

  • Sasha al'Therin
  • Planewalker
  • *****
  • Posts: 491
    • Infinity Engine Modding
FUNCTION use & variables
« on: June 09, 2009, 07:31:01 PM »
Here's my situation...

I've got a PATCH_FUNCTION.  I have variables with default values defined via INT_VAR and STR_VAR. For a single use, everything works fine.  If I should use the same function a second time, I run into an issue with the variables.  Because it is a FUNCTION and not a MACRO, I only set what I know I need to.  When another use of the function doesn't require me to set a given variable that I set in a previous component, the value from the previous component is used rather than the default built into the function.

I understand that it is behaving as it should, but I had hoped that since I called the FUNCTION definition separately in each component that the variables from the previous use would be forgotten. The advantage to using FUNCTION is that I can define variables with default values so the user doesn't have to set every variable that gets written. But with multiple uses of the same function and with different variables being written potentially each time, there will come a point when being a function gives no benefit as all variables will need to be set by the user to the default values if not needed.

What I'd like...

CLEAR_PATCH_FUNCTION_VAR and CLEAR_ACTION_FUNCTION_VAR //automatically forgets values for all variables listed under INT_VAR and STR_VAR within the named function

Usage would be

LAUNCH_PATCH_FUNCTION ~some_name~ END
CLEAR_PATCH_FUNCTION_VAR ~some_name~
My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altherin.webs.com

Offline GeN1e

  • Planewalker
  • *****
  • Posts: 267
  • Gender: Male
Re: FUNCTION use & variables
« Reply #1 on: June 09, 2009, 08:49:41 PM »
If I got it right, you need to make a use of RET part. Like this

Code: [Select]
DEFINE_ACTION_FUNCTION test INT_VAR a=2 b=3 RET c BEGIN
  OUTER_SET c = a + b
END

LAUNCH_ACTION_FUNCTION test INT_VAR a=12 END
PRINT ~c = %outer_c%~

LAUNCH_ACTION_FUNCTION test INT_VAR a=12 RET outer_c=c END
PRINT ~c = %outer_c%~
« Last Edit: June 09, 2009, 08:51:30 PM by GeN1e »

Offline Mike1072

  • Planewalker
  • *****
  • Posts: 298
  • Gender: Male
Re: FUNCTION use & variables
« Reply #2 on: June 10, 2009, 12:35:53 AM »
If I got it right, you need to make a use of RET part.
I think it's more an issue of ensuring the default values are used when you want them to be used.

If you're careful and give your parameters crazy prefixes, there's little chance someone's going to accidentally set "mi_name" to anything.  But, if your parameters are sensible things like "name", there's a good chance it'll get set once somewhere else [and never un-set], making the cases where you left it out of the function call end up with some random name you were using before instead of the default you were expecting.
« Last Edit: June 10, 2009, 12:38:30 AM by Mike1072 »

Offline plainab

  • Sasha al'Therin
  • Planewalker
  • *****
  • Posts: 491
    • Infinity Engine Modding
Re: FUNCTION use & variables
« Reply #3 on: June 10, 2009, 03:15:54 PM »
If I got it right, you need to make a use of RET part. Like this
Way off, Mike1072 was a little bit closer...
I think it's more an issue of ensuring the default values are used when you want them to be used.
Yes this part is correct...
Quote
If you're careful and give your parameters crazy prefixes, there's little chance someone's going to accidentally set "mi_name" to anything.  But, if your parameters are sensible things like "name", there's a good chance it'll get set once somewhere else [and never un-set], making the cases where you left it out of the function call end up with some random name you were using before instead of the default you were expecting.
However, this has no bearing in this case... 

Unless I make a separate function with unique variable names for each use, I will always have this problem. Why would I make four different functions that do the same thing just so I can use different variable names?

We need to be able to use the same function multiple times within the same mod and only set those values that are needed each time the function is used. The user should never have to set values for variables not needed when using a function.

Here is a specific example where you can see the problem that I was trying to explain:

The function is defined as follows:
Code: [Select]
DEFINE_PATCH_FUNCTION ~Milochs_ITM_G_Eff_Add~
INT_VAR
pc = 0-1 //Opcode
tg = 1 //Target
tm = 2 //Timing mode
dp = 0 //Dispellability
pw = 0 //Power
p1 = 0 //Parameter 1
p2 = 0 //Parameter 2
dr = 0 //Duration
b1 = 100 //Probability 1
b2 = 0 //Probability 2
dn = 0 //Dice number
ds = 0 //Dice size
st = 0 //Saving throw
sb = 0 //Save bonus
STR_VAR
rf = ~~ //ResRef
BEGIN
READ_LONG 0x64 hf //Header offset
READ_SHORT 0x68 hc //Header count
READ_LONG 0x6a fb //Feature block table offset
READ_SHORT 0x6e fs //Feature block offset
READ_SHORT 0x70 fc //Casting feature block count
INSERT_BYTES (0x30 * fc + fs + fb) 0x30
WRITE_SHORT (0x30 * fc + fs + fb) pc //Opcode
WRITE_BYTE (0x30 * fc + fs + fb + 2) tg //Target
WRITE_BYTE (0x30 * fc + fs + fb + 3) pw //Power
WRITE_LONG (0x30 * fc + fs + fb + 4) p1 //Parameter 1
WRITE_LONG (0x30 * fc + fs + fb + 8) p2 //Parameter 2
WRITE_BYTE (0x30 * fc + fs + fb + 0xc) tm //Timing mode
WRITE_BYTE (0x30 * fc + fs + fb + 0xd) dp //Dispellability
PATCH_IF (tm != 1) AND (tm != 2) AND (tm < 7) BEGIN
  WRITE_BYTE (0x30 * fc + fs + fb + 0xe) dr //Duration
END
WRITE_BYTE (0x30 * fc + fs + fb + 0x12) b1 //Probability 1
WRITE_BYTE (0x30 * fc + fs + fb + 0x13) b2 //Probability 2
WRITE_ASCIIE (0x30 * fc + fs + fb + 0x14) ~%rf%~ #8 //ResRef
WRITE_LONG (0x30 * fc + fs + fb + 0x1c) dn //Dice number
WRITE_LONG (0x30 * fc + fs + fb + 0x20) ds //Dice size
WRITE_LONG (0x30 * fc + fs + fb + 0x24) st //Saving throw
WRITE_LONG (0x30 * fc + fs + fb + 0x28) sb //Save bonus
fc += 1 //Update effects count
WRITE_SHORT 0x70 fc
FOR (i1 = 0; i1 < hc; i1 += 1) BEGIN //Update 1st effect indices
  READ_SHORT (hf + i1 * 0x38 + 0x20) fx //1st effect index
  PATCH_IF (fx > fs) BEGIN //If ability after eq effects
    WRITE_SHORT (hf + i1 * 0x38 + 0x20) (fx + 1) //Increase 1st effect index by 1
  END
END
END //end function define

The function is used as follows:
Component 1
Code: [Select]
INCLUDE ~bg_fixpack\tph\ab_function_list.tph~
COPY_EXISTING ~clck11.itm~ ~override~ // dudley itm but it does need fixed
 PATCH_IF (SOURCE_SIZE > 0x71) THEN BEGIN // protects against invalid files
  //variables from Milochs tpp file merged into my function_list
  SET pc = 29 //Opcode
  SET tg = 1 //Target
  SET tm = 2 //Timing mode
  SET p1 = 20 //Parameter 1
  SET b1 = 100 //Probability 1
  LAUNCH_PATCH_FUNCTION ~Milochs_ITM_G_Eff_Add~ END
 END
BUT_ONLY_IF_IT_CHANGES
Component 2
Code: [Select]
INCLUDE ~bg_fixpack\tph\ab_function_list.tph~
COPY_EXISTING ~ring23.itm~ ~override~
 PATCH_IF (SOURCE_SIZE > 0x71) THEN BEGIN // protects against invalid files
  SET pc = 142 //Opcode
  SET tg = 1 //Target
  SET tm = 2 //Timing mode
  SET p2 = 35 //Parameter 2
  SET b1 = 100 //Probability 1
  LAUNCH_PATCH_FUNCTION ~Milochs_ITM_G_Eff_Add~ END
 END
BUT_ONLY_IF_IT_CHANGES
Component 3
Code: [Select]
INCLUDE ~bg_fixpack\tph\ab_function_list.tph~
COPY_EXISTING ~sw2h06.itm~ ~override~
 PATCH_IF (SOURCE_SIZE > 0x71) THEN BEGIN // protects against invalid files
//add graphic: removal of slow icon
  SET pc = 169 //Opcode
  SET tg = 1 //Target
  SET tm = 2 //Timing mode
  SET p2 = 41 //Parameter 2
  SET b1 = 100 //Probability 1
  LAUNCH_PATCH_FUNCTION ~Milochs_ITM_G_Eff_Add~ END
//add graphic: removal of stun icon
  SET pc = 169 //Opcode
  SET tg = 1 //Target
  SET tm = 2 //Timing mode
  SET p2 = 55 //Parameter 2
  SET b1 = 100 //Probability 1
  LAUNCH_PATCH_FUNCTION ~Milochs_ITM_G_Eff_Add~ END
 END
BUT_ONLY_IF_IT_CHANGES
You will note that parameter 1 is needed in the first use, but not in any of the other uses.  However, since parameter 1 was defined in the first use it carries over and gets applied to ALL future uses within the same install session of the same mod.

I want something that will clear all variables as defined within INT_VAR and STR_VAR of the named function.  If the variables can not be cleared, can they at least be reset to the defined default value.

Yes, I could reset them myself, but that defeats the purpose of the function. Might as well use a macro and make the user set ALL the variables themselves...

My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altherin.webs.com

Offline GeN1e

  • Planewalker
  • *****
  • Posts: 267
  • Gender: Male
Re: FUNCTION use & variables
« Reply #4 on: June 10, 2009, 04:18:56 PM »
You can additionally INT_VAR and STR_VAR right before LAUNCHing. Try the example below
Code: [Select]
DEFINE_ACTION_FUNCTION test INT_VAR a=2 b=3 BEGIN
  OUTER_SET c = a + b
  PRINT ~c = %c%~
END

PRINT ~Step 1 - using INT_VAR
the result should 5+3=8~
LAUNCH_ACTION_FUNCTION test INT_VAR a=5 END
PRINT ~... it works~

PRINT ~Step 2 - trying to use the default value
the result should 2+3=5~
LAUNCH_ACTION_FUNCTION test END
PRINT ~... it works~

PRINT ~Step 3 - using a conventional SET
the result should 5+3=8~
OUTER_SET a=5
LAUNCH_ACTION_FUNCTION test END
PRINT ~... it works~

PRINT ~Step 4 - trying to use the default value after the SET was done
the result should 2+3=5~
LAUNCH_ACTION_FUNCTION test END
PRINT ~... it fails!~

PRINT ~Step 5 - using INT_VAR again to ignore the previous SET
the result should 15+3=18~
LAUNCH_ACTION_FUNCTION test INT_VAR a=15 END
PRINT ~... voila, it works!~
PS should be now as clear as possible.
« Last Edit: June 10, 2009, 04:27:22 PM by GeN1e »

Offline plainab

  • Sasha al'Therin
  • Planewalker
  • *****
  • Posts: 491
    • Infinity Engine Modding
Re: FUNCTION use & variables
« Reply #5 on: June 10, 2009, 05:00:37 PM »
I saw a working example from Mike1072 over at SHS...  I just gave it a try and it does indeed solve the problem...

One query though... How to best explain to possible users of the function that they need to set the variables inside the LAUNCH command?
My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altherin.webs.com

Offline GeN1e

  • Planewalker
  • *****
  • Posts: 267
  • Gender: Male
Re: FUNCTION use & variables
« Reply #6 on: June 10, 2009, 08:31:52 PM »
Quote
How to best explain to possible users of the function that they need to set the variables inside the LAUNCH command?
I guess it's the same as telling them to SET before launching a macro. Only now it's INT_VAR instead, and unlike SETs it lies within a command, making it even less confusing.

LAUNCH_PATCH_FUNCTION myfunction
INT_VAR
opcode=67
duration=180
STR_VAR
resource = ~dempitsu~
END



Offline GeN1e

  • Planewalker
  • *****
  • Posts: 267
  • Gender: Male
Re: FUNCTION use & variables
« Reply #7 on: July 12, 2009, 05:14:40 PM »
Code: [Select]
DEFINE_PATCH_FUNCTION
RET
function_var_0
function_var_1
function_var_2
... // 47 more lines
function_var_50
BEGIN DO_SMART_STUFF END

LAUNCH_ACTION_FUNCTION
RET
 var1=function_var_0
 var2=function_var_1
 var3=function_var_15
END
It works fine. However I'd prefer not having to specify 50 names in the RET part of definition, as it drastically increases the size of code. Can it be regexped into $function_var([0-50]) or the like (my regexp skill sucks)?

PS My problem is how to SAY inside of function the user-given string. Atm the best solution I could come up with was to use the RET to drag the correct offset outside of function and SAY after it's executed.
« Last Edit: July 12, 2009, 05:21:24 PM by GeN1e »

Offline plainab

  • Sasha al'Therin
  • Planewalker
  • *****
  • Posts: 491
    • Infinity Engine Modding
Re: FUNCTION use & variables
« Reply #8 on: July 12, 2009, 05:58:45 PM »
Another issue with using FUNCTIONS is when you have a group of files that you want to do the same or similar things to. If it were normal tp2 code we could use COPY_EXISTING with a 'laundry list' of files or ACTION_FOR_EACH (AFE) followed by the patch code with the AFE variable as the file to copy.  Should the patch code already be within an ACTION_FUNCTION it would make sense to apply it following the AFE.  However the variable from the AFE does not get evaluated if it is assigned to the functions variable.  Now it does work if the AFE variable happens to be the same name as the function variable, but then that would cause problems for future uses of the function.

To avoid this and use the function, each file has to get its own function launch.  Yes, if a patch function version was made it could be called up underneath the COPY_EXISTING whether it be with an AFE or a 'laundry list'

This doesn't work but I think it should
Code: [Select]
OUTER_SET foo = 300
ACTION_FOR_EACH file IN ~minsc.cre~ ~khalid.cre~ ~imoen.cre~ BEGIN
LAUNCH_ACTION_FUNCTION ~some_function~
INT_VAR
var_1 = 100
var_2 = 200
var_3 = %foo%
STR_VAR
str_1 = ~boo~
str_2 = ~%file%~
END

This does work but can and will cause problems for later uses of the same function
Code: [Select]
OUTER_SET var_3 = 300
ACTION_FOR_EACH str_2 IN ~minsc.cre~ ~khalid.cre~ ~imoen.cre~ BEGIN
LAUNCH_ACTION_FUNCTION ~some_function~
INT_VAR
var_1 = 100
var_2 = 200
//var_3 -- don't need to set this variable as it is set outside of the launch
STR_VAR
str_1 = ~boo~
//str_2 -- don't need to set this variable as it is set outside of the launch
END
My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altherin.webs.com

Offline Mike1072

  • Planewalker
  • *****
  • Posts: 298
  • Gender: Male
Re: FUNCTION use & variables
« Reply #9 on: July 12, 2009, 06:36:15 PM »
This doesn't work but I think it should
Code: [Select]
OUTER_SET foo = 300
ACTION_FOR_EACH file IN ~minsc.cre~ ~khalid.cre~ ~imoen.cre~ BEGIN
LAUNCH_ACTION_FUNCTION ~some_function~
INT_VAR
var_1 = 100
var_2 = 200
var_3 = %foo%
STR_VAR
str_1 = ~boo~
str_2 = ~%file%~
END

Don't ask why, but I think it would work if you used:
Code: [Select]
OUTER_SET foo = 300
ACTION_FOR_EACH file IN ~minsc.cre~ ~khalid.cre~ ~imoen.cre~ BEGIN
  LAUNCH_ACTION_FUNCTION ~some_function~
    INT_VAR
      var_1 = 100
      var_2 = 200
      var_3 = foo
    STR_VAR
      str_1 = ~boo~
      str_2 = EVALUATE_BUFFER ~%file%~
  END
END

Offline the bigg

  • The Avatar of Fighter / Thieves
  • Moderator
  • Planewalker
  • *****
  • Posts: 3804
  • Gender: Male
Re: FUNCTION use & variables
« Reply #10 on: July 12, 2009, 07:05:42 PM »
It works fine. However I'd prefer not having to specify 50 names in the RET part of definition, as it drastically increases the size of code. Can it be regexped into $function_var([0-50]) or the like (my regexp skill sucks)?
Passing arrays to/from functions is something that should go in, I agree.

Quote
PS My problem is how to SAY inside of function the user-given string. Atm the best solution I could come up with was to use the RET to drag the correct offset outside of function and SAY after it's executed.
I can't understand what you're saying (and, most importantly, what is failing). Plz provide code. BTW, I can't support @(1 + %foo%) natively, so don't ask.

Another issue with using FUNCTIONS is when you have a group of files that you want to do the same or similar things to. If it were normal tp2 code we could use COPY_EXISTING with a 'laundry list' of files or ACTION_FOR_EACH (AFE) followed by the patch code with the AFE variable as the file to copy.  Should the patch code already be within an ACTION_FUNCTION it would make sense to apply it following the AFE.  However the variable from the AFE does not get evaluated if it is assigned to the functions variable.  Now it does work if the AFE variable happens to be the same name as the function variable, but then that would cause problems for future uses of the function.
There's nothing in AFE that can make this fail specifically if using OUTER_SPRINT works. Likely it needs the EVALUATE_BUFFER like Mkie said. Yes, I know having to use EVALUATE_BUFFER sucks, but I can't change this without breaking existing mods - EVALUATE_BUFFER is the top thing that bugs me most about WeiDU and makes me wish I had the drive/time to do the fabled tp3.
Author or Co-Author: WeiDU (http://j.mp/bLtjOn) - Widescreen (http://j.mp/aKAiqG) - Generalized Biffing (http://j.mp/aVgw3U) - Refinements (http://j.mp/bLHoCc) - TB#Tweaks (http://j.mp/ba02Eg) - IWD2Tweaks (http://j.mp/98OFYY) - TB#Characters (http://j.mp/ak8J55) - Traify Tool (http://j.mp/g1Ry9A) - Some mods that I won't mention in public
Maintainer: Semi-Multi Clerics (http://j.mp/9UeIwB) - Nalia Mod (http://j.mp/dng9l0) - Nvidia Fix (http://j.mp/aRWjjg)
Code dumps: Detect custom secondary types (http://j.mp/hVzzXG) - Stutter Investigator (http://j.mp/gdtBn8)

If possible, send diffs, translations and other contributions using Git (http://j.mp/aBZFrq).

Offline plainab

  • Sasha al'Therin
  • Planewalker
  • *****
  • Posts: 491
    • Infinity Engine Modding
Re: FUNCTION use & variables
« Reply #11 on: July 12, 2009, 08:21:35 PM »
Quote
PS My problem is how to SAY inside of function the user-given string. Atm the best solution I could come up with was to use the RET to drag the correct offset outside of function and SAY after it's executed.
I can't understand what you're saying (and, most importantly, what is failing). Plz provide code. BTW, I can't support @(1 + %foo%) natively, so don't ask.
I think I know what he's talking about.  I might have first brought it up to him. Here is a FUNCTION that should use a SAY or SAY_EVALUATED to get the user's string into the game (I'll use a quote box so I can highlight):
Quote
////////////////////////////////////////////////////
DEFINE_ACTION_FUNCTION wapt_add_container
  INT_VAR
    wapt_object=1
    wapt_item=0
    wapt_bbox=0x38
  STR_VAR
    wapt_ob_type= ~Conta~
  BEGIN
COPY_EXISTING ~%wapt_area%.are~ ~override~
  PATCH_IF (VARIABLE_IS_SET wapt_num_new_Conta) BEGIN   //if user choose to add more than one container -- uses a more user friendly variable name
   wapt_object = %wapt_num_new_Conta%
  END
  PATCH_IF (VARIABLE_IS_SET wapt_num_new_Items) BEGIN   //if user choose to add one or more items to a container -- uses a more user friendly variable name
   wapt_item = %wapt_num_new_Items%
  END
  LAUNCH_PATCH_MACRO wapt_inserter
  FOR (i=1;i<wapt_object+1;i+=1) BEGIN
    LAUNCH_PATCH_MACRO wapt_routine
DEFINE_ARRAY field BEGIN use_point_x use_point_y type lock_diff flags trap_detect_diff trap_disarm_diff trap_trapped trap_detected trap_launch_x trap_launch_y script key_item string vertices END
DEFINE_ARRAY Off   BEGIN 0x20        0x22        0x24 0x26      0x28  0x2c             0x2e             0x30         0x32          0x34          0x36          0x48   0x78     0x84   0x54     END
DEFINE_ARRAY SoL   BEGIN 2           2           2    2         4     2                2                2            2             2             2             8      8        4      4        END
    FOR(i2=0;i2<15;i2+=1)BEGIN
     PATCH_IF ($SoL("%i2%")=2) AND (VARIABLE_IS_SET $wapt($field("%i2%")"%i%") ) BEGIN
      WRITE_SHORT (%new_loc%+ $Off("%i2%")) $wapt($field("%i2%")"%i%")
     END
     PATCH_IF ($SoL("%i2%")=4) AND (VARIABLE_IS_SET $wapt($field("%i2%")"%i%") ) BEGIN
      WRITE_LONG (%new_loc%+ $Off("%i2%")) $wapt($field("%i2%")"%i%")
     END
     PATCH_IF ($SoL("%i2%")=8) AND (VARIABLE_IS_SET $wapt($field("%i2%")"%i%") ) BEGIN
      WRITE_ASCIIE (%new_loc%+ $Off("%i2%")) $wapt($field("%i2%")"%i%") (8)
     END
    END
    PATCH_IF (%wapt_item% >0) BEGIN
     WRITE_LONG (new_loc+0x40) %wapt_idx_items%                 // index value for first new item in current container
     WRITE_LONG (new_loc+0x44) $wapt_num_items("%i%")           // won't write for some reason within the array system
     wapt_idx_items += $wapt_num_items("%i%")                   // update item index for the next container
    END
    WRITE_LONG (new_loc + 0x50)  vert_entry                    // vertex index
    vert_entry += $wapt_vertices("%i%")                        // update vertex index for the next object
  END
DEFINE_ARRAY ifield BEGIN itm_name exp_time qc1 qc2 qc3 itm_flags END
DEFINE_ARRAY i_off  BEGIN 0x0      0x8      0xa 0xc 0xe 0x10      END
DEFINE_ARRAY i_sol  BEGIN 8        2        2   2   2   4         END
  FOR (i4=1;i4<%wapt_item%+1;i4+=1)BEGIN
    FOR(i3=0;i3<6;i3+=1)BEGIN
     PATCH_IF ($i_sol("%i3%")=8) AND (VARIABLE_IS_SET $wapt($ifield("%i3%")"%i4%") ) BEGIN
      WRITE_ASCIIE (%Q_NewOffset_Items% + (%Q_Siz_Items% * (%i4%-1))) $wapt($ifield("%i3%")"%i4%") (8)
     END
     PATCH_IF ($i_sol("%i3%")=4) AND (VARIABLE_IS_SET $wapt($ifield("%i3%")"%i4%") ) BEGIN
      WRITE_LONG (%Q_NewOffset_Items% + (%Q_Siz_Items% * (%i4%-1))) $wapt($ifield("%i3%")"%i4%")
     END
     PATCH_IF ($i_sol("%i3%")=2) AND (VARIABLE_IS_SET $wapt($ifield("%i3%")"%i4%") ) BEGIN
      WRITE_SHORT (%Q_NewOffset_Items% + (%Q_Siz_Items% * (%i4%-1))) $wapt($ifield("%i3%")"%i4%")
     END
    END
  END
BUT_ONLY_IF_IT_CHANGES
END
The array values in BOLD equate to an entry into the containers section of the ARE file that contains a string reference to a dialog.tlk entry. I suggested to GeN1e that it might be better to see if SAY or SAY_EVALUATED would work because the user might not know what the string reference # would be seeing as they most likely would be using a new string.  I can only guess then that this is what he is talking about.  I myself have not tried to use SAY or SAY_EVALUATED in this case.  My guess is that he has tried
Code: [Select]
     PATCH_IF ($SoL("%i2%")=4) AND (VARIABLE_IS_SET $wapt($field("%i2%")"%i%") ) AND (~%field%~ STRING_EQUAL_CASE ~string~) BEGIN
      SAY_EVALUATED (%new_loc%+ $Off("%i2%")) $wapt($field("%i2%")"%i%")
     END
and in the LAUNCH command have either
Code: [Select]
STR_VAR wapt_string_1 = ~some text~ or
Code: [Select]
STR_VAR wapt_string_1 = @101

If I have guessed incorrectly, hopefully GeN1e will come along and restate what he is trying to tell us. 

@GeN1e -- The italic and underlined lines need to be added to your copy for proper functioning when 0 items are being added to the new containers.  Sorry about missing that the first time around...

Quote
Another issue with using FUNCTIONS is when you have a group of files that you want to do the same or similar things to. If it were normal tp2 code we could use COPY_EXISTING with a 'laundry list' of files or ACTION_FOR_EACH (AFE) followed by the patch code with the AFE variable as the file to copy.  Should the patch code already be within an ACTION_FUNCTION it would make sense to apply it following the AFE.  However the variable from the AFE does not get evaluated if it is assigned to the functions variable.  Now it does work if the AFE variable happens to be the same name as the function variable, but then that would cause problems for future uses of the function.
There's nothing in AFE that can make this fail specifically if using OUTER_SPRINT works. Likely it needs the EVALUATE_BUFFER like Mkie said. Yes, I know having to use EVALUATE_BUFFER sucks, but I can't change this without breaking existing mods - EVALUATE_BUFFER is the top thing that bugs me most about WeiDU and makes me wish I had the drive/time to do the fabled tp3.
I don't think OUTER_SPRINT would work either unless it was using a variable name that was the same as the one in the function.  I actually had wondered if there was something in FUNCTION that prevented us from assigning calling environment defined variables to a function variable (of a different name) especially since FUNCTION is designed to not pass variable values back to the calling environment . But I will try EVALUATE_BUFFER out the next chance I get and see what my results are...
My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altherin.webs.com

Offline GeN1e

  • Planewalker
  • *****
  • Posts: 267
  • Gender: Male
Re: FUNCTION use & variables
« Reply #12 on: July 13, 2009, 07:17:00 AM »
Quote
The array values in BOLD equate to an entry into the containers section of the ARE file that contains a string reference to a dialog.tlk entry. I suggested to GeN1e that it might be better to see if SAY or SAY_EVALUATED would work because the user might not know what the string reference # would be seeing as they most likely would be using a new string.  I can only guess then that this is what he is talking about.  I myself have not tried to use SAY or SAY_EVALUATED in this case.  My guess is that he has tried Code:
     PATCH_IF ($SoL("%i2%")=4) AND (VARIABLE_IS_SET $wapt($field("%i2%")"%i%") ) AND (~%field%~ STRING_EQUAL_CASE ~string~) BEGIN
      SAY_EVALUATED (%new_loc%+ $Off("%i2%")) $wapt($field("%i2%")"%i%")
     END
and in the LAUNCH command have either
Code:
STR_VAR wapt_string_1 = ~some text~or
Code:
STR_VAR wapt_string_1 = @101
Yep. SAY_EVALUATED works fine with STR_VAR string = ~New dialog.tlk entry~, but it won't recognize @123 as a valid INT_VAR or STR_VAR value . Tried EVALUATE_BUFFERs, enclosing in ~s, SRPINTing into secondary variable and then trying to evaluate it, but no effect, the @123 remains not evaluated.

Well, I suppose it can work with SAY_EVALUATED, but what if one wants to traify the code?

Offline the bigg

  • The Avatar of Fighter / Thieves
  • Moderator
  • Planewalker
  • *****
  • Posts: 3804
  • Gender: Male
Re: FUNCTION use & variables
« Reply #13 on: July 13, 2009, 07:29:46 AM »
Code: [Select]
<<<<<<<< say_var_keep.tpp
SAY %say_var_where% @%say_var_what%
>>>>>>>>

DEFINE_PATCH_FUNCTION say_at_var BEGIN
  INNER_ACTION BEGIN
    COPY - say_var_keep.tpp say_var_use.tpp
      EVALUATE_BUFFER
  END
  PATCH_REINCLUDE ~say_var_use.tpp
END

LAUNCH_PATCH_FUNCTION say_at_var
INT_VAR
  say_at_where = 4 * var + baseOffset
  say_at_what = 3 + 5 * otherVar
END
this is the closest thing to SAY @(variable) I can offer without a serious code rewrite.
Author or Co-Author: WeiDU (http://j.mp/bLtjOn) - Widescreen (http://j.mp/aKAiqG) - Generalized Biffing (http://j.mp/aVgw3U) - Refinements (http://j.mp/bLHoCc) - TB#Tweaks (http://j.mp/ba02Eg) - IWD2Tweaks (http://j.mp/98OFYY) - TB#Characters (http://j.mp/ak8J55) - Traify Tool (http://j.mp/g1Ry9A) - Some mods that I won't mention in public
Maintainer: Semi-Multi Clerics (http://j.mp/9UeIwB) - Nalia Mod (http://j.mp/dng9l0) - Nvidia Fix (http://j.mp/aRWjjg)
Code dumps: Detect custom secondary types (http://j.mp/hVzzXG) - Stutter Investigator (http://j.mp/gdtBn8)

If possible, send diffs, translations and other contributions using Git (http://j.mp/aBZFrq).

Offline GeN1e

  • Planewalker
  • *****
  • Posts: 267
  • Gender: Male
Re: FUNCTION use & variables
« Reply #14 on: July 13, 2009, 02:11:33 PM »
I did consider the inlining but later discarded it as being, well, not as appealing (and perhaps not as intuitive) as RET.

Speaking of RET, any variable can be INT/STR_VARed at the launch, whether or not it is INT/STR_VARed in definition, so it'd be convenient if RET is the same. Is it feasible to eliminate the need to preset every allowed RET before it can be called in launch?
If yes then it'll be a nice deal to define for the time being a couple of dozens of vars in the RET part, then delete it once Weidu-212 is out.

Offline plainab

  • Sasha al'Therin
  • Planewalker
  • *****
  • Posts: 491
    • Infinity Engine Modding
Re: FUNCTION use & variables
« Reply #15 on: July 13, 2009, 02:28:45 PM »
A little testing with ACTION_FOR_EACH in conjunction with an ACTION_FUNCTION

The function is a simple thing that allows for making edits to the header of an itm file.

Initial code:
Code: [Select]
ACTION_FOR_EACH file0 IN ~book68~ ~helm06~ BEGIN
 LAUNCH_ACTION_FUNCTION ~ab_Item_Header_Edit~ STR_VAR ab_file = ~%file0%.itm~ ab_ii = ~i%file0%~ END
END
The results:
ab_file was correctly evaluated to book68.itm and helm06.itm -- I know this to be true because those files were modified.
ab_ii was not evaluated and was written as i%file0% rather than ibook68 or ihelm06

I changed the code to include EVALUATE_BUFFER:
Code: [Select]
ACTION_FOR_EACH file0 IN ~book68~ ~helm06~ BEGIN
 LAUNCH_ACTION_FUNCTION ~ab_Item_Header_Edit~ STR_VAR ab_file = ~%file0%.itm~ ab_ii = EVALUATE_BUFFER ~i%file0%~ END
END
The results:
everything evaluated and wrote correctly.  In case you need to know, the relevant write inside the function
Code: [Select]
  PATCH_IF (VARIABLE_IS_SET ~ab_ii~) BEGIN
   WRITE_ASCIIE 0x3a ~%ab_ii%~ // inventory icon
  END

What I don't understand is why the AFE variable was properly evaluated for ab_file and not for ab_ii?  The only difference between the two is that in ab_file the AFE variable came first and in ab_ii the AFE variable was after other text.

Sure, I can use EVALUATE_BUFFER, but don't we need to find out why the variable is not being evaluated when other text comes before it in the string?
My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altherin.webs.com

Offline GeN1e

  • Planewalker
  • *****
  • Posts: 267
  • Gender: Male
Re: FUNCTION use & variables
« Reply #16 on: October 04, 2009, 11:56:58 AM »
So I'm back to ramble on the RET part :)

I run into one more issue with it - if the var specified in defined RET is not set then the installation fails with Not_found error. It took me almost an hour of mindfaqing to figure out where exactly I made a mistake.

To demonstrate
Code: [Select]
DEFINE_ACTION_FUNCTION test
  RET a b
BEGIN
 OUTER_SET a=1
END

LAUNCH_ACTION_FUNCTION test END
will fail, while

Code: [Select]
DEFINE_ACTION_FUNCTION test
  RET a b
BEGIN
 OUTER_SET a=1
END

LAUNCH_ACTION_FUNCTION test STR_VAR b=~boo~ END
works.

Furthermore, if possible I would want the following to be applied to FUNCTIONs:
In DEFINE_TYPE_FUNCTION name RET var1 BEGIN patch_list END ret variables are always returned if they exist, whether specified in LAUNCHing or not, so that 'var1' always goes outside.
LAUNCH_TYPE_FUNCTION name RET outcome=var2 END (I honestly would prefer just 'var2' instead of 'outcome=var2', but guess it'll break already existing mods) - these rets, if exist at the end of function execution, will be added to ones specified by DEFINE.
If rets do not exist then nothing happens, user will simply get the usual 'cannot convert %varname% or varname to integer' later on when they try to use vars they forgot to set.

Finally, is there any chance to shortcut macros and functions to three letters?
LAUNCH_ACTION_FUNCTION = LAF
LAUNCH_ACTION_MACRO = LAM
LAUNCH_PATCH_FUNCTION = LPF
LAUNCH_PATCH_MACRO = LPM

PS About breaking older mods. Perhaps just one more category beside INT_VAR, STR_VAR and RET? Which would do exactly what proposed, autoret from launching ('var2' instead of 'outcome=var2') and definition.
« Last Edit: October 04, 2009, 12:02:53 PM by GeN1e »

Offline the bigg

  • The Avatar of Fighter / Thieves
  • Moderator
  • Planewalker
  • *****
  • Posts: 3804
  • Gender: Male
Re: FUNCTION use & variables
« Reply #17 on: October 04, 2009, 02:12:16 PM »
1. No.
This ensures that you haven't misspelled the ret variable.

2. No.
3. No.
FUNCTIONs should be used to ensure that nothing gets out of a function unless esplicitly required. 2 and 3 go against that goal.

4. Yes.
Author or Co-Author: WeiDU (http://j.mp/bLtjOn) - Widescreen (http://j.mp/aKAiqG) - Generalized Biffing (http://j.mp/aVgw3U) - Refinements (http://j.mp/bLHoCc) - TB#Tweaks (http://j.mp/ba02Eg) - IWD2Tweaks (http://j.mp/98OFYY) - TB#Characters (http://j.mp/ak8J55) - Traify Tool (http://j.mp/g1Ry9A) - Some mods that I won't mention in public
Maintainer: Semi-Multi Clerics (http://j.mp/9UeIwB) - Nalia Mod (http://j.mp/dng9l0) - Nvidia Fix (http://j.mp/aRWjjg)
Code dumps: Detect custom secondary types (http://j.mp/hVzzXG) - Stutter Investigator (http://j.mp/gdtBn8)

If possible, send diffs, translations and other contributions using Git (http://j.mp/aBZFrq).

Offline GeN1e

  • Planewalker
  • *****
  • Posts: 267
  • Gender: Male
Re: FUNCTION use & variables
« Reply #18 on: October 04, 2009, 08:52:40 PM »
Quote
4. Yes.
Pardon, does it refer to shortcuts or to AUTO_RET?

Offline the bigg

  • The Avatar of Fighter / Thieves
  • Moderator
  • Planewalker
  • *****
  • Posts: 3804
  • Gender: Male
Re: FUNCTION use & variables
« Reply #19 on: October 05, 2009, 06:18:20 AM »
Shortcuts.
Author or Co-Author: WeiDU (http://j.mp/bLtjOn) - Widescreen (http://j.mp/aKAiqG) - Generalized Biffing (http://j.mp/aVgw3U) - Refinements (http://j.mp/bLHoCc) - TB#Tweaks (http://j.mp/ba02Eg) - IWD2Tweaks (http://j.mp/98OFYY) - TB#Characters (http://j.mp/ak8J55) - Traify Tool (http://j.mp/g1Ry9A) - Some mods that I won't mention in public
Maintainer: Semi-Multi Clerics (http://j.mp/9UeIwB) - Nalia Mod (http://j.mp/dng9l0) - Nvidia Fix (http://j.mp/aRWjjg)
Code dumps: Detect custom secondary types (http://j.mp/hVzzXG) - Stutter Investigator (http://j.mp/gdtBn8)

If possible, send diffs, translations and other contributions using Git (http://j.mp/aBZFrq).

 

With Quick-Reply you can write a post when viewing a topic without loading a new page. You can still use bulletin board code and smileys as you would in a normal post.

Warning: this topic has not been posted in for at least 120 days.
Unless you're sure you want to reply, please consider starting a new topic.

Name: Email:
Verification:
Type the letters shown in the picture
Listen to the letters / Request another image
Type the letters shown in the picture:
What color is grass?:
What is the seventh word in this sentence?:
What is five minus two (use the full word)?: