2781 lines
104 KiB
Text
2781 lines
104 KiB
Text
// The SWWM GZ HUD is mostly built on top of what I had already done for SWWM Z, also a bit of Dark Souls
|
|
|
|
Class MsgLine
|
|
{
|
|
String str;
|
|
int tic, type, rep;
|
|
}
|
|
|
|
Class SWWMStatusBar : BaseStatusBar
|
|
{
|
|
TextureID StatusTex, WeaponTex, ScoreTex[3], InventoryTex, ChatTex[6],
|
|
HealthTex[6], FuelTex[2], DashTex, EnemyBTex, EnemyHTex[6],
|
|
GenericAmmoTex[3], MiniBox, AutoPage, PauseTex, bgtex;
|
|
HUDFont mTewiFont, mMiniwiFont, mMPlusFont, mk6x8Font;
|
|
|
|
Array<MsgLine> MainQueue, PickupQueue;
|
|
|
|
// sorted arrays of various elements
|
|
Array<SWWMInterest> intpoints;
|
|
Array<SWWMScoreObj> scoreobjs;
|
|
Array<SWWMCombatTracker> trackers;
|
|
Array<SWWMItemSense> senseitems;
|
|
|
|
// the event handler, holding all sorts of stuff
|
|
SWWMHandler hnd;
|
|
|
|
// shared stuff
|
|
Vector2 ss, hs;
|
|
Vector2 ssb, hsb;
|
|
Vector2 ssn, hsn;
|
|
Vector2 sss, hss;
|
|
Vector2 ssi, hsi;
|
|
Vector2 ssd, hsd;
|
|
int margin;
|
|
double FracTic;
|
|
double FrameTime;
|
|
int PrevFrame;
|
|
int chatopen;
|
|
bool camhidden;
|
|
|
|
// shared from renderunderlay, needed for proper interpolation of some things
|
|
Vector3 viewpos, viewrot;
|
|
|
|
// projection data cache
|
|
SWWMProjectionData projdata;
|
|
|
|
DynamicValueInterpolator HealthInter, ScoreInter, ScoreInter2, FuelInter, DashInter;
|
|
|
|
Inventory lastsel;
|
|
Weapon lastwep;
|
|
String ntagstr;
|
|
int ntagtic, ntagcol;
|
|
|
|
String midstr;
|
|
int midtic, midtype;
|
|
|
|
bool koraxhack, mainframehack, bosshack;
|
|
int puzzlecnt, realpuzzlecnt;
|
|
|
|
SWWMWeaponTooltip ctip;
|
|
|
|
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_gridcolor, 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_xhaircolor, mm_yourcolor;
|
|
bool mm_displaylocks, mm_drawautopage;
|
|
|
|
// deathmatch stuff
|
|
int playercount, rank, lead;
|
|
bool tiedscore;
|
|
Array<PlayerInfo> sortplayers;
|
|
Array<bool> teamactive;
|
|
Array<int> teamscore;
|
|
|
|
// if playing in Japanese, returns an alternate font of the same height
|
|
// Tewi -> MPlus
|
|
// Miniwi -> k6x8
|
|
Font LangFont( HUDFont req )
|
|
{
|
|
if ( language ~== "jp" )
|
|
{
|
|
if ( req == mMiniwiFont ) return mk6x8Font.mFont;
|
|
return mMPlusFont.mFont;
|
|
}
|
|
return req.mFont;
|
|
}
|
|
|
|
override void FlushNotify()
|
|
{
|
|
// flush interpolators (useful since this virtual gets called
|
|
// when loading saves, too)
|
|
HealthInter.Reset(CPlayer.Health);
|
|
ScoreInter.Reset(SWWMCredits.Get(CPlayer));
|
|
FuelInter.Reset((CPlayer.mo is 'Demolitionist')?int(Demolitionist(CPlayer.mo).dashfuel):0);
|
|
DashInter.Reset((CPlayer.mo is 'Demolitionist')?int((40-Demolitionist(CPlayer.mo).dashcooldown)*3.):0);
|
|
if ( level.maptime <= 1 )
|
|
{
|
|
// flush ALL messages
|
|
MainQueue.Clear();
|
|
PickupQueue.Clear();
|
|
return;
|
|
}
|
|
// flush non-chat messages
|
|
for ( int i=0; i<MainQueue.Size(); i++ )
|
|
{
|
|
if ( MainQueue[i].type >= 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<SWWMWeapon> 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;
|
|
}
|
|
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;
|
|
}
|
|
// 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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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 )
|
|
{
|
|
koraxhack = true;
|
|
Console.Printf(msg);
|
|
koraxhack = false;
|
|
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('swwm_achievement_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 )
|
|
{
|
|
mainframehack = true;
|
|
Console.Printf(msg);
|
|
mainframehack = false;
|
|
return true;
|
|
}
|
|
if ( (msg == StringTable.Localize("$BOSSLINE_IOS"))
|
|
|| (msg == StringTable.Localize("$BOSSLINE_ARCHANGELUS"))
|
|
|| (msg == StringTable.Localize("$BOSSLINE_DSPARIL")) )
|
|
{
|
|
bosshack = true;
|
|
Console.Printf(msg);
|
|
bosshack = false;
|
|
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 )
|
|
{
|
|
// this ignoring stuff has to be a thing until we can set printlevels directly
|
|
if ( outline.Left(21) == "SWWMHandler profiling" )
|
|
return true;
|
|
if ( outline.left(18) == "\cxSWWM GZ RNG dump" )
|
|
return true;
|
|
if ( koraxhack )
|
|
{
|
|
// treat as chat message
|
|
printlevel = PRINT_CHAT;
|
|
outline = "\cmKorax\c-: "..outline;
|
|
}
|
|
else if ( mainframehack )
|
|
{
|
|
// same here, hi yholl
|
|
printlevel = PRINT_CHAT;
|
|
outline = "\cmAI Mainframe\c-: "..outline;
|
|
}
|
|
else if ( bosshack )
|
|
{
|
|
// no need to attach name, these are done specifically for this
|
|
printlevel = PRINT_CHAT;
|
|
}
|
|
let m = new("MsgLine");
|
|
m.str = outline.Left(outline.Length()-1); // strip newline
|
|
m.type = printlevel;
|
|
m.tic = level.totaltime;
|
|
m.rep = 1;
|
|
// append chat messages to full history
|
|
if ( (printlevel == PRINT_CHAT) || (printlevel == PRINT_TEAMCHAT) )
|
|
EventHandler.SendNetworkEvent("swwmstoremessage."..m.str,m.tic,m.type,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
|
|
if ( printlevel == PRINT_LOW )
|
|
{
|
|
// check if repeated
|
|
for ( int i=0; i<PickupQueue.Size(); i++ )
|
|
{
|
|
if ( PickupQueue[i].str != m.str ) continue;
|
|
// delete old one and add its repeats
|
|
m.rep += PickupQueue[i].rep;
|
|
PickupQueue.Delete(i);
|
|
break;
|
|
}
|
|
PickupQueue.Push(m);
|
|
}
|
|
else
|
|
{
|
|
// check if repeated
|
|
for ( int i=0; i<MainQueue.Size(); i++ )
|
|
{
|
|
if ( MainQueue[i].str != m.str ) continue;
|
|
// delete old one and add its repeats
|
|
m.rep += MainQueue[i].rep;
|
|
MainQueue.Delete(i);
|
|
break;
|
|
}
|
|
MainQueue.Push(m);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool CmpTarget( SWWMCombatTracker a, SWWMCombatTracker b )
|
|
{
|
|
if ( !a || !b ) return true;
|
|
return (a.myplayer && !b.myplayer);
|
|
}
|
|
|
|
private bool CmpScore( SWWMScoreObj a, SWWMScoreObj b )
|
|
{
|
|
if ( !a || !b ) return true;
|
|
int srt[4] = { Font.CR_GOLD, Font.CR_FIRE, Font.CR_GREEN, Font.CR_RED };
|
|
int s1 = 0, s2 = 0;
|
|
for ( int i=0; i<3; i++ )
|
|
{
|
|
if ( a.tcolor == srt[i] ) s1 = i;
|
|
if ( b.tcolor == srt[i] ) s2 = i;
|
|
}
|
|
return s1 < s2;
|
|
}
|
|
|
|
private bool CmpInterest( SWWMInterest a, SWWMInterest b )
|
|
{
|
|
if ( !a || !b ) return true;
|
|
return a.type < b.type;
|
|
}
|
|
|
|
private bool CmpDist( Vector3 a, Vector3 b )
|
|
{
|
|
double dista = level.Vec3Diff(viewpos,a).length();
|
|
double distb = level.Vec3Diff(viewpos,b).length();
|
|
return (dista < distb);
|
|
}
|
|
|
|
// quicksort (points of interest)
|
|
private int partition_intpoints( Array<SWWMInterest> a, int l, int h )
|
|
{
|
|
SWWMInterest pv = a[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpInterest(pv,a[j]) || CmpDist(pv.pos,a[j].pos) )
|
|
{
|
|
i++;
|
|
SWWMInterest tmp = a[j];
|
|
a[j] = a[i];
|
|
a[i] = tmp;
|
|
}
|
|
}
|
|
SWWMInterest tmp = a[h];
|
|
a[h] = a[i+1];
|
|
a[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_intpoints( Array<SWWMInterest> a, int l, int h )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_intpoints(a,l,h);
|
|
qsort_intpoints(a,l,p-1);
|
|
qsort_intpoints(a,p+1,h);
|
|
}
|
|
|
|
// quicksort (combat trackers)
|
|
private int partition_trackers( Array<SWWMCombatTracker> a, int l, int h )
|
|
{
|
|
SWWMCombatTracker pv = a[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpTarget(pv,a[j]) || CmpDist(pv.pos,a[j].pos) )
|
|
{
|
|
i++;
|
|
SWWMCombatTracker tmp = a[j];
|
|
a[j] = a[i];
|
|
a[i] = tmp;
|
|
}
|
|
}
|
|
SWWMCombatTracker tmp = a[h];
|
|
a[h] = a[i+1];
|
|
a[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_trackers( Array<SWWMCombatTracker> a, int l, int h )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_trackers(a,l,h);
|
|
qsort_trackers(a,l,p-1);
|
|
qsort_trackers(a,p+1,h);
|
|
}
|
|
|
|
// quicksort (score objects)
|
|
private int partition_scoreobjs( Array<SWWMScoreObj> a, int l, int h )
|
|
{
|
|
SWWMScoreObj pv = a[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpScore(pv,a[j]) || CmpDist(pv.pos,a[j].pos) )
|
|
{
|
|
i++;
|
|
SWWMScoreObj tmp = a[j];
|
|
a[j] = a[i];
|
|
a[i] = tmp;
|
|
}
|
|
}
|
|
SWWMScoreObj tmp = a[h];
|
|
a[h] = a[i+1];
|
|
a[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_scoreobjs( Array<SWWMScoreObj> a, int l, int h )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_scoreobjs(a,l,h);
|
|
qsort_scoreobjs(a,l,p-1);
|
|
qsort_scoreobjs(a,p+1,h);
|
|
}
|
|
|
|
// quicksort (item sense)
|
|
private int partition_itemsense( Array<SWWMItemSense> a, int l, int h )
|
|
{
|
|
SWWMItemSense pv = a[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpDist(pv.pos,a[j].pos) )
|
|
{
|
|
i++;
|
|
SWWMItemSense tmp = a[j];
|
|
a[j] = a[i];
|
|
a[i] = tmp;
|
|
}
|
|
}
|
|
SWWMItemSense tmp = a[h];
|
|
a[h] = a[i+1];
|
|
a[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_itemsense( Array<SWWMItemSense> a, int l, int h )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_itemsense(a,l,h);
|
|
qsort_itemsense(a,l,p-1);
|
|
qsort_itemsense(a,p+1,h);
|
|
}
|
|
|
|
// quicksort (player scores)
|
|
private int partition_playerscore( Array<PlayerInfo> 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<PlayerInfo> 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()
|
|
{
|
|
HealthInter.Update(CPlayer.health);
|
|
if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
|
|
int s1, s2;
|
|
[s1, s2] = SWWMCredits.Get(CPlayer);
|
|
ScoreInter.Update(s1);
|
|
if ( ScoreInter.GetValue() >= ScoreInter.mCurrentValue ) ScoreInter2.Update(s2);
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov);
|
|
int maxtargetnum = max(0,swwm_maxtargets);
|
|
int maxscorenum = max(0,swwm_maxscorenums);
|
|
int maxdamnum = max(0,swwm_maxdamnums);
|
|
// prune old messages
|
|
for ( int i=0; i<PickupQueue.Size(); i++ )
|
|
{
|
|
if ( level.totaltime < (PickupQueue[i].tic+35*swwm_pickduration) ) continue;
|
|
PickupQueue.Delete(i);
|
|
i--;
|
|
}
|
|
for ( int i=0; i<MainQueue.Size(); i++ )
|
|
{
|
|
if ( (MainQueue[i].type <= PRINT_HIGH) && (level.totaltime < (MainQueue[i].tic+35*swwm_msgduration)) ) continue;
|
|
else if ( (MainQueue[i].type > PRINT_HIGH) && (level.totaltime < (MainQueue[i].tic+35*swwm_chatduration)) ) continue;
|
|
MainQueue.Delete(i);
|
|
i--;
|
|
}
|
|
// update interpolators
|
|
TickInterpolators();
|
|
let d = Demolitionist(CPlayer.mo);
|
|
if ( d )
|
|
{
|
|
FuelInter.Update(int(d.dashfuel));
|
|
DashInter.Update(int((40-d.dashcooldown)*3.));
|
|
}
|
|
else
|
|
{
|
|
FuelInter.Update(0);
|
|
DashInter.Update(0);
|
|
}
|
|
// let weapons update their own interpolators
|
|
if ( CPlayer.ReadyWeapon is 'SWWMWeapon' )
|
|
SWWMWeapon(CPlayer.ReadyWeapon).HudTick();
|
|
bool thesight = CPlayer.mo.FindInventory("Omnisight");
|
|
double desiredzoom = clamp(swwm_mm_zoom,.5,thesight?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;
|
|
}
|
|
let cam = players[consoleplayer].camera;
|
|
Vector3 viewvec = (cos(viewrot.x)*cos(viewrot.y),sin(viewrot.x)*cos(viewrot.y),sin(-viewrot.y));
|
|
int sz;
|
|
if ( thesight && swwm_pois )
|
|
{
|
|
// update omnisight stuff
|
|
if ( intpoints.Size() != hnd.intpoints_cnt )
|
|
intpoints.Resize(hnd.intpoints_cnt);
|
|
int i = 0;
|
|
for ( SWWMInterest poi=hnd.intpoints; poi; poi=poi.next )
|
|
{
|
|
// ignore points clearly outside of player view
|
|
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);
|
|
if ( !SWWMUtility.TestScreenBounds(projdata,vpos) ) continue;
|
|
intpoints[i++] = poi;
|
|
}
|
|
// squeeze if some were discarded
|
|
if ( i != hnd.intpoints_cnt )
|
|
intpoints.Resize(i);
|
|
// sort by distance
|
|
qsort_intpoints(intpoints,0,intpoints.Size()-1);
|
|
}
|
|
if ( swwm_targeter )
|
|
{
|
|
// update target stuff
|
|
if ( trackers.Size() != hnd.trackers_cnt )
|
|
trackers.Resize(hnd.trackers_cnt);
|
|
int i = 0;
|
|
for ( SWWMCombatTracker trk=hnd.trackers; trk; trk=trk.next )
|
|
{
|
|
// ignore dormant/invisible targets
|
|
if ( !trk.mytarget || trk.mytarget.bDORMANT || trk.mytarget.bINVISIBLE ) continue;
|
|
// ignore local player
|
|
if ( trk.mytarget == CPlayer.mo ) continue;
|
|
if ( trk.mytarget is 'PlayerGone' ) continue; // ignore "gone" players
|
|
int mtime = 35;
|
|
if ( thesight && (trk.lasthealth > 0) ) mtime += 105;
|
|
if ( level.maptime > trk.updated+mtime ) continue;
|
|
// ignore trackers clearly outside of player view
|
|
Vector3 tdir = level.Vec3Diff(viewpos,trk.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);
|
|
if ( !SWWMUtility.TestScreenBounds(projdata,vpos) ) continue;
|
|
trackers[i++] = trk;
|
|
}
|
|
// squeeze if some were discarded
|
|
if ( i != hnd.trackers_cnt )
|
|
trackers.Resize(i);
|
|
// sort by distance (give priority to players)
|
|
qsort_trackers(trackers,0,trackers.Size()-1);
|
|
// cap if limited (must cap after sorting, though, otherwise it'll look weird)
|
|
if ( maxtargetnum && (trackers.Size() > maxtargetnum) )
|
|
{
|
|
int endo = trackers.Size()-maxtargetnum;
|
|
// we gotta push the frontmost bars to the start, due to the inverted draw order
|
|
for ( int i=maxtargetnum-1; i>=0; i-- )
|
|
trackers[i] = trackers[endo+i];
|
|
trackers.Resize(maxtargetnum);
|
|
}
|
|
}
|
|
else trackers.Clear();
|
|
// update floating scores, adding the scorenums first, then the damnums
|
|
int total_sz = 0;
|
|
if ( swwm_scorenums ) total_sz += maxscorenum?min(maxscorenum,hnd.scorenums_cnt):hnd.scorenums_cnt;
|
|
if ( swwm_healthnums ) total_sz += maxdamnum?min(maxdamnum,hnd.damnums_cnt):hnd.damnums_cnt;
|
|
if ( scoreobjs.Size() != total_sz )
|
|
scoreobjs.Resize(total_sz);
|
|
int i = 0;
|
|
if ( swwm_scorenums )
|
|
{
|
|
for ( SWWMScoreObj scr=hnd.scorenums; scr && (i<total_sz); scr=scr.next )
|
|
{
|
|
// ignore numbers clearly outside of player view
|
|
Vector3 tdir = level.Vec3Diff(viewpos,scr.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);
|
|
if ( !SWWMUtility.TestScreenBounds(projdata,vpos) ) continue;
|
|
scoreobjs[i++] = scr;
|
|
}
|
|
}
|
|
if ( swwm_healthnums )
|
|
{
|
|
for ( SWWMScoreObj scr=hnd.damnums; scr && (i<total_sz); scr=scr.next )
|
|
{
|
|
// ignore numbers clearly outside of player view
|
|
Vector3 tdir = level.Vec3Diff(viewpos,scr.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);
|
|
if ( !SWWMUtility.TestScreenBounds(projdata,vpos) ) continue;
|
|
scoreobjs[i++] = scr;
|
|
}
|
|
}
|
|
// squeeze if some were discarded
|
|
if ( i != total_sz )
|
|
scoreobjs.Resize(i);
|
|
// sort by distance
|
|
qsort_scoreobjs(scoreobjs,0,scoreobjs.Size()-1);
|
|
// check if player has item sense
|
|
let demo = Demolitionist(CPlayer.mo);
|
|
if ( demo && (demo.itemsense_cnt > 0) )
|
|
{
|
|
if ( senseitems.Size() != demo.itemsense_cnt )
|
|
senseitems.Resize(demo.itemsense_cnt);
|
|
i = 0;
|
|
for ( SWWMItemSense s=demo.itemsense; s; s=s.next )
|
|
{
|
|
if ( !thesight && (level.maptime > s.updated+35) ) continue;
|
|
// ignore points clearly outside of player view
|
|
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);
|
|
if ( !SWWMUtility.TestScreenBounds(projdata,vpos) ) continue;
|
|
senseitems[i++] = s;
|
|
}
|
|
// squeeze if some were discarded
|
|
if ( i != demo.itemsense_cnt )
|
|
senseitems.Resize(i);
|
|
// sort by distance
|
|
qsort_itemsense(senseitems,0,senseitems.Size()-1);
|
|
}
|
|
// 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<Teams.Size(); i++ )
|
|
{
|
|
teamactive[i] = false;
|
|
teamscore[i] = 0;
|
|
}
|
|
for ( int i=0; i<MAXPLAYERS; i++ )
|
|
{
|
|
if ( !playeringame[i] ) continue;
|
|
int team = players[i].GetTeam();
|
|
if ( team != -1 )
|
|
{
|
|
teamactive[team] = true;
|
|
teamscore[team] += players[i].fragcount;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
playercount = 0;
|
|
int highscore = int.min;
|
|
tiedscore = false;
|
|
rank = 1;
|
|
for ( int i=0; i<MAXPLAYERS; i++ )
|
|
{
|
|
if ( !playeringame[i] ) continue;
|
|
playercount++;
|
|
if ( players[i] == CPlayer ) continue;
|
|
if ( players[i].fragcount > 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<MAXPLAYERS; i++ )
|
|
{
|
|
if ( !playeringame[i] ) continue;
|
|
sortplayers[j++] = players[i];
|
|
}
|
|
// sort players by score
|
|
qsort_playerscore(sortplayers,0,playercount-1);
|
|
if ( playercount <= 1 ) highscore = CPlayer.fragcount;
|
|
lead = CPlayer.fragcount-highscore;
|
|
}
|
|
|
|
override void Init()
|
|
{
|
|
Super.Init();
|
|
// scaling is set to 640 pixels wide minimum
|
|
// and height set so it fits up to ultrawide (2.370:1 ~ 2.4:1)
|
|
// ultrawide is honestly an abomination,
|
|
// and these numbers should be proof enough of it
|
|
// none of the commercially available "21:9" screens even have
|
|
// that actual ratio in the first place, what the fuck man
|
|
// they dangle anywhere between 12:4, 43:18 and 64:27
|
|
// fuck ultrawide, seriously
|
|
// get a 16:10 screen instead, it's the best aspect ratio
|
|
SetSize(0,640,266);
|
|
StatusTex = TexMan.CheckForTexture("graphics/HUD/StatusBox.png",TexMan.Type_Any);
|
|
DashTex = TexMan.CheckForTexture("graphics/HUD/DashBar.png",TexMan.Type_Any);
|
|
FuelTex[0] = TexMan.CheckForTexture("graphics/HUD/FuelBar.png",TexMan.Type_Any);
|
|
FuelTex[1] = TexMan.CheckForTexture("graphics/HUD/FuelBarS.png",TexMan.Type_Any);
|
|
HealthTex[0] = TexMan.CheckForTexture("graphics/HUD/HealthBar0.png",TexMan.Type_Any);
|
|
HealthTex[1] = TexMan.CheckForTexture("graphics/HUD/HealthBar1.png",TexMan.Type_Any);
|
|
HealthTex[2] = TexMan.CheckForTexture("graphics/HUD/HealthBar2.png",TexMan.Type_Any);
|
|
HealthTex[3] = TexMan.CheckForTexture("graphics/HUD/HealthBar3.png",TexMan.Type_Any);
|
|
HealthTex[4] = TexMan.CheckForTexture("graphics/HUD/HealthBarS.png",TexMan.Type_Any);
|
|
HealthTex[5] = TexMan.CheckForTexture("graphics/HUD/HealthBarD.png",TexMan.Type_Any);
|
|
ScoreTex[0] = TexMan.CheckForTexture("graphics/HUD/ScoreBoxL.png",TexMan.Type_Any);
|
|
ScoreTex[1] = TexMan.CheckForTexture("graphics/HUD/ScoreBoxM.png",TexMan.Type_Any);
|
|
ScoreTex[2] = TexMan.CheckForTexture("graphics/HUD/ScoreBoxR.png",TexMan.Type_Any);
|
|
WeaponTex = TexMan.CheckForTexture("graphics/HUD/WeaponBox.png",TexMan.Type_Any);
|
|
ChatTex[0] = TexMan.CheckForTexture("graphics/HUD/ChatBoxTop.png",TexMan.Type_Any);
|
|
ChatTex[1] = TexMan.CheckForTexture("graphics/HUD/ChatBoxLine.png",TexMan.Type_Any);
|
|
ChatTex[2] = TexMan.CheckForTexture("graphics/HUD/ChatBoxBottom.png",TexMan.Type_Any);
|
|
ChatTex[3] = TexMan.CheckForTexture("graphics/HUD/ChatBoxTop_Smol.png",TexMan.Type_Any);
|
|
ChatTex[4] = TexMan.CheckForTexture("graphics/HUD/ChatBoxLine_Smol.png",TexMan.Type_Any);
|
|
ChatTex[5] = TexMan.CheckForTexture("graphics/HUD/ChatBoxBottom_Smol.png",TexMan.Type_Any);
|
|
InventoryTex = TexMan.CheckForTexture("graphics/HUD/InventoryBox.png",TexMan.Type_Any);
|
|
EnemyBTex = TexMan.CheckForTexture("graphics/HUD/EnemyBox.png",TexMan.Type_Any);
|
|
EnemyHTex[0] = TexMan.CheckForTexture("graphics/HUD/EnemyBar0.png",TexMan.Type_Any);
|
|
EnemyHTex[1] = TexMan.CheckForTexture("graphics/HUD/EnemyBar1.png",TexMan.Type_Any);
|
|
EnemyHTex[2] = TexMan.CheckForTexture("graphics/HUD/EnemyBar2.png",TexMan.Type_Any);
|
|
EnemyHTex[3] = TexMan.CheckForTexture("graphics/HUD/EnemyBar3.png",TexMan.Type_Any);
|
|
EnemyHTex[4] = TexMan.CheckForTexture("graphics/HUD/EnemyBarS.png",TexMan.Type_Any);
|
|
EnemyHTex[5] = TexMan.CheckForTexture("graphics/HUD/EnemyBarD.png",TexMan.Type_Any);
|
|
GenericAmmoTex[0] = TexMan.CheckForTexture("graphics/HUD/GenericAmmoBoxL.png",TexMan.Type_Any);
|
|
GenericAmmoTex[1] = TexMan.CheckForTexture("graphics/HUD/GenericAmmoBoxM.png",TexMan.Type_Any);
|
|
GenericAmmoTex[2] = TexMan.CheckForTexture("graphics/HUD/GenericAmmoBoxR.png",TexMan.Type_Any);
|
|
MiniBox = TexMan.CheckForTexture("graphics/HUD/MinimapBox.png",TexMan.Type_Any);
|
|
AutoPage = TexMan.CheckForTexture("AUTOPAGE",TexMan.Type_Autopage);
|
|
PauseTex = TexMan.CheckForTexture("graphics/swwmpause.png",TexMan.Type_Any);
|
|
bgtex = TexMan.CheckForTexture("graphics/tempbg.png",TexMan.Type_Any);
|
|
minimapzoom = oldminimapzoom = 1.;
|
|
mTewiFont = HUDFont.Create("TewiShaded");
|
|
mMiniwiFont = HUDFont.Create("MiniwiShaded");
|
|
mMPlusFont = HUDFont.Create("MPlusShaded");
|
|
mk6x8Font = HUDFont.Create("k6x8Shaded");
|
|
HealthInter = DynamicValueInterpolator.Create(100,.1,1,100);
|
|
ScoreInter = DynamicValueInterpolator.Create(0,.1,1,999999999);
|
|
ScoreInter2 = DynamicValueInterpolator.Create(0,.1,1,999999999);
|
|
FuelInter = DynamicValueInterpolator.Create(120,.5,1,100);
|
|
DashInter = DynamicValueInterpolator.Create(120,.5,1,40);
|
|
hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
|
|
PrevFrame = MSTime();
|
|
}
|
|
|
|
static private string FormatDist( double dist )
|
|
{
|
|
double meters = dist/32.;
|
|
if ( meters > 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 DrawTarget()
|
|
{
|
|
// don't draw when dead or with automap open
|
|
if ( (CPlayer.health <= 0) || automapactive ) return;
|
|
SWWMUtility.PrepareProjData(projdata,ViewPos,ViewRot.x,ViewRot.y,ViewRot.z,players[consoleplayer].fov);
|
|
int cliptop = projdata.viewy, clipbottom = projdata.viewy+projdata.viewh,
|
|
clipleft = projdata.viewx, clipright = projdata.viewx+projdata.vieww;
|
|
bool thesight = !!CPlayer.mo.FindInventory("Omnisight");
|
|
// points of interest
|
|
String tag;
|
|
if ( thesight )
|
|
{
|
|
for ( int i=0; i<intpoints.Size(); i++ )
|
|
{
|
|
let poi = intpoints[i];
|
|
if ( !poi ) continue;
|
|
Vector3 tdir = level.Vec3Diff(ViewPos,poi.pos);
|
|
Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir);
|
|
if ( ndc.z >= 1. ) continue;
|
|
Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc);
|
|
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"));
|
|
}
|
|
}
|
|
Font fnt = LangFont(mMiniwiFont);
|
|
Screen.DrawText(fnt,Font.CR_WHITE,(vpos.x-hsi.x*fnt.StringWidth(tag)/2.)/hsi.x,(vpos.y-hsi.y*fnt.GetHeight()/2.)/hsi.y,tag,DTA_VirtualWidthF,ssi.x,DTA_VirtualHeightF,ssi.y,DTA_KeepRatio,true,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
tag = String.Format("\cu(%s\cu)\c-",FormatDist(tdir.length()));
|
|
Screen.DrawText(fnt,Font.CR_WHITE,(vpos.x-hsi.x*fnt.StringWidth(tag)/2.)/hsi.x,(vpos.y+hsi.y*fnt.GetHeight()/2.)/hsi.y,tag,DTA_VirtualWidthF,ssi.x,DTA_VirtualHeightF,ssi.y,DTA_KeepRatio,true,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
}
|
|
}
|
|
// sensed items
|
|
let demo = Demolitionist(CPlayer.mo);
|
|
if ( demo && (demo.itemsense_cnt > 0) )
|
|
{
|
|
for ( int i=0; i<senseitems.Size(); i++ )
|
|
{
|
|
let s = senseitems[i];
|
|
if ( !s || !s.item ) continue;
|
|
Vector3 tdir = level.Vec3Diff(ViewPos,s.pos);
|
|
Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+tdir);
|
|
if ( ndc.z >= 1. ) continue;
|
|
Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc);
|
|
Font fnt = LangFont(mMiniwiFont);
|
|
int mtime = thesight?70:35;
|
|
double alph = clamp(((s.updated+mtime)-(level.maptime+fractic))/35.,0.,1.);
|
|
alph *= clamp(1.5-1.5*(tdir.length()/(thesight?1200.:800.)),0.,1.);
|
|
tag = s.tag;
|
|
Screen.DrawText(fnt,s.vipitem?Font.CR_PURPLE:s.scoreitem?Font.CR_GOLD:Font.CR_GREEN,(vpos.x-hsd.x*fnt.StringWidth(tag)/2.)/hsd.x,(vpos.y-hsd.y*fnt.GetHeight()/2.)/hsd.y,tag,DTA_VirtualWidthF,ssd.x,DTA_VirtualHeightF,ssd.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
tag = String.Format("\cu(%s\cu)\c-",FormatDist(tdir.length()));
|
|
Screen.DrawText(fnt,Font.CR_WHITE,(vpos.x-hsd.x*fnt.StringWidth(tag)/2.)/hsd.x,(vpos.y+hsd.y*fnt.GetHeight()/2.)/hsd.y,tag,DTA_VirtualWidthF,ssd.x,DTA_VirtualHeightF,ssd.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
if ( s.item is 'SWWMRespawnTimer' )
|
|
{
|
|
tag = String.Format(StringTable.Localize("$SWWM_TRESPAWN"),s.item.special2/GameTicRate);
|
|
Screen.DrawText(fnt,Font.CR_WHITE,(vpos.x-hsd.x*fnt.StringWidth(tag)/2.)/hsd.x,(vpos.y+hsd.y*fnt.GetHeight()*2)/hsd.y,tag,DTA_VirtualWidthF,ssd.x,DTA_VirtualHeightF,ssd.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
}
|
|
}
|
|
}
|
|
// targetting array
|
|
for ( int i=0; i<trackers.Size(); i++ )
|
|
{
|
|
let targ = trackers[i];
|
|
if ( !targ ) continue;
|
|
Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+level.Vec3Diff(ViewPos,targ.prevpos*(1.-fractic)+targ.pos*fractic));
|
|
if ( ndc.z >= 1. ) continue;
|
|
Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc);
|
|
tag = targ.mytag;
|
|
if ( (tag != "") && !targ.myplayer )
|
|
{
|
|
if ( targ.legged && (targ.mutated || swwm_ldspoil) )
|
|
{
|
|
if ( StringTable.Localize("$SWWM_LEGPREFIX") == "R" ) tag = tag..StringTable.Localize("$SWWM_LEG");
|
|
else tag = StringTable.Localize("$SWWM_LEG")..tag;
|
|
}
|
|
if ( targ.bBOSS ) tag = "\cx★\c- "..tag.." \cx★\c-";
|
|
if ( targ.bFRIENDLY ) tag = "\cg♥\c- "..tag.." \cg♥\c-";
|
|
}
|
|
int mtime = 35;
|
|
if ( thesight && (targ.lasthealth > 0) ) mtime += 105;
|
|
double alph = clamp(((targ.updated+mtime)-(level.maptime+fractic))/35.,0.,1.);
|
|
Vector2 barsiz = TexMan.GetScaledSize(EnemyBTex);
|
|
barsiz.x *= hsb.x;
|
|
barsiz.y *= hsb.y;
|
|
Vector2 barpos = vpos-(barsiz/2.);
|
|
barpos.y -= 16.;
|
|
Font fnt = LangFont(swwm_bigtags?mTewiFont:mMiniwiFont);
|
|
int col = Font.CR_WHITE;
|
|
if ( teamplay )
|
|
{
|
|
int team = targ.myplayer.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;
|
|
}
|
|
if ( swwm_targettags || targ.myplayer && (tag != "") )
|
|
Screen.DrawText(fnt,col,(barpos.x+barsiz.x/2.-(fnt.StringWidth(tag)*hsb.x)/2.)/hsb.x,(barpos.y-fnt.GetHeight()*hsb.y)/hsb.y,tag,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
Screen.DrawTexture(EnemyBTex,false,barpos.x/hsb.x,barpos.y/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
double ht = clamp(targ.intp.GetValue(),0,targ.maxhealth*100);
|
|
double hw = (min(ht,targ.maxhealth)*50.)/targ.maxhealth;
|
|
if ( targ.mytarget && (targ.mytarget.bInvulnerable || (targ.myplayer && (targ.myplayer.cheats&(CF_GODMODE|CF_GODMODE2))) || targ.mytarget.FindInventory("InvinciballPower")) )
|
|
{
|
|
Screen.DrawTexture(EnemyHTex[4],false,(barpos.x+2*hsb.x)/hsb.x,(barpos.y+2*hsb.y)/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
}
|
|
else
|
|
{
|
|
Screen.DrawTexture(EnemyHTex[0],false,(barpos.x+2*hsb.x)/hsb.x,(barpos.y+2*hsb.y)/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
if ( ht > targ.maxhealth )
|
|
{
|
|
hw = (min(ht-targ.maxhealth,targ.maxhealth)*50.)/targ.maxhealth;
|
|
Screen.DrawTexture(EnemyHTex[1],false,(barpos.x+2*hsb.x)/hsb.x,(barpos.y+2*hsb.y)/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
}
|
|
if ( ht > targ.maxhealth*2 )
|
|
{
|
|
hw = (min(ht-targ.maxhealth*2,targ.maxhealth*3)*50.)/(targ.maxhealth*3);
|
|
Screen.DrawTexture(EnemyHTex[2],false,(barpos.x+2*hsb.x)/hsb.x,(barpos.y+2*hsb.y)/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
}
|
|
if ( ht > targ.maxhealth*5 )
|
|
{
|
|
hw = (min(ht-targ.maxhealth*5,targ.maxhealth*5)*50.)/(targ.maxhealth*5);
|
|
Screen.DrawTexture(EnemyHTex[3],false,(barpos.x+2*hsb.x)/hsb.x,(barpos.y+2*hsb.y)/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRightF,hw,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
}
|
|
}
|
|
if ( targ.mytarget && targ.mytarget.FindInventory("DivineSpriteEffect") )
|
|
{
|
|
double falph = clamp((ht-targ.maxhealth*10)/(targ.maxhealth*60.),0.,1.);
|
|
Screen.DrawTexture(EnemyHTex[5],false,(barpos.x+2*hsb.x)/hsb.x,(barpos.y+2*hsb.y)/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph*falph,DTA_LegacyRenderStyle,STYLE_Add,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
}
|
|
}
|
|
// floating kill scores and others
|
|
for ( int i=0; i<scoreobjs.Size(); i++ )
|
|
{
|
|
let snum = scoreobjs[i];
|
|
if ( !snum ) continue;
|
|
Vector3 ndc = SWWMUtility.ProjectPoint(projdata,ViewPos+level.Vec3Diff(ViewPos,snum.pos));
|
|
if ( ndc.z >= 1. ) continue;
|
|
Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc);
|
|
tag = String.Format("%+d",snum.score);
|
|
double alph = clamp((snum.lifespan+fractic)/35.,0.,1.);
|
|
Vector2 fo = (0,0);
|
|
bool isscore = false;
|
|
if ( snum.damnum )
|
|
{
|
|
if ( snum.score < 0 )
|
|
{
|
|
// damage falls down
|
|
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));
|
|
}
|
|
else
|
|
{
|
|
// health falls up (?)
|
|
int initspd = (128-snum.seed);
|
|
int boostup = 16+snum.seed2/4;
|
|
fo.x = (.15*initspd)*((snum.initialspan-(snum.lifespan-fractic))**.6);
|
|
fo.y = ((snum.initialspan-(snum.lifespan-fractic))**1.2)-boostup*sin((90./snum.initialspan)*(level.maptime+fractic-snum.starttic));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// score rises linearly
|
|
fo.y = snum.initialspan-(snum.lifespan-fractic);
|
|
isscore = true;
|
|
}
|
|
Font fnt = mMiniwiFont.mFont;
|
|
Vector2 hs0 = isscore?hss:hsn;
|
|
Vector2 ss0 = isscore?sss:ssn;
|
|
Screen.DrawText(fnt,snum.tcolor,(vpos.x-hs0.x*(fo.x+fnt.StringWidth(tag)/2.))/hs0.x,(vpos.y-hs0.y*(fo.y+(fnt.GetHeight()/2.)))/hs0.y,tag,DTA_VirtualWidthF,ss0.x,DTA_VirtualHeightF,ss0.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
// extra strings (if available)
|
|
if ( !swwm_scorebonus ) continue;
|
|
fo.y += fnt.GetHeight();
|
|
fnt = LangFont(mMiniwiFont);
|
|
for ( int i=0; i<snum.xcnt; i++ )
|
|
{
|
|
tag = snum.xstr[i];
|
|
if ( snum.xscore[i] == int.max ) tag.AppendFormat(" MAX");
|
|
else if ( snum.xscore[i] > 0 ) tag.AppendFormat(" x%d",snum.xscore[i]);
|
|
Screen.DrawText(fnt,snum.xtcolor[i],(vpos.x-hss.x*(fo.x+fnt.StringWidth(tag)/2.))/hss.x,(vpos.y-hss.y*(fo.y+(fnt.GetHeight()/2.)))/hss.y,tag,DTA_VirtualWidthF,sss.x,DTA_VirtualHeightF,sss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
|
|
fo.y += fnt.GetHeight();
|
|
}
|
|
}
|
|
}
|
|
|
|
override void DrawMyPos()
|
|
{
|
|
String str = String.Format("(%d,%d,%d)",CPlayer.mo.pos.X,CPlayer.mo.pos.Y,CPlayer.mo.pos.Z);
|
|
let fnt = LangFont(mMiniwiFont);
|
|
Screen.DrawText(fnt,Font.CR_GREEN,(ss.x-fnt.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;
|
|
mm_drawautopage = AutoPage&&(am_drawmapback==1);
|
|
switch ( mm_colorset )
|
|
{
|
|
case 1:
|
|
// gzdoom
|
|
mm_backcolor = am_backcolor;
|
|
mm_cdwallcolor = am_cdwallcolor;
|
|
mm_efwallcolor = am_efwallcolor;
|
|
mm_fdwallcolor = am_fdwallcolor;
|
|
mm_gridcolor = am_gridcolor;
|
|
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_xhaircolor = am_xhaircolor;
|
|
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_gridcolor = "4c 4c 4c";
|
|
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_xhaircolor = "80 80 80";
|
|
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_gridcolor = "4c 4c 4c";
|
|
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_xhaircolor = "80 80 80";
|
|
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_gridcolor = "46 32 10";
|
|
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_xhaircolor = "00 00 00";
|
|
mm_yourcolor = "ff ff ff";
|
|
mm_displaylocks = true;
|
|
break;
|
|
default:
|
|
// swwm
|
|
mm_backcolor = swwm_mm_backcolor;
|
|
mm_cdwallcolor = swwm_mm_cdwallcolor;
|
|
mm_efwallcolor = swwm_mm_efwallcolor;
|
|
mm_fdwallcolor = swwm_mm_fdwallcolor;
|
|
mm_gridcolor = swwm_mm_gridcolor;
|
|
mm_interlevelcolor = swwm_mm_interlevelcolor;
|
|
mm_intralevelcolor = swwm_mm_intralevelcolor;
|
|
mm_lockedcolor = swwm_mm_lockedcolor;
|
|
mm_notseencolor = swwm_mm_notseencolor;
|
|
mm_portalcolor = swwm_mm_portalcolor;
|
|
mm_secretsectorcolor = swwm_mm_secretsectorcolor;
|
|
mm_secretwallcolor = swwm_mm_secretwallcolor;
|
|
mm_specialwallcolor = swwm_mm_specialwallcolor;
|
|
mm_thingcolor = swwm_mm_thingcolor;
|
|
mm_thingcolor_citem = swwm_mm_thingcolor_citem;
|
|
mm_thingcolor_friend = swwm_mm_thingcolor_friend;
|
|
mm_thingcolor_item = swwm_mm_thingcolor_item;
|
|
mm_thingcolor_monster = swwm_mm_thingcolor_monster;
|
|
mm_thingcolor_ncmonster = swwm_mm_thingcolor_ncmonster;
|
|
mm_thingcolor_shootable = swwm_mm_thingcolor_shootable;
|
|
mm_thingcolor_vipitem = swwm_mm_thingcolor_vipitem;
|
|
mm_thingcolor_missile = swwm_mm_thingcolor_missile;
|
|
mm_tswallcolor = swwm_mm_tswallcolor;
|
|
mm_unexploredsecretcolor = swwm_mm_unexploredsecretcolor;
|
|
mm_wallcolor = swwm_mm_wallcolor;
|
|
mm_xhaircolor = swwm_mm_xhaircolor;
|
|
mm_yourcolor = swwm_mm_yourcolor;
|
|
mm_displaylocks = true;
|
|
mm_drawautopage = false;
|
|
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 DrawMapGrid( Vector2 basepos )
|
|
{
|
|
double zoomlevel = oldminimapzoom*(1.-FracTic)+minimapzoom*FracTic;
|
|
double zoomview = MAPVIEWDIST*zoomlevel, zoomclip = CLIPDIST*zoomlevel;
|
|
Vector2 cpos = players[consoleplayer].Camera.prev.xy*(1.-FracTic)+players[consoleplayer].Camera.pos.xy*FracTic;
|
|
// find farthest visible southwest grid point from camera position
|
|
int maxlines = int(zoomview/64);
|
|
Vector2 gpt = (cpos-(zoomview,zoomview))/128;
|
|
gpt.x = int(gpt.x)*128;
|
|
gpt.y = int(gpt.y)*128;
|
|
for ( int i=0; i<maxlines; i++ )
|
|
{
|
|
Vector2 rv1 = (gpt+(i*128,0))-cpos;
|
|
Vector2 rv2 = (gpt+(i*128,maxlines*128))-cpos;
|
|
if ( min(min(abs(rv1.x),abs(rv2.x)),min(abs(rv1.y),abs(rv2.y))) > zoomview )
|
|
continue;
|
|
// flip Y
|
|
rv1.y *= -1;
|
|
rv2.y *= -1;
|
|
// rotate by view
|
|
if ( swwm_mm_rotate )
|
|
{
|
|
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.x;
|
|
rv2 *= (HALFMAPSIZE/zoomclip)*hs.x;
|
|
// offset to minimap center
|
|
rv1 += basepos;
|
|
rv2 += basepos;
|
|
// draw the line
|
|
Screen.DrawThickLine(int(rv1.x),int(rv1.y),int(rv2.x),int(rv2.y),max(1.,hs.x*.25),mm_gridcolor);
|
|
}
|
|
for ( int i=0; i<maxlines; i++ )
|
|
{
|
|
Vector2 rv1 = (gpt+(0,i*128))-cpos;
|
|
Vector2 rv2 = (gpt+(maxlines*128,i*128))-cpos;
|
|
if ( min(min(abs(rv1.x),abs(rv2.x)),min(abs(rv1.y),abs(rv2.y))) > zoomview )
|
|
continue;
|
|
// flip Y
|
|
rv1.y *= -1;
|
|
rv2.y *= -1;
|
|
// rotate by view
|
|
if ( swwm_mm_rotate )
|
|
{
|
|
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.x;
|
|
rv2 *= (HALFMAPSIZE/zoomclip)*hs.x;
|
|
// offset to minimap center
|
|
rv1 += basepos;
|
|
rv2 += basepos;
|
|
// draw the line
|
|
Screen.DrawThickLine(int(rv1.x),int(rv1.y),int(rv2.x),int(rv2.y),max(1.,hs.x*.25),mm_gridcolor);
|
|
}
|
|
// draw the origin crosshair
|
|
Vector2 tv[4];
|
|
tv[0] = (-16,0);
|
|
tv[1] = (16,0);
|
|
tv[2] = (0,-16);
|
|
tv[3] = (0,16);
|
|
for ( int i=0; i<4; i+=2 )
|
|
{
|
|
Vector2 rv1 = tv[i]-cpos;
|
|
Vector2 rv2 = tv[i+1]-cpos;
|
|
if ( min(min(abs(rv1.x),abs(rv2.x)),min(abs(rv1.y),abs(rv2.y))) > zoomview )
|
|
continue;
|
|
// flip Y
|
|
rv1.y *= -1;
|
|
rv2.y *= -1;
|
|
// rotate by view
|
|
if ( swwm_mm_rotate )
|
|
{
|
|
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.x;
|
|
rv2 *= (HALFMAPSIZE/zoomclip)*hs.x;
|
|
// offset to minimap center
|
|
rv1 += basepos;
|
|
rv2 += basepos;
|
|
// draw the line
|
|
Screen.DrawThickLine(int(rv1.x),int(rv1.y),int(rv2.x),int(rv2.y),max(1.,hs.x*.75),mm_xhaircolor);
|
|
}
|
|
}
|
|
|
|
private void DrawMapLines( Vector2 basepos )
|
|
{
|
|
double zoomlevel = oldminimapzoom*(1.-FracTic)+minimapzoom*FracTic;
|
|
double zoomview = MAPVIEWDIST*zoomlevel, zoomclip = CLIPDIST*zoomlevel;
|
|
Vector2 cpos = players[consoleplayer].Camera.prev.xy*(1.-FracTic)+players[consoleplayer].Camera.pos.xy*FracTic;
|
|
Sector csec = players[consoleplayer].Camera.CurSector;
|
|
for ( int i=0; i<level.lines.Size(); i++ )
|
|
{
|
|
Line l = level.lines[i];
|
|
if ( !(l.flags&Line.ML_MAPPED) && !level.allmap && !am_cheat ) continue;
|
|
if ( (l.flags&Line.ML_DONTDRAW) && ((am_cheat == 0) || (am_cheat >= 4)) )
|
|
continue;
|
|
Vector2 rv1 = l.v1.p-cpos, rv2 = l.v2.p-cpos;
|
|
bool isportal = false;
|
|
if ( swwm_mm_portaloverlay )
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
if ( min(min(abs(rv1.x),abs(rv2.x)),min(abs(rv1.y),abs(rv2.y))) > zoomview )
|
|
continue;
|
|
// flip Y
|
|
rv1.y *= -1;
|
|
rv2.y *= -1;
|
|
// rotate by view
|
|
if ( swwm_mm_rotate )
|
|
{
|
|
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.x;
|
|
rv2 *= (HALFMAPSIZE/zoomclip)*hs.x;
|
|
// 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.x*.25),col);
|
|
}
|
|
else Screen.DrawThickLine(int(rv1.x),int(rv1.y),int(rv2.x),int(rv2.y),max(1.,hs.x*.5),col);
|
|
}
|
|
}
|
|
private void DrawMapThings( Vector2 basepos )
|
|
{
|
|
bool thesight = !!CPlayer.mo.FindInventory("Omnisight");
|
|
double zoomlevel = oldminimapzoom*(1.-FracTic)+minimapzoom*FracTic;
|
|
double zoomview = MAPVIEWDIST*zoomlevel, zoomclip = CLIPDIST*zoomlevel;
|
|
Vector2 cpos = players[consoleplayer].Camera.prev.xy*(1.-FracTic)+players[consoleplayer].Camera.pos.xy*FracTic;
|
|
Sector csec = players[consoleplayer].Camera.CurSector;
|
|
for ( SWWMSimpleTracker t=hnd.strackers; t; t=t.next )
|
|
{
|
|
if ( !swwm_mm_missiles && t.ismissile ) continue;
|
|
Color col = mm_thingcolor;
|
|
bool isitem = false;
|
|
bool plainactor = false;
|
|
Vector2 pos;
|
|
double angle;
|
|
double radius;
|
|
if ( t.target )
|
|
{
|
|
pos = t.target.prev.xy*(1.-FracTic)+t.target.pos.xy*FracTic;
|
|
angle = t.target.angle;
|
|
radius = t.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 = 35;
|
|
if ( thesight && !t.expired && t.target ) mtime += 105;
|
|
Vector2 rv = pos-cpos;
|
|
bool isportal = false;
|
|
if ( swwm_mm_portaloverlay )
|
|
{
|
|
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 ( min(abs(rv.x)-radius,abs(rv.y)-radius) > zoomview )
|
|
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<nidx; j++ ) tv[j].y *= -1;
|
|
// rotate by view
|
|
if ( swwm_mm_rotate ) for ( int j=0; j<nidx; j++ ) tv[j] = Actor.RotateVector(tv[j],ViewRot.x-90);
|
|
bool visible, drawn;
|
|
Vector2 x0, x1;
|
|
// clip to frame
|
|
for ( int j=0; j<nidx; j++ )
|
|
{
|
|
[visible, x0, x1] = SWWMUtility.LiangBarsky((-1,-1)*zoomclip,(1,1)*zoomclip,tv[j],tv[(j+1)%nidx]);
|
|
if ( visible )
|
|
{
|
|
// scale to minimap frame
|
|
x0 *= (HALFMAPSIZE/zoomclip)*hs.x;
|
|
x1 *= (HALFMAPSIZE/zoomclip)*hs.x;
|
|
// offset to minimap center
|
|
x0 += basepos;
|
|
x1 += basepos;
|
|
// draw the line
|
|
if ( isportal ) Screen.DrawThickLine(int(x0.x),int(x0.y),int(x1.x),int(x1.y),max(1.,hs.x*.25),col,int(t.smoothalpha*255));
|
|
else Screen.DrawThickLine(int(x0.x),int(x0.y),int(x1.x),int(x1.y),max(1.,hs.x*.5),col,int(t.smoothalpha*255));
|
|
drawn = true;
|
|
}
|
|
}
|
|
if ( drawn )
|
|
{
|
|
double alph = clamp(((t.lastupdate+mtime)-level.maptime)/35.,0.,1.);
|
|
if ( t.isbeam ) alph *= t.target?(t.target.alpha/t.target.default.alpha):0.;
|
|
double theta = clamp(5.*FrameTime,0.,1.);
|
|
t.smoothalpha = t.smoothalpha*(1.-theta)+alph*theta;
|
|
}
|
|
else t.smoothalpha = 0.;
|
|
}
|
|
}
|
|
|
|
private String OrdinalStr( int val, int gender )
|
|
{
|
|
String lstr = "SWWM_PLACE"..val.."_GENDER"..gender;
|
|
String str = StringTable.Localize("$"..lstr);
|
|
if ( str != lstr ) return str;
|
|
return StringTable.Localize("$SWWM_PLACE"..val);
|
|
}
|
|
|
|
private void DrawScore()
|
|
{
|
|
String sstr;
|
|
if ( ScoreInter2.GetValue() > 0 ) sstr = String.Format("%d%09d",ScoreInter2.GetValue(),ScoreInter.GetValue());
|
|
else sstr = String.Format("%09d",ScoreInter.GetValue());
|
|
int digits = sstr.Length();
|
|
int xx = 19+6*digits;
|
|
Screen.DrawTexture(ScoreTex[0],false,ss.x-(margin+xx),margin,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
xx -= 15;
|
|
for ( int i=0; i<digits; i++ )
|
|
{
|
|
Screen.DrawTexture(ScoreTex[1],false,ss.x-(margin+xx),margin,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
xx -= 6;
|
|
}
|
|
Screen.DrawTexture(ScoreTex[2],false,ss.x-(margin+xx),margin,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,ss.x-(margin+4+6*digits),margin+1,sstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
int yy = margin+19;
|
|
// obviously, don't draw the minimap if the automap is open
|
|
if ( !automapactive && swwm_mm_enable )
|
|
{
|
|
GetMinimapColors();
|
|
xx = int(ss.x-(margin+(HALFMAPSIZE+2)*2));
|
|
Screen.DrawTexture(MiniBox,false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
Vector2 basemappos = (xx+HALFMAPSIZE+2,yy+HALFMAPSIZE+2);
|
|
Screen.Dim(mm_backcolor,1.,int((basemappos.x-HALFMAPSIZE)*hs.x),int((basemappos.y-HALFMAPSIZE)*hs.x),int(HALFMAPSIZE*2*hs.x),int(HALFMAPSIZE*2*hs.x));
|
|
if ( mm_drawautopage ) Screen.DrawTexture(AutoPage,false,xx+2,yy+2,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ClipRight,int((xx+2+HALFMAPSIZE*2)*hs.x),DTA_ClipBottom,int((yy+2+HALFMAPSIZE*2)*hs.x));
|
|
// draw dat stuff
|
|
if ( swwm_mm_grid ) DrawMapGrid(basemappos*hs.x);
|
|
DrawMapLines(basemappos*hs.x);
|
|
DrawMapThings(basemappos*hs.x);
|
|
// finally, draw the player arrow
|
|
Vector2 tv[3];
|
|
tv[0] = (0,-4);
|
|
tv[1] = (-3,2);
|
|
tv[2] = (3,2);
|
|
if ( !swwm_mm_rotate ) for ( int i=0; i<3; i++ ) tv[i] = Actor.RotateVector(tv[i],90-ViewRot.x);
|
|
for ( int i=0; i<3; i++ ) tv[i] = (tv[i]+basemappos)*hs.x;
|
|
for ( int i=0; i<3; i++ ) Screen.DrawThickLine(int(tv[i].x),int(tv[i].y),int(tv[(i+1)%3].x),int(tv[(i+1)%3].y),max(1.,hs.x*.5),mm_yourcolor);
|
|
yy += ((HALFMAPSIZE+2)*2)+3;
|
|
}
|
|
// draw stats and timer when automap is open
|
|
int fstats = swwm_forcestats;
|
|
if ( automapactive || (fstats > 0) )
|
|
{
|
|
xx = int(ss.x-(margin+2));
|
|
String str;
|
|
Font fnt;
|
|
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);
|
|
fnt = LangFont(mTewiFont);
|
|
Screen.DrawText(fnt,Font.CR_FIRE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
fnt = LangFont(mMiniwiFont);
|
|
if ( (level.total_monsters > 0) && am_showmonsters && !deathmatch )
|
|
{
|
|
str = String.Format("\cxK \c-%d\cu/\c-%d",level.killed_monsters,level.total_monsters);
|
|
Screen.DrawText(fnt,(level.killed_monsters>=level.total_monsters)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
if ( (level.total_items > 0) && am_showitems && !deathmatch )
|
|
{
|
|
str = String.Format("\cxI \c-%d\cu/\c-%d",level.found_items,level.total_items);
|
|
Screen.DrawText(fnt,(level.found_items>=level.total_items)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
if ( (level.total_secrets > 0) && am_showsecrets && !deathmatch )
|
|
{
|
|
str = String.Format("\cxS \c-%d\cu/\c-%d",level.found_secrets,level.total_secrets);
|
|
Screen.DrawText(fnt,(level.found_secrets>=level.total_secrets)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
int sec;
|
|
if ( am_showtime )
|
|
{
|
|
sec = Thinker.Tics2Seconds(level.maptime);
|
|
str = String.Format("\cxT \c-%02d\cu:\c-%02d\cu:\c-%02d",sec/3600,(sec%3600)/60,sec%60);
|
|
Screen.DrawText(fnt,((level.sucktime>0)&&(sec>=(level.sucktime*3600)))?Font.CR_RED:(sec<=level.partime)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
// 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("\cxTT \c-%02d\cu:\c-%02d\cu:\c-%02d",sec/3600,(sec%3600)/60,sec%60);
|
|
Screen.DrawText(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
yy += 3;
|
|
}
|
|
if ( deathmatch )
|
|
{
|
|
yy += 9;
|
|
if ( playercount <= 1 ) return;
|
|
xx = int(ss.x-(margin+2));
|
|
String str;
|
|
Font fnt = LangFont(mTewiFont);
|
|
if ( teamplay )
|
|
{
|
|
// draw team scores
|
|
for ( int i=0; i<teamscore.Size(); i++ )
|
|
{
|
|
if ( !teamactive[i] ) continue;
|
|
str = String.Format("\cx%s \c-%d",Teams[i].mName,teamscore[i]);
|
|
Screen.DrawText(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// draw rank and spread like in UT
|
|
if ( tiedscore ) str = String.Format("\cx%s \cg%d\cr/\cg%d\c-",StringTable.Localize("$SWWM_DMRANK"),rank,playercount);
|
|
else str = String.Format("\cx%s \cj%d\cu/\cj%d\c-",StringTable.Localize("$SWWM_DMRANK"),rank,playercount);
|
|
Screen.DrawText(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
if ( lead > 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(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight()+3;
|
|
// draw top 3 players
|
|
for ( int i=0; i<min(3,playercount); i++ )
|
|
{
|
|
if ( sortplayers[i].fragcount < 0 ) str = String.Format("\cx#%d: \c-%s\c- \cr(\cg%d\cr)\c-",i+1,sortplayers[i].GetUserName(),sortplayers[i].fragcount);
|
|
else str = String.Format("\cx%s: \c-%s\c- \cu(\cj%d\cu)\c-",OrdinalStr(i+1,sortplayers[i].GetGender()),sortplayers[i].GetUserName(),sortplayers[i].fragcount);
|
|
Screen.DrawText(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += fnt.GetHeight();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
// draw key icons
|
|
Vector2 keypos = (ss.x-(margin+2),yy);
|
|
int colc = 0;
|
|
double colh = 0;
|
|
int n = Key.GetKeyTypeCount();
|
|
Array<Key> klist;
|
|
for ( int i=0; i<n; i++ )
|
|
{
|
|
let k = Key(CPlayer.mo.FindInventory(Key.GetKeyType(i)));
|
|
if ( !k || !k.Icon.IsValid() ) continue;
|
|
klist.Push(k);
|
|
}
|
|
// because we can't call GetReplacement from ui, let's wrangle something real ugly here to clean up replaced keys
|
|
for ( int i=0; i<klist.Size(); i++ )
|
|
{
|
|
if ( !(klist[i] is 'SWWMKey') ) continue;
|
|
// remove the key this replaces
|
|
Class<Key> pc = klist[i].Species;
|
|
if ( !pc ) continue;
|
|
for ( int j=0; j<klist.Size(); j++ )
|
|
{
|
|
if ( klist[j].GetClass() != pc ) continue;
|
|
klist.Delete(j);
|
|
j--;
|
|
if ( i >= j ) i--;
|
|
}
|
|
}
|
|
int maxcolc = (gameinfo.gametype&GAME_DOOMCHEX)?6:4;
|
|
for ( int i=0; i<klist.Size(); i++ )
|
|
{
|
|
let k = klist[i];
|
|
// Hexen key icons aren't meant for this kind of HUD
|
|
TextureID icon = (k is 'HexenKey')?k.SpawnState.GetSpriteTexture(0):k.Icon;
|
|
Vector2 siz = TexMan.GetScaledSize(icon);
|
|
Screen.DrawTexture(icon,false,keypos.x-siz.x,keypos.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_TopLeft,true);
|
|
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 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 = mTewiFont.mFont.StringWidth(nstr);
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,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 = mTewiFont.mFont.StringWidth(nstr);
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,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 = mTewiFont.mFont.StringWidth(nstr);
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,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 = mTewiFont.mFont.StringWidth(nstr);
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,nstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void DrawInventory()
|
|
{
|
|
// active items (armor / powerups)
|
|
double xx = margin+2;
|
|
double yy = ss.y-(margin+58);
|
|
if ( CPlayer.mo.InvSel && !isInventoryBarVisible() ) yy -= 34;
|
|
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) ) continue;
|
|
yy -= 34;
|
|
drewarmor = true;
|
|
}
|
|
yy = ss.y-(margin+58);
|
|
if ( drewarmor ) xx += 40;
|
|
else 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,aspowerup:true);
|
|
yy -= 34;
|
|
continue;
|
|
}
|
|
if ( (i is 'DivineSpriteEffect') && !DivineSpriteEffect(i).bHealDone )
|
|
{
|
|
DrawInvIcon(i,xx,yy,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<Inventory> 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);
|
|
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,ss.y-(margin+60),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
DrawInvIcon(CPlayer.mo.InvSel,margin+2,ss.y-(margin+58));
|
|
}
|
|
|
|
private void DrawWeapon()
|
|
{
|
|
if ( CPlayer.ReadyWeapon is 'SWWMWeapon' ) SWWMWeapon(CPlayer.ReadyWeapon).DrawWeapon(FracTic,ss.x-margin,ss.y-(margin+28),hs,ss);
|
|
else if ( CPlayer.ReadyWeapon )
|
|
{
|
|
// generic display
|
|
double xx = ss.x-(margin+13), yy = ss.y-(margin+42);
|
|
int maxlen = 0;
|
|
String astr2, astr1;
|
|
if ( CPlayer.ReadyWeapon.Ammo2 ) astr2 = String.Format("%d",CPlayer.ReadyWeapon.Ammo2.Amount);
|
|
if ( CPlayer.ReadyWeapon.Ammo1 ) astr1 = String.Format("%d",CPlayer.ReadyWeapon.Ammo1.Amount);
|
|
maxlen = max(astr1.Length(),astr2.Length());
|
|
if ( CPlayer.ReadyWeapon.Ammo2 && (CPlayer.ReadyWeapon.Ammo2 != CPlayer.ReadyWeapon.Ammo1) )
|
|
{
|
|
yy -= 14;
|
|
Screen.DrawTexture(GenericAmmoTex[2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
for ( int i=0; i<maxlen; i++ )
|
|
{
|
|
xx -= 6;
|
|
Screen.DrawTexture(GenericAmmoTex[1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
}
|
|
Screen.DrawTexture(GenericAmmoTex[0],false,xx-3,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,xx,yy,astr2,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy += 14;
|
|
}
|
|
xx = ss.x-(margin+13);
|
|
if ( CPlayer.ReadyWeapon.Ammo1 )
|
|
{
|
|
Screen.DrawTexture(GenericAmmoTex[2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
for ( int i=0; i<maxlen; i++ )
|
|
{
|
|
xx -= 6;
|
|
Screen.DrawTexture(GenericAmmoTex[1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
}
|
|
Screen.DrawTexture(GenericAmmoTex[0],false,xx-3,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,xx,yy,astr1,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
}
|
|
}
|
|
Screen.DrawTexture(WeaponTex,false,ss.x-(margin+60),ss.y-(margin+28),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
double xx = ss.x-(margin+57), yy = ss.y-(margin+28);
|
|
for ( int i=1; i<=10; i++ )
|
|
{
|
|
int ncolor = Font.CR_WHITE;
|
|
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 ( !CPlayer.HasWeaponsInSlot(i%10) ) ncolor = Font.CR_DARKGRAY;
|
|
else if ( hasgesture && hasgesture.formerweapon && (hasgesture.formerweapon.SlotNumber == (i%10)) ) ncolor = Font.CR_FIRE;
|
|
else if ( hasitemgesture && hasitemgesture.gest.formerweapon && (hasitemgesture.gest.formerweapon.SlotNumber == (i%10)) ) ncolor = Font.CR_FIRE;
|
|
else if ( CPlayer.PendingWeapon && (CPlayer.PendingWeapon != WP_NOCHANGE) && (CPlayer.PendingWeapon.SlotNumber == (i%10)) ) ncolor = Font.CR_FIRE;
|
|
else if ( (!CPlayer.PendingWeapon || (CPlayer.PendingWeapon == WP_NOCHANGE)) && CPlayer.ReadyWeapon && (CPlayer.ReadyWeapon.SlotNumber == (i%10)) ) ncolor = Font.CR_FIRE;
|
|
else
|
|
{
|
|
bool hasammo = false;
|
|
for ( Inventory inv=CPlayer.mo.Inv; inv; inv=inv.Inv )
|
|
{
|
|
bool dummy;
|
|
int slot;
|
|
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 = Font.CR_RED;
|
|
}
|
|
Screen.DrawText(mTewiFont.mFont,ncolor,xx,yy,String.Format("%d",(i%10)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
xx += 12;
|
|
if ( i == 5 )
|
|
{
|
|
xx = ss.x-(margin+57);
|
|
yy += 14;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawStatus()
|
|
{
|
|
Screen.DrawTexture(StatusTex,false,margin,ss.y-(margin+26),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
let d = Demolitionist(CPlayer.mo);
|
|
double dw = DashInter.GetValue();
|
|
double alph = .6;
|
|
if ( !d || (d.dashfuel > 20) || ((gametic%10) < 5) ) alph = 1.;
|
|
Screen.DrawTexture(DashTex,false,margin+2,ss.y-(margin+20),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,dw,DTA_Alpha,alph);
|
|
double fw = FuelInter.GetValue()/2.;
|
|
Screen.DrawTexture(FuelTex[swwm_superfuel],false,margin+2,ss.y-(margin+24),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,fw);
|
|
double ht = clamp(HealthInter.GetValue(),0,10000);
|
|
double hw = min(ht,100);
|
|
int hcolor = Font.CR_RED;
|
|
if ( ht > 500 ) hcolor = Font.CR_GOLD;
|
|
else if ( ht > 200 ) hcolor = Font.CR_PURPLE;
|
|
else if ( ht > 100 ) hcolor = Font.CR_CYAN;
|
|
if ( isInvulnerable() || CPlayer.mo.FindInventory("InvinciballPower") )
|
|
{
|
|
Screen.DrawTexture(HealthTex[4],false,margin+2,ss.y-(margin+14),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,hw);
|
|
hcolor = Font.CR_WHITE;
|
|
}
|
|
else
|
|
{
|
|
Screen.DrawTexture(HealthTex[0],false,margin+2,ss.y-(margin+14),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,ss.y-(margin+14),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,ss.y-(margin+14),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,ss.y-(margin+14),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,ss.y-(margin+14),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 <= 1.; alph += .1 )
|
|
{
|
|
tst = "AAA";
|
|
SWWMUtility.ObscureText(tst,(gametic-trl)/3);
|
|
trl--;
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,margin+108,ss.y-(margin+15),tst,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,falph*alph,DTA_LegacyRenderStyle,STYLE_Add);
|
|
}
|
|
Screen.DrawText(mTewiFont.mFont,hcolor,margin+108,ss.y-(margin+15),String.Format("%3d",clamp(ht,0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,1.-falph);
|
|
}
|
|
else Screen.DrawText(mTewiFont.mFont,hcolor,margin+108,ss.y-(margin+15),String.Format("%3d",clamp(ht,0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
}
|
|
|
|
private void DrawPickups()
|
|
{
|
|
Font fnt = LangFont(mTewiFont);
|
|
int h = fnt.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(25*clamp(hnd.bossalpha*2.,0.,1.));
|
|
int len = fnt.StringWidth(ntagstr);
|
|
double xx = (ss.x-len)/2.;
|
|
Screen.Dim("Black",.8*nalph,int((xx-6)*hs.x),int(yy*hs.y),int((len+12)*hs.x),int((h+4)*hs.y));
|
|
Screen.DrawText(fnt,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()-swwm_maxpickup);
|
|
yy = ss.y-(margin+50);
|
|
// shift up if boss healthbar is present
|
|
if ( hnd && (hnd.bossalpha > 0.) ) yy -= int(25*clamp(hnd.bossalpha*2.,0.,1.));
|
|
// shift up again if nametag is present
|
|
if ( nalph > 0. ) yy -= int((fnt.GetHeight()+6)*clamp(nalph*2.,0.,1.));
|
|
for ( int i=PickupQueue.Size()-1; i>=mend; i-- )
|
|
{
|
|
String cstr = PickupQueue[i].str;
|
|
if ( PickupQueue[i].rep > 1 ) cstr.AppendFormat(" (x%d)",PickupQueue[i].rep);
|
|
double curtime = (PickupQueue[i].tic+35*swwm_pickduration)-(level.totaltime+fractic);
|
|
double alph = clamp(curtime/20.,0.,1.);
|
|
BrokenLines l = fnt.BreakLines(cstr,int(ss.x*.75));
|
|
int maxlen = 0;
|
|
for ( int j=0; j<l.Count(); j++ )
|
|
{
|
|
int len = fnt.StringWidth(l.StringAt(j));
|
|
if ( len > maxlen ) maxlen = len;
|
|
}
|
|
double xx = (ss.x-maxlen)/2.;
|
|
Screen.Dim("Black",.8*alph,int((xx-6)*hs.x),int((yy-h*(l.Count()-1))*hs.y),int((maxlen+12)*hs.x),int((h*l.Count()+4)*hs.y));
|
|
for ( int j=l.Count()-1; j>=0; j-- )
|
|
{
|
|
int len = fnt.StringWidth(l.StringAt(j));
|
|
xx = int((ss.x-len)/2.);
|
|
Screen.DrawText(fnt,msg0color,xx,yy+2,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
yy -= h;
|
|
}
|
|
l.Destroy();
|
|
yy -= 6;
|
|
}
|
|
}
|
|
|
|
private void DrawMessages( double boxalph = 1. )
|
|
{
|
|
Font fnt = LangFont(mTewiFont);
|
|
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.);
|
|
BrokenLines l = fnt.BreakLines(midstr,int(ss.x*ssp));
|
|
int h = fnt.GetHeight();
|
|
int maxlen = 0;
|
|
for ( int i=0; i<l.Count(); i++ ) maxlen = max(maxlen,fnt.StringWidth(l.StringAt(i)));
|
|
xx = int((ss.x*ssp-maxlen)/2.);
|
|
yy = ss.y*ssp*.375;
|
|
yy -= (h*l.Count()+4)/2; // center
|
|
Screen.Dim("Black",.8*alph,int((xx-6)*hs.x*hsp),int(yy*hs.y*hsp),int((maxlen+12)*hs.x*hsp),int((h*l.Count()+4)*hs.y*hsp));
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
{
|
|
int len = fnt.StringWidth(l.StringAt(i));
|
|
xx = int((ss.x*ssp-len)/2.);
|
|
Screen.DrawText(fnt,col,int(xx),yy+2,l.StringAt(i),DTA_VirtualWidthF,ss.x*ssp,DTA_VirtualHeightF,ss.y*ssp,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
yy += h;
|
|
}
|
|
l.Destroy();
|
|
}
|
|
if ( MainQueue.Size() <= 0 ) return;
|
|
int mstart = max(0,MainQueue.Size()-((chatopen>=gametic)?swwm_maxshownbig:swwm_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++;
|
|
for ( int i=mstart; i<MainQueue.Size(); i++ )
|
|
{
|
|
int col = msg2color;
|
|
if ( MainQueue[i].type == PRINT_MEDIUM ) col = msg1color;
|
|
else if ( MainQueue[i].type == PRINT_CHAT ) col = msg3color;
|
|
else if ( MainQueue[i].type == PRINT_TEAMCHAT ) col = msg4color;
|
|
String cstr = MainQueue[i].str;
|
|
if ( MainQueue[i].rep > 1 ) cstr.AppendFormat(" (x%d)",MainQueue[i].rep);
|
|
double curtime = MainQueue[i].tic-(level.totaltime+fractic);
|
|
if ( MainQueue[i].type < PRINT_CHAT ) curtime += GameTicRate*swwm_msgduration;
|
|
else curtime += GameTicRate*swwm_chatduration;
|
|
double alph = clamp(curtime/20.,0.,1.);
|
|
BrokenLines l = fnt.BreakLines(cstr,smol?211:361);
|
|
for ( int j=0; j<l.Count(); j++ )
|
|
{
|
|
Screen.DrawTexture(ChatTex[smol?4:1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,boxalph);
|
|
Screen.DrawText(fnt,col,xx+4,yy,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
yy += 13;
|
|
}
|
|
l.Destroy();
|
|
}
|
|
Screen.DrawTexture(ChatTex[smol?5:2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,boxalph);
|
|
}
|
|
|
|
override bool DrawChat( String txt )
|
|
{
|
|
// ignore during intermission
|
|
if ( gamestate != GS_LEVEL ) return false;
|
|
chatopen = gametic+1; // have to add 1 because DrawChat is called after everything else
|
|
double xx = 2;
|
|
double yy = ss.y-14;
|
|
Screen.Dim("Black",.8,0,Screen.GetHeight()-int(15*hs.y),Screen.GetWidth(),int(15*hs.y));
|
|
String pname = players[consoleplayer].GetUserName();
|
|
// strip colors
|
|
SWWMUtility.StripColor(pname);
|
|
String fullstr = String.Format("\cq%s\cd@\cqdemolitionist%d\cn ~ \c-wall %s_",pname,consoleplayer+1,txt);
|
|
Font fnt = LangFont(mTewiFont);
|
|
// cut out to fit
|
|
int w = fnt.StringWidth(fullstr);
|
|
if ( w > ss.x-4 )
|
|
{
|
|
// draw trailing dots
|
|
Screen.DrawText(fnt,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(fnt,Font.CR_WHITE,xx,yy,fullstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ClipLeft,int(26*hs.x));
|
|
}
|
|
else Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,fullstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
return true;
|
|
}
|
|
|
|
override bool DrawPaused( int player )
|
|
{
|
|
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());
|
|
Screen.DrawTexture(PauseTex,false,Screen.GetWidth()/2,Screen.GetHeight()/2,DTA_CleanNoMove,true,DTA_CenterOffset,true);
|
|
if ( multiplayer && (player != -1) )
|
|
{
|
|
Font fnt = LangFont(mTewiFont);
|
|
String str = String.Format(StringTable.Localize("$TXT_BY"),players[player].GetUserName());
|
|
Vector2 sz = TexMan.GetScaledSize(PauseTex);
|
|
double xx = (Screen.GetWidth()-fnt.StringWidth(str)*CleanXFac)/2;
|
|
double yy = (Screen.GetHeight()+(sz.y+4)*CleanYFac)/2;
|
|
Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,str,DTA_CleanNoMove,true);
|
|
}
|
|
// TODO draw something extra to make the screen more visually interesting, maybe
|
|
return true;
|
|
}
|
|
|
|
override void DrawPowerups()
|
|
{
|
|
// don't do anything
|
|
}
|
|
|
|
private double DrawDeath()
|
|
{
|
|
// death prompt
|
|
let demo = Demolitionist(CPlayer.mo);
|
|
let goner = PlayerGone(CPlayer.mo);
|
|
if ( (!demo && !goner) || (CPlayer.Health > 0) || (CPlayer != players[consoleplayer]) ) return 1.;
|
|
String str;
|
|
double alph;
|
|
int len;
|
|
double xx, yy;
|
|
Font fnt;
|
|
double deadtimer = (goner?goner.deadtimer:demo.deadtimer)+fractic;
|
|
if ( goner || (demo.player.viewheight <= 6) )
|
|
{
|
|
double dimalph = goner?1.:min(deadtimer/80.,1.);
|
|
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");
|
|
fnt = LangFont(mTewiFont);
|
|
len = fnt.StringWidth(str);
|
|
xx = int((ss.x-len)/2.);
|
|
yy = ss.y-48;
|
|
if ( ((demo.revivefail-level.maptime)%16) < 8 )
|
|
Screen.DrawText(fnt,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);
|
|
fnt = LangFont(mTewiFont);
|
|
len = fnt.StringWidth(str);
|
|
xx = int((ss.x-len)/2.);
|
|
yy = (ss.y-fnt.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.+fnt.GetHeight();
|
|
Screen.DrawText(fnt,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"));
|
|
fnt = LangFont(mTewiFont);
|
|
len = fnt.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(fnt,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"));
|
|
fnt = LangFont(mTewiFont);
|
|
len = fnt.StringWidth(str);
|
|
xx = int((ss.x-len)/2.);
|
|
yy = ss.y/2.;
|
|
Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
if ( goner || !swwm_revive )
|
|
return (1.-dimalph);
|
|
alph = clamp((deadtimer-160)/60.,0.,1.);
|
|
str = String.Format(StringTable.Localize("$SWWM_URDED3"));
|
|
fnt = LangFont(mTewiFont);
|
|
len = fnt.StringWidth(str);
|
|
xx = int((ss.x-len)/2.);
|
|
yy = (ss.y+fnt.GetHeight()*2)/2.;
|
|
Screen.DrawText(fnt,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);
|
|
int CurFrame = MSTime();
|
|
FrameTime = (CurFrame-PrevFrame)/1000.;
|
|
if ( (state != HUD_StatusBar) && (state != HUD_Fullscreen) )
|
|
{
|
|
PrevFrame = CurFrame;
|
|
return;
|
|
}
|
|
if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
|
|
if ( !swwm_camhud && !(players[consoleplayer].Camera is 'PlayerPawn') )
|
|
camhidden = true;
|
|
else camhidden = false;
|
|
BeginHUD();
|
|
if ( swwm_hudscale <= 0 ) hs = GetHUDScale();
|
|
else hs.x = swwm_hudscale;
|
|
hs.y = hs.x;
|
|
ss = (Screen.GetWidth()/hs.x,Screen.GetHeight()/hs.y);
|
|
margin = clamp(swwm_hudmargin,0,40);
|
|
if ( swwm_barscale <= 0 ) hsb = GetHUDScale();
|
|
else hsb.x = swwm_barscale;
|
|
hsb.y = hsb.x;
|
|
ssb = (Screen.GetWidth()/hsb.x,Screen.GetHeight()/hsb.y);
|
|
if ( swwm_numscale <= 0 ) hsn = GetHUDScale();
|
|
else hsn.x = swwm_numscale;
|
|
hsn.y = hsn.x;
|
|
ssn = (Screen.GetWidth()/hsn.x,Screen.GetHeight()/hsn.y);
|
|
if ( swwm_scrscale <= 0 ) hss = GetHUDScale();
|
|
else hss.x = swwm_scrscale;
|
|
hss.y = hss.x;
|
|
sss = (Screen.GetWidth()/hss.x,Screen.GetHeight()/hss.y);
|
|
if ( swwm_poiscale <= 0 ) hsi = GetHUDScale();
|
|
else hsi.x = swwm_poiscale;
|
|
hsi.y = hsi.x;
|
|
ssi = (Screen.GetWidth()/hsi.x,Screen.GetHeight()/hsi.y);
|
|
if ( swwm_detscale <= 0 ) hsd = GetHUDScale();
|
|
else hsd.x = swwm_detscale;
|
|
hsd.y = hsd.x;
|
|
ssd = (Screen.GetWidth()/hsd.x,Screen.GetHeight()/hsd.y);
|
|
FracTic = TicFrac;
|
|
if ( camhidden )
|
|
{
|
|
if ( hnd ) hnd.DrawBossBar(self);
|
|
DrawPickups();
|
|
DrawDeath();
|
|
DrawMessages(0.);
|
|
}
|
|
else
|
|
{
|
|
DrawTarget();
|
|
DrawScore();
|
|
DrawInventory();
|
|
DrawStatus();
|
|
DrawWeapon();
|
|
if ( hnd ) hnd.DrawBossBar(self);
|
|
DrawPickups();
|
|
double malph = DrawDeath();
|
|
DrawMessages(malph);
|
|
}
|
|
PrevFrame = CurFrame;
|
|
}
|
|
}
|