Skip to content

Hiding spell feedback

SystemSystem Administrator Posts: 199
This discussion was created from comments split from: The New UI System: How to Use It.

Comments

  • GalactygonGalactygon Member, Developer Posts: 412
    Do any of you UI gurus know if it's possible to use the "idenfitied name" in a spell (0xc in the .spl header) rather than the unidentified name that is currently being used?

    I am attempting to write a tweak that removes combat feedback from spellcasting much like IWD2 so that you will have to guess what your foes have cast. One way to do that is set the name to all spells to "" but that carries with the disadvantage of you not knowing the spell description from you abilities bar/spell book. I am thinking about using the currently unused "identified name" for spellbooks/ability selection.

    Another alternative is modifying ENGINEST.2da's entry STRREF_FEEDBACK_CASTS but that does not seem to work as the strref itself does not include any tokens. You would still see "X - Stoneskin: X" instead of "X - Casts Stoneskin: X".
  • kjeronkjeron Member Posts: 2,367
    @Galactygon
    I know it's been a while, but I have found something that works, for spells at least:
    Find the 'WORLD_MESSAGES' menu section,
    add this to the function section above it:
    	function removespellmessage()
    		local text = worldMessageBoxText
    		text = string.gsub(text, "Casts[%w%p ]*", "Casts a spell")
    		return text
    	end
    and edit this section of it:
    	text
    	{
    		name "worldMessageBox"
    		area 28 35 816 197
    --		text lua "worldMessageBoxText"		Replace with this:
    		text lua "removespellmessage()"
    		text style "normal"
    		scrollbar	'GUISCRC'
    		scrollbar func "chatboxScroll"
    	}
    

    It can't block the string for using innate abilities, because they aren't preceded with anything to match.
  • GalactygonGalactygon Member, Developer Posts: 412
    That's amazing. Thanks very much for your work! It's a shame that innate abilities do not use any special strings from ENGINEST.2da and/or cannot be so easily identified/replaced. It would be easiest if all of the ENGINEST.2da strings would contain tokens but that's not the case today.

    I just do not have the patience and energy to explore the possibilities of UI.menu modding; I will sooner figure out how to parse and replace blocks in UI.menu on the fly than figure out how the entire UI system works. May I borrow the code for inclusion of a future tweak pack? I will look into writing a function that can parse/replace blocks in the UI.menu with the help of INDEX_BUFFER.
  • kjeronkjeron Member Posts: 2,367

    That's amazing. Thanks very much for your work! It's a shame that innate abilities do not use any special strings from ENGINEST.2da and/or cannot be so easily identified/replaced. It would be easiest if all of the ENGINEST.2da strings would contain tokens but that's not the case today.

    I just do not have the patience and energy to explore the possibilities of UI.menu modding; I will sooner figure out how to parse and replace blocks in UI.menu on the fly than figure out how the entire UI system works. May I borrow the code for inclusion of a future tweak pack? I will look into writing a function that can parse/replace blocks in the UI.menu with the help of INDEX_BUFFER.

    You are welcome to do with it as you please.

    Fortunately it is a case sensitive check, reducing the chance of it matching in dialog anywhere, but its still a slight possibility. This will get a more strict text match:
    	text = string.gsub(text, ":[%w%p ]*Casts[%w%p ]*", ": Casts a spell")
    and should be enough to avoid any normal dialog instance of the word "Casts" from triggering the replacement.
  • GalactygonGalactygon Member, Developer Posts: 412
    edited April 2017
    I've got this working in my game. Is there a way to reference a particular .tlk entry instead of stating the ": Casts a spell" text directly in the UI.menu?

    Now that I think more about it is it possible to exclude innates by specifying a list of innates in the string.gsub function if it works with regexps? i.e. by adding another line
    text = string.gsub(text, ":[%w%p ]*(Cure Light Wounds|...|...)[%w%p ]*", ": Activates an ability")
    I could theoretically scan all of the innate spells in the game, record their strings, and construct a monster regexp string that catches all the spells.
  • kjeronkjeron Member Posts: 2,367

    I've got this working in my game. Is there a way to reference a particular .tlk entry instead of stating the ": Casts a spell" text directly in the UI.menu?

    Weidu:
    	COPY_EXISTING	~ENGINEST.2DA~	override
    		COUNT_2DA_COLS	cols
    		READ_2DA_ENTRIES_NOW	~ENGINEST~	cols
    		FOR	(i = 0; i < ENGINEST; ++i)	BEGIN
    			READ_2DA_ENTRY_FORMER	~ENGINEST~	i 0 label
    			READ_2DA_ENTRY_FORMER	~ENGINEST~	i 1 strref
    			PATCH_MATCH	~%label%~	WITH
    				~STRREF_FEEDBACK_CASTS ~
    				BEGIN
    					GET_STRREF strref string
    					INNER_ACTION	BEGIN
    						APPEND	~BGEE.LUA~	~%label% = "%string%"~
    					END
    				END
    				DEFAULT
    			END
    		END
    	BUT_ONLY
    I wouldn't necessarily append it to BGEE.lua, but your own master "M_*.lua" file.
    UI.Menu:
    text = string.gsub(text, ":[%w%p ]*" .. STRREF_FEEDBACK_CASTS .. "[%w%p ]*", ": Casts a spell")


    Now that I think more about it is it possible to exclude innates by specifying a list of innates in the string.gsub function if it works with regexps? i.e. by adding another line
    text = string.gsub(text, ":[%w%p ]*(Cure Light Wounds|...|...)[%w%p ]*", ": Activates an ability")
    I could theoretically scan all of the innate spells in the game, record their strings, and construct a monster regexp string that catches all the spells.

    Unless having several filters starts to slow down the game, I don't see any reason it wouldn't work.
  • kjeronkjeron Member Posts: 2,367
    @Galactygon
    Sorry, misread your post, but the idea is similar, what I posted was to pull the "Casts" string from ENGINEST, instead of the TLK entry number. This version will enable you to reference a tlk entry. I also forgot that the message text contains color codes for the text, which was making it difficult to get specific matches, so again improved it a little:
    Weidu:
    	COPY_EXISTING	~ENGINEST.2DA~	override
    		COUNT_2DA_COLS	cols
    		READ_2DA_ENTRIES_NOW	~ENGINEST~	cols
    		FOR	(i = 0; i < ENGINEST; ++i)	BEGIN
    			READ_2DA_ENTRY_FORMER	~ENGINEST~	i 0 label
    			READ_2DA_ENTRY_FORMER	~ENGINEST~	i 1 strref
    			PATCH_MATCH	~%label%~	WITH
    				~STRREF_FEEDBACK_CASTS ~
    				BEGIN
    					INNER_ACTION	BEGIN
    						APPEND	~M_CUSTOM.LUA~	~%label% = "%strref %"~
    					END
    				END
    				DEFAULT
    			END
    		END
    	BUT_ONLY
    	OUTER_SET	strref = RESOLVE_STR_REF (@tra)
    	OUTER_SPRINT	label ~STRREF_FEEDBACK_NONDESCRIPT_CAST~
    	APPEND	~M_CUSTOM.LUA~	~%label% = "%strref %"~
    UI.Menu:
    	function removespellmessage()
    		local text = worldMessageBoxText
    		local checktext = Infinity_FetchString(STRREF_FEEDBACK_CASTS )
    		local newtext = Infinity_FetchString(STRREF_FEEDBACK_NONDESCRIPT_CAST)
    		text = string.gsub(text, ":%^0x%w%w%w%w%w%w%w%w" .. checktext .. "[%w%p ]*", ": " .. newtext)
    		return text
    	end

    the %^0x%w... is to match any hex color code that string contains. It may be replacable with an exact hex string, I just don't know how/where that color is determined or if its going to be the same across games.
  • GalactygonGalactygon Member, Developer Posts: 412
    Although I do prefer labels over directly applying strings in UI.menu, I'm thinking more of using a number for a .tlk entry. I.e. below where "tip" is set to various .tlk entries which point to explanations of how contingencies work. I don't quite understand why it's a good idea for "title" and "action" use labels from lua files over .tlk entries.
    mageBookStrings = {
    	SPWI908 = {tip = 24615, title = 'CHAIN_CONTINGENCY_TITLE', action = "ADD_SPELLS_CONTINGENCY_LABEL"},
    	SPWI617 = {tip = 24615, title = 'CONTINGENCY_TITLE', action = "ADD_SPELLS_CONTINGENCY_LABEL"},
    	SPWI809 = {tip = 24617, title = 'SPELL_TRIGGER_TITLE', action = "ADD_SPELLS_TRIGGER_LABEL"},
    	SPWI710 = {tip = 24616, title = 'SPELL_SEQUENCER_TITLE', action = "ADD_SPELLS_SEQUENCER_LABEL"},
    	SPWI420 = {tip = 24616, title = 'MINOR_SEQUENCER_TITLE', action = "ADD_SPELLS_SEQUENCER_LABEL"},
    	}
    What do the ".."s represent within the function? I can't seem to be getting white text like you mentioned.

    Meanwhile I've made some progress with the "hide spell feedback" mod. I've got around the limitation of innate abilities with a trick by adding a marker in front of the name all spells i.e. "Armor" becomes "-:Armor" and so on. Note that spells cast from scrolls do not use the "Casts " so they appear as innates as well. This "marker" trick can fix that by applying a different set of markers to differenciate between spell types. I like this system because it's possible to refine it by spell type (i.e. "Uses a psionic ability" for a narrow class of spells) and spells that are not patched will still use the default feedback. The only missing part is now hiding those markers when you view your spellbooks/hover your mouse over the ability so that you see "Armor" instead of "-:Armor:-".

    I'm attaching the entire code below so you can play around with it. It still generates text directly in the menu file but it has the basics of the "marker" concept working.


    BEGIN "Hide spell feedback" DEFINE_PATCH_FUNCTION "INSERT_UI_BLOCK" INT_VAR added_ui_block = 0 STR_VAR new_block = "" find_block = "" RET added_ui_block // set to 1 if insertion is successful BEGIN SET added_ui_block = 0 // reset to default value // Truncate any blank spaces/lines at the end of input variable INNER_PATCH_SAVE new_block "%new_block%" BEGIN PATCH_IF BUFFER_LENGTH > 0 BEGIN // truncate at end READ_ASCII (BUFFER_LENGTH - 1) last (1) WHILE "%last%" STRING_MATCHES_REGEXP "[ %TAB%%LNL%%MNL%%WNL%]" = 0 AND BUFFER_LENGTH > 0 BEGIN DELETE_BYTES (BUFFER_LENGTH - 1) 1 READ_ASCII (BUFFER_LENGTH - 1) last (1) END END END // Set OS-specific newline variable PATCH_IF "%WEIDU_OS%" STRING_EQUAL_CASE "win32" BEGIN SPRINT NEWLINE "%WNL%" END ELSE PATCH_IF "%WEIDU_OS%" STRING_EQUAL_CASE "osx" BEGIN SPRINT NEWLINE "%MNL%" END ELSE BEGIN SPRINT NEWLINE "%LNL%" END PATCH_IF "%SOURCE_FILE%" STRING_MATCHES_REGEXP "^.+\.menu$" = 0 BEGIN // sanity check SET index_begin = INDEX_BUFFER ("%find_block%" 0) PATCH_IF index_begin >= 0 BEGIN // If found a result SET write_length = STRING_LENGTH "%new_block%" INSERT_BYTES index_begin (write_length + 2) WRITE_ASCIIE index_begin "%new_block%%NEWLINE%%NEWLINE%" (write_length + 2) SET added_ui_block = 1 END END END OUTER_SPRINT UI_casts_new_text ": *casts a spell*" OUTER_SPRINT UI_usesab_new_text ": *uses an ability*" // Pad name of every single spell with special characters (i.e. convert "Armor" into "-:Armor:-") OUTER_SPRINT begin_padsplname_new "-:" OUTER_SPRINT end_padsplname_new ":-" OUTER_SPRINT UI_casts_existing_text "Casts" // default value COPY_EXISTING "ENGINEST.2da" "override" REPLACE_EVALUATE "\(STRREF_FEEDBACK_CASTS[ %TAB%]+\)\([0]?[x]?[0-9]+\)" BEGIN PATCH_IF IS_AN_INT MATCH2 BEGIN GET_STRREF MATCH2 UI_casts_existing_text // Get string END END "%MATCH1%%MATCH2%" BUT_ONLY <<<<<<<< .../%MOD_FOLDER%-Inlined/RemoveSpellMessage.menu function removespellmessage() -- Replace casting text (i.e. "Edwin: Casts Armor" becomes "Edwin: *casts a spell*") -- Replace padded spell names (i.e. "Edwin: -:Armor:-" becomes "Edwin: *uses an ability*") local text = worldMessageBoxText text = string.gsub(text, ":[%w%p ]*%UI_casts_existing_text%[%w%p ]*", "%UI_casts_new_text%") text = string.gsub(text, ":[%w%p ]*%begin_padsplname_new%[%w%p ]*", "%UI_usesab_new_text%") text = string.gsub(text, ":%^0x%w%w%w%w%w%w%w%w", "^0xFFFFFFFF") return text end >>>>>>>> COPY - ".../%MOD_FOLDER%-Inlined/RemoveSpellMessage.menu" "" READ_ASCII 0 removespellmessage (BUFFER_LENGTH) // Insert function "RemoveSpellMessage" above "menu { name 'WORLD_MESSAGES'" COPY_EXISTING "UI.menu" "override" LPF "INSERT_UI_BLOCK" STR_VAR new_block = EVAL "%removespellmessage%" find_block = EVAL "[ %TAB%%LNL%%MNL%%WNL%]`[ %TAB%%LNL%%MNL%%WNL%]+menu[ %TAB%%LNL%%MNL%%WNL%]+{[ %TAB%%LNL%%MNL%%WNL%]+name 'WORLD_MESSAGES'" RET added_ui_block END PATCH_IF added_ui_block = 1 BEGIN // if function was successfully added REPLACE_TEXTUALLY ~\(name "worldMessageBox"[^{}]+\)\([%LNL%%MNL%%WNL%][ %TAB%]*\)\(text lua "worldMessageBoxText"\)~ ~\1\2\3\2text lua "removespellmessage()"~ END BUT_ONLY // Pad name of every single spell COPY_EXISTING_REGEXP GLOB "^.+\.spl$" "override" PATCH_IF SOURCE_SIZE > 0x71 BEGIN // Sanity check PATCH_IF LONG_AT 0x8 > 0 AND LONG_AT 0x8 < 1000000 BEGIN // If valid spell name READ_STRREF 0x8 spell_name_text PATCH_IF NOT "%spell_name_text%" STRING_EQUAL_CASE "" AND NOT "%spell_name_text%" STRING_MATCHES_REGEXP "<\(NO TEXT\|Not Available\|Invalid Reference\|Invalid Strref\).*>" = 0 BEGIN // If valid spell name INNER_PATCH_SAVE spell_name_text "%spell_name_text%" BEGIN // Pad beginning of spell name SPRINT begin_padsplname_existing "" PATCH_IF BUFFER_LENGTH >= STRING_LENGTH "%begin_padsplname_new%" BEGIN READ_ASCII 0 begin_padsplname_existing (STRING_LENGTH "%begin_padsplname_new%") END PATCH_IF NOT "%begin_padsplname_existing%" STRING_EQUAL_CASE "%begin_padsplname_new%" BEGIN INSERT_BYTES 0 (STRING_LENGTH "%begin_padsplname_new%") WRITE_ASCIIE 0 "%begin_padsplname_new%" (STRING_LENGTH "%begin_padsplname_new%") END // Pad end of spell name SPRINT end_padsplname_existing "" PATCH_IF BUFFER_LENGTH >= STRING_LENGTH "%end_padsplname_new%" BEGIN READ_ASCII (BUFFER_LENGTH - (STRING_LENGTH "%end_padsplname_new%")) end_padsplname_existing (STRING_LENGTH "%end_padsplname_new%") END PATCH_IF NOT "%begin_padsplname_existing%" STRING_EQUAL_CASE "%end_padsplname_new%" BEGIN INSERT_BYTES BUFFER_LENGTH (STRING_LENGTH "%end_padsplname_new%") WRITE_ASCIIE (BUFFER_LENGTH - (STRING_LENGTH "%end_padsplname_new%")) "%end_padsplname_new%" (STRING_LENGTH "%end_padsplname_new%") END END SAY_EVALUATED 0x8 "%spell_name_text%" END END END BUT_ONLY
  • kjeronkjeron Member Posts: 2,367
    edited April 2017

    Although I do prefer labels over directly applying strings in UI.menu, I'm thinking more of using a number for a .tlk entry. I.e. below where "tip" is set to various .tlk entries which point to explanations of how contingencies work. I don't quite understand why it's a good idea for "title" and "action" use labels from lua files over .tlk entries.

    I don't know the proper reasoning. I just find it easier to patch my custom M_.lua files with a different string/tlk number than to patch UI.MENU with a different label/string/tlk number.

    What do the ".."s represent within the function? I can't seem to be getting white text like you mentioned.

    Lua String Concatenation
    I was using the color code as a marker, not trying to replace it. By not using the wildcard(*+-) matches, but instead getting exactly 11 characters matching the color code format, there is almost no risk of catching the text "Casts" somewhere *within* dialogue. My text was still off-white when I did this - not the white used by the game. I have since found the color the game uses for "white" text: 0xffbed7d7, so it can resume in proper color.

    Some of your code is still more than I understand, but here are the parts I would alter for tra/tlk references.
    Just comment/delete the forms you don't wish to use (str, tra, or tlk), and input proper @tra or #tlk reference numbers.
    
    OUTER_SPRINT UI_casts_new_text " *casts a spell*"
    OUTER_SPRINT UI_usesab_new_text " *uses an ability*"
    replace with:
    OUTER_SET UI_casts_new_str = RESOLVE_STR_REF (~ *casts a spell*~)
    //OUTER_SET UI_casts_new_tra = RESOLVE_STR_REF (@tra)
    //OUTER_SET UI_casts_new_tlk = RESOLVE_STR_REF (#tlk)
    OUTER_SET UI_usesab_new_str = RESOLVE_STR_REF (~ *uses an ability*~)
    //OUTER_SET UI_usesab_new_tra = RESOLVE_STR_REF (@tra)
    //OUTER_SET UI_usesab_new_tlk = RESOLVE_STR_REF (#tlk)
    and then changes to this section:
    <<<<<<<< .../%MOD_FOLDER%-Inlined/RemoveSpellMessage.menu
    function removespellmessage()
    	-- Replace casting text (i.e. "Edwin: Casts Armor" becomes "Edwin: *casts a spell*")
    	-- Replace padded spell names (i.e. "Edwin: -:Armor:-" becomes "Edwin: *uses an ability*")
    	local text = worldMessageBoxText
    	local UI_casts_new_text = Infinity_FetchString(%UI_casts_new_str%)
    	--local UI_casts_new_text = Infinity_FetchString(%UI_casts_new_tra%)
    	--local UI_casts_new_text = Infinity_FetchString(%UI_casts_new_tlk%)
    	local UI_usesab_new_text = Infinity_FetchString(%UI_usesab_new_str%)
    	--local UI_usesab_new_text = Infinity_FetchString(%UI_usesab_new_tra%)
    	--local UI_usesab_new_text = Infinity_FetchString(%UI_usesab_new_tlk%)
    	text = string.gsub(text, ": %^0x%w%w%w%w%w%w%w%w%UI_casts_existing_text%[%w%p ]*", ": ^0xffbed7d7" .. UI_casts_new_text)
    	text = string.gsub(text, ": %^0x%w%w%w%w%w%w%w%w%%begin_padsplname_new%[%w%p ]*", ": ^0xffbed7d7" .. UI_usesab_new_text)
    	return text
    end
    >>>>>>>>
    These are the lines that get spellnames, to remove the "-: | :-" in the:
    magebook:
    text lua "Infinity_FetchString( bookSpells[rowNumber].name)"->
    function replacemagespellheader()
    	local text = Infinity_FetchString( bookSpells[rowNumber].name)
    	text = string.gsub(text, "%-:", "")
    	text = string.gsub(text, ":%-", "")
    	return text
    end
    text lua "replacemagespellheader()"
    priestscroll:
    text lua "Infinity_FetchString( characters[id].priestSpells[currentSpellLevel][rowNumber].name)"->
    function replacepriestspellheader()
    	local text = Infinity_FetchString( characters[id].priestSpells[currentSpellLevel][rowNumber].name)
    	text = string.gsub(text, "%-:", "")
    	text = string.gsub(text, ":%-", "")
    	return text
    end
    text lua "replacepriestspellheader()"
  • GalactygonGalactygon Member, Developer Posts: 412
    Thanks Kjeron! Fetching strrefs was exactly the way I imagined it without having to worry about any lua files. The LUA scripting guide will be handy in the future, it's well written.

    I've applied your functions and patches and I've got all the issues fixed, the text *casts a spell* now correctly displays in white, and all markers are gone when viewing the priest/mage scroll. I did run into two issues:
    1. *uses an ability* did not display correctly, possibly having to do with the number of spaces between "charname: abilityname" which is two spaces. I had to replace text = string.gsub(text, ": %^0x%w%w%w%w%w%w%w%w%%begin_padsplname_new%[%w%p ]*", ": ^0xffbed7d7" .. UI_usesab_new_text) with text = string.gsub(text, ":[%w%p ]*%begin_padsplname_new%[%w%p ]*", ": ^0xffbed7d7" .. UI_usesab_new_text) to fix the issue.
    2. The markers are still there when hovering your mouse over a spell or ability in the main game screen and the tooltip scroll appears. Do you know where in UI.menu the text from tooltips can be transformed?
  • kjeronkjeron Member Posts: 2,367
    @Galactygon
    menu "WORLD_ACTIONBAR"
    There are 12 buttons(0-11), Button 0 has this line:
    tooltip lua "actionBarTooltip[0]"Button 1:
    tooltip lua "actionBarTooltip[1]"etc...
    It could use a similar function, as the casters name is replaced with the function key, and there is no color code to worry about.
    The new function would need to replace these lines:
    function removespellmessage()
    	local text = worldMessageBoxText
    	text = string.gsub(text, ": %^0x%w%w%w%w%w%w%w%w%UI_casts_existing_text%[%w%p ]*", ": ^0xffbed7d7" .. UI_casts_new_text)
    	text = string.gsub(text, ":[%w%p ]*%begin_padsplname_new%[%w%p ]*", ": ^0xffbed7d7" .. UI_usesab_new_text)
    with:
    function removetooltipmarker(num)
    	local text = "actionBarTooltip[num]"
    	text = string.gsub(text, "%-:", "")
    	text = string.gsub(text, ":%-", "")
    and replace:
    tooltip lua "actionBarTooltip[0]"with:
    tooltip lua "removetooltipmarker(0)"for each button (0-11).
  • GalactygonGalactygon Member, Developer Posts: 412
    Thanks for all of the help you have given me. The mod can now handle different groups/categories of spells with different feedback text. All of this information can now be set in two ASSOCIATIVE_ARRAYs in the beginning.

    See some examples on how it now works ingame:


    I did run into one last problem: the spell markers are visible during character generation. Do you know where to replace them? I will post the full code once that remaining issue is fixed.
  • kjeronkjeron Member Posts: 2,367
    edited April 2017

    I did run into one last problem: the spell markers are visible during character generation. Do you know where to replace them? I will post the full code once that remaining issue is fixed.

    There are 3 seperate entries used during chargen that you would need to replace with similar functions:
    menu:
     'CHARGEN_CHOOSE_SPELLS'
    	text lua "Infinity_FetchString(spellBook[chargen.currentSpellLevelChoice][chargen.choose_spell[rowNumber].key].name)"
    menu:
     'CHARGEN_MEMORIZE_MAGE'
    	text lua "Infinity_FetchString(mageSpells[chargen.currentSpellLevelChoice][chargen.choose_spell[rowNumber].key].name)"
    menu:
     'CHARGEN_MEMORIZE_PRIEST'
    	text lua "Infinity_FetchString(priestSpells[chargen.currentSpellLevelChoice][chargen.choose_spell[rowNumber].key].name)"
    And a fourth that lists your current chargen summary/progress:
    menu:
     'CHARGEN'
    	text lua "chargen.information"
  • GalactygonGalactygon Member, Developer Posts: 412
    I keep getting blank strings during character generation choose spells when I add
    function replacechargenchoosespells()
    	local text = Infinity_FetchString( spellBook[chargen.currentSpellLevelChoice][chargen.choose_spell[rowNumber].key].name )
    	--generate replacement text later, this is a test function
    	return text
    end
    and replace
    text lua "Infinity_FetchString(spellBook[chargen.currentSpellLevelChoice][chargen.choose_spell[rowNumber].key].name)"
    with
    text lua replacechargenchoosespells()
    
    This is strange since the "hardcoded" lua functions work fine when called in all other applications of functions (tooltip, magebook, priest scroll).
  • kjeronkjeron Member Posts: 2,367
    edited April 2017


    text lua replacechargenchoosespells()
    
    text lua "replacechargenchoosespells()"
    Need the quotes "", not that I know why.
  • AncientCowboyAncientCowboy Member Posts: 199
    The quotes delimit the beginning and the end of the Lua code since this appears within a menu definition rather than a Lua code chunk/block (which are delimited by accent grave ` characters). Similarly, Lua code that appears within a menu's onOpen, a component's action , and other similar events is likewise delimited even though they aren't preceded by the lua keyword.
  • GalactygonGalactygon Member, Developer Posts: 412
    edited April 2017
    Yes, it was the missing quotes! Thanks! I also took care of the ability description when right clicking on a spell/special ability in the main game screen, found under "POPUP_DETAILS".

    This mod is pretty much complete except for the .traification and assigning categories to various groups of spells i.e. *uses breath weapon* and so on.

    Here is the complete code:

    BEGIN "Hide spell feedback" REQUIRE_PREDICATE (FILE_EXISTS_IN_GAME "UI.menu" AND FILE_EXISTS_IN_GAME "ENGINEST.2da") "Game must be EE" // Assign feedback text to spell types. // All spells matching conditions (left term) use the listed feedback (right term). // If a spell fulfills more than one condition the first valid item in the list is used. // Higher priority ...s are listed on top. // NOTE: Feedback text can be a string (i.e. "*uses psionics*") or a valid .tra entry (i.e. "100" or "@100" or "#100"). ACTION_DEFINE_ASSOCIATIVE_ARRAY "HIDE_SPELL_FEEDBACK" BEGIN "idsmask:.*PSIONIC.*" => "*uses psionics*" // Any spell where spell.ids symbol matches regexp "resmask:SPIN\(727\|834\|959\|97[45]\)" => "*uses psionics*" // Get remaining psionic spells "resmask:W_P.+" => "*uses psionics*" // Psionics Unleashed mod "spelltype:[12]" => "*launches a spell*" // Any wizard or priest spell "resmask:.*" => "*uses an ability*" // Catch all remaining spells END // Assign marker text to feedback text. // Higher priority text replacements are listed on top. // i.e. "*casts a spell*" text is overriden by anything above it. // NOTE: Feedback text can be a string (i.e. "*uses psionics*") or a valid .tra entry (i.e. "100" or "@100" or "#100"). ACTION_DEFINE_ASSOCIATIVE_ARRAY "HIDE_SPELL_FEEDBACK_MARKER" BEGIN "*uses psionics*" => ":PS:" // Psionics text is replaced before "X: Casts Y" text "*casts a spell*" => "STRREF_FEEDBACK_CASTS" // Replace "X: Casts Y" "*launches a spell*" => ":SP:" // If spell is cast via other means (i.e. ForceSpell(), scrolls, etc. that do not use "X: Casts Y") "*uses an ability*" => ":AB:" // Catch all remaining spells END DEFINE_PATCH_FUNCTION "STRING_TO_TRA" STR_VAR input_string = "" RET output_string BEGIN SPRINT output_string "" PATCH_IF "%input_string%" STRING_MATCHES_REGEXP "^[@#]\(0x\)?\([0-9]+\)$" = 0 BEGIN INNER_PATCH_SAVE input_string "%input_string%" BEGIN REPLACE_TEXTUALLY "[@#]" "" // Remove @/# symbol END END PATCH_IF IS_AN_INT input_string BEGIN PATCH_TRY SPRINT output_string (AT input_string) WITH DEFAULT SPRINT output_string "" END END ELSE BEGIN SPRINT output_string "" END END /** * Inserts a complete LUA function in *.menu or *.lua files. * STR_VAR new_block Insertion text. Two newlines are automatically added after the text. * STR_VAR find_block Text will be inserted before the following text (e.g. "function myFunctionToReplace(param1)"). * Match includes any whitespace found directly before the search text. * RET added_ui_block Returns 1 if the insertion was successful, 0 otherwise. * * Original author: Galactygon */ DEFINE_PATCH_FUNCTION INSERT_UI_BLOCK STR_VAR new_block = "" find_block = "" RET added_ui_block // set to 1 if insertion is successful BEGIN SET added_ui_block = 0 // reset to default value // Truncate any blank spaces/lines at the end of input variable INNER_PATCH_SAVE new_block "%new_block%" BEGIN PATCH_IF BUFFER_LENGTH > 0 BEGIN // truncate at end READ_ASCII (BUFFER_LENGTH - 1) last (1) WHILE "%last%" STRING_MATCHES_REGEXP "[ %TAB%%LNL%%MNL%%WNL%]" = 0 AND BUFFER_LENGTH > 0 BEGIN DELETE_BYTES (BUFFER_LENGTH - 1) 1 READ_ASCII (BUFFER_LENGTH - 1) last (1) END END END // Set OS-specific newline variable PATCH_IF "%WEIDU_OS%" STRING_EQUAL_CASE "unix" BEGIN SPRINT NEWLINE "%LNL%" END ELSE BEGIN SPRINT NEWLINE "%WNL%" END PATCH_IF ("%SOURCE_EXT%" STRING_EQUAL_CASE "menu" OR "%SOURCE_EXT%" STRING_EQUAL_CASE "lua") BEGIN // sanity check SET index_begin = INDEX_BUFFER ("[ %TAB%]*%find_block%" 0) PATCH_IF index_begin >= 0 BEGIN // If found a result SET write_length = STRING_LENGTH "%new_block%" INSERT_BYTES index_begin (write_length + 2) WRITE_ASCIIE index_begin "%new_block%%NEWLINE%%NEWLINE%" (write_length + 2) SET added_ui_block = 1 END END END <<<<<<<< .../%MOD_FOLDER%-Inlined/RemoveSpellMessage.menu function removespellmessage() local text = worldMessageBoxText temptext return text end >>>>>>>> COPY - ".../%MOD_FOLDER%-Inlined/RemoveSpellMessage.menu" "" PATCH_PHP_EACH "HIDE_SPELL_FEEDBACK_MARKER" AS input_feedback => input_marker BEGIN // Transform %input_feedback% variable if set to tra entry PATCH_IF "%input_feedback%" STRING_MATCHES_REGEXP "^[@#]?\(0x\)?\([0-9]+\)$" = 0 BEGIN LPF "STRING_TO_TRA" STR_VAR input_string = EVAL "%input_feedback%" RET use_feedback = output_string END END ELSE BEGIN SPRINT use_feedback "%input_feedback%" END SET UI_use_feedback = RESOLVE_STR_REF ("%use_feedback%") // Interpret %input_marker% and whether it exists in ENGINEST.2da PATCH_IF FILE_CONTAINS_EVALUATED ("ENGINEST.2da" "^%input_marker%[ %TAB%]+\(0x\)?[0-9]+") BEGIN INNER_PATCH_FILE "ENGINEST.2da" BEGIN // Record string from ENGINEST.2da as %UI_use_marker% REPLACE_EVALUATE "^%input_marker%[ %TAB%]+\([0]?[x]?[0-9]+\)" BEGIN PATCH_IF IS_AN_INT MATCH1 BEGIN SET UI_use_marker = MATCH1 END END "" END REPLACE_TEXTUALLY ~\([%LNL%%MNL%%WNL%]\)\([ %TAB%]*\)\(temptext\)~ ~\1\2local UI_use_marker = Infinity_FetchString(%UI_use_marker%)\1\2local UI_use_feedback = Infinity_FetchString(%UI_use_feedback%)\1\2text = string.gsub(text, ":[ ]*%^0x%w%w%w%w%w%w%w%w%" .. UI_use_marker .. "[%w%p ]*", ": ^0xffbed7d7" .. UI_use_feedback)\1\2\3~ END ELSE BEGIN SPRINT UI_use_marker "%input_marker%" REPLACE_TEXTUALLY ~\([%LNL%%MNL%%WNL%]\)\([ %TAB%]*\)\(temptext\)~ ~\1\2local UI_use_feedback = Infinity_FetchString(%UI_use_feedback%)\1\2text = string.gsub(text, ":[%w%p ]*%UI_use_marker%[%w%p ]*", ": ^0xffbed7d7" .. UI_use_feedback)\1\2\3~ END END // Remove tempstring REPLACE_TEXTUALLY "[%LNL%%MNL%%WNL%][ %TAB%]*temptext" "" // Record entire function as string %removespellmessage% READ_ASCII 0 removespellmessage (BUFFER_LENGTH) DEFINE_PATCH_MACRO "UI_SUBSTITUTE_LIST" BEGIN PATCH_PHP_EACH "HIDE_SPELL_FEEDBACK_MARKER" AS input_feedback => input_marker BEGIN // Interpret %input_marker% and whether it exists in ENGINEST.2da PATCH_IF NOT FILE_CONTAINS_EVALUATED ("ENGINEST.2da" "^%input_marker%[ %TAB%]+\(0x\)?[0-9]+") BEGIN REPLACE_TEXTUALLY ~\([%LNL%%MNL%%WNL%]\)\([ %TAB%]*\)\(temptext\)~ ~\1\2text = string.gsub(text, "%input_marker%", "")\1\2\3~ END END // Remove tempstring REPLACE_TEXTUALLY "[%LNL%%MNL%%WNL%][ %TAB%]*temptext" "" END // Remove markers in spell name when viewing mage book <<<<<<<< .../%MOD_FOLDER%-Inlined/ReplaceMageSpellHeader.menu function replacemagespellheader() local text = Infinity_FetchString( bookSpells[rowNumber].name) temptext return text end >>>>>>>> COPY - ".../%MOD_FOLDER%-Inlined/ReplaceMageSpellHeader.menu" "" LAUNCH_PATCH_MACRO "UI_SUBSTITUTE_LIST" // replace "temptext" with generated list of string.gsub() function calls READ_ASCII 0 replacemagespellheader (BUFFER_LENGTH) // Remove markers in spell name when viewing priest scroll <<<<<<<< .../%MOD_FOLDER%-Inlined/ReplacePriestSpellHeader.menu function replacepriestspellheader() local text = Infinity_FetchString( characters[id].priestSpells[currentSpellLevel][rowNumber].name) temptext return text end >>>>>>>> COPY - ".../%MOD_FOLDER%-Inlined/ReplacePriestSpellHeader.menu" "" LAUNCH_PATCH_MACRO "UI_SUBSTITUTE_LIST" // replace "temptext" with generated list of string.gsub() function calls READ_ASCII 0 replacepriestspellheader (BUFFER_LENGTH) // Remove markers in spell name during character generation choose spells <<<<<<<< .../%MOD_FOLDER%-Inlined/ReplaceCharGenChooseSpells.menu function replacechargenchoosespells() local text = Infinity_FetchString(spellBook[chargen.currentSpellLevelChoice][chargen.choose_spell[rowNumber].key].name) temptext return text end >>>>>>>> COPY - ".../%MOD_FOLDER%-Inlined/ReplaceCharGenChooseSpells.menu" "" LAUNCH_PATCH_MACRO "UI_SUBSTITUTE_LIST" // replace "temptext" with generated list of string.gsub() function calls READ_ASCII 0 replacechargenchoosespells (BUFFER_LENGTH) // Remove markers in spell name during character generation memorize mage spells <<<<<<<< .../%MOD_FOLDER%-Inlined/ReplaceCharGenMemorizeMage.menu function replacechargenmemorizemage() local text = Infinity_FetchString(mageSpells[chargen.currentSpellLevelChoice][chargen.choose_spell[rowNumber].key].name) temptext return text end >>>>>>>> COPY - ".../%MOD_FOLDER%-Inlined/ReplaceCharGenMemorizeMage.menu" "" LAUNCH_PATCH_MACRO "UI_SUBSTITUTE_LIST" // replace "temptext" with generated list of string.gsub() function calls READ_ASCII 0 replacechargenmemorizemage (BUFFER_LENGTH) // Remove markers in spell name during character generation memorize priest spells <<<<<<<< .../%MOD_FOLDER%-Inlined/ReplaceCharGenMemorizePriest.menu function replacechargenmemorizepriest() local text = Infinity_FetchString(priestSpells[chargen.currentSpellLevelChoice][chargen.choose_spell[rowNumber].key].name) temptext return text end >>>>>>>> COPY - ".../%MOD_FOLDER%-Inlined/ReplaceCharGenMemorizePriest.menu" "" LAUNCH_PATCH_MACRO "UI_SUBSTITUTE_LIST" // replace "temptext" with generated list of string.gsub() function calls READ_ASCII 0 replacechargenmemorizepriest (BUFFER_LENGTH) // Remove markers in spell name during character generation information <<<<<<<< .../%MOD_FOLDER%-Inlined/ReplaceCharGenInformation.menu function replacechargeninformation() local text = chargen.information temptext return text end >>>>>>>> COPY - ".../%MOD_FOLDER%-Inlined/ReplaceCharGenInformation.menu" "" LAUNCH_PATCH_MACRO "UI_SUBSTITUTE_LIST" // replace "temptext" with generated list of string.gsub() function calls READ_ASCII 0 replacechargeninformation (BUFFER_LENGTH) // Remove markers in spell name when tooltip hovering <<<<<<<< .../%MOD_FOLDER%-Inlined/RemoveTooltipMarker.menu function removetooltipmarker(num) local text = actionBarTooltip[num] temptext return text end >>>>>>>> COPY - ".../%MOD_FOLDER%-Inlined/RemoveTooltipMarker.menu" "" LAUNCH_PATCH_MACRO "UI_SUBSTITUTE_LIST" // replace "temptext" with generated list of string.gsub() function calls READ_ASCII 0 removetooltipmarker (BUFFER_LENGTH) // Remove markers in spell name when viewing ability description <<<<<<<< .../%MOD_FOLDER%-Inlined/RemoveAbilityNameMarker.menu function removeabilitynamemarker() local text = Infinity_FetchString(PopupDetails.name) temptext return text end >>>>>>>> COPY - ".../%MOD_FOLDER%-Inlined/RemoveAbilityNameMarker.menu" "" LAUNCH_PATCH_MACRO "UI_SUBSTITUTE_LIST" // replace "temptext" with generated list of string.gsub() function calls READ_ASCII 0 removeabilitynamemarker (BUFFER_LENGTH) // Insert function "RemoveSpellMessage" above "menu { name 'WORLD_MESSAGES'" COPY_EXISTING "UI.menu" "override" // Insert new UI block before "menu { name 'WORLD_MESSAGES'" LPF "INSERT_UI_BLOCK" STR_VAR new_block = EVAL "%removespellmessage%" find_block = EVAL "[ %TAB%%LNL%%MNL%%WNL%]`[ %TAB%%LNL%%MNL%%WNL%]*menu[ %TAB%%LNL%%MNL%%WNL%]*{[ %TAB%%LNL%%MNL%%WNL%]*name[ %TAB%]+'WORLD_MESSAGES'" RET added_ui_block END PATCH_IF added_ui_block = 1 BEGIN // if function was successfully added // Remove spell message in dialogue window/combat log REPLACE_TEXTUALLY ~\(name "worldMessageBox"[^{}]+\)\([%LNL%%MNL%%WNL%][ %TAB%]*\)\(text lua "worldMessageBoxText"\)~ ~\1\2\3\2text lua "removespellmessage()"~ // Remove added strings in mage book REPLACE_TEXTUALLY EXACT_MATCH ~text lua "Infinity_FetchString( bookSpells[rowNumber].name)"~ ~text lua "replacemagespellheader()"~ LPF "INSERT_UI_BLOCK" STR_VAR new_block = EVAL "%replacemagespellheader%" find_block = EVAL "function refreshMageBook()" END // Remove added strings in priest scroll REPLACE_TEXTUALLY EXACT_MATCH ~text lua "Infinity_FetchString( characters[id].priestSpells[currentSpellLevel][rowNumber].name)"~ ~text lua "replacepriestspellheader()"~ LPF "INSERT_UI_BLOCK" STR_VAR new_block = EVAL "%replacepriestspellheader%" find_block = EVAL "function refreshPriestBook()" END // Remove added strings in character generation choose spells REPLACE_TEXTUALLY EXACT_MATCH ~text lua "Infinity_FetchString(spellBook[chargen.currentSpellLevelChoice][chargen.choose_spell[rowNumber].key].name)"~ ~text lua "replacechargenchoosespells()"~ LPF "INSERT_UI_BLOCK" STR_VAR new_block = EVAL "%replacechargenchoosespells%" find_block = EVAL "`[ %TAB%%LNL%%MNL%%WNL%]*menu[ %TAB%%LNL%%MNL%%WNL%]*{[ %TAB%%LNL%%MNL%%WNL%]*name[ %TAB%]+'CHARGEN_CHOOSE_SPELLS'" END // Remove added strings in character generation memorize mage spells REPLACE_TEXTUALLY EXACT_MATCH ~text lua "Infinity_FetchString(mageSpells[chargen.currentSpellLevelChoice][chargen.choose_spell[rowNumber].key].name)"~ ~text lua "replacechargenmemorizemage()"~ LPF "INSERT_UI_BLOCK" STR_VAR new_block = EVAL "%replacechargenmemorizemage%" find_block = EVAL "`[ %TAB%%LNL%%MNL%%WNL%]*menu[ %TAB%%LNL%%MNL%%WNL%]*{[ %TAB%%LNL%%MNL%%WNL%]*name[ %TAB%]+'CHARGEN_MEMORIZE_MAGE'" END // Remove added strings in character generation memorize priest spells REPLACE_TEXTUALLY EXACT_MATCH ~text lua "Infinity_FetchString(priestSpells[chargen.currentSpellLevelChoice][chargen.choose_spell[rowNumber].key].name)"~ ~text lua "replacechargenmemorizepriest()"~ LPF "INSERT_UI_BLOCK" STR_VAR new_block = EVAL "%replacechargenmemorizepriest%" find_block = EVAL "`[ %TAB%%LNL%%MNL%%WNL%]*menu[ %TAB%%LNL%%MNL%%WNL%]*{[ %TAB%%LNL%%MNL%%WNL%]*name[ %TAB%]+'CHARGEN_MEMORIZE_PRIEST'" END // Remove added strings in character generation information REPLACE_TEXTUALLY EXACT_MATCH ~text lua "chargen.information"~ ~text lua "replacechargeninformation()"~ LPF "INSERT_UI_BLOCK" STR_VAR new_block = EVAL "%replacechargeninformation%" find_block = EVAL "`[ %TAB%%LNL%%MNL%%WNL%]*menu[ %TAB%%LNL%%MNL%%WNL%]*{[ %TAB%%LNL%%MNL%%WNL%]*name[ %TAB%]+'CHARGEN'" END // Remove added strings in ability description REPLACE_TEXTUALLY EXACT_MATCH ~text lua "Infinity_FetchString(PopupDetails.name)"~ ~text lua "removeabilitynamemarker()"~ LPF "INSERT_UI_BLOCK" STR_VAR new_block = EVAL "%removeabilitynamemarker%" find_block = EVAL ~`[ %TAB%%LNL%%MNL%%WNL%]*menu[ %TAB%%LNL%%MNL%%WNL%]*{[ %TAB%%LNL%%MNL%%WNL%]*name[ %TAB%]+'MAGE_CONTINGENCY'~ END // Remove added strings in tooltip FOR (button = 0; button < 12; button += 1) BEGIN REPLACE_TEXTUALLY EXACT_MATCH ~tooltip lua "actionBarTooltip[%button%]"~ ~tooltip lua "removetooltipmarker(%button%)"~ END LPF "INSERT_UI_BLOCK" STR_VAR new_block = EVAL "%removetooltipmarker%" find_block = EVAL ~`[ %TAB%%LNL%%MNL%%WNL%]*menu[ %TAB%%LNL%%MNL%%WNL%]*{[ %TAB%%LNL%%MNL%%WNL%]*name[ %TAB%]+"WORLD_ACTIONBAR"~ END END ELSE BEGIN PATCH_FAIL "Unable to patch UI.menu: component aborted" END BUT_ONLY // Pad name of every single spell COPY_EXISTING_REGEXP GLOB "^.+\.spl$" "override" PATCH_IF SOURCE_SIZE > 0x71 BEGIN // Sanity check PATCH_IF LONG_AT 0x8 > 0 AND LONG_AT 0x8 < 1000000 BEGIN // If valid spell name READ_STRREF 0x8 spell_name_text PATCH_IF NOT "%spell_name_text%" STRING_EQUAL_CASE "" AND NOT "%spell_name_text%" STRING_MATCHES_REGEXP "<\(NO TEXT\|Not Available\|Invalid Reference\|Invalid Strref\).*>" = 0 BEGIN // If valid spell name SPRINT pad_spl_name "" // Reset to default value PATCH_PHP_EACH "HIDE_SPELL_FEEDBACK" AS input_conditions => input_feedback BEGIN PATCH_IF VARIABLE_IS_SET $HIDE_SPELL_FEEDBACK_MARKER("%input_feedback%") AND "%pad_spl_name%" STRING_EQUAL_CASE "" BEGIN // Proceed only if corresponding variable is set in $HIDE_SPELL_FEEDBACK_MARKER & %pad_spl_name% is still undetermined // Extract input variables (i.e. %input_resmask% is set to regexp after "resmask:") PATCH_FOR_EACH input_type IN // list of possible inputs resmask idsmask spelltype spelllevel castinggraphics BEGIN PATCH_IF "%input_conditions%" STRING_CONTAINS_REGEXP "%input_type%:[^,; %TAB%%LNL%%MNL%%WNL%]+" = 0 BEGIN INNER_PATCH_SAVE EVAL "input_%input_type%" "%input_conditions%" BEGIN REPLACE_TEXTUALLY "^.*\(%input_type%:\)" "" // clear everything up to and including "resmask:" REPLACE_TEXTUALLY "[,; %TAB%%LNL%%MNL%%WNL%]+.*$" "" // clear everything after input regexp END END ELSE BEGIN SPRINT EVAL "input_%input_type%" ".*" // Set variable input_%input_type% to default value END END // Transform input feedback variable if set to tra entry PATCH_IF "%input_feedback%" STRING_MATCHES_REGEXP "^[@#]?\(0x\)?\([0-9]+\)$" = 0 BEGIN LPF "STRING_TO_TRA" STR_VAR input_string = EVAL "%input_feedback%" RET use_feedback = output_string END END ELSE BEGIN SPRINT use_feedback "%input_feedback%" END // Compare parameters of current spell if it matches SET matching_input = 0 // set to true by default // Check resmask PATCH_IF "%SOURCE_RES%" STRING_MATCHES_REGEXP "%input_resmask%" = 1 BEGIN // If regexp is not matching SET matching_input = 1 // set to false END // Check idsmask (if spell is SPPR/SPWI/SPIN/SPCL...) & is set PATCH_IF "%input_idsmask%" STRING_COMPARE_CASE ".*" = 1 AND matching_input = 0 BEGIN PATCH_IF "%SOURCE_RES%" STRING_MATCHES_REGEXP "^SP\(PR\|WI\|IN\|CL\)[0-9][0-9][0-9]$" = 0 BEGIN INNER_PATCH_SAVE ids_num "%SOURCE_RES%" BEGIN REPLACE_TEXTUALLY "SPPR" "1" REPLACE_TEXTUALLY "SPWI" "2" REPLACE_TEXTUALLY "SPIN" "3" REPLACE_TEXTUALLY "SPCL" "4" END PATCH_IF FILE_CONTAINS_EVALUATED ("SPELL.IDS" "^%ids_num%[ %TAB%]+.+") BEGIN INNER_PATCH_FILE "SPELL.IDS" BEGIN REPLACE_EVALUATE "^%ids_num%[ %TAB%]+\([^ %TAB%%LNL%%MNL%%WNL%]+\)" BEGIN SPRINT read_ids_symbol "%MATCH1%" END "" END PATCH_IF "%read_ids_symbol%" STRING_MATCHES_REGEXP "%input_idsmask%" = 1 BEGIN // If regexp is not matching SET matching_input = 1 // set to false END END ELSE BEGIN SET matching_input = 1 // set to false END END ELSE BEGIN SET matching_input = 1 // set to false END END // Check spell type (i.e. wizard/priest) READ_SHORT 0x1c read_spelltype PATCH_IF "%read_spelltype%" STRING_MATCHES_REGEXP "%input_spelltype%" = 1 // If regexp is not matching AND matching_input = 0 BEGIN SET matching_input = 1 // set to false END // Check spell level READ_LONG 0x34 read_spelllevel PATCH_IF "%read_spelllevel%" STRING_MATCHES_REGEXP "%input_spelllevel%" = 1 // If regexp is not matching AND matching_input = 0 BEGIN SET matching_input = 1 // set to false END // Check casting graphics READ_SHORT 0x22 read_castinggraphics PATCH_IF "%read_castinggraphics%" STRING_MATCHES_REGEXP "%input_castinggraphics%" = 1 // If regexp is not matching AND matching_input = 0 BEGIN SET matching_input = 1 // set to false END PATCH_IF matching_input = 0 BEGIN // Modify description if spell passed all tests SPRINT pad_spl_name $HIDE_SPELL_FEEDBACK_MARKER("%input_feedback%") INNER_PATCH_SAVE spell_name_text "%spell_name_text%" BEGIN // Pad beginning of spell name INSERT_BYTES 0 (STRING_LENGTH "%pad_spl_name%") WRITE_ASCIIE 0 "%pad_spl_name%" (STRING_LENGTH "%pad_spl_name%") END SAY_EVALUATED 0x8 "%spell_name_text%" END END END END END END BUT_ONLY
    Post edited by Galactygon on
Sign In or Register to comment.