X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fmenu%2Fxonotic%2Fserverlist.c;h=69f5d47374e32fde63deb1663901505c552c5b01;hb=60f5e26be58f996cf0262de7dd92be8166e11af8;hp=23e4797679cdd1cb6cb6bfd529e79e5b95f4f32e;hpb=71a090654873ac80061b87696d8437ec94327b15;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/menu/xonotic/serverlist.c b/qcsrc/menu/xonotic/serverlist.c index 23e479767..69f5d4737 100644 --- a/qcsrc/menu/xonotic/serverlist.c +++ b/qcsrc/menu/xonotic/serverlist.c @@ -49,7 +49,6 @@ CLASS(XonoticServerList) EXTENDS(XonoticListBox) ATTRIB(XonoticServerList, infoButton, entity, NULL) ATTRIB(XonoticServerList, currentSortOrder, float, 0) ATTRIB(XonoticServerList, currentSortField, float, -1) - ATTRIB(XonoticServerList, lastBumpSelectTime, float, 0) ATTRIB(XonoticServerList, lastClickedServer, float, -1) ATTRIB(XonoticServerList, lastClickedTime, float, 0) @@ -57,18 +56,25 @@ CLASS(XonoticServerList) EXTENDS(XonoticListBox) ATTRIB(XonoticServerList, seenIPv4, float, 0) ATTRIB(XonoticServerList, seenIPv6, float, 0) + ATTRIB(XonoticServerList, categoriesHeight, float, 1.25) + + METHOD(XonoticServerList, getTotalHeight, float(entity)) + METHOD(XonoticServerList, getItemAtPos, float(entity, float)) + METHOD(XonoticServerList, getItemStart, float(entity, float)) + METHOD(XonoticServerList, getItemHeight, float(entity, float)) ENDCLASS(XonoticServerList) entity makeXonoticServerList(); #ifndef IMPLEMENTATION -var float autocvar_menu_slist_categories = TRUE; -var float autocvar_menu_slist_categories_onlyifmultiple = TRUE; -var float autocvar_menu_slist_purethreshold = 10; -var float autocvar_menu_slist_recommendations = 2; -var float autocvar_menu_slist_recommendations_minfreeslots = 1; -var float autocvar_menu_slist_recommendations_minhumans = 1; -var float autocvar_menu_slist_recommendations_maxping = 150; -//var string autocvar_menu_slist_recommended = "76.124.107.5:26004"; +float autocvar_menu_slist_categories; +float autocvar_menu_slist_categories_onlyifmultiple; +float autocvar_menu_slist_purethreshold; +float autocvar_menu_slist_modimpurity; +float autocvar_menu_slist_recommendations; +float autocvar_menu_slist_recommendations_maxping; +float autocvar_menu_slist_recommendations_minfreeslots; +float autocvar_menu_slist_recommendations_minhumans; +float autocvar_menu_slist_recommendations_purethreshold; // server cache fields #define SLIST_FIELDS \ @@ -99,12 +105,13 @@ const float REFRESHSERVERLIST_ASK = 2; // ..., also suggest querying serve const float REFRESHSERVERLIST_RESET = 3; // ..., also clear the list first // function declarations -entity RetrieveCategoryEnt(float catnum); - float IsServerInList(string list, string srv); #define IsFavorite(srv) IsServerInList(cvar_string("net_slist_favorites"), srv) +#define IsPromoted(srv) IsServerInList(_Nex_ExtResponseSystem_PromotedServers, srv) #define IsRecommended(srv) IsServerInList(_Nex_ExtResponseSystem_RecommendedServers, srv) +entity RetrieveCategoryEnt(float catnum); + float CheckCategoryOverride(float cat); float CheckCategoryForEntry(float entry); float m_gethostcachecategory(float entry) { return CheckCategoryOverride(CheckCategoryForEntry(entry)); } @@ -292,8 +299,7 @@ float CheckCategoryForEntry(float entry) } } - if(impure > autocvar_menu_slist_purethreshold) { impure = TRUE; } - else { impure = FALSE; } + if(modtype != "xonotic") { impure += autocvar_menu_slist_modimpurity; } // check if this server is favorited if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, entry)) { return CAT_FAVORITED; } @@ -301,36 +307,50 @@ float CheckCategoryForEntry(float entry) // now check if it's recommended if(autocvar_menu_slist_recommendations) { - float recommended = 0; - if(autocvar_menu_slist_recommendations & 1) - { - if(IsRecommended(gethostcachestring(SLIST_FIELD_CNAME, entry))) - { ++recommended; } - else - { --recommended; } - } - if(autocvar_menu_slist_recommendations & 2) + string cname = gethostcachestring(SLIST_FIELD_CNAME, entry); + + if(IsPromoted(cname)) { return CAT_RECOMMENDED; } + else { - if( - (freeslots >= autocvar_menu_slist_recommendations_minfreeslots) - && - ( - gethostcachenumber(SLIST_FIELD_NUMHUMANS, entry) - >= - autocvar_menu_slist_recommendations_minhumans - ) - && - ( - gethostcachenumber(SLIST_FIELD_PING, entry) - <= - autocvar_menu_slist_recommendations_maxping + float recommended = 0; + if(autocvar_menu_slist_recommendations & 1) + { + if(IsRecommended(cname)) { ++recommended; } + else { --recommended; } + } + if(autocvar_menu_slist_recommendations & 2) + { + if( + ///// check for minimum free slots + (freeslots >= autocvar_menu_slist_recommendations_minfreeslots) + + && // check for purity requirement + ( + (autocvar_menu_slist_recommendations_purethreshold < 0) + || + (impure <= autocvar_menu_slist_recommendations_purethreshold) + ) + + && // check for minimum amount of humans + ( + gethostcachenumber(SLIST_FIELD_NUMHUMANS, entry) + >= + autocvar_menu_slist_recommendations_minhumans + ) + + && // check for maximum latency + ( + gethostcachenumber(SLIST_FIELD_PING, entry) + <= + autocvar_menu_slist_recommendations_maxping + ) ) - ) - { ++recommended; } - else - { --recommended; } + { ++recommended; } + else + { --recommended; } + } + if(recommended > 0) { return CAT_RECOMMENDED; } } - if(recommended > 0) { return CAT_RECOMMENDED; } } // if not favorited or recommended, check modname @@ -356,25 +376,7 @@ float CheckCategoryForEntry(float entry) } // must be normal or impure server - return (impure ? CAT_MODIFIED : CAT_NORMAL); -} - -float CheckItemNumber(float num) -{ - float i, n; - - if not(category_draw_count) { return num; } // there are no categories to process - - for(i = 0, n = 1; n <= category_draw_count; ++i, ++n) - { - if(category_item[i] == (num - i)) { return -category_name[i]; } - else if(n == category_draw_count) { return (num - n); } - else if((num - i) <= category_item[n]) { return (num - n); } - } - - // should never hit this point - error(sprintf("CheckItemNumber(%d): Function fell through without normal return!\n", num)); - return FALSE; + return ((impure > autocvar_menu_slist_purethreshold) ? CAT_MODIFIED : CAT_NORMAL); } void XonoticServerList_toggleFavorite(entity me, string srv) @@ -431,7 +433,7 @@ void ServerList_Update_favoriteButton(entity btn, entity me) { me.favoriteButton.setText(me.favoriteButton, (IsFavorite(me.ipAddressBox.text) ? - _("Remove") : _("Bookmark") + _("Remove") : _("Favorite") ) ); } @@ -457,8 +459,7 @@ void XonoticServerList_configureXonoticServerList(entity me) } void XonoticServerList_setSelected(entity me, float i) { - // todo: add logic to skip categories - float save, num; + float save; save = me.selectedItem; SUPER(XonoticServerList).setSelected(me, i); /* @@ -467,58 +468,17 @@ void XonoticServerList_setSelected(entity me, float i) */ if(me.nItems == 0) return; + if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems) + return; // sorry, it would be wrong - //if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != CheckItemNumber(me.nItems)) - // { error("^1XonoticServerList_setSelected(); ERROR: ^7Host cache viewcount mismatches nItems!\n"); return; } // sorry, it would be wrong - // ^ todo: make this work somehow? - - #define SET_SELECTED_SERVER(cachenum) \ - if(me.selectedServer) { strunzone(me.selectedServer); } \ - me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, cachenum)); \ - me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer); \ - me.ipAddressBox.cursorPos = strlen(me.selectedServer); \ - me.ipAddressBoxFocused = -1; \ - return; - - num = CheckItemNumber(me.selectedItem); + if(me.selectedServer) + strunzone(me.selectedServer); + me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem)); - if(num >= 0) { SET_SELECTED_SERVER(num); } - else if(save > me.selectedItem) - { - if(me.selectedItem == 0) { return; } - else - { - if(me.lastClickedTime >= me.lastBumpSelectTime) - { - SUPER(XonoticServerList).setSelected(me, me.selectedItem - 1); - num = CheckItemNumber(me.selectedItem); - if(num >= 0) - { - me.lastBumpSelectTime = time; - SET_SELECTED_SERVER(num); - } - } - } - } - else if(save < me.selectedItem) - { - if(me.selectedItem == me.nItems) { return; } - else - { - if(me.lastClickedTime >= me.lastBumpSelectTime) - { - SUPER(XonoticServerList).setSelected(me, me.selectedItem + 1); - num = CheckItemNumber(me.selectedItem); - if(num >= 0) - { - me.lastBumpSelectTime = time; - SET_SELECTED_SERVER(num); - } - } - } - } + me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer); + me.ipAddressBox.cursorPos = strlen(me.selectedServer); + me.ipAddressBoxFocused = -1; } - void XonoticServerList_refreshServerList(entity me, float mode) { //print("refresh of type ", ftos(mode), "\n"); @@ -613,7 +573,7 @@ void XonoticServerList_focusEnter(entity me) void XonoticServerList_draw(entity me) { - float i, found, owned, num; + float i, found, owned; if(_Nex_ExtResponseSystem_BannedServersNeedsRefresh) { @@ -622,6 +582,13 @@ void XonoticServerList_draw(entity me) _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 0; } + if(_Nex_ExtResponseSystem_PromotedServersNeedsRefresh) + { + if(!me.needsRefresh) + me.needsRefresh = 3; + _Nex_ExtResponseSystem_PromotedServersNeedsRefresh = 0; + } + if(_Nex_ExtResponseSystem_RecommendedServersNeedsRefresh) { if(!me.needsRefresh) @@ -663,31 +630,74 @@ void XonoticServerList_draw(entity me) // ^ unfortunately no such optimization can be made-- we must process through the // entire list, otherwise there is no way to know which item is first in its category. - float cat, x; - for(i = 0; i < itemcount; ++i) // FIXME this loop is TOTALLY unacceptable (O(servers)). Make it O(categories * log(servers)). Yes, that is possible. - { - cat = gethostcachenumber(SLIST_FIELD_CATEGORY, i); - if(cat) - { - if(category_draw_count == 0) - { - category_name[category_draw_count] = cat; - category_item[category_draw_count] = i; + // binary search method suggested by div + float x; + float begin = 0; + for(x = 1; x <= category_ent_count; ++x) { + float first = begin; + float last = (itemcount - 1); + if (first > last) { + // List is empty. + break; + } + float catf = gethostcachenumber(SLIST_FIELD_CATEGORY, first); + float catl = gethostcachenumber(SLIST_FIELD_CATEGORY, last); + if (catf > x) { + // The first one is already > x. + // Therefore, category x does not exist. + // Higher numbered categories do exist though. + } else if (catl < x) { + // The last one is < x. + // Thus this category - and any following - + // don't exist. + break; + } else if (catf == x) { + // Starts at first. This breaks the loop + // invariant in the binary search and thus has + // to be handled separately. + if(gethostcachenumber(SLIST_FIELD_CATEGORY, first) != x) + error("Category mismatch I"); + if(first > 0) + if(gethostcachenumber(SLIST_FIELD_CATEGORY, first - 1) == x) + error("Category mismatch II"); + category_name[category_draw_count] = x; + category_item[category_draw_count] = first; + ++category_draw_count; + begin = first + 1; + } else { + // At this point, catf <= x < catl, thus + // catf < catl, thus first < last. + // INVARIANTS: + // last - first >= 1 + // catf == gethostcachenumber(SLIST_FIELD_CATEGORY(first) + // catl == gethostcachenumber(SLIST_FIELD_CATEGORY(last) + // catf < x + // catl >= x + while (last - first > 1) { + float middle = floor((first + last) / 2); + // By loop condition, middle != first && middle != last. + float cat = gethostcachenumber(SLIST_FIELD_CATEGORY, middle); + if (cat >= x) { + last = middle; + catl = cat; + } else { + first = middle; + catf = cat; + } + } + if (catl == x) { + if(gethostcachenumber(SLIST_FIELD_CATEGORY, last) != x) + error("Category mismatch III"); + if(last > 0) + if(gethostcachenumber(SLIST_FIELD_CATEGORY, last - 1) == x) + error("Category mismatch IV"); + category_name[category_draw_count] = x; + category_item[category_draw_count] = last; ++category_draw_count; - ++me.nItems; + begin = last + 1; // already scanned through these, skip 'em } else - { - found = 0; - for(x = 0; x < category_draw_count; ++x) { if(cat == category_name[x]) { found = 1; } } - if not(found) - { - category_name[category_draw_count] = cat; - category_item[category_draw_count] = i; - ++category_draw_count; - ++me.nItems; - } - } + begin = last; // already scanned through these, skip 'em } } if(autocvar_menu_slist_categories_onlyifmultiple && (category_draw_count == 1)) @@ -709,19 +719,15 @@ void XonoticServerList_draw(entity me) { for(i = 0; i < me.nItems; ++i) { - num = CheckItemNumber(i); - if(num >= 0) + if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer) { - if(gethostcachestring(SLIST_FIELD_CNAME, num) == me.selectedServer) + if(i != me.selectedItem) { - if(i != me.selectedItem) - { - me.lastClickedServer = -1; - me.selectedItem = i; - } - found = 1; - break; + me.lastClickedServer = -1; + me.selectedItem = i; } + found = 1; + break; } } } @@ -729,11 +735,11 @@ void XonoticServerList_draw(entity me) { if(me.nItems > 0) { - if(me.selectedItem >= me.nItems) { me.selectedItem = me.nItems - 1; } - if(me.selectedServer) { strunzone(me.selectedServer); } - - num = CheckItemNumber(me.selectedItem); - if(num >= 0) { me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, num)); } + if(me.selectedItem >= me.nItems) + me.selectedItem = me.nItems - 1; + if(me.selectedServer) + strunzone(me.selectedServer); + me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem)); } } @@ -835,13 +841,6 @@ void ServerList_Filter_Change(entity box, entity me) void ServerList_Categories_Click(entity box, entity me) { box.setChecked(box, autocvar_menu_slist_categories = !autocvar_menu_slist_categories); - ///refreshhostcache(TRUE); - - //cvar_set("net_slist_pause", "0"); - //Destroy_Category_Entities(); - //CALL_ACCUMULATED_FUNCTION(RegisterSLCategories); - //me.refreshServerList(me, REFRESHSERVERLIST_REFILTER); - me.refreshServerList(me, REFRESHSERVERLIST_RESORT); me.ipAddressBox.setText(me.ipAddressBox, ""); @@ -955,23 +954,20 @@ void ServerList_Favorite_Click(entity btn, entity me) } void ServerList_Info_Click(entity btn, entity me) { - main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, CheckItemNumber(me.selectedItem)); + if (me.nItems != 0) + main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem); DialogOpenButton_Click(me, main.serverInfoDialog); } void XonoticServerList_clickListBoxItem(entity me, float i, vector where) { - float num = CheckItemNumber(i); - if(num >= 0) - { - if(num == me.lastClickedServer) - if(time < me.lastClickedTime + 0.3) - { - // DOUBLE CLICK! - ServerList_Connect_Click(NULL, me); - } - me.lastClickedServer = num; - me.lastClickedTime = time; - } + if(i == me.lastClickedServer) + if(time < me.lastClickedTime + 0.3) + { + // DOUBLE CLICK! + ServerList_Connect_Click(NULL, me); + } + me.lastClickedServer = i; + me.lastClickedTime = time; } void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected) { @@ -983,32 +979,52 @@ void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float float m, pure, freeslots, j, sflags; string s, typestr, versionstr, k, v, modname; - float item = CheckItemNumber(i); //print(sprintf("time: %f, i: %d, item: %d, nitems: %d\n", time, i, item, me.nItems)); - - if(item < 0) + + vector oldscale = draw_scale; + vector oldshift = draw_shift; +#define SET_YRANGE(start,end) \ + draw_scale = boxToGlobalSize(eX * 1 + eY * (end - start), oldscale); \ + draw_shift = boxToGlobal(eY * start, oldshift, oldscale); + + for (j = 0; j < category_draw_count; ++j) { + // Matches exactly the headings with increased height. + if (i == category_item[j]) + break; + } + + if (j < category_draw_count) { - entity catent = RetrieveCategoryEnt(-item); + entity catent = RetrieveCategoryEnt(category_name[j]); if(catent) { + SET_YRANGE( + (me.categoriesHeight - 1) / (me.categoriesHeight + 1), + me.categoriesHeight / (me.categoriesHeight + 1) + ); draw_Text( eY * me.realUpperMargin + +#if 0 eX * (me.columnNameOrigin + (me.columnNameSize - draw_TextWidth(catent.cat_string, 0, me.realFontSize)) * 0.5), catent.cat_string, +#else + eX * (me.columnNameOrigin), + strcat(catent.cat_string, ":"), +#endif me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0 ); - return; + SET_YRANGE(me.categoriesHeight / (me.categoriesHeight + 1), 1); } } if(isSelected) draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED); - s = gethostcachestring(SLIST_FIELD_QCSTATUS, item); + s = gethostcachestring(SLIST_FIELD_QCSTATUS, i); m = tokenizebyseparator(s, ":"); typestr = ""; if(m >= 2) @@ -1043,7 +1059,7 @@ void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float /* SLIST_FIELD_MOD = gethostcacheindexforkey("mod"); - s = gethostcachestring(SLIST_FIELD_MOD, item); + s = gethostcachestring(SLIST_FIELD_MOD, i); if(s != "data") if(modname == "Xonotic") modname = s; @@ -1057,16 +1073,16 @@ void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float if(modname != "NewToys") pure = 0; - if(gethostcachenumber(SLIST_FIELD_FREESLOTS, item) <= 0) + if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0) theAlpha = SKINALPHA_SERVERLIST_FULL; else if(freeslots == 0) theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support - else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, item)) + else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)) theAlpha = SKINALPHA_SERVERLIST_EMPTY; else theAlpha = 1; - p = gethostcachenumber(SLIST_FIELD_PING, item); + p = gethostcachenumber(SLIST_FIELD_PING, i); #define PING_LOW 75 #define PING_MED 200 #define PING_HIGH 500 @@ -1085,13 +1101,13 @@ void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float theAlpha *= SKINALPHA_SERVERLIST_HIGHPING; } - if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, item)) + if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i)) { theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE; theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE; } - s = gethostcachestring(SLIST_FIELD_CNAME, item); + s = gethostcachestring(SLIST_FIELD_CNAME, i); isv4 = isv6 = 0; if(substring(s, 0, 1) == "[") @@ -1206,11 +1222,11 @@ void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0); // server name - s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, item), me.columnNameSize, 0, me.realFontSize); + s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize); draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0); // server map - s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, item), me.columnMapSize, 0, me.realFontSize); + s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize); draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0); // server gametype @@ -1218,20 +1234,17 @@ void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0); // server playercount - s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, item)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, item))); + s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))); draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0); } float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift) { - float i = CheckItemNumber(me.selectedItem); vector org, sz; org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size); sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size); - me.lastBumpSelectTime = 0; - if(scan == K_ENTER || scan == K_KP_ENTER) { ServerList_Connect_Click(NULL, me); @@ -1239,9 +1252,9 @@ float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift) } else if(scan == K_MOUSE2 || scan == K_SPACE) { - if((me.nItems != 0) && (i >= 0)) + if(me.nItems != 0) { - main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, i); + main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem); DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz); return 1; } @@ -1249,7 +1262,7 @@ float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift) } else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS) { - if((me.nItems != 0) && (i >= 0)) + if(me.nItems != 0) { me.toggleFavorite(me, me.selectedServer); me.ipAddressBoxFocused = -1; @@ -1264,4 +1277,47 @@ float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift) else return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift); } + +float XonoticServerList_getTotalHeight(entity me) { + float num_normal_rows = me.nItems; + float num_headers = category_draw_count; + return me.itemHeight * (num_normal_rows + me.categoriesHeight * num_headers); +} +float XonoticServerList_getItemAtPos(entity me, float pos) { + pos = pos / me.itemHeight; + float i; + for (i = category_draw_count - 1; i >= 0; --i) { + float itemidx = category_item[i]; + float itempos = i * me.categoriesHeight + category_item[i]; + if (pos >= itempos + me.categoriesHeight + 1) + return itemidx + 1 + floor(pos - (itempos + me.categoriesHeight + 1)); + if (pos >= itempos) + return itemidx; + } + // No category matches? Note that category 0 is... 0. Therefore no headings exist at all. + return floor(pos); +} +float XonoticServerList_getItemStart(entity me, float item) { + float i; + for (i = category_draw_count - 1; i >= 0; --i) { + float itemidx = category_item[i]; + float itempos = i * me.categoriesHeight + category_item[i]; + if (item >= itemidx + 1) + return (itempos + me.categoriesHeight + 1 + item - (itemidx + 1)) * me.itemHeight; + if (item >= itemidx) + return itempos * me.itemHeight; + } + // No category matches? Note that category 0 is... 0. Therefore no headings exist at all. + return item * me.itemHeight; +} +float XonoticServerList_getItemHeight(entity me, float item) { + float i; + for (i = 0; i < category_draw_count; ++i) { + // Matches exactly the headings with increased height. + if (item == category_item[i]) + return me.itemHeight * (me.categoriesHeight + 1); + } + return me.itemHeight; +} + #endif