//***************************************************************************** // void SERVER_RCON_Tick( ) { // Remove timed-out candidates. for ( unsigned int i = 0; i < g_Candidates.Size( ); ) { if (( gametic - g_Candidates[i].iLastMessageTic ) >= ( RCON_CANDIDATE_TIMEOUT_TIME * TICRATE )) g_Candidates.Delete( i ); else i++; } // Remove timed-out clients. for ( unsigned int i = 0; i < g_AuthedClients.Size( ); ) { if (( gametic - g_AuthedClients[i].iLastMessageTic ) >= ( RCON_CLIENT_TIMEOUT_TIME * TICRATE )) { Printf( "RCON client at %s timed out.\n", NETWORK_AddressToString( g_AuthedClients[i].Address )); g_AuthedClients.Delete( i ); SERVER_RCON_UpdateInfo( SVRCU_ADMINCOUNT ); } else i++; } g_BadRequestFloodQueue.adjustHead( gametic / 1000 ); }
//============================================================================= // // // //============================================================================= void MergeLines(FGLSectionLoop *loop) { int i; int deleted = 0; FGLSectionLine *ln1; FGLSectionLine *ln2; // Merge identical lines in the list for(i = loop->numlines - 1; i > 0; i--) { ln1 = loop->GetLine(i); ln2 = loop->GetLine(i-1); if (ln1->sidedef == ln2->sidedef && ln1->otherside == ln2->otherside) { // identical references. These 2 lines can be merged. ln2->end = ln1->end; SectionLines.Delete(loop->startline + i); loop->numlines--; deleted++; } } // If we started in the middle of a sidedef the first and last lines // may reference the same sidedef. check that, too. int loopstart = 0; ln1 = loop->GetLine(0); for(i = loop->numlines - 1; i > 0; i--) { ln2 = loop->GetLine(i); if (ln1->sidedef != ln2->sidedef || ln1->otherside != ln2->otherside) break; } if (i < loop->numlines-1) { i++; ln2 = loop->GetLine(i); ln1->start = ln2->start; SectionLines.Delete(loop->startline + i, loop->numlines - i); deleted += loop->numlines - i; loop->numlines = i; } // Adjust all following loops for(unsigned ii = unsigned(loop - &SectionLoops[0]) + 1; ii < SectionLoops.Size(); ii++) { SectionLoops[ii].startline -= deleted; } }
static int UseHealthItems(TArray<AInventory *> &Items, int &saveHealth) { int saved = 0; while (Items.Size() > 0 && saveHealth > 0) { int maxhealth = 0; int index = -1; // Find the largest item in the list for(unsigned i = 0; i < Items.Size(); i++) { if (Items[i]->health > maxhealth) { index = i; maxhealth = Items[i]->health; } } // Now apply the health items, using the same logic as Heretic and Hexen. int count = (saveHealth + maxhealth-1) / maxhealth; for(int i = 0; i < count; i++) { saved += maxhealth; saveHealth -= maxhealth; if (--Items[index]->Amount == 0) { Items[index]->DepleteOrDestroy (); Items.Delete(index); break; } } } return saved; }
//============================================================================= // // // //============================================================================= void DeleteLine(int i) { SectionLines.Delete(i); for(int i = SectionLoops.Size() - 1; i >= 0; i--) { FGLSectionLoop *loop = &SectionLoops[i]; if (loop->startline > i) loop->startline--; } }
static void server_rcon_HandleNewConnection( NETADDRESS_s Address, int iProtocolVersion ) { // Banned client? Notify him, ignore him, and get out of here. if ( SERVERBAN_IsIPBanned( Address )) { NETWORK_WriteByte( &g_MessageBuffer.ByteStream, SVRC_BANNED ); NETWORK_LaunchPacket( &g_MessageBuffer, Address ); g_BadRequestFloodQueue.addAddress( Address, gametic / 1000 ); return; } // Old protocol version? Notify, ignore, and quit. if ( iProtocolVersion < MIN_PROTOCOL_VERSION ) { NETWORK_WriteByte( &g_MessageBuffer.ByteStream, SVRC_OLDPROTOCOL ); NETWORK_WriteByte( &g_MessageBuffer.ByteStream, PROTOCOL_VERSION ); NETWORK_WriteString( &g_MessageBuffer.ByteStream, DOTVERSIONSTR ); NETWORK_LaunchPacket( &g_MessageBuffer, Address ); g_BadRequestFloodQueue.addAddress( Address, gametic / 1000 ); return; } // Check if there's already a user at this address. Remove him if so (must be reconnecting). // This ensures that each address never has more than one entry (since this is the only function that gives out new candidate slots). int iIndex = server_rcon_FindCandidate( Address ); if ( iIndex != -1 ) g_Candidates.Delete( iIndex ); iIndex = server_rcon_FindClient( Address ); if ( iIndex != -1 ) g_AuthedClients.Delete( iIndex ); // Create a slot for him, and request his password. RCONCANDIDATE_s Candidate; Candidate.iLastMessageTic = gametic; Candidate.Address = Address; server_rcon_CreateSalt( Candidate.szSalt ); g_Candidates.Push( Candidate ); NETWORK_ClearBuffer( &g_MessageBuffer ); NETWORK_WriteByte( &g_MessageBuffer.ByteStream, SVRC_SALT ); NETWORK_WriteString( &g_MessageBuffer.ByteStream, Candidate.szSalt ); NETWORK_LaunchPacket( &g_MessageBuffer, Address ); }
bool Remove(ASpecialSpot *spot) { for(unsigned i = 0; i < Spots.Size(); i++) { if (Spots[i] == spot) { Spots.Delete(i); if (Index > i) Index--; return true; } } return false; }
void SkylineBinPack::Insert(TArray<RectSize> &rects, TArray<Rect> &dst) { dst.Clear(); while(rects.Size() > 0) { Rect bestNode; int bestScore1 = INT_MAX; int bestScore2 = INT_MAX; int bestSkylineIndex = -1; int bestRectIndex = -1; for(unsigned i = 0; i < rects.Size(); ++i) { Rect newNode; int score1; int score2; int index; newNode = FindPositionForNewNodeMinWaste(rects[i].width, rects[i].height, score2, score1, index); assert(disjointRects.Disjoint(newNode)); if (newNode.height != 0) { if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2)) { bestNode = newNode; bestScore1 = score1; bestScore2 = score2; bestSkylineIndex = index; bestRectIndex = i; } } } if (bestRectIndex == -1) return; // Perform the actual packing. assert(disjointRects.Disjoint(bestNode)); #ifdef _DEBUG disjointRects.Add(bestNode); #endif AddSkylineLevel(bestSkylineIndex, bestNode); usedSurfaceArea += rects[bestRectIndex].width * rects[bestRectIndex].height; rects.Delete(bestRectIndex); dst.Push(bestNode); } }
void gl_AddLightDefaults(FLightDefaults *defaults) { FLightDefaults *temp; unsigned int i; // remove duplicates for (i = 0; i < LightDefaults.Size(); i++) { temp = LightDefaults[i]; if (temp->GetName() == defaults->GetName()) { delete temp; LightDefaults.Delete(i); break; } } LightDefaults.Push(defaults); }
void P_AutoUseStrifeHealth (player_t *player) { TArray<AInventory *> Items; for(AInventory *inv = player->mo->Inventory; inv != NULL; inv = inv->Inventory) { if (inv->Amount > 0 && inv->IsKindOf(RUNTIME_CLASS(AHealthPickup))) { int mode = static_cast<AHealthPickup*>(inv)->autousemode; if (mode == 3) Items.Push(inv); } } if (!sv_disableautohealth) { while (Items.Size() > 0) { int maxhealth = 0; int index = -1; // Find the largest item in the list for(unsigned i = 0; i < Items.Size(); i++) { if (Items[i]->health > maxhealth) { index = i; maxhealth = Items[i]->Amount; } } while (player->health < 50) { if (!player->mo->UseInventory (Items[index])) break; } if (player->health >= 50) return; // Using all of this item was not enough so delete it and restart with the next best one Items.Delete(index); } } }
void WordGenerator (CXMLElement *pCmdLine) { int i; // Load input file CString sFilespec = pCmdLine->GetAttribute(CONSTLIT("input")); if (sFilespec.IsBlank()) { printf("ERROR: input filename expected.\n"); return; } CFileReadBlock InputFile(sFilespec); if (InputFile.Open() != NOERROR) { printf("ERROR: Unable to open file: %s\n", sFilespec.GetASCIIZPointer()); return; } // "Novel" means that we only generate words that are not // in the input file. bool bNovelWordsOnly = pCmdLine->GetAttributeBool(NOVEL_ATTRIB); // Build up a word generator CMarkovWordGenerator Generator; TMap<CString, DWORD> InputWords; // Read each line of the file char *pPos = InputFile.GetPointer(0); char *pEndPos = pPos + InputFile.GetLength(); while (pPos < pEndPos) { // Skip whitespace while (pPos < pEndPos && (strIsWhitespace(pPos) || *pPos < ' ')) pPos++; // Parse the line char *pStart = pPos; while (pPos < pEndPos && *pPos != '\r' && *pPos != '\n' && *pPos >= ' ') pPos++; CString sWord(pStart, pPos - pStart); // Add the word to the generator if (!sWord.IsBlank()) { Generator.AddSample(strTrimWhitespace(sWord)); // If we are looking for novel words we need to keep a map // of all words in the input file. if (bNovelWordsOnly) InputWords.Insert(sWord); } } // If we have a count, then output a list of random words int iCount; if (pCmdLine->FindAttributeInteger(COUNT_ATTRIB, &iCount)) { if (iCount > 0) { TArray<CString> Result; Generator.GenerateUnique(iCount, &Result); for (i = 0; i < Result.GetCount(); i++) if (InputWords.Find(Result[i])) { Result.Delete(i); i--; } Result.Sort(); for (i = 0; i < Result.GetCount(); i++) printf("%s\n", Result[i].GetASCIIZPointer()); } } // Otherwise, output the generator as XML else { CMemoryWriteStream Output; if (Output.Create() != NOERROR) { printf("ERROR: Out of memory.\n"); return; } if (Generator.WriteAsXML(&Output) != NOERROR) { printf("ERROR: Unable to output generator as XML.\n"); return; } Output.Write("\0", 1); printf(Output.GetPointer()); } }
static void server_rcon_HandleLogin( int iCandidateIndex, const char *pszHash ) { // If there's no slot, the candidate must have timed out, or is hacking. Bye! if ( iCandidateIndex == -1 ) return; // Combine the salt and password, and hash it. FString fsString, fsCorrectHash; fsString.Format( "%s%s", g_Candidates[iCandidateIndex].szSalt, sv_rconpassword.GetGenericRep(CVAR_String).String ); CMD5Checksum::GetMD5( reinterpret_cast<const BYTE *>(fsString.GetChars()), fsString.Len(), fsCorrectHash ); // Compare that to what he sent us. // Printf("Mine: %s\nTheirs: %s\n", fsCorrectHash, pszHash ); NETWORK_ClearBuffer( &g_MessageBuffer ); // [BB] Do not allow the server to let anybody use RCON in case sv_rconpassword is empty. if ( fsCorrectHash.Compare( pszHash ) || ( strlen( sv_rconpassword.GetGenericRep(CVAR_String).String ) == 0 ) ) { // Wrong password. NETWORK_WriteByte( &g_MessageBuffer.ByteStream, SVRC_INVALIDPASSWORD ); NETWORK_LaunchPacket( &g_MessageBuffer, g_Candidates[iCandidateIndex].Address ); // [RC] Note: Be sure to finish any packets before calling Printf(). Otherwise SERVER_RCON_Print will clear your buffer. // To prevent mass password flooding, ignore the IP for a few seconds. g_BadRequestFloodQueue.addAddress( g_Candidates[iCandidateIndex].Address, gametic / 1000 ); Printf( "Failed RCON login from %s. Ignoring IP for 10 seconds...\n", NETWORK_AddressToString( g_Candidates[iCandidateIndex].Address )); } else { // [BB] Since we log when RCON clients disconnect, we should also log when they connect. // Do this before we do anything else so that this message is sent to the new RCON client // with the console history. Printf( "RCON client at %s connected.\n", NETWORK_AddressToString( g_Candidates[iCandidateIndex].Address )); // Correct password. Promote him to an authed client. RCONCLIENT_s Client; Client.Address = g_Candidates[iCandidateIndex].Address; Client.iLastMessageTic = gametic; g_AuthedClients.Push( Client ); NETWORK_ClearBuffer( &g_MessageBuffer ); NETWORK_WriteByte( &g_MessageBuffer.ByteStream, SVRC_LOGGEDIN ); // Tell him some info about the server. NETWORK_WriteByte( &g_MessageBuffer.ByteStream, PROTOCOL_VERSION ); NETWORK_WriteString( &g_MessageBuffer.ByteStream, sv_hostname.GetGenericRep( CVAR_String ).String ); // Send updates. NETWORK_WriteByte( &g_MessageBuffer.ByteStream, NUM_RCON_UPDATES ); for ( int i = 0; i < NUM_RCON_UPDATES; i++ ) server_WriteUpdateInfo( &g_MessageBuffer.ByteStream, i ); // Send the console history. NETWORK_WriteByte( &g_MessageBuffer.ByteStream, g_RecentConsoleLines.size() ); for( std::list<FString>::iterator i = g_RecentConsoleLines.begin(); i != g_RecentConsoleLines.end(); ++i ) NETWORK_WriteString( &g_MessageBuffer.ByteStream, *i ); NETWORK_LaunchPacket( &g_MessageBuffer, g_Candidates[iCandidateIndex].Address ); SERVER_RCON_UpdateInfo( SVRCU_ADMINCOUNT ); } // Remove his temporary slot. g_Candidates.Delete( iCandidateIndex ); }
void SERVER_RCON_ParseMessage( NETADDRESS_s Address, LONG lMessage, BYTESTREAM_s *pByteStream ) { int iIndex = -1; switch ( lMessage ) { case CLRC_BEGINCONNECTION: server_rcon_HandleNewConnection( Address, NETWORK_ReadByte( pByteStream )); break; case CLRC_PASSWORD: server_rcon_HandleLogin( server_rcon_FindCandidate( Address ), NETWORK_ReadString( pByteStream )); break; case CLRC_PONG: iIndex = server_rcon_FindClient( Address ); if ( iIndex != -1 ) g_AuthedClients[iIndex].iLastMessageTic = gametic; break; case CLRC_COMMAND: // Execute the command (if this came from an admin). iIndex = server_rcon_FindClient( Address ); if ( iIndex != -1 ) { const char *szCommand = NETWORK_ReadString( pByteStream ); // [BB] Log the command before adding it. If we don't have a server GUI, the command // is executed immediately and may cause Skulltag to exit before the command is logged. Printf( "-> %s (RCON by %s)\n", szCommand, NETWORK_AddressToString( Address ) ); SERVER_AddCommand( szCommand ); g_AuthedClients[iIndex].iLastMessageTic = gametic; } break; case CLRC_DISCONNECT: iIndex = server_rcon_FindClient( Address ); if ( iIndex != -1 ) { g_AuthedClients.Delete( iIndex ); SERVER_RCON_UpdateInfo( SVRCU_ADMINCOUNT ); Printf( "RCON client at %s disconnected.\n", NETWORK_AddressToString( Address )); } break; case CLRC_TABCOMPLETE: // [TP] RCON client wishes to tab-complete iIndex = server_rcon_FindClient( Address ); if ( iIndex != -1 ) { const char* part = NETWORK_ReadString( pByteStream ); TArray<FString> list = C_GetTabCompletes( part ); NETWORK_ClearBuffer( &g_MessageBuffer ); // [TP] Let's not send too many of these though if ( list.Size() < 50 ) { NETWORK_WriteByte( &g_MessageBuffer.ByteStream, SVRC_TABCOMPLETE ); NETWORK_WriteByte( &g_MessageBuffer.ByteStream, list.Size() ); for ( unsigned i = 0; i < list.Size(); ++i ) NETWORK_WriteString( &g_MessageBuffer.ByteStream, list[i] ); } else { NETWORK_WriteByte( &g_MessageBuffer.ByteStream, SVRC_TOOMANYTABCOMPLETES ); NETWORK_WriteShort( &g_MessageBuffer.ByteStream, list.Size() ); } NETWORK_LaunchPacket( &g_MessageBuffer, g_AuthedClients[iIndex].Address ); } break; } }
void P_Recalculate3DFloors(sector_t * sector) { F3DFloor * rover; F3DFloor * pick; unsigned pickindex; F3DFloor * clipped=NULL; F3DFloor * solid=NULL; double solid_bottom=0; double clipped_top; double clipped_bottom=0; double maxheight, minheight; unsigned i, j; lightlist_t newlight; lightlist_t resetlight; // what it goes back to after FF_DOUBLESHADOW TArray<F3DFloor*> & ffloors=sector->e->XFloor.ffloors; TArray<lightlist_t> & lightlist = sector->e->XFloor.lightlist; // Sort the floors top to bottom for quicker access here and later // Translucent and swimmable floors are split if they overlap with solid ones. if (ffloors.Size()>1) { TArray<F3DFloor*> oldlist; oldlist = ffloors; ffloors.Clear(); // first delete the old dynamic stuff for(i=0;i<oldlist.Size();i++) { F3DFloor * rover=oldlist[i]; if (rover->flags&FF_DYNAMIC) { delete rover; oldlist.Delete(i); i--; continue; } if (rover->flags&FF_CLIPPED) { rover->flags&=~FF_CLIPPED; rover->flags|=FF_EXISTS; } } while (oldlist.Size()) { pick=oldlist[0]; double height=pick->top.plane->ZatPoint(sector->centerspot); // find highest starting ffloor - intersections are not supported! pickindex=0; for (j=1;j<oldlist.Size();j++) { double h2=oldlist[j]->top.plane->ZatPoint(sector->centerspot); if (h2>height) { pick=oldlist[j]; pickindex=j; height=h2; } } oldlist.Delete(pickindex); double pick_bottom=pick->bottom.plane->ZatPoint(sector->centerspot); if (pick->flags & FF_THISINSIDE) { // These have the floor higher than the ceiling and cannot be processed // by the clipping code below. ffloors.Push(pick); } else if ((pick->flags&(FF_SWIMMABLE|FF_TRANSLUCENT) || (!(pick->flags&FF_RENDERALL))) && pick->flags&FF_EXISTS) { // We must check if this nonsolid segment gets clipped from the top by another 3D floor if (solid != NULL && solid_bottom < height) { ffloors.Push(pick); if (solid_bottom < pick_bottom) { // this one is fully covered pick->flags|=FF_CLIPPED; pick->flags&=~FF_EXISTS; } else { F3DFloor * dyn=new F3DFloor; *dyn=*pick; pick->flags|=FF_CLIPPED; pick->flags&=~FF_EXISTS; dyn->flags|=FF_DYNAMIC; dyn->top.copyPlane(&solid->bottom); ffloors.Push(dyn); clipped = dyn; clipped_top = solid_bottom; clipped_bottom = pick_bottom; } } else if (pick_bottom > height) // do not allow inverted planes { F3DFloor * dyn = new F3DFloor; *dyn = *pick; pick->flags |= FF_CLIPPED; pick->flags &= ~FF_EXISTS; dyn->flags |= FF_DYNAMIC; dyn->bottom.copyPlane(&pick->top); ffloors.Push(pick); ffloors.Push(dyn); } else { clipped = pick; clipped_top = height; clipped_bottom = pick_bottom; ffloors.Push(pick); } } else if (clipped && clipped_bottom<height) { // translucent floor above must be clipped to this one! F3DFloor * dyn=new F3DFloor; *dyn=*clipped; clipped->flags|=FF_CLIPPED; clipped->flags&=~FF_EXISTS; dyn->flags|=FF_DYNAMIC; dyn->bottom.copyPlane(&pick->top); ffloors.Push(dyn); ffloors.Push(pick); if (pick_bottom<=clipped_bottom) { clipped=NULL; } else { // the translucent part extends below the clipper dyn=new F3DFloor; *dyn=*clipped; dyn->flags|=FF_DYNAMIC|FF_EXISTS; dyn->top.copyPlane(&pick->bottom); ffloors.Push(dyn); clipped = dyn; clipped_top = pick_bottom; } solid = pick; solid_bottom = pick_bottom; } else { clipped = NULL; if (solid == NULL || solid_bottom > pick_bottom) { // only if this one is lower solid = pick; solid_bottom = pick_bottom; } ffloors.Push(pick); } } } // having the floors sorted makes this routine significantly simpler // Only some overlapping cases with FF_DOUBLESHADOW might create anomalies // but these are clearly undefined. if(ffloors.Size()) { lightlist.Resize(1); lightlist[0].plane = sector->ceilingplane; lightlist[0].p_lightlevel = §or->lightlevel; lightlist[0].caster = NULL; lightlist[0].lightsource = NULL; lightlist[0].extra_colormap = sector->ColorMap; lightlist[0].blend = 0; lightlist[0].flags = 0; resetlight = lightlist[0]; maxheight = sector->ceilingplane.ZatPoint(sector->centerspot); minheight = sector->floorplane.ZatPoint(sector->centerspot); for(i = 0; i < ffloors.Size(); i++) { rover=ffloors[i]; if ( !(rover->flags & FF_EXISTS) || rover->flags & FF_NOSHADE ) continue; double ff_top=rover->top.plane->ZatPoint(sector->centerspot); if (ff_top < minheight) break; // reached the floor if (ff_top < maxheight) { newlight.plane = *rover->top.plane; newlight.p_lightlevel = rover->toplightlevel; newlight.caster = rover; newlight.lightsource = rover; newlight.extra_colormap = rover->GetColormap(); newlight.blend = rover->GetBlend(); newlight.flags = rover->flags; lightlist.Push(newlight); } else { double ff_bottom=rover->bottom.plane->ZatPoint(sector->centerspot); if (ff_bottom<maxheight) { // this segment begins over the ceiling and extends beyond it lightlist[0].p_lightlevel = rover->toplightlevel; lightlist[0].caster = rover; lightlist[0].lightsource = rover; lightlist[0].extra_colormap = rover->GetColormap(); lightlist[0].blend = rover->GetBlend(); lightlist[0].flags = rover->flags; } } if (!(rover->flags & (FF_DOUBLESHADOW | FF_RESET))) { resetlight = lightlist.Last(); } else if (rover->flags & FF_RESET) { resetlight.p_lightlevel = §or->lightlevel; resetlight.lightsource = NULL; resetlight.extra_colormap = sector->ColorMap; resetlight.blend = 0; } if (rover->flags&FF_DOUBLESHADOW) { double ff_bottom=rover->bottom.plane->ZatPoint(sector->centerspot); if(ff_bottom < maxheight && ff_bottom>minheight) { newlight.caster = rover; newlight.plane = *rover->bottom.plane; newlight.lightsource = resetlight.lightsource; newlight.p_lightlevel = resetlight.p_lightlevel; newlight.extra_colormap = resetlight.extra_colormap; newlight.blend = resetlight.blend; newlight.flags = rover->flags; lightlist.Push(newlight); } } } } }
void CIntGraph::GenerateRandomConnections (DWORD dwStartNode, int iMinConnections, int iMaxConnections) // GenerateRandomConnections // // Generate random connection across all nodes. { int i, j; // We start by making sure every node is connected with one other node. // We keep track of the nodes that are connected and those that are not. TArray<int> Connected; TArray<int> NotConnected; // All the nodes are part of the not-connected group // (except for the start node) for (i = 0; i < m_Nodes.GetCount(); i++) if (i != dwStartNode && !NodeIsFree(GetNode(i))) NotConnected.Insert(i); Connected.Insert((int)dwStartNode); // Loop until all nodes are connected while (NotConnected.GetCount() > 0) { // Look for the shortest, non-overlapping distance // between a node in the connected list and a node in the // not-connected list. int iBestDist2 = MAX_DIST2; int iBestFrom = -1; int iBestTo = -1; for (i = 0; i < Connected.GetCount(); i++) { int iFrom = i; SNode *pFrom = GetNode(Connected[iFrom]); for (j = 0; j < NotConnected.GetCount(); j++) { int iTo = j; SNode *pTo = GetNode(NotConnected[iTo]); int xDist = pTo->x - pFrom->x; int yDist = pTo->y - pFrom->y; int iDist2 = xDist * xDist + yDist * yDist; if (iDist2 < iBestDist2 && !IsCrossingConnection(Connected[iFrom], NotConnected[iTo])) { iBestDist2 = iDist2; iBestFrom = iFrom; iBestTo = iTo; } } } // If we found a best distance, connect the two nodes if (iBestFrom != -1) { Connect(Connected[iBestFrom], NotConnected[iBestTo]); Connected.Insert(NotConnected[iBestTo]); NotConnected.Delete(iBestTo); } // If we did not find the best distance, then it means that we could not // connect without overlapping. In that case, just connect all the unconnected else { for (i = 0; i < NotConnected.GetCount(); i++) Connect(Connected[0], NotConnected[i]); NotConnected.DeleteAll(); } } }