class PlayerPawn : Actor native
{
	
	native int			crouchsprite;
	native int			MaxHealth;
	native int			BonusHealth;
	native int			MugShotMaxHealth;
	native int			RunHealth;
	native int			PlayerFlags;
	native Inventory	InvFirst;		// first inventory item displayed on inventory bar
	native Inventory	InvSel;			// selected inventory item
	native Name 		SoundClass;		// Sound class
	native Name 		Face;			// Doom status bar face (when used)
	native Name 		Portrait;
	native Name 		Slot[10];
	native double 		HexenArmor[5];
	native uint8		ColorRangeStart;	// Skin color range
	native uint8		ColorRangeEnd;

	// [GRB] Player class properties
	native double		JumpZ;
	native double		GruntSpeed;
	native double		FallingScreamMinSpeed, FallingScreamMaxSpeed;
	native double		ViewHeight;
	native double		ForwardMove1, ForwardMove2;
	native double		SideMove1, SideMove2;
	native TextureID	ScoreIcon;
	native int			SpawnMask;
	native Name			MorphWeapon;
	native double		AttackZOffset;			// attack height, relative to player center
	native double		UseRange;				// [NS] Distance at which player can +use
	native double		AirCapacity;			// Multiplier for air supply underwater.
	native Class<Actor> FlechetteType;
	native color 		DamageFade;				// [CW] Fades for when you are being damaged.
	native double		ViewBob;				// [SP] ViewBob Multiplier
	native double		FullHeight;

	meta Name HealingRadiusType;
	meta Name InvulMode;
	
	Property prefix: Player;
	Property HealRadiusType: HealingradiusType;
	Property InvulnerabilityMode: InvulMode;
	
	Default
	{
		Health 100;
		Radius 16;
		Height 56;
		Mass 100;
		Painchance 255;
		Speed 1;
		+SOLID
		+SHOOTABLE
		+DROPOFF
		+PICKUP
		+NOTDMATCH
		+FRIENDLY
		+SLIDESONWALLS
		+CANPASS
		+CANPUSHWALLS
		+FLOORCLIP
		+WINDTHRUST
		+TELESTOMP
		+NOBLOCKMONST
		Player.AttackZOffset 8;
		Player.JumpZ 8;
		Player.GruntSpeed 12;
		Player.FallingScreamSpeed 35,40;
		Player.ViewHeight 41;
		Player.UseRange 64;
		Player.ForwardMove 1,1;
		Player.SideMove 1,1;
		Player.ColorRange 0,0;
		Player.SoundClass "player";
		Player.DamageScreenColor "ff 00 00";
		Player.MugShotMaxHealth 0;
		Player.FlechetteType "ArtiPoisonBag3";
		Player.AirCapacity 1;
		Player.ViewBob 1;
		Obituary "$OB_MPDEFAULT";
	}
	
	virtual void PlayIdle ()
	{
		if (InStateSequence(CurState, SeeState))
			SetState (SpawnState);
	}

	virtual void PlayRunning ()
	{
		if (InStateSequence(CurState, SpawnState) && SeeState != NULL)
			SetState (SeeState);
	}
	
	virtual void PlayAttacking ()
	{
		if (MissileState != null) SetState (MissileState);
	}

	virtual void PlayAttacking2 ()
	{
		if (MeleeState != null) SetState (MeleeState);
	}
	
	virtual void MorphPlayerThink()
	{
	}
	
	virtual void OnRespawn()
	{
		if (sv_respawnprotect && (multiplayer || alwaysapplydmflags))
		{
			let invul = Powerup(Spawn("PowerInvulnerable"));
			invul.EffectTics = 3 * TICRATE;
			invul.BlendColor = 0;			// don't mess with the view
			invul.bUndroppable = true;		// Don't drop this
			bRespawnInvul = true;			// [RH] special effect
		}
	}
	
	override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack)
	{
		if (victim.player != player && victim.IsTeammate(self))
		{
			victim = self;
			return String.Format("$OB_FRIENDLY%c", random[Obituary](49, 53));
		}
		else
		{
			if (mod == 'Telefrag') return "$OB_MPTELEFRAG";

			String message;
			if (inflictor != NULL)
			{
				message = inflictor.GetObituary(victim, inflictor, mod, playerattack);
			}
			if (message.Length() == 0 && playerattack && player.ReadyWeapon != NULL)
			{
				message = player.ReadyWeapon.GetObituary(victim, inflictor, mod, playerattack);
			}
			if (message.Length() == 0)
			{
				if (mod == 'BFGSplash') return "$OB_MPBFG_SPLASH";
				if (mod == 'Railgun') return "$OB_RAILGUN";
				message = Obituary;
			}
			return message;
		}
	}
	
	// This is for SBARINFO.
	clearscope int, int GetEffectTicsForItem(class<Inventory> item) const 
	{
		let pg = (class<PowerupGiver>)(item);
		if (pg != null)
		{
			let powerupType = (class<Powerup>)(GetDefaultByType(pg).PowerupType);
			let powerup = Powerup(FindInventory(powerupType));
			if(powerup != null) 
			{
				let maxtics = GetDefaultByType(pg).EffectTics;
				if (maxtics == 0) maxtics = powerup.default.EffectTics;
				return powerup.EffectTics, maxtics;
			}
		}
		return -1, -1;
	}

	native clearscope int GetMaxHealth(bool withupgrades = false) const;
	native bool ResetAirSupply (bool playgasp = false);
	native void CheckWeaponSwitch(class<Inventory> item);
	native clearscope static String GetPrintableDisplayName(Class<Actor> cls);

}

class PlayerChunk : PlayerPawn
{
	Default
	{
		+NOSKIN
		-SOLID
		-SHOOTABLE
		-PICKUP
		-NOTDMATCH
		-FRIENDLY
		-SLIDESONWALLS
		-CANPUSHWALLS
		-FLOORCLIP
		-WINDTHRUST
		-TELESTOMP
	}
}

class PSprite : Object native play
{
	enum PSPLayers
	{
		STRIFEHANDS = -1,
		WEAPON = 1,
		FLASH = 1000,
		TARGETCENTER = 0x7fffffff - 2,
		TARGETLEFT,
		TARGETRIGHT,
	};

	native readonly State CurState; 
	native Actor Caller;
	native readonly PSprite Next;
	native readonly PlayerInfo Owner;
	native SpriteID Sprite;
	native int Frame;
	native readonly int ID;
	native Bool processPending;
	native double x;
	native double y;
	native double oldx;
	native double oldy;
	native Bool firstTic;
	native int Tics;
	native bool bAddWeapon;
	native bool bAddBob;
	native bool bPowDouble;
	native bool bCVarFast;
	native bool bFlip;	
	
	native void SetState(State newstate, bool pending = false);

}

enum EPlayerState
{
	PST_LIVE,	// Playing or camping.
	PST_DEAD,	// Dead on the ground, view follows killer.
	PST_REBORN,	// Ready to restart/respawn???
	PST_ENTER,	// [BC] Entered the game
	PST_GONE	// Player has left the game
}

struct PlayerInfo native play	// this is what internally is known as player_t
{
	// technically engine constants but the only part of the playsim using them is the player.
	const NOFIXEDCOLORMAP = -1;
	const NUMCOLORMAPS = 32;
	
	native PlayerPawn mo;
	native uint8 playerstate;
	native uint original_oldbuttons;
	native readonly Class<PlayerPawn> cls;
	native float DesiredFOV;
	native float FOV;
	native double viewz;
	native double viewheight;
	native double deltaviewheight;
	native double bob;
	native vector2 vel;
	native bool centering;
	native uint8 turnticks;
	native bool attackdown;
	native bool usedown;
	native uint oldbuttons;
	native int health;
	native int inventorytics;
	native uint8 CurrentPlayerClass;
	native int frags[MAXPLAYERS];
	native int fragcount;
	native int lastkilltime;
	native uint8 multicount;
	native uint8 spreecount;
	native uint16 WeaponState;
	native Weapon ReadyWeapon;
	native Weapon PendingWeapon;
	native PSprite psprites;
	native int cheats;
	native int timefreezer;
	native int16 refire;
	native int16 inconsistent;
	native bool waiting;
	native int killcount;
	native int itemcount;
	native int secretcount;
	native int damagecount;
	native int bonuscount;
	native int hazardcount;
	native int hazardinterval;
	native Name hazardtype;
	native int poisoncount;
	native Name poisontype;
	native Name poisonpaintype;
	native Actor poisoner;
	native Actor attacker;
	native int extralight;
	native int16 fixedcolormap;
	native int16 fixedlightlevel;
	native int morphtics;
	native Class<PlayerPawn>MorphedPlayerClass;
	native int MorphStyle;
	native Class<Actor> MorphExitFlash;
	native Class<Weapon> PremorphWeapon;
	native int chickenPeck;
	native int jumpTics;
	native bool onground;
	native int respawn_time;
	native Actor camera;
	native int air_finished;
	native Name LastDamageType;
	native Actor MUSINFOactor;
	native int8 MUSINFOtics;
	native bool settings_controller;
	native int8 crouching;
	native int8 crouchdir;
	native Bot bot;
	native float BlendR;
	native float BlendG;
	native float BlendB;
	native float BlendA;
	native String LogText;
	native double MinPitch;
	native double MaxPitch;
	native double crouchfactor;
	native double crouchoffset;
	native double crouchviewdelta;
	native Actor ConversationNPC;
	native Actor ConversationPC;
	native double ConversationNPCAngle;
	native bool ConversationFaceTalker;
	//native WeaponSlots weapons; <- defined internally

/* these are not doable yet
ticcmd_t	cmd;
usercmd_t	original_cmd;
*/
	

	native bool MorphPlayer(playerinfo p, Class<PlayerPawn> spawntype, int duration, int style, Class<Actor> enter_flash = null, Class<Actor> exit_flash = null);
	native bool UndoPlayerMorph(playerinfo player, int unmorphflag = 0, bool force = false);
	native bool PoisonPlayer(Actor poisoner, Actor source, int poison);
	native void PoisonDamage(Actor source, int damage, bool playPainSound);
	native void SetPsprite(int id, State stat, bool pending = false);
	native void SetSafeFlash(Weapon weap, State flashstate, int index);
	native PSprite GetPSprite(int id) const;
	native PSprite FindPSprite(int id) const;
	native void SetLogNumber (int text);
	native void SetLogText (String text);
	native void DropWeapon();
	native void BringUpWeapon();

	native String GetUserName() const;
	native Color GetColor() const;
	native int GetColorSet() const;
	native int GetPlayerClassNum() const;
	native int GetSkin() const;
	native bool GetNeverSwitch() const;
	native int GetGender() const;
	native int GetTeam() const;
	native float GetAutoaim() const;
	native void SetFOV(float fov);
}

struct PlayerClass native
{
	native class<Actor> Type;
	native uint Flags;
	native Array<int> Skins;
	
	native bool CheckSkin(int skin);
	native void EnumColorsets(out Array<int> data);
	native Name GetColorsetName(int setnum);
}

struct PlayerSkin native
{
	native readonly String		SkinName;
	native readonly String		Face;
	native readonly uint8		gender;
	native readonly uint8		range0start;
	native readonly uint8		range0end;
	native readonly bool		othergame;
	native readonly Vector2		Scale;
	native readonly int			sprite;
	native readonly int			crouchsprite;
	native readonly int			namespc;
};

struct Team native
{
	const NoTeam = 255;
	const Max = 16;
	native String mName;
}
