Jump to content

Convert Decimal FormID to Hexadecimal


dylbill

Recommended Posts

So I finally got a function working to convert a formID to Hexadecimal after using the .GetformId() function by converting first to binary and then to hex. Here's the relevant code if anyone is interested. Requires SKSE.

 

 

String[] Property HexDigits Auto 
String[] Property BinDigits Auto 
String[] Property EvenNumbers Auto
 
Event OnInit()
    InitArrays()
EndEvent 
 
Function InitArrays()
    BinDigits = New String[16]
    BinDigits[0] = "0000"
    BinDigits[1] = "0001"
    BinDigits[2] = "0010"
    BinDigits[3] = "0011"
    BinDigits[4] = "0100"
    BinDigits[5] = "0101"
    BinDigits[6] = "0110"
    BinDigits[7] = "0111"
    BinDigits[8] = "1000"
    BinDigits[9] = "1001"
    BinDigits[10] = "1010"
    BinDigits[11] = "1011"
    BinDigits[12] = "1100"
    BinDigits[13] = "1101"
    BinDigits[14] = "1110"
    BinDigits[15] = "1111"
 

    HexDigits = New String[16]
    HexDigits[0] = "0"
    HexDigits[1] = "1"
    HexDigits[2] = "2"
    HexDigits[3] = "3"
    HexDigits[4] = "4"
    HexDigits[5] = "5"
    HexDigits[6] = "6"
    HexDigits[7] = "7"
    HexDigits[8] = "8"
    HexDigits[9] = "9"
    HexDigits[10] = "a"
    HexDigits[11] = "b"
    HexDigits[12] = "c"
    HexDigits[13] = "d"
    HexDigits[14] = "e"
    HexDigits[15] = "f"
    
    EvenNumbers = New String[5]
    EvenNumbers[0] = "0"
    EvenNumbers[1] = "2"
    EvenNumbers[2] = "4"
    EvenNumbers[3] = "6"
    EvenNumbers[4] = "8"
EndFunction

 
String Function ConvertIDToHex(Int IDToConvert)
    If IDToConvert >= 0
        Int A = IDToConvert
        String IntBinary
        If EvenNumbers.Find(StringUtil.GetNthChar(A, (StringUtil.GetLength(A as string) - 1))) > -1
            IntBinary = ("0")
        Else 
            IntBinary = ("1")
        Endif 
        
        Utility.WaitMenuMode(0.1)
        
        While A > 1
            A /= 2
            
            If EvenNumbers.Find(StringUtil.GetNthChar(A, (StringUtil.GetLength(A as string) - 1))) > -1
                IntBinary = ("0" + IntBinary)
            Else 
                IntBinary = ("1" + IntBinary)
            Endif 
            
            If A <= 1
                
                Float decCheck = ((StringUtil.GetLength(IntBinary) as float) / 4)
                Float decRemainder = decCheck - Math.Floor(decCheck)
                
                If decRemainder == 0.25
                    IntBinary = "000" + IntBinary
                Elseif decRemainder == 0.5
                    IntBinary = "00" + IntBinary
                Elseif decRemainder == 0.75
                    IntBinary = "0" + IntBinary
                Endif
                
                ;Debug.MessageBox("Bin is " + IntBinary)
                Utility.Wait(0.1)
                Return ConvertBinaryToHex(IntBinary)
            Endif
        EndWhile
    Else 
        Int A = ((IDToConvert - (IDToConvert * 2)) - 1) ;converts negative to positive.
        String IntBinary
        If EvenNumbers.Find(StringUtil.GetNthChar(A, (StringUtil.GetLength(A as string) - 1))) > -1
            IntBinary = ("1")
        Else 
            IntBinary = ("0")
        Endif 
        
        Utility.WaitMenuMode(0.1)
        
        While A > 1
            A /= 2
            
            If EvenNumbers.Find(StringUtil.GetNthChar(A, (StringUtil.GetLength(A as string) - 1))) > -1
                IntBinary = ("1" + IntBinary)
            Else 
                IntBinary = ("0" + IntBinary)
            Endif 
            
            If A <= 1
                
                Float decCheck = ((StringUtil.GetLength(IntBinary) as float) / 4)
                Float decRemainder = decCheck - Math.Floor(decCheck)
                
                If decRemainder == 0.25
                    IntBinary = "111" + IntBinary
                Elseif decRemainder == 0.5
                    IntBinary = "11" + IntBinary
                Elseif decRemainder == 0.75
                    IntBinary = "1" + IntBinary
                Endif
                
                ;Debug.MessageBox("Bin is " + IntBinary)
                Utility.Wait(0.1)
                Return "ff" + ConvertBinaryToHex(IntBinary)
            Endif
        EndWhile
    Endif 
EndFunction
 
String Function ConvertBinaryToHex(String BinToConvert)
    String HexResult
    Int I = -4
    Int M = (StringUtil.GetLength(BinToConvert) - 1)
    While I < M
        I += 4
        If I < M
            String Bin4 = (StringUtil.Substring(BinToConvert, I, 4))
            HexResult = (HexResult + HexDigits[BinDigits.Find(Bin4)])
        Else
           Return  HexResult
        Endif
    EndWhile
EndFunction
 

Event SomeEvent()
    String HexID =  ConvertIDToHex(SomeForm.GetformId())
EndEvent

 

 

My Question is, does anybody know if negative FormID's always start with FF? Because that's what this function assumes. I've tried looking around skyrim for negative ID's and this seems to be the case. Negative IDs occure when using placeAtMe to create new object references, and they all seem to start with FF too. Any help would be appreciated!

 

 

Link to comment
Share on other sites

I guess I should be more specific. Sometimes when calling the .GetFormId() function, it returns a negative number, and yes I've found this is for created items in game. Example: -16773862 according to Skyrim is FF000D1A in hex. According to a programmer calculator it is FFFF FFFF FF00 0D1A‬. If I didn't put an FF in front manually for the negative number, my function would return 000D1A. I was wondering if it's always an FF in front for negative ID's, or if there are exceptions. I also remember when I was trying to do this a while ago, the mod follower Recorder returned a negative ID, so I'm just trying to make sure the function is accurate.

Edited by dylbill
Link to comment
Share on other sites

Didn't you aware of using modulo? So there is not required any SKSE function.

 

maybe next function is working as you like

 

;---------------------------------------------------------------
 String FUNCTION Dec2Hex(Int m, String sAdd="", Bool bAdd=False) ;Global
;---------------------------------------------------------------
; convert integer (i10) into hexstring with count of 8 numbers
; sample: 842 -> "0000034A"

; 842  = 8*10² + 4*10 + 2*1        ; base 10
; 34Ah = 3*16² + 4*16 + A*1        ; base 16

    string s

int v = 0x10000000            ; init divisor
    WHILE (v > 0)
        int j = m / v

        IF     (j < 10)
                            s += j as String
        ELSEIF (j == 10)
                            s += "A"
        ELSEIF (j == 11)
                            s += "B"
        ELSEIF (j == 12)
                            s += "C"
        ELSEIF (j == 13)
                            s += "D"
        ELSEIF (j == 14)
                            s += "E"
        ELSE ;IF (j == 15)
                            s += "F"
;;        ELSE
;;            s += "?"
        ENDIF

        m = m % v            ; new remainder as result of modulo

        IF (v > 1)
            v = v / 16       ; new divisor
        ELSE
            v = 0            ; 1 / 16 = ?    safety first
        ENDIF
    ENDWHILE

IF ( bAdd )                  ; appendix
    RETURN (s + sAdd)
ENDIF
;---------
    RETURN (sAdd + s)        ; prefix by default
ENDFUNCTION

 

 

Edited by ReDragon2013
Link to comment
Share on other sites

Hey thanks, I didn't think of using modulo. You still have to account for negative numbers though. I modified your code to do so and it works!

 

 

 

 
String function Dec2Hex(Int m, String sAdd="", Bool bAdd=False) ;Global
;---------------------------------------------------------------
; convert integer (i10) into hexstring with count of 8 numbers
; sample: 842 -> "0000034A"
 
; 842  = 8*10² + 4*10 + 2*1        ; base 10
; 34Ah = 3*16² + 4*16 + A*1        ; base 16
 
    If m >= 0
 
        string s
 
        int v = 0x10000000            ; init divisor
            WHILE (v > 0)
                int j = m / v
 
                IF     (j < 10)
                                    s += j as String
                ELSEIF (j == 10)
                                    s += "A"
                ELSEIF (j == 11)
                                    s += "B"
                ELSEIF (j == 12)
                                    s += "C"
                ELSEIF (j == 13)
                                    s += "D"
                ELSEIF (j == 14)
                                    s += "E"
                ELSE ;IF (j == 15)
                                    s += "F"
        ;;        ELSE
        ;;            s += "?"
                ENDIF
 
                m = m % v            ; new remainder as result of modulo
 
                IF (v > 1)
                    v = v / 16       ; new divisor
                ELSE
                    v = 0            ; 1 / 16 = ?    safety first
                ENDIF
            ENDWHILE
 
        IF ( bAdd )                  ; appendix
            RETURN (s + sAdd)
        ENDIF
        ;---------
        RETURN (sAdd + s)        ; prefix by default
    Else
        m += 1
        string s
        
        int v = 0x10000000            ; init divisor
            WHILE (v > 0)
                int k = m / v
                int j = 15 - (k - (k * 2)) ;converts negative to positive and inverts
 
                IF     (j < 10)
                                    s += j as String
                ELSEIF (j == 10)
                                    s += "A"
                ELSEIF (j == 11)
                                    s += "B"
                ELSEIF (j == 12)
                                    s += "C"
                ELSEIF (j == 13)
                                    s += "D"
                ELSEIF (j == 14)
                                    s += "E"
                ELSE ;IF (j == 15)
                                    s += "F"
        ;;      ELSE
        ;;            s += "?"
                ENDIF
 
                m = m % v            ; new remainder as result of modulo
 
                IF (v > 1)
                    v = v / 16       ; new divisor
                ELSE
                    v = 0            ; 1 / 16 = ?    safety first
                ENDIF
            ENDWHILE
 
        IF ( bAdd )                  ; appendix
            RETURN (s + sAdd)
        ENDIF
        ;---------
        RETURN (sAdd + s)        ; prefix by default
    Endif 
ENDFUNCTION
 

 

 

 

Thanks a bunch!

Edited by dylbill
Link to comment
Share on other sites

One more thing, using the hexDigits array is faster than using the if, andif conditions. So here's the code modified for that:

 

 

 

 

 
String[] Property HexDigits Auto
 
Event OnInit()
    InitArrays()
EndEvent 
 
Function InitArrays()
    HexDigits = New String[16]
    HexDigits[0] = "0"
    HexDigits[1] = "1"
    HexDigits[2] = "2"
    HexDigits[3] = "3"
    HexDigits[4] = "4"
    HexDigits[5] = "5"
    HexDigits[6] = "6"
    HexDigits[7] = "7"
    HexDigits[8] = "8"
    HexDigits[9] = "9"
    HexDigits[10] = "a"
    HexDigits[11] = "b"
    HexDigits[12] = "c"
    HexDigits[13] = "d"
    HexDigits[14] = "e"
    HexDigits[15] = "f"
 
EndFunction
 
String function Dec2Hex(Int m, String sAdd="", Bool bAdd=False) ;Global
;---------------------------------------------------------------
; convert integer (i10) into hexstring with count of 8 numbers
; sample: 842 -> "0000034A"
 
; 842  = 8*10² + 4*10 + 2*1        ; base 10
; 34Ah = 3*16² + 4*16 + A*1        ; base 16
 
    If m >= 0
 
        string s
 
        int v = 0x10000000            ; init divisor
            WHILE (v > 0)
                int j = m / v
                
                s += HexDigits[j]
 
                m = m % v            ; new remainder as result of modulo
 
                IF (v > 1)
                    v = v / 16       ; new divisor
                ELSE
                    v = 0            ; 1 / 16 = ?    safety first
                ENDIF
            ENDWHILE
 
        IF ( bAdd )                  ; appendix
            RETURN (s + sAdd)
        ENDIF
        ;---------
        RETURN (sAdd + s)        ; prefix by default
    Else
        m += 1
        string s
        
        int v = 0x10000000            ; init divisor
            WHILE (v > 0)
                int k = m / v
                int j = 15 - (k - (k * 2)) ;converts negative to positive and inverts
                
                s += HexDigits[j]
 
                m = m % v            ; new remainder as result of modulo
 
                IF (v > 1)
                    v = v / 16       ; new divisor
                ELSE
                    v = 0            ; 1 / 16 = ?    safety first
                ENDIF
            ENDWHILE
 
        IF ( bAdd )                  ; appendix
            RETURN (s + sAdd)
        ENDIF
        ;---------
        RETURN (sAdd + s)        ; prefix by default
    Endif 
ENDFUNCTION
 

 

 

 

Thanks again!

Link to comment
Share on other sites

One last tweak. For negative numbers you can just use another array to find the hex digit, instead of turning to positive and inverting:

 

 

 

 
String[] Property HexDigits Auto
Int[] Property NegativeDecDigits Auto
 
Event OnInit()
    InitArrays()
EndEvent 
 
Function InitArrays()
    HexDigits = New String[16]
    HexDigits[0] = "0"
    HexDigits[1] = "1"
    HexDigits[2] = "2"
    HexDigits[3] = "3"
    HexDigits[4] = "4"
    HexDigits[5] = "5"
    HexDigits[6] = "6"
    HexDigits[7] = "7"
    HexDigits[8] = "8"
    HexDigits[9] = "9"
    HexDigits[10] = "a"
    HexDigits[11] = "b"
    HexDigits[12] = "c"
    HexDigits[13] = "d"
    HexDigits[14] = "e"
    HexDigits[15] = "f"
 
    NegativeDecDigits = New Int[16]
    NegativeDecDigits[0] = -15
    NegativeDecDigits[1] = -14
    NegativeDecDigits[2] = -13
    NegativeDecDigits[3] = -12
    NegativeDecDigits[4] = -11
    NegativeDecDigits[5] = -10
    NegativeDecDigits[6] = -9
    NegativeDecDigits[7] = -8
    NegativeDecDigits[8] = -7
    NegativeDecDigits[9] = -6
    NegativeDecDigits[10] = -5
    NegativeDecDigits[11] = -4
    NegativeDecDigits[12] = -3
    NegativeDecDigits[13] = -2
    NegativeDecDigits[14] = -1
    NegativeDecDigits[15] = 0
 
EndFunction
 
String function ConvertIDToHex(Int m)
;---------------------------------------------------------------
; convert integer (i10) into hexstring with count of 8 numbers
; sample: 842 -> "0000034A"
 
; 842  = 8*10² + 4*10 + 2*1        ; base 10
; 34Ah = 3*16² + 4*16 + A*1        ; base 16
 
    If m >= 0
 
        string s
 
        int v = 0x10000000            ; init divisor
            While (v > 0)
                int j = m / v
                s += HexDigits[j]
                
                m = m % v            ; new remainder as result of modulo
 
                If (v > 1)
                    v = v / 16       ; new divisor
                Else
                    v = 0            ; 1 / 16 = ?    safety first
                Endif
            Endwhile
            
        Return (s)
    Else
        m += 1
        string s
        
        int v = 0x10000000            ; init divisor
            While (v > 0)
                int j = m / v
                
                s += HexDigits[(NegativeDecDigits.Find(j))]
 
                m = m % v            ; new remainder as result of modulo
 
                If (v > 1)
                    v = v / 16       ; new divisor
                Else
                    v = 0            ; 1 / 16 = ?    safety first
                Endif
            Endwhile
            
        return (s)
    Endif 
EndFunction
 

 

 

Edited by dylbill
Link to comment
Share on other sites

I do not believe it's a good idea to use array(s) for this kind of function. I would like to use that as convenience without any initialization.

My final version would look as follow with minimum of function variables inside. Just in case the parameters for string and bool may be stripped, if that is desired

the last code lines for appending a string to the return value should be removed as well.

 

 

 

;-----------------------------------------------------------
 String FUNCTION Dec2Hex(Int n, String sA="", Bool bA=False) Global
;-----------------------------------------------------------
; sample: 842 -> "0000034A"

; 842  = 8*10² + 4*10 + 2*1          ; base 10
; 34Ah = 3*16² + 4*16 + A*1          ; base 16

; convert a signed integer (longint32) into unsigned doubleword as hexstring
; positive: 0x0        .. 0x7fffffff
; negative: 0x80000000 .. 0xffffffff

int T                                ; Zero by default
    IF (n < 0)
        n = 0x7FFFFFFF + n + 1       ; transform negative to positive  (2147483647 == 0x7FFFFFFF)
        T = 8
    ENDIF
    T = (n / 0x10000000) + T         ; store leading halfbyte

string s                             ; "" by default
int j
int i = 8                            ; minimum length of string (that will be the return value)
    WHILE (i)            ; (i > 0)
        i = i - 1

        IF (i)
            j = n % 16               ; n iMODULO 16 == (n AND 15)
            n = n / 16               ; n iDIV 16    == (n SHR 4)
        ELSE
            j = T                    ; get stored halfbyte
        ENDIF

        IF     (j < 10)
                    s = (j as String) + s    ; "0" .. "9"

        ELSEIF (j > 13)
            IF (j == 15)
                    s = "f" + s
            ELSE
                    s = "e" + s
            ENDIF
        ELSEIF (j > 11)
            IF (j == 13)
                    s = "d" + s
            ELSE
                    s = "c" + s
            ENDIF
        ELSE
            IF (j == 11)
                    s = "b" + s
            ELSE
                    s = "a" + s
            ENDIF
        ENDIF
    ENDWHILE                
;    -------------------------------- append parameter string
    IF ( bA )
        s = s + sA        ; as suffix
    ELSE
        s = sA + s        ; as prefix (by default)
    ENDIF
    RETURN s

ENDFUNCTION

 

 

Edited by ReDragon2013
Link to comment
Share on other sites

  • Recently Browsing   0 members

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