Jump to content

MODDER TIPS - Read if you're modding. Post if you discovered a trick


Recommended Posts

MODDER TIPS

Read if you're modding.

Post if you discovered a trick

 

This topic is NOT meant as a request topic, so please do not ask for support.   This thread is meant as a repository of tips and insight from modders (script writers, modelers, map makers, etc.) to share what extra tips and tricks that they had learned.

 

As not everyone may be up on new techniques, I hope this thread will be useful to those reading.  And as updates might be made to software (such as the OBSE) which might not have been advertised, members may be encouraged to recount the documentation.  I myself would not have been aware of one such instance had it not been for Akor two weeks ago. 

 

So if a member does learn of a technique, he/she is encouraged to begin their post with BIG STRONG BOLD TEXT for a brief title to their learned  trick, followed by an explanation of the trick and what led them to recognizing it.

 

 

* === * === * === *

 

 

READING USABLE STRINGS FROM INI

 

This assumes you know how to make a 'quest' script that reads an INI file.  I came up with a method that reads from an .INI file to read string data which can be used to load data from other mods.  In essence, you

can have an INI file that contains the name of another mod, and the Hex Form ID of an object in which to check.  While some mods may be able to test for the existence of another with hard-coded commands, this lets one make an INI file which can be expanded.

 

An example script appears below:

 

scn xLoversExampleScript

short DoOnce

string_var IniModName01   ;; Filename of a Mod that can be loaded
string_var IniModHxID01   ;; Form ID you are trying to load from the mod

string_var testfile       ;; Temporary string values
string_var testhex        ;; Temporary string values

Ref RefExModObject        ;; Actual Form loaded from the mod
short bExModLoaded        ;; (0/1) if the mod and form was loaded 

;; Game System Function
Begin GameMode


	;; Upon game start/restart
	if GetGameLoaded || GetGameRestarted
		;; If data not loaded
		if DoOnce == 0

			;; Set empty/default values

			let IniModName01 := ""      ;; A vacancy for loaded string
			let IniModHxID01 := ""      ;; A vacancy for loaded string
			set bExModLoaded to 0       ;; Set Mod loaded value to not-loaded (0)


			;; Load the INI if present
			if FileExists "Data\ini\LAPF_Example.ini"
				RunBatchScript "Data\ini\LAPF_Example.ini"
				printC "LAPF Example INI loaded"
			else
				printC "LAPF Example using default values"
			endif

			;; Load a mod if it exists...
			set testfile	to IniModName01
			set testhex	to IniModHxID01
			
			if IsModLoaded $testfile
				let RefExModObject := GetFormFromMod $testfile $testhex
				set bExModLoaded to testtype
			endif

			;; Turn data loaded switch on
		;	Set DoOnce to 1
		endif
	endif


End

 

This assumes that the script is a QUEST script, and that the INI file is something simple like below:

 

xLoversExampleScript.ini


; Example INI file mod and Hex ID (detects Horse Riding Gear)
  set IniModName01 to sv_construct "LoversHorseRider.esp"
  set IniModHxID01 to sv_construct "002384"

 

:blush:   I hope Fejeena appreciates I looked into Horse Rider as an example.

 

The example script uses two values, IniModName01 and INIModHxID01, which is meant to hold the name of a mod and the form ID of an object within that mod.  For this, I had to use the string_var command in the script to identify these two values as string values.

 

Further down, and within the GameMode function, I ensured the two values were empty strings with the let command:   Let string_value := ""    That's pretty simple, and sets up the values as default values assuming the necessary INI wasn't found.  And to be honest, this string would work in messagebox commands.  But it does NOT work in an actual OBSE command.

 

After this, I used a basic 'Load the INI file' system.  It's fairly commonplace, and I am using printC commands to send messages to the console for debugging purposes.

 

If there is an INI file, and the appropriate data is loaded, I pass the data from  IniModName01 and INIModHxID01 into temporary strings.  It may seem odd, but I've come to use temporary values or placeholders in my work to prevent or bypass some limitations.  This is definitely the case when testing forms read from outside mods in scripts other than the central quest script.  But that could be another discussion.

 

Now the last part is important.   The 'IsModLoaded' and the 'GetFormFromMod' commands cannot accept string data unless the string has the '$' prefix attached to the name.  This actual issue may not have been apparent.  It wasn't to me when I first attempted to use string data in these commands.  To be honest, I tried testing this without reading INI data (using hardcoded strings) and initially failed.   If not for Akor with the post below, this technique would not have been learned.

On 3/18/2018 at 6:38 AM, Akor said:

 

Quote

As of OBSE v0017, string variables can be passed to any command expecting a string literal as an argument by prefacing the name of the variable with a dollar sign. This deprecates many of the Set...EX commands. The variable must be local to the calling script and its name must immediately follow the '$' without parentheses.

 

Example:

    string_var msg
    let msg := "Greetings from Stonekeep, " + player.GetName + "!!!"
    MessageBox $msg

 

 

And of the INI file itself, please note that the two lines holding string data use the string value construct command (sv_construct)  to create the string data itself.

 

 

 

* === * === * === *

 

Now it's your turn :smiley:    Unless I make another post first.

Link to comment
  • 3 weeks later...

RETRIEVING VALUES FROM A STRING-BASED ARRAY

 

These are a number of scripts  I developed recently in my modding adventures, whether  to retrieve a value for the LoversQuest.SPos valuefor Sex Animation Position or to obtain Clothing FormIDs from a list.  However, these could be used to retrieve numeric or string data data from any string that is shaped as a  data array.

 

The scripts assume that the data being returned will be valid data.  But if it cannot generate valid data, the ones that return numeric data includes a contingency command to use LAPF's native xLoversCmnGetRandomSPos call to generate a valid substitute in the event of an emergency.  Still, a properly formatted call with valid data should generate proper data.

 

The string value must be a string such as "1,2,3,4,5", or even something as simple as "2".  The string must be a valid string with one or more arguments with a comma separating each value (no spaces).

 

 

 

Insofar as the four scripts, these are the valid commands:

 

value = Call xLDDStrGetSize

value = Call xLDDStrRndPose stringvalue

value = Call xLDDStrSetPose stringvalue index

  stringvalue = Call xLDDStrGetString stringvalue index

The index value begins at 0.  So the first value in the array is position 0, the 2nd value is at index position 1, etc.

 

 

 

And these are the two FOUR scripts...

 

StringArray - Get Size

scn xLDDStrGetSize

; FUNCTION:  Determines the size of a string array 
; STATUS:    New
; USAGE:     Called from 'xLSTTokenFixArrayCreate' script


;; Define values for script
string_var sArgsList       ; Function Parameter:  The string array containing the individual strings
short iReturn              ; Function Return:     The returned size of the array
array_var aArgsArray       ; Variable:            The generated Array of strings
short iCount               ; Variable:            Determined length of the string


; Call function in the following manner:
; value = Call xLDDStrGetSize stringvalue
; Example:  let iSize := xLDDStrGetSize xFuk.MisPose
;           Assumes xFuk is a quest, the value of MisPose is a string
;           and it returns the number of valid arguments into iSize


;; Define script function
begin function { sArgsList }


    ;; Set the return value, and get ready to exit if no valid length
    set iReturn to 0
    SetFunctionValue iReturn


    ;; Test string length and exit if no data
    let iCount := sv_Length sArgsList
    if iCount == 0
        return
    endif


    ;; Convert the string into an array
    let aArgsArray := sv_Split sArgsList ","


    ;; Determine the size of the Array
    let iReturn := ar_size aArgsArray


    ;; Eliminate the Array
    let aArgsArray := ar_null


    ;; Set the return value and exit
    SetFunctionValue iReturn
    return


End

 

StringArray - Random Pose

scn xLDDStrRndPose


string_var sPoseList     ; The string containing the poses
array_var aPoseArray     ; The generated Array of poses
short iArraySize         ; The size of the array
short iArrayIdx          ; The index position in the array
short iReturn            ; The Returned value for the function


; Call function in the following manner:
; value = Call xLDDStrRndPose stringvalue


begin function { sPoseList }


	printc "LDD Rand Pose:  List is %z" sPoseList


	;; Set default return value
	let iReturn := 0


	;; Convert the string into an array
	let aPoseArray := sv_Split sPoseList ","


	;; Determine the size of the Array
	let iArraySize := ar_size aPoseArray


	;; For a Valid Array (At least 1 param in size)
	if iArraySize >= 1
		; Set the random index position (Random choice!)
		set iArrayIdx to Rand 0 iArraySize
		; if the random position is too large, reduce by 1
		if iArrayIdx == iArraySize
			set iArrayIdx to (iArrayIdx - 1)
		endif
		; Obtain the data from the array by index position
		let iReturn := tonumber aPoseArray[iArrayIdx]
	;; Otherwise, Randomize
	else
		Let iReturn := Call xLoversCmnGetRandomSPos 11111
	endif


	;; Eliminate the Array
	let aPoseArray := ar_null


	printc "LDD Rand Pose:  Generated %.0f" iReturn


	;; Set the return value and exit
	SetFunctionValue iReturn
	return


End

 

 

StringArray - Set Pose

scn xLDDStrSetPose


string_var sPoseList     ; The string containing the poses
array_var aPoseArray     ; The generated Array of poses
short iArraySize         ; The size of the array
short iArrayIdx          ; The index position in the array
short iReturn            ; The Returned value for the function


; Call function in the following manner:
; value = Call xLDDStrSetPose stringvalue index
; Example:  let SPos := xLDDStrSetPose xFuk.MisPose 2
;           Assumes xFuk is a quest, the value of MisPose is a string
;           and choosing index #2 (or 3rd pose in list)


begin function { sPoseList iArrayIdx }


	printc "LDD Set Pose:  List is %z" sPoseList


	;; Set default return value
	let iReturn := 0


	;; Convert the string into an array
	let aPoseArray := sv_Split sPoseList ","


	;; Determine the size of the Array
	let iArraySize := ar_size aPoseArray


	;; For a Valid Array (At least 1 param in size)
	if iArraySize >= 1
		; if the index position is too large, reduce by 1
		if iArrayIdx > (iArraySize - 1)
			set iArrayIdx to (iArrayIdx - 1)
		endif
		; Obtain the data from the array by index position
		let iReturn := tonumber aPoseArray[iArrayIdx]
	;; Otherwise, Randomize
	else
		Let iReturn := Call xLoversCmnGetRandomSPos 11111
	endif


	;; Eliminate the Array
	let aPoseArray := ar_null


	printc "LDD Set Pose:  Generated %.0f" iReturn


	;; Set the return value and exit
	SetFunctionValue iReturn
	return


End

 

StringArray - Get String

scn xLDDStrGetString


string_var sStringList   ; The string array containing the individual strings
array_var aStringArray   ; The generated Array of strings
short iArraySize         ; The size of the array
short iArrayIdx          ; The index position in the array
string_var iReturn       ; The Returned value for the function


; Call function in the following manner:
; value = Call xLDDStrGetString stringvalue index
; Example:  let sString := xLDDStrGetString xFuk.TehStringList 2
;           Assumes xFuk is a quest, the value of TehStringList is a string
;           and choosing index #2 (or 3rd pose in list)


begin function { sStringList iArrayIdx }


    printc "LDD Get String:  List is %z" sStringList


    ;; Set default return value
    let iReturn := ""


    ;; Convert the string into an array
    let aStringArray := sv_Split sStringList ","


    ;; Determine the size of the Array
    let iArraySize := ar_size aStringArray


    ;; For a Valid Array (At least 1 param in size)
    if iArraySize >= 1
        ; if the index position is too large, reduce by 1
        if iArrayIdx > (iArraySize - 1)
            set iArrayIdx to (iArrayIdx - 1)
        endif
        ; Obtain the data from the array by index position
        let iReturn := aStringArray[iArrayIdx]
    endif


    ;; Eliminate the Array
    let aStringArray := ar_null


    printc "LDD Get String:  Generated %z" iReturn


    ;; Set the return value and exit
    SetFunctionValue iReturn
    return


End

 

The first command is the easiest to understand.  It just acquires the number of arguments in the array, or 'How many Items' in plain terms.  So using the command to look at an array of  "Fred,Barry,Aw,Thit" would let the command return 4.

 

set iSize to Call xLDDStrGetSize XLovers.CurseWords       ... Generates '2' if the array resembles:  "Fucker,Asshole"

 

 

So between the next two commands that acquire numeric data, I could have a string for missionary poses like "113,116,120,125" in some arbitrary value called XLovers.Missionary.  And I could use the following calls:

 

 

set xLoversQuest.SPos to Call xLDDStrRndPose XLovers.Missionary       ... Generates any one of the four values:  113, 116, 120 or 125

set xLoversQuest.SPos to Call xLDDStrSetPose XLovers.Missionary 2     ... Going by Index value #2, it generates only one specific value:  120

 

 

And lastly, the final command is much like the first that retrieves a specific number from an array by its ID.  That is, from a list of words in the array, I can pick and choose which one just by selecting its ID.    So with an arbitrary string like "Bill,Feathers,Webbed,Quack,Duck", in a value like xLoversBirdbrain, I could use the following call and shove the string into a string value of WTF:

 

set xLoversQuest.WTF to Call xLDDStrSetPose XLovers.Birdbrain 3     ... Going by Index value #3, it generates the 4th object ("Quack") in the array.

 

Just remember... Arrays begin counting at position 0, not 1.  So the 1st item is index 0,

the 2nd item is at index 1, the 3rd item is at index 2, and so on.

 

Simple, but effective.  Enjoy.  :smiley:

 

 

 

Link to comment
  • 1 month later...

TRANSLATIONS FROM OTHER LANGUAGES (Primarily Japanese)

 

PART I:   Directly Translating a Mod

 

I just tried something. 

  • I downloaded an 'original' Japanese Mod.
  • Made a temporary copy to screw with.  Let's say the mod is "LoversImmoralGuards - Copy.esp"
  • I changed the .esp extension of the temporary mod copy to .html  Okay, now it's "LoversImmoralGuards - Copy.html"
  • I opened up the temporary mod in my browser.  Yeah, it looks like garbage.
  • While the mod.html is loaded, I changed my browser's settings to read it as Japanese (Shift_JIS)

Instead of the expected garbage characters in with the scripts, I was able to see actual Japanese lettering and Kanji script which I could put through an actual translator.

 

It's working for the actual scripts. 

 

 

* === * === * === *

 

 

Part II:  Ripping from the Mod and Pasting.

 

This is a second technique I came up with.  It requires that your Browser allows you to 'edit' a web page.

  • I downloaded an 'original' Japanese Mod.
  • I downloaded some basic web page, so I can screw with it.  The name isn't important.  It could be Fred.html.
  • I open both the mod and the html page.  Important:  Use the default settings for my browser at this point.
  • I go to something in the Mod Editor that needs translation, it is bound to be showing garbage characters.  I highlight and copy a selection.
  • I hit 'Edit Page' in the web browser, and paste the copied text from the mod in place.  It still looks like garbage.
  • I then hit SAVE so the garbage text is now part of the webpage.
  • I reload the webpage, and then change the browser's settings to read it as Japanese (Shift_JIS).

The text that was formerly garbage in the mod now reads with Japanese lettering and Kanji script in the browser with the Japanese settings turned on.

 

And this bit works for race content (descriptions at the very least), and DIALOG!   I haven't tested it with scripts, but I have no doubts it would work otherwise.

 

 

 

* === * === * === *

 

This certainly works, and with the content appearing now in Japanese lettering, I can convert the text from Garbage to Japanese to English.  Currently, my endeavors are being performed with Google Translate.   Yeah, I said Google Translate.  Sue me.  :P

 

EXAMPLE:  The heading for Nec Mystic Humans (Copy) within the original Japanese version of LoversImmoralGuards:

 

  • Imperial‚Å‚àBreton‚Å‚àNord‚Å‚à‚È‚¢ƒqƒgŽí‘°BDaedra‚̉¤‚Ì‹Y‚ê‚©Aedra‚Ì_‚̉æô‚É‚æ‚袊«Aˆ½‚¢‚Í‘n‘¢‚³‚ꂽ‚à‚Ì‚ÆŽv‚í‚ê‚éB
  • ImperialでもBretonでもNordでもないヒト種族。Daedraの王の戯れかAedraの神の画策により召喚、或いは創造されたものと思われる。
  • A human race that is neither Imperial, Breton nor Nord. It seems to have been summoned or created by the play of the king of Daedra or by the gods of the god of Aedra.

 

And dialog from the same said mod, this particularly being "SNITCH" dialog that was removed from the current English Translations.

 

ふぅ~ん・・・どうするのかね?
Fuu ... what are you going to do?

 

ふふふ・・・さ� 、どうしようと言うの?
Hehehe ...  what are you saying?

 

さて・・・それで?
Well ... So?

 

ふぅ~ん・・・それでどうするの?
Fuu · · · · · What then?

 

 

This works just fine.  And for those using LoversVoiceSSPlus....   I guess you can have fun translating the garbage text that has not YET been translated and still reads as garbage.

 

Link to comment

Why not the good old Egg translator?

Add the Japanese database.  Start Egg traslator, open the esp/ESM and all gibberish text is in japanese.

Egg translator even shows you if in a script is something to translate, it highlight the scripts, so you can ignore all scripts without changes.

You copy the Japanese text and use Google translator (and laugh at the results) or another translator.

Spoiler

Dialogues

11ttt1.jpg

 

scripts

11ttt2.jpg

-------------------

And in LoversVoiceSSPlus are only 4-5 untranslated lines and I never saw them in game. ( But I translated the lines 1-2 years ago in my esp)

 

____________________

Which version of Immoral Guards?
The last version I translated was 1.02 ( and gregathit uploaded it...but you say it is not the rigth version? )
The last version is 1.02a but I never finished it because no japanese LL member wants to help.

https://www.loverslab.com/topic/50052-mod-translations-help/

There you find the work in progress esp with a text file with the not translated lines that no web translator was able to translate (nothing that makes sense )

Then I was frustrated that nobody help and I lost interest.

 

Link to comment

Oooh.  Another toy to try out!    An Egg to hatch!!!!  :D   Good for modders to use.   So yep, I approve.  But if one doesn't use it (or know about it), there's my version which works.

 

OFF-Topic:  Actually, XTOPIC02 has about 30 lines untranslated from the 3/4ths point down.   ?  Unless I have an older version?  Waaait.  1-2 years ago?  I had mine for like 5.  I might need to re-download.  :P

 

What I said was that the current versions of Immoral Guards eliminated an option for 'snitches'.  And as to the ImmoralGuards that has it, I went and snagged the oldest of the old available at 4Shared, with no dialog and practically nil in the scripts ever converted.   Talk about going back to basics, eh?  But again, that is another topic.  

Link to comment
  • 5 weeks later...

The 2nd post with the header that read:  RETRIEVING VALUES FROM A STRING-BASED ARRAY .......

 

It used to have only two scripts within,, one that retrieved a single random value from a string array, another that you choose by an index value.   I now added two others, one that retrieved string data (not much different from the one that retrieves numeric), and a simple routine that gets the size of the array.

 

All four assume that you use a comma  ( " , " )  as a separator between arguments.  You COULD use something else like the Vertical whatits symbol (" | ") instead.  You'd just have to adapt.

Link to comment

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use