 
class RandomObjectsLiquidsHandler : EventHandler
{

    private void setupObjectsLiquids(bool bwaterjet, bool brat)
    {
        for (int i = 0; i < level.sectors.size(); i += 1)
	{
		Sector sec = level.sectors[i];

                Vector2 lowest = (double.infinity, double.infinity);
                Vector2 highest = (-double.infinity, -double.infinity);
                for (int l = 0; l < sec.lines.size(); l++)
		{
                    Vector2 verts[2];
                    verts[0] = sec.lines[l].v1.p;
                    verts[1] = sec.lines[l].v2.p;
                   
                    for (int v = 0; v < 2; v++)
		    {
                        Vector2 vert = verts[v];
                       
                        if (vert.x < lowest.x ) lowest.x  = vert.x;
                        if (vert.y < lowest.y ) lowest.y  = vert.y;
                        if (vert.x > highest.x) highest.x = vert.x;
                        if (vert.y > highest.y) highest.y = vert.y;
                    }
                }

		int objecttype = 0;
		string objectactor = "DukeWaterJet";
		int spawnDist = 128;
		int sectorLimit = random[RIDMAP](1,3);
		int clusterLimitMax = 1;
		int extraobjects = 0;
		int failChanceBase = 224;
		if(bwaterjet) spawnObjectsLiquids(objecttype, objectactor, spawnDist, sectorLimit, clusterLimitMax, extraobjects, failChanceBase, sec, lowest, highest);
		objecttype = 2;
		objectactor = "DukeSlimeJet";
		if(bwaterjet) spawnObjectsLiquids(objecttype, objectactor, spawnDist, sectorLimit, clusterLimitMax, extraobjects, failChanceBase, sec, lowest, highest);
		objecttype = 3;
		if(bwaterjet) spawnObjectsLiquids(objecttype, objectactor, spawnDist, sectorLimit, clusterLimitMax, extraobjects, failChanceBase, sec, lowest, highest);

		objecttype = 1;
		objectactor = "DukeRat";
		spawnDist = 32;
		sectorLimit = random[RIDMAP](1,6);
		clusterLimitMax = 3;
		extraobjects = 8;
		failChanceBase = 224;
		if(brat) spawnObjectsLiquids(objecttype, objectactor, spawnDist, sectorLimit, clusterLimitMax, extraobjects, failChanceBase, sec, lowest, highest);
		objecttype = 2;
		if(brat) spawnObjectsLiquids(objecttype, objectactor, spawnDist, sectorLimit, clusterLimitMax, extraobjects, failChanceBase, sec, lowest, highest);
		objecttype = 3;
		if(brat) spawnObjectsLiquids(objecttype, objectactor, spawnDist, sectorLimit, clusterLimitMax, extraobjects, failChanceBase, sec, lowest, highest);
        }
    }

    private void spawnObjectsLiquids(int objecttype, string objectactor, int spawnDist, int sectorLimit, int clusterLimitMax, int extraobjects, int failChanceBase, Sector sec, Vector2 lowest, Vector2 highest)
    {
		int sectorQ = 0;
		int clusterQ = 0;
		int clusterLimit = random[RIDMAP](1,clusterLimitMax);
		int spawnStep = 1;
		int failChance = failChanceBase;
                Vector2 start = (lowest.x+spawnDist*spawnStep, lowest.y+spawnDist*spawnStep);

                  for (double x = start.x; x < (highest.x-spawnDist); x += spawnDist * spawnStep)
		  {
                    for (double y = start.y; y < (highest.y-spawnDist); y += spawnDist * spawnStep)
		    {
                        if (Level.pointInSector((x, y)) == sec)
			{
                            if ( checkTexture(objecttype, sec.GetTexture(Sector.floor)) )
			    {
				if (random[RIDMAPPROB](1,256)>failChance && checkEdgeDistance(objecttype,x,y,spawnDist)) {
                                	let a = Actor.spawn(objectactor,  (x, y, sec.floorplane.zAtPoint((x, y))));
					if ( !a.TestMobjLocation() ) {
						a.Destroy();
					} else {
						for(int i=0;i<extraobjects;i++) {
							int extraobjectsdistX = random[RIDMAP](0, 15)*random[RIDMAP](-1,1);
							int extraobjectsdistY = random[RIDMAP](0, 15)*random[RIDMAP](-1,1);
							if(random[RIDMAPPROB](1,256)>128) {
								let aextra = Actor.spawn(objectactor,  (x+extraobjectsdistX, y+extraobjectsdistY, sec.floorplane.zAtPoint((x+extraobjectsdistX, y+extraobjectsdistY))));
								if ( !aextra.TestMobjLocation() ) aextra.Destroy();
							}
						}

						clusterQ++;
						sectorQ++;
						if(clusterQ==clusterLimit) {
							clusterQ = 0;
							clusterLimit = random[RIDMAP](1,clusterLimitMax);
							spawnStep = spawnStep + 1;
							failChance = failChanceBase;
						} else {
							spawnStep = 1;
							failChance = 0;
						}
						if(sectorQ==sectorLimit) {
							x = highest.x;
							y = highest.y;
						}
					}
				}
                            } else {
				clusterQ = 0;
				clusterLimit = random[RIDMAP](1,clusterLimitMax);
				spawnStep = 1;
				failChance = failChanceBase;
			    }
                        }
                    }
                  }
    }

    private bool checkTexture(int objecttype, TextureID tex)
    {
	if(objecttype==0) {
		if (tex == TexMan.checkForTexture("FWATER1", TexMan.Type_Any) || tex == TexMan.checkForTexture("FWATER2", TexMan.Type_Any) || tex == TexMan.checkForTexture("FWATER3", TexMan.Type_Any) || tex == TexMan.checkForTexture("FWATER4", TexMan.Type_Any)) return true;
	}
	else if (objecttype==1) {
		if (tex == TexMan.checkForTexture("NUKAGE1", TexMan.Type_Any) || tex == TexMan.checkForTexture("NUKAGE2", TexMan.Type_Any) || tex == TexMan.checkForTexture("NUKAGE3", TexMan.Type_Any)) return true;
	}
	else if (objecttype==2) {
		if (tex == TexMan.checkForTexture("SLIME01", TexMan.Type_Any) || tex == TexMan.checkForTexture("SLIME02", TexMan.Type_Any) || tex == TexMan.checkForTexture("SLIME03", TexMan.Type_Any) || tex == TexMan.checkForTexture("SLIME04", TexMan.Type_Any)) return true;
	}
	else if (objecttype==3) {
		if (tex == TexMan.checkForTexture("SLIME05", TexMan.Type_Any) || tex == TexMan.checkForTexture("SLIME06", TexMan.Type_Any) || tex == TexMan.checkForTexture("SLIME07", TexMan.Type_Any) || tex == TexMan.checkForTexture("SLIME08", TexMan.Type_Any)) return true;
	}
	return false;
    }

    private bool checkEdgeDistance(int objecttype, double x, double y, int spawnDist)
    {
	if(objecttype==0) {
		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("FWATER1", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER1", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER1", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER1", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER1", TexMan.Type_Any)) return false;
		}

		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("FWATER2", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER2", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER2", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER2", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER2", TexMan.Type_Any)) return false;
		}

		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("FWATER3", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER3", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER3", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER3", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER3", TexMan.Type_Any)) return false;
		}

		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("FWATER4", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER4", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER4", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER4", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("FWATER4", TexMan.Type_Any)) return false;
		}
	}
	else if (objecttype==1) {
		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("NUKAGE1", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE1", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE1", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE1", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE1", TexMan.Type_Any)) return false;
		}

		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("NUKAGE2", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE2", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE2", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE2", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE2", TexMan.Type_Any)) return false;
		}

		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("NUKAGE3", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE3", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE3", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE3", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("NUKAGE3", TexMan.Type_Any)) return false;
		}
	}
	else if (objecttype==2) {
		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("SLIME01", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME01", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME01", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME01", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME01", TexMan.Type_Any)) return false;
		}

		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("SLIME02", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME02", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME02", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME02", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME02", TexMan.Type_Any)) return false;
		}

		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("SLIME03", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME03", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME03", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME03", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME03", TexMan.Type_Any)) return false;
		}

		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("SLIME04", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME04", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME04", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME04", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME04", TexMan.Type_Any)) return false;
		}
	}
	else if (objecttype==3) {
		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("SLIME05", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME05", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME05", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME05", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME05", TexMan.Type_Any)) return false;
		}

		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("SLIME06", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME06", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME06", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME06", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME06", TexMan.Type_Any)) return false;
		}

		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("SLIME07", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME07", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME07", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME07", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME07", TexMan.Type_Any)) return false;
		}

		if (Level.pointInSector((x, y)).GetTexture(Sector.floor) == TexMan.checkForTexture("SLIME08", TexMan.Type_Any)) {
			if (Level.pointInSector((x, y+spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME08", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x, y-spawnDist)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME08", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x+spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME08", TexMan.Type_Any)) return false;
			if (Level.pointInSector((x-spawnDist, y)).GetTexture(Sector.floor) != TexMan.checkForTexture("SLIME08", TexMan.Type_Any)) return false;
		}
	}
	return true;
    }
   
    override void worldLoaded(WorldEvent e) {
	bool bwaterjet = true;
	bool brat = true;

	if(d3d_waterjet==1) bwaterjet = false;
	if(d3d_rat==1) brat = false;

	setupObjectsLiquids(bwaterjet, brat);
    }

}