// all them messages Class DemolitionistChatTab : DemolitionistMenuTab { DemolitionistMenuList msglist; int ofs, maxofs; double smofs; bool drag; bool justopened; SWWMFullHistory hist; override DemolitionistMenuTab Init( DemolitionistMenu master ) { title = StringTable.Localize("$SWWM_CHATTAB"); hist = SWWMFullHistory.Get(); justopened = true; return Super.Init(master); } override void OnDestroy() { Super.OnDestroy(); if ( msglist ) msglist.Destroy(); } override void OnSelect() { smofs = ofs; justopened = true; } 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 (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( double fractic ) { 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 ssmofs = (smofs~==ofs)?smofs:(smofs*(1.-fractic)+((smofs*.6)+(ofs*.4))*fractic); double xx = 3; double yy = 23; Screen.SetClipRect(int((master.origin.x+3)*master.hs),int((master.origin.y+23)*master.hs),int((master.ws.x-12)*master.hs),int((master.ws.y-46)*master.hs)); msglist.Drawer((xx,yy-ssmofs)); Screen.ClearClipRect(); if ( maxofs <= 0 ) return; xx = master.ws.x-8; master.DrawVSeparator(xx,14,master.ws.y-28); xx += 2; yy = floor(ssmofs*((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 ) { 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); 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); for ( int i=0; i