DavidW Posted June 27, 2020 Share Posted June 27, 2020 Pretty sure it’s correct. Quote Link to comment
Luke Posted June 28, 2020 Author Share Posted June 28, 2020 On 6/27/2020 at 2:03 PM, DavidW said: Pretty sure it’s correct. Me too, otherwise the SSL compiler would complain... It's simply little weird notation to me... I'd write: scsroot=stratagems&tutu_var=%tutu_var%, but whatever... Quote Link to comment
Luke Posted June 28, 2020 Author Share Posted June 28, 2020 (edited) Another initialization issue: clone_template doesn't make use of the variable "tv". Is that intended? I'm asking because you set it when launching clone_store and clone_creature... Edited June 28, 2020 by Luke Quote Link to comment
DavidW Posted June 28, 2020 Share Posted June 28, 2020 46 minutes ago, Luke said: Me too, otherwise the SSL compiler would complain... It's simply little weird notation to me... I'd write: scsroot=stratagems&tutu_var=%tutu_var%, but whatever... But I don’t want the string ‘scsroot’ replaced by ‘stratagems’. I want the string ‘%scsroot%’ replaced. Quote Link to comment
DavidW Posted June 28, 2020 Share Posted June 28, 2020 31 minutes ago, Luke said: Another initialization issue: clone_template doesn't make use of the variable "tv". Is that intended? I'm asking because you set it when launching clone_store and clone_creature... I think I’m going to use this question to say that I’m probably not going to answer much more, unless it’s an actual bug or it catches my interest for some reason. It’s too time-consuming and goes against my ‘this is as-is, I don’t support it’ intention. Quote Link to comment
Luke Posted June 28, 2020 Author Share Posted June 28, 2020 9 minutes ago, DavidW said: unless it’s an actual bug or it catches my interest for some reason... OK, I simply find that issue similar to the missing "arguments" string in "enforce_hp"... Sure, maybe it's not critical, but still something that should be taken into account...? Anyway, I really like reading your code and the "functional programming" way of doing things, sorry if I ask you too many questions Quote Link to comment
DavidW Posted June 28, 2020 Share Posted June 28, 2020 No need to be sorry! I don't mind at all (and I'm really glad you're interested in the code), I just wanted to flag that I wasn't always going to respond. I'll probably go back through this thread next time I do a proper update of the library (thouh I'm a bit cautious modifying the existing code too much even when it seems logical, because it's being used all over SCS and you never know when surprise problems will turn up.) Quote Link to comment
Luke Posted June 29, 2020 Author Share Posted June 29, 2020 (edited) 19 hours ago, DavidW said: I'll probably go back through this thread next time I do a proper update of the library OK, I'll keep reporting issues/oddities then... Missing "warning =" here (after STR_VAR). Edited June 29, 2020 by Luke Quote Link to comment
Luke Posted July 3, 2020 Author Share Posted July 3, 2020 Variable mismatch: macro_read_in_hit_point_levels vs. read_in_hit_point_levels. Quote Link to comment
Luke Posted July 5, 2020 Author Share Posted July 5, 2020 (edited) In case you're interested, my version of "ENFORCE_HP" *should* correctly handle dual-class characters. Note that: I assume the CRE being patched is a playable CLASS my notation is a bit different from yours I'm not interested in "at_best", "at_worst" and the like: I simply want the maximum (possibly adjusted by the INI variable "hitpoint_percentage") Spoiler DEFINE_ACTION_MACRO ~HPCLASS_2DA~ BEGIN LOCAL_SET "read_hpclass" = 0 LOCAL_SET "i" = 0 LOCAL_SPRINT "class" "" LOCAL_SPRINT "table" "" LOCAL_SET "cols" = 0 LOCAL_SET "read_hptable" = 0 LOCAL_SET "j" = 0 LOCAL_SET "level" = 0 LOCAL_SET "sides" = 0 LOCAL_SET "rolls" = 0 LOCAL_SET "modifier" = 0 COPY_EXISTING - "HPCLASS.2DA" "override" READ_2DA_ENTRIES_NOW "read_hpclass" 0 // Column count starts from 0 FOR ("i" = 3; "%i%" < "%read_hpclass%"; "i" += 1) BEGIN READ_2DA_ENTRY_FORMER "read_hpclass" "%i%" 0 "class" READ_2DA_ENTRY_FORMER "read_hpclass" "%i%" 1 "table" INNER_PATCH_FILE "%table%.2da" BEGIN COUNT_2DA_COLS "cols" READ_2DA_ENTRIES_NOW "read_hptable" "%cols%" FOR ("j" = 0; "%j%" < "%read_hptable%"; "j" += 1) BEGIN READ_2DA_ENTRY_FORMER "read_hptable" "%j%" 0 "level" READ_2DA_ENTRY_FORMER "read_hptable" "%j%" 1 "sides" READ_2DA_ENTRY_FORMER "read_hptable" "%j%" 2 "rolls" READ_2DA_ENTRY_FORMER "read_hptable" "%j%" 3 "modifier" //PATCH_PRINT "class = %class%, level = %level%, sides = %sides%, rolls = %rolls%, modifier = %modifier%" SET $hp_increment_max("%class%" "%level%") = ("%sides%" * "%rolls%") + "%modifier%" END END END BUT_ONLY_IF_IT_CHANGES END LAUNCH_ACTION_MACRO ~HPCLASS_2DA~ DEFINE_PATCH_FUNCTION "ENFORCE_HP" BEGIN // Get the IDS name of the CRE CLASS READ_BYTE 0x273 "class_num" LOOKUP_IDS_SYMBOL_OF_INT "class_name" "CLASS" "%class_num%" // Determine if the CRE in question is a playable CLASS LPF "IS_PLAYABLE_CLASS" STR_VAR "class" = "%class_name%" END // Determine if the CRE in question is a dual-class character LPF "IS_DUAL_CLASS" STR_VAR "class" = "%class_name%" RET "is_dual_class" END // If the CRE in question is a Dual-class character, then get its original class PATCH_IF ("%is_dual_class%") BEGIN LPF "READ_ORIGINAL_CLASS" RET "original_class" END END ELSE BEGIN // Determine if the CRE in question is a non-human multi-class – Optional...? LPF "IS_VALID_MULTI-CLASS" STR_VAR "class" = "%class_name%" END END // Get the IDS name of the its KIT READ_LONG 0x244 "kit_num" LPF "REVERSE_LONG" INT_VAR "input" = "%kit_num%" RET "kit_num" = "output" END LOOKUP_IDS_SYMBOL_OF_INT "kit_name" "KIT" "%kit_num%" // Strip "MAGESCHOOL_" from "%kit_name%" if needed – This is because specialist mages are stripped of "MAGESCHOOL_" in "HPCLASS.2DA" PATCH_IF (("%kit_name%" STRING_MATCHES_REGEXP "^MAGESCHOOL_.+$") == 0) BEGIN INNER_PATCH_SAVE "kit_name" "%kit_name%" BEGIN REPLACE_TEXTUALLY CASE_SENSITIVE EXACT_MATCH "MAGESCHOOL_" "" END END // Initialization SET "number_of_classes" = 0 SET "hp_total" = 0 // Main WHILE ("%class_name%" STRING_COMPARE_CASE "") BEGIN SET "number_of_classes" = "%number_of_classes%" + 1 LPF "RETURN_FIRST_ENTRY" STR_VAR "separator" = "_" "list" = "%class_name%" RET "class_name" = "list" "entry" END PATCH_MATCH "%number_of_classes%" WITH "1" BEGIN READ_BYTE 0x234 "level" PATCH_IF "%is_dual_class%" BEGIN //PATCH_PRINT ~Determine if the CLASS "%entry%" is the original class~ PATCH_IF ("%entry%" STRING_EQUAL "%original_class%") BEGIN // CLASS ~%entry%~ is the original class PATCH_IF (VARIABLE_IS_SET $hp_increment_max("%kit_name%" "1")) BEGIN // The original class can be a KIT FOR ("i" = 1; "%i%" <= "%level%"; "i" += 1) BEGIN SET "hp_total" = "%hp_total%" + $hp_increment_max("%kit_name%" "%i%") END END ELSE BEGIN FOR ("i" = 1; "%i%" <= "%level%"; "i" += 1) BEGIN SET "hp_total" = "%hp_total%" + $hp_increment_max("%entry%" "%i%") END END END ELSE BEGIN // CLASS ~%entry%~ is the current/active class READ_BYTE 0x235 "level2" SET "diff" = "%level%" - "%level2%" PATCH_IF ("%diff%" > 0) BEGIN FOR ("i" = "%level2%" + 1; "%i%" <= "%level%"; "i" += 1) BEGIN SET "hp_total" = "%hp_total%" + $hp_increment_max("%entry%" "%i%") END END ELSE BEGIN PATCH_WARN "~%SOURCE_FILE%~ (~%class_name%~, ~%kit_name%~) is an incomplete dual-class character (active_class = %level%; inactive_class = %level2%). Deliberate?" END END END ELSE BEGIN // Multi-class or Single-class PATCH_IF ("%class_name%" STRING_EQUAL_CASE "") BEGIN // Single-class PATCH_IF (VARIABLE_IS_SET $hp_increment_max("%kit_name%" "1")) BEGIN // Single-class characters can have a KIT FOR ("i" = 1; "%i%" <= "%level%"; "i" += 1) BEGIN SET "hp_total" = "%hp_total%" + $hp_increment_max("%kit_name%" "%i%") END END ELSE BEGIN FOR ("i" = 1; "%i%" <= "%level%"; "i" += 1) BEGIN SET "hp_total" = "%hp_total%" + $hp_increment_max("%entry%" "%i%") END END END ELSE BEGIN // First class of a Multi-class FOR ("i" = 1; "%i%" <= "%level%"; "i" += 1) BEGIN SET "hp_total" = "%hp_total%" + $hp_increment_max("%entry%" "%i%") END END END END "2" BEGIN READ_BYTE 0x235 "level2" PATCH_IF "%is_dual_class%" BEGIN //PATCH_PRINT ~Determine if the CLASS "%entry%" is the original class~ PATCH_IF ("%entry%" STRING_EQUAL "%original_class%") BEGIN // CLASS ~%entry%~ is the original class PATCH_IF (VARIABLE_IS_SET $hp_increment_max("%kit_name%" "1")) BEGIN // The original class can be a KIT FOR ("i" = 1; "%i%" <= "%level2%"; "i" += 1) BEGIN SET "hp_total" = "%hp_total%" + $hp_increment_max("%kit_name%" "%i%") END END ELSE BEGIN FOR ("i" = 1; "%i%" <= "%level2%"; "i" += 1) BEGIN SET "hp_total" = "%hp_total%" + $hp_increment_max("%entry%" "%i%") END END END ELSE BEGIN // CLASS ~%entry%~ is the current/active class READ_BYTE 0x234 "level" SET "diff" = "%level2%" - "%level%" PATCH_IF ("%diff%" > 0) BEGIN FOR ("i" = "%level%" + 1; "%i%" <= "%level2%"; "i" += 1) BEGIN SET "hp_total" = "%hp_total%" + $hp_increment_max("%entry%" "%i%") END END ELSE BEGIN PATCH_WARN "~%SOURCE_FILE%~ (~%class_name%~, ~%kit_name%~) is an incomplete dual-class character (inactive_class = %level%; active_class = %level2%). Deliberate?" END END END ELSE BEGIN // Multi-class // Second class of a Multi-class FOR ("i" = 1; "%i%" <= "%level2%"; "i" += 1) BEGIN SET "hp_total" = "%hp_total%" + $hp_increment_max("%entry%" "%i%") END END END "3" BEGIN // Third class of a Multi-class READ_BYTE 0x236 "level3" FOR ("i" = 1; "%i%" <= "%level3%"; "i" += 1) BEGIN SET "hp_total" = "%hp_total%" + $hp_increment_max("%entry%" "%i%") END END DEFAULT END END PATCH_IF ("%number_of_classes%" == 1) OR ("%is_dual_class%") BEGIN WRITE_SHORT 0x24 ("%hp_total%") WRITE_SHORT 0x26 ("%hp_total%") END ELSE BEGIN WRITE_SHORT 0x24 ("%hp_total%" / "%number_of_classes%") WRITE_SHORT 0x26 ("%hp_total%" / "%number_of_classes%") END END // Helper functions DEFINE_PATCH_FUNCTION "IS_DUAL_CLASS" STR_VAR "class" = "" RET "is_dual_class" BEGIN PATCH_MATCH "%class%" WITH "FIGHTER_MAGE" "FIGHTER_CLERIC" "FIGHTER_THIEF" "MAGE_THIEF" "CLERIC_MAGE" "CLERIC_THIEF" "FIGHTER_DRUID" "CLERIC_RANGER" BEGIN SET "not_single_class" = 1 END DEFAULT SET "not_single_class" = 0 SET "is_dual_class" = 0 END PATCH_IF "%not_single_class%" BEGIN READ_LONG 0x10 "flags" SET "x" = (BIT3 BOR BIT4 BOR BIT5 BOR BIT6 BOR BIT7 BOR BIT8) SET "y" = "%flags%" BAND "%x%" PATCH_MATCH "%y%" WITH "8" "16" "32" "64" "128" "256" BEGIN // One of those flags is set => Dual-class SET "is_dual_class" = 1 LPF "IS_VALID_DUAL-CLASS" // Optional...? END END "0" BEGIN // None of those flags is set => Multi-class SET "is_dual_class" = 0 END DEFAULT PATCH_FAIL "~%SOURCE_FILE%~ cannot have more than one original class!" END END END DEFINE_PATCH_FUNCTION "READ_ORIGINAL_CLASS" RET "original_class" BEGIN READ_LONG 0x10 "flags" // Determine the original class CLEAR_ARRAY "array" DEFINE_ASSOCIATIVE_ARRAY "array" BEGIN "FIGHTER" => "BIT3" "MAGE" => "BIT4" "CLERIC" => "BIT5" "THIEF" => "BIT6" "DRUID" => "BIT7" "RANGER" => "BIT8" END PHP_EACH "array" AS "class" => "bit" BEGIN PATCH_IF (("%flags%" BAND "%bit%") == "%bit%") BEGIN TEXT_SPRINT "original_class" "%class%" END END END DEFINE_PATCH_FUNCTION "IS_PLAYABLE_CLASS" STR_VAR "class" = "" BEGIN PATCH_MATCH "%class%" WITH "MAGE" "FIGHTER" "CLERIC" "THIEF" "BARD" "PALADIN" "FIGHTER_MAGE" "FIGHTER_CLERIC" "FIGHTER_THIEF" "FIGHTER_MAGE_THIEF" "DRUID" "RANGER" "MAGE_THIEF" "CLERIC_MAGE" "CLERIC_THIEF" "FIGHTER_DRUID" "FIGHTER_MAGE_CLERIC" "CLERIC_RANGER" "SORCERER" "MONK" "SHAMAN" BEGIN END DEFAULT PATCH_FAIL "~%SOURCE_FILE%~ => you cannot use ~ENFORCE_HP~ with the non-playable CLASS ~%class%~" END END DEFINE_PATCH_FUNCTION "IS_VALID_MULTI-CLASS" STR_VAR "class" = "" BEGIN PATCH_IF (("%class%" STRING_CONTAINS_REGEXP "_") == 0) BEGIN READ_BYTE 0x272 "race_num" LOOKUP_IDS_SYMBOL_OF_INT "race_name" "RACE" "%race_num%" PATCH_IF ("%race_name%" STRING_EQUAL_CASE "HUMAN") BEGIN PATCH_WARN "~%SOURCE_FILE%~ (~%class_name%~, ~%race_name%~) is a HUMAN multi-class. Deliberate?" END END END DEFINE_PATCH_FUNCTION "IS_VALID_DUAL-CLASS" BEGIN READ_BYTE 0x272 "race_num" LOOKUP_IDS_SYMBOL_OF_INT "race_name" "RACE" "%race_num%" PATCH_IF ("%race_name%" STRING_COMPARE_CASE "HUMAN") BEGIN PATCH_WARN "~%SOURCE_FILE%~ (~%race_name%~) is a non-HUMAN dual-class. Deliberate?" END END Edited July 6, 2020 by Luke Quote Link to comment
Luke Posted July 14, 2020 Author Share Posted July 14, 2020 (edited) The variable "loc" written here and here is defined and initialized as an INTEGER variable (so you might want to replace that "STR_VAR loc=xxx" with "INT_VAR loc=xxx"...). This occurs several times and it fake works because the string under consideration is indeed an integer. Anyway, you might want to check that out... The function CRE_delete_opcodes doesn't take any variable called file_ext (just "arguments"...) After this instruction (that should probably be "^.+\.cre$"...?), you might want to throw "PATCH_IF (SOURCE_SIZE > 0x2D3) BEGIN ... END", just in case... Actually, you might want to do it after every COPY_EXISTING_REGEXP so as to skip corrupted files... This READ_SHORT should be READ_LONG! Regarding this complain: I'm 100% sure you can solve it via the so-called PATCH_REINCLUDE trick... You often write (integer) in place of #integer when using WRITE_ASCII (example here). According to WeiDU's docs, #integer is the correct form. Edited September 2, 2020 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.