/*

	Copyright (C) 2004 Michael Liebscher
	Copyright (C) 2000-2002 by DarkOne the Hacker

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

/*
 *	wolf_player.c:  Wolfenstein3-D player management.
 *	
 *	Author:	Michael Liebscher <johnnycanuck@users.sourceforge.net>
 *	Date:	2004 
 *
 *	Acknowledgement:
 *	Portion of this code was derived from NewWolf, and was originally
 *	written by DarkOne the Hacker. 
 *
 */

#include "../wolfiphone.h"

player_t Player; // player struct (pos, health etc...)


#define PLAYERSIZE	MINDIST	// player radius



struct atkinf
{
	char tics, attack, frame; // attack is 1 for gun, 2 for knife

} attackinfo[ 4 ][ 14 ] = // 4 guns, 14 frames max for every gun!
{
	{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} },
	{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} },
	{ {6,0,1},{6,1,2},{6,3,3},{6,-1,4} },
	{ {6,0,1},{6,1,2},{6,4,3},{6,-1,4} },
};


/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns: true if player can change weapons, otherwise false.
 
 Notes: 

-----------------------------------------------------------------------------
*/
PRIVATE _boolean PL_ChangeWeapon( player_t *self, int weapon )
{
	unsigned itemflag;
	
	itemflag = ITEM_WEAPON_1 << weapon;

	if( self->ammo[ AMMO_BULLETS ] == 0 && weapon != WEAPON_KNIFE )
	{
		Com_Printf("Not enough ammo.\n");
		return false;
	}

	if( ! (self->items & itemflag) ) 
	{
		Com_Printf( "No weapon.\n" );
		return false;
	}

	self->weapon = 
	self->pendingweapon = weapon;

	self->attackframe = 
	self->attackcount = 
	self->weaponframe = 0;

	return true;
}


/*
-----------------------------------------------------------------------------
 Function: Called if player pressed USE button
 
 Parameters:
 
 Returns: returns true if player used something
 
 Notes: 

-----------------------------------------------------------------------------
*/
PRIVATE _boolean PL_Use( player_t *self, LevelData_t *lvl )
{
	int x, y, dir;

	dir = Get4dir( FINE2RAD( self->position.angle ) );
	x = self->tilex + dx4dir[ dir ];
	y = self->tiley + dy4dir[ dir ];

	if( lvl->tilemap[ x ][ y ] & DOOR_TILE )
	{
		return Door_TryUse( &lvl->Doors.DoorMap[ x ][ y ], Player.items );
	}

	if( lvl->tilemap[ x ][ y ] & SECRET_TILE )
	{
		return PushWall_Push( x, y, dir );
	}

	if( lvl->tilemap[ x ][ y ] & ELEVATOR_TILE )
	{
		int newtex;
		
		switch( dir )
		{
			case dir4_east:
			case dir4_west:
				newtex = lvl->wall_tex_x[ x ][ y ] += 2;
				break;
				
			case dir4_north:
			case dir4_south:
				return false; // don't allow to press elevator rails
		}
		
		if( lvl->tilemap[ self->tilex ][ self->tiley ] & SECRETLEVEL_TILE )
		{
			self->playstate = ex_secretlevel;
		}
		else
		{
			self->playstate = ex_complete;
		}
		Sound_StartSound( NULL, 0, CHAN_BODY, Sound_RegisterSound( "lsfx/040.wav" ), 1, ATTN_NORM, 0 );
		
		iphoneStartIntermission( 0 );
		
		return true;
	}

	//Sound_StartSound( NULL, 0, CHAN_BODY, Sound_RegisterSound( "lsfx/020.wav" ), 1, ATTN_NORM, 0 );	
	return false;
}



#define STOPSPEED 0x0D00
#define FRICTION  0.25f
#define MAXMOVE 	(MINDIST*2-1)


/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns: returns true if move ok
 
 Notes: 

-----------------------------------------------------------------------------
*/
PRIVATE _boolean PL_TryMove( player_t *self, LevelData_t *lvl )
{
	int xl, yl, xh, yh, x, y;
	int d, n;

	xl = POS2TILE( Player.position.origin[ 0 ] - PLAYERSIZE );
	yl = POS2TILE( Player.position.origin[ 1 ] - PLAYERSIZE );
	xh = POS2TILE( Player.position.origin[ 0 ] + PLAYERSIZE );
	yh = POS2TILE( Player.position.origin[ 1 ] + PLAYERSIZE );

	// Cheching for solid walls:
	for( y = yl ; y <= yh ; ++y )
		for( x = xl ; x <= xh ; ++x )
	{
		if( lvl->tilemap[ x ][ y ] & SOLID_TILE ) 
			return 0;

		if( lvl->tilemap[ x ][ y ] & DOOR_TILE && 
		   Door_Opened( &lvl->Doors, x, y) != DOOR_FULLOPEN ) {
			// iphone hack to allow player to move halfway into door tiles
			// if the player bounds doesn't cross the middle of the tile, let the move continue			
			if ( abs( Player.position.origin[0] - TILE2POS( x ) ) <= 0x9000
				&& abs( Player.position.origin[1] - TILE2POS( y ) ) <= 0x9000 ) {
				return 0;
			}
		}
	}

// check for actors
	for( n = 0 ; n < NumGuards ; ++n )
	{
		if( Guards[ n ].state >= st_die1 ) 
			continue;

		d = self->position.origin[ 0 ] - Guards[ n ].x;

		if( d < -MINACTORDIST || d > MINACTORDIST )
			continue;

		d = self->position.origin[ 1 ] - Guards[ n ].y;

		if( d < -MINACTORDIST || d > MINACTORDIST)
			continue;

		return false;
	}

	return true;
}

/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
PRIVATE void PL_ClipMove( player_t *self, int xmove, int ymove )
{
	int basex, basey;

	basex = self->position.origin[ 0 ];
	basey = self->position.origin[ 1 ];

	self->position.origin[ 0 ] += xmove;
	self->position.origin[ 1 ] += ymove;
	if( PL_TryMove( self, r_world ) )
	{
		return; // we moved as we wanted
	}

	//Sound_StartSound( NULL, 0, CHAN_BODY, Sound_RegisterSound( "lsfx/000.wav" ), 1, ATTN_NORM, 0 );	

	if( xmove )	// don't bother if we don't move x!
	{
		self->position.origin[ 0 ] = basex + xmove;
		self->position.origin[ 1 ] = basey;
		if( PL_TryMove( self, r_world ) ) 
		{
			return; // May be we'll move only X direction?
		}
	}
	if( ymove )	// don't bother if we don't move y!
	{
		self->position.origin[ 0 ] = basex;
		self->position.origin[ 1 ] = basey + ymove;
		if( PL_TryMove( self, r_world ) ) 
		{
			return; // May be we'll move only Y direction?
		}
	}

// movement blocked; we must stay on one place... :(
	self->position.origin[ 0 ] = basex;
	self->position.origin[ 1 ] = basey;
}


/*
-----------------------------------------------------------------------------
 Function: Changes player's angle and position
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
PRIVATE void PL_ControlMovement( player_t *self, LevelData_t *lvl )
{
	int angle, speed;

// rotation
	angle = self->position.angle;

//	if(cmd->forwardmove || cmd->sidemove)
		self->movx = self->movy = 0; // clear accumulated movement

	if( Player.cmd.forwardmove )
	{
		speed = tics * Player.cmd.forwardmove;
		self->movx+=(int)(speed * CosTable[ angle ] );
		self->movy+=(int)(speed * SinTable[ angle ] );
	}
	if( Player.cmd.sidemove )
	{
		speed = tics * Player.cmd.sidemove;
		self->movx += (int)( speed * SinTable[ angle ] );
		self->movy -= (int)( speed * CosTable[ angle ] );
	}

	if( ! self->movx && ! self->movy ) 
		return;
	
#ifdef SPEAR

	funnyticount = 0; // ZERO FUNNY COUNTER IF MOVED! // FIXME!

#endif
	self->speed = self->movx + self->movy;

// bound movement
	if( self->movx > MAXMOVE ) 
		self->movx = MAXMOVE;
	else if( self->movx < -MAXMOVE ) 
		self->movx = -MAXMOVE;

	if( self->movy > MAXMOVE ) 
		self->movy = MAXMOVE;
	else if( self->movy < -MAXMOVE ) 
		self->movy = -MAXMOVE;

// move player and clip movement to walls (check for no-clip mode here)
	PL_ClipMove( self, self->movx, self->movy );
	self->tilex = POS2TILE( self->position.origin[ 0 ] );
	self->tiley = POS2TILE( self->position.origin[ 1 ] );

	// pick up items easier -- any tile you touch, instead of
	// just the midpoint tile
	{
		int	x, y;
		
		for ( x = -1 ; x <= 1 ; x+= 2 ) {
			int	tilex = POS2TILE( self->position.origin[0] + x * PLAYERSIZE );
			for ( y = -1 ; y <= 1 ; y+= 2 ) {
				int	tiley = POS2TILE( self->position.origin[1] + y * PLAYERSIZE );
				Powerup_PickUp( tilex, tiley );
			}
		}
	}
//	Powerup_PickUp( self->tilex, self->tiley );

// Checking for area change, ambush tiles and doors will have negative values
	if( lvl->areas[ self->tilex ][ self->tiley ] >= 0 &&
		lvl->areas[ self->tilex ][ self->tiley ] != Player.areanumber )
	{
		Player.areanumber = lvl->areas[ self->tilex ][ self->tiley ];
		assert( Player.areanumber >= 0 && Player.areanumber < NUMAREAS );
		Areas_ConnectAreas( Player.areanumber );
	}

	if( lvl->tilemap[ self->tilex ][ self->tiley ] & EXIT_TILE )
	{
		iphoneStartIntermission( 0 );
	}
	

}

/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
PRIVATE void PL_PlayerAttack( player_t *self, _boolean re_attack )
{
	struct atkinf *cur;

	self->attackcount -= tics;
	while( self->attackcount <= 0 )
	{
		cur = &attackinfo[ self->weapon ][ self->attackframe ];
		switch( cur->attack )
		{
			case -1:
				self->flags &= ~PL_FLAG_ATTCK;
				if( ! self->ammo[ AMMO_BULLETS ] )
				{
					self->weapon = WEAPON_KNIFE;
				}
				else if( self->weapon != self->pendingweapon )
				{
					self->weapon = self->pendingweapon;
				}
				self->attackframe = self->weaponframe = 0;
				return;

			case 4:
				if( ! self->ammo[ AMMO_BULLETS ] )
				{
					break;
				}

				if( re_attack ) 
				{
					self->attackframe -= 2;
				}

			case 1:
				if( ! self->ammo[ AMMO_BULLETS ] ) // can only happen with chain gun
				{
					self->attackframe++;
					break;
				}
				fire_lead( self );
				self->ammo[ AMMO_BULLETS ]--;
				break;

			case 2:
				fire_hit( self );
				break;

			case 3:
				if(self->ammo[AMMO_BULLETS] && re_attack)
					self->attackframe-=2;
				break;
		}

		self->attackcount += cur->tics;
		self->attackframe++;
		self->weaponframe = attackinfo[ self->weapon ][ self->attackframe ].frame;
	}

}


/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC void PL_Process( player_t *self, LevelData_t *lvl )
{
	int n;

	self->madenoise = false;

	PL_ControlMovement( self, lvl );

	if( self->flags & PL_FLAG_ATTCK )
	{
		PL_PlayerAttack( self, Player.cmd.buttons & BUTTON_ATTACK );
	}
	else
	{
		if( Player.cmd.buttons & BUTTON_USE )
		{
			if(!(self->flags & PL_FLAG_REUSE) && PL_Use( self, lvl ) )
			{
				self->flags|=PL_FLAG_REUSE;
			}
		}
		else
		{
			self->flags &= ~PL_FLAG_REUSE;
		}

		if( Player.cmd.buttons & BUTTON_ATTACK )
		{
			self->flags |= PL_FLAG_ATTCK;

			self->attackframe = 0;
			self->attackcount = attackinfo[ self->weapon ][ 0 ].tics;
			self->weaponframe = attackinfo[ self->weapon ][ 0 ].frame;
		}
	}

// process impulses
	switch( Player.cmd.impulse )
	{
		case 0:
			break; // no impulse

		case 1:
		case 2:
		case 3:
		case 4:
			PL_ChangeWeapon( self, Player.cmd.impulse - 1 );
			break;

		case 10: // next weapon /like in Quake/ FIXME: weapprev, weapnext
			self->pendingweapon=self->weapon;
			for( n = 0 ; n < 4; ++n )
			{
				if( ++self->weapon > WEAPON_CHAIN ) 
				{
					self->weapon = WEAPON_KNIFE;
				}
				
				if( PL_ChangeWeapon( self, self->weapon ) ) 
				{
					break;
				}
			}
			self->weapon = self->pendingweapon;
			break;

		default:
			Com_Printf( "Unknown Impulse: %d\n", Player.cmd.impulse );
			break;
	}

}



/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters: Nothing.
 
 Returns: Nothing.
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC void PL_Reset(void)
{
	memset( &Player, 0, sizeof( Player ) );
	Player.playstate = ex_notingame;
}

/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters: Nothing.
 
 Returns: Nothing.
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC void PL_Spawn( placeonplane_t location, LevelData_t *lvl )
{
	Player.position = location;
	Player.tilex = POS2TILE( location.origin[ 0 ] );
	Player.tiley = POS2TILE( location.origin[ 1 ] );
	Player.areanumber = lvl->areas[ Player.tilex ][ Player.tiley ];
	assert( Player.areanumber >= 0 && Player.areanumber < NUMAREAS );
	if( Player.areanumber < 0 ) 
	{
		Player.areanumber = 36;
	}

	Areas_ConnectAreas( Player.areanumber );
}

/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters: Nothing.
 
 Returns: Nothing.
 
 Notes: 

-----------------------------------------------------------------------------
*/
PRIVATE void Cmd_Give_f( void )
{
	PL_GiveHealth( &Player, 999, 0 );
	PL_GiveAmmo( &Player, AMMO_BULLETS, 99 );
	PL_GiveWeapon( &Player, WEAPON_AUTO );
	PL_GiveWeapon( &Player, WEAPON_CHAIN );
	PL_GiveKey( &Player, KEY_GOLD );
	PL_GiveKey( &Player, KEY_SILVER );
}

/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters: Nothing.
 
 Returns: Nothing.
 
 Notes: 

-----------------------------------------------------------------------------
*/
PRIVATE void Cmd_God_f( void )
{
	Player.flags ^= FL_GODMODE;

	Com_Printf( "God mode %s\n", Player.flags & FL_GODMODE ? "ON":"OFF" );
}

/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters: Nothing.
 
 Returns: Nothing.
 
 Notes: 

-----------------------------------------------------------------------------
*/
PRIVATE void PL_notarget_f( void )
{
	Player.flags ^= FL_NOTARGET;
}


/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC void PL_Init(void)
{
	PL_Reset();
	PL_NewGame( &Player );

	Cmd_AddCommand( "god", Cmd_God_f );
	Cmd_AddCommand( "notarget", PL_notarget_f );

	Cmd_AddCommand( "give", Cmd_Give_f );
}

// ------------------------- * environment interraction * -------------------------
#define EXTRAPOINTS 40000	// points for an extra life


/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
#ifdef IPHONE
void vibrateDevice();
#else
void vibrateDevice() {}
#endif

PUBLIC void PL_Damage( player_t *self, entity_t *attacker, int points )
{
	
	if( self->playstate == ex_dead )
	{
		return;
	}

	self->LastAttacker = attacker;

	if( skill->value == gd_baby )
	{
		points >>= 2;
	}

	// vibe the phone
	vibrateDevice();

	// note the direction of the last hit for the directional blends
	{
		int		dx = attacker->x - self->position.origin[0];
		int		dy = attacker->y - self->position.origin[1];
		
		// probably won't ever have damage from self, but check anyway
		if ( dx != 0 || dy != 0 ) {
			float angle = atan2f( dy, dx );
			float playerAngle = self->position.angle * 360.0f / (float)ANG_360;
			float deltaAngle;
			angle = angle * 180.0f / M_PI;
			if ( angle < 0 ) {
				angle = 360 + angle;
			}
			deltaAngle = angle - playerAngle;
			if ( deltaAngle > 180 ) {
				deltaAngle = deltaAngle - 360;
			}
			if ( deltaAngle < -180 ) {
				deltaAngle = 360 + deltaAngle;
			}
//			Com_Printf( "damage: player angle: %4.0f shotAngle: %4.0f deltaAngle:%4.0f\n", playerAngle, angle, deltaAngle );
			if ( deltaAngle > 40 ) {
				iphoneSetAttackDirection( 1 );
			} else if ( deltaAngle < -40 ) {
				iphoneSetAttackDirection( -1 );
			}
		}
	}

	// do everything else but subtract health in god mode, to ease
	// testing of damage feedback
	if( !(self->flags & FL_GODMODE) )
	{
		self->health -= points;
	}
	
	if( self->health <= 0 )
	{
		// dead
		self->health = 0;
		self->playstate = ex_dead;

		Sound_StartSound( NULL, 0, CHAN_BODY, Sound_RegisterSound( "lsfx/009.wav" ), 1, ATTN_NORM, 0 );
	}

	// red screen flash
	iphoneStartDamageFlash( points );
	
	// stop the happy grin face if shot before it times out
	Player.face_gotgun = false;

	// make BJ's eyes bulge on huge hits
	if( points > 30 && Player.health != 0 )
	{
		Player.face_ouch = true;
		Player.facecount = 0;
	}
}


/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns: returns true if player needs this health.
 
 Notes: 
	gives player some HP
	max can be:
	 0 - natural player's health limit (100 or 150 with augment)
	>0 - indicates the limit
-----------------------------------------------------------------------------
*/
PUBLIC _boolean PL_GiveHealth( player_t *self, int points, int max )
{
	if( max == 0 )
	{
		max = (self->items & ITEM_AUGMENT) ? 150 : 100;
	}

	if( self->health >= max )
	{
		return false; // doesn't need this health
	}

	self->health += points;

	if( self->health > max )
	{
		self->health = max;
	}

	Player.face_gotgun = false;

	return true; // took it
}

/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns: returns true if player needs this ammo
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC _boolean PL_GiveAmmo( player_t *self, int type, int ammo )
{
	int max_ammo[ AMMO_TYPES ] = { 99 };
	int max;

	max = max_ammo[ type ];
	if( self->items & ITEM_BACKPACK )
	{
		max *= 2;
	}

	if( self->ammo[ type ] >= max )
	{
		return false; // don't need
	}

	if( ! self->ammo[ type ] && ! self->attackframe ) // knife was out
	{
		self->weapon = self->pendingweapon;
	}

	self->ammo[ type ] += ammo;
	if( self->ammo[ type ] > max )
	{
		self->ammo[ type ] = max;
	}

	return true;
}

/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC void PL_GiveWeapon( player_t *self, int weapon )
{
	unsigned itemflag;

	PL_GiveAmmo( self, AMMO_BULLETS, 6 ); // give some ammo with a weapon

	itemflag = ITEM_WEAPON_1 << weapon;
	if( self->items & itemflag )
	{
		return; // player owns this weapon
	}
	else
	{
		self->items |= itemflag;
		if ( self->weapon < weapon ) {	// don't switch if already using better weapon
			self->weapon = self->pendingweapon = weapon;
		}
	}
}

/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC void PL_GiveLife( player_t *self )
{
	if( self->lives < 9 )
	{
		self->lives++;
	}

	Sound_StartSound( NULL, 0, CHAN_ITEM, Sound_RegisterSound( "lsfx/044.wav" ), 1, ATTN_NORM, 0 );
}


/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC void PL_GivePoints( player_t *self, W32 points )
{
	self->score += points;
	while( self->score >= self->next_extra )
	{
		self->next_extra += EXTRAPOINTS;
		PL_GiveLife( self );
	}	
}

/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC void PL_GiveKey( player_t *self, int key )
{
	self->items |= ITEM_KEY_1 << key;
}


/*
-----------------------------------------------------------------------------
 Function:  Set up player for the new game
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC void PL_NewGame( player_t *self )
{
	memset( self, 0, sizeof( player_t ) );

	self->health = 100;
	self->ammo[ AMMO_BULLETS ] = 16;	// JDC: changed for iphone 8;
	self->lives = 3;

	self->weapon = self->pendingweapon = WEAPON_PISTOL;
	self->items = ITEM_WEAPON_1 | ITEM_WEAPON_2;
	self->next_extra = EXTRAPOINTS;
}

/*
-----------------------------------------------------------------------------
 Function: Set up player for level transition
 
 Parameters:
 
 Returns:
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC void PL_NextLevel( player_t *self )
{
	self->old_score = self->score;
	self->attackcount = self->attackframe = self->weaponframe = 0;
	self->flags = 0;

	self->items &= ~(ITEM_KEY_1 | ITEM_KEY_2 | ITEM_KEY_3 | ITEM_KEY_4);
}

/*
-----------------------------------------------------------------------------
 Function: 
 
 Parameters: self -[in] Player to respawn in game world.
 
 Returns: returns false if no lives left
 
 Notes: 

-----------------------------------------------------------------------------
*/
PUBLIC _boolean PL_Reborn( player_t *self )
{
#if 0		// removed game over from iphone version
	if( --self->lives < 1 )
	{
		return false;
	}
#endif

	self->health = 100;
	self->ammo[ AMMO_BULLETS ] = 16;	// JDC: changed for iphone 8;
	self->score = self->old_score;
	self->attackcount = 0;
	self->attackframe = 0;
	self->weaponframe = 0;
	self->flags = 0;

	self->weapon = self->pendingweapon = WEAPON_PISTOL;
	self->items = ITEM_WEAPON_1 | ITEM_WEAPON_2;

	self->playstate = ex_playing;

	return true;
}
