swwmgz_m/zscript/kbase/swwm_kbasetab_keychain.zsc
Marisa the Magician 80db58b0d0 Bump zscript ver to 4.14.1, plus a whole lot of stuff.
- Try to get rid of all implicit casts from string to name, color or class.
 - Use FindClass where needed.
 - Used a map in a case where a dictionary was unneeded.
 - Use new bounce flags where needed.
 - Replace Legacy of Rust weapons/ammo.
2025-03-13 14:50:58 +01:00

320 lines
8.4 KiB
Text

// the keychain
Class DemolitionistKeychainTab : DemolitionistMenuTab
{
DemolitionistMenuList invlist;
int ofs, maxofs;
double smofs;
bool drag;
private bool CmpCollectible( Inventory a, Inventory b )
{
int ta = 0, tb = 0;
if ( a is 'Key' ) ta = 1;
if ( b is 'Key' ) tb = 1;
if ( ta == tb )
{
if ( a is 'Key' )
{
// sort by "index"
int n = Key.GetKeyTypeCount();
int ida = -1, idb = -1;
for ( int i=0; i<n; i++ )
{
let k = Key.GetKeyType(i);
if ( (ida == -1) && ((a is k) || (a.species == k.GetClassName())) )
ida = i;
if ( (idb == -1) && ((b is k) || (b.species == k.GetClassName())) )
idb = i;
}
return ida > idb;
}
// collectible
if ( a.Stamina == b.Stamina )
{
// alphabetic
return a.GetTag() > b.GetTag();
}
// descending value
return a.default.Stamina < b.default.Stamina;
}
return ta > tb;
}
private int partition_collectible( Array<DemolitionistMenuListItem> a, int l, int h )
{
DemolitionistMenuListItem pv = a[h];
int i = (l-1);
for ( int j=l; j<=(h-1); j++ )
{
if ( CmpCollectible(DemolitionistMenuInvItem(pv).inv,DemolitionistMenuInvItem(a[j]).inv) )
{
i++;
DemolitionistMenuListItem tmp = a[j];
a[j] = a[i];
a[i] = tmp;
}
}
DemolitionistMenuListItem tmp = a[h];
a[h] = a[i+1];
a[i+1] = tmp;
return i+1;
}
private void qsort_collectible( Array<DemolitionistMenuListItem> a, int l, int h )
{
if ( l >= h ) return;
int p = partition_collectible(a,l,h);
qsort_collectible(a,l,p-1);
qsort_collectible(a,p+1,h);
}
override DemolitionistMenuTab Init( DemolitionistMenu master )
{
title = StringTable.Localize("$SWWM_KEYTAB");
bHidden = deathmatch;
return Super.Init(master);
}
override void OnDestroy()
{
Super.OnDestroy();
if ( invlist ) invlist.Destroy();
}
override void OnSelect()
{
smofs = ofs;
}
override void OnDeselect()
{
smofs = ofs;
}
private bool FilterInventory( Inventory inv )
{
if ( !inv || (inv.Owner != players[consoleplayer].mo) ) return true;
if ( !(inv is 'Key') && !(inv is 'SWWMCollectible') ) return true;
return false;
}
override void Ticker()
{
bool mustsort = false;
bool skipsel = false;
if ( !invlist )
{
mustsort = true;
skipsel = true;
// initialize
invlist = new('DemolitionistMenuList');
invlist.master = master;
invlist.selected = 0;
int j = 0;
for ( Inventory i=players[consoleplayer].mo.inv; i; i=i.inv )
{
if ( FilterInventory(i) ) continue;
invlist.items.Push(new('DemolitionistMenuInvItem').Init(master,i));
}
}
else
{
// check if current entries must be deleted
for ( int i=0; i<invlist.items.Size(); i++ )
{
if ( !FilterInventory(DemolitionistMenuInvItem(invlist.items[i]).inv) ) continue;
invlist.items[i].Destroy();
invlist.items.Delete(i);
if ( invlist.selected > i ) invlist.selected = max(0,invlist.selected-1);
i--;
}
// check if new entries must be added
for ( Inventory i=players[consoleplayer].mo.inv; i; i=i.inv )
{
if ( FilterInventory(i) ) continue;
// skip if it's already there
bool skipme = false;
for ( int j=0; j<invlist.items.Size(); j++ )
{
if ( DemolitionistMenuInvItem(invlist.items[j]).inv != i ) continue;
skipme = true;
break;
}
if ( skipme ) continue;
invlist.items.Push(new('DemolitionistMenuInvItem').Init(master,i));
mustsort = true;
}
}
// don't do anything if empty
if ( invlist.items.Size() <= 0 ) return;
// sort inventory
if ( mustsort )
{
DemolitionistMenuListItem csel = invlist.items[invlist.selected];
qsort_collectible(invlist.items,0,invlist.items.Size()-1);
let idx = invlist.items.Find(csel);
if ( !skipsel && (idx != invlist.items.Size()) && (idx != invlist.selected) )
invlist.selected = idx;
}
// rearrange all item positions
maxofs = 0;
int maxw = invlist.GetWidth();
int xx = 0;
int yy = 0;
for ( int i=0; i<invlist.items.Size(); i++ )
{
maxofs = max(maxofs,int(xx+invlist.items[i].GetWidth()));
invlist.items[i].xpos = xx;
invlist.items[i].ypos = yy;
yy += 16;
if ( yy > (master.ws.y-62) )
{
xx += maxw+16; // pad
yy = 0;
}
}
maxofs = max(0,maxofs-int(master.ws.x-18));
if ( ofs > maxofs ) smofs = ofs = maxofs;
// update smooth scroll
smofs = (smofs*.6)+(ofs*.4);
if ( abs(smofs-ofs) < (1./master.hs) ) smofs = ofs;
// tick the list
invlist.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
// x: relative click position
bool SetOffset( double x )
{
if ( maxofs <= 0 ) return false;
int oldofs = ofs;
ofs = clamp(int(round((x-5.)/((master.ws.x-10.)/maxofs))),0,maxofs);
return (ofs != oldofs);
}
// called when keyboard scrolling
void KBScroll()
{
if ( maxofs <= 0 ) return;
int minx = (invlist.items[invlist.selected].xpos+invlist.items[invlist.selected].GetWidth())-int(master.ws.x-18);
int maxx = invlist.items[invlist.selected].xpos;
if ( ofs < minx ) ofs = clamp(minx,0,maxofs);
else if ( ofs > maxx ) ofs = clamp(maxx,0,maxofs);
}
override void MenuInput( int key )
{
if ( !invlist || (invlist.items.Size() <= 0) ) return;
switch ( key )
{
case MK_LEFT:
int prev = max(0,invlist.selected-22);
if ( prev == invlist.selected ) break;
invlist.selected = prev;
master.MenuSound("menu/demoscroll");
KBScroll();
break;
case MK_RIGHT:
int next = min(invlist.items.Size()-1,invlist.selected+22);
if ( next == invlist.selected ) break;
invlist.selected = next;
master.MenuSound("menu/demoscroll");
KBScroll();
break;
case MK_DOWN:
if ( invlist.selected < invlist.items.Size()-1 )
{
invlist.selected++;
master.MenuSound("menu/demoscroll");
KBScroll();
}
break;
case MK_UP:
if ( invlist.selected > 0 )
{
invlist.selected--;
master.MenuSound("menu/demoscroll");
KBScroll();
}
break;
case MK_ENTER:
if ( invlist.selected >= invlist.items.Size() ) break;
DemolitionistMenuInvItem(invlist.items[invlist.selected]).UseItem();
break;
}
}
override void MouseInput( Vector2 pos, int btn )
{
if ( !invlist || (invlist.items.Size() <= 0) ) return;
switch ( btn )
{
case MB_LEFT:
// see if we're clicking the scrollbar (if it exists)
if ( pos.y > (master.ws.y-21) )
{
if ( SetOffset(pos.x) )
{
master.MenuSound("menu/demoscroll");
drag = true;
}
break;
}
// find which element we clicked
for ( int i=0; i<invlist.items.Size(); i++ )
{
if ( !invlist.items[i].CheckBounds((pos.x-9)+smofs,pos.y-23) )
continue;
invlist.selected = i;
KBScroll();
// use it
MenuInput(MK_ENTER);
break;
}
break;
case MB_WHEELUP:
if ( Scroll(-invlist.GetWidth()/16) ) master.MenuSound("menu/demoscroll");
break;
case MB_WHEELDOWN:
if ( Scroll(invlist.GetWidth()/16) ) master.MenuSound("menu/demoscroll");
break;
case MB_DRAG:
if ( drag ) SetOffset(pos.x);
break;
case MB_RELEASE:
drag = false;
break;
}
}
override void Drawer( double fractic )
{
if ( !invlist || (invlist.items.Size() <= 0) )
{
String str = StringTable.Localize("$SWWM_NOKEYS");
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 = 9;
double yy = 23;
Screen.SetClipRect(int((master.origin.x+9)*master.hs),int((master.origin.y+23)*master.hs),int((master.ws.x-18)*master.hs),int((master.ws.y-46)*master.hs));
invlist.Drawer((xx-ssmofs,yy));
Screen.ClearClipRect();
if ( maxofs <= 0 ) return;
yy = master.ws.y-21;
master.DrawHSeparator(0,yy,master.ws.x);
yy -= 4;
xx = floor(ssmofs*((master.ws.x-10)/maxofs))+2;
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);
}
}