From 9b6c7b0d8155de404e3b51b153fe7de2a347b7aa Mon Sep 17 00:00:00 2001 From: Marisa Kirisame Date: Sun, 21 Feb 2021 02:00:43 +0100 Subject: [PATCH] Implement minimap (like radar from SWWM Z but better). Make item sense detect Chanceboxes too. Cache LOCKDEFS parsing. --- README.md | 4 +- cvarinfo.txt | 1 + graphics/HUD/MinimapBox.png | Bin 0 -> 169 bytes language.def_menu | 2 + language.es_menu | 2 + language.version | 4 +- menudef.txt | 1 + zscript/swwm_handler.zsc | 168 +++++++++++++++++++++- zscript/swwm_hud.zsc | 275 ++++++++++++++++++++++++++++++++++-- zscript/swwm_player.zsc | 7 +- zscript/swwm_thinkers.zsc | 159 ++++++++++++++++++++- zscript/swwm_utility.zsc | 90 +++++++----- 12 files changed, 657 insertions(+), 56 deletions(-) create mode 100644 graphics/HUD/MinimapBox.png diff --git a/README.md b/README.md index 26a95e5fb..6a3b0ad30 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Some Weird Weapons Mod ~ GZDoom Edition ![](docimg/logo.png) -**SWWM GZ** brings to **GZDoom** a "best of" collection of custom weapons I've made for **Unreal Tournament**, plus many new things that didn't make the cut there. +**SWWM GZ** brings to **GZDoom** a "best of" collection of custom weapons I've made for **Unreal Tournament**, plus many new things that didn't make the cut there. It is also effectively a reboot of the entire **SWWM** series, which unfortunately ended with the cancelled **SWWM Z**, this mod's direct predecessor. It contains weapons and items remastered and revived from old projects such as the previous **SWWM** entries, along with the **Zanaveth Ultra Suite** side project, and also notably, the main **UnSX** series that never truly saw the light of day, as all work done on it so far has been lost forever. There may also be some original things here and there just to spice things up. @@ -491,6 +491,8 @@ In **Doom** and **Heretic**, collected keys will be displayed below the score bo When the **Automap** is open, the map name and stats will also be shown here. +Optionally, a minimap can be shown below the score box too. This works mostly like the radar did in **SWWM Z**, but it has the added benefit of also showing map geometry. Colors are taken from GZDoom's own custom automap settings. + ### Bottom left corner Your health and fuel, along with an inventory box, and all active armors and powerups (with their respective durability/duration). diff --git a/cvarinfo.txt b/cvarinfo.txt index 31cfa5598..9af52fda8 100644 --- a/cvarinfo.txt +++ b/cvarinfo.txt @@ -100,6 +100,7 @@ user int swwm_numcolor_dmg = 6; // font color for damage numbers (default: red user int swwm_numcolor_hp = 7; // font color for health numbers (default: blue) user int swwm_numcolor_ap = 3; // font color for armor numbers (default: green) server int swwm_drlaskill = 3; // [DRLA Monsters] skill setting for monster spawns +user bool swwm_showminimap = false; // show a minimap below the score counter server noarchive bool swwm_iseriouslywanttoplaythiswithbd = false; // self-explanatory diff --git a/graphics/HUD/MinimapBox.png b/graphics/HUD/MinimapBox.png new file mode 100644 index 0000000000000000000000000000000000000000..2b6d1cacf89a3fc34ce750e5563a0266bbadaf23 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0y~yU4^NCfzVxH7;12akY&go1*B zgF`}nLjQhA{Uy8%3=B*qL4LsuXP!7ZFJ@q1u=8|r4DslEd&-cPK|z4!AUB_fz=wle z`i#sX3XFdvcFcNnWpTAnbkx-=O{bq0?Tpcz4x;4m&0Hp^byt+1Q%^hKUXS@Ckd>aU KelF{r5}E)hoiQf> literal 0 HcmV?d00001 diff --git a/language.def_menu b/language.def_menu index 9892da47a..a107e71f8 100644 --- a/language.def_menu +++ b/language.def_menu @@ -205,6 +205,7 @@ SWWM_DRLASKILL_NIGHTMARE = "Nightmare"; SWWM_DRLASKILL_TECHNOPHOBIA = "Technophobia"; SWWM_DRLASKILL_ARMAGEDDON = "Armageddon"; SWWM_DRLASKILL_ADAPTIVE = "Adaptive"; +SWWM_SHOWMINIMAP = "Show Minimap"; TOOLTIP_SWWM_VOICETYPE = "Sets the voice pack for the player."; TOOLTIP_SWWM_MUTEVOICE = "Control what gets muted, if you'd rather have a more silent protagonist."; TOOLTIP_SWWM_FLASHSTRENGTH = "Screen flashes usually happen when firing some weapons, you can lower this if these effects are harmful for you."; @@ -295,6 +296,7 @@ TOOLTIP_SWWM_NUMCOLOR_DMG = "Select the color for damage numbers."; TOOLTIP_SWWM_NUMCOLOR_HP = "Select the color for health numbers."; TOOLTIP_SWWM_NUMCOLOR_AP = "Select the color for armor numbers."; TOOLTIP_SWWM_DRLASKILL = "[DRLA Monsters] Sets the skill level for enemy spawns."; +TOOLTIP_SWWM_SHOWMINIMAP = "Displays a minimap under the score counter."; // knowledge base SWWM_COMINGSOON = "(coming soon)"; SWWM_MISSTAB = "Mission"; diff --git a/language.es_menu b/language.es_menu index 1263454c6..ef67354d0 100644 --- a/language.es_menu +++ b/language.es_menu @@ -202,6 +202,7 @@ SWWM_DRLASKILL_NIGHTMARE = "Pesadilla"; SWWM_DRLASKILL_TECHNOPHOBIA = "Tecnofobia"; SWWM_DRLASKILL_ARMAGEDDON = "Armagedón"; SWWM_DRLASKILL_ADAPTIVE = "Adaptado"; +SWWM_SHOWMINIMAP = "Mostrar Minimapa"; TOOLTIP_SWWM_VOICETYPE = "Selecciona el pack de voz para el jugador."; TOOLTIP_SWWM_MUTEVOICE = "Controla lo que se mutea, si prefieres tener un protagonista más silencioso."; TOOLTIP_SWWM_FLASHSTRENGTH = "Los destellos en pantalla suelen ocurrir al disparar algunas armas, puedes reducirlo si este tipo de efectos te causan malestar."; @@ -292,6 +293,7 @@ TOOLTIP_SWWM_NUMCOLOR_DMG = "Selecciona el color para los números de daño."; TOOLTIP_SWWM_NUMCOLOR_HP = "Selecciona el color para los números de salud."; TOOLTIP_SWWM_NUMCOLOR_AP = "Selecciona el color para los números de armadura."; TOOLTIP_SWWM_DRLASKILL = "[DRLA Monsters] Elige el nivel de dificultad para spawns de enemigos."; +TOOLTIP_SWWM_SHOWMINIMAP = "Muestra un minimapa bajo el contador de puntuación."; // knowledge base SWWM_COMINGSOON = "(próximamente)"; SWWM_MISSTAB = "Misión"; diff --git a/language.version b/language.version index 555c28c41..7731ac096 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r290 \cu(Fri 19 Feb 14:20:14 CET 2021)\c-"; -SWWM_SHORTVER="\cw0.9.11b-pre r290 \cu(2021-02-19 14:20:14)\c-"; +SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r291 \cu(Sun 21 Feb 02:00:43 CET 2021)\c-"; +SWWM_SHORTVER="\cw0.9.11b-pre r291 \cu(2021-02-21 02:00:43)\c-"; diff --git a/menudef.txt b/menudef.txt index 32453dbb0..aab15f440 100644 --- a/menudef.txt +++ b/menudef.txt @@ -99,6 +99,7 @@ OptionMenu "SWWMOptionMenu" Slider "$SWWM_CHATLEN", "swwm_chatduration", 1, 30, 1, 0 Slider "$SWWM_MSGLEN", "swwm_msgduration", 1, 30, 1, 0 Slider "$SWWM_PICKLEN", "swwm_pickduration", 1, 30, 1, 0 + Option "$SWWM_SHOWMINIMAP", "swwm_showminimap", "YesNo" Option "$SWWM_TARGET", "swwm_targeter", "YesNo" Option "$SWWM_TARGETTAG", "swwm_targettags", "YesNo" Option "$SWWM_DAMAGETARGET", "swwm_damagetarget", "SWWMDamageTarget" diff --git a/zscript/swwm_handler.zsc b/zscript/swwm_handler.zsc index 4e334623c..7570e7793 100644 --- a/zscript/swwm_handler.zsc +++ b/zscript/swwm_handler.zsc @@ -226,7 +226,8 @@ Class SWWMHandler : EventHandler SWWMCombatTracker trackers; SWWMScoreObj scorenums, damnums; SWWMInterest intpoints; - int trackers_cnt, scorenums_cnt, damnums_cnt, intpoints_cnt; + SWWMSimpleTracker strackers; + int trackers_cnt, scorenums_cnt, damnums_cnt, intpoints_cnt, strackers_cnt; bool tookdamage[MAXPLAYERS]; int spreecount[MAXPLAYERS]; int lastkill[MAXPLAYERS]; @@ -306,6 +307,10 @@ Class SWWMHandler : EventHandler bool hasdrlamonsters; + // for minimap + Array ffsectors; + transient CVar showmini; + enum EVanillaMap { MAP_NONE, @@ -828,6 +833,70 @@ Class SWWMHandler : EventHandler } } + private void SetupLockdefsCache( SWWMCachedLockInfo cli ) + { + for ( int i=0; i lines; + lines.Clear(); + data.Split(lines,"\n"); + bool valid = false; + for ( int j=0; j spl; + spl.Clear(); + lines[j].Split(spl," ",TOK_SKIPEMPTY); + // check game string (if any) + if ( spl.Size() > 2 ) + { + if ( (spl[2] ~== "DOOM") && !(gameinfo.gametype&GAME_Doom) ) continue; + else if ( (spl[2] ~== "HERETIC") && !(gameinfo.gametype&GAME_Heretic) ) continue; + else if ( (spl[2] ~== "HEXEN") && !(gameinfo.gametype&GAME_Hexen) ) continue; + else if ( (spl[2] ~== "STRIFE") && !(gameinfo.gametype&GAME_Strife) ) continue; + else if ( (spl[2] ~== "CHEX") && !(gameinfo.gametype&GAME_Chex) ) continue; + } + // valid lock, prepare it + let li = new("LIEntry"); + li.locknumber = spl[1].ToInt(); + li.hascolor = false; + // see if there's a Mapcolor defined + int k = j+1; + for ( int k=j+2; k skipme; skipme.Clear(); @@ -1321,6 +1411,81 @@ Class SWWMHandler : EventHandler mapclearagain++; } + // "simple" tracking (used by the minimap) + private void SimpleTracking() + { + if ( !showmini ) showmini = CVar.GetCVar('swwm_showminimap',players[consoleplayer]); + if ( !showmini.GetBool() ) + { + while ( strackers ) + { + SWWMSimpleTracker next = strackers.next; + strackers.Destroy(); + strackers = next; + } + strackers_cnt = 0; + return; + } + // update trackers for anything around the player + bool thesight = players[consoleplayer].mo.FindInventory("Omnisight"); + BlockThingsIterator bt = BlockThingsIterator.Create(players[consoleplayer].Camera,SWWMStatusBar.MAPVIEWDIST); + while ( bt.Next() ) + { + let a = bt.Thing; + if ( !a ) continue; + Vector2 rv = a.pos.xy-players[consoleplayer].Camera.pos.xy; + if ( max(abs(rv.x)-a.radius,abs(rv.y)-a.radius) > SWWMStatusBar.MAPVIEWDIST ) + continue; + if ( a == players[consoleplayer].Camera ) + continue; + if ( !a.player && !a.bISMONSTER && !a.bFRIENDLY && !(a is 'Inventory') && !(a is 'Chancebox') ) + continue; + if ( !thesight && !a.IsFriend(players[consoleplayer].mo) && !players[consoleplayer].Camera.CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) + continue; + if ( a.bKILLED ) + continue; + if ( (a is 'Inventory') && (!a.bSPECIAL || Inventory(a).Owner) ) + continue; + if ( (a is 'Chancebox') && (a.CurState != a.SpawnState) ) + { + // "last breath" update + for ( SWWMSimpleTracker t=strackers; t; t=t.next ) + { + if ( t.target != a ) continue; + if ( !t.expired ) t.Update(); + } + continue; + } + SWWMSimpleTracker.Track(a); + } + // prune expired trackers + SWWMSimpleTracker trk = strackers; + while ( trk ) + { + SWWMSimpleTracker next = trk.next; + // minimize lifespan of destroyed targets + if ( !trk.target ) + trk.lastupdate = min(trk.lastupdate,level.maptime); + else if ( !trk.expired ) + { + // "last breath" update + if ( trk.target.bKILLED + || ((trk.target is 'Inventory') && (!trk.target.bSPECIAL || Inventory(trk.target).Owner)) + || ((trk.target is 'Chancebox') && (trk.target.CurState != trk.target.SpawnState)) ) + trk.Update(); + } + if ( trk.lastupdate+140 < level.maptime ) + { + if ( !trk.prev ) strackers = trk.next; + else trk.prev.next = trk.next; + if ( trk.next ) trk.next.prev = trk.prev; + trk.Destroy(); + strackers_cnt--; + } + trk = next; + } + } + override void WorldTick() { LangRefresh(); @@ -1373,6 +1538,7 @@ Class SWWMHandler : EventHandler ItemCountTrack(); CombatTrack(); OneHundredPercentCheck(); + SimpleTracking(); if ( initialized ) return; // wait until bosses are active for ( int i=0; i MPlus // Miniwi -> k6x8 @@ -542,9 +548,8 @@ Class SWWMStatusBar : BaseStatusBar { if ( senseitems.Size() != demo.itemsense_cnt ) senseitems.Resize(demo.itemsense_cnt); - total_sz = demo.itemsense_cnt; i = 0; - for ( SWWMItemSense s=demo.itemsense; s && (i= 2 ) return true; + if ( (l.special == Door_Open) + || (l.special == Door_Close) + || (l.special == Door_CloseWaitOpen) + || (l.special == Door_Raise) + || (l.special == Door_Animated) + || (l.special == Generic_Door) ) + return false; + return true; + } + private bool CmpFloorPlanes( Line l ) + { + return (l.frontsector.floorplane.Normal == l.backsector.floorplane.Normal) + && (l.frontsector.floorplane.D == l.backsector.floorplane.D); + } + private bool CmpCeilingPlanes( Line l ) + { + return (l.frontsector.ceilingplane.Normal == l.backsector.ceilingplane.Normal) + && (l.frontsector.ceilingplane.D == l.backsector.ceilingplane.D); + } + + private int CheckSecret( Line l ) + { + if ( l.frontsector && (l.frontsector.flags&Sector.SECF_WASSECRET) ) + { + if ( am_map_secrets && !(l.frontsector.flags&Sector.SECF_SECRET) ) return 1; + if ( (am_map_secrets == 2) && !(l.flags&Line.ML_SECRET) ) return 2; + } + if ( l.backsector && (l.backsector.flags&Sector.SECF_WASSECRET) ) + { + if ( am_map_secrets && !(l.backsector.flags&Sector.SECF_SECRET) ) return 1; + if ( (am_map_secrets == 2) && !(l.flags&Line.ML_SECRET) ) return 2; + } + return 0; + } + private bool CheckFFBoundary( Line l ) + { + if ( !hnd || !hnd.ffsectors.Size() ) return false; + int frontidx = hnd.ffsectors.Find(l.frontsector.Index()); + int backidx = hnd.ffsectors.Find(l.backsector.Index()); + // no 3D floors, no boundary + if ( (frontidx == hnd.ffsectors.Size()) && (backidx == frontidx) ) + return false; + return true; + } + + private void DrawMapLines( Vector2 basepos ) + { + Vector2 cpos = CPlayer.Camera.prev.xy*(1.-FracTic)+CPlayer.Camera.pos.xy*FracTic; + for ( int i=0; i= 4)) ) + continue; + Vector2 rv1 = l.v1.p-cpos, rv2 = l.v2.p-cpos; + if ( min(min(abs(rv1.x),abs(rv2.x)),min(abs(rv1.y),abs(rv2.y))) > MAPVIEWDIST ) + continue; + // flip Y + rv1.y *= -1; + rv2.y *= -1; + // rotate by view + rv1 = Actor.RotateVector(rv1,ViewRot.x-90); + rv2 = Actor.RotateVector(rv2,ViewRot.x-90); + // clip to frame + bool visible; + [visible, rv1, rv2] = SWWMUtility.LiangBarsky((-1,-1)*CLIPDIST,(1,1)*CLIPDIST,rv1,rv2); + if ( !visible ) continue; + // scale to minimap frame + rv1 *= (HALFMAPSIZE/double(CLIPDIST))*hs.x; + rv2 *= (HALFMAPSIZE/double(CLIPDIST))*hs.x; + // offset to minimap center + rv1 += basepos; + rv2 += basepos; + // get the line color + Color col = am_wallcolor; + if ( (l.flags&Line.ML_MAPPED) || am_cheat ) + { + int secwit = CheckSecret(l); + int lock = SWWMUtility.GetLineLock(l); + if ( secwit == 1 ) col = am_secretsectorcolor; + else if ( secwit == 2 ) col = am_unexploredsecretcolor; + else if ( l.flags&Line.ML_SECRET ) + { + if ( am_cheat && l.backsector ) + col = am_secretwallcolor; + else col = am_wallcolor; + } + else if ( (l.special == Exit_Normal) + || (l.special == Exit_Secret) + || (l.special == Teleport_NewMap) + || (l.special == Teleport_EndGame) ) + col = am_interlevelcolor; + else if ( (l.activation&SPAC_PlayerActivate) + && (l.special == Teleport) + || (l.special == Teleport_NoFog) + || (l.special == Teleport_ZombieChanger) + || (l.special == Teleport_Line) ) + col = am_intralevelcolor; + else if ( (lock > 1) && (lock < 256) && SWWMUtility.IsValidLockNum(lock) ) + col = SWWMUtility.GetLockColor(lock); + else if ( (l.activation&SPAC_PlayerActivate) && l.special && ShowTriggerLine(l) ) + col = am_specialwallcolor; + else if ( l.frontsector && l.backsector ) + { + if ( !CmpFloorPlanes(l) ) col = am_fdwallcolor; + else if ( !CmpCeilingPlanes(l) ) col = am_cdwallcolor; + else if ( CheckFFBoundary(l) ) col = am_efwallcolor; + else + { + if ( (am_cheat == 0) || (am_cheat >= 4) ) + continue; + col = am_tswallcolor; + } + } + } + else col = am_notseencolor; + // draw the line + Screen.DrawThickLine(int(rv1.x),int(rv1.y),int(rv2.x),int(rv2.y),max(1.,hs.x*.5),col); + } + } + private void DrawMapThings( Vector2 basepos ) + { + bool thesight = !!CPlayer.mo.FindInventory("Omnisight"); + Vector2 cpos = CPlayer.Camera.prev.xy*(1.-FracTic)+CPlayer.Camera.pos.xy*FracTic; + for ( SWWMSimpleTracker t=hnd.strackers; t; t=t.next ) + { + Color col = am_thingcolor; + bool isitem = false; + Vector2 pos; + double angle; + double radius; + if ( t.target ) + { + pos = t.target.prev.xy*(1.-FracTic)+t.target.pos.xy*FracTic; + angle = t.target.angle; + radius = t.target.radius; + if ( t.isitem ) + { + if ( ((t.target is 'Chancebox') && (t.target.CurState == t.target.SpawnState)) || (t.target is 'SWWMCollectible') ) col = "Purple"; + else if ( t.target.bCOUNTITEM || (t.target is 'Key') ) col = am_thingcolor_citem; + else col = am_thingcolor_item; + isitem = true; + } + else if ( t.target.player ) col = t.target.player.GetColor(); + else if ( t.target.bFRIENDLY ) col = am_thingcolor_friend; + else if ( t.target.bCOUNTKILL ) col = am_thingcolor_monster; + else if ( t.target.bISMONSTER ) col = am_thingcolor_ncmonster; + } + else + { + pos = t.pos.xy; + angle = t.angle; + radius = t.radius; + if ( t.isitem ) + { + if ( t.vipitem ) col = "Purple"; + else if ( t.countitem ) col = am_thingcolor_citem; + else col = am_thingcolor_item; + isitem = true; + } + if ( t.isplayer ) col = t.playercol; + else if ( t.friendly ) col = am_thingcolor_friend; + else if ( t.countkill ) col = am_thingcolor_monster; + else if ( t.ismonster ) col = am_thingcolor_ncmonster; + } + int mtime = 35; + if ( thesight && !t.expired ) mtime += 105; + double alph = clamp(((t.lastupdate+mtime)-level.maptime)/35.,0.,1.); + if ( alph <= 0. ) continue; + Vector2 rv = pos-cpos; + if ( min(abs(rv.x)-radius,abs(rv.y)-radius) > MAPVIEWDIST ) continue; + // get actor triangle + Vector2 tv[4]; + int nidx = isitem?4:3; + if ( isitem ) + { + tv[0] = rv+(-10,-10); + tv[1] = rv+(10,10); + tv[2] = rv+(10,-10); + tv[3] = rv+(-10,10); + } + else + { + tv[0] = rv+Actor.RotateVector((radius,0),angle); + tv[1] = rv+Actor.RotateVector((-radius,radius),angle); + tv[2] = rv+Actor.RotateVector((-radius,-radius),angle); + } + // flip Y + for ( int j=0; j 0) ) { if ( !showitems ) showitems = CVar.GetCVar('am_showitems',players[consoleplayer]); @@ -878,7 +1137,7 @@ Class SWWMStatusBar : BaseStatusBar if ( !showsecrets ) showsecrets = CVar.GetCVar('am_showsecrets',players[consoleplayer]); if ( !showtime ) showtime = CVar.GetCVar('am_showtime',players[consoleplayer]); if ( !showtotaltime ) showtotaltime = CVar.GetCVar('am_showtotaltime',players[consoleplayer]); - int xx = int(ss.x-(margin+2)); + xx = int(ss.x-(margin+2)); String str; Font fnt; if ( automapactive || (fstats > 1) ) diff --git a/zscript/swwm_player.zsc b/zscript/swwm_player.zsc index 72c50d16e..0b27c3b2d 100644 --- a/zscript/swwm_player.zsc +++ b/zscript/swwm_player.zsc @@ -462,8 +462,11 @@ Class Demolitionist : PlayerPawn let bt = BlockThingsIterator.Create(self,800); while ( bt.Next() ) { - let i = Inventory(bt.Thing); - if ( !i || i.bINVISIBLE || !i.bSPECIAL || i.Owner || !SWWMUtility.SphereIntersect(i,pos,800) ) continue; + let i = bt.Thing; + if ( !i || (!(i is 'Inventory') && !(i is 'Chancebox')) ) continue; + if ( (i is 'Inventory') && (i.bINVISIBLE || !i.bSPECIAL || Inventory(i).Owner) ) continue; + if ( (i is 'Chancebox') && (i.CurState != i.SpawnState) ) continue; + if ( !SWWMUtility.SphereIntersect(i,pos,800) ) continue; if ( !thesight && !CheckSight(i,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; SWWMItemSense.Spawn(self,i); } diff --git a/zscript/swwm_thinkers.zsc b/zscript/swwm_thinkers.zsc index ca5a6fe3d..052d362d2 100644 --- a/zscript/swwm_thinkers.zsc +++ b/zscript/swwm_thinkers.zsc @@ -757,15 +757,15 @@ Class SWWMInterest : Thinker Class SWWMItemSense : Thinker { - Inventory item; + Actor item; String tag; int updated; - bool scoreitem; + bool scoreitem, vipitem; Demolitionist parent; SWWMItemSense prev, next; Vector3 pos; - static SWWMItemSense Spawn( Demolitionist parent, Inventory item ) + static SWWMItemSense Spawn( Demolitionist parent, Actor item ) { if ( !parent || !item ) return null; // only refresh the updated time if existing @@ -779,7 +779,8 @@ Class SWWMItemSense : Thinker let i = new("SWWMItemSense"); i.ChangeStatNum(STAT_USER); i.item = item; - i.scoreitem = item.bCOUNTITEM; + i.scoreitem = (item is 'Key')||item.bCOUNTITEM; + i.vipitem = (item is 'Chancebox')||(item is 'SWWMCollectible'); i.parent = parent; i.updated = level.maptime+35; i.UpdateTag(); @@ -800,7 +801,7 @@ Class SWWMItemSense : Thinker || (item is 'BlackShell') || (item is 'PurpleShell') || (item is 'GoldShell') || (item is 'SMW05Ammo') || (item is 'SheenAmmo') ) - tag = item.PickupMessage(); + tag = Inventory(item).PickupMessage(); else tag = item.GetTag(); } @@ -1307,3 +1308,151 @@ Class SWWMCrusherBroken : Thinker } } } + +// cache data for manual lockdefs parsing nonsense +Class LIEntry +{ + int locknumber; + bool hascolor; + Color mapcolor; +} + +Class SWWMCachedLockInfo : Thinker +{ + Array ent; + + static clearscope bool IsValidLock( int l ) + { + let ti = ThinkerIterator.Create("SWWMCachedLockInfo",STAT_STATIC); + SWWMCachedLockInfo cli = SWWMCachedLockInfo(ti.Next()); + if ( !cli ) return false; + for ( int i=0; i t1 ) return false; + else if ( r > t0 ) t0 = r; + } + else if ( p > 0 ) + { + r = q/p; + if ( r < t0 ) return false; + else if ( r < t1 ) t1 = r; + } + } + Vector2 ov0 = v0+(xdelta,ydelta)*t0; + Vector2 ov1 = v0+(xdelta,ydelta)*t1; + return true, ov0, ov1; + } + static clearscope bool IsValidLockNum( int l ) { if ( (l < 1) || (l > 255) ) return true; - Array valid; - valid.Clear(); - for ( int i=0; i lines; - lines.Clear(); - data.Split(lines,"\n"); - for ( int j=0; j spl; - spl.Clear(); - lines[j].Split(spl," ",TOK_SKIPEMPTY); - // check game string (if any) - if ( spl.Size() > 2 ) - { - if ( (spl[2] ~== "DOOM") && !(gameinfo.gametype&GAME_Doom) ) continue; - else if ( (spl[2] ~== "HERETIC") && !(gameinfo.gametype&GAME_Heretic) ) continue; - else if ( (spl[2] ~== "HEXEN") && !(gameinfo.gametype&GAME_Hexen) ) continue; - else if ( (spl[2] ~== "STRIFE") && !(gameinfo.gametype&GAME_Strife) ) continue; - else if ( (spl[2] ~== "CHEX") && !(gameinfo.gametype&GAME_Chex) ) continue; - } - valid.Push(spl[1].ToInt()); - } - } - } - for ( int i=0; i