
struct SectorPortal native play
{
	enum EType
	{
		TYPE_SKYVIEWPOINT = 0,		// a regular skybox
		TYPE_STACKEDSECTORTHING,	// stacked sectors with the thing method
		TYPE_PORTAL,				// stacked sectors with Sector_SetPortal
		TYPE_LINKEDPORTAL,			// linked portal (interactive)
		TYPE_PLANE,					// EE-style plane portal (not implemented in SW renderer)
		TYPE_HORIZON,				// EE-style horizon portal (not implemented in SW renderer)
	};

	enum EFlags
	{
		FLAG_SKYFLATONLY = 1,			// portal is only active on skyflatnum
		FLAG_INSKYBOX = 2,				// to avoid recursion
	};

	native int mType;
	native int mFlags;
	native uint mPartner;
	native int mPlane;
	native Sector mOrigin;
	native Sector mDestination;
	native Vector2 mDisplacement;
	native double mPlaneZ;
	native Actor mSkybox;
	
	native static uint GetSkyboxPortal(Actor actor);
};


struct Vertex native play
{
	native readonly Vector2 p;
	native int Index();
}

struct Side native play
{
	enum ETexpart
	{
		top=0,
		mid=1,
		bottom=2
	};
	
	enum EColorPos
	{
		walltop = 0,
		wallbottom = 1
	}
	
	enum EWallFlags
	{
		WALLF_ABSLIGHTING	 = 1,	// Light is absolute instead of relative
		WALLF_NOAUTODECALS	 = 2,	// Do not attach impact decals to this wall
		WALLF_NOFAKECONTRAST = 4,	// Don't do fake contrast for this wall in side_t::GetLightLevel
		WALLF_SMOOTHLIGHTING = 8,   // Similar to autocontrast but applies to all angles.
		WALLF_CLIP_MIDTEX	 = 16,	// Like the line counterpart, but only for this side.
		WALLF_WRAP_MIDTEX	 = 32,	// Like the line counterpart, but only for this side.
		WALLF_POLYOBJ		 = 64,	// This wall belongs to a polyobject.
		WALLF_LIGHT_FOG      = 128,	// This wall's Light is used even in fog.
	};


	native readonly Sector sector;			// Sector the SideDef is facing.
	//DBaseDecal*	AttachedDecals;	// [RH] Decals bound to the wall
	native readonly Line linedef;
	native int16	Light;
	native uint8	Flags;

	native TextureID GetTexture(int which);
	native void SetTexture(int which, TextureID tex);
	native void SetTextureXOffset(int which, double offset);
	native double GetTextureXOffset(int which);
	native void AddTextureXOffset(int which, double delta);
	native void SetTextureYOffset(int which, double offset);
	native double GetTextureYOffset(int which);
	native void AddTextureYOffset(int which, double delta);
	native void SetTextureXScale(int which, double scale);
	native double GetTextureXScale(int which);
	native void MultiplyTextureXScale(int which, double delta);
	native void SetTextureYScale(int which, double scale);
	native double GetTextureYScale(int which);
	native void MultiplyTextureYScale(int which, double delta);
	native void SetSpecialColor(int tier, int position, Color scolor);
	//native DInterpolation *SetInterpolation(int position);
	//native void StopInterpolation(int position);

	native clearscope Vertex V1();
	native clearscope Vertex V2();

	native int Index();
	
	int GetUDMFInt(Name nm)
	{
		return Level.GetUDMFInt(LevelLocals.UDMF_Side, Index(), nm);
	}
	double GetUDMFFloat(Name nm)
	{
		return Level.GetUDMFFloat(LevelLocals.UDMF_Side, Index(), nm);
	}
	String GetUDMFString(Name nm)
	{
		return Level.GetUDMFString(LevelLocals.UDMF_Side, Index(), nm);
	}
	
};

struct Line native play
{
	enum ESide
	{
		front=0,
		back=1
	}

	enum ELineFlags
	{
		ML_BLOCKING					=0x00000001,	// solid, is an obstacle
		ML_BLOCKMONSTERS			=0x00000002,	// blocks monsters only
		ML_TWOSIDED					=0x00000004,	// backside will not be present at all if not two sided
		ML_DONTPEGTOP				= 0x00000008,	// upper texture unpegged
		ML_DONTPEGBOTTOM			= 0x00000010,	// lower texture unpegged
		ML_SECRET					= 0x00000020,	// don't map as two sided: IT'S A SECRET!
		ML_SOUNDBLOCK				= 0x00000040,	// don't let sound cross two of these
		ML_DONTDRAW 				= 0x00000080,	// don't draw on the automap
		ML_MAPPED					= 0x00000100,	// set if already drawn in automap
		ML_REPEAT_SPECIAL			= 0x00000200,	// special is repeatable
		ML_ADDTRANS					= 0x00000400,	// additive translucency (can only be set internally)

		// Extended flags
		ML_MONSTERSCANACTIVATE		= 0x00002000,	// [RH] Monsters (as well as players) can activate the line
		ML_BLOCK_PLAYERS			= 0x00004000,
		ML_BLOCKEVERYTHING			= 0x00008000,	// [RH] Line blocks everything
		ML_ZONEBOUNDARY				= 0x00010000,
		ML_RAILING					= 0x00020000,
		ML_BLOCK_FLOATERS			= 0x00040000,
		ML_CLIP_MIDTEX				= 0x00080000,	// Automatic for every Strife line
		ML_WRAP_MIDTEX				= 0x00100000,
		ML_3DMIDTEX					= 0x00200000,
		ML_CHECKSWITCHRANGE			= 0x00400000,
		ML_FIRSTSIDEONLY			= 0x00800000,	// activated only when crossed from front side
		ML_BLOCKPROJECTILE			= 0x01000000,
		ML_BLOCKUSE					= 0x02000000,	// blocks all use actions through this line
		ML_BLOCKSIGHT				= 0x04000000,	// blocks monster line of sight
		ML_BLOCKHITSCAN				= 0x08000000,	// blocks hitscan attacks
		ML_3DMIDTEX_IMPASS			= 0x10000000,	// [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING
	};


	native readonly vertex			v1, v2;		// vertices, from v1 to v2
	native readonly Vector2			delta;		// precalculated v2 - v1 for side checking
	native uint						flags;
	native uint						activation;	// activation type
	native int						special;
	native int						args[5];	// <--- hexen-style arguments (expanded to ZDoom's full width)
	native double					alpha;		// <--- translucency (0=invisible, FRACUNIT=opaque)
	native readonly Side			sidedef[2];
	native readonly double			bbox[4];	// bounding box, for the extent of the LineDef.
	native readonly Sector			frontsector, backsector;
	native int 						validcount;	// if == validcount, already checked
	native int						locknumber;	// [Dusk] lock number for special
	native readonly uint			portalindex;
	native readonly uint			portaltransferred;

	native readonly int		health;
	native readonly int		healthgroup;
	
	native bool isLinePortal();
	native bool isVisualPortal();
	native Line getPortalDestination();
	native int getPortalAlignment();
	native int Index();
	native bool Activate(Actor activator, int side, int type);
	native bool RemoteActivate(Actor activator, int side, int type, Vector3 pos);
	
	int GetUDMFInt(Name nm)
	{
		return Level.GetUDMFInt(LevelLocals.UDMF_Line, Index(), nm);
	}
	double GetUDMFFloat(Name nm)
	{
		return Level.GetUDMFFloat(LevelLocals.UDMF_Line, Index(), nm);
	}
	String GetUDMFString(Name nm)
	{
		return Level.GetUDMFString(LevelLocals.UDMF_Line, Index(), nm);
	}

    native clearscope int GetHealth();
    native void SetHealth(int newhealth);
}

struct SecPlane native play
{
	native Vector3 Normal;
	native double D;
	native double negiC;
	
	native bool isSlope() const;
	native int PointOnSide(Vector3 pos) const;
	native clearscope double ZatPoint (Vector2 v) const;
	native double ZatPointDist(Vector2 v, double dist) const;
	native bool isEqual(Secplane other) const;
	native void ChangeHeight(double hdiff);
	native double GetChangedHeight(double hdiff) const;
	native double HeightDiff(double oldd, double newd = 1e37) const;
	native double PointToDist(Vector2 xy, double z) const;
}

// This encapsulates all info Doom's original 'special' field contained - for saving and transferring.
struct SecSpecial play
{
	Name damagetype;
	int damageamount;
	short special;
	short damageinterval;
	short leakydamage;
	int Flags;
}

struct FColormap
{
	Color		LightColor;
	Color		FadeColor;
	uint8		Desaturation;
	uint8		BlendFactor;
	uint16		FogDensity;
}

struct Sector native play
{

	native readonly FColormap 	ColorMap;
	native readonly Color		SpecialColors[5];

	native Actor 		SoundTarget;

	native int16 		special;
	native int16 		lightlevel;
	native int16		seqType;	

	native int			sky;
	native Name			SeqName;	

	native readonly Vector2		centerspot;	
	native int 			validcount;	
	native Actor		thinglist;	

	native double		friction, movefactor;
	native int			terrainnum[2];

	// thinker_t for reversable actions
	native SectorEffect floordata;
	native SectorEffect ceilingdata;
	native SectorEffect lightingdata;

	enum EPlane
	{
		floor,
		ceiling,
		// only used for specialcolors array
		walltop,
		wallbottom,
		sprites
	};
	
	enum EInterpolationType
	{
		CeilingMove,
		FloorMove,
		CeilingScroll,
		FloorScroll
	};
	//Interpolation interpolations[4];

	native uint8 		soundtraversed;
	native int8 		stairlock;
	native int 			prevsec;
	native int	 		nextsec;

	native readonly Array<Line> lines;

	native readonly @secplane floorplane;
	native readonly @secplane ceilingplane;
	
	native readonly Sector		heightsec;

	native uint			bottommap, midmap, topmap;

	//struct msecnode_t *touching_thinglist;
	//struct msecnode_t *sectorportal_thinglist;

	native double 		gravity;	
	native Name 		damagetype;
	native int 			damageamount;
	native int16 		damageinterval;
	native int16 		leakydamage;

	native readonly uint16	ZoneNumber;

	native readonly int healthceiling;
	native readonly int healthfloor;
	native readonly int healthceilinggroup;
	native readonly int healthfloorgroup;
	
	enum ESectorMoreFlags
	{
		SECMF_FAKEFLOORONLY	= 2,	// when used as heightsec in R_FakeFlat, only copies floor
		SECMF_CLIPFAKEPLANES = 4,	// as a heightsec, clip planes to target sector's planes
		SECMF_NOFAKELIGHT	= 8,	// heightsec does not change lighting
		SECMF_IGNOREHEIGHTSEC= 16,	// heightsec is only for triggering sector actions
		SECMF_UNDERWATER		= 32,	// sector is underwater
		SECMF_FORCEDUNDERWATER= 64,	// sector is forced to be underwater
		SECMF_UNDERWATERMASK	= 32+64,
		SECMF_DRAWN			= 128,	// sector has been drawn at least once
		SECMF_HIDDEN			= 256,	// Do not draw on textured automap
	}
	native uint16		MoreFlags;
	
	enum ESectorFlags
	{
		SECF_SILENT			= 1,	// actors in sector make no noise
		SECF_NOFALLINGDAMAGE= 2,	// No falling damage in this sector
		SECF_FLOORDROP		= 4,	// all actors standing on this floor will remain on it when it lowers very fast.
		SECF_NORESPAWN		= 8,	// players can not respawn in this sector
		SECF_FRICTION		= 16,	// sector has friction enabled
		SECF_PUSH			= 32,	// pushers enabled
		SECF_SILENTMOVE		= 64,	// Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.) 
		SECF_DMGTERRAINFX	= 128,	// spawns terrain splash when inflicting damage
		SECF_ENDGODMODE		= 256,	// getting damaged by this sector ends god mode
		SECF_ENDLEVEL		= 512,	// ends level when health goes below 10
		SECF_HAZARD			= 1024,	// Change to Strife's delayed damage handling.
		SECF_NOATTACK		= 2048,	// monsters cannot start attacks in this sector.

		SECF_WASSECRET		= 1 << 30,	// a secret that was discovered
		SECF_SECRET			= 1 << 31,	// a secret sector

		SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD,
		SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET,	// not modifiable by Sector_ChangeFlags
		SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH,	// these flags originate from 'special and must be transferrable by floor thinkers
	}
	
	enum EMoveResult 
	{ 
		MOVE_OK, 
		MOVE_CRUSHED, 
		MOVE_PASTDEST
	};
	
	native uint			Flags;

	native SectorAction		SecActTarget;

	native internal uint		Portals[2];
	native readonly int			PortalGroup;

	native readonly int			sectornum;

	native int Index();

	native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0);
	native double, Sector, F3DFloor NextLowestFloorAt(double x, double y, double z, int flags = 0, double steph = 0);

	native void RemoveForceField();
	native static clearscope Sector PointInSector(Vector2 pt);

	native bool PlaneMoving(int pos);
	native int GetFloorLight();
	native int GetCeilingLight();
	native Sector GetHeightSec();
	native void TransferSpecial(Sector model);
	native void GetSpecial(out SecSpecial spec);
	native void SetSpecial( SecSpecial spec);
	native int GetTerrain(int pos);
	native void CheckPortalPlane(int plane);
	native double, Sector HighestCeilingAt(Vector2 a);
	native double, Sector LowestFloorAt(Vector2 a);
	native double, double GetFriction(int plane);

	native void SetXOffset(int pos, double o);
	native void AddXOffset(int pos, double o);
	native double GetXOffset(int pos);
	native void SetYOffset(int pos, double o);
	native void AddYOffset(int pos, double o);
	native double GetYOffset(int pos, bool addbase = true);
	native void SetXScale(int pos, double o);
	native double GetXScale(int pos);
	native void SetYScale(int pos, double o);
	native double GetYScale(int pos);
	native void SetAngle(int pos, double o);
	native double GetAngle(int pos, bool addbase = true);
	native void SetBase(int pos, double y, double o);
	native void SetAlpha(int pos, double o);
	native double GetAlpha(int pos);
	native int GetFlags(int pos);
	native int GetVisFlags(int pos);
	native void ChangeFlags(int pos, int And, int Or);
	native int GetPlaneLight(int pos);
	native void SetPlaneLight(int pos, int level);
	native void SetColor(color c, int desat = 0);
	native void SetFade(color c);
	native void SetFogDensity(int dens);
	native double GetGlowHeight(int pos);
	native color GetGlowColor(int pos);
	native void SetGlowHeight(int pos, double height);
	native void SetGlowColor(int pos, color color);
	native void SetSpecialColor(int pos, color color);
	
	native TextureID GetTexture(int pos);
	native void SetTexture(int pos, TextureID tex, bool floorclip = true);
	native double GetPlaneTexZ(int pos);
	native void SetPlaneTexZ(int pos, double val, bool dirtify = false);	// This mainly gets used by init code. The only place where it must set the vertex to dirty is the interpolation code.
	native void ChangeLightLevel(int newval);
	native void SetLightLevel(int newval);
	native int GetLightLevel();
	native void AdjustFloorClip();
	native bool IsLinked(Sector other, bool ceiling);

	native bool PortalBlocksView(int plane);
	native bool PortalBlocksSight(int plane);
	native bool PortalBlocksMovement(int plane);
	native bool PortalBlocksSound(int plane);
	native bool PortalIsLinked(int plane);
	native void ClearPortal(int plane);
	native double GetPortalPlaneZ(int plane);
	native Vector2 GetPortalDisplacement(int plane);
	native int GetPortalType(int plane);
	native int GetOppositePortalGroup(int plane);
	native double CenterFloor();
	native double CenterCeiling();

	native int MoveFloor(double speed, double dest, int crush, int direction, bool hexencrush, bool instant = false);
	native int MoveCeiling(double speed, double dest, int crush, int direction, bool hexencrush);

	native Sector NextSpecialSector(int type, Sector prev);
	native double, Vertex FindLowestFloorSurrounding();
	native double, Vertex FindHighestFloorSurrounding();
	native double, Vertex FindNextHighestFloor();
	native double, Vertex FindNextLowestFloor();
	native double, Vertex FindLowestCeilingSurrounding();
	native double, Vertex FindHighestCeilingSurrounding();
	native double, Vertex FindNextLowestCeiling();	
	native double, Vertex FindNextHighestCeiling();

	native double FindShortestTextureAround();
	native double FindShortestUpperAround();
	native Sector FindModelFloorSector(double floordestheight);
	native Sector FindModelCeilingSector(double floordestheight);
	native int FindMinSurroundingLight(int max);
	native double, Vertex FindLowestCeilingPoint();
	native double, Vertex FindHighestFloorPoint();

	native void SetEnvironment(String env);
	native void SetEnvironmentID(int envnum);

	native SeqNode StartSoundSequenceID (int chan, int sequence, int type, int modenum, bool nostop = false);
	native SeqNode StartSoundSequence (int chan, Name seqname, int modenum);
	native SeqNode CheckSoundSequence (int chan);
	native void StopSoundSequence(int chan);
	native bool IsMakingLoopingSound ();
	
	 bool isSecret()
	 {
		 return !!(Flags & SECF_SECRET);
	 }

	 bool wasSecret()
	 {
		 return !!(Flags & SECF_WASSECRET);
	 }

	 void ClearSecret()
	 {
		 Flags &= ~SECF_SECRET;
	 }
	 
	int GetUDMFInt(Name nm)
	{
		return Level.GetUDMFInt(LevelLocals.UDMF_Sector, Index(), nm);
	}
	double GetUDMFFloat(Name nm)
	{
		return Level.GetUDMFFloat(LevelLocals.UDMF_Sector, Index(), nm);
	}
	String GetUDMFString(Name nm)
	{
		return Level.GetUDMFString(LevelLocals.UDMF_Sector, Index(), nm);
	}

	//===========================================================================
	//
	//
	//
	//===========================================================================

	bool TriggerSectorActions(Actor thing, int activation)
	{
		let act = SecActTarget;
		bool res = false;

		while (act != null)
		{
			Actor next = act.tracer;

			if (act.TriggerAction(thing, activation))
			{
				if (act.bStandStill)
				{
					act.Destroy();
				}
				res = true;
			}
			act = SectorAction(next);
		}
		return res;
	}

	
    native clearscope int GetHealth(SectorPart part);
    native void SetHealth(SectorPart part, int newhealth);
}

class SectorTagIterator : Object native
{
	native static SectorTagIterator Create(int tag, line defline = null);
	native int Next();
	native int NextCompat(bool compat, int secnum);
}

class LineIdIterator : Object native
{
	native static LineIdIterator Create(int tag);
	native int Next();
}
