/* $Id$
 *
 * Copyright (c) 1999 Xenonsoft Limited. All Rights Reserved.
 *
 * This software is protected by copyright. You are hereby notified from
 * now by reading this message. This software is also the confidential 
 * and proprietary information of Xenonsoft Limited.  ("Confidential
 * Information"). 
 *
 * This software is distributed under the Xenonsoft Public end user 
 * License ("XPeL"), where the machine-readable source code is provided 
 * under the "Open Source" model.
 * For more information, please read the file "LICENSE-XPL.txt" 
 */

// File:`Human.java'
//
//
// DESCRIPTION
//	Human
// 
// Author
//
//	Peter Pilgrim
//	Wed May 26 23:40:49 BST 1999
// 
// RCS HEADER ``Human.java''
// 
//	$Author$
//	$Date$
//	$Source$
//	$Revision$    $State$    $Locker$
//

package xenon.humanoid;

import java.io.*;
import java.util.Vector;
import java.awt.*;
import java.awt.image.*;

import xenon.gamekit.*;				// for GameEngine, WorldObject, etc
import xenon.soundkit.*;			// for SoundEngine, PPMCAudioPlayer, etc

public class Human extends FriendObject
{
    public final static int		STATE_FREE=0; // free human
    public final static int		STATE_FALLING=1; // falling human
    public final static int		STATE_CAPTURED=2; //  abducted by lander
    public final static int		STATE_RESCUED=3; // rescued by Starship

    public final static int		MAXIMUM_FALLING_DISTANCE=50;
    public final static int		OPTIMAL_HEIGHT=24;

    // Images of these type of world
    // Object are stored in an array
    protected static Image		humanImage=null;

    // Private object instance counter
    private static Vector		humanList = new Vector();

    protected WorldObject		imprisoner;
    protected int			initialFallingHeight;
    
    // CURRENT state
    protected int			state;

    protected static Envelope		env1=null;
    protected static SoundEngine	se1=null;

    protected static Envelope		env2=null;
    protected static SoundEngine	se2=null;

    protected static Envelope		env3=null;
    protected static SoundEngine	se3=null;

    protected static Envelope		env4=null;
    protected static SoundEngine	se4=null;


    public Human( GameEngine gameEngine ) 
    {
	this( gameEngine, STATE_FREE, 0 );
    }

    /** 
     * Constructor take a single game object 
     * 
     * @param gameEngine the game engine
     * @param state the state of the lander (STATE_HUNTING, STATE_MUTANT)
     * @param wx the world x coodinate
     */
    public Human( GameEngine gameEngine, int state, int wx ) 
    {
	super( gameEngine );

	this.state = state;
	this.wx = wx;
	this.wy = OPTIMAL_HEIGHT;		/*!*/
	dx_vel = ( Math.random() < 0.5 ) ? -3 : 3 ;
	dy_vel = 0;

	// Get the bounds
	width = humanImage.getWidth(component);
	height = humanImage.getHeight(component);
	
	humanList.addElement( this );			/* ! */
    }

    /** retrieves a default image used for placating an image of
     * the world object on the screen. For example displaying image
     * on the left of the display and the number of points scored
     * destroying this world object on the right.
     * <b>Subclassers</b> should override this methods.
     */
    public Image getDefaultImage() 
    {
	return (humanImage);
    }
    
    /** Gets type description type */
    public String getDescriptionType()
    {
	switch (state) {
	  case STATE_CAPTURED: return ("Abducted Human");
	  case STATE_RESCUED: return ("Rescuing Captured Human");
	  case STATE_FREE:  return ("Setting Free Human");
	}
	return ("Human");
    }
    
    /** Gets the points score for this world object */
    public int getPointsScored()
    {
	switch (state) {
	  case STATE_CAPTURED: return (250);
	  case STATE_FREE:  return (500);
	}
	return (0);
    }
    
    public static int getInstanceCount() 
    {
	return humanList.size();
    }
    
    public static void  removeAllInstances()
    {
	humanList.removeAllElements();
    }
    
    public static Vector getHumanList() 
    {
	return (humanList);
    }
    
    public boolean loadImages()
    {
	if (humanImage == null) {
	    // Load lander images
	    humanImage = 
		GraphicsUtils.getImageAsClassResource( this, "images/human.gif" );

	    GraphicsUtils.loadImageCompletely( component, humanImage );
	}
	
	return (true);
    }

    public boolean loadAudioClips()
    {

	if (env1 == null ) {
	    env1 = new Envelope( 
		1,  2,4, -1,4, 8,8,     1, 126 ,1, 0, 26, -1, 16, -2, 128 );
	    se1 = new SoundEngine(
		8000, 2.25, 
		110, 525, 80, 
		StaticWave.SQUARE_WAVE,
		env1 /* new Envelope() */ );
	    
	    se1.setFlags( se1.getFlags() | SoundEngine.FM_DELTA_RANDOM_FLAG | SoundEngine.NOISE_MIX_GATE_FLAG );
	    se1.makeWave();
	    
	}
	if (env2 == null ) {
	    // Generating HUMAN DIED sound ...
	    env2 = new Envelope(
		1,  0,1, -1,1, -2,1,
		1,128,1, 0,128, 0,128, -5,128 );
	    se2 = new SoundEngine(
		8000, 3.0, 100, 543, 25,
		StaticWave.RAMP_BACKWARD_WAVE, env2 );
	    se2.setFlags( 0x0 );
	    se2.makeWave();
	}
	if (env3 == null ) {
	    // Create Human Ouch sound ...
	    InputStream is = getClass().getResourceAsStream("audio/ouch.au");
	    try {
		env3 = new Envelope(
		    1,  0,1, -1,1, -2,1,
		    1,128,1, 0,128, 0,128, -8,128 );
		se3 = new SoundEngine(
		    8000, 3.0, 261, 543, 30,
		    new AudioClipWave(is), env3 );
		se3.setFilter( new DelaySoundFilter(25) );
		se3.makeWave();
	    }
	    catch (IOException ioe) {
		System.err.println("cannot load audio clip `audio/ouch.au'");
		System.err.println(ioe.getMessage());
		System.exit(3);
	    }
	}
	if (env4 == null ) {
	    // Create giant bite sound ...
	    InputStream is = getClass().getResourceAsStream("audio/Doh2.au");
	    try {
		env4 = new Envelope(
		    1,  0,1, -1,1, -2,1,
		    1,128,1, 0,128, 0,128, -4,128 );
		se4 = new SoundEngine(
		    8000, 3.0, 261, 543, 40,
		    new AudioClipWave(is), env4 );
		se3.setFilter( new DelaySoundFilter(5) );
		se4.makeWave();
	    }
	    catch (IOException ioe) {
		System.err.println("cannot load audio clip `audio/ouch.au'");
		System.err.println(ioe.getMessage());
		System.exit(3);
	    }
	}
	
	return (true);
    }

    
    public SoundEngine getRescueSound() 
    {
	return (se1);
    }

    public SoundEngine getDiedSound() 
    {
	return (se2);
    }

    public SoundEngine getOuchSound() 
    {
	return (se3);
    }

    public SoundEngine getGiantBiteSound() 
    {
	return (se4);
    }

    public synchronized void setState( int newState )
    {
	int oldState = state;
	state = newState;
	if ( oldState != STATE_FALLING && newState == STATE_FALLING ) {
	    initialFallingHeight=wy;
	}
    }
    
    public synchronized int getState()
    {
	return (state);
    }
    
    public synchronized void setImprisoner( WorldObject newImprisoner )
    {
	imprisoner = newImprisoner;
    }
    
    public synchronized WorldObject getImprisoner()
    {
	return (imprisoner);
    }
    
    /** update world object */
    public WorldObject	update()
    {
	HumanoidGameEngine hengine = (HumanoidGameEngine)gameEngine;
	
	switch ( state ) {
	  case STATE_CAPTURED:
	  case STATE_RESCUED:
	      if ( getImprisoner() == null )
		  state=STATE_FREE;
	      break;
	  
	  case STATE_FREE:
	  {
	      if ( wy > OPTIMAL_HEIGHT + 16 ) {
		  state = STATE_FALLING;
		  initialFallingHeight = wy;
	      }
	      
	      if ( gameEngine.frameClock % 3 == 0 ) 
		  wx = ( wx + dx_vel + gameEngine.world_width ) % 
		      gameEngine.world_width;
	      if ( wy < OPTIMAL_HEIGHT ) 
		  dy_vel = 2;
	      else if ( wy > OPTIMAL_HEIGHT ) 
		  dy_vel = -2;
	      else
		  dy_vel = 0;
	      wy += dy_vel;
	      
	      if ( gameEngine.frameClock % 21 == 0 && Math.random() < 0.045 )
		  dx_vel = -dx_vel;
	  }
	  break;
	  
	  case STATE_FALLING:
	  {
	      dx_vel = 0;
	      dy_vel = -2;
	      wy = wy + dy_vel;

	      if ( wy < OPTIMAL_HEIGHT ) {
		  wy = OPTIMAL_HEIGHT;
		  if ( initialFallingHeight > OPTIMAL_HEIGHT + MAXIMUM_FALLING_DISTANCE ) {
		      // Too high to fall from
		      PPMCAudioPlayer mcap = hengine.getMCAudioPlayer();
		      mcap.play( 6, getDiedSound().getSoundData() );
		      destroy();
		      Explosion explosion = new Explosion( 
			  gameEngine, null, wx, wy, Color.yellow );
		      gameEngine.addWorldObject( explosion );
		  }
		  else {
		      state = STATE_FREE;	/* ! */
		      dx_vel = ( Math.random() < 0.5 ) ? -3 : 3 ;
		      gameEngine.incrementScore( 250 );
		      PPMCAudioPlayer mcap = gameEngine.getMCAudioPlayer();
		      mcap.play( 3, se1.getSoundData() );

		      BonusFlyer flyer = new BonusFlyer( 
			  gameEngine, wx, wy+16, 0, 3, 250 );
		      gameEngine.addWorldObject( flyer );
		  }
	      }
	  }
	}
	
	return (this);
    }
    
    /** draw object if displayed */
    public WorldObject	drawObject( Graphics g ) 
    {
	if ( isVisible() ) {
	    
	    translateWorldToScreen();
	    
	    if ( isViewable() )
		g.drawImage( humanImage, scrx, scry, component );
	}

	return (this);
    }
    
    /** undraw object if displayed */
    public WorldObject	undrawObject( Graphics g )
    {
	return (this);
    }

    public void	destroy()
    {
	imprisoner = null;			/* ! */
	humanList.removeElement( this );	/* ! */
	super.destroy();
    }
    
    /** Get the radar color for this world object */
    public Color  getRadarColor()
    {
	return Color.white;
    }

    // =============================================================================
    //		I N N E R    C L A S S E S
    // =============================================================================

}

// fini
