return 1;
}
+void MapInfo_FilterString(string sf)
+{
+ // this function further filters _MapInfo_filtered, which is prepared by MapInfo_FilterGametype by string
+ float i, j;
+ string title;
+
+ for(i = 0, j = -1; i < MapInfo_count; ++i)
+ {
+ if (MapInfo_Get_ByID(i))
+ {
+ // prepare for keyword filter
+ if (MapInfo_Map_title && strstrofs(MapInfo_Map_title, "<TITLE>", 0) == -1)
+ title = MapInfo_Map_title;
+ else
+ title = MapInfo_Map_bspname;
+ // keyword filter
+ if((strstrofs(strtolower(title), strtolower(sf), 0)) >= 0)
+ bufstr_set(_MapInfo_filtered, ++j, bufstr_get(_MapInfo_filtered, i));
+ }
+ }
+ MapInfo_count = j + 1;
+ MapInfo_ClearTemps();
+
+ // sometimes the glob isn't sorted nicely, so fix it here...
+ heapsort(MapInfo_count, _MapInfo_FilterList_swap, _MapInfo_FilterList_cmp, world);
+}
void MapInfo_Filter_Free()
{
// filter the info by game type mask (updates MapInfo_count)
float MapInfo_progress;
float MapInfo_FilterGametype(float gametype, float features, float pFlagsRequired, float pFlagsForbidden, float pAbortOnGenerate); // 1 on success, 0 on temporary failure (call it again next frame then; use MapInfo_progress as progress indicator)
+void MapInfo_FilterString(string sf); // filter _MapInfo_filtered (created by MapInfo_FilterGametype) with keyword
int MapInfo_CurrentFeatures(); // retrieves currently required features from cvars
int MapInfo_CurrentGametype(); // retrieves current gametype from cvars
int MapInfo_ForbiddenFlags(); // retrieves current flags from cvars
{
entity e, e0;
+ // the left half begins here
+
me.gotoRC(me, 0.5, 0);
me.TD(me, 1, 3, makeXonoticHeaderLabel(_("Gametype")));
me.TR(me);
e.configureXonoticTextSliderValues(e);
setDependent(e, "bot_number", 0, -1);
- me.gotoRC(me, me.rows - 3.5, 0);
+ me.gotoRC(me, me.rows - 3.8, 0);
me.TD(me, 1, 3, e0 = makeXonoticTextLabel(0.5, string_null));
e0.textEntity = main.mutatorsDialog;
e0.allowCut = 1;
//e0.allowWrap = 1;
- me.TR(me);
+
+ // mapListBox is in the right column but the ref is needed for mutators dialog here
+ me.mapListBox = makeXonoticMapList();
+ // here we use the following line instead of me.TR(me) for better visual spacing;
+ // this decision was made in this poll: http://forums.xonotic.org/showthread.php?tid=5445
+ me.gotoRC(me, me.rows - 2.5, 0);
me.TDempty(me, 0.5);
me.TD(me, 1, 2, e = makeXonoticButton(_("Mutators"), '0 0 0'));
e.onClick = DialogOpenButton_Click;
e.onClickEntity = main.mutatorsDialog;
main.mutatorsDialog.refilterEntity = me.mapListBox;
+ // The right half begins here
+
me.gotoRC(me, 0.5, 3.2); me.setFirstColumn(me, me.currentColumn);
- me.mapListBox = makeXonoticMapList();
+ // the maplistbox
me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Maplist")));
makeCallback(e, me.mapListBox, me.mapListBox.refilterCallback);
me.TR(me);
- me.TD(me, me.rows - 4, 3, me.mapListBox);
- me.gotoRC(me, me.rows - 2.5, 3.2);
- me.TDempty(me, 0.375);
- me.TD(me, 1, 1.125, e = makeXonoticButton(_("Select all"), '0 0 0'));
- e.onClick = MapList_All;
+ // we use 5.8 here to visually match the bottom line of the component on the left (Bot Skill)
+ me.TD(me, me.rows - 5.8, 3, me.mapListBox);
+
+ me.gotoRC(me, me.rows - 3.8, me.firstColumn);
+ // string filter label and box
+ me.TD(me, 1, 0.35, e = makeXonoticTextLabel(1, _("Filter:")));
+ me.mapListBox.stringFilterBox = makeXonoticMapListStringFilterBox(me, 0, string_null);
+ me.mapListBox.stringFilterBox.tooltip = getZonedTooltipForIdentifier("XonoticMultiplayerDialog_StringFilterBox");
+ me.TD(me, 1, me.columns - me.firstColumn - 0.35, e = me.mapListBox.stringFilterBox);
+ e.onChange = MapList_StringFilterBox_Change;
+ e.keyDown = MapList_StringFilterBox_keyDown;
+ e.onChangeEntity = me.mapListBox;
+ me.mapListBox.controlledTextbox = e;
+
+ // here we use the following line instead of me.TR(me) for better visual spacing;
+ // this decision was made in this poll: http://forums.xonotic.org/showthread.php?tid=5445
+ me.gotoRC(me, me.rows - 2.5, me.firstColumn);
+ // the selection buttons
+ me.TD(me, 1, 1, e = makeXonoticButton(_("Add shown"), '0 0 0'));
+ e.onClick = MapList_Add_Shown;
+ e.onClickEntity = me.mapListBox;
+ me.TD(me, 1, 1, e = makeXonoticButton(_("Remove shown"), '0 0 0'));
+ e.onClick = MapList_Remove_Shown;
e.onClickEntity = me.mapListBox;
- me.TD(me, 1, 1.125, e = makeXonoticButton(_("Select none"), '0 0 0'));
- e.onClick = MapList_None;
+ me.TD(me, 1, 1, e = makeXonoticButton(_("Remove all"), '0 0 0'));
+ e.onClick = MapList_Remove_All;
e.onClickEntity = me.mapListBox;
+ // The big button at the bottom
+
me.gotoRC(me, me.rows - 1, 0);
me.TD(me, 1, me.columns, e = makeXonoticButton(_("Start Multiplayer!"), '0 0 0'));
e.onClick = MapList_LoadMap;
METHOD(XonoticMapList, g_maplistCacheToggle, void(entity, float))
METHOD(XonoticMapList, g_maplistCacheQuery, float(entity, float))
+ ATTRIB(XonoticMapList, stringFilter, string, string_null)
+ ATTRIB(XonoticMapList, stringFilterBox, entity, NULL)
+
ATTRIB(XonoticMapList, startButton, entity, NULL)
METHOD(XonoticMapList, loadCvars, void(entity))
ATTRIB(XonoticMapList, alphaBG, float, 0)
ENDCLASS(XonoticMapList)
entity makeXonoticMapList();
-void MapList_All(entity btn, entity me);
-void MapList_None(entity btn, entity me);
+entity makeXonoticMapListStringFilterBox(entity me, float doEditColorCodes, string theCvar);
+void MapList_StringFilterBox_Change(entity box, entity me);
+float MapList_StringFilterBox_keyDown(entity me, float key, float ascii, float shift);
+void MapList_Add_Shown(entity btn, entity me);
+void MapList_Remove_Shown(entity btn, entity me);
+void MapList_Remove_All(entity btn, entity me);
void MapList_LoadMap(entity btn, entity me);
#endif
MapInfo_Shutdown();
}
+entity makeXonoticMapListStringFilterBox(entity me, float doEditColorCodes, string theCvar)
+{
+ return makeXonoticInputBox(doEditColorCodes, theCvar);
+}
entity makeXonoticMapList()
{
entity me;
return me;
}
+entity MapList_Set_String_Filter_Box(entity me, entity e)
+{
+ me.stringFilterBox = e;
+ return e;
+}
+
void XonoticMapList_configureXonoticMapList(entity me)
{
me.configureXonoticListBox(me);
me.refilter(me);
}
+
float XonoticMapList_g_maplistCacheQuery(entity me, float i)
{
return stof(substring(me.g_maplistCache, i, 1));
gt = MapInfo_CurrentGametype();
f = MapInfo_CurrentFeatures();
MapInfo_FilterGametype(gt, f, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
+ if (me.stringFilter)
+ MapInfo_FilterString(me.stringFilter);
me.nItems = MapInfo_count;
+
for(i = 0; i < MapInfo_count; ++i)
draw_PreloadPicture(strcat("/maps/", MapInfo_BSPName_ByID(i)));
if(me.g_maplistCache)
me.refilter(me);
}
-void MapList_All(entity btn, entity me)
+void MapList_StringFilterBox_Change(entity box, entity me)
{
- float i;
- string s;
- MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, MapInfo_ForbiddenFlags(), 0); // all
- s = "";
- for(i = 0; i < MapInfo_count; ++i)
- s = strcat(s, " ", MapInfo_BSPName_ByID(i));
- cvar_set("g_maplist", substring(s, 1, strlen(s) - 1));
+ if(me.stringFilter)
+ strunzone(me.stringFilter);
+ if(box.text != "")
+ me.stringFilter = strzone(box.text);
+ else
+ me.stringFilter = string_null;
+
+ me.refilter(me);
+}
+
+void MapList_Add_Shown(entity btn, entity me)
+{
+ float i, n;
+ n = strlen(me.g_maplistCache);
+ for (i = 0 ; i < n; i++)
+ {
+ if (!me.g_maplistCacheQuery(me, i))
+ me.g_maplistCacheToggle(me, i);
+ }
+ me.refilter(me);
+}
+
+void MapList_Remove_Shown(entity btn, entity me)
+{
+ float i, n;
+ n = strlen(me.g_maplistCache);
+ for (i = 0 ; i < n; i++)
+ {
+ if (me.g_maplistCacheQuery(me, i))
+ me.g_maplistCacheToggle(me, i);
+ }
me.refilter(me);
}
-void MapList_None(entity btn, entity me)
+void MapList_Remove_All(entity btn, entity me)
{
cvar_set("g_maplist", "");
me.refilter(me);
if(MapInfo_FindName_firstResult >= 0)
me.setSelected(me, MapInfo_FindName_firstResult);
}
+ else if(shift & S_CTRL && scan == 'f') // ctrl-f (as in "F"ind)
+ {
+ me.parent.setFocus(me.parent, me.stringFilterBox);
+ }
+ else if(shift & S_CTRL && scan == 'u') // ctrl-u (remove stringFilter line
+ {
+ me.stringFilterBox.setText(me.stringFilterBox, "");
+ MapList_StringFilterBox_Change(me.stringFilterBox, me);
+ }
else
return SUPER(XonoticMapList).keyDown(me, scan, ascii, shift);
return 1;
}
+float MapList_StringFilterBox_keyDown(entity me, float scan, float ascii, float shift)
+{
+ // in this section, note that onChangeEntity has the ref to mapListBox
+ // we make use of that, instead of extending a class to add one more attrib
+ switch(scan)
+ {
+ case K_KP_ENTER:
+ case K_ENTER:
+ // move the focus to the mapListBox
+ me.onChangeEntity.parent.setFocus(me.onChangeEntity.parent, me.onChangeEntity);
+ return 1;
+ case K_KP_UPARROW:
+ case K_UPARROW:
+ case K_KP_DOWNARROW:
+ case K_DOWNARROW:
+ // pass the event to the mapListBox (to scroll up and down)
+ return me.onChangeEntity.keyDown(me.onChangeEntity, scan, ascii, shift);
+ }
+ return SUPER(XonoticInputBox).keyDown(me, scan, ascii, shift);
+}
#endif
\g_instagib\Players will be given the Minstanex, which is a railgun with infinite damage. If the player runs out of ammo, he will have 10 seconds to find some or if he fails to do so, face death. The secondary fire mode is a laser which does not inflict any damage and is good for doing trickjumps.
\g_nix\No items Xonotic - instead of pickup items, everyone plays with the same weapon. After some time, a countdown will start, after which everyone will switch to another weapon.
\g_nix_with_laser\Always carry the laser as an additional weapon in Nix
-\XonoticMultiplayerDialog/Select all\Select all maps
-\XonoticMultiplayerDialog/Select none\Unselect all maps
+
+\XonoticMultiplayerDialog_StringFilterBox\Click here or Ctrl-F to provide a keyword to narrow down the maplist above. Ctrl-Delete to clear; Enter when done.
+\XonoticMultiplayerDialog/Add shown\Add the maps shown in Maplist above to your selection
+\XonoticMultiplayerDialog/Remove shown\Remove the maps shown in Maplist above from your selection
+\XonoticMultiplayerDialog/Remove all\Remove all the maps from your selection
\XonoticMultiplayerDialog/Timedemo\Benchmark how fast your computer can run the highlighted demo