Last active
January 9, 2021 14:29
-
-
Save yggdrasil75/4ae8f8455b36d87b2bcee4623b3b89af 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 | |
j, i: int; | |
cini: TMemIniFile; | |
overrides, overrideprimary, debugmsg: boolean; | |
IniFilestreams, IniTemplates:TStringlist; | |
cg:string; | |
begin | |
templateMegaList := tstringlist.create; | |
debugmsg := 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 filecount - 1 do begin | |
if FileExists(DataPath + 'alla' + GetFileName(FileByIndex(i)) + 'template.ini') then | |
IniTemplates.add(DataPath + 'alla' + GetFileName(fileByIndex(i)) + 'template.ini'); | |
end; | |
msg('[TemplateLists] detected ' + IniTemplates.count + ' Template Inis'); | |
for i := IniTemplates.count - 1 downto 2 do begin | |
cini := TMemIniFile.create(IniTemplates[i]); | |
overrides := cini.Readbool('explanation', 'ignorePrimary', false); // this is for waccf and similar to "fix" leveled lists | |
if overrides then overrideprimary := true; | |
IniFilestreams.addobject(initemplates[i],cini); | |
end; | |
if not overrideprimary then begin | |
msg('[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 | |
cini := TMemIniFile.create(IniTemplates[i]); | |
IniFilestreams.addobject(initemplates[i],cini); | |
end; | |
end else msg('[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'''); | |
{debug} if debugmsg then msg('[TemplateLists] loaded all detected INIs'); | |
{debug} if debugmsg then msg('[TemplateLists] begin detection of major groupings'); | |
groupings := TStringlist.create; | |
groupings.Sorted := True; | |
groupings.Duplicates := dupIgnore; | |
for i := IniFilestreams.count - 1 downto 0 do begin // use appenddelimted | |
AppendDelimited(groupings,IniFilestreams.objects[i].readstring('explanation','groupings','')); | |
end; | |
msg('[TemplateLists] detected ' + groupings.count + ' different primary categories of items'); | |
for i := groupings.count - 1 downto 0 do begin | |
cg := groupings[i]; | |
templist := tstringlist.create; //this contains the info stored in the inis temporarily. | |
types := tstringlist.create; //this is the "types" of items, it splits up for instance helmet, pauldron, poleyn, and sabaton | |
types.sorted := true; | |
types.duplicates := dupIgnore; | |
grup := tstringlist.create; //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.sorted := true; | |
grup.duplicates := dupIgnore; | |
ident := tstringlist.create; //this determines words/phrases that will be used to attempt to determine whether an item belonds in this grouping. | |
ident.sorted := true; | |
ident.duplicates := dupIgnore; | |
secondaryPath := tstringlist.create; //this is the list of comparable elements used to determine tier association. secondary is able to shift the tier logarithmically up or down a certain number (bigger changes required each shift) | |
secondaryPath.sorted := true; | |
secondaryPath.duplicates := dupIgnore; | |
for j := 0 to IniFilestreams.count - 1 begin | |
cini := IniFilestreams.objects[j]; | |
appenddelimted(types,cini.readstring(cg,'types','')); | |
appenddelimted(grup,cini.readstring(cg,'grup','')); | |
appenddelimted(ident,cini.readstring(cg,'ident','')); | |
PrimaryPath := cini.readstring(cg,'primaryPath',''); //this is used to set the tier of a given item initially, secondary can be used to determine a further shift (the last will be the only kept) | |
appenddelimted(secondaryPath,cini.readstring(cg,'secondaryPath','')); | |
MaxLevel := cini.readint(cg,'maxLevel',''); // this is the upper limit for the tiers only the last version will be kept | |
end; | |
templist.addobject('types',types); | |
templist.addobject('grup',grup); | |
templist.addobject('identifier',ident); | |
templist.addobject('path1',primaryPath); | |
templist.addobject('path2',secondaryPath); | |
templist.addobject('max',MaxLevel); | |
groupings2.addobject(cg,templist); | |
end; | |
{debug} if debugmsg then msg('groupings pass 1 has been completed.'); | |
for i := groupings2.count - 1 downto 0 do begin | |
cgs := groupings2[i]; | |
cg2 := groupings2.objects[i]; | |
cgti := cg2.objects[cg2.indexof(types)]; | |
tml := tstring.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('path1', groupings2.objects[groupings2.indexof('path1')]); | |
tml.addobject('path2', groupings2.objects[groupings2.indexof('path2')]); | |
tml.addobject('max', groupings2.objects[groupings2.indexof('max')]); | |
for j := cgti.count - 1 downto 0 do begin | |
ct := cgti[j]; | |
TempItemList := TStringlist.Create; | |
TempKywdList := TStringlist.Create; | |
TempDuolist := TStringlist.Create; | |
for k := 0 to IniFilestreams.count - 1 do begin | |
cini := IniFilestreams.objects[i]; | |
AppendDelimited(TempItemList, cini.readstring(cgs,ct,'')); | |
appenddelimted(TempKywdList, cini.readstring(cgs,ct+'keywords','')); | |
end; | |
TempDuolist.addobject(cgs,TempItemList); | |
TempDuolist.addobject(cgs+'keywords',TempKywdList); | |
tml.addobject(ct,TempDuolist); | |
end; | |
compact(tml); | |
templateMegaList.addobject(cgs,tml); | |
end; | |
{debug} if debugmsg then msg('groupings pass 2 completed.'); | |
end; | |
procedure AppendDelimited(out templist: TStringlist; tempstring: string); | |
var | |
templist2: tstringlist; | |
begin | |
templist2 := tstringlist.create; | |
templist2.delimitedText := tempstring; | |
templist.addstrings(templist2); | |
templist2.free; | |
end; | |
procedure compact(out templist: tstringlist); | |
var | |
valuetiers,cil2,cil,values,empty,temppath2list,paths: TStringList; | |
cip,cin,cis,temps: string; | |
ct,cit,max,i,j,k: integer; | |
debugmsg: boolean; | |
ci: IInterface; | |
begin | |
debugmsg := false; | |
paths := tstringlist.create; | |
temps := templist.objects[3]; //primary path | |
paths.addobject(copy(temps,0,pos(':',temps)-1), tryStrToFloat(copy(temps,pos(':',temps)+1,temps.length),1)); | |
temppath2list := templist.objects[4]; //secondary paths. | |
for i := temppath2list.count - 1 downto 0 do begin | |
temps := temppath2list.objects[i]; | |
paths.addobject(copy(temps,0,pos(':',temps)-1), tryStrToFloat(copy(temps,pos(':',temps)+1,temps.length),1)); | |
end; | |
values := tstringlist.create; | |
max := templist.objects[5]; | |
for i := paths.count - 1 downto 0 do begin //initialize the values to have a proper name | |
empty := tstringlist.create; | |
for i := 0 to values - 1 do begin | |
empty.addobject(IntToStr(i),0); | |
end; | |
values.addobject(paths[i],empty); | |
end; | |
i := 6; | |
repeat | |
{debug} if debugmsg then msg('generating compacted comparison values'); | |
//get the value of path1 and path2 for each, and average them. | |
cil := templist.objects[i]; //current item list | |
cil2 := tstringlist.create; | |
for j := cil.count - 1 downto 0 do begin //process all items | |
cis := cil.objects[j]; | |
cip := copy(cis, 0,pos('|')-1); | |
cin := copy(cis, pos('|') + 1, pos(':') - 1); | |
cit := tryStrToInt(copy(cis, pos(':') + 1, cis.length), 15); | |
ci := RecordByEDID(fileByName(cip), cin); | |
cil2[j] := cit | |
cil2.objects[j] := ci; | |
end; | |
cil := cil2; | |
cil2.free; | |
templist.addobject(templist[i]+'values',values); | |
i := i + 2; | |
until i > templist.count - 2; | |
i := 6; | |
repeat | |
{debug} if debugmsg then msg('generating compacted comparison values'); | |
//get the value of path1 and path2 for each, and average them. | |
cil := templist.objects[i]; //current item list | |
for j := cil.count - 1 downto 0 do begin //process all items | |
ci := objecttoelement(cil.objects[j]); | |
ct := cil[j]; | |
for k := paths.count - 1 downto 0 do begin //process all items over all paths | |
valueTiers := values.objects[k]; | |
if ct > max then begin | |
msg('an item breached max level of selected template list'); | |
continue; | |
end; | |
valueTiers.objects[ct] := valueTiers.objects[ct] + (tryStrToFloat(getelementeditvalues(ci, paths[k]), 1) * paths.objects[k]); //the extra math is for smoothing the curve a bit. probably could drop it easily. | |
end; | |
end; | |
templist.addobject(templist[i]+'values',values); | |
i := i + 2; | |
until i > templist.count - 2; | |
end; | |
function GetTemplate(aRecord: iinterface): IInterface; //where the record is actually compared. | |
var | |
ctl,ctml: tstringlist; | |
tier:integer; | |
item:IInterface; | |
begin | |
// get values of record, compare with expected template. | |
ctml := templatelistselector(aRecord); | |
// find which part type (ie: helmet, chestplate, etc) list to use | |
ctl := subtemplateSelector(aRecord, ctml); | |
//find "most similar" by a few things. dunno what all yet, probably shared keyword count, and difference of values listed in the 2 paths options. | |
tier := getTier(aRecord, ctl,ctml); | |
item := getTemplateItem(aRecord, ctl, ctml, tier); | |
result :=item; | |
end; | |
function getTemplateItem(aRecord: IInterface; templateList, templateMain: TStringlist, tier: integer): IInterface; | |
var | |
itemlist:tstringlist; | |
nearest,likeness,likenessnew,i,startcount,endcount:integer; | |
ci:IInterface; | |
begin | |
itemList := templateList.objects[0]; | |
itemlist.sorted := true; | |
startcount := itemlist.indexOf(tier); | |
endcount := itemlist.indexof(tier+1); | |
for i := startcount - 1 to endcount - 1 do begin | |
likenessnew := 0 | |
ci := ote(itemlist.objects[i]); | |
likenessnew := SameKeywordCount(aRecord, ci); | |
list1 := tstringlist.create; | |
list1.delimiter := ' '; | |
list2 := tstringlist.create; | |
list2.delimiter := ' '; | |
list1.delimitedText := displayName(aRecord); | |
list2.delimitedText := displayName(ci); | |
likenessnew := likenessnew + CompareStringLists(list1,list2); | |
list1.delimiter := '_'; | |
list2.delimiter := '_'; | |
list1.delimitedText := EditorID(aRecord); | |
list2.delimitedText := EditorID(ci); | |
likenessnew := likenessnew + CompareStringLists(list1,list2); | |
//todo: change up likeness to be more? | |
if likenessnew > likeness then begin | |
likeness := likenessnew; | |
nearest := i; | |
end; | |
end; | |
result := ote(itemlist.objects[nearest]); | |
end; | |
function CompareStringLists(List1, List2: TStringList;): integer; | |
var | |
l1i,count,i:integer; | |
begin | |
List1.Sort; | |
List2.Sort; | |
for i := 0 to list1.count - 1 do begin | |
l1i := list2.indexOf(list1[i]); | |
if not l1i < 0 then begin | |
list1.delete[l1i]; | |
count := count + 1; | |
end; | |
end; | |
result := count; | |
end; | |
function SameKeywordCount(aRecord,bRecord: IInterface): integer; | |
var | |
debugmsg:boolean; | |
i:integer; | |
begin | |
// Begin debugMsg section | |
debugMsg := false; | |
Result := False; | |
tempRecord := ebp(aRecord, 'KWDA'); | |
for i := 0 to ec(tempRecord) - 1 do begin | |
if hasKeyword(bRecord, elementbyIndex(temprecord,i)) then total := total + 1; | |
end; | |
debugMsg := false; | |
// End debugMsg section | |
end; | |
function subtemplateSelector(aRecord: IInterface; templateList: tstringlist): tstringlist; | |
var | |
i:integer; | |
subTemplate,ctl:tstringlist; | |
ctln,ctln1:string; | |
begin | |
repeat | |
i := i + 1; | |
until containsText(templateList[i],'keywords'); | |
while i < templateList.count - 2 do begin | |
if not containsText(templateList[i],keywords) then break; | |
ctl := templateList.objects[i]; | |
ctln := templateList[i]; | |
ctln1 := templateList[i-1]; | |
subTemplate := tstringlist.create; | |
if hasakeyword(aRecord,ctl) then begin | |
if containsText(ctln,ctln1) then begin | |
subTemplate.addobjects(ctln1,templateList.objects[i-1]); | |
subTemplate.addobjects(ctln1+'values',templateList.objects[templateList.indexof(ctln1+'values')]); | |
result := subTemplate; | |
exit; | |
end; | |
end; | |
i := i + 2; | |
end; | |
end; | |
function getTier(aRecord: IInterface; templateList, templateMain: TStringlist): tStringList; | |
var | |
temppath2list,path2,valuesublist,valuelist: tstringlist; | |
temps,path1:string; | |
primepathCR,path1comp,p2t,p2a:float; | |
tier,i,j: integer; | |
begin | |
//result here will be a list of items in the tier | |
valuelist := templatelist.objects[1]; | |
path1 := copy(templateMain.objects[3],0,pos(':',templateMain.objects[3])-1) //primary path for comparison | |
path1comp := tryStrToFloat(copy(temps,pos(':',temps)+1,temps.length),1) //path1 mult value | |
temppath2list := templatemain.objects[4]; | |
for i := temppath2list.count - 1 downto 0 do begin | |
temps := temppath2list.objects[i]; | |
path2.addobject(copy(temps,0,pos(':',temps)-1), tryStrToFloat(copy(temps,pos(':',temps)+1,temps.length),1)); | |
end; | |
valuesublist := valuelist.objects[valuelist.indexOf(path1)]; | |
primepathCR := tryStrToFloat(getelementeditvalues(aRecord, path1),1) * path1comp; | |
for i := 0 to valuesublist.count - 1 do begin | |
if primepathCR > valuesublist.objects[i] + 1 then continue | |
else if primepathCR < valuesublist.objects[i] - 1 then begin | |
i := i - 1; | |
break; | |
end else begin | |
break; | |
end; | |
end; | |
tier := i; | |
msg('primary tier for ' + displayName(aRecord) + ' is ' + tier + ' processing secondary modifiers now'); | |
for i := 0 to path2.count - 1 do begin | |
valuesublist := valuelist.objects[valuelist.indexOf(path2[i])]; | |
for j := 0 to valuesublist.count - 1 do begin | |
if primepathCR > valuesublist.objects[j] + 1 then continue | |
else if primepathCR < valuesublist.objects[j] - 1 then begin | |
j := j - 1; | |
break; | |
end else begin | |
break; | |
end; | |
end; | |
p2t := p2t + j; | |
end; | |
p2a := p2t / path2.count; | |
if tier < p2a - 10 then begin | |
tier := tier - 3; | |
end else if tier < p2a - 7 then begin | |
tier := tier - 2; | |
end else if tier < p2a - 3 then begin | |
tier := tier - 1; | |
end else if tier > p2a + 10 then begin | |
tier := tier + 3; | |
end else if tier < p2a + 7 then begin | |
tier := tier + 2; | |
end else if tier < p2a + 3 then begin | |
tier := tier + 1; | |
end; | |
msg('with alternative paths, tier is now ' + tier); | |
end; | |
function templatelistselector(aRecord: IInterface): tstringlist; | |
var | |
i:integer; | |
ctml:tstringlist; | |
begin | |
//2 options, find first applicable template section based on idents | |
//find the most applicable. first easier. | |
for i := 0 to templateMegaList.Count - 1 do begin | |
ctml := templateMegaList.objects[i]; | |
if not signature(aRecord) = ctml.objects[2] then continue; | |
if not hasIdent(aRecord, ctml.objects[3]) then continue; | |
result := ctml; | |
exit; | |
end; | |
end; | |
function hasakeyword(aRecord: IInterface; keywords: tstringlist): boolean; | |
var | |
debugmsg: boolean; | |
temprecord: IInterface; | |
i,j:integer; | |
begin | |
// Begin debugMsg section | |
debugMsg := false; | |
Result := False; | |
tempRecord := ebp(aRecord, 'KWDA'); | |
for i := 0 to Pred(ec(tempRecord)) do begin | |
for j := 0 to keywords.count - 1 do begin | |
{Debug} if debugMsg then msg('[HasaKeyword] if ('+EditorID(LinksTo(ebi(tempRecord, i)))+' = '+keywords[j]+' ) then begin'); | |
if (EditorID(LinksTo(ebi(tempRecord, i))) = keywords[j]) then begin | |
{Debug} if debugMsg then msg('[HasaKeyword] Result := True'); | |
Result := True; | |
exit; | |
end; | |
end; | |
end; | |
debugMsg := false; | |
// End debugMsg section | |
end; | |
function hasident(aRecord: IInterface; idents: tstringlist): boolean; | |
var | |
tempname,tempedid: string; | |
i:integer; | |
begin | |
tempEDID := EditorID(aRecord); | |
tempName := displayName(aRecord); | |
result := false; | |
for i := idents.count - 1 downto 0 do begin | |
if containsText(tempEDID, idents[i]) or if containsText(tempName, idents[i]) then begin | |
result := true; | |
exit; | |
end; | |
end; | |
end; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment