bool StationaryMixPointIrregular::SimulationTick()
{
	//The simulation does nothing until the next scheduled silent period.
	if(SimulationTime>=NextSilentPeriod)
	{
		NextSilentPeriod+=RandInt(RandDurationMin,RandDurationMax);
		LogTraffic(&Transmitter,ANNOUNCEMENT);//Each mix zone gets one announcement frame to signal the other vehicles.
		ArrayList<Vehicle*>* NearbyVehicles=GetVehiclesInRange(&Transmitter);
		AnonymitySet* CurrentSet=new AnonymitySet(Transmitter.x,Transmitter.y,Transmitter.Radius,SimulationTime,SimulationTime,NextSilentPeriod,&Transmitter);
		//Any vehicles in range that do not already have an anonymity set are assigned to the current one.
		for(int i=0;i<NearbyVehicles->Count();i++)
		{
			Vehicle* CurrentVehicle=(*NearbyVehicles)[i];
			if(CurrentVehicle->AssignedSet==NULL){CurrentSet->AddVehicle(CurrentVehicle);}
		}
		if(CurrentSet->Count()>0){AnonymitySets.PushObj(CurrentSet);}//We must remember to register this anonymity set in the global record so the simulator can claculate anonymity stats properly.
		else{delete CurrentSet;}//If the anonymity set is empty, we remove it.
		delete NearbyVehicles;//We no longer need this structure. Note that the objects referenced in the structure belong to the global vehicle roster, so it is not our responsibility to delete it.
	}
	return true;
}
bool DummyEventProtocol::SimulationTick()
{
	//Outermost loop cycles through all anonymity sets, until the simulation reaches the assignment point for that set and builds the list of vehicles.
	for(int i=0;i<AnonymitySets.Count();i++)
	{
		AnonymitySet* CurrentSet=AnonymitySets[i];
		if(SimulationTime==CurrentSet->k_assign_t)
		{
			//when the assignment point is reached, all vehicles in range that are not already part of a set are added.
			if(OnTheFly)
			{
				LogTraffic(&MainTransmitter,NOMINATE);//In the case of on-the-fly assignment, the transmitter will first nominate the group founder.
				//This loop finds a random vehicle within the simulation to act as the announcer.
				Vehicle* Announcer=NULL;
				for(int Attempts=1;Attempts<=ON_THE_FLY_SELECT_ANNOUNCER_ATTEMPTS;Attempts++)
				{
					Announcer=Vehicles[RandInt(0,VehicleMax-1)];
					if(Announcer->CurrentlyWithinSimulation()&&Announcer->AssignedSet==NULL){break;}
					if(Attempts==ON_THE_FLY_SELECT_ANNOUNCER_ATTEMPTS){Announcer=NULL;}
				}
				if(Announcer==NULL)
				{
					cerr<<"WARNING: No On-the-Fly announcer could be selected at t="<<SimulationTime<<"!"<<endl;
					continue;
				}
				//cerr<<"ANNOUNCER: ("<<Announcer->x<<","<<Announcer->y<<")";
				CurrentSet->Announcer=Announcer;
				CurrentSet->k_assign_x=CurrentSet->Announcer->x;
				CurrentSet->k_assign_y=CurrentSet->Announcer->y;//We also need to change the position of the anonymity set to the announcer's current location.
			}
			//Otherwise, the transmitter acts as the group founder, and no nomination is needed because the transmitter can announce the group immediately.
			LogTraffic(CurrentSet->Announcer,ANNOUNCEMENT);
			ArrayList<Vehicle*>* AnonymityCandidates=GetVehiclesInRange(CurrentSet->Announcer);
			//cerr<<":"<<AnonymityCandidates->Count()<<endl;
			for(int io=0;io<AnonymityCandidates->Count();)
			{
				Vehicle* CurrentVehicle=(*AnonymityCandidates)[io];
				if(CurrentVehicle->AssignedSet==NULL)
				{
					if(CurrentVehicle!=CurrentSet->Announcer){LogTraffic(CurrentVehicle,JOIN);}//All vehicles that wish to join send a confirmation packet, regardless of whether the group founder accepts them.
					io++;
				}
				else{AnonymityCandidates->Remove(io);}
			}
			if(MaxVehiclesInSet>0)
			{
				//For as many cars as exceed the maximum allowed vehicles in the set, the farthest one is removed.
				for(int VehiclesToRemove=AnonymityCandidates->Count()-MaxVehiclesInSet;VehiclesToRemove>0;VehiclesToRemove--)
				{
					float FarthestDistanceSquared=0;
					Vehicle* FarthestVehicle;
					for(int io=0;io<AnonymityCandidates->Count();io++)
					{
						Vehicle* CheckVehicle=(*AnonymityCandidates)[io];
						float XDist=CurrentSet->k_assign_x-CheckVehicle->x;
						float YDist=CurrentSet->k_assign_y-CheckVehicle->y;
						float DistSqr=XDist*XDist+YDist*YDist;
						if(DistSqr>=FarthestDistanceSquared)
						{
							FarthestVehicle=CheckVehicle;
							FarthestDistanceSquared=DistSqr;
						}
					}
					AnonymityCandidates->Remove(FarthestVehicle);
				}
			}
			//If only one vehicle participates, the anonymous set is invalid, and the participating vehicle is free to join a later group.
			if(AnonymityCandidates->Count()>1)
			{
				//The announcer will only announce confirmations for those vehicles which were not omitted due to the set size minimum or maximum.
				for(int io=0;io<AnonymityCandidates->Count();io++)
				{
					Vehicle* CurrentVehicle=(*AnonymityCandidates)[io];
					if(Vehicles.IndexOf(CurrentVehicle)==8)
					{
						//cerr<<"CONFIRM!"<<endl;
					}
					CurrentSet->AddVehicle(CurrentVehicle);
					if(CurrentVehicle!=CurrentSet->Announcer){LogTraffic(CurrentSet->Announcer,JOIN_CONFIRMATION);}
				}
			}
			delete AnonymityCandidates;
		}
	}
	LogApplicationTraffic(&MainTransmitter);//Even if the RSU is not the group founder, messages are sent there.
	return true;
}