swwmgz_m/zscript/kbase/swwm_kbasetab_chat.zsc

223 lines
6.7 KiB
Text

// all them messages
Class DemolitionistChatTab : DemolitionistMenuTab
{
DemolitionistMenuList msglist;
int ofs, maxofs;
double smofs;
bool drag;
SWWMFullHistory hist;
override DemolitionistMenuTab Init( DemolitionistMenu master )
{
title = StringTable.Localize("$SWWM_CHATTAB");
hist = SWWMFullHistory.Get();
return Super.Init(master);
}
override void OnDestroy()
{
Super.OnDestroy();
if ( msglist ) msglist.Destroy();
}
override void OnSelect()
{
smofs = ofs;
}
override void OnDeselect()
{
smofs = ofs;
}
override void Ticker()
{
if ( !hist ) return;
int ypos = 0;
bool recenter = true;
if ( !msglist )
{
msglist = new("DemolitionistMenuList");
msglist.master = master;
msglist.selected = -1;
msglist.items.Resize(hist.msg.Size());
for ( int i=0; i<hist.msg.Size(); i++ )
{
msglist.items[i] = new("DemolitionistMenuChatItem").Init(master,hist.msg[i]);
msglist.items[i].ypos = ypos;
ypos += msglist.items[i].GetHeight();
}
}
else if ( msglist.items.Size() < hist.msg.Size() )
{
// theoretically we can assume that the message list will never shrink in the middle of gameplay, only grow
// also the array only ever has elements pushed, never inserted in-between
// if this somehow breaks, I don't know what the hell can do that
msglist.items.Resize(hist.msg.Size());
for ( int i=0; i<hist.msg.Size(); i++ )
{
if ( !msglist.items[i] )
{
msglist.items[i] = new("DemolitionistMenuChatItem").Init(master,hist.msg[i]);
msglist.items[i].ypos = ypos;
}
ypos += msglist.items[i].GetHeight();
}
if ( ofs < maxofs ) recenter = false; // don't recenter if we weren't at the bottom
}
else recenter = false;
maxofs = max(ypos-int(master.ws.y-46),0);
// push it to the bottom
if ( recenter ) ofs = maxofs;
// update smooth scroll
smofs = (smofs*.6)+(ofs*.4);
if ( abs(smofs-ofs) < (1./master.hs) ) smofs = ofs;
// tick the list (not really needed, as elements don't dynamically update anything)
msglist.Ticker();
}
// called when sending a scroll input
// returns true if the position actually changed
// speed: how many pixels to move (either back or forward)
bool Scroll( int speed )
{
if ( maxofs <= 0 ) return false;
int oldofs = ofs;
ofs = clamp(ofs+speed,0,maxofs);
return (ofs != oldofs);
}
// called when clicking on our scrollbar
// returns true if the position actually changed
// y: relative click position
bool SetOffset( double y )
{
if ( maxofs <= 0 ) return false;
int oldofs = ofs;
ofs = clamp(int(round((y-20.5)/((master.ws.y-41.)/maxofs))),0,maxofs);
return (ofs != oldofs);
}
override void MenuInput( int key )
{
if ( maxofs <= 0 ) return;
switch ( key )
{
case MK_DOWN:
if ( Scroll(16) ) master.MenuSound("menu/demoscroll");
break;
case MK_UP:
if ( Scroll(-16) ) master.MenuSound("menu/demoscroll");
break;
}
}
override void MouseInput( Vector2 pos, int btn )
{
if ( maxofs <= 0 ) return;
switch ( btn )
{
case MB_LEFT:
// see if we're clicking the scrollbar (if it exists)
if ( pos.x > (master.ws.x-8) )
{
SetOffset(pos.y);
master.MenuSound("menu/demoscroll");
drag = true;
}
break;
case MB_WHEELUP:
if ( Scroll(-8) ) master.MenuSound("menu/demoscroll");
break;
case MB_WHEELDOWN:
if ( Scroll(8) ) master.MenuSound("menu/demoscroll");
break;
case MB_DRAG:
if ( drag ) SetOffset(pos.y);
break;
case MB_RELEASE:
drag = false;
break;
}
}
override void Drawer()
{
if ( !hist || (msglist.items.Size() <= 0) )
{
String str = StringTable.Localize("$SWWM_NOCHAT");
double xx = int(master.ws.x-master.mSmallFont.StringWidth(str))/2;
double yy = int(master.ws.y-master.mSmallFont.GetHeight())/2;
Screen.DrawText(master.mSmallFont,Font.CR_FIRE,master.origin.x+xx,master.origin.y+yy,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
return;
}
double xx = 3;
double yy = 23;
int cliptop = int((master.origin.y+23)*master.hs);
int clipbottom = int((master.origin.y+master.ws.y-23)*master.hs);
int clipleft = int((master.origin.x+3)*master.hs);
int clipright = int((master.origin.x+master.ws.x-9)*master.hs);
msglist.Drawer((xx,yy-smofs),cliptop,clipbottom,clipleft,clipright);
if ( maxofs <= 0 ) return;
xx = master.ws.x-8;
master.DrawVSeparator(xx,14,master.ws.y-28);
xx += 2;
yy = floor(smofs*((master.ws.y-39)/maxofs))+14;
Screen.DrawText(master.mSmallFont,Font.CR_FIRE,master.origin.x+xx,master.origin.y+yy,"▮",DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
}
}
// chat message item
Class DemolitionistMenuChatItem : DemolitionistMenuListItem
{
BrokenLines l;
int margin;
String tstamp;
DemolitionistMenuChatItem Init( DemolitionistMenu master, MsgLine m )
{
Super.Init(master,"");
if ( m.type == -1 )
{
// map change marker
label = String.Format("\cx[\c-%s\cx]\c-",m.str);
return self;
}
// actually use crimetime for the timestamps, for immersion
int rtime = (m.tic/GameTicRate)+(master.c_minute*60)+(master.c_hour*3600);
int thour = (rtime/3600)%24;
int tmin = (rtime/60)%60;
int tsec = rtime%60;
tstamp = String.Format("\cm[\c-%02d\cm:\c-%02d\cm:\c-%02d\cm]\c- ",thour,tmin,tsec);
margin = master.mSmallFont.StringWidth(tstamp);
l = master.mSmallFont.BreakLines(m.str,int(master.ws.x-14)-margin);
return self;
}
override void OnDestroy()
{
Super.OnDestroy();
if ( l ) l.Destroy();
}
override int GetWidth()
{
return int(master.ws.x-14);
}
override int GetHeight()
{
if ( l ) return l.Count()*14;
return 14;
}
override void Drawer( Vector2 pos, bool selected, int cliptop, int clipbottom, int clipleft, int clipright )
{
if ( !l )
{
// we'll assume this is a level change label
double xx = int((master.ws.x-14)-master.mSmallFont.StringWidth(label))/2;
Screen.DrawText(master.mSmallFont,Font.CR_GOLD,master.origin.x+pos.x+xx,master.origin.y+pos.y,label,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
return;
}
Screen.DrawText(master.mSmallFont,Font.CR_DARKGRAY,master.origin.x+pos.x,master.origin.y+pos.y,tstamp,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
for ( int i=0; i<l.Count(); i++ )
Screen.DrawText(master.mSmallFont,Font.CR_WHITE,master.origin.x+pos.x+margin,master.origin.y+pos.y+i*14,l.StringAt(i),DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright);
}
}