Icon representing a recipe

Recipe: HNetwork Probe 2.3 mp

created by malphis

Profile


Name
HNetwork Probe 2.3 mp
ID
104056
Shared with
Public
Parent
HNetwork Probe 2.3
Children
None
Created on
October 15, 2020 at 13:57 PM UTC
Updated on
October 15, 2020 at 13:57 PM UTC
Description

Modified for "minimum print" (mp) to keep list of all found networks together--similar to version 2.0

Best for


Code


--[[ HNetwork Probe 2.1 - spvincent - 8 October 2020 2.2 - LociOiling - 12 October 2020 + optionally skip initial mutation of all segments + optionally shuffle the list of mutable segments + gracefully handle cases where there's nothing to do + fluffier dialog + more complete cleanup, catch script errors + some minor polishing, Luafication, and Locifaction + print progress messages, more if VERBOSE + filch some EDRW code from TvdL + pilfer wiggle factor from Timo, too + outright theft of better randomseed from KarenCH + "borrow" ShuffleTable from Rav3n_pl + validate those AA codes 2.3 - LociOiling - 13 October 2020 + make named saves when hydrogen bond network score improves + report initial score and filter scores + track overall score and filter changes + reset filters at end, report final score + don't save solutions with the same overall score + reserve slot 1 for starting pose + restore starting pose at end if no gain ]]-- Recipe = "HNetworkProbe" Version = "2.3 mp" ReVersion = Recipe .. " " .. Version -- -- globals section -- polar_aas = "stnqdehyw" n_polar_aas = 0 n_residues = 0 first_qs_slot = 13 last_qs_slot = 35 next_qs_slot = 0 start_slot = 1 FIRST_FREE_SLOT = start_slot + 1 MAX_SLOT = 99 select_unfrozen = true sidechain_minimum = -70 n_it = 0 mutate_list_ui = {} -- will be a list of 1's & 0's for each residue. 1 means can mutate. 0 means don't mutate. mutable_list = {} filter_list = {} filter_stat = {} init_score = 0 best_score = 0 init_filter_score = 0 best_filter_score = 0 WF = 1 -- wiggle like Timo VERBOSE = false -- what's happening? skip_initial_mutate = false shuffle_mutables = true slot_stat = {} -- track the score saved in each slot -- -- AminoAcids -- -- short version of amino acids table for validation and display -- -- AminoAcids = { a = { polar = false, short = "Ala", long = "Alanine", }, c = { polar = false, short = "Cys", long = "Cysteine", }, d = { polar = true, short = "Asp", long = "Aspartate", }, e = { polar = true, short = "Glu", long = "Glutamate", }, f = { polar = false, short = "Phe", long = "Phenylalanine", }, g = { polar = false, short = "Gly", long = "Glycine", }, h = { polar = true, short = "His", long = "Histidine", }, i = { polar = false, short = "Ile", long = "Isoleucine", }, k = { polar = false, short = "Lys", long = "Lysine", }, l = { polar = true, short = "Leu", long = "Leucine", }, m = { polar = false, short = "Met", long = "Methionine", }, n = { polar = true, short = "Asn", long = "Asparagine", }, p = { polar = false, short = "Pro", long = "Proline", }, q = { polar = true, short = "Gln", long = "Glutamine", }, r = { polar = true, short = "Arg", long = "Arginine", }, s = { polar = true, short = "Ser", long = "Serine", }, t = { polar = true, short = "Thr", long = "Threonine", }, v = { polar = false, short = "Val", long = "Valine", }, w = { polar = true, short = "Trp", long = "Tryptophan", }, y = { polar = true, short = "Tyr", long = "Tyrosine", }, } -- -- end of globals section -- function r3 ( x ) -- Round to 3 decimal places t = 10 ^ 3 return math.floor ( x*t + 0.5 ) / t end -- -- get score, including metrics -- function GetScore () local scor = current.GetEnergyScore () local mbon = 0 -- -- check for the "metric" functions, -- report the total metric bonus if -- this puzzle has metrics defined -- if metric ~= nil then if metric.GetNames () ~= nil then mbon = metric.GetBonusTotal () end end return scor + mbon, mbon end function GetFilterScore () filter_bonus = filter.GetBonus ( "Hydrogen Bond Network" ) return filter_bonus end function GetListOfMutablesUnfrozen () for ii = 1, n_residues do localseg_backbone_frozen, seg_sidechain_frozen = freeze.IsFrozen ( ii ) if seg_sidechain_frozen == false -- and seg_backbone_frozen == false and structure.IsMutable ( ii ) == true then table.insert ( mutable_list , ii ) end end end function GetListOfMutablesSelected () for ii = 1, n_residues do local seg_backbone_frozen, seg_sidechain_frozen = freeze.IsFrozen ( ii ) if seg_sidechain_frozen == false and mutate_list_ui [ ii ] == 1 and structure.IsMutable ( ii ) == true then table.insert ( mutable_list , ii ) end end end -- -- getlist - pinched from Loop Rebuild 9.0 -- http://www.lua.org/manual/5.2/manual.html#6.4 -- helped make this function 11/16/17 -- function getlist ( liststr ) local newlist = {} local ilo, ihi, idir, substr -- -- the variable ii here exists for the scope -- of the for loop, no need to define another -- one, which would have different scope -- for ii = 1, n_residues do newlist [ ii ] = 0 end -- for ii -- -- the Lua regular expression below, -- used with string.gmatch, -- reads a series of substrs from liststr, -- where each substr contains an integer -- followed by one or more '-' signs, -- followed by an integer -- for substr in liststr:gmatch ( "(%d+%-+%d+)" ) do -- substr includes one or more '-' characters in a row -- -- get ilo & ihi from substr using string.gsub -- the same regex is used twice -- the regex contains two expressions in parens -- the first gsub extracts the first expression, -- the "from", and the second gsub gets the "to" -- ilo = substr:gsub ( "(%d+)%-+(%d+)", "%1" ) + 0 ihi = substr:gsub ( "(%d+)%-+(%d+)", "%2" ) + 0 idir = 1 -- the increment to use from ilo to ihi if ilo > ihi then idir = -1 end -- if ilo -- -- add an entry for each segment in the range -- any invalid entries are silently rejected here -- for ii = ilo, ihi, idir do -- for i=ilo to ihi step idir if ii >= 1 and ii <= n_residues then newlist [ ii ] = 1 end -- if ii end -- for ii end -- for substr -- -- the Lua regex below -- reads a series of substrs from liststr, -- where each substr contains an integer -- by itself -- for substr in liststr:gmatch ( "(%d+)" ) do local ij = substr + 0 -- converts substr into the number ij if ij >= 1 and ij <= n_residues then newlist [ ij ] = 1 end -- if i end -- for substr return newlist end -- -- SegmentListToSet, SegmentSetToString -- Originals by Timo van der Laan: -- 02-05-2012 TvdL Free to use for non commercial purposes -- SegmentListToSet = function ( list ) -- retirer doublons local result = {} local ff = 0 local ll = -1 table.sort ( list ) for ii = 1, #list do if list [ ii ] ~= ll + 1 and list [ ii ] ~= ll then -- note: duplicates are removed if ll > 0 then result [ #result + 1 ] = { ff, ll } end ff = list [ ii ] end ll = list [ ii ] end if ll > 0 then result [ #result + 1 ] = { ff, ll } end return result end SegmentSetToString = function ( set ) -- pour pouvoir imprimer local line = "" for ii = 1, #set do if ii ~= 1 then line = line .. ", " end line = line .. set [ ii ] [ 1 ] .. "-" .. set [ ii ] [ 2 ] end return line end -- -- seedRandom -- original by KarenCH -- -- looks for a seed > 10,000,000 and < 2 ^ 32 -- -- v2 - LociOiling - 20191103 -- * added 2 ^ 32 overflow check -- function seedRandom() local seed = os.time () / math.abs ( current.GetEnergyScore () ) seed = seed % 0.001 seed = 1 / seed while seed < 10000000 do seed = seed * 1000 end while seed > 2 ^ 32 do seed = seed / 10 end seed = seed - seed % 1 print ( "Random number seed = " .. seed ) math.randomseed( seed ) -- throw away a couple of randoms math.random () math.random () end -- -- Thanks to Rav3n_pl -- function ShuffleTable ( tab ) --randomize order of elements local cnt = #tab for i = 1, cnt do local r = math.random ( cnt ) tab [ i ], tab [ r ]= tab [ r ], tab [ i ] end return tab end function Init () save.Quickload ( start_slot ) if not skip_initial_mutate then if VERBOSE then print ( "initial mutations" ) end for ii = 1, #mutable_list do local kk = math.random ( n_polar_aas ) local replacement_aa = polar_aas:sub ( kk, kk ) if VERBOSE then print ( "changing segment " .. mutable_list [ ii ] .. " to \"" .. replacement_aa .. "\"" ) end if structure.CanMutate ( mutable_list [ ii ] , replacement_aa ) then structure.SetAminoAcid ( mutable_list [ ii ] , replacement_aa ) end end end selection.SelectAll () structure.WiggleSelected ( 2 * WF, false, true ) -- sidechains end function PrintParameters () print ( "--" ) print ( "wiggle factor = " .. WF ) print ( "skip initial mutate = " .. tostring ( skip_initial_mutate ) ) print ( "shuffle mutables = " .. tostring ( shuffle_mutables ) ) print ( #mutable_list .. " mutable segments =\"" .. SegmentSetToString ( SegmentListToSet ( mutable_list ) ) .. "\"" ) print ( polar_aas:len() .. " amino acids to use = \"" .. polar_aas .. "\"" ) print ( "Sidechain minimum = " .. r3 ( sidechain_minimum ) ) print ( "Using slots " .. first_qs_slot .. " to " .. last_qs_slot ) print ( "verbose output = " .. tostring ( VERBOSE ) ) end function GetParameters () local uerror = "" local rc repeat changed = false local dlog = dialog.CreateDialog ( ReVersion ) dlog.WF = dialog.AddSlider ( "Wiggle factor" , WF, 1, 5, 0 ) dlog.skip_initial_mutate = dialog.AddCheckbox ( "Skip initial mutates" , skip_initial_mutate ) dlog.shuffle_mutables = dialog.AddCheckbox ( "Shuffle mutable list" , shuffle_mutables ) dlog.M0000 = dialog.AddLabel ( "" ) dlog.M0001 = dialog.AddLabel ( "Select unfrozen works on unfrozen sidechains:" ) dlog.use_unfrozen = dialog.AddCheckbox ( "Select unfrozen" , select_unfrozen ) dlog.M0002 = dialog.AddLabel ( "If select unfrozen is not checked," ) dlog.M0003 = dialog.AddLabel ( "segment ranges are used." ) dlog.mutate_list = dialog.AddTextbox ( "Use ranges" , "" ) dlog.mlabela = dialog.AddLabel('Specify segment ranges like 1-3,6,19-30,45-62') dlog.M0005 = dialog.AddLabel ( "Specify the amino acids to try" ) dlog.aa_list = dialog.AddTextbox ( "Amino acids" , polar_aas ) dlog.M0009 = dialog.AddLabel ( "" ) dlog.M0010 = dialog.AddLabel ( "Minimum sidechain score after mutation," ) dlog.M0011 = dialog.AddLabel ( "lower scoring mutations are skipped." ) dlog.sidechain_minimum = dialog.AddSlider ( "Sidechain minimum" , sidechain_minimum , -200 , -20 , 0 ) dlog.M0019 = dialog.AddLabel ( "" ) dlog.M0020 = dialog.AddLabel ( "Quick save slot range" ) dlog.start_qs_slot = dialog.AddSlider ( "Start quick save", first_qs_slot, FIRST_FREE_SLOT, MAX_SLOT, 0 ) dlog.end_qs_slot = dialog.AddSlider ( "End quick save", last_qs_slot, FIRST_FREE_SLOT, MAX_SLOT, 0 ) dlog.M0029 = dialog.AddLabel ( "" ) dlog.VERBOSE = dialog.AddCheckbox ( "Verbose output" , VERBOSE ) if uerror:len () > 0 then dlog.lerr1 = dialog.AddLabel ( "" ) dlog.lerr2 = dialog.AddLabel ( "ERROR: " .. uerror ) end dlog.ok = dialog.AddButton ( "OK" , 1 ) dlog.cancel = dialog.AddButton ( "Cancel" , -1 ) rc = dialog.Show ( dlog ) uerror = "" if rc > 0 then WF = dlog.WF.value skip_initial_mutate = dlog.skip_initial_mutate.value shuffle_mutables = dlog.shuffle_mutables.value select_unfrozen = dlog.use_unfrozen.value mutate_list_ui = getlist(dlog.mutate_list.value) polar_aas = dlog.aa_list.value uerror = CheckAAs ( polar_aas ) sidechain_minimum = dlog.sidechain_minimum.value first_qs_slot = dlog.start_qs_slot.value last_qs_slot = dlog.end_qs_slot.value if first_qs_slot > last_qs_slot then uerror = "first quick save " .. first_qs_slot .. " greater than last quick save " .. last_qs_slot end -- -- these are Should Not Occur Errors (SNOCR), since the dialog uses a slider... -- if first_qs_slot < 1 or first_qs_slot > 99 then uerror = "first quick save " .. first_qs_slot .. " invalid, valid range 1-99" end if last_qs_slot < 1 or last_qs_slot > 99 then uerror = "last quick save " .. last_qs_slot .. " invalid, valid range 1-99" end VERBOSE = dlog.VERBOSE.value end until rc < 0 or uerror:len () == 0 if rc > 0 then return true else return false end end -- -- just being thorough here -- function CheckAAs ( aalist ) local err = "" for ii = 1, aalist:len () do local aac = aalist:sub ( ii, ii ) local aar = AminoAcids [ aac ] if aar == nil then err = "invalid amino acid \"" .. aac .. "\" specified" break else if not aar.polar then err = "amino acid \"" .. aac .. "\" is not polar" break end end end return err end function NoMutablesFound () local ask = dialog.CreateDialog ( ReVersion .. " no mutables found" ) ask.l15 = dialog.AddLabel ( "No mutable segments found in this puzzle." ) ask.l20 = dialog.AddLabel ( "This recipe only works on design puzzles," ) ask.l30 = dialog.AddLabel ( "which have segments that can be mutated (mutable segments)." ) ask.l35 = dialog.AddLabel ( "Also, a \"Hydrogen Bond Network\" condition is required." ) ask.OK = dialog.AddButton ( "OK", 1 ) dialog.Show ( ask ) end function NoMutablesSpecd () local ask = dialog.CreateDialog ( ReVersion .. " no mutables specified" ) ask.l15 = dialog.AddLabel ( "No mutable segments specified." ) ask.l20 = dialog.AddLabel ( "You can specify which segments to mutate in two ways:" ) ask.l25 = dialog.AddLabel ( "1) freeze all, then unfreeze the sidechains you want to mutate" ) ask.l35 = dialog.AddLabel ( "2) specifying numeric ranges in the segment ranges box" ) ask.OK = dialog.AddButton ( "OK", 1 ) dialog.Show ( ask ) end function NoHbondFilter () local ask = dialog.CreateDialog ( ReVersion .. " no Hydrogen Bond Network condition" ) ask.l15 = dialog.AddLabel ( "This puzzle doesn't have a condition (filter)" ) ask.l20 = dialog.AddLabel ( "called \"Hydrogen Bond Network\"." ) ask.l25 = dialog.AddLabel ( "This recipe only works on puzzles with this condition." ) ask.OK = dialog.AddButton ( "OK", 1 ) dialog.Show ( ask ) end function main () Ident ( ReVersion ) -- -- initialize -- seedRandom () n_residues = structure.GetCount () n_mutables = 0 for ii = 1, n_residues do if structure.IsMutable ( ii ) then n_mutables = n_mutables + 1 end end if n_mutables == 0 then NoMutablesFound () cleanup () -- cleanup is just a regular function call here return -- we still need to leave once cleanup is done end filter.EnableAll () init_score = GetScore () print ( "initial score = " .. r3 ( init_score ) ) best_score = init_score local hbond_filter = false filter_list = filter.GetNames () print ( #filter_list .. " Filters" ) for ii = 1, #filter_list do local filt = { name = "", hasbonus = false, initbonus = 0, currbonus = 0, initsatisfied = false, currsatisfied = false, } filt.name = filter_list [ ii ] if not filter.IsEnabled ( filt.name ) then filter.Enable ( filt.name ) end filt.hasbonus = filter.HasBonus ( filt.name ) if filt.hasbonus then filt.initbonus = filter.GetBonus ( filt.name ) end filt.initsatisfied = filter.ConditionSatisfied ( filt.name ) filter_stat [ #filter_stat + 1 ] = filt local filtinfo = "" if filt.hasbonus then filtinfo = filtinfo .. "score = " .. r3 ( filt.initbonus ) else if filt.initsatisfied then filtinfo = filtinfo .. "satsified" else filtinfo = filtinfo .. "not satisfied" end end if filt.name == "Hydrogen Bond Network" then hbond_filter = true filter.Enable ( filt.name ) print ( "Enabling " .. filt.name .. ", " .. filtinfo ) else filter.Disable ( filt.name ) print ( "Disabling " .. filt.name .. ", " .. filtinfo ) end end if not hbond_filter then NoHbondFilter () cleanup () return end init_filter_score = GetFilterScore () print ( "initial hydrogen bond network score " .. r3 ( init_filter_score ) ) band.DisableAll () undo.SetUndo ( false ) save.Quicksave ( start_slot ) if GetParameters () == false then cleanup () return -- graceful exit end -- -- Lua method calls can be used where available -- in this case, polar_aa:len() is the method version, -- equivalent to string.len ( polar_aas ) -- n_polar_aas = polar_aas:len() if select_unfrozen == true then GetListOfMutablesUnfrozen () else GetListOfMutablesSelected () end PrintParameters () if #mutable_list == 0 then NoMutablesSpecd () cleanup () return end print ( "--" ) next_qs_slot = first_qs_slot Init () local mutidx = 0 if shuffle_mutables then mutable_list = ShuffleTable ( mutable_list ) end while next_qs_slot <= last_qs_slot do n_it = n_it + 1 if VERBOSE then print ( "begin run " .. n_it ) end -- -- shuffle the mutables each time, process each entry once per iteration -- if shuffle_mutables then mutidx = mutidx + 1 if mutidx > #mutable_list then mutidx = 0 end if mutidx == 0 then mutable_list = ShuffleTable ( mutable_list ) mutidx = 1 end -- -- else pick a random mutable, can repeat the same segment multiple times -- else mutidx = math.random ( #mutable_list ) end local mutate_seg = mutable_list [ mutidx ] if VERBOSE then print ( "run " .. n_it .. ", probing segment " .. mutate_seg ) end local nn = 0 local valid_replacement_found = false local replacement_aa = "" -- a bit untidy this code repeat nn = nn + 1 local kk = math.random ( n_polar_aas ) replacement_aa = string.sub ( polar_aas, kk, kk ) if structure.CanMutate ( mutate_seg, replacement_aa ) == true then structure.SetAminoAcid ( mutate_seg, replacement_aa ) sidechain_score = current.GetSegmentEnergySubscore ( mutate_seg , "Sidechain" ) if VERBOSE then print ( "mutation " .. nn .. " for segment " .. mutate_seg .. " to \"" .. replacement_aa .. "\", sidechain score " .. r3 ( sidechain_score ) ) end if sidechain_score > sidechain_minimum then valid_replacement_found = true end end until nn > 5 or valid_replacement_found == true selection.SelectAll () --structure.ShakeSidechainsSelected ( 1 ) structure.WiggleSelected ( 2 * WF, false, true ) -- all selected, but wiggle sidechains only filter_score = GetFilterScore () if filter_score > init_filter_score then if VERBOSE then print ( "run " .. n_it .. ", segment " .. mutate_seg .. ", mutated to \"" .. replacement_aa .. "\"" ) print ( "hydrogen bond network score = " .. filter_score .. ", gain = " .. r3 ( filter_score - init_filter_score ) ) end -- -- check overall score and all filters, report on changes -- filter.EnableAll () local curr_score = GetScore () if VERBOSE then print ( "current score = " .. r3 ( curr_score ) .. ", change = " .. r3 ( curr_score - init_score ) ) end for ii = 1, #filter_stat do local filt = filter_stat [ ii ] if filt.hasbonus then filt.currbonus = filter.GetBonus ( filt.name ) if filt.initbonus ~= filt.currbonus then if VERBOSE then print ( "filter \"" .. filt.name .. "\", current bonus = " .. r3 ( filt.currbonus ) .. ", change = " .. r3 ( filt.currbonus - filt.initbonus ) ) end end end filt.currsatisfied = filter.ConditionSatisfied ( filt.name ) if filt.initsatisfied ~= filt.currsatisfied then if VERBOSE then print ( "filter \"" .. filt.name .. "\" satisfied, current = " .. tostring ( filt.currsatisfied ) .. ", initial = " .. tostring ( filt.initsatisfied ) ) end end end -- -- only make saves if the current solution if the different than -- what we have -- local saveit = true for ii = 1, #slot_stat do if slot_stat [ ii ].score == curr_score then if VERBOSE then print ( "same score found in slot " .. slot_stat [ ii ].slot .. ", not saving" ) end saveit = false break end end if saveit then if VERBOSE then print ( "storing in slot " .. next_qs_slot ) else print ( "HBN score = " .. filter_score .. ", gain = " .. r3 ( filter_score - init_filter_score ) .. " --> quicksave slot " .. next_qs_slot ) end save.Quicksave ( next_qs_slot ) slot_stat [ #slot_stat + 1 ] = { slot = next_qs_slot, score = curr_score } next_qs_slot = next_qs_slot + 1 -- -- make a named save -- local solname = r3 ( curr_score ) .. ", HBN score = " .. r3 ( filter_score ) .. ", gain = " .. r3 ( filter_score - init_filter_score ) save.SaveSolution ( solname ) if VERBOSE then print ( "saved solution as \"" .. solname .. "\"" ) end end -- -- reset filters -- for ii = 1, #filter_stat do local filt = filter_stat [ ii ] if filt.name == "Hydrogen Bond Network" then filter.Enable ( filt.name ) else filter.Disable ( filt.name ) end end Init () elseif VERBOSE then print ( "no gain, run " .. n_it .. ", segment " .. mutate_seg ) end -- -- let the user know something's happening -- if n_it % 100 == 0 then if VERBOSE then print ( "number of runs completed = " .. n_it ) end end end -- while next_qs_slot <= last_qs_slot print ( "maximum quick save slot " .. last_qs_slot .. " reached, recipe complete" ) cleanup () end -- -- Ident - print identifying information at beginning and end of recipe -- -- slugline - first line to print - normally recipe name and version -- -- v0.2 - LociOiling - 20191118 -- + streamline the format -- + user.GetGroupName not working, remove -- v0.3 - LociOiling - 20201012 -- + combine user name and rank in one line -- + don't report on group at all -- function Ident ( slugline ) local function round ( ii ) return ii - ii % 0.001 end print ( slugline ) print ( "Puzzle: " .. puzzle.GetName () .. " (" .. puzzle.GetPuzzleID () .. ")" ) print ( "Track: " .. ui.GetTrackName () ) local luser = user.GetPlayerName () local scoretype = scoreboard.GetScoreType () local scort = "" if scoretype == 0 then scort = "soloist" elseif scoretype == 1 then scort = "evolver" elseif scoretype == 2 then scort = "all hands" elseif scoretype == 3 then scort = "no score" else scort = "unknown/error" end print ( "User: " .. luser .. " (" .. scort .. " #" .. scoreboard.GetRank ( scoretype ) .. ")" ) end function cleanup ( errmsg ) if CLEANUPENTRY ~= nil then return end CLEANUPENTRY = true print ( "---" ) local reason local start, stop, line, msg if errmsg == nil then reason = "complete" else -- -- civilized error reporting, thanks to Bruno K. and Jean-Bob -- start, stop, line, msg = errmsg:find ( ":(%d+):%s()" ) if msg ~= nil then errmsg = errmsg:sub ( msg, #errmsg ) end if errmsg:find ( "Cancelled" ) ~= nil then reason = "cancelled" else reason = "error" end end Ident ( ReVersion .. " " .. reason ) if reason == "error" then print ( "Unexpected error detected" ) print ( "Error line: " .. line ) print ( "Error: \"" .. errmsg .. "\"" ) end print ( "number of runs " .. n_it ) undo.SetUndo ( true ) if next_qs_slot > first_qs_slot then print ( "Loading quick saves " .. first_qs_slot .. " to " .. next_qs_slot - 1 ) for ii = first_qs_slot , next_qs_slot - 1 do save.Quickload ( ii ) end else print ( "No gain, restoring starting pose" ) save.Quickload ( start_slot ) end band.EnableAll () filter.EnableAll () local final_score = GetScore () print ( "final score = " .. r3 ( final_score ) ) print ( "gain = " .. r3 ( final_score - init_score ) ) for ii = 1, #filter_stat do local filt = filter_stat [ ii ] if filt.hasbonus then filt.currbonus = filter.GetBonus ( filt.name ) if filt.initbonus ~= filt.currbonus then print ( "filter \"" .. filt.name .. "\", current bonus = " .. r3 ( filt.currbonus ) .. ", change = " .. r3 ( filt.currbonus - filt.initbonus ) ) end end filt.currsatisfied = filter.ConditionSatisfied ( filt.name ) if filt.initsatisfied ~= filt.currsatisfied then print ( "filter \"" .. filt.name .. "\" satisfied, current = " .. tostring ( filt.currsatisfied ) .. ", initial = " .. tostring ( filt.initsatisfied ) ) end end end xpcall ( main, cleanup )

Comments


malphis Lv 1

This is a simple modification of version 2.3 by LociOiling. See the script comments for attributions.

All I've done is moved more of the print statements to VERBOSE mode and added a print statement to produce concise output that resembles version 2.0 (by spvincent) more closely:

-- HBN score = 1350, gain = 1350 --> quicksave slot 13 HBN score = 1575, gain = 1575 --> quicksave slot 14 HBN score = 1350, gain = 1350 --> quicksave slot 15 HBN score = 1350, gain = 1350 --> quicksave slot 16 ---