-
-
Save fireundubh/b607858acfda6506cc360ddf993393be to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
procedure TemplateLists; | |
var | |
i : Integer; | |
j : Integer; | |
memIniFile : TMemIniFile; | |
bOverrides : Boolean; | |
bOverridePrimary : Boolean; | |
bDebug : Boolean; | |
IniFileStreams : TStringList; | |
IniTemplates : TStringList; | |
s : String; | |
begin | |
templateMegaList := TStringList.Create; | |
bDebug := False; | |
// setup template files | |
// ALLATemplate.ini | |
// ALLAUserTemplate.ini | |
// ALLA+<modname>+template.ini in data folder (ie: ALLAYggKeywords.espTemplate.ini) | |
IniTemplates := TStringList.Create; | |
IniTemplates.Add(ScriptsPath + 'ALLATemplate.ini'); | |
IniTemplates.Add(ScriptsPath + 'ALLAUserTemplate.ini'); | |
for i := 0 to Pred(FileCount) do | |
if FileExists(DataPath + 'alla' + GetFileName(FileByIndex(i)) + 'template.ini') then | |
IniTemplates.Add(DataPath + 'alla' + GetFileName(FileByIndex(i)) + 'template.ini'); | |
AddMessage('[TemplateLists] detected ' + IniTemplates.Count + ' Template Inis'); | |
for i := Pred(IniTemplates.Count) downto 2 do | |
begin | |
memIniFile := TMemIniFile.Create(IniTemplates[i]); | |
bOverrides := memIniFile.ReadBool('explanation', 'ignorePrimary', False); | |
// this is for waccf and similar to "fix" leveled lists | |
if bOverrides then | |
bOverridePrimary := True; | |
IniFileStreams.AddObject(IniTemplates[i], memIniFile); | |
end; | |
if not bOverridePrimary then | |
begin | |
AddMessage('[TemplateLists] Primary INI files are used as WACCF or similar has not been detected - if you believe this is in error, please check your inis for ''ignorePrimary'''); | |
for i := 2 downto 0 do | |
begin | |
memIniFile := TMemIniFile.Create(IniTemplates[i]); | |
IniFileStreams.AddObject(IniTemplates[i], memIniFile); | |
end; | |
end | |
else | |
AddMessage('[TemplateLists] Primary INI files are ignored as WACCF or similar has been detected - if you believe this is in error, please check your inis for ''ignorePrimary'''); | |
if bDebug then | |
AddMessage('[TemplateLists] loaded all detected INIs'); | |
if bDebug then | |
AddMessage('[TemplateLists] begin detection of major groupings'); | |
groupings := TStringList.Create; | |
groupings.Sorted := True; | |
groupings.Duplicates := dupIgnore; | |
// use AppendDelimited | |
for i := Pred(IniFileStreams.Count) downto 0 do | |
AppendDelimited(groupings, IniFileStreams.Objects[i].ReadString('explanation', 'groupings', '')); | |
AddMessage('[TemplateLists] detected ' + groupings.Count + ' different primary categories of items'); | |
for i := Pred(groupings.Count) downto 0 do | |
begin | |
s := groupings[i]; | |
// this contains the info stored in the inis temporarily. | |
aStringList := TStringList.Create; | |
// this is the "types" of items, it splits up for instance helmet, pauldron, poleyn, and sabaton | |
types := TStringList.Create; | |
types.Sorted := True; | |
types.Duplicates := dupIgnore; | |
// this is the grup(s) that the grouping is used on. for instance, heavy and light are armo, weapon is weap, misc is possible as well eventually | |
grup := TStringList.Create; | |
grup.Sorted := True; | |
grup.Duplicates := dupIgnore; | |
// this determines words/phrases that will be used to attempt to determine whether an r belonds in this grouping. | |
ident := TStringList.Create; | |
ident.Sorted := True; | |
ident.Duplicates := dupIgnore; | |
// this is the list of comparable elements used to determine iTier association. secondary is able to shift the iTier logarithmically up or down a certain number (bigger changes required each shift) | |
secondaryPath := TStringList.Create; | |
secondaryPath.Sorted := True; | |
secondaryPath.Duplicates := dupIgnore; | |
for j := 0 to Pred(IniFileStreams.Count) do | |
begin | |
memIniFile := IniFileStreams.Objects[j]; | |
AppendDelimited(types, memIniFile.ReadString(s, 'types', '')); | |
AppendDelimited(grup, memIniFile.ReadString(s, 'grup', '')); | |
AppendDelimited(ident, memIniFile.ReadString(s, 'ident', '')); | |
// this is used to set the iTier of a given r initially, secondary can be used to determine a further shift (the last will be the only kept) | |
PrimaryPath := memIniFile.ReadString(s, 'primaryPath', ''); | |
AppendDelimited(secondaryPath, memIniFile.ReadString(s, 'secondaryPath', '')); | |
// this is the upper limit for the tiers only the last version will be kept | |
MaxLevel := memIniFile.ReadInt(s, 'maxLevel', ''); | |
end; | |
end; | |
aStringList.AddObject('types', types); | |
aStringList.AddObject('grup', grup); | |
aStringList.AddObject('identifier', ident); | |
aStringList.AddObject('sPath1', PrimaryPath); | |
aStringList.AddObject('slPath2', secondaryPath); | |
aStringList.AddObject('iMax', MaxLevel); | |
groupings2.AddObject(s, aStringList); | |
if bDebug then | |
AddMessage('groupings pass 1 has been completed.'); | |
for i := Pred(groupings2.Count) downto 0 do | |
begin | |
cgs := groupings2[i]; | |
cg2 := groupings2.Objects[i]; | |
cgti := cg2.Objects[cg2.IndexOf(types)]; | |
tml := TStringList.Create; | |
tml.AddObject('types', groupings2.Objects[groupings2.IndexOf('types')]); | |
tml.AddObject('grup', groupings2.Objects[groupings2.IndexOf('grup')]); | |
tml.AddObject('identifier', groupings2.Objects[groupings2.IndexOf('identifier')]); | |
tml.AddObject('sPath1', groupings2.Objects[groupings2.IndexOf('sPath1')]); | |
tml.AddObject('slPath2', groupings2.Objects[groupings2.IndexOf('slPath2')]); | |
tml.AddObject('iMax', groupings2.Objects[groupings2.IndexOf('iMax')]); | |
for j := Pred(cgti.Count) downto 0 do | |
begin | |
iCT := cgti[j]; | |
TempItemList := TStringList.Create; | |
TempKywdList := TStringList.Create; | |
TempDuolist := TStringList.Create; | |
for k := 0 to Pred(IniFileStreams.Count) do | |
begin | |
memIniFile := IniFileStreams.Objects[i]; | |
AppendDelimited(TempItemList, memIniFile.ReadString(cgs, iCT, '')); | |
AppendDelimited(TempKywdList, memIniFile.ReadString(cgs, iCT + 'aKeywords', '')); | |
end; | |
TempDuolist.AddObject(cgs, TempItemList); | |
TempDuolist.AddObject(cgs + 'aKeywords', TempKywdList); | |
tml.AddObject(iCT, TempDuolist); | |
end; | |
Compact(tml); | |
templateMegaList.AddObject(cgs, tml); | |
if bDebug then | |
AddMessage('groupings pass 2 completed.'); | |
end; | |
end; | |
procedure AppendDelimited(out aStringList: TStringList; aSourceText: String); | |
var | |
sl: TStringList; | |
begin | |
sl := TStringList.Create; | |
sl.DelimitedText := aSourceText; | |
aStringList.AddStrings(sl); | |
sl.Free; | |
end; | |
procedure Compact(out aStringList: TStringList); | |
var | |
slValueTiers : TStringList; | |
slCIL2 : TStringList; | |
slCIL : TStringList; | |
slValues : TStringList; | |
slEmpty : TStringList; | |
slPath2Temp : TStringList; | |
slPaths : TStringList; | |
sCIPp : String; | |
sCIN : String; | |
sCIS : String; | |
sTemp : String; | |
iCT : Integer; | |
iCIT : Integer; | |
iMax : Integer; | |
i : Integer; | |
j : Integer; | |
k : Integer; | |
bDebug : Boolean; | |
kCI : IInterface; | |
begin | |
bDebug := False; | |
slPaths := TStringList.Create; | |
// primary path | |
sTemp := aStringList.Objects[3]; | |
slPaths.AddObject(Copy(sTemp, 0, Pos(':', sTemp) - 1), TryStrToFloat(Copy(sTemp, Pos(':', sTemp) + 1, sTemp.Length), 1)); | |
// secondary slPaths | |
slPath2Temp := aStringList.Objects[4]; | |
for i := Pred(slPath2Temp.Count) downto 0 do | |
begin | |
sTemp := slPath2Temp.Objects[i]; | |
slPaths.AddObject(Copy(sTemp, 0, Pos(':', sTemp) - 1), TryStrToFloat(Copy(sTemp, Pos(':', sTemp) + 1, sTemp.Length), 1)); | |
end; | |
slValues := TStringList.Create; | |
iMax := aStringList.Objects[5]; | |
for i := Pred(slPaths.Count) downto 0 do | |
begin | |
// initialize the slValues to have a proper name | |
slEmpty := TStringList.Create; | |
for i := 0 to Pred(slValues.Count) do | |
slEmpty.AddObject(IntToStr(i), 0); | |
slValues.AddObject(slPaths[i], slEmpty); | |
end; | |
i := 6; | |
repeat | |
if bDebug then | |
AddMessage('generating compacted comparison slValues'); | |
// get the value of sPath1 and slPath2 for each, and average them. | |
slCIL := aStringList.Objects[i]; // current r list | |
slCIL2 := TStringList.Create; | |
// process all items | |
for j := Pred(slCIL.Count) downto 0 do | |
begin | |
sCIS := slCIL.Objects[j]; | |
sCIP := Copy(sCIS, 0, Pos('|') - 1); | |
sCIN := Copy(sCIS, Pos('|') + 1, Pos(':') - 1); | |
iCIT := TryStrToInt(Copy(sCIS, Pos(':') + 1, sCIS.Length), 15); | |
kCI := RecordByEDID(fileByName(sCIP), sCIN); | |
slCIL2[j] := iCIT; | |
slCIL2.Objects[j] := kCI; | |
end; | |
slCIL := slCIL2; | |
slCIL2.Free; | |
aStringList.AddObject(aStringList[i] + 'slValues', slValues); | |
i := i + 2; | |
until i > aStringList.Count - 2; | |
i := 6; | |
repeat | |
if bDebug then | |
AddMessage('generating compacted comparison slValues'); | |
// get the value of sPath1 and slPath2 for each, and average them. | |
slCIL := aStringList.Objects[i]; // current r list | |
for j := Pred(slCIL.Count) downto 0 do | |
begin // process all items | |
kCI := ObjectToElement(slCIL.Objects[j]); | |
iCT := slCIL[j]; | |
// process all items over all slPaths | |
for k := Pred(slPaths.Count) downto 0 do begin | |
slValueTiers := slValues.Objects[k]; | |
if iCT > iMax then | |
begin | |
AddMessage('an r breached iMax level of selected template list'); | |
continue; | |
end; | |
// the extra math is for smoothing the curve a bit. probably could drop it easily. | |
slValueTiers.Objects[iCT] := slValueTiers.Objects[iCT] + (TryStrToFloat(GetElementEditValues(kCI, slPaths[k]), 1) * slPaths.Objects[k]); | |
end; | |
end; | |
aStringList.AddObject(aStringList[i] + 'slValues', slValues); | |
i := i + 2; | |
until i > aStringList.Count - 2; | |
end; | |
function GetTemplate(aRecord: IInterface): IInterface; | |
// where the record is actually compared. | |
var | |
slPartType : TStringList; | |
slValues : TStringList; | |
iTier : Integer; | |
begin | |
// get slValues of record, compare with expected template. | |
slValues := TemplateListSelector(aRecord); | |
// find which part type (ie: helmet, chestplate, etc) list to use | |
slPartType := SubTemplateSelector(aRecord, slValues); | |
// find "most similar" by a few things. dunno what all yet, probably shared keyword count, and difference of slValues listed in the 2 slPaths options. | |
iTier := GetTier(aRecord, slPartType, slValues); | |
Result := GetTemplateItem(aRecord, slPartType, slValues, iTier); | |
end; | |
function GetTemplateItem(aRecord: IInterface; aTemplateList: TStringList; aTemplateMain: TStringList; aTier: Integer): IInterface; | |
var | |
slItems : TStringList; | |
i : Integer; | |
iNearest : Integer; | |
iLikeness : Integer; | |
iLikenessNew : Integer; | |
iStartCount : Integer; | |
iEndCount : Integer; | |
kCI : IInterface; | |
begin | |
slItems := aTemplateList.Objects[0]; | |
slItems.Sorted := True; | |
iStartCount := slItems.IndexOf(aTier); | |
iEndCount := slItems.IndexOf(aTier + 1); | |
for i := Pred(iStartCount) to Pred(iEndCount) do | |
begin | |
iLikenessNew := 0; | |
kCI := ObjectToElement(slItems.Objects[i]); | |
iLikenessNew := SameKeywordCount(aRecord, kCI); | |
aStringList := TStringList.Create; | |
aStringList.Delimiter := ' '; | |
aOtherStringList := TStringList.Create; | |
aOtherStringList.Delimiter := ' '; | |
aStringList.DelimitedText := DisplayName(aRecord); | |
aOtherStringList.DelimitedText := DisplayName(kCI); | |
iLikenessNew := iLikenessNew + CompareStringLists(aStringList, aOtherStringList); | |
aStringList.Delimiter := '_'; | |
aOtherStringList.Delimiter := '_'; | |
aStringList.DelimitedText := EditorID(aRecord); | |
aOtherStringList.DelimitedText := EditorID(kCI); | |
iLikenessNew := iLikenessNew + CompareStringLists(aStringList, aOtherStringList); | |
// todo: change up iLikeness to be more? | |
if iLikenessNew > iLikeness then begin | |
iLikeness := iLikenessNew; | |
iNearest := i; | |
end; | |
end; | |
Result := ObjectToElement(slItems.Objects[iNearest]); | |
end; | |
function CompareStringLists(aStringList: TStringList; aOtherStringList: TStringList): Integer; | |
var | |
i : Integer; | |
iCount : Integer; | |
iIndex : Integer; | |
begin | |
aStringList.Sort; | |
aOtherStringList.Sort; | |
for i := 0 to Pred(aStringList.Count) do | |
begin | |
iIndex := aOtherStringList.IndexOf(aStringList[i]); | |
if not iIndex < 0 then begin | |
aStringList.delete[iIndex]; | |
iCount := iCount + 1; | |
end; | |
end; | |
Result := iCount; | |
end; | |
function SameKeywordCount(aRecord: IInterface; aOtherRecord: IInterface): Integer; | |
var | |
bDebug : Boolean; | |
i : Integer; | |
begin | |
// Begin debugMsg section | |
bDebug := False; | |
Result := False; | |
kTempRecord := ElementBySignature(aRecord, 'KWDA'); | |
for i := 0 to Pred(ElementCount(kTempRecord)) do | |
if HasKeyword(aOtherRecord, ElementByIndex(kTempRecord, i)) then | |
total := total + 1; | |
bDebug := False; | |
// End debugMsg section | |
end; | |
function SubTemplateSelector(aRecord: IInterface; aTemplateList: TStringList): TStringList; | |
var | |
i : Integer; | |
slSubTemplate : TStringList; | |
slPartType : TStringList; | |
sCTLN : String; | |
sCTLN1 : String; | |
begin | |
repeat | |
i := i + 1; | |
until ContainsText(aTemplateList[i], 'aKeywords'); | |
while i < aTemplateList.Count - 2 do | |
begin | |
if not ContainsText(aTemplateList[i], aKeywords) then | |
break; | |
slPartType := aTemplateList.Objects[i]; | |
sCTLN := aTemplateList[i]; | |
sCTLN1 := aTemplateList[i - 1]; | |
slSubTemplate := TStringList.Create; | |
if HasAKeyword(aRecord, slPartType) then | |
if ContainsText(sCTLN, sCTLN1) then | |
begin | |
slSubTemplate.AddObjects(sCTLN1, aTemplateList.Objects[i - 1]); | |
slSubTemplate.AddObjects(sCTLN1 + 'slValues', aTemplateList.Objects[aTemplateList.IndexOf(sCTLN1 + 'slValues')]); | |
Result := slSubTemplate; | |
exit; | |
end; | |
i := i + 2; | |
end; | |
end; | |
function GetTier(aRecord: IInterface; aTemplateList: TStringList; aTemplateMain: TStringList): TStringList; | |
var | |
slPath2Temp : TStringList; | |
slPath2 : TStringList; | |
slValueSublist : TStringList; | |
slValue : TStringList; | |
sTemp : String; | |
sPath1 : String; | |
dPrimePathCR : Double; | |
dPath1Comp : Double; | |
dPath2T : Double; | |
dPath2A : Double; | |
i : Integer; | |
j : Integer; | |
iTier : Integer; | |
begin | |
// Result here will be a list of items in the iTier | |
slValue := aTemplateList.Objects[1]; | |
// primary path for comparison | |
sPath1 := Copy(aTemplateMain.Objects[3], 0, Pos(':', aTemplateMain.Objects[3]) - 1); | |
// sPath1 mult value | |
dPath1Comp := TryStrToFloat(Copy(sTemp, Pos(':', sTemp) + 1, sTemp.Length), 1); | |
slPath2Temp := aTemplateMain.Objects[4]; | |
for i := Pred(slPath2Temp.Count) downto 0 do | |
begin | |
sTemp := slPath2Temp.Objects[i]; | |
slPath2.AddObject(Copy(sTemp, 0, Pos(':', sTemp) - 1), TryStrToFloat(Copy(sTemp, Pos(':', sTemp) + 1, sTemp.Length), 1)); | |
end; | |
slValueSublist := slValue.Objects[slValue.IndexOf(sPath1)]; | |
dPrimePathCR := TryStrToFloat(GetElementEditValues(aRecord, sPath1), 1) * dPath1Comp; | |
for i := 0 to Pred(slValueSublist.Count) do | |
begin | |
if dPrimePathCR > slValueSublist.Objects[i] + 1 then | |
continue; | |
if dPrimePathCR < slValueSublist.Objects[i] - 1 then | |
begin | |
i := i - 1; | |
break; | |
end; | |
break; | |
end; | |
iTier := i; | |
AddMessage('primary iTier for ' + DisplayName(aRecord) + ' is ' + iTier + ' processing secondary modifiers now'); | |
for i := 0 to Pred(slPath2.Count) do | |
begin | |
slValueSublist := slValue.Objects[slValue.IndexOf(slPath2[i])]; | |
for j := 0 to Pred(slValueSublist.Count) do | |
begin | |
if dPrimePathCR > slValueSublist.Objects[j] + 1 then | |
continue; | |
if dPrimePathCR < slValueSublist.Objects[j] - 1 then | |
begin | |
j := j - 1; | |
break; | |
end; | |
break; | |
end; | |
dPath2T := dPath2T + j; | |
end; | |
dPath2A := dPath2T / slPath2.Count; | |
if iTier < dPath2A - 10 then | |
iTier := iTier - 3 | |
else if iTier < dPath2A - 7 then | |
iTier := iTier - 2 | |
else if iTier < dPath2A - 3 then | |
iTier := iTier - 1 | |
else if iTier > dPath2A + 10 then | |
iTier := iTier + 3 | |
else if iTier < dPath2A + 7 then | |
iTier := iTier + 2 | |
else if iTier < dPath2A + 3 then | |
iTier := iTier + 1; | |
AddMessage('with alternative slPaths, iTier is now ' + iTier); | |
end; | |
function TemplateListSelector(aRecord: IInterface): TStringList; | |
var | |
slValues : TStringList; | |
i : Integer; | |
begin | |
// 2 options, find first applicable template section based on aIdents | |
// find the most applicable. first easier. | |
for i := 0 to Pred(templateMegaList.Count) do | |
begin | |
slValues := templateMegaList.Objects[i]; | |
if not signature(aRecord) = slValues.Objects[2] then | |
continue; | |
if not HasIdent(aRecord, slValues.Objects[3]) then | |
continue; | |
Result := slValues; | |
exit; | |
end; | |
end; | |
function HasAKeyword(aRecord: IInterface; aKeywords: TStringList): Boolean; | |
var | |
bDebug : Boolean; | |
kTempRecord : IInterface; | |
i : Integer; | |
j : Integer; | |
begin | |
// Begin debugMsg section | |
bDebug := False; | |
Result := False; | |
kTempRecord := ElementBySignature(aRecord, 'KWDA'); | |
for i := 0 to Pred(ElementCount(kTempRecord)) do | |
begin | |
for j := 0 to Pred(aKeywords.Count) do | |
begin | |
if bDebug then | |
AddMessage('[HasAKeyword] if (' + EditorID(LinksTo(ElementByIndex(kTempRecord, i))) + ' = ' + aKeywords[j] + ' ) then begin'); | |
if SameText(EditorID(LinksTo(ElementByIndex(kTempRecord, i))), aKeywords[j]) then | |
begin | |
if bDebug then | |
AddMessage('[HasAKeyword] Result := True'); | |
Result := True; | |
exit; | |
end; | |
end; | |
end; | |
bDebug := False; | |
// End debugMsg section | |
end; | |
function HasIdent(aRecord: IInterface; aIdents: TStringList): Boolean; | |
var | |
sTempEDID : String; | |
sTempName : String; | |
i : Integer; | |
begin | |
sTempEDID := EditorID(aRecord); | |
sTempName := DisplayName(aRecord); | |
Result := False; | |
for i := Pred(aIdents.Count) downto 0 do | |
if ContainsText(sTempEDID, aIdents[i]) or ContainsText(sTempName, aIdents[i]) then | |
begin | |
Result := True; | |
exit; | |
end; | |
end; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment