From 98b5ebecacada41ac152af0f217a0d4d038a90a7 Mon Sep 17 00:00:00 2001 From: Marisa the Magician Date: Sun, 24 Dec 2023 15:02:10 +0100 Subject: [PATCH] Rework how level stats are handled. (Note: this WILL break old saves) --- cvarinfo.base | 1 - language.def_menu | 2 - language.es_menu | 2 - language.version | 4 +- menudef.txt | 1 - zscript/handler/swwm_handler_playerevents.zsc | 1 + zscript/handler/swwm_statichandler.zsc | 4 - zscript/kbase/swwm_kbasetab_stats.zsc | 172 ++++++++++-------- zscript/menu/swwm_inter.zsc | 6 +- zscript/swwm_thinkers_player.zsc | 95 +++++++++- 10 files changed, 195 insertions(+), 93 deletions(-) diff --git a/cvarinfo.base b/cvarinfo.base index 89d7606d4..f8a3dd9a8 100644 --- a/cvarinfo.base +++ b/cvarinfo.base @@ -50,7 +50,6 @@ server int swwm_ps_resetitems = 0; // removes all carried items server int swwm_ps_resethealth = 0; // sets health back to 100 server int swwm_drlaskill = 3; // [DRLA Monsters] skill setting for monster spawns server bool swwm_singlefirst = false; // single weapons are selected before dual ones, has to be a server cvar due to limitations -nosave bool swwm_uniqstats = false; // only list stats from the same map once, rather than for each single visit nosave int swwm_filterachievements = 1; // filter for achievements at 0%: 0 - no filter, 1 - obscure text, 2 - don't show nosave noarchive bool swwm_debugview = false; // debug visual aid for various things, such as actor collision, trajectories, relationships, etc. server bool swwm_usetopickup = false; // allow item pickup only by pressing use diff --git a/language.def_menu b/language.def_menu index 32af5a52f..004bb787e 100644 --- a/language.def_menu +++ b/language.def_menu @@ -124,7 +124,6 @@ SWWM_DRLASKILL_TECHNOPHOBIA = "Technophobia"; SWWM_DRLASKILL_ARMAGEDDON = "Armageddon"; SWWM_DRLASKILL_ADAPTIVE = "Adaptive"; SWWM_SINGLEFIRST = "Single Weapons Take Priority"; -SWWM_UNIQSTATS = "Omit Repeated Map Stats"; SWWM_FILTERACHIEVEMENTS = "Achievement Filtering"; SWWM_FILTER_NONE = "No Filter"; SWWM_FILTER_OBFUSCATE = "Obfuscate"; @@ -252,7 +251,6 @@ TOOLTIP_SWWM_PS_RESETITEMS = "Clears all your carried items that aren't weapons TOOLTIP_SWWM_PS_RESETHEALTH = "Sets your health back to 100%, and removes all equipped armor."; TOOLTIP_SWWM_DRLASKILL = "[DRLA Monsters] Sets the skill level for enemy spawns."; TOOLTIP_SWWM_SINGLEFIRST = "For weapons that have dual-wield variants, enabling this will always select the single weapon first."; -TOOLTIP_SWWM_UNIQSTATS = "Clears duplicate map entries in the mission stats tab, useful to unclutter the list when moving back and forth in hubs."; TOOLTIP_SWWM_FILTERACHIEVEMENTS = "Filters out achievements at 0% in the Demolitionist Menu, if you'd rather avoid spoiling the fun. The 'Obfuscate' option is recommended, as it will at least leave a hint of things to be discovered."; TOOLTIP_SWWM_PLAYTIME = "Your total play time with this mod loaded."; TOOLTIP_SWWM_USETOPICKUP = "Prevents picking up mod items through touch, exclusively requiring a use action instead. Note that this disables the \"dropped item magnet\" feature when holding Use."; diff --git a/language.es_menu b/language.es_menu index ee1917839..6fc34b7b0 100644 --- a/language.es_menu +++ b/language.es_menu @@ -120,7 +120,6 @@ SWWM_DRLASKILL_TECHNOPHOBIA = "Tecnofobia"; SWWM_DRLASKILL_ARMAGEDDON = "Armagedón"; SWWM_DRLASKILL_ADAPTIVE = "Adaptado"; SWWM_SINGLEFIRST = "Arma Singular con Prioridad"; -SWWM_UNIQSTATS = "Omitir Estadísticas Repetidas de Mapa"; SWWM_FILTERACHIEVEMENTS = "Filtro de Logros"; SWWM_FILTER_NONE = "Sin Filtro"; SWWM_FILTER_OBFUSCATE = "Ofuscar"; @@ -247,7 +246,6 @@ TOOLTIP_SWWM_PS_RESETITEMS = "Vacía todos los ítems que llevas que no sean arm TOOLTIP_SWWM_PS_RESETHEALTH = "Resetea tu salud de vuelta al 100%, y quita toda la armadura equipada."; TOOLTIP_SWWM_DRLASKILL = "[DRLA Monsters] Elige el nivel de dificultad para spawns de enemigos."; TOOLTIP_SWWM_SINGLEFIRST = "Para armas que tienen variantes duales, activando esto selecionará siempre primero el arma singular."; -TOOLTIP_SWWM_UNIQSTATS = "Elimina entradas duplicadas de mapa en la pestaña de estadísticas de misión, útil para despejar la lista al moverse por hubs."; TOOLTIP_SWWM_FILTERACHIEVEMENTS = "Filtra logros al 0% en el Menú de Demolicionista, si prefieres no estropear la sorpresa. La opción de 'Ofuscar' es la recomendada, ya que al menos dejará pistas de cosas que quedan por descubrir."; TOOLTIP_SWWM_PLAYTIME = "Tu tiempo de juego total con este mod cargado."; TOOLTIP_SWWM_USETOPICKUP = "Evita recoger ítems del mod al tocarlos, en su lugar requiriendo exclusivamente una acción de uso. Ten en cuenta que esto deshabilita el \"imán de ítems dropeados\" al mantener la tecla de Usar."; diff --git a/language.version b/language.version index f4aa97026..d33a59469 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r1067 \cu(Sat 23 Dec 16:37:34 CET 2023)\c-"; -SWWM_SHORTVER="\cw1.3pre r1067 \cu(2023-12-23 16:37:34)\c-"; +SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r1068 \cu(Sun 24 Dec 15:02:10 CET 2023)\c-"; +SWWM_SHORTVER="\cw1.3pre r1068 \cu(2023-12-24 15:02:10)\c-"; diff --git a/menudef.txt b/menudef.txt index e5cf052a7..a20cec16f 100644 --- a/menudef.txt +++ b/menudef.txt @@ -136,7 +136,6 @@ OptionMenu "SWWMOptionMenu" Option "$SWWM_SKIPSKILL", "swwm_skipskill", "YesNo" Option "$SWWM_FORCESTATS", "swwm_forcestats", "SWWMForceStats" Option "$SWWM_PERCENTSTATS", "swwm_percentstats", "YesNo" - Option "$SWWM_UNIQSTATS", "swwm_uniqstats", "YesNo" Slider "$SWWM_HUDMARGIN", "swwm_hudmargin", 0, 10, 1, 0 SWWMScaleField "$SWWM_HUDSCALE", "swwm_hudscale", "$SWWM_HS_AUTOL", "$SWWM_HS_AUTOT" SWWMScaleField "$SWWM_HUDSCALE0", "swwm_hudscale0", "$SWWM_HS_AUTOL", "$SWWM_HS_AUTOT" diff --git a/zscript/handler/swwm_handler_playerevents.zsc b/zscript/handler/swwm_handler_playerevents.zsc index b6ef06db3..6b0c6485e 100644 --- a/zscript/handler/swwm_handler_playerevents.zsc +++ b/zscript/handler/swwm_handler_playerevents.zsc @@ -102,6 +102,7 @@ extend Class SWWMHandler } else if ( level.info.flags2&LEVEL2_RESETINVENTORY && !e.IsReturn ) s.CleanGotWeapons(); // clean up the "got weapons" so their obtain lines are played again + s.PreloadLevelStats(); // reset some vars multilevel[e.playernumber] = 0; spreecount[e.playernumber] = 0; diff --git a/zscript/handler/swwm_statichandler.zsc b/zscript/handler/swwm_statichandler.zsc index 890f7d1c6..1c863600f 100644 --- a/zscript/handler/swwm_statichandler.zsc +++ b/zscript/handler/swwm_statichandler.zsc @@ -99,10 +99,6 @@ Class SWWMStaticHandler : StaticEventHandler SWWMHandler.ClearAllShaders(); EventHandler.SendInterfaceEvent(consoleplayer,"swwmflushhud"); EventHandler.SendInterfaceEvent(consoleplayer,"swwmaprcheck"); - // quick fix for old savegames (to be removed in 1.3 release) - let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); - if ( hnd && (hnd.sbounds.Size() <= 0) ) - hnd.PrecalculateSectorBounds(); if ( !e.IsSaveGame ) return; // save version checker tainted = false; diff --git a/zscript/kbase/swwm_kbasetab_stats.zsc b/zscript/kbase/swwm_kbasetab_stats.zsc index 7daef7a39..1ef56b24c 100644 --- a/zscript/kbase/swwm_kbasetab_stats.zsc +++ b/zscript/kbase/swwm_kbasetab_stats.zsc @@ -10,7 +10,6 @@ Class DemolitionistStatsTab : DemolitionistMenuTab int ofs[4], maxofs[4]; double smofs[4]; bool drag; - LevelStat clstat; override DemolitionistMenuTab Init( DemolitionistMenu master ) { @@ -29,36 +28,15 @@ Class DemolitionistStatsTab : DemolitionistMenuTab stats = Demolitionist(players[consoleplayer].mo)?Demolitionist(players[consoleplayer].mo).mystats:null; if ( !stats ) return Super.Init(master); // because these types of stats don't actually change while the menu is open, we can initialize their lists ONLY ONCE here - if ( swwm_uniqstats ) + foreach ( s:stats.lstats ) + lists[2].items.Push(new("DemolitionistMenuMapStatItem").Init(master,s)); + // find the current level + for ( int i=0; i 0 ) w -= 8; int len[4], maxlen[4]; for ( int i=0; i<4; i++ ) maxlen[i] = 0; - foreach ( i:lists[2].items ) + for ( int i=0; i maxlen[0] ) maxlen[0] = len[0]; - if ( l.s.stotal > 0 ) - { - str = String.Format("S %d/%d",l.s.scount,l.s.stotal); - len[1] = master.mTinyFont.StringWidth(str); - if ( len[1] > maxlen[1] ) maxlen[1] = len[1]; - } - if ( l.s.itotal > 0 ) - { - str = String.Format("I %d/%d",l.s.icount,l.s.itotal); - len[2] = master.mTinyFont.StringWidth(str); - if ( len[2] > maxlen[2] ) maxlen[2] = len[2]; - } - if ( l.s.ktotal > 0 ) - { - str = String.Format("K %d/%d",l.s.kcount,l.s.ktotal); - len[3] = master.mTinyFont.StringWidth(str); - if ( len[3] > maxlen[3] ) maxlen[3] = len[3]; - } + l.GetLengths(lists[2].selected==i,len[0],len[1],len[2],len[3]); + for ( int j=0; j<4; j++ ) if ( len[j] > maxlen[j] ) maxlen[j] = len[j]; } // second pass to propagate the "max lengths" foreach ( i:lists[2].items ) @@ -626,37 +576,113 @@ Class DemolitionistMenuMapStatItem : DemolitionistMenuListItem return width; } + void GetLengths( bool selected, out int tlen, out int slen, out int ilen, out int klen ) + { + int time, par, suck, stotal, scount, itotal, icount, ktotal, kcount; + if ( selected ) + { + time = level.maptime; + par = level.partime; + suck = level.sucktime; + stotal = level.total_secrets; + scount = level.found_secrets; + itotal = level.total_items; + icount = level.found_items; + ktotal = level.total_monsters; + kcount = level.killed_monsters; + } + else + { + time = s.time; + par = s.par; + suck = s.suck; + stotal = s.stotal; + scount = s.scount; + itotal = s.itotal; + icount = s.icount; + ktotal = s.ktotal; + kcount = s.kcount; + } + int sec = Thinker.Tics2Seconds(time); + String str = String.Format("T %02d:%02d:%02d",sec/3600,(sec%3600)/60,sec%60); + tlen = master.mTinyFont.StringWidth(str); + if ( stotal > 0 ) + { + str = String.Format("S %d/%d",scount,stotal); + slen = master.mTinyFont.StringWidth(str); + } + else slen = 0; + if ( itotal > 0 ) + { + str = String.Format("I %d/%d",icount,itotal); + ilen = master.mTinyFont.StringWidth(str); + } + else ilen = 0; + if ( ktotal > 0 ) + { + str = String.Format("K %d/%d",kcount,ktotal); + klen = master.mTinyFont.StringWidth(str); + } + else klen = 0; + } + override void Drawer( Vector2 pos, bool selected ) { String str = label; if ( selected ) str = "\cd▸\c- "..str; bool smallname = master.mSmallFont.StringWidth(str)>(width-(maxlen[3]+maxlen[2]+maxlen[1]+maxlen[0]+24)); - Screen.DrawText(smallname?master.mTinyFont:master.mSmallFont,Font.CR_FIRE,master.origin.x+pos.x,master.origin.y+pos.y+smallname*2,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); + Screen.DrawText(smallname?master.mTinyFont:master.mSmallFont,(selected||s.visited)?Font.CR_FIRE:Font.CR_DARKGRAY,master.origin.x+pos.x,master.origin.y+pos.y+smallname*2,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); + if ( !selected && !s.visited ) return; double xx = pos.x+width; double yy = pos.y+2; - int sec = Thinker.Tics2Seconds(s.time); + int time, par, suck, stotal, scount, itotal, icount, ktotal, kcount; + if ( selected ) + { + time = level.maptime; + par = level.partime; + suck = level.sucktime; + stotal = level.total_secrets; + scount = level.found_secrets; + itotal = level.total_items; + icount = level.found_items; + ktotal = level.total_monsters; + kcount = level.killed_monsters; + } + else + { + time = s.time; + par = s.par; + suck = s.suck; + stotal = s.stotal; + scount = s.scount; + itotal = s.itotal; + icount = s.icount; + ktotal = s.ktotal; + kcount = s.kcount; + } + int sec = Thinker.Tics2Seconds(time); str = String.Format("%02d\cu:\c-%02d\cu:\c-%02d",sec/3600,(sec%3600)/60,sec%60); - Screen.DrawText(master.mTinyFont,((s.suck>0)&&(sec>=(s.suck*3600)))?Font.CR_RED:(sec<=s.par)?Font.CR_GOLD:Font.CR_WHITE,master.origin.x+xx-master.mTinyFont.StringWidth(str),master.origin.y+yy,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); + Screen.DrawText(master.mTinyFont,((suck>0)&&(sec>=(suck*3600)))?Font.CR_RED:(sec<=par)?Font.CR_GOLD:Font.CR_WHITE,master.origin.x+xx-master.mTinyFont.StringWidth(str),master.origin.y+yy,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); Screen.DrawText(master.mTinyFont,Font.CR_FIRE,master.origin.x+xx-maxlen[0],master.origin.y+yy,"T",DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); if ( maxlen[0] > 0 ) xx -= maxlen[0]+8; - if ( s.stotal > 0 ) + if ( stotal > 0 ) { - str = String.Format("%d\cu/\c-%d",s.scount,s.stotal); - Screen.DrawText(master.mTinyFont,(s.scount>=s.stotal)?Font.CR_GOLD:Font.CR_WHITE,master.origin.x+xx-master.mTinyFont.StringWidth(str),master.origin.y+yy,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); + str = String.Format("%d\cu/\c-%d",scount,stotal); + Screen.DrawText(master.mTinyFont,(scount>=stotal)?Font.CR_GOLD:Font.CR_WHITE,master.origin.x+xx-master.mTinyFont.StringWidth(str),master.origin.y+yy,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); Screen.DrawText(master.mTinyFont,Font.CR_FIRE,master.origin.x+xx-maxlen[1],master.origin.y+yy,"S",DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); } if ( maxlen[1] > 0 ) xx -= maxlen[1]+8; - if ( s.itotal > 0 ) + if ( itotal > 0 ) { - str = String.Format("%d\cu/\c-%d",s.icount,s.itotal); - Screen.DrawText(master.mTinyFont,(s.icount>=s.itotal)?Font.CR_GOLD:Font.CR_WHITE,master.origin.x+xx-master.mTinyFont.StringWidth(str),master.origin.y+yy,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); + str = String.Format("%d\cu/\c-%d",icount,itotal); + Screen.DrawText(master.mTinyFont,(icount>=itotal)?Font.CR_GOLD:Font.CR_WHITE,master.origin.x+xx-master.mTinyFont.StringWidth(str),master.origin.y+yy,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); Screen.DrawText(master.mTinyFont,Font.CR_FIRE,master.origin.x+xx-maxlen[2],master.origin.y+yy,"I",DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); } if ( maxlen[2] > 0 ) xx -= maxlen[2]+8; - if ( s.ktotal > 0 ) + if ( ktotal > 0 ) { - str = String.Format("%d\cu/\c-%d",s.kcount,s.ktotal); - Screen.DrawText(master.mTinyFont,(s.kcount>=s.ktotal)?Font.CR_GOLD:Font.CR_WHITE,master.origin.x+xx-master.mTinyFont.StringWidth(str),master.origin.y+yy,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); + str = String.Format("%d\cu/\c-%d",kcount,ktotal); + Screen.DrawText(master.mTinyFont,(kcount>=ktotal)?Font.CR_GOLD:Font.CR_WHITE,master.origin.x+xx-master.mTinyFont.StringWidth(str),master.origin.y+yy,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); Screen.DrawText(master.mTinyFont,Font.CR_FIRE,master.origin.x+xx-maxlen[3],master.origin.y+yy,"K",DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true); } } diff --git a/zscript/menu/swwm_inter.zsc b/zscript/menu/swwm_inter.zsc index 49b2f4c4e..dc1020ca8 100644 --- a/zscript/menu/swwm_inter.zsc +++ b/zscript/menu/swwm_inter.zsc @@ -42,11 +42,13 @@ Class SWWMStatScreen : StatusScreen TewiFont = Font.GetFont('TewiFont'); TewiFontOutline = Font.GetFont('TewiFontOutline'); MiniwiFont = Font.GetFont('MiniwiFont'); - // support for old author text style int iof; for ( int i=0; i<=1; i++ ) { + // level name may contain trailing whitespace due to DEHACKED nonsense, so strip it + lnametexts[i].StripRight(); if ( authortexts[i] != "" ) continue; + // support for old author text style if ( (iof = lnametexts[i].RightIndexOf(" - by: ")) != -1 ) // 20 heretics, spooktober { authortexts[i] = lnametexts[i].Mid(iof+7); @@ -62,8 +64,6 @@ Class SWWMStatScreen : StatusScreen authortexts[i] = lnametexts[i].Mid(iof+3); lnametexts[i].Truncate(iof); } - // level name may contain trailing whitespace due to DEHACKED nonsense, so strip it - lnametexts[i].StripRight(); } tipalpha = -1.; hs = CleanXFac_1; diff --git a/zscript/swwm_thinkers_player.zsc b/zscript/swwm_thinkers_player.zsc index 003b6938c..453400eb0 100644 --- a/zscript/swwm_thinkers_player.zsc +++ b/zscript/swwm_thinkers_player.zsc @@ -67,7 +67,8 @@ Class MonsterKill Class LevelStat { - bool hub; + bool hub, visited; + int cluster; String levelname, mapname; int kcount, ktotal; int icount, itotal; @@ -212,13 +213,87 @@ Class SWWMStats : SWWMStaticThinker } } + private LevelStat FindLevelStats( String mapname ) + { + foreach ( ls:lstats ) + { + if ( ls.mapname != mapname ) continue; + return ls; + } + return null; + } + + void PreloadLevelStats() + { + // pre-adds all unvisited levels from the current cluster + int nlevels = LevelInfo.GetLevelInfoCount(); + for ( int i=0; i