diff --git a/Source/Scripts/_EQ_ItemRoulette_FormChunks.psc b/Source/Scripts/_EQ_ItemRoulette_FormChunks.psc index 76925fc..f92728e 100644 --- a/Source/Scripts/_EQ_ItemRoulette_FormChunks.psc +++ b/Source/Scripts/_EQ_ItemRoulette_FormChunks.psc @@ -1,30 +1,67 @@ Scriptname _EQ_ItemRoulette_FormChunks extends Form +Activator Property FormChunks Auto + Form[] Property Children Auto +String Property ChunkName Auto + +String Property StartName Auto +String Property EndName Auto + +String[] ChildNames +Bool ChildNamesInitialized + +String[] Function GetChildNames() + if !ChildNamesInitialized + String[] names = new String[127] + Int i = 0 + ChildNamesInitialized = True + + While(i < Children.Length) + Debug.Trace(i) + If Children[i] != None + names[i] = GetSortName(Children[i].GetName()) + Debug.Trace(names[i]) + Else + names[i] = "" + EndIf + i += 1 + EndWhile + + ChildNames = names + EndIf + + return ChildNames +EndFunction + +Bool Function StartsWith(String haystack, String needle) + return StringUtil.Find(haystack, needle, 0) == 0 +EndFunction + +String Function GetSortName(String name) + If StartsWith(name, "A ") + name = StringUtil.Substring(name, 2, StringUtil.GetLength(name) - 2) + ElseIf StartsWith(name, "The ") + name = StringUtil.Substring(name, 4, StringUtil.GetLength(name) - 4) + EndIf + + return name +EndFunction Function SortByName() ; based on "Optimized QuickSort - C Implementation" by darel rex finley (http://alienryderflex.com/quicksort/) Int[] Beg = new Int[127] Int[] End = new Int[127] - String[] Names = new String[127] - Int i = 0 + Int i Int L Int R Int swap Form piv String pivName - + String[] Names = GetChildNames() + Beg[0] = 0 End[0] = Children.Length - - While(i < Children.Length) - If Children[i] != None - Names[i] = Children[i].GetName() - Else - Names[i] = "" - EndIf - i += 1 - EndWhile i = 0 While (i >= 0) @@ -34,7 +71,7 @@ Function SortByName() piv = Children[L] pivName = Names[L] While (L < R) - While ((Names[R] >= pivName) && (L < R)) + While ((Names[R] == "" || Names[R] >= pivName) && (L < R)) R -= 1 EndWhile If (L < R) @@ -42,7 +79,7 @@ Function SortByName() Children[L] = Children[R] L += 1 EndIf - While ((Names[L] <= pivName) && (L < R)) + While ((pivName == "" || Names[L] <= pivName) && (L < R)) L += 1 EndWhile If (L < R) @@ -69,13 +106,16 @@ Function SortByName() i -= 1 EndIf EndWhile + + ChildNamesInitialized = False EndFunction Function SortByNameRecursive() SortByName() Int childIndex = 0 + Form child While childIndex < Children.Length - Form child = Children[childIndex] + child = Children[childIndex] _EQ_ItemRoulette_FormChunks subChunk = (child as _EQ_ItemRoulette_FormChunks) If(subChunk != None) subChunk.SortByNameRecursive() @@ -90,11 +130,148 @@ Function PrintNamesRecursive() Form child = Children[childIndex] _EQ_ItemRoulette_FormChunks subChunk = (child as _EQ_ItemRoulette_FormChunks) If(subChunk != None) - Debug.Trace("Chunk") + Debug.Trace("Chunk " + subChunk.ChunkName) subChunk.PrintNamesRecursive() ElseIf child != None Debug.Trace(child.GetName()) EndIf childIndex += 1 EndWhile +EndFunction + +String Function Disambiguate(String source, String prev, String next) + Int i = 0 + Int sourceLength = StringUtil.GetLength(source) + Int nextLength = StringUtil.GetLength(next) + Bool finished = False + String substr + if prev != "" + Int prevLength = StringUtil.GetLength(prev) + While !finished && i < sourceLength && i < prevLength + If StringUtil.GetNthChar(source, i) != StringUtil.GetNthChar(prev, i) + finished = True + Else + i += 1 + EndIf + EndWhile + EndIf + While i < sourceLength && i < nextLength + If StringUtil.GetNthChar(source, i) != StringUtil.GetNthChar(next, i) + return StringUtil.Substring(source, 0, i + 1) + EndIf + i += 1 + EndWhile + + return StringUtil.Substring(source, 0, i) +EndFunction + +Function FinishLastChunk(_EQ_ItemRoulette_FormChunks prevChunk, _EQ_ItemRoulette_FormChunks newChunk) + String prevChunkEndName = "" + if prevChunk != None + prevChunkEndName = prevChunk.EndName + EndIf + newChunk.ChunkName = Disambiguate(newChunk.StartName, prevChunkEndName, newChunk.EndName) +EndFunction + +Int Function FindMinIndex(Int[] indices, String[] names) + Form currentItem + Int minIndex = -1 + Int index + String min + String currentName + Int i = 0 + _EQ_ItemRoulette_FormChunks oldChunk + While i < Children.Length + oldChunk = (Children[i] as _EQ_ItemRoulette_FormChunks) + If oldChunk != None + index = indices[i] + If index < oldChunk.Children.Length + currentItem = oldChunk.Children[index] + If currentItem != None + currentName = names[i] + If minIndex == -1 || currentName < min + min = currentName + minIndex = i + EndIf + EndIf + EndIf + EndIf + i += 1 + EndWhile + + return minIndex +EndFunction + +_EQ_ItemRoulette_FormChunks Function GroupByName(ObjectReference placer) + _EQ_ItemRoulette_FormChunks groupChunks = ((placer.PlaceAtMe(FormChunks) as Form) as _EQ_ItemRoulette_FormChunks) + groupChunks.Children = new Form[127] + + Int[] indices = new Int[127] + Int i = 0 + While i < indices.Length + indices[i] = 0 + i += 1 + EndWhile + + Form currentItem + _EQ_ItemRoulette_FormChunks oldChunk + String[] names = new String[127] + i = 0 + While i < names.Length + oldChunk = (Children[i] as _EQ_ItemRoulette_FormChunks) + If oldChunk != None + names[i] = oldChunk.GetChildNames()[indices[i]] + EndIf + i += 1 + EndWhile + + Int chunkItemIndex = 5 + Int chunkIndex = -1 + Bool finishedScanningIndices = False + Int index + Int minIndex + _EQ_ItemRoulette_FormChunks newChunk + _EQ_ItemRoulette_FormChunks prevChunk + + While !finishedScanningIndices + finishedScanningIndices = True + minIndex = FindMinIndex(indices, names) + If minIndex > -1 + finishedScanningIndices = False + If chunkItemIndex >= 5 + chunkItemIndex = 0 + chunkIndex += 1 + prevChunk = newChunk + newChunk = ((placer.PlaceAtMe(FormChunks) as Form) as _EQ_ItemRoulette_FormChunks) + newChunk.Children = new Form[5] + groupChunks.Children[chunkIndex] = newChunk + EndIf + + index = indices[minIndex] + currentItem = (Children[minIndex] as _EQ_ItemRoulette_FormChunks).Children[index] + newChunk.Children[chunkItemIndex] = currentItem + if chunkItemIndex == 0 + newChunk.StartName = names[minIndex] + if prevChunk != None + prevChunk.ChunkName += "-" + Disambiguate(prevChunk.EndName, prevChunk.StartName, newChunk.StartName) + EndIf + ElseIf chunkItemIndex == newChunk.Children.Length - 1 + newChunk.EndName = names[minIndex] + FinishLastChunk(prevChunk, newChunk) + EndIf + indices[minIndex] = index + 1 + + names[minIndex] = "" + oldChunk = (Children[minIndex] as _EQ_ItemRoulette_FormChunks) + If oldChunk != None + If index + 1 < oldChunk.Children.Length + names[minIndex] = oldChunk.GetChildNames()[index + 1] + EndIf + EndIf + chunkItemIndex += 1 + EndIf + EndWhile + FinishLastChunk(prevChunk, newChunk) + + Return groupChunks EndFunction \ No newline at end of file diff --git a/Source/Scripts/_EQ_ItemRoulette_Main.psc b/Source/Scripts/_EQ_ItemRoulette_Main.psc index c4ae190..6b63a72 100644 --- a/Source/Scripts/_EQ_ItemRoulette_Main.psc +++ b/Source/Scripts/_EQ_ItemRoulette_Main.psc @@ -1,5 +1,13 @@ Scriptname _EQ_ItemRoulette_Main extends ReferenceAlias +Event OnItemAdded(Form baseItem, Int itemCount, ObjectReference itemRef, ObjectReference destContainer) + (GetOwningQuest() as _EQ_ItemRoulette_Quest).PlayerItemAdded(baseItem, itemCount, itemRef, destContainer) +EndEvent + +Event OnItemRemoved(Form baseItem, Int itemCount, ObjectReference itemRef, ObjectReference destContainer) + (GetOwningQuest() as _EQ_ItemRoulette_Quest).PlayerItemRemoved(baseItem, itemCount, itemRef, destContainer) +EndEvent + Event OnPlayerLoadGame() (GetOwningQuest() as _EQ_ItemRoulette_Quest).Main() EndEvent diff --git a/Source/Scripts/_EQ_ItemRoulette_Quest.psc b/Source/Scripts/_EQ_ItemRoulette_Quest.psc index af5df7b..d53d44c 100644 --- a/Source/Scripts/_EQ_ItemRoulette_Quest.psc +++ b/Source/Scripts/_EQ_ItemRoulette_Quest.psc @@ -9,6 +9,7 @@ Form[] SpawnedForms Form[] UnspawnedForms ObjectReference Roulette +Bool ShouldSortInventoryItems Int MAX_ITEMS Float UI_TRANSLATE_SPEED Float UI_DISTANCE @@ -50,9 +51,13 @@ Function Main() index += 1 EndWhile + ShouldSortInventoryItems = True + Debug.Trace("Item Roulette loaded") + Roulette = PlayerRef.PlaceAtMe(_EQ_ItemRoulette_Roulette) Roulette.SetMotionType(Roulette.Motion_Keyframed) + RegisterForModEvent("_EQ_ItemRoulette_Activate", "OnMyAction") VRIK.VrikAddGestureAction("_EQ_ItemRoulette_Activate", "Activate Item Roulette") RegisterForSingleUpdate(0.01) @@ -61,6 +66,11 @@ EndFunction Event OnUpdate() Float playerAngle = PlayerRef.GetAngleZ() + if ShouldSortInventoryItems + ShouldSortInventoryItems = False + SortInventoryItems() + EndIf + Int index = 0 While index < MAX_ITEMS Form unspawnedForm = UnspawnedForms[index] @@ -104,22 +114,13 @@ Event OnUpdate() RegisterForSingleUpdate(0.01) EndEvent -Event OnMyAction(string eventName, string strArg, float numArg, Form sender) - Debug.Trace("VRIK activated me!") - ;/ - Get list of all inventory item names, sorted alphabetically - break into groups of five - find a common label for that group - group the groups in a similar manner until there are only five? - /; - Int numItems = PlayerRef.getNumItems() - Debug.Trace("Found " + numItems + " items") - +Function SortInventoryItems() _EQ_ItemRoulette_FormChunks sortChunks = ((Roulette.PlaceAtMe(FormChunks) as Form) as _EQ_ItemRoulette_FormChunks) sortChunks.Children = new Form[127] Int formIndex = 0 Int chunkIndex = -1 Int chunkItemIndex = 127 + Int numItems = PlayerRef.getNumItems() _EQ_ItemRoulette_FormChunks chunk While formIndex < numItems If chunkItemIndex >= 127 @@ -134,13 +135,39 @@ Event OnMyAction(string eventName, string strArg, float numArg, Form sender) chunkItemIndex += 1 EndWhile + Debug.StartStackProfiling() Debug.Trace("Sorting") sortChunks.SortByNameRecursive() Debug.Trace("Printing") sortChunks.PrintNamesRecursive() + Debug.Trace("Grouping") + _EQ_ItemRoulette_FormChunks groupChunks = sortChunks.GroupByName(Roulette) + Debug.Trace("Printing") + Debug.StopStackProfiling() + groupChunks.PrintNamesRecursive() +EndFunction + +Function PlayerItemAdded(Form baseItem, Int itemCount, ObjectReference itemRef, ObjectReference destContainer) + ShouldSortInventoryItems = True +EndFunction + +Function PlayerItemRemoved(Form baseItem, Int itemCount, ObjectReference itemRef, ObjectReference destContainer) + ShouldSortInventoryItems = True +EndFunction + +Event OnMyAction(string eventName, string strArg, float numArg, Form sender) + Debug.Trace("VRIK activated me!") + ;/ + Get list of all inventory item names, sorted alphabetically + break into groups of five + find a common label for that group + group the groups in a similar manner until there are only five? + /; + Int numItems = PlayerRef.GetNumItems() + Debug.Trace("Found " + numItems + " items") Int count = 0 - formIndex = numItems + Int formIndex = numItems While formIndex > 0 && formIndex > numItems - MAX_ITEMS formIndex -= 1 count = numItems - formIndex diff --git a/plugin/Data/_EQ_ItemRoulette.esp b/plugin/Data/_EQ_ItemRoulette.esp index 2ba7f18..082d5b0 100644 Binary files a/plugin/Data/_EQ_ItemRoulette.esp and b/plugin/Data/_EQ_ItemRoulette.esp differ