// The Demolitionist HUD is mostly built on top of what I had already done for // SWWM Z, but with lots of color, gradient text and bars, beveled borders, // drop shadows, and much more to give off this sorta "retro UI" vibe. // (The SWWM Z hud was built entirely on borderless flat graphics and smooth // gradient shadows, not exactly the finest looking aesthetic, to be honest) Class MsgLine { String str; transient BrokenLines l, ls; int tic, type, rep; int lastrep; int lastsz; void UpdateText( int sz = 0 ) { bool mustupdate = (!l||!ls||(lastrep!=rep)||((type==PRINT_LOW)&&(sz!=lastsz))); if ( !mustupdate ) return; if ( l ) l.Destroy(); if ( ls ) ls.Destroy(); lastsz = sz; lastrep = rep; String nstr = str; if ( rep > 1 ) nstr.AppendFormat(" (x%d)",rep); let fnt = Font.GetFont('TewiFont'); l = fnt.BreakLines(nstr,(type==PRINT_LOW)?sz:361); if ( type != PRINT_LOW ) ls = fnt.BreakLines(nstr,211); } } Class KeyGet { Class got; int flashtime; } Enum EMiniHUDFontColor { MCR_DEMOHUD, MCR_IBUKIHUD, MCR_SAYAHUD, MCR_KIRINHUD, MCR_MARISAHUD, MCR_VOIDHUD, MCR_WHITE, MCR_RED, MCR_GREEN, MCR_BLUE, MCR_YELLOW, MCR_CYAN, MCR_PURPLE, MCR_BRASS, MCR_SILVER, MCR_GOLD, MCR_MANA, MCR_CRIMSON, MCR_ELDRITCH, MCR_KINYLUM, MCR_NOKRON, MCR_NOKOROKINYLUM, MCR_DEMOBLUE, MCR_DEMOPINK, MCR_ORANGE, MCR_GRASS, MCR_MINT, MCR_AQUA, MCR_MAGENTA, MCR_PINK, MCR_CRYSTAL, MCR_FIRE, MCR_SULFUR, MCR_WITCH, MCR_CYANBLU, MCR_ICE, MCR_PURPUR, MCR_TOMATO, MCR_BLURP, MCR_PURB, MCR_FLASH, MCR_REDFLASH, MCR_WHITEFLASH, NUM_MINIHUD_COLOR }; Class SWWMStatusBar : BaseStatusBar { TextureID StatusTex, WeaponTex, ScoreTex, InventoryTex, ChatTex[6], HealthTex[9], FuelTex[2], DashTex, EnemyBTex, EnemyHTex[7], GenericAmmoTex[3], AmmoTex[3], MiniBox, bgtex, FaceTex[19]; Font mSmallFont, mSmallFontOutline, mTinyFont, mTinyFontOutline, MiniHUDFont, MiniHUDFontOutline; int mhudfontcol[NUM_MINIHUD_COLOR]; Array MainQueue, PickupQueue; transient ThinkerIterator cti; // the event handler, holding all sorts of stuff SWWMHandler hnd; // shared stuff double hs; double hs1; double hs2; Vector2 ss; Vector2 ss1; Vector2 ss2; int margin; double FracTic; double FrameTime; double PrevFrame; int chatopen; int pausetime; Vector2 pausepos, pausedir; // constants const MAXSHOWN = 4; const MAXSHOWNBIG = 10; const MAXPICKUP = 5; const CHATDURATION = 25; const MSGDURATION = 5; const PICKDURATION = 3; // shared from renderunderlay, needed for proper interpolation of some things Vector3 viewpos, viewrot; // projection data cache SWWMProjectionData projdata; DynamicValueInterpolator ScoreInter; Inventory lastsel; Weapon lastwep; String ntagstr; int ntagtic, ntagcol; String midstr; int midtic, midtype; transient BrokenLines midl; int midsz; int puzzlecnt, realpuzzlecnt; SWWMWeaponTooltip ctip; transient ThinkerIterator mi; // for map markers double minimapzoom, oldminimapzoom; // minimap constants const CLIPDIST = 800; // clip distance for minimap view, with rotation accounted const MAPVIEWDIST = 1132; // maximum distance for something to be considered visible (rounded up CLIPDIST*sqrt(2)) const HALFMAPSIZE = 40; // half the size of the minimap draw region (unscaled) // minimap colors (thats a lot of 'em) int mm_colorset; Color mm_backcolor, mm_cdwallcolor, mm_efwallcolor, mm_fdwallcolor, mm_interlevelcolor, mm_intralevelcolor, mm_lockedcolor, mm_notseencolor, mm_portalcolor, mm_secretsectorcolor, mm_secretwallcolor, mm_specialwallcolor, mm_thingcolor, mm_thingcolor_citem, mm_thingcolor_friend, mm_thingcolor_item, mm_thingcolor_monster, mm_thingcolor_ncmonster, mm_thingcolor_shootable, mm_thingcolor_vipitem, mm_thingcolor_missile, mm_tswallcolor, mm_unexploredsecretcolor, mm_wallcolor, mm_yourcolor; bool mm_displaylocks; // deathmatch stuff int playercount, rank, lead; bool tiedscore; Array sortplayers; Array teamactive; Array teamscore; int PulsePhase; // for health pulsing // for flashing some elements in the hud Array keyflash; int oldkills, olditems, oldsecrets; int oldtkills, oldtitems, oldtsecrets; int killflash, itemflash, secretflash; int tkillflash, titemflash, tsecretflash; // top stuff colors int tclabel, tcvalue, tcextra, tccompl, tcsucks; String tclabel_s, tcextra_s; int AmmoFlash[26]; // flash when new ammo is received int AmmoOldAmounts[26]; // to detect when to flash int AmmoMaxFlash[26]; // flash when ammo max amount changes int AmmoOldMaxAmounts[26]; // to detect when to flash Class AmmoSlots[26]; // ammo type on each slot String AmmoNames[26]; // ammo 4-letter names int HealthFlash; // flash when healing int LastHealth; // to detect when to flash int LagHealth[10]; // for delayed decay bar SmoothDynamicValueInterpolator HealthInter, FuelInter, DashInter; SmoothLinearValueInterpolator LagHealthInter; transient ui int rss; override void FlushNotify() { // flush interpolators (useful since this virtual gets called // when loading saves, too) ScoreInter.Reset(SWWMCredits.Get(CPlayer)); int hp = CPlayer.Health; HealthInter.Reset(hp); for ( int i=9; i>0; i-- ) LagHealth[i] = hp; LagHealthInter.Reset(hp); let d = Demolitionist(CPlayer.mo); if ( d ) { FuelInter.Reset(d.dashfuel/2); DashInter.Reset((40-d.dashcooldown)*3); } else { FuelInter.Reset(0); DashInter.Reset(0); } if ( level.maptime <= 1 ) { // flush ALL messages MainQueue.Clear(); PickupQueue.Clear(); return; } // flush non-chat messages for ( int i=0; i= PRINT_CHAT ) continue; MainQueue.Delete(i); i--; } // flush nametag ntagstr = ""; ntagtic = 0; } override bool ProcessMidPrint( Font fnt, String msg, bool bold ) { // hack lol if ( msg.Left(15) ~== "swwmwpntooltip." ) { String wname = msg.Mid(15); Class w = wname; if ( w ) { let tt = new("SWWMWeaponTooltip").Init(w); bool appended = false; for ( SWWMWeaponTooltip t=ctip; t; t=t.next ) { if ( t.next ) continue; appended = true; t.next = tt; break; } if ( !appended ) { ctip = tt; AttachMessage(tt,-2910); } } return true; } else if ( msg.Left(11) ~== "swwmkeyget." ) { String kname = msg.Mid(11); Class k = kname; if ( k ) { let kg = new("KeyGet"); kg.got = k; kg.flashtime = gametic+25; keyflash.Push(kg); } return true; } SWWMDirectMessage m, m2; // more hack if ( msg ~== "swwmultdoom2map20dlg" ) { m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m.seqname = "SAYAGOTCHAEND"; m.seqcnt = 5; m.delay = 40; AttachMessage(m,-1232); return true; } else if ( msg.Left(25) ~== "swwmsilverbulleteasteregg" ) { m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); let num = msg.Mid(25).ToInt(); switch ( num ) { case 1: default: m.seqname = "SAYAWASTEA"; m.seqcnt = 1; m.delay = 5; m.startdelay = 10; m.enddelay = 25; break; case 2: m.seqname = "SAYAWASTEB"; m.seqcnt = 1; m.delay = 10; m.startdelay = 20; m.enddelay = 30; break; case 3: m.seqname = "SAYAWASTEC"; m.seqcnt = 1; m.delay = 30; m.startdelay = 15; m.enddelay = 25; break; case 4: m.seqname = "SAYAWASTED"; m.seqcnt = 2; m.delay = 40; m.startdelay = 10; m.enddelay = 20; break; case 5: m.seqname = "SAYAWASTEE"; m.seqcnt = 1; m.delay = 20; m.startdelay = 10; m.enddelay = 30; break; case 6: m.seqname = "SAYAWASTEF"; m.seqcnt = 1; m.delay = 50; m.startdelay = 20; m.enddelay = 30; break; } AttachMessage(m,-1232); return true; } else if ( msg.Left(22) ~== "swwmquadravoleasteregg" ) { m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); let num = msg.Mid(22).ToInt(); switch ( num ) { case 1: default: m.seqname = "SAYALEVERA"; m.seqcnt = 1; m.delay = 5; m.startdelay = 20; m.enddelay = 50; break; case 2: m.seqname = "SAYALEVERB"; m.seqcnt = 1; m.delay = 10; m.startdelay = 30; m.enddelay = 40; break; case 3: m.seqname = "SAYALEVERC"; m.seqcnt = 1; m.delay = 30; m.startdelay = 10; m.enddelay = 25; break; case 4: m.seqname = "SAYALEVERD"; m.seqcnt = 1; m.delay = 40; m.startdelay = 10; m.enddelay = 20; break; case 5: m.seqname = "SAYALEVERE"; m.seqcnt = 1; m.delay = 20; m.startdelay = 10; m.enddelay = 30; break; case 6: m.seqname = "SAYALEVERF"; m.seqcnt = 1; m.delay = 50; m.startdelay = 20; m.enddelay = 30; break; case 7: m.seqname = "SAYALEVERG"; m.seqcnt = 2; m.delay = 50; m.startdelay = 30; m.enddelay = 50; break; } AttachMessage(m,-1232); return true; } // check for Korax lines, add them to chat (and reply to some of them) bool koraxline = false; if ( msg == StringTable.Localize("$TXT_ACS_MAP02_9_GREET") ) koraxline = true; else if ( msg == StringTable.Localize("$TXT_ACS_MAP02_11_AREYO") ) { EventHandler.SendNetworkEvent("swwmkoraxline",0,consoleplayer); koraxline = true; if ( !swwm_nomapmsg ) { m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m.seqname = "SAYAGREETA"; m.seqcnt = 3; m.delay = 150; AttachMessage(m,-1232); m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m2.seqname = "SAYAGREETB"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "SAYAGREETC"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m2.seqname = "SAYAGREETD"; m2.seqcnt = 1; m2.delay = 30; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "SAYAGREETE"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m2.seqname = "SAYAGREETF"; m2.seqcnt = 1; m2.delay = 30; m.nextmsg = m2; m.nextdirect = true; } } else if ( msg == StringTable.Localize("$TXT_ACS_MAP13_11_MYSER") ) { EventHandler.SendNetworkEvent("swwmkoraxline",1,consoleplayer); koraxline = true; if ( !swwm_nomapmsg ) { m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m.seqname = "SAYABLOODA"; m.seqcnt = 2; m.delay = 220; AttachMessage(m,-1232); m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_IBUKISNAME"),StringTable.Localize("$SWWM_IBUKINAME"),"Ibuki"); m2.seqname = "SAYABLOODB"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "SAYABLOODC"; m2.seqcnt = 1; m2.delay = 30; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_IBUKISNAME"),StringTable.Localize("$SWWM_IBUKINAME"),"Ibuki"); m2.seqname = "SAYABLOODD"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; } } else if ( msg == StringTable.Localize("$TXT_ACS_MAP22_27_YOUHA") ) koraxline = true; else if ( msg == StringTable.Localize("$TXT_ACS_MAP22_29_ITHIN") ) { EventHandler.SendNetworkEvent("swwmkoraxline",2,consoleplayer); koraxline = true; if ( !swwm_nomapmsg ) { m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m.seqname = "SAYAGAMEA"; m.seqcnt = 2; m.delay = 200; AttachMessage(m,-1232); m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_IBUKISNAME"),StringTable.Localize("$SWWM_IBUKINAME"),"Ibuki"); m2.seqname = "SAYAGAMEB"; m2.seqcnt = 1; m2.delay = 30; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "SAYAGAMEC"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; } } else if ( msg == StringTable.Localize("$TXT_ACS_MAP27_8_WORSH") ) koraxline = true; else if ( msg == StringTable.Localize("$TXT_ACS_MAP27_10_THENA") ) { EventHandler.SendNetworkEvent("swwmkoraxline",3,consoleplayer); koraxline = true; if ( !swwm_nomapmsg ) { m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m.seqname = "KIRINWORSHIPA"; m.seqcnt = 1; m.delay = 150; AttachMessage(m,-1232); m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "KIRINWORSHIPB"; m2.seqcnt = 1; m2.delay = 40; m2.enddelay = 10; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m2.seqname = "KIRINWORSHIPC"; m2.seqcnt = 1; m2.delay = 10; m2.enddelay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "KIRINWORSHIPD"; m2.seqcnt = 2; m2.delay = 10; m.nextmsg = m2; m.nextdirect = true; } } else if ( msg == StringTable.Localize("$TXT_ACS_MAP35_12_AREYO") ) koraxline = true; else if ( msg == StringTable.Localize("$TXT_ACS_MAP35_14_TOFAC") ) { EventHandler.SendNetworkEvent("swwmkoraxline",4,consoleplayer); koraxline = true; if ( !swwm_nomapmsg ) { m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m.seqname = "SAYAMASTERSA"; m.seqcnt = 2; m.delay = 150; m.enddelay = 60; AttachMessage(m,-1232); m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_IBUKISNAME"),StringTable.Localize("$SWWM_IBUKINAME"),"Ibuki"); m2.seqname = "SAYAMASTERSB"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "SAYAMASTERSC"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_IBUKISNAME"),StringTable.Localize("$SWWM_IBUKINAME"),"Ibuki"); m2.seqname = "SAYAMASTERSD"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m2.seqname = "SAYAMASTERSE"; m2.seqcnt = 1; m2.delay = 40; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "SAYAMASTERSF"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; } } if ( koraxline ) { Console.PrintfEx(PRINT_CHAT,"\cmKorax\c-: "..msg); return true; } bool ispuzzle = false; let s = SWWMStats.Find(players[consoleplayer]); if ( s ) { puzzlecnt = s.puzzlecnt; realpuzzlecnt = s.realpuzzlecnt; } // check for puzzle solving lines (oh god why), and increment the achievement if ( ((level.mapname ~== "MAP04") || (level.mapname ~== "MAP05")) && ((msg == StringTable.Localize("$TXT_ACS_MAP04_9_ONEHA")) || (msg == StringTable.Localize("$TXT_ACS_MAP04_11_ONETH")) || (msg == StringTable.Localize("$TXT_ACS_MAP05_6_ONETH"))) ) { if ( puzzlecnt >= 4 ) puzzlecnt = 0; puzzlecnt++; realpuzzlecnt++; ispuzzle = true; } else if ( ((level.mapname ~== "MAP08") || (level.mapname ~== "MAP09") || (level.mapname ~== "MAP10")) && ((msg == StringTable.Localize("$TXT_ACS_MAP08_6_ONESI")) || (msg == StringTable.Localize("$TXT_ACS_MAP09_6_ONESI")) || (msg == StringTable.Localize("$TXT_ACS_MAP10_6_ONESI"))) ) { if ( (puzzlecnt < 4) || (puzzlecnt >= 10) ) puzzlecnt = 4; puzzlecnt++; realpuzzlecnt++; ispuzzle = true; } else if ( ((level.mapname ~== "MAP28") || (level.mapname ~== "MAP30") || (level.mapname ~== "MAP34")) && ((msg == StringTable.Localize("$TXT_ACS_MAP28_6_ONENI")) || (msg == StringTable.Localize("$TXT_ACS_MAP30_6_ONENI")) || (msg == StringTable.Localize("$TXT_ACS_MAP34_1_ONENI"))) ) { if ( (puzzlecnt < 10) || (puzzlecnt >= 19) ) puzzlecnt = 10; puzzlecnt++; realpuzzlecnt++; ispuzzle = true; } // deathkings else if ( ((level.mapname ~== "MAP44") || (level.mapname ~== "MAP46")) && ((msg == StringTable.Localize("$TXT_ACS_MAP44_1_THREE")) || (msg == StringTable.Localize("$TXT_ACS_MAP44_2_TWOMO")) || (msg == StringTable.Localize("$TXT_ACS_MAP44_3_ONEMO")) || (msg == StringTable.Localize("$TXT_ACS_MAP44_4_THEPU")) || (msg == StringTable.Localize("$TXT_ACS_MAP44_10_ONETH")) || (msg == StringTable.Localize("$TXT_ACS_MAP44_11_TWOTH")) || (msg == StringTable.Localize("$TXT_ACS_MAP46_8_ONEFO"))) ) { if ( (puzzlecnt < 19) || (puzzlecnt >= 30) ) puzzlecnt = 19; puzzlecnt++; realpuzzlecnt++; ispuzzle = true; } else if ( (level.mapname ~== "MAP51") && ((msg == StringTable.Localize("$TXT_ACS_MAP51_8_ONETH")) || (msg == StringTable.Localize("$TXT_ACS_MAP51_9_TWOTH")) || (msg == StringTable.Localize("$TXT_ACS_MAP51_10_THECR"))) ) { if ( (puzzlecnt < 30) || (puzzlecnt >= 34) ) puzzlecnt = 30; puzzlecnt++; realpuzzlecnt++; ispuzzle = true; } if ( ispuzzle ) { EventHandler.SendNetworkEvent("swwmstorepuzzlecnt",consoleplayer,puzzlecnt,realpuzzlecnt); int tpuz = SWWMUtility.IsDeathkings()?15:19; if ( realpuzzlecnt >= tpuz ) SWWMUtility.MarkAchievement("puzzle",players[consoleplayer]); if ( !swwm_nomapmsg ) { switch ( puzzlecnt ) { case 1: m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m.seqname = "KIRINPUZZLEA"; m.seqcnt = 2; m.delay = 90; AttachMessage(m,-1232); break; case 2: m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m.seqname = "KIRINPUZZLEB"; m.seqcnt = 1; m.delay = 80; AttachMessage(m,-1232); break; case 3: m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m.seqname = "KIRINPUZZLEC"; m.seqcnt = 2; m.delay = 70; AttachMessage(m,-1232); break; case 5: m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m.seqname = "KIRINPUZZLED"; m.seqcnt = 2; m.delay = 70; AttachMessage(m,-1232); break; case 8: m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m.seqname = "KIRINPUZZLEE"; m.seqcnt = 2; m.delay = 60; AttachMessage(m,-1232); break; case 11: m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m.seqname = "KIRINPUZZLEF"; m.seqcnt = 3; m.delay = 60; AttachMessage(m,-1232); m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "KIRINPUZZLEG"; m2.seqcnt = 1; m.delay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m2.seqname = "KIRINPUZZLEH"; m2.seqcnt = 1; m.delay = 30; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "KIRINPUZZLEI"; m2.seqcnt = 2; m.delay = 20; m.nextmsg = m2; m.nextdirect = true; break; case 20: m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m.seqname = "KIRINPUZZLEJ"; m.seqcnt = 2; m.delay = 80; AttachMessage(m,-1232); break; case 30: m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m.seqname = "KIRINPUZZLEK"; m.seqcnt = 1; m.delay = 60; AttachMessage(m,-1232); m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_IBUKISNAME"),StringTable.Localize("$SWWM_IBUKINAME"),"Ibuki"); m2.seqname = "KIRINPUZZLEL"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m2.seqname = "KIRINPUZZLEM"; m2.seqcnt = 1; m2.delay = 10; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "KIRINPUZZLEN"; m2.seqcnt = 1; m2.delay = 30; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_IBUKISNAME"),StringTable.Localize("$SWWM_IBUKINAME"),"Ibuki"); m2.seqname = "KIRINPUZZLEO"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "KIRINPUZZLEP"; m2.seqcnt = 1; m2.delay = 30; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_IBUKISNAME"),StringTable.Localize("$SWWM_IBUKINAME"),"Ibuki"); m2.seqname = "KIRINPUZZLEQ"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; break; case 31: m = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m.seqname = "KIRINPUZZLER"; m.seqcnt = 3; m.delay = 60; AttachMessage(m,-1232); m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "KIRINPUZZLES"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_KIRINSNAME"),StringTable.Localize("$SWWM_KIRINNAME"),"Kirin"); m2.seqname = "KIRINPUZZLET"; m2.seqcnt = 1; m2.delay = 30; m.nextmsg = m2; m.nextdirect = true; m = m2; m2 = new("SWWMDirectMessage").Init(StringTable.Localize("$SWWM_SAYASNAME"),StringTable.Localize("$SWWM_SAYANAME"),"Saya"); m2.seqname = "KIRINPUZZLEU"; m2.seqcnt = 1; m2.delay = 20; m.nextmsg = m2; m.nextdirect = true; break; } } } // rampancy fun stuff bool mainframeline = false; if ( (msg == StringTable.Localize("$AISPAWN_TEXT1")) || (msg == StringTable.Localize("$AISPAWN_TEXT2")) || (msg == StringTable.Localize("$AISEE_TEXT")) || (msg == StringTable.Localize("$AIACTIVE_TEXT1")) || (msg == StringTable.Localize("$AIACTIVE_TEXT2")) || (msg == StringTable.Localize("$AIPAIN_TEXT1")) || (msg == StringTable.Localize("$AIPAIN_TEXT2")) || (msg == StringTable.Localize("$AIPAIN_TEXT3")) || (msg == StringTable.Localize("$AIPAIN_TEXT4")) || (msg == StringTable.Localize("$AIPAIN_TEXT5")) || (msg == StringTable.Localize("$AIPAIN_TEXT6")) || (msg == StringTable.Localize("$AIPAIN_TEXT7")) ) mainframeline = true; if ( mainframeline ) { Console.PrintfEx(PRINT_CHAT,"\cmAI Mainframe\c-: "..msg); return true; } if ( !fnt || (fnt == smallfont) ) { midstr = msg; midtic = level.totaltime; midtype = bold?2:0; return true; } if ( (fnt == bigfont) || (fnt == originalbigfont) ) { midstr = msg; midtic = level.totaltime; midtype = bold?3:1; return true; } return false; } override bool ProcessNotify( EPrintLevel printlevel, String outline ) { // append chat messages to full history if ( (printlevel == PRINT_CHAT) || (printlevel == PRINT_TEAMCHAT) ) EventHandler.SendNetworkEvent("swwmstoremessage."..outline.Left(outline.Length()-1),level.totaltime,printlevel,consoleplayer); // ignore during intermission if ( gamestate != GS_LEVEL ) return false; if ( (printlevel < PRINT_LOW) || (printlevel > PRINT_TEAMCHAT) ) return true; // we couldn't care less about these let m = new("MsgLine"); m.str = outline.Left(outline.Length()-1); // strip newline m.type = printlevel; m.tic = level.totaltime; m.rep = 1; if ( printlevel == PRINT_LOW ) { // check if repeated for ( int i=0; i a, int l, int h ) { PlayerInfo pv = a[h]; int i = (l-1); for ( int j=l; j<=(h-1); j++ ) { if ( pv.fragcount < a[j].fragcount ) { i++; PlayerInfo tmp = a[j]; a[j] = a[i]; a[i] = tmp; } } PlayerInfo tmp = a[h]; a[h] = a[i+1]; a[i+1] = tmp; return i+1; } private void qsort_playerscore( Array a, int l, int h ) { if ( l >= h ) return; int p = partition_playerscore(a,l,h); qsort_playerscore(a,l,p-1); qsort_playerscore(a,p+1,h); } // separated so they can be auto-ticked by the demolitionist menu void TickInterpolators() { ScoreInter.Update(SWWMCredits.Get(CPlayer)); int hp = CPlayer.Health; HealthInter.Update(hp); // flash 'em if ( hp > LastHealth ) HealthFlash = gametic+25; // lag if ( hp > LastHealth ) { for ( int i=9; i>0; i-- ) LagHealth[i] = hp; } LagHealth[0] = LastHealth = hp; LagHealthInter.Update(LagHealth[9]); for ( int i=9; i>0; i-- ) LagHealth[i] = LagHealth[i-1]; // ammo updates for ( int i=0; i<26; i++ ) { let a = SWWMAmmo(CPlayer.mo.FindInventory(AmmoSlots[i])); int amt = 0; int maxamt = 0; if ( a ) { amt = a.Amount; maxamt = a.MaxAmount; if ( a.MagAmmoType ) { let m = MagAmmo(CPlayer.mo.FindInventory(a.MagAmmoType)); if ( m ) { amt *= m.ClipSize; amt += m.Amount; maxamt *= m.ClipSize; } } } else { let a = GetDefaultByType(AmmoSlots[i]); maxamt = a.MaxAmount; if ( a.MagAmmoType ) { let m = GetDefaultByType(a.MagAmmoType); maxamt *= m.ClipSize; } } if ( (amt > AmmoOldAmounts[i]) && (AmmoOldAmounts[i] != int.min) ) AmmoFlash[i] = gametic+25; AmmoOldAmounts[i] = amt; if ( (maxamt > AmmoOldMaxAmounts[i]) && (AmmoOldMaxAmounts[i] != int.min) ) AmmoMaxFlash[i] = gametic+25; AmmoOldMaxAmounts[i] = maxamt; } } override void Tick() { Super.Tick(); pausetime = gametic; SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov); // prune old messages for ( int i=0; i PRINT_HIGH) && (level.totaltime < (MainQueue[i].tic+GameTicRate*CHATDURATION)) ) continue; MainQueue.Delete(i); i--; } // update interpolators TickInterpolators(); let d = Demolitionist(CPlayer.mo); if ( d ) { FuelInter.Update(d.dashfuel/2); DashInter.Update((40-d.dashcooldown)*3); } else { FuelInter.Update(0); DashInter.Update(0); } // stats flashing if ( level.killed_monsters > oldkills ) { oldkills = level.killed_monsters; killflash = gametic+25; } if ( level.found_items > olditems ) { olditems = level.found_items; itemflash = gametic+25; } if ( level.found_secrets > oldsecrets ) { oldsecrets = level.found_secrets; secretflash = gametic+25; } if ( level.total_monsters > oldtkills ) { oldtkills = level.total_monsters; tkillflash = gametic+25; } if ( level.total_items > oldtitems ) { oldtitems = level.total_items; titemflash = gametic+25; } if ( level.total_secrets > oldtsecrets ) { oldtsecrets = level.total_secrets; tsecretflash = gametic+25; } // purge expired key flashes for ( int i=0; i= gametic ) continue; keyflash.Delete(i--); } // low health pulsing if ( (CPlayer.health <= 0) || (CPlayer.health > 25) ) PulsePhase = 0; else { PulsePhase--; if ( (PulsePhase < 0) || (PulsePhase > CPlayer.health*2+25) ) PulsePhase = CPlayer.health*2+25; } // let weapons update their own interpolators for ( Inventory i=CPlayer.mo.inv; i; i=i.inv ) { if ( !(i is 'SWWMWeapon') ) continue; SWWMWeapon(i).HudTick(); } double desiredzoom = clamp(swwm_mm_zoom,.5,level.allmap?2.:1.); if ( (minimapzoom != swwm_mm_zoom) || (oldminimapzoom != swwm_mm_zoom) ) { oldminimapzoom = minimapzoom; double diff = .1*(desiredzoom-minimapzoom); minimapzoom += diff; if ( abs(minimapzoom-desiredzoom) <= .01 ) minimapzoom = desiredzoom; } if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); // part of gross hackery to override nametag display if ( CPlayer.inventorytics > 0 ) { if ( CPlayer.mo.InvSel && (CPlayer.mo.InvSel != lastsel) && (displaynametags&1) && (CPlayer == players[consoleplayer]) ) { ntagstr = CPlayer.mo.InvSel.GetTag(); ntagtic = level.totaltime; ntagcol = nametagcolor; } lastsel = CPlayer.mo.InvSel; } if ( CPlayer.PendingWeapon && (CPlayer.PendingWeapon != WP_NOCHANGE) && (CPlayer.PendingWeapon != lastwep) ) { if ( (displaynametags&2) && (CPlayer == players[consoleplayer]) && !(CPlayer.PendingWeapon is 'SWWMGesture') && !(CPlayer.PendingWeapon is 'SWWMItemGesture') ) { ntagstr = CPlayer.PendingWeapon.GetTag(); ntagtic = level.totaltime; ntagcol = nametagcolor; } } lastwep = CPlayer.PendingWeapon; // make sure vanilla nametags don't display DetachMessageID(0x5745504e); // WEPN DetachMessageID(0x53494e56); // SINV // also try with different endianness, just in case DetachMessageID(0x4e504557); // WEPN DetachMessageID(0x564e4953); // SINV // deathmatch stuff if ( !deathmatch ) return; if ( teamplay ) { if ( teamactive.Size() != Teams.Size() ) teamactive.Resize(Teams.Size()); if ( teamscore.Size() != Teams.Size() ) teamscore.Resize(Teams.Size()); for ( int i=0; i CPlayer.fragcount ) rank += 1; else if ( players[i].fragcount == CPlayer.fragcount ) tiedscore = true; if ( players[i].fragcount > highscore ) highscore = players[i].fragcount; } if ( sortplayers.Size() != playercount ) sortplayers.Resize(playercount); for ( int i=0, j=0; i 1000. ) return String.Format("\cj%d\cc%s",int(meters/1000.),StringTable.Localize("$SWWM_UNIT_KILOMETER")); return String.Format("\cj%d\cc%s",int(meters),StringTable.Localize("$SWWM_UNIT_METER")); } private void DrawInterest( Vector3 viewvec, out bool projinit ) { String tag; SWWMInterest poi = hnd.intpoints; if ( !poi ) return; do { // this ensures that projection data isn't cached if there are no target array elements, to avoid needless GC thrashing if ( !projinit ) { projinit = true; SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov); Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh); } Vector3 tdir = level.Vec3Diff(ViewPos,poi.pos); if ( viewvec dot tdir < 0 ) continue; Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir); if ( ndc.z >= 1. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs2; if ( poi.type == INT_Key ) tag = String.Format("\cf%s\c-",poi.keytag); else if ( poi.type == INT_Exit ) { if ( (poi.trackedline.special == Teleport_EndGame) || ((poi.trackedline.special == Exit_Secret) && (level.nextsecretmap.Left(6) == "enDSeQ")) || ((poi.trackedline.special == Exit_Normal) && (level.nextmap.Left(6) == "enDSeQ")) ) tag = String.Format("\cg%s\c-",StringTable.Localize("$SWWM_EEXIT")); else if ( poi.trackedline.special == Exit_Secret ) { LevelInfo l = LevelInfo.FindLevelInfo(level.nextsecretmap); if ( l && l.isValid() ) tag = String.Format("\cx%s:\c- %s\c-",StringTable.Localize("$SWWM_SEXIT"),l.LookupLevelName()); else tag = String.Format("\cx%s\c-",StringTable.Localize("$SWWM_SEXIT")); } else if ( (poi.trackedline.special == Exit_Normal) || ((poi.trackedline.special == ACS_Execute) && (poi.trackedline.Args[0] == -Int('E1M8_KNOCKOUT'))) ) { LevelInfo l = LevelInfo.FindLevelInfo(level.nextmap); if ( l && l.isValid() ) tag = String.Format("\cy%s:\c- %s\c-",StringTable.Localize("$SWWM_NEXIT"),l.LookupLevelName()); else tag = String.Format("\cy%s\c-",StringTable.Localize("$SWWM_NEXIT")); } else if ( poi.trackedline.special == Teleport_NewMap ) { LevelInfo l = LevelInfo.FindLevelByNum(poi.trackedline.Args[0]); if ( l && l.isValid() ) tag = String.Format("\cy%s\c-%s\c-",StringTable.Localize("$SWWM_EXIT"),l.LookupLevelName()); else tag = String.Format("\cy%s\c-",StringTable.Localize("$SWWM_NEXIT")); } else if ( ((poi.trackedline.special == ACS_Execute) || (poi.trackedline.special == ACS_ExecuteAlways)) && (poi.trackedline.Args[0] == -Int('MapFadeOut')) ) { LevelInfo l = LevelInfo.FindLevelByNum(poi.trackedline.Args[2]); if ( (level.levelnum != 1) && l && l.isValid() ) tag = String.Format("\cy%s\c-%s\c-",StringTable.Localize("$SWWM_EXIT"),l.LookupLevelName()); else tag = String.Format("\cy%s\c-",StringTable.Localize("$SWWM_NEXIT")); } } Screen.DrawText(mTinyFontOutline,Font.CR_WHITE,vpos.x-mTinyFontOutline.StringWidth(tag)/2.,vpos.y-mTinyFontOutline.GetHeight()/2.,tag,DTA_VirtualWidthF,ss2.x,DTA_VirtualHeightF,ss2.y,DTA_KeepRatio,true); tag = String.Format("\cu(%s\cu)\c-",FormatDist(tdir.length())); Screen.DrawText(mTinyFontOutline,Font.CR_WHITE,vpos.x-mTinyFontOutline.StringWidth(tag)/2.,vpos.y+mTinyFontOutline.GetHeight()/2.,tag,DTA_VirtualWidthF,ss2.x,DTA_VirtualHeightF,ss2.y,DTA_KeepRatio,true); } while ( poi = poi.next ); } private int GetItemFontColor( SWWMitemSense s ) { let col = s.scoreitem?Font.CR_YELLOW:Font.CR_WHITE; let i = (s.item is 'SWWMRespawnTimer')?s.item.tracer:s.item; if ( i is 'Weapon' ) col = s.vipitem?Font.FindFontColor('VIPGold'):Font.CR_GOLD; else if ( i is 'MagAmmo' ) col = s.vipitem?Font.FindFontColor('VIPTan'):Font.CR_TAN; else if ( (i is 'BackpackItem') || (i is 'HammerspaceEmbiggener') ) col = Font.CR_DARKBROWN; else if ( i is 'Ammo' ) col = s.vipitem?Font.FindFontColor('VIPBrown'):Font.CR_BROWN; else if ( (i is 'PowerupGiver') || (i is 'AmmoFabricator') || Inventory(i).bBIGPOWERUP ) col = s.vipitem?Font.FindFontColor('VIPPurple'):Font.CR_PURPLE; else if ( (i is 'Health') || (i is 'HealthPickup') || (i is 'SWWMHealth') ) col = Font.CR_RED; else if ( (i is 'Armor') || (i is 'SWWMSpareArmor') ) col = Font.CR_GREEN; else if ( i is 'PuzzleItem' ) col = Font.CR_LIGHTBLUE; else if ( i is 'Key' ) col = Font.CR_UNTRANSLATED; else if ( i is 'SWWMCollectible' ) col = Font.CR_PURPLE; return col; } private void DrawItemSense( Vector3 viewvec, out bool projinit ) { let demo = Demolitionist(CPlayer.mo); if ( !demo ) return; SWWMItemSense s = demo.itemsense; if ( !s ) return; do { if ( !s.item ) continue; Vector3 tdir = level.Vec3Diff(ViewPos,s.pos); if ( viewvec dot tdir < 0 ) continue; Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir); if ( ndc.z >= 1. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs1; int mtime = level.allmap?(GameTicRate*2):GameTicRate; double alph = clamp(((s.updated+mtime)-(level.maptime+fractic))/double(GameTicRate),0.,1.); alph *= clamp(1.5-1.5*(tdir.length()/(level.allmap?1200.:800.)),0.,1.); String tag = s.tag; Screen.DrawText(mTinyFontOutline,GetItemFontColor(s),vpos.x-mTinyFontOutline.StringWidth(tag)/2.,vpos.y-mTinyFontOutline.GetHeight()/2.,tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph); tag = String.Format("\cu(%s\cu)\c-",FormatDist(tdir.length())); Screen.DrawText(mTinyFontOutline,Font.CR_WHITE,vpos.x-mTinyFontOutline.StringWidth(tag)/2.,vpos.y+mTinyFontOutline.GetHeight()/2.,tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph); if ( s.item is 'SWWMRespawnTimer' ) { tag = String.Format(StringTable.Localize("$SWWM_TRESPAWN"),s.item.special2/GameTicRate); Screen.DrawText(mTinyFontOutline,Font.CR_WHITE,vpos.x-mTinyFontOutline.StringWidth(tag)/2.,vpos.y+mTinyFontOutline.GetHeight()*2,tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph); } } while ( s = s.next ); } private bool IsLegendary( Actor a ) { for ( Inventory i=a.inv; i; i=i.inv ) { if ( (i.GetClassName() == "LDLegendaryMonsterToken") && swwm_ldspoil ) return true; else if ( i.GetClassName() == "LDLegendaryMonsterTransformed" ) return true; } return false; } private void DrawTrackers( Vector3 viewvec, out bool projinit ) { let cam = players[consoleplayer].camera; if ( !cti ) cti = ThinkerIterator.Create("SWWMQuickCombatTracker",Thinker.STAT_INVENTORY); else cti.Reinit(); SWWMQuickCombatTracker ct; bool onlyfriends = (swwm_targeter >= 2); while ( ct = SWWMQuickCombatTracker(cti.Next()) ) { // this ensures that projection data isn't cached if there are no target array elements, to avoid needless GC thrashing if ( !projinit ) { projinit = true; SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov); Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh); } // ignore unowned (can happen?) if ( !ct.Owner ) continue; // ignore if max health is zero (SOMEHOW can happen) if ( ct.maxhealth <= 0 ) continue; // ignore player trackers unless voodoo dolls if ( ct.Owner.player && (ct.Owner.player.mo == ct.Owner) ) continue; // ignore local player or camera if ( (ct.Owner == CPlayer.mo) || (ct.Owner == cam) ) continue; // ignore trackers not of this player if ( ct.myplayer != CPlayer ) continue; // ignore enemies if filtering friends if ( onlyfriends && (!ct.Owner.IsFriend(CPlayer.mo) || ct.Owner.player) ) continue; // ignore trackers clearly outside of player view Vector3 smpos = level.Vec3Offset(SWWMUtility.LerpVector3(ct.Owner.prev,ct.Owner.pos,fractic),(0,0,ct.lvheight)); Vector3 tdir = level.Vec3Diff(viewpos,smpos); if ( viewvec dot tdir < 0 ) continue; Vector3 ndc = SWWMUtility.ProjectPoint(projdata,viewpos+tdir); if ( ndc.z >= 1. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs1; if ( !SWWMUtility.TestScreenBounds(projdata,vpos) ) continue; double fin = clamp(ct.fadein+fractic,0.,5.)/5.; double fout = clamp(ct.lifespan-fractic,0.,25.)/25.; double alph = fin*fout; Vector2 barpos = vpos-(27,7); if ( swwm_targettags && (ct.mytag != "") ) { Font fnt = swwm_bigtags?mSmallFontOutline:mTinyFontOutline; String tag = ct.mytag; if ( IsLegendary(ct.Owner) ) { if ( StringTable.Localize("$SWWM_LEGPREFIX") == "R" ) tag = tag..StringTable.Localize("$SWWM_LEG"); else tag = StringTable.Localize("$SWWM_LEG")..tag; } if ( ct.Owner.bBOSS || ct.Owner.FindInventory("BossMarker") ) { if ( swwm_bigtags ) tag = "\cx★\c- "..tag.." \cx★\c-"; else tag = "\cx*\c- "..tag.." \cx*\c-"; // miniwi has no stars } // voodoo dolls aren't friends if ( ct.Owner.IsFriend(CPlayer.mo) && !ct.Owner.player ) tag = "\cg♥\c- "..tag.." \cg♥\c-"; Screen.DrawText(fnt,Font.CR_WHITE,vpos.x-fnt.StringWidth(tag)/2,barpos.y-(fnt.GetHeight()+2),tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph); } Screen.DrawTexture(EnemyBTex,false,barpos.x,barpos.y,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph); double ht = clamp(ct.intp.GetValue(fractic),0,ct.maxhealth); double hw = (ht*50.)/ct.maxhealth; Screen.DrawTexture(EnemyHTex[ct.Owner.bINVULNERABLE?1:0],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw); double ohw = hw; ht = clamp(ct.intpl.GetValue(fractic),0,ct.maxhealth); hw = (ht*50.)/ct.maxhealth; Screen.DrawTexture(EnemyHTex[2],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowLeftF,ohw,DTA_WindowRightF,hw); if ( ct.cummdamage <= 0 ) continue; double calph = clamp(ct.cummspan-fractic,0.,20.)/20.; Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_RED],barpos.x+3,barpos.y+10,(ct.cummdamage>=Actor.TELEFRAG_DAMAGE)?"∞":String.Format("%d",ct.cummdamage),DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,calph*alph); if ( ct.cummflash <= 0 ) continue; double falph = max((ct.cummflash-FracTic)/15.,0.)**1.5; Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_REDFLASH],barpos.x+3,barpos.y+10,(ct.cummdamage>=Actor.TELEFRAG_DAMAGE)?"∞":String.Format("%d",ct.cummdamage),DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,falph*calph*alph,DTA_LegacyRenderStyle,STYLE_Add); } // player-owned trackers are drawn last cti.Reinit(); while ( ct = SWWMQuickCombatTracker(cti.Next()) ) { // this ensures that projection data isn't cached if there are no target array elements, to avoid needless GC thrashing if ( !projinit ) { projinit = true; SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov); Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh); } // ignore unowned (can happen?) if ( !ct.Owner ) continue; // ignore if max health is zero (SOMEHOW can happen) if ( ct.maxhealth <= 0 ) continue; // ignore non-player trackers and voodoo dolls if ( !ct.Owner.player || (ct.Owner.player.mo != ct.Owner) ) continue; // ignore local player or camera if ( (ct.Owner == CPlayer.mo) || (ct.Owner == cam) ) continue; // ignore trackers not of this player if ( ct.myplayer != CPlayer ) continue; // ignore enemies if filtering friends if ( onlyfriends && !ct.Owner.IsFriend(CPlayer.mo) ) continue; // ignore trackers clearly outside of player view Vector3 smpos = level.Vec3Offset(SWWMUtility.LerpVector3(ct.Owner.prev,ct.Owner.pos,fractic),(0,0,ct.lvheight)); Vector3 tdir = level.Vec3Diff(viewpos,smpos); if ( viewvec dot tdir < 0 ) continue; Vector3 ndc = SWWMUtility.ProjectPoint(projdata,viewpos+tdir); if ( ndc.z >= 1. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs1; if ( !SWWMUtility.TestScreenBounds(projdata,vpos) ) continue; double fin = clamp(ct.fadein+fractic,0.,5.)/5.; double fout = clamp(ct.lifespan-fractic,0.,25.)/25.; double alph = fin*fout; Vector2 barpos = vpos-(27,7); Font fnt = swwm_bigtags?mSmallFontOutline:mTinyFontOutline; int col = Font.CR_WHITE; if ( teamplay ) { int team = ct.Owner.player.GetTeam(); if ( team != -1 ) col = Font.FindFontColor(Teams[team].mName); // this works in practice because team names are the same as their text colors if ( col == -1 ) col = Font.CR_WHITE; } Screen.DrawText(fnt,col,vpos.x-fnt.StringWidth(ct.mytag)/2,barpos.y-(fnt.GetHeight()+2),ct.mytag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph); Screen.DrawTexture(EnemyBTex,false,barpos.x,barpos.y,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph); double ht = clamp(ct.intp.GetValue(fractic),0,ct.maxhealth*100); double hw = (ht*50.)/ct.maxhealth; double ohw = hw; if ( ct.Owner.bINVULNERABLE || (ct.Owner.player.cheats&(CF_GODMODE|CF_GODMODE2)) || ct.Owner.FindInventory("InvinciballPower") ) Screen.DrawTexture(EnemyHTex[1],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw); else { Screen.DrawTexture(EnemyHTex[0],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw); if ( ht > ct.maxhealth ) { hw = (min(ht-ct.maxhealth,ct.maxhealth)*50.)/ct.maxhealth; Screen.DrawTexture(EnemyHTex[3],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw); } if ( ht > ct.maxhealth*2 ) { hw = (min(ht-ct.maxhealth*2,ct.maxhealth*3)*50.)/ct.maxhealth; Screen.DrawTexture(EnemyHTex[4],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw); } if ( ht > ct.maxhealth*5 ) { hw = (min(ht-ct.maxhealth*5,ct.maxhealth*5)*50.)/ct.maxhealth; Screen.DrawTexture(EnemyHTex[5],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw); } } if ( ct.Owner.FindInventory("DivineSpriteEffect") ) { double falph = clamp((ht-ct.maxhealth*10)/(ct.maxhealth*60.),0.,1.); Screen.DrawTexture(EnemyHTex[6],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph*falph,DTA_LegacyRenderStyle,STYLE_Add); } else { ht = clamp(ct.intpl.GetValue(fractic),0,ct.maxhealth); hw = (ht*50.)/ct.maxhealth; Screen.DrawTexture(EnemyHTex[2],false,barpos.x+2,barpos.y+2,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowLeftF,ohw,DTA_WindowRightF,hw); } if ( ct.cummdamage <= 0 ) continue; double calph = clamp(ct.cummspan-fractic,0.,20.)/20.; Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_RED],barpos.x+3,barpos.y+10,(ct.cummdamage>=Actor.TELEFRAG_DAMAGE)?"∞":String.Format("%d",ct.cummdamage),DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,calph*alph); if ( ct.cummflash <= 0 ) continue; double falph = max((ct.cummflash-FracTic)/15.,0.)**1.5; Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_REDFLASH],barpos.x+3,barpos.y+10,(ct.cummdamage>=Actor.TELEFRAG_DAMAGE)?"∞":String.Format("%d",ct.cummdamage),DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,falph*calph*alph,DTA_LegacyRenderStyle,STYLE_Add); } } private void DrawNumbers( Vector3 viewvec, out bool projinit ) { SWWMDamNum snum = hnd.damnums; if ( !snum ) return; do { // this ensures that projection data isn't cached if there are no target array elements, to avoid needless GC thrashing if ( !projinit ) { projinit = true; SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov); Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh); } Vector3 tdir = level.Vec3Diff(ViewPos,snum.pos); if ( viewvec dot tdir < 0 ) continue; Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir); if ( ndc.z >= 1. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs; String tag = abs(snum.damage>=Actor.TELEFRAG_DAMAGE)?(snum.damage>0)?"-∞":"+∞":String.Format("%+d",-snum.damage); double alph = clamp((snum.lifespan+fractic)/35.,0.,1.); Vector2 fo; int initspd = (128-snum.seed); int boostup = 64+snum.seed2; fo.x = (.05*initspd)*((snum.initialspan-(snum.lifespan-fractic))**.8); fo.y = -((snum.initialspan-(snum.lifespan-fractic))**1.5)+boostup*sin((90./snum.initialspan)*(level.maptime+fractic-snum.starttic)); Screen.DrawText(MiniHUDFontOutline,snum.tcolor,(vpos.x-fo.x)-(MiniHUDFontOutline.StringWidth(tag))/2,(vpos.y-fo.y)-(MiniHUDFontOutline.GetHeight())/2,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); } while ( snum = snum.next ); } private void DrawScores( Vector3 viewvec, out bool projinit ) { SWWMScoreObj snum = hnd.scorenums; if ( !snum ) return; do { // this ensures that projection data isn't cached if there are no target array elements, to avoid needless GC thrashing if ( !projinit ) { projinit = true; SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov); Screen.SetClipRect(projdata.viewx,projdata.viewy,projdata.vieww,projdata.viewh); } Vector3 tdir = level.Vec3Diff(ViewPos,snum.pos); if ( viewvec dot tdir < 0 ) continue; Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir); if ( ndc.z >= 1. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc)/hs1; String tag = String.Format("%+d",snum.score); double alph = clamp((snum.lifespan+fractic)/double(GameTicRate),0.,1.); // score rises linearly Vector2 fo = (0,snum.initialspan-(snum.lifespan-fractic)); Screen.DrawText(mTinyFontOutline,snum.tcolor,vpos.x-(fo.x+mTinyFontOutline.StringWidth(tag)/2.),vpos.y-(fo.y+(mTinyFontOutline.GetHeight()/2.)),tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph); // extra strings (if available) fo.y += mTinyFontOutline.GetHeight(); for ( int i=0; i 0 ) tag.AppendFormat(" x%d",snum.xscore[i]); Screen.DrawText(mTinyFontOutline,snum.xtcolor[i],vpos.x-(fo.x+mTinyFontOutline.StringWidth(tag)/2.),vpos.y-(fo.y+(mTinyFontOutline.GetHeight()/2.)),tag,DTA_VirtualWidthF,ss1.x,DTA_VirtualHeightF,ss1.y,DTA_KeepRatio,true,DTA_Alpha,alph); fo.y += mTinyFontOutline.GetHeight(); } } while ( snum = snum.next ); } private void DrawTarget() { // don't draw when dead or with automap open if ( (CPlayer.health <= 0) || automapactive ) return; bool projinit = false; Vector3 viewvec = SWWMUtility.Vec3FromAngles(viewrot.x,viewrot.y); // points of interest if ( level.allmap && swwm_pois ) DrawInterest(viewvec,projinit); // sensed items DrawItemSense(viewvec,projinit); // targetting array if ( swwm_targeter ) DrawTrackers(viewvec,projinit); // floating kill scores and others if ( swwm_damnums ) DrawNumbers(viewvec,projinit); if ( swwm_scorenums ) DrawScores(viewvec,projinit); Screen.ClearClipRect(); } override void DrawMyPos() { String str = String.Format("(%d,%d,%d)",CPlayer.mo.pos.X,CPlayer.mo.pos.Y,CPlayer.mo.pos.Z); Screen.DrawText(mTinyFontOutline,Font.CR_GREEN,(ss.x-mTinyFontOutline.StringWidth(str))/2,4,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); } override void DrawAutomapHUD( double ticFrac ) { // do nothing, DrawScore handles this } // minimap helper code private void GetMinimapColors() { mm_colorset = swwm_mm_colorset; switch ( mm_colorset ) { case 1: // gzdoom mm_backcolor = am_backcolor; mm_cdwallcolor = am_cdwallcolor; mm_efwallcolor = am_efwallcolor; mm_fdwallcolor = am_fdwallcolor; mm_interlevelcolor = am_interlevelcolor; mm_intralevelcolor = am_intralevelcolor; mm_lockedcolor = am_lockedcolor; mm_notseencolor = am_notseencolor; mm_portalcolor = am_portalcolor; mm_secretsectorcolor = am_secretsectorcolor; mm_secretwallcolor = am_secretwallcolor; mm_specialwallcolor = am_specialwallcolor; mm_thingcolor = am_thingcolor; mm_thingcolor_citem = am_thingcolor_citem; mm_thingcolor_friend = am_thingcolor_friend; mm_thingcolor_item = am_thingcolor_item; mm_thingcolor_monster = am_thingcolor_monster; mm_thingcolor_ncmonster = am_thingcolor_ncmonster; mm_thingcolor_shootable = am_thingcolor; mm_thingcolor_vipitem = am_unexploredsecretcolor; mm_thingcolor_missile = am_specialwallcolor; mm_tswallcolor = am_tswallcolor; mm_unexploredsecretcolor = am_unexploredsecretcolor; mm_wallcolor = am_wallcolor; mm_yourcolor = am_yourcolor; mm_displaylocks = true; break; case 2: // doom mm_backcolor = "00 00 00"; mm_cdwallcolor = "fc fc 00"; mm_efwallcolor = "bc 78 48"; mm_fdwallcolor = "bc 78 48"; mm_interlevelcolor = 0; mm_intralevelcolor = 0; mm_lockedcolor = "fc fc 00"; mm_notseencolor = "6c 6c 6c"; mm_portalcolor = "40 40 40"; mm_secretsectorcolor = 0; mm_secretwallcolor = 0; mm_specialwallcolor = 0; mm_thingcolor = "74 fc 6c"; mm_thingcolor_citem = "74 fc 6c"; mm_thingcolor_friend = "74 fc 6c"; mm_thingcolor_item = "74 fc 6c"; mm_thingcolor_monster = "74 fc 6c"; mm_thingcolor_ncmonster = "74 fc 6c"; mm_thingcolor_shootable = "74 fc 6c"; mm_thingcolor_vipitem = "74 fc 6c"; mm_thingcolor_missile = "74 fc 6c"; mm_tswallcolor = "80 80 80"; mm_unexploredsecretcolor = 0; mm_wallcolor = "fc 00 00"; mm_yourcolor = "ff ff ff"; mm_displaylocks = false; break; case 3: // strife mm_backcolor = "00 00 00"; mm_cdwallcolor = "77 73 73"; mm_efwallcolor = "37 3b 5b"; mm_fdwallcolor = "37 3b 5b"; mm_interlevelcolor = 0; mm_intralevelcolor = 0; mm_lockedcolor = "77 73 73"; mm_notseencolor = "6c 6c 6c"; mm_portalcolor = "40 40 40"; mm_secretsectorcolor = 0; mm_secretwallcolor = 0; mm_specialwallcolor = 0; mm_thingcolor = "bb 3b 00"; mm_thingcolor_citem = "db ab 00"; mm_thingcolor_friend = "fc 00 00"; mm_thingcolor_item = "db ab 00"; mm_thingcolor_monster = "fc 00 00"; mm_thingcolor_ncmonster = "fc 00 00"; mm_thingcolor_shootable = "bb 3b 00"; mm_thingcolor_vipitem = "db ab 00"; mm_thingcolor_missile = "bb 3b 00"; mm_tswallcolor = "77 73 73"; mm_unexploredsecretcolor = 0; mm_wallcolor = "c7 ce ce"; mm_yourcolor = "ef ef ef"; mm_displaylocks = false; break; case 4: // raven mm_backcolor = "6c 54 40"; mm_cdwallcolor = "67 3b 1f"; mm_efwallcolor = "d0 b0 85"; mm_fdwallcolor = "d0 b0 85"; mm_interlevelcolor = 0; mm_intralevelcolor = 0; mm_lockedcolor = "67 3b 1f"; mm_notseencolor = "00 00 00"; mm_portalcolor = "50 50 50"; mm_secretsectorcolor = 0; mm_secretwallcolor = 0; mm_specialwallcolor = 0; mm_thingcolor = "ec ec ec"; mm_thingcolor_citem = "ec ec ec"; mm_thingcolor_friend = "ec ec ec"; mm_thingcolor_item = "ec ec ec"; mm_thingcolor_monster = "ec ec ec"; mm_thingcolor_ncmonster = "ec ec ec"; mm_thingcolor_shootable = "ec ec ec"; mm_thingcolor_vipitem = "ec ec ec"; mm_thingcolor_missile = "ec ec ec"; mm_tswallcolor = "58 5d 56"; mm_unexploredsecretcolor = 0; mm_wallcolor = "4b 32 10"; mm_yourcolor = "ff ff ff"; mm_displaylocks = true; break; default: // swwm mm_backcolor = "10 10 10"; mm_cdwallcolor = "30 50 70"; mm_efwallcolor = "80 a0 c0"; mm_fdwallcolor = "50 70 90"; mm_interlevelcolor = "ff 00 60"; mm_intralevelcolor = "00 60 ff"; mm_lockedcolor = "00 90 80"; mm_notseencolor = "20 20 30"; mm_portalcolor = "40 30 20"; mm_secretsectorcolor = "80 00 ff"; mm_secretwallcolor = "60 40 80"; mm_specialwallcolor = "ff a0 00"; mm_thingcolor = "ff ff ff"; mm_thingcolor_citem = "00 ff ff"; mm_thingcolor_friend = "80 ff a0"; mm_thingcolor_item = "ff c0 00"; mm_thingcolor_monster = "ff 60 40"; mm_thingcolor_ncmonster = "a0 40 20"; mm_thingcolor_shootable = "ff a0 a0"; mm_thingcolor_vipitem = "80 60 ff"; mm_thingcolor_missile = "ff a0 20"; mm_tswallcolor = "30 20 40"; mm_unexploredsecretcolor = "40 00 80"; mm_wallcolor = "c0 e0 ff"; mm_yourcolor = "80 ff 00"; mm_displaylocks = true; break; } } private bool ShouldDisplaySpecial( int special ) { // thanks graf/randi/whoever switch ( special ) { // the following have (max_args < 0) // but we can't know this from zscript, so they're hardcoded here case Polyobj_StartLine: case Polyobj_ExplicitLine: case Transfer_WallLight: case Sector_Attach3dMidtex: case ExtraFloor_LightOnly: case Sector_CopyScroller: case Scroll_Texture_Left: case Scroll_Texture_Right: case Scroll_Texture_Up: case Scroll_Texture_Down: case Plane_Copy: case Line_SetIdentification: case Line_SetPortal: case Sector_Set3DFloor: case Sector_SetContents: case Plane_Align: case Static_Init: case Transfer_Heights: case Transfer_FloorLight: case Transfer_CeilingLight: case Scroll_Texture_Model: case Scroll_Texture_Offsets: case PointPush_SetForce: return false; } return true; } private bool CheckSectorAction( Sector s, out int special, bool useonly ) { for ( Actor act=s.SecActTarget; act; act=act.tracer ) { if ( (act.Health&(SectorAction.SECSPAC_Use|SectorAction.SECSPAC_UseWall) || !useonly) && act.special && !act.bFRIENDLY ) { special = act.special; return true; } } return false; } private bool RealLineSpecial( Line l, out int special ) { if ( special && l.activation&SPAC_PlayerActivate ) return true; if ( CheckSectorAction(l.frontsector,special,!l.backsector) ) return true; return (l.backsector && CheckSectorAction(l.backsector,special,false)); } private bool ShowTriggerLine( Line l ) { if ( am_showtriggerlines == 0 ) return false; int special = l.special; if ( !RealLineSpecial(l,special) ) return false; if ( !ShouldDisplaySpecial(special) ) return false; if ( special && (am_showtriggerlines >= 2) ) return true; if ( !special || (special == Door_Open) || (special == Door_Close) || (special == Door_CloseWaitOpen) || (special == Door_Raise) || (special == Door_Animated) || (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 ( !mm_secretsectorcolor || !mm_unexploredsecretcolor ) return 0; 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 ) { double zoomlevel = SWWMUtility.Lerp(oldminimapzoom,minimapzoom,FracTic); double zoomview = MAPVIEWDIST*zoomlevel, zoomclip = CLIPDIST*zoomlevel; Vector2 cpos = SWWMUtility.LerpVector2(players[consoleplayer].Camera.prev.xy,players[consoleplayer].Camera.pos.xy,FracTic); Sector csec = players[consoleplayer].Camera.CurSector; for ( int i=0; i= 4)) ) continue; Vector2 rv1 = l.v1.p-cpos, rv2 = l.v2.p-cpos; bool isportal = false; Sector linesector; if ( l.sidedef[0].flags&Side.WALLF_POLYOBJ ) linesector = level.PointInSector(l.v1.p+l.delta/2.); else linesector = l.frontsector; isportal = (linesector.portalgroup!=csec.portalgroup); if ( isportal ) { // portal displacement Vector2 pofs = SWWMUtility.PortalDisplacement(csec,linesector); rv1 -= pofs; rv2 -= pofs; } Vector2 mid = (rv1+rv2)/2.; Vector2 siz = (abs(rv1.x-rv2.x),abs(rv1.y-rv2.y))/2.; if ( (((siz.x+zoomview)-abs(mid.x)) <= 0) || (((siz.y+zoomview)-abs(mid.y)) <= 0) ) 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)*zoomclip,(1,1)*zoomclip,rv1,rv2); if ( !visible ) continue; // scale to minimap frame rv1 *= (HALFMAPSIZE/zoomclip)*hs; rv2 *= (HALFMAPSIZE/zoomclip)*hs; // offset to minimap center rv1 += basepos; rv2 += basepos; // get the line color Color col = mm_wallcolor; if ( (l.flags&Line.ML_MAPPED) || am_cheat ) { int secwit = CheckSecret(l); int lock = SWWMUtility.GetLineLock(l); if ( secwit == 1 ) col = mm_secretsectorcolor; else if ( secwit == 2 ) col = mm_unexploredsecretcolor; else if ( l.flags&Line.ML_SECRET ) { if ( am_cheat && l.backsector && mm_secretwallcolor ) col = mm_secretwallcolor; else col = mm_wallcolor; } else if ( mm_interlevelcolor && ((l.special == Exit_Normal) || (l.special == Exit_Secret) || (l.special == Teleport_NewMap) || (l.special == Teleport_EndGame)) ) col = mm_interlevelcolor; else if ( mm_intralevelcolor && (l.activation&SPAC_PlayerActivate) && ((l.special == Teleport) || (l.special == Teleport_NoFog) || (l.special == Teleport_ZombieChanger) || (l.special == Teleport_Line)) ) col = mm_intralevelcolor; else if ( mm_displaylocks && (lock > 0) && (lock < 256) ) { let lcol = SWWMUtility.GetLockColor(lock); if ( lcol ) col = lcol; else col = mm_lockedcolor; } else if ( mm_specialwallcolor && ShowTriggerLine(l) ) col = mm_specialwallcolor; else if ( l.frontsector && l.backsector ) { if ( !CmpFloorPlanes(l) ) col = mm_fdwallcolor; else if ( !CmpCeilingPlanes(l) ) col = mm_cdwallcolor; else if ( CheckFFBoundary(l) ) col = mm_efwallcolor; else { if ( (am_cheat == 0) || (am_cheat >= 4) ) continue; col = mm_tswallcolor; } } } else col = mm_notseencolor; // draw the line if ( isportal ) { col = Color((col.r+mm_portalcolor.r*7)/8,(col.g+mm_portalcolor.g*7)/8,(col.b+mm_portalcolor.b*7)/8); Screen.DrawThickLine(int(rv1.x),int(rv1.y),int(rv2.x),int(rv2.y),max(1.,hs*.25),col); } else Screen.DrawThickLine(int(rv1.x),int(rv1.y),int(rv2.x),int(rv2.y),max(1.,hs*.5),col); } } private void DrawMapMarkers( Vector2 basepos ) { double zoomlevel = SWWMUtility.Lerp(oldminimapzoom,minimapzoom,FracTic); double zoomview = MAPVIEWDIST*zoomlevel, zoomclip = CLIPDIST*zoomlevel; Vector2 cpos = SWWMUtility.LerpVector2(players[consoleplayer].Camera.prev.xy,players[consoleplayer].Camera.pos.xy,FracTic); Sector csec = players[consoleplayer].Camera.CurSector; if ( !mi ) mi = ThinkerIterator.Create("MapMarker",Thinker.STAT_MAPMARKER); else mi.Reinit(); MapMarker m; while ( m = MapMarker(mi.Next()) ) { if ( m.bDORMANT ) continue; if ( m.args[1] && !(m.CurSector.moreflags&Sector.SECMF_DRAWN) ) continue; TextureID tx; if ( m.picnum.IsValid() ) tx = m.picnum; else tx = m.CurState.GetSpriteTexture(1); Vector2 sz = TexMan.GetScaledSize(tx); Vector2 scl; // seems to match automap scaling somewhat if ( m.Args[2] ) scl = (m.Scale/zoomlevel)*.15; else scl = m.Scale*.5; sz.x *= scl.x; sz.y *= scl.y; double radius = max(sz.x,sz.y); // naive, I know if ( m.args[0] ) { // oh bother, this will be dicks let ai = level.CreateActorIterator(m.args[0]); Actor a; while ( a = ai.Next() ) { Vector2 rv = a.pos.xy-cpos; bool isportal = false; Sector sec = level.PointInSector(a.pos.xy); if ( sec.portalgroup != csec.portalgroup ) { isportal = true; // portal displacement rv -= SWWMUtility.PortalDisplacement(csec,sec); } if ( (((radius+zoomview)-abs(rv.x)) <= 0) || (((radius+zoomview)-abs(rv.y)) <= 0) ) continue; // flip Y rv.y *= -1; // rotate by view rv = Actor.RotateVector(rv,ViewRot.x-90); // scale to minimap frame rv *= (HALFMAPSIZE/zoomclip)*hs; // offset to minimap center rv += basepos; // draw Screen.DrawTexture(tx,false,rv.x,rv.y,DTA_ColorOverlay,isportal?Color(128,mm_portalcolor.r,mm_portalcolor.g,mm_portalcolor.b):Color(0,0,0,0),DTA_ScaleX,hs*scl.x,DTA_ScaleY,hs*scl.y,DTA_LegacyRenderStyle,m.GetRenderStyle(),DTA_Alpha,m.Alpha,DTA_FillColor,m.FillColor,DTA_TranslationIndex,m.Translation); } ai.Destroy(); continue; } Vector2 rv = m.pos.xy-cpos; bool isportal = false; Sector sec = level.PointInSector(m.pos.xy); if ( sec.portalgroup != csec.portalgroup ) { isportal = true; // portal displacement rv -= SWWMUtility.PortalDisplacement(csec,sec); } if ( (((radius+zoomview)-abs(rv.x)) <= 0) || (((radius+zoomview)-abs(rv.y)) <= 0) ) continue; // flip Y rv.y *= -1; // rotate by view rv = Actor.RotateVector(rv,ViewRot.x-90); // scale to minimap frame rv *= (HALFMAPSIZE/zoomclip)*hs; // offset to minimap center rv += basepos; // draw Screen.DrawTexture(tx,false,rv.x,rv.y,DTA_ColorOverlay,isportal?Color(128,mm_portalcolor.r,mm_portalcolor.g,mm_portalcolor.b):Color(0,0,0,0),DTA_ScaleX,hs*scl.x,DTA_ScaleY,hs*scl.y,DTA_LegacyRenderStyle,m.GetRenderStyle(),DTA_Alpha,m.Alpha,DTA_FillColor,m.FillColor,DTA_TranslationIndex,m.Translation); } } private void DrawMapThings( Vector2 basepos ) { double zoomlevel = SWWMUtility.Lerp(oldminimapzoom,minimapzoom,FracTic); double zoomview = MAPVIEWDIST*zoomlevel, zoomclip = CLIPDIST*zoomlevel; Vector2 cpos = SWWMUtility.LerpVector2(players[consoleplayer].Camera.prev.xy,players[consoleplayer].Camera.pos.xy,FracTic); Sector csec = players[consoleplayer].Camera.CurSector; bool drawmissiles = swwm_mm_missiles; for ( SWWMSimpleTracker t=hnd.strackers; t; t=t.next ) { if ( !drawmissiles && t.ismissile ) continue; if ( level.allmap && (t.target is 'Key') ) continue; // don't draw keys over the actual markers they have Color col = mm_thingcolor; bool isitem = false; bool plainactor = false; Vector2 pos; double angle; double radius; if ( t.target ) { pos = SWWMUtility.LerpVector2(t.target.prev.xy,t.target.pos.xy,FracTic); angle = t.target.angle; radius = t.isybeam?(t.target.scale.y*cos(t.target.pitch-90)):t.isbeam?(t.target.speed*cos(t.target.pitch)):t.target.radius; } else { pos = t.pos.xy; angle = t.angle; radius = t.radius; } if ( t.isitem ) { if ( t.vipitem ) col = mm_thingcolor_vipitem; else if ( t.countitem ) col = mm_thingcolor_citem; else col = mm_thingcolor_item; isitem = true; } else if ( t.isplayer ) col = t.playercol; else if ( t.friendly ) col = mm_thingcolor_friend; else if ( t.countkill ) col = mm_thingcolor_monster; else if ( t.ismonster ) col = mm_thingcolor_ncmonster; else if ( t.ismissile ) col = mm_thingcolor_missile; else { if ( t.vipitem ) col = mm_thingcolor_vipitem; // chanceboxes else if ( t.shootable ) col = mm_thingcolor_shootable; plainactor = true; } int mtime = GameTicRate; if ( level.allmap && !t.expired && t.target ) mtime += GameTicRate*3; Vector2 rv = pos-cpos; bool isportal = false; Sector sec = level.PointInSector(pos); if ( sec.portalgroup != csec.portalgroup ) { isportal = true; // portal displacement rv -= SWWMUtility.PortalDisplacement(csec,sec); // and blend in the color too col = Color((col.r+mm_portalcolor.r*7)/8,(col.g+mm_portalcolor.g*7)/8,(col.b+mm_portalcolor.b*7)/8); } if ( (((radius+zoomview)-abs(rv.x)) <= 0) || (((radius+zoomview)-abs(rv.y)) <= 0) ) continue; Vector2 tv[4]; int nidx; if ( t.isbeam ) { // oriented line nidx = 2; tv[0] = rv; tv[1] = rv+Actor.RotateVector((radius,0),angle); } else if ( isitem ) { // rhombus nidx = 4; double crad = min(radius,10); for ( int i=0; i<4; i++ ) tv[i] = rv+Actor.RotateVector((crad,0),i*90); } else if ( plainactor ) { // aabb box nidx = 4; tv[0] = rv+(-radius,-radius); tv[1] = rv+(radius,-radius); tv[2] = rv+(radius,radius); tv[3] = rv+(-radius,radius); } else { // oriented triangle nidx = 3; tv[0] = rv+Actor.RotateVector((radius,0),angle); tv[1] = rv+Actor.RotateVector((-radius*.5,radius*.7),angle); tv[2] = rv+Actor.RotateVector((-radius*.5,-radius*.7),angle); } // flip Y for ( int j=0; j 0) ) { xx = int(ss.x-(margin+2)); String str; if ( automapactive || (fstats > 1) ) { int label = am_showmaplabel; String ln = level.levelname; int iof = ln.IndexOf(" - by: "); if ( iof != -1 ) ln.Truncate(iof); if ( !label || ((level.clusterflags&level.CLUSTER_HUB) && (label == 2)) ) str = ln; else str = String.Format("%s - %s",level.mapname.MakeUpper(),ln); Screen.DrawText(mSmallFontOutline,tclabel,xx-mSmallFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); yy += mSmallFontOutline.GetHeight()+4; } if ( (level.total_monsters > 0) && am_showmonsters && !deathmatch ) { str = String.Format("\c"..tclabel_s.."K \c-%d\c"..tcextra_s.."/\c-%d",level.killed_monsters,level.total_monsters); Screen.DrawText(MiniHUDFontOutline,(level.killed_monsters>=level.total_monsters)?tccompl:tcvalue,xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); if ( killflash && (gametic < killflash) ) { double alph = max((killflash-(gametic+FracTic))/25.,0.)**1.5; str = String.Format("%d/%d",level.killed_monsters,level.total_monsters); int slashpos = str.IndexOf("/"); Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str.Left(slashpos),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph); } if ( tkillflash && (gametic < tkillflash) ) { double alph = max((tkillflash-(gametic+FracTic))/25.,0.)**1.5; str = String.Format("%d",level.total_monsters); Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph); } yy += MiniHUDFontOutline.GetHeight()+2; } if ( (level.total_items > 0) && am_showitems && !deathmatch ) { str = String.Format("\c"..tclabel_s.."I \c-%d\c"..tcextra_s.."/\c-%d",level.found_items,level.total_items); Screen.DrawText(MiniHUDFontOutline,(level.found_items>=level.total_items)?tccompl:tcvalue,xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); if ( itemflash && (gametic < itemflash) ) { double alph = max((itemflash-(gametic+FracTic))/25.,0.)**1.5; str = String.Format("%d/%d",level.found_items,level.total_items); int slashpos = str.IndexOf("/"); Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str.Left(slashpos),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph); } if ( titemflash && (gametic < titemflash) ) { double alph = max((titemflash-(gametic+FracTic))/25.,0.)**1.5; str = String.Format("%d",level.total_items); Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph); } yy += MiniHUDFontOutline.GetHeight()+2; } if ( (level.total_secrets > 0) && am_showsecrets && !deathmatch ) { str = String.Format("\c"..tclabel_s.."S \c-%d\c"..tcextra_s.."/\c-%d",level.found_secrets,level.total_secrets); Screen.DrawText(MiniHUDFontOutline,(level.found_secrets>=level.total_secrets)?tccompl:tcvalue,xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); if ( secretflash && (gametic < secretflash) ) { double alph = max((secretflash-(gametic+FracTic))/25.,0.)**1.5; str = String.Format("%d/%d",level.found_secrets,level.total_secrets); int slashpos = str.IndexOf("/"); Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str.Left(slashpos),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph); } if ( tsecretflash && (gametic < tsecretflash) ) { double alph = max((tsecretflash-(gametic+FracTic))/25.,0.)**1.5; str = String.Format("%d",level.total_secrets); Screen.DrawText(MiniHUDFontOutline,mhudfontcol[MCR_FLASH],xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph); } yy += MiniHUDFontOutline.GetHeight()+2; } int sec; if ( am_showtime ) { sec = Thinker.Tics2Seconds(level.maptime); str = String.Format("\c"..tclabel_s.."T \c-%02d\c"..tcextra_s..":\c-%02d\c"..tcextra_s..":\c-%02d",sec/3600,(sec%3600)/60,sec%60); Screen.DrawText(MiniHUDFontOutline,((level.sucktime>0)&&(sec>=(level.sucktime*3600)))?tcsucks:((level.partime>0)&&(sec<=level.partime))?tccompl:tcvalue,xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); yy += MiniHUDFontOutline.GetHeight()+2; } // don't show total time if it's equal to map time if ( am_showtotaltime && (level.totaltime != level.maptime) ) { sec = Thinker.Tics2Seconds(level.totaltime); str = String.Format("\c"..tclabel_s.."TT \c-%02d\c"..tcextra_s..":\c-%02d\c"..tcextra_s..":\c-%02d",sec/3600,(sec%3600)/60,sec%60); Screen.DrawText(MiniHUDFontOutline,tcvalue,xx-MiniHUDFontOutline.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); yy += MiniHUDFontOutline.GetHeight()+2; } yy += 3; } if ( deathmatch ) { yy += 9; if ( playercount <= 1 ) return; xx = int(ss.x-(margin+2)); String str; if ( teamplay ) { // draw team scores for ( int i=0; i 0 ) str = String.Format("\cx%s \cj+%d\c-",StringTable.Localize("$SWWM_DMSPREAD"),lead); else str = String.Format("\cx%s \cj%d\c-",StringTable.Localize("$SWWM_DMSPREAD"),lead); Screen.DrawText(mSmallFont,Font.CR_WHITE,xx-mSmallFont.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); yy += mSmallFont.GetHeight()+3; // draw top 3 players for ( int i=0; i klist; for ( int i=0; i= keyflash[j].flashtime) ) continue; double alph = max((keyflash[j].flashtime-(gametic+FracTic))/25.,0.)**1.5; Screen.DrawTexture(icon,false,keypos.x-siz.x,keypos.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_TopLeft,true,DTA_ColorOverlay,0xFFFFC040,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph); break; } keypos.x -= siz.x+2; colh = max(colh,siz.y); if ( ++colc == maxcolc ) { keypos.x = ss.x-(margin+2); keypos.y += colh+2; colh = colc = 0; } } } private bool DrawInvIcon( Inventory i, double xx, double yy, double alpha = 1., bool forceamt = false, bool selected = false, bool aspowerup = false ) { if ( !i || !i.Icon.IsValid() ) return false; Vector2 scl = TexMan.GetScaledSize(i.Icon); double mscl = min(1.,30./max(scl.x,scl.y)); double dw = (ss.x/mscl), dh = (ss.y/mscl); double dx = (xx+(30-scl.x*mscl)/2)/mscl, dy = (yy+(30-scl.y*mscl)/2)/mscl; if ( i is 'Powerup' ) { Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,Powerup(i).IsBlinking()?alpha*.5:alpha,DTA_TopOffset,0,DTA_LeftOffset,0); String nstr = String.Format("%ds",Powerup(i).EffectTics/GameTicRate); int len = MiniHudFontOutline.StringWidth(nstr); Screen.DrawText(MiniHudFontOutline,mhudfontcol[MCR_BRASS],(xx+30)-len,(yy+30)-6,nstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,Powerup(i).IsBlinking()?alpha*.5:alpha); return true; } if ( (i is 'SWWMLamp') && aspowerup ) { Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,SWWMLamp(i).isBlinking()?alpha*.5:alpha,DTA_TopOffset,0,DTA_LeftOffset,0); String nstr = String.Format("%d%%",SWWMLamp(i).Charge); int len = MiniHudFontOutline.StringWidth(nstr); Screen.DrawText(MiniHudFontOutline,mhudfontcol[SWWMLamp(i).bActive?MCR_BRASS:MCR_WHITE],(xx+30)-len,(yy+30)-6,nstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,SWWMLamp(i).isBlinking()?alpha*.5:alpha); return true; } if ( (i is 'DivineSpriteEffect') && aspowerup ) { Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,DivineSpriteEffect(i).isBlinking()?alpha*.5:alpha,DTA_TopOffset,0,DTA_LeftOffset,0); String nstr = String.Format("%ds",DivineSpriteEffect(i).healtim/GameTicRate); int len = MiniHudFontOutline.StringWidth(nstr); Screen.DrawText(MiniHudFontOutline,mhudfontcol[MCR_BRASS],(xx+30)-len,(yy+30)-6,nstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,DivineSpriteEffect(i).isBlinking()?alpha*.5:alpha); return true; } Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,alpha,DTA_TopOffset,0,DTA_LeftOffset,0); if ( (i.Amount > 1) || forceamt ) { String nstr; if ( (i.Amount > 99999) && !forceamt ) nstr = "99999"; else nstr = String.Format("%d",i.Amount); int len = MiniHudFontOutline.StringWidth(nstr); Screen.DrawText(MiniHudFontOutline,mhudfontcol[(i.Amount<=0)?MCR_RED:selected?MCR_BRASS:MCR_WHITE],(xx+30)-len,(yy+30)-6,nstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha); } return true; } private void DrawInventory() { int invy = 61; // active items (armor / powerups) double xx = margin+2; double yy = ss.y-(margin+invy+9); bool drewarmor = false; for ( Inventory i=CPlayer.mo.Inv; i; i=i.Inv ) { if ( (i.Amount <= 0) || (!(i is 'SWWMArmor') && !(i is 'BasicArmor')) ) continue; if ( !DrawInvIcon(i,xx,yy,forceamt:true,selected:true) ) continue; yy -= 34; drewarmor = true; } yy = ss.y-(margin+invy+9); if ( drewarmor ) { xx += 36; if ( CPlayer.mo.InvSel && !isInventoryBarVisible() ) yy -= 34; } for ( Inventory i=CPlayer.mo.Inv; i; i=i.Inv ) { if ( (i is 'SWWMLamp') && SWWMLamp(i).bActivated ) { DrawInvIcon(i,xx,yy,selected:true,aspowerup:true); yy -= 34; continue; } if ( (i is 'DivineSpriteEffect') && !DivineSpriteEffect(i).bHealDone ) { DrawInvIcon(i,xx,yy,selected:true,aspowerup:true); yy -= 34; continue; } if ( !(i is 'Powerup') || (Powerup(i).EffectTics <= 0) || !(Powerup(i).Icon) ) continue; if ( DrawInvIcon(i,xx,yy) ) yy -= 34; } // inventory box / bar if ( !CPlayer.mo.InvSel ) return; if ( isInventoryBarVisible() ) { Array bar; bar.Clear(); for ( Inventory i=CPlayer.mo.FirstInv(); i; i=i.NextInv() ) bar.Push(i); int ps = bar.Find(CPlayer.mo.InvSel); Inventory prev[2], next[2]; if ( bar.Size() > 1 ) { if ( ps+1 >= bar.Size() ) next[0] = bar[0]; else next[0] = bar[ps+1]; if ( ps-1 < 0 ) prev[0] = bar[bar.Size()-1]; else prev[0] = bar[ps-1]; } if ( bar.Size() > 2 ) { if ( ps+2 >= bar.Size() ) next[1] = bar[(ps+2)-bar.Size()]; else next[1] = bar[ps+2]; if ( ps-2 < 0 ) prev[1] = bar[bar.Size()+(ps-2)]; else prev[1] = bar[ps-2]; } xx = (ss.x-34)/2; yy = (ss.y+64)/2; Screen.DrawTexture(InventoryTex,false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); DrawInvIcon(CPlayer.mo.InvSel,xx+2,yy+2,selected:true); DrawInvIcon(prev[0],xx-32,yy+2,2./3.); DrawInvIcon(prev[1],xx-66,yy+2,1./3.); DrawInvIcon(next[0],xx+36,yy+2,2./3.); DrawInvIcon(next[1],xx+70,yy+2,1./3.); return; } Screen.DrawTexture(InventoryTex,false,margin+36,ss.y-(margin+invy+2),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); DrawInvIcon(CPlayer.mo.InvSel,margin+38,ss.y-(margin+invy),selected:true); } private void DrawWeapons() { Screen.DrawTexture(WeaponTex,false,ss.x-(margin+80),ss.y-(margin+10),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); double xx = ss.x-(margin+78), yy = ss.y-(margin+8); for ( int i=1; i<=10; i++,xx+=8 ) { int ncolor = mhudfontcol[MCR_WHITE]; if ( !CPlayer.HasWeaponsInSlot(i%10) ) { Screen.DrawText(MiniHUDFont,ncolor,xx,yy,String.Format("%d",(i%10)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,Color(128,0,0,0)); continue; } bool selected = false; bool dummy; int slot; SWWMGesture hasgesture = null; SWWMItemGesture hasitemgesture = null; if ( CPlayer.PendingWeapon is 'SWWMGesture' ) hasgesture = SWWMGesture(CPlayer.PendingWeapon); else if ( CPlayer.ReadyWeapon is 'SWWMGesture' ) hasgesture = SWWMGesture(CPlayer.ReadyWeapon); if ( CPlayer.PendingWeapon is 'SWWMItemGesture' ) hasitemgesture = SWWMItemGesture(CPlayer.PendingWeapon); else if ( CPlayer.ReadyWeapon is 'SWWMItemGesture' ) hasitemgesture = SWWMItemGesture(CPlayer.ReadyWeapon); if ( hasgesture && hasgesture.formerweapon ) { [dummy, slot] = CPlayer.weapons.LocateWeapon(hasgesture.formerweapon.GetClass()); if ( slot == (i%10) ) selected = true; } else if ( hasitemgesture && hasitemgesture.gest.formerweapon ) { [dummy, slot] = CPlayer.weapons.LocateWeapon(hasitemgesture.gest.formerweapon.GetClass()); if ( slot == (i%10) ) selected = true; } else if ( CPlayer.PendingWeapon && (CPlayer.PendingWeapon != WP_NOCHANGE) ) { [dummy, slot] = CPlayer.weapons.LocateWeapon(CPlayer.PendingWeapon.GetClass()); if ( slot == (i%10) ) selected = true; } else if ( (!CPlayer.PendingWeapon || (CPlayer.PendingWeapon == WP_NOCHANGE)) && CPlayer.ReadyWeapon ) { [dummy, slot] = CPlayer.weapons.LocateWeapon(CPlayer.ReadyWeapon.GetClass()); if ( slot == (i%10) ) selected = true; } if ( selected ) ncolor = mhudfontcol[MCR_BRASS]; else { bool hasammo = (i==1); for ( Inventory inv=CPlayer.mo.Inv; inv; inv=inv.Inv ) { if ( inv is 'Weapon' ) [dummy, slot] = CPlayer.weapons.LocateWeapon(Weapon(inv).GetClass()); else continue; if ( slot != (i%10) ) continue; // CheckAmmo can't be called from ui, so we have to improvise // for SWWM weapons I made a function for this at least if ( (inv is 'SWWMWeapon') && SWWMWeapon(inv).ReportHUDAmmo() ) hasammo = true; else if ( !(inv is 'SWWMWeapon') && ((!Weapon(inv).Ammo1 || (Weapon(inv).Ammo1.Amount > 0) || Weapon(inv).bAMMO_OPTIONAL) || (Weapon(inv).Ammo2 && ((Weapon(inv).Ammo2.Amount > 0) || Weapon(inv).bALT_AMMO_OPTIONAL))) ) hasammo = true; } if ( !hasammo ) ncolor = mhudfontcol[MCR_RED]; } Screen.DrawText(MiniHUDFont,ncolor,xx,yy,String.Format("%d",(i%10)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); int f = hnd.WeaponFlash[i%10]; if ( f && (gametic < f) ) { double alph = max((f-(gametic+FracTic))/25.,0.)**1.5; Screen.DrawText(MiniHUDFont,mhudfontcol[MCR_FLASH],xx,yy,String.Format("%d",(i%10)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_LegacyRenderStyle,STYLE_Add); } } xx = ss.x-(margin+54); yy = ss.y-(margin+14); bool bDrewAmmo = false; bool checkowned = !swwm_hudallammo; Array OwnedWeapons; if ( checkowned ) for ( Inventory i=CPlayer.mo.inv; i; i=i.inv ) { if ( !(i is 'SWWMWeapon') ) continue; OwnedWeapons.Push(SWWMWeapon(i)); } String str; for ( int i=25; i>=0; i-- ) { let a = AmmoSlots[i]; // check if owned if ( checkowned ) { bool owned = false; for ( int j=0; j0)?scol:mhudfontcol[MCR_RED]; int dcnt1 = 2-int(Log10(clamp(amt,1,999))); int dcnt2 = 2-int(Log10(clamp(amax,1,999))); for ( int j=0; j= FS_PAIN) ) return 12; if ( facestate == FS_OUCH ) return 10; if ( facestate == FS_PAIN ) return (paindir==1)?8:(paindir==-1)?9:7; if ( facestate == FS_GRIN ) return 5; if ( facestate == FS_EVIL ) return 6; if ( facestate == FS_SAD ) return 17; if ( facestate == FS_WINK ) return 18; if ( facestate == FS_BLINK ) return ((facetimer>28)||(facetimer<2))?3:4; switch ( blinktime ) { case -1: case -3: return 3; break; case -2: return 4; break; } return 2; } private void DrawMugshot() { rss = int(MSTimeF())*128; let demo = Demolitionist(CPlayer.mo); if ( !demo ) return; double paintime = clamp((demo.lastdamagetimer-(gametic+Fractic))/double(GameTicRate),0.,1.); double noiz = min(demo.lastdamage*.5*paintime,3.); Vector2 shake = (RandomShiver(),RandomShiver())*noiz; if ( !CPlayer.mo.FindInventory("GhostPower") ) { Screen.DrawTexture(FaceTex[0],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); bool raging = CPlayer.mo.FindInventory("RagekitPower"); bool angy = CPlayer.mo.FindInventory("AngeryPower"); if ( raging && angy ) Screen.DrawTexture(FaceTex[16],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); else if ( raging ) Screen.DrawTexture(FaceTex[15],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); else if ( angy ) Screen.DrawTexture(FaceTex[13],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); Screen.DrawTexture(FaceTex[1],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Color,Color(255,255,0,0),DTA_Alpha,min(1.,noiz)); if ( (CPlayer.Health > 0) && (isInvulnerable() || CPlayer.mo.FindInventory("InvinciballPower")) ) Screen.DrawTexture(FaceTex[1],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,.8+.1*sin(gametic+fractic)); } else { Screen.DrawTexture(FaceTex[0],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_FillColor,Color(0,0,0),DTA_Alpha,.25*(1.-min(1.,noiz))); Screen.DrawTexture(FaceTex[1],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_FillColor,Color(255,0,0),DTA_Alpha,.25*min(1.,noiz)); } Screen.DrawTexture(FaceTex[GetFaceTex(demo)],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); if ( CPlayer.mo.FindInventory("BarrierPower") ) Screen.DrawTexture(FaceTex[14],false,margin+shake.x,ss.y-(margin+32)+shake.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,.5,DTA_LegacyRenderStyle,STYLE_Add); } private void DrawStatus() { DrawMugshot(); int ox = 36; int oy = 5; Screen.DrawTexture(StatusTex,false,margin+ox,ss.y-(margin+22+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); String str; double ht = clamp(HealthInter.GetValue(fractic),0,10000); str = String.Format("%3d",clamp(round(ht),0,999)); double hw = min(ht,100); double bhw = hw; int hcolor = MCR_RED; if ( round(ht) > 500 ) hcolor = MCR_YELLOW; else if ( round(ht) > 200 ) hcolor = MCR_PURPLE; else if ( round(ht) > 100 ) hcolor = MCR_AQUA; if ( isInvulnerable() || CPlayer.mo.FindInventory("InvinciballPower") ) { Screen.DrawTexture(HealthTex[0],false,margin+3+ox,ss.y-(margin+19+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw,DTA_ColorOverlay,Color(255,0,0,0)); Screen.DrawTexture(HealthTex[4],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw); hcolor = MCR_WHITE; } else { Screen.DrawTexture(HealthTex[0],false,margin+3+ox,ss.y-(margin+19+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw,DTA_ColorOverlay,Color(255,0,0,0)); Screen.DrawTexture(HealthTex[0],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw); if ( ht > 100 ) { hw = min(ht-100,100); Screen.DrawTexture(HealthTex[1],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw); } if ( ht > 200 ) { hw = min(ht-200,300)/3.; Screen.DrawTexture(HealthTex[2],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw); } if ( ht > 500 ) { hw = min(ht-500,500)/5.; Screen.DrawTexture(HealthTex[3],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw); } } if ( CPlayer.mo.FindInventory("DivineSpriteEffect") ) { double falph = clamp((ht-1000)/6000.,0.,1.); Screen.DrawTexture(HealthTex[5],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,falph,DTA_LegacyRenderStyle,STYLE_Add); String tst; double alph = .1; int trl = 9; for ( double alph = .1; alph <= .5; alph += .1 ) { tst = "AAA"; SWWMUtility.ObscureText(tst,(gametic-trl)/3,true); trl--; Screen.DrawText(MiniHUDFont,mhudfontcol[MCR_WHITE],margin+107+ox,ss.y-(margin+20+oy),tst,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,falph*alph,DTA_LegacyRenderStyle,STYLE_Add); } Screen.DrawText(MiniHUDFont,mhudfontcol[hcolor],margin+107+ox,ss.y-(margin+20+oy),String.Format("%3d",clamp(round(ht),0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,1.-falph); } else { Screen.DrawText(MiniHUDFont,mhudfontcol[hcolor],margin+107+ox,ss.y-(margin+20+oy),String.Format("%3d",clamp(round(ht),0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); int f = HealthFlash; if ( f && (gametic < f) ) { double alph = max((f-(gametic+FracTic))/25.,0.)**1.5; Screen.DrawTexture(HealthTex[7],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,bhw,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph); Screen.DrawText(MiniHUDFont,mhudfontcol[MCR_FLASH],margin+107+ox,ss.y-(margin+20+oy),str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Add,DTA_Alpha,alph); } if ( (CPlayer.health > 0) && (CPlayer.health <= 25) && (PulsePhase <= 15) && (hcolor != MCR_WHITE) ) { double alph = clamp(sin((PulsePhase-FracTic)*12.),0.,1.); Screen.DrawTexture(HealthTex[6],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw,DTA_Alpha,alph); Screen.DrawText(MiniHUDFont,mhudfontcol[MCR_REDFLASH],margin+107+ox,ss.y-(margin+20+oy),str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); } ht = clamp(LagHealthInter.GetValue(fractic),0,1000); double hwl = min(ht,100); if ( hwl > bhw ) { Screen.DrawTexture(HealthTex[8],false,margin+3+ox,ss.y-(margin+19+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowLeftF,bhw,DTA_WindowRightF,hwl,DTA_ColorOverlay,Color(255,0,0,0)); Screen.DrawTexture(HealthTex[8],false,margin+2+ox,ss.y-(margin+20+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowLeftF,bhw,DTA_WindowRightF,hwl); } } double ft = clamp(FuelInter.GetValue(fractic),0,120); Screen.DrawTexture(FuelTex[swwm_superfuel],false,margin+3+ox,ss.y-(margin+7+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,ft,DTA_ColorOverlay,Color(255,0,0,0)); Screen.DrawTexture(FuelTex[swwm_superfuel],false,margin+2+ox,ss.y-(margin+8+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,ft); let d = Demolitionist(CPlayer.mo); bool blink = (!d || (d.dashfuel > 20) || ((gametic%10) < 5)); double dt = clamp(DashInter.GetValue(fractic),0,120); Screen.DrawTexture(DashTex,false,margin+3+ox,ss.y-(margin+4+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,dt,DTA_ColorOverlay,Color(255,0,0,0)); Screen.DrawTexture(DashTex,false,margin+2+ox,ss.y-(margin+5+oy),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,dt,DTA_ColorOverlay,Color(blink?0:96,0,0,0)); } private void DrawPickups() { int h = mSmallFont.GetHeight(); // draw nametags below them double yy; double nalph = 0.; double tagtime = (ntagtic+70)-(level.totaltime+fractic); if ( (ntagstr != "") && (tagtime > 0) ) { nalph = clamp(tagtime/20.,0.,1.); yy = ss.y-(margin+50); // shift up if boss healthbar is present if ( hnd && (hnd.bossalpha > 0.) ) yy -= int(40*clamp(hnd.bossalpha*2.,0.,1.)); int len = mSmallFont.StringWidth(ntagstr); double xx = (ss.x-len)/2.; Screen.Dim("Black",.8*nalph,int((xx-6)*hs),int(yy*hs),int((len+12)*hs),int((h+4)*hs)); Screen.DrawText(mSmallFont,ntagcol,int(xx),yy+2,ntagstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,nalph); } if ( PickupQueue.Size() <= 0 ) return; // reverse order since they're drawn bottom to top int mend = max(0,PickupQueue.Size()-MAXPICKUP); yy = ss.y-(margin+50); // shift up if boss healthbar is present if ( hnd && (hnd.bossalpha > 0.) ) yy -= int(40*clamp(hnd.bossalpha*2.,0.,1.)); // shift up again if nametag is present if ( nalph > 0. ) yy -= int((mSmallFont.GetHeight()+6)*clamp(nalph*2.,0.,1.)); for ( int i=PickupQueue.Size()-1; i>=mend; i-- ) { PickupQueue[i].UpdateText(int(ss.x*.75)); double curtime = (PickupQueue[i].tic+GameTicRate*PICKDURATION)-(level.totaltime+fractic); double alph = clamp(curtime/20.,0.,1.); let l = PickupQueue[i].l; int maxlen = 0; for ( int j=0; j maxlen ) maxlen = len; } double xx = (ss.x-maxlen)/2.; Screen.Dim("Black",.8*alph,int((xx-6)*hs),int((yy-h*(l.Count()-1))*hs),int((maxlen+12)*hs),int((h*l.Count()+4)*hs)); for ( int j=l.Count()-1; j>=0; j-- ) { int len = mSmallFont.StringWidth(l.StringAt(j)); xx = int((ss.x-len)/2.); Screen.DrawText(mSmallFont,msg0color,xx,yy+2,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); yy -= h; } yy -= 6; } } private void DrawMessages( double boxalph = 1. ) { double xx, yy; if ( midstr != "" ) { double ssp = (midtype&1)?.5:1.; double hsp = (midtype&1)?2.:1.; int col = (midtype&2)?msgmidcolor2:msgmidcolor; double curtime = (midtic+int(GameTicRate*con_midtime))-(level.totaltime+fractic); double alph = clamp(curtime/20.,0.,1.); if ( !midl || (midsz != int(ss.x*ssp)) ) { if ( midl ) midl.Destroy(); midl = mSmallFont.BreakLines(midstr,int(ss.x*ssp)); } int h = mSmallFont.GetHeight(); int maxlen = 0; for ( int i=0; i=gametic)?MAXSHOWNBIG:MAXSHOWN)); xx = margin; yy = margin; bool smol = (ss.x<640); Screen.DrawTexture(ChatTex[smol?3:0],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,boxalph); yy += 2; for ( int i=mstart; i ss.x-4 ) { // draw trailing dots Screen.DrawText(mSmallFont,Font.CR_WHITE,xx,yy,"...",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); // shift back xx -= w-(ss.x-4); // draw trimmed Screen.DrawText(mSmallFont,Font.CR_WHITE,xx,yy,fullstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ClipLeft,int(26*hs)); } else Screen.DrawText(mSmallFont,Font.CR_WHITE,xx,yy,fullstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); return true; } override bool DrawPaused( int player ) { let fnt = mSmallFontOutline?mSmallFontOutline:NewSmallFont; let fnt2 = mSmallFont?mSmallFont:NewConsoleFont; if ( swwm_fuzz ) { Vector2 tsize = TexMan.GetScaledSize(bgtex); double zoom = max(ceil(Screen.GetWidth()/tsize.x),ceil(Screen.GetHeight()/tsize.y)); Vector2 vsize = (Screen.GetWidth(),Screen.GetHeight())/zoom; Screen.DrawTexture(bgtex,false,(vsize.x-tsize.x)/2,(vsize.y-tsize.y)/2,DTA_VirtualWidthF,vsize.x,DTA_VirtualHeightF,vsize.y,DTA_KeepRatio,true,DTA_ColorOverlay,Color(192,0,0,0),DTA_Alpha,.5); } else Screen.Dim("Black",.5,0,0,Screen.GetWidth(),Screen.GetHeight()); String str = StringTable.Localize("$SWWM_PAUSE"); if ( gametic < pausetime+1000 ) { pausepos.x = Screen.GetWidth()/2; pausepos.y = Screen.GetHeight()/2; pausedir = (1,1); } else { pausepos.x += pausedir.x*CleanXFac; pausepos.y += pausedir.y*CleanYFac; if ( pausepos.x >= Screen.GetWidth()-((fnt.StringWidth(str)*3+8)*CleanXFac/2) ) pausedir.x = -1; if ( pausepos.x < ((fnt.StringWidth(str)*3+8)*CleanXFac/2) ) pausedir.x = 1; if ( pausepos.y >= Screen.GetHeight()-((fnt.GetHeight()*3+8)*CleanYFac/2) ) pausedir.y = -1; if ( pausepos.y < ((fnt.GetHeight()*3+8)*CleanYFac/2) ) pausedir.y = 1; } double xx = pausepos.x-(fnt.StringWidth(str)*3*CleanXFac)/2; double yy = pausepos.y-(fnt.GetHeight()*3*CleanYFac)/2; int tlen = str.CodePointCount(); for ( int i=0, pos=0; i 0) || (CPlayer != players[consoleplayer]) ) return 1.; String str; double alph; int len; double xx, yy; double deadtimer = (goner?goner.deadtimer:demo.deadtimer)+fractic; if ( goner || (demo.player.viewheight <= 6) ) { double dimalph = goner?1.:min(deadtimer/80.,.8); Screen.Dim("Black",dimalph,0,0,Screen.GetWidth(),Screen.GetHeight()); if ( demo && (demo.revivefail > level.maptime) ) { Screen.Dim("Red",clamp((demo.revivefail-(level.maptime+fractic))/60.,0.,.2),0,0,Screen.GetWidth(),Screen.GetHeight()); str = StringTable.Localize("$SWWM_REFAIL"); len = mSmallFont.StringWidth(str); xx = int((ss.x-len)/2.); yy = ss.y-48; if ( ((demo.revivefail-level.maptime)%16) < 8 ) Screen.DrawText(mSmallFont,Font.CR_RED,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); } alph = clamp((deadtimer-60)/60.,0.,1.); String nam = CPlayer.GetUserName(); if ( nam == "Player" ) str = StringTable.Localize("$SWWM_URDED_GEN"); else str = String.Format(StringTable.Localize("$SWWM_URDED"),nam); len = mSmallFont.StringWidth(str); xx = int((ss.x-len)/2.); yy = (ss.y-mSmallFont.GetHeight()*4)/2.; // shift down if scoreboard is shown if ( (deathmatch && sb_deathmatch_enable && (!teamplay || sb_teamdeathmatch_enable)) || (multiplayer && sb_cooperative_enable) ) yy += ss.y/3.+mSmallFont.GetHeight(); Screen.DrawText(mSmallFont,Font.CR_RED,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); if ( multiplayer || level.AllowRespawn || sv_singleplayerrespawn || G_SkillPropertyInt(SKILLP_PlayerRespawn) ) { if ( sv_norespawn ) return (1.-dimalph); alph = clamp((deadtimer-90)/60.,0.,1.); str = String.Format(StringTable.Localize("$SWWM_URDEDMP")); len = mSmallFont.StringWidth(str); xx = int((ss.x-len)/2.); yy = ss.y/2.; // shift down if scoreboard is shown if ( (deathmatch && sb_deathmatch_enable && (!teamplay || sb_teamdeathmatch_enable)) || (multiplayer && sb_cooperative_enable) ) yy += ss.y/3.; Screen.DrawText(mSmallFont,Font.CR_WHITE,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); return (1.-dimalph); } alph = clamp((deadtimer-140)/60.,0.,1.); str = String.Format(StringTable.Localize("$SWWM_URDED2")); len = mSmallFont.StringWidth(str); xx = int((ss.x-len)/2.); yy = ss.y/2.; Screen.DrawText(mSmallFont,Font.CR_WHITE,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); if ( goner || CPlayer.mo.FindInventory("SWWMReviveDisabler") || !swwm_revive ) return (1.-dimalph); alph = clamp((deadtimer-160)/60.,0.,1.); str = String.Format(StringTable.Localize("$SWWM_URDED3")); len = mSmallFont.StringWidth(str); xx = int((ss.x-len)/2.); yy = (ss.y+mSmallFont.GetHeight()*2)/2.; Screen.DrawText(mSmallFont,Font.CR_WHITE,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); return (1.-dimalph); } return 1.; } override void Draw( int state, double TicFrac ) { Super.Draw(state,TicFrac); double CurFrame = MSTimeF(); FrameTime = (CurFrame-PrevFrame)/1000.; if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.); ss = (Screen.GetWidth()/hs,Screen.GetHeight()/hs); margin = clamp(swwm_hudmargin,0,20); hs1 = max(hs-1.,1.); hs2 = max(hs-2.,1.); ss1 = (Screen.GetWidth()/hs1,Screen.GetHeight()/hs1); ss2 = (Screen.GetWidth()/hs2,Screen.GetHeight()/hs2); FracTic = TicFrac; if ( (players[consoleplayer].Camera is 'Demolitionist') && (state <= HUD_Fullscreen) ) { if ( hnd ) hnd.DrawBossBar(self); DrawTarget(); DrawTopStuff(); DrawInventory(); DrawStatus(); DrawWeapons(); } DrawPickups(); double malph = DrawDeath(); DrawMessages(malph); if ( state == HUD_AltHud ) { String str = StringTable.Localize("$SWWM_WARNALTHUD"); Screen.DrawText(NewSmallFont,Font.CR_RED,(ss.x-NewSmallFont.StringWidth(str))/2,margin,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); } PrevFrame = CurFrame; } }