// Property of Alientrap // custom/joingame.qm // stepValue should contain the field name void() Nex_Action_JoinGame_SortBy_Action = { if( HostCache_SortField == self._realValue ) sethostcachesort( self._realValue, !HostCache_SortDescending ); else sethostcachesort( self._realValue, true ); HostCache_ResortViewSet(); }; void() Nex_Action_JoinGame_SortBy = { self._realValue = gethostcacheindexforkey( self.target ); self.action = Nex_Action_JoinGame_SortBy_Action; }; void() Nex_Automation_CreateEntries = { local entity lTemplate; local float lCounter; lTemplate = Menu_GetItem( "Entry" ); for( lCounter = 0 ; lCounter < 64 ; ++lCounter ) { local entity lEntry; lEntry = Menu_DeriveItem( lTemplate, strcat( "Entry", ftos( lCounter) ), self.parent, true ); lEntry.stepValue = lCounter; } Menu_LinkItem( self._parent ); }; void() Nex_Action_EntryConnect = { cmd( "connect \"" ); cmd( gethostcachestring( SLIST_FIELD_CNAME, self.stepValue ) ); cmd( "\"\n" ); m_hide(); }; void() Nex_Action_RefreshSlist = { HostCache_RefreshHostCache(); }; void() Nex_Action_JumpToJoinGame = { local entity lItem; resethostcachemasks(); sethostcachesort( SLIST_FIELD_PING, false ); HostCache_RefreshHostCache(); lItem = Menu_GetItem( "Normal::Panel" ); String_EntitySet( lItem, link, "JoinGame" ); Raise_Update( lItem ); Menu_UpdateRunFlags(); Menu_JumpToWindow( lItem._link, false, false ); }; // mask parser /* query string format: two types: 1) Prefix "mask" Advanced query Format: ( and|or TYPE OP MASK [...] )* TYPE : one of the slist fields OP: <;<=;>=;==;!= normal arithmetic comparison operators (default <=) (= instead of == also supported) $$ 'does contain' (default string op) !$ 'does not contain' : leads to default op On every occurence of AND or OR a new mask of the spec type is created. E.g. or name: "WWClan" ping: 200 and protocol == 3 maxplayers > 5 will create an or and an and mask 2) No prefix: keyword * notempty compatible (same net protocol version) goodping (ping <= 150) mediumping (ping <= 250) */ #define GetNextToken if( ++lTokenNum > lTokenCount ) goto finish; else lToken = argv( lTokenNum ) void() Nex_Action_ExecuteQuery = { local float lAndPos, lOrPos; local float lTokenNum, lTokenCount; resethostcachemasks(); lAndPos = SLIST_MASK_AND; lOrPos = SLIST_MASK_OR; lTokenCount = tokenize( self._target.value ); for( lTokenNum = 0 ; lTokenNum < lTokenCount ; ++lTokenNum ) { local string lToken; lToken = argv( lTokenNum ); if( lToken == "notempty" ) { sethostcachemasknumber( lAndPos, SLIST_FIELD_NUMPLAYERS, 0, SLIST_TEST_NOTEQUAL ); ++lAndPos; } else if( lToken == "compatible" ) { sethostcachemasknumber( lAndPos, SLIST_FIELD_PROTOCOL, NET_CURRENTPROTOCOL, SLIST_TEST_EQUAL ); ++lAndPos; } else if( lToken == "goodping" ) { sethostcachemasknumber( lAndPos, SLIST_FIELD_PING, 150, SLIST_TEST_LESSEQUAL ); ++lAndPos; } else if( lToken == "mediumping" ) { sethostcachemasknumber( lAndPos, SLIST_FIELD_PROTOCOL, 250, SLIST_TEST_LESSEQUAL ); ++lAndPos; } else if( lToken == "mask" ) { // start the query loop GetNextToken; while( 1 ) { local bool lAndMask; if( lToken == "or" ) lAndMask = false; else if( lToken == "and" ) lAndMask = true; else goto finish; // abort the parsing // now parse all condition fields while( 1 ) { local float lField; local float lOperator; local bool lIsStringArg; GetNextToken; // now get the field number if( lToken == "cname" ) { lField = SLIST_FIELD_CNAME; lIsStringArg = true; } else if( lToken == "ping" ) { lField = SLIST_FIELD_PING; lIsStringArg = false; } else if( lToken == "game" ) { lField = SLIST_FIELD_GAME; lIsStringArg = true; } else if( lToken == "mod" ) { lField = SLIST_FIELD_MOD; lIsStringArg = true; } else if( lToken == "map" ) { lField = SLIST_FIELD_MAP; lIsStringArg = true; } else if( lToken == "name" ) { lField = SLIST_FIELD_NAME; lIsStringArg = true; } else if( lToken == "maxplayers" ) { lField = SLIST_FIELD_MAXPLAYERS; lIsStringArg = false; } else if( lToken == "numplayers" ) { lField = SLIST_FIELD_NUMPLAYERS; lIsStringArg = false; } else if( lToken == "protocol" ) { lField = SLIST_FIELD_PROTOCOL; lIsStringArg = false; } else { // increment the mask pos and let upper check for or or and if( lAndMask ) ++lAndPos; else ++lOrPos; break; } // now lets determine the comparison operator GetNextToken; if( lToken == "$$" ) lOperator = SLIST_TEST_CONTAINS; else if( lToken == "!$" ) lOperator = SLIST_TEST_NOTCONTAIN; else if( lToken == "<" ) lOperator = SLIST_TEST_LESS; else if( lToken == "<=" ) lOperator = SLIST_TEST_LESSEQUAL; else if( lToken == "==" || lToken == "=" ) lOperator = SLIST_TEST_EQUAL; else if( lToken == ">" ) lOperator = SLIST_TEST_GREATER; else if( lToken == ">=" ) lOperator = SLIST_TEST_GREATEREQUAL; else if( lToken == "!=" ) lOperator = SLIST_TEST_NOTEQUAL; else if( lToken == ":" ) if( lIsStringArg ) lOperator = SLIST_TEST_CONTAINS; else lOperator = SLIST_TEST_LESSEQUAL; else goto finish; // abort the parsing GetNextToken; if( lIsStringArg ) if( lAndMask ) sethostcachemaskstring( lAndPos, lField, lToken, lOperator ); else sethostcachemaskstring( lOrPos, lField, lToken, lOperator ); else if( lAndMask ) sethostcachemasknumber( lAndPos, lField, stof( lToken ), lOperator ); else sethostcachemasknumber( lOrPos, lField, stof( lToken ), lOperator ); } } } else { // lets have a try it with or and string contain sethostcachemaskstring( lOrPos, SLIST_FIELD_MAP, lToken, SLIST_TEST_CONTAINS ); lOrPos = lOrPos + 1; sethostcachemaskstring( lOrPos, SLIST_FIELD_NAME, lToken, SLIST_TEST_CONTAINS ); lOrPos = lOrPos + 1; //sethostcachemasknumber( lOrPos, SLIST_FIELD_MOD, lToken, SLIST_TEST_CONTAINS ); //lOrPos = lOrPos + 1; } } :finish HostCache_ResortViewSet(); #undef GetNextToken() };