[13046] in Athena Bugs

home help back first fref pref prev next nref lref last post

decmips 7.7G: cygnus/g++

daemon@ATHENA.MIT.EDU (hardts@MIT.EDU)
Thu Dec 22 19:55:50 1994

From: hardts@MIT.EDU
Date: Thu, 22 Dec 94 19:55:35 -0500
To: bugs@MIT.EDU

System name:            bolognese
Type and version:       KN02ca 7.7G (1 update(s) to same version)
Display type:


g++ in the cygnus locker crashed under the following situation:
Using a decmips machine  bolognese.mit.edu)  December 22, 1994

athena% add cygnus
/afs/athena.mit.edu/user/h/a/hardts/src/X/xevil
athena% /mit/cygnus/decmipsbin/g++ test.cc
Fixed up unaligned data access for pid 8547 (cc1plus) at pc 0x5c9770
pid 8547 (cc1plus) was killed on a kernel access, at pc 0x5c976c
In file included from test.cc:2:
physical.hh:755: Internal compiler error.
physical.hh:755: Please submit a full bug report to `bug-g++@prep.ai.mit.edu'.
athena% 


Do you know of any other C++ compilers on Athena, g++ in the gnu locker
did basically the same thing.  g++ in cygnus-930630 gave me a bunch of 
different errors.




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RELEVANT FILES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
"test.cc"
"physical.hh"
"utils.hh"
"coord.hh"
"area.hh"
"world.hh"
"id.hh"
"intel.hh"
"locator.hh"


;;;;;;;;;;;;; "test.cc"
#include <iostream.h>
#include "physical.hh"

main()
{
  cout << "Hello World." << endl;
}




;;;;;;;;; "physical.hh"
// "physical.hh"  Interior nodes of the physical object tree.  These classes
// are never instantiated.
// TAG: PH

/*    Copyright (C) 1994  Steve Hardt

      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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

      Steve Hardt 
      hardts@athena.mit.edu (or hardts@r4002.3dem.bioch.bcm.tmc.edu)
      2043 McClendon
      Houston, TX 77030
      */

#ifndef PHYSICAL_HH
#define PHYSICAL_HH

#pragma interface


// Include Files
#include "utils.hh"
#include "coord.hh"
#include "area.hh"
#include "world.hh"
#include "id.hh"
#include "intel.hh"
#include "locator.hh"


// Defines
#define PH_ANIM_MAX 4
#define PH_FRAME_MAX 7
#define PH_WEAPONS_MAX 10
#define PH_ITEMS_MAX 20
#define PH_AMMO_UNLIMITED -1
#define PH_CORPSE_TIME 400



// Other declarations
enum PHsig {PH_NO_SIG, PH_NOT_SET, PH_ID_CHANGED};



// Class declarations

////////// Physical
/* The parent class of all physical objects. */

struct PhysicalContext {
  Health health;
  Mass mass;
  ClassId classId;
  const char *clas;
};


class Physical {
public:
  Physical(const PhysicalContext &,WorldP,LocatorP);
  /* EFFECTS: Create a new, mapped physical with no Id with undefined area. */

  Physical();
  /* NOTE: Should never be called. */

  virtual ~Physical();

  virtual const Area &get_area() = 0;
  Health get_health() {return health;}
  Health get_health_max() {return pc->health;}
  Mass get_mass() {return mass;}
  virtual Vel get_vel();
  virtual Dir get_dir();

  ClassId get_class_id() {return pc->classId;}
  const char *identify() {return pc->clas;}

  virtual int get_drawing_level();

  Boolean delete_me() {return deleteMe;}

  Boolean alive() {return health >= 0;}
  /* NOTE: Is publicly known that (health >= 0) <=> alive.  So this function is
   just for convenience. */

  /* Should only be used for abstract classes.  Actual classes can be tested
     for with get_class_id(). */
  virtual Boolean is_moving();
  virtual Boolean is_shot();
  virtual Boolean is_item(); 
  virtual Boolean is_bomb();
  virtual Boolean is_weapon();
  virtual Boolean is_cutter();
  virtual Boolean is_gun();
  virtual Boolean is_creature(); 
  virtual Boolean is_user();
  virtual Boolean is_fighter();
  virtual Boolean is_walking(); 
  virtual Boolean is_sticky(); 
  virtual Boolean is_flying();

  Boolean get_mapped() {return mapped;}

  virtual Boolean collidable();
  /* NOTE: This value never changes for an object. */

  const Acc *get_unit_accs() {return unitAccs;}
  const Vel *get_unit_vels() {return unitVels;}

  Id get_id() {assert(idValid); return id;}

  PHsig get_id(Id &id);
  /* MODIFIES: id */
  /* EFFECTS: Set id to be the Id and return PH_NO_SIG if set.  Otherwise, 
     return PH_NOT_SET. */

  PhysicalP get_dont_collide() {return dontCollide;}
  /* EFFECTS: If there is another object that *this is not allowed to collide
     with, return it.  Otherwise return NULL; */

  IntelP get_intel() {return intel;}
  /* NOTE: Can be NULL. */

  void set_command(ITcommand c) {command = c;}
  /* EFFECTS: Sets the command to be c, overrides any previous command 
     setting. */
  /* NOTE: command is not clocked. */

  PHsig set_id(const Id &id);
  /* EFFECTS: Set the Id to be id.  Return PH_NO_SIG if there was no previous
     id.  Return PH_ID_CHANGED if there was a previous id.  The id is set in 
     either case. */

  void set_dont_collide(PhysicalP other) {dontCollide = other;}
  /* EFFECTS: *this will not be allowed to collide with other.  Any previous 
     value will be overridden.  A setting of NULL disables this feature. */

  void set_intel(IntelP i) {intel = i;  if (i) i->set_id(id);}
  /* REQUIRES: Object has been added to locator (has valid id.)
  /* NOTE: Can be NULL. */

  void set_health_next(Health h) {healthNext = h;}
  
  virtual void set_mapped_next(Boolean val);
  /* NOTE: Should be ok to set the value to the previous value. */
  /* NOTE: idempotent */
  /* Calls up the tree. */

  void set_no_death_delete() {noDeathDelete = True;}

  virtual void corporeal_attack(PhysicalP killer,int damage); 
  virtual void heat_attack(PhysicalP,int heat,Boolean secondary = False);
  /* NOTE: Sometimes call up the tree. */
  /* NOTE: killer is the one responsible for causing the damage.  Can be 
     NULL.  Adds kills to the killer. */
  /* NOTE: Only the last call before the update cycle takes effect. */

  virtual void avoid(PhysicalP);
  virtual void collide(PhysicalP);
  /* EFFECTS: Collision procedures.  avoid is called on the lighter of the two
     objects.  collide is called on both objects. */
  /* NOTE: Not always called up the tree. */

  void intelligence() {if (intel) intel->clock(this);}

  void kill_self() {healthNext = -1;}

  virtual void set_quiet_death();
  /* EFFECTS: When this dies, do not do any funny things like leaving corpses
     or exploding or any other type of physical evidence. */
  /* NOTE: Calls up the tree. */

  void virtual act();
  /* EFFECTS: Action phase.  All next variables must be set here.  Commands 
     are interpreted here.*/

  void virtual update(); 
  /* EFFECTS: Set current variables to be the next ones.  No interactions 
     between physical objects. */
  
  void virtual draw(Drawable buffer,Xvars &xvars, const Area &area) = 0;
  /* REQUIRES: buffer is at least as big as area. */
  /* EFFECTS: Draw the physical object in buffer.  buffer represents area. */
  /* NOTE: Does not check for overlap */
  /* NOTE: X variables initialized in draw.  Thus, if draw is never called for
     a base class, the X variables never need to be initialized. */

  void virtual die();
  /* EFFECTS:  If the *this dies a natural death (I.e. health < 0), then this
     function is called.  Not called if *this is 
     destroyed for any other reason.  E.g. end of game.  The default is to 
     kill the intel and set_delete_me. */
  /* NOTE: Intel is created/destroyed by Game or Locator. */
  /* NOTE: Should be called in update phase. */
  /* NOTE: Calls up the tree. */
  /* NOTE: Guaranteed to be called only once. */


  virtual int get_weapons_num();
  virtual int get_items_num(); 
  /* NOTE: Returned value is not valid after current turn. */
  
  virtual PhysicalP get_weapon(int);
  virtual PhysicalP get_item(int); 
  virtual PhysicalP get_weapon_current();
  virtual PhysicalP get_item_current();
  /* NOTE: Can return NULL. */


#ifndef PROTECTED_IS_PUBLIC
protected:
#endif
  WorldP get_world() {return world;}

  Boolean alive_next() {return healthNext >= 0;}

  LocatorP get_locator() {return locator;}

  const ITcommand &get_command() {return command;}
  /* EFFECTS: Gets the command. */
  /* NOTE: command is not clocked. */

  Boolean get_mapped_next() {return mappedNext;}

  void set_mass_next(Mass mss) {massNext = mss;}

  void set_delete_me() {deleteMe = True;}


private:
  void init_static();

  static Boolean staticValid;
  static Acc unitAccs[CO_DIR_MAX]; 
  static Vel unitVels[CO_DIR_MAX]; 
  Boolean idValid;
  Id id;
  WorldP world;
  LocatorP locator;
  ITcommand command;
  const PhysicalContext *pc; 
  Health health, healthNext;
  Mass mass, massNext;
  PhysicalP dontCollide;
  IntelP intel;
  Boolean deleteMe;
  Boolean mapped,mappedNext;
  Boolean noDeathDelete; // Should set_delete_me be called at death.
  Boolean dieCalled;
  int heat, heatNext;
  Boolean previousHeatWasSecondary;
};
// PhysicalP defined in locator.hh



////////// Moving
// Parent: Physical
// Has all 19 directions.  Multiple pixmaps.  Can change size and position. 
// Top speed is VEL_MAX.

/* Only sizes[CO_air] and offsets[CO_air] are required to be set.  
   Gives initial size and offset. */
struct MovingContext {
  char *foreColorName;
  Boolean foreWhiteDefault;
  const char *backColorName;
  Boolean backWhiteDefault;
  int animMax[CO_DIR_MAX];
  Size sizes[CO_DIR_MAX];
  Size offsets[CO_DIR_MAX];
  char *pixmapBits[CO_DIR_MAX][PH_ANIM_MAX];
  char *maskBits[CO_DIR_MAX][PH_ANIM_MAX];
  PhysicalContext physicalContext;
};


class MovingXdata {
public:
  MovingXdata() {valid = False;}
  
  Boolean valid;
  Pixmap pixmaps[CO_DIR_MAX][PH_ANIM_MAX],
  masks[CO_DIR_MAX][PH_ANIM_MAX];
};


class Moving: public Physical {
public:
  Moving(const MovingContext &m_c,
	 MovingXdata &x_data,
	 WorldP world,
	 LocatorP l,
	 const Pos &rawPos,
	 Dir dirInitial = CO_air);

  Moving();
  /* NOTE: Should never be called. */

  virtual Boolean is_moving();

  virtual const Area &get_area();
  virtual Vel get_vel();
  const Pos &get_raw_pos() {return rawPos;}
  virtual Dir get_dir();

  void set_middle_next(const Pos &pos);
  /* EFFECTS: Sets the middle of pos according to the current (not next) values
     of dir, and area (for size). */
  /* NOTE: May be called before or after act phase. */

  void set_extra_vel_next(const Vel &vel) 
  {extraVelNext = vel; extraVelNextSet = True;}

  virtual void act();
  virtual void update();
  virtual void draw(Drawable,Xvars &,const Area &);
  virtual void avoid(PhysicalP);
  virtual void collide(PhysicalP);


#ifndef PROTECTED_IS_PUBLIC
protected:
#endif
  Boolean hit_wall() {return hitWall;}
  Boolean hit_wall_next() {return hitWallNext;}

  Dir get_dir_next() {return dirNext;}

  const Area &get_area_next() {return areaNext;}
  const MovingContext *get_moving_context() {return mc;}
  Vel get_vel_next() {return velNext;}

  void set_vel(const Vel &v) {vel = v;}

  void set_vel_next(const Vel &vel) {velNext = vel;}
  void set_vel_next(int zero) {assert (zero == 0); velNext.set_zero();}
  /* EFFECTS: Sets the next velocity for the object to be vel.  Can be called
     multiple times before update, only the last call is used. */

//  void set_extra_vel(const Vel &vel) {extraVel = vel;}
  /* NOTE: Not clocked. */
  
  void set_dir(const Dir &d) {dir = d;}
  /* NOTE: Only used by Lance for initialization. */

  void set_dir_next(const Dir &d) {dirNext = d;}

  void set_raw_pos_next(const Pos &rpos)
    {rawPosNext = rpos; rawPosChanged = True;}

  void update_next();
  /* EFFECTS: Compute areaNext and hitWallNext.  May modify rawPosNext or 
     dirNext. */
  /* NOTE: May be called more than once per turn. */

  virtual void get_pixmap_mask(Pixmap &pixmap,Pixmap &mask,
			       Dir dir,int animNum);
  /* MODIFIES: pixmap, mask */
  /* NOTE: Only used so that children of Moving can affect Moving's actions. */
  
  virtual void get_size_offset_next(Size &size,Size &offset,Dir dirNext);
  /* MODIFIES: size, offset */
  /* NOTE: Only used so that children of Moving can affect Moving's actions. */

  virtual void init_x(Xvars &);
  /* NOTE: Now called up the tree. */


private:
  Boolean context_valid();
  /* EFFECTS: Returns True if this->cx is valid, False otherwise. */

  float compute_collision(Mass m1,float v1,Mass m2,float v2);


  MovingXdata *movingXdata;
  int movingAnimNum;
  Timer animTimer;
  const MovingContext *mc;
  Pos rawPos,rawPosNext; Boolean rawPosChanged;
  Area area,areaNext;   
  Dir dir,dirNext;
  Vel vel,velNext; 
  Boolean extraVelNextSet;
  Vel extraVel,extraVelNext; // Follows clock in non-standard way.
  Boolean hitWall,hitWallNext;
};
typedef Moving *MovingP;



////////// Shot
// Parent: Moving

struct ShotContext {
  int damage;  // Or heat.
  Speed speed;
  MovingContext movingContext;
};

typedef MovingXdata ShotXdata ;

class Shot: public Moving {
public:
  Shot(const ShotContext &,ShotXdata &,WorldP,LocatorP,
       const Pos &,const Id &shooter,
       Dir shotDir,Dir movingDir = CO_air);
  
  const Id &get_shooter() {return shooter;}

  virtual Boolean is_shot();

  virtual void avoid(PhysicalP other);
  virtual void collide(PhysicalP other);

  virtual void update();


#ifndef PROTECTED_IS_PUBLIC
 protected:
#endif
  int get_damage() {return context->damage;}


private:
  Id shooter;
  const ShotContext *context;
};



////////// Falling
// Parent: Moving
// Moving with gravity.  Falls until it is blocked by the world.  

struct FallingContext {
  MovingContext movingContext;
};

typedef MovingXdata FallingXdata;

class Falling: public Moving {
public:
  Falling(const FallingContext &h_c,FallingXdata &x_data,
	  WorldP world,LocatorP l,const Pos &rawPos,
	  Dir dirInitial = CO_air);
  
  virtual void act();
};



//////////// Heavy
// Parent: Falling
// Does damage to things it lands on.

struct HeavyContext {
  int damage;
  FallingContext fallingContext;
};

typedef FallingXdata HeavyXdata;

class Heavy: public Falling {
 public:
  Heavy(const HeavyContext &h_c,
	HeavyXdata &x_data,
	WorldP world,
	LocatorP l,
	const Pos &rawPos);
  
  virtual void collide(PhysicalP);
  /* EFFECTS: Crush things it falls on. */
  

 private:
  const HeavyContext *context;
};



//////////// Generator
// Parent: Heavy
// Generate machines and register them with the locator.

struct GeneratorContext {
  HeavyContext heavyContext;
};

typedef HeavyXdata GeneratorXdata;

class Generator: public Heavy {
public:
  Generator(const IntelOptions &ops,ITmask opMask,
	    const char *prefix,
	    const GeneratorContext &g_c,
	    GeneratorXdata &x_data,
	    WorldP w,
	    LocatorP l,
	    const Pos &rawPos);
  
  virtual void act();
  
  
#ifndef PROTECTED_IS_PUBLIC
protected:
#endif
  virtual PhysicalP generate() = 0;
  
  
private:
  enum {MAX = 10, TIME = 100};

  Timer timer;
  int machineCount; // Always increasing.
  IntelOptions machineOps;
  ITmask machineOpMask;
  const char *machinePrefix;

  Id generated[MAX];
  const GeneratorContext *generatorContext;
};



//////////// Item
// Parent: Falling
// 
struct ItemContext {
  Boolean persists;
  FallingContext fallingContext;
};
typedef FallingXdata ItemXdata;


class Item: public Falling {
public:
  Item(const ItemContext &c_x,
       ItemXdata &x_data,
       WorldP w,
       LocatorP l,
       const Pos &pos);
  
  Boolean is_item() {return True;}

  Boolean is_held() {return held;}
  
  Boolean can_take() {return canTake.ready() && !held && !cantTake;}
  /* EFFECTS: Returns whether the object can be picked up. */

  virtual int get_drawing_level();
  /* NOTE: Items are at drawing level 1. */

  Boolean persists() {return context->persists;}

  virtual void follow_user(const Pos &userMiddle,Dir userDir);

  void taken(PhysicalP);
  /* EFFECTS:  The object has been taken by another Physical. */
  /* NOTE: Changes immediate externally visible state.  Should only be called
     in the collision phase. */

  void dropped(PhysicalP);
  /* EFFECTS:  The object has been dropped by another Physical. */
  /* NOTE: Called by another object in the act phase. */
  /* NOTE: Called in either the act or update phase. */
  /* NOTE: Calls up the tree. */

  virtual void use(PhysicalP);
  /* EFFECTS: p uses *this. */
  /* NOTE: Called by another object in act phase. */

  void set_used_message() {usedMessage = True;}
  /* EFFECTS: On death, the printed message will say the item was used instead
     of saying the item was destroyed. */
  
  virtual void act();
  
  virtual void die();
  
  
#ifndef PROTECTED_IS_PUBLIC
protected:
#endif
  void set_cant_take() {cantTake = True;}
  
  
private:
  Boolean held;
  Boolean usedMessage;
  Timer canTake;
  Boolean cantTake;
  const ItemContext *context;
};
typedef Item *ItemP;



//////////// Animated
// Parent: Item
//
struct AnimatedContext {
  char *colorName;
  Size size;
  int animMax[PH_FRAME_MAX];
  char *pixmapBits[PH_FRAME_MAX][PH_ANIM_MAX];
  char *maskBits[PH_FRAME_MAX][PH_ANIM_MAX];
  ItemContext itemContext;
};


class AnimatedXdata {
public:
  AnimatedXdata() {valid = False;}
  Boolean valid;
  Pixmap pixmaps[PH_FRAME_MAX][PH_ANIM_MAX],
  masks[PH_FRAME_MAX][PH_ANIM_MAX];
  ItemXdata itemXdata;
}; 


class Animated: public Item {
public:
  Animated::Animated(const AnimatedContext &,AnimatedXdata &,
		     WorldP,LocatorP,const Pos &);


#ifndef PROTECTED_IS_PUBLIC
protected:
#endif
  void set_frame(Frame fr) {frame = fr;}
  void set_frame_next(Frame fr) {frameNext = fr;}
  Frame get_frame() {return frame;}
  
  virtual void get_pixmap_mask(Pixmap &pixmap,Pixmap &mask,
			       Dir dir,int animNum);
  virtual void get_size_offset_next(Size &size,Size &offset,
				    Dir dirNext);
  
  virtual void init_x(Xvars &);
  
  virtual void update();


private:
  Boolean context_valid();

  AnimatedXdata *animatedXdata;
  const AnimatedContext *ac;
  Frame frame,frameNext;
  int animatedAnimNum;
};



//////////// Weapon
// Parent: Item
// 
struct WeaponContext {
  Boolean defaultable;
  ItemContext itemContext;
};
typedef ItemXdata WeaponXdata;
class Weapon;
typedef Weapon *WeaponP;


class Weapon: public Item {
public:
  Weapon(const WeaponContext &c_x,
	 WeaponXdata &x_data,
	 WorldP w,
	 LocatorP l,
	 const Pos &pos);
  
  Boolean is_weapon() {return True;}

  virtual Boolean ready() = 0;
  /* EFFECTS: Can the weapon be fired now. */
  /* NOTE: Sometimes calls up the tree.*/

  Boolean defaultable() {return wc->defaultable;}
  /* EFFECTS: Is this a type of weapon that can safely be set automatically as
     the current weapon.  E.g. You do not want to set a soul-swapper as the 
     current weapon unless the user explicitly says so. */

  virtual int get_ammo() = 0;
  virtual int get_ammo_max() = 0;
  /* NOTE: Can return PH_AMMO_UNLIMITED. */

  virtual void fire(const Id &id,ITcommand command);
  /* REQUIRES: command is a weapon command. */
  /* EFFECTS: Fire the weapon according to the specified command.  id is the
     physical firing the weapon.  */

  virtual void enter_scope_next(PhysicalP user);
  virtual void leave_scope_next(PhysicalP user);
  /* NOTE: Called during act(collide) or update phase. Should be just 
     act(). */
  /* NOTE: Calls up the tree. */
  /* NOTE: ok to call multiple times in same turn, but must enter/leave scope
     in proper order. */

  void take_ammo_from(WeaponP other);
  /* EFFECTS: Take as much ammo as possible from the other weapon. */


#ifndef PROTECTED_IS_PUBLIC
 protected:
#endif
  Boolean entered_scope() {return enteredScope;}

  virtual void set_ammo(int) = 0;


private:
  const WeaponContext *wc;
  Boolean enteredScope; // not clocked
};
// typedef Weapon *WeaponP; Defined above.



//////////// Cutter
// Parent: Weapon
// NOTE: Uses CO_center for cutter directly in front of user.
struct CutterContext {
  int damage;  // per turn
  Size offsets[CO_DIR_MAX];  // From User's middle to Cutter's middle.

  char *unheldColorName;
  Size unheldSize;
  char *unheldPixmapBits;
  char *unheldMaskBits;
  WeaponContext weaponContext;
};


class CutterXdata {
 public:
  CutterXdata() {valid = False;}

  Boolean valid;
  Pixmap unheldPixmap,unheldMask;
  WeaponXdata weaponXdata;
};


class Cutter: public Weapon {
public:
  Cutter(const CutterContext &c_x,CutterXdata &x_data,
	 WorldP w,LocatorP l,const Pos &pos);
  
  virtual Boolean is_cutter();

  virtual Boolean ready();

  virtual int get_ammo();
  virtual int get_ammo_max();

  virtual void get_pixmap_mask(Pixmap &pixmap,Pixmap &mask,
			       Dir dir,int animNum);
  
  virtual void get_size_offset_next(Size &size,Size &offset,Dir dirNext);

  virtual void set_ammo(int);

  virtual void follow_user(const Pos &,Dir);

  virtual void enter_scope_next(PhysicalP);
  virtual void leave_scope_next(PhysicalP);

  virtual void collide(PhysicalP);

  virtual void update();


#ifndef PROTECTED_IS_PUBLIC
 protected: 
#endif
  virtual void init_x(Xvars &);


private:
  Dir dir_4_from_user_dir(Dir);

  Boolean inScope,inScopeNext;
  Id killerId;  // Valid iff inScope.
  CutterXdata *cutterXdata;
  const CutterContext *context;
};




////////// Creature
// Parent: Moving
// Moving with stances.  Can be affected by gravity.
struct CreatureContext {
  Speed crawlSpeed;
  Speed centerSpeed; 
  Speed airSpeed;
  Speed climbSpeed;
  Speed jump;
  Speed acceleration;
  Health corpseHealth; // A positive number.

  Size deadSize;
  Size deadOffset;
  char *deadPixmapBits;
  char *deadMaskBits;
  
  MovingContext movingContext;
};


struct CreatureXdata
{
  CreatureXdata() {valid = False;}

  Pixmap deadPixmap,deadMask;
  Boolean valid;
  MovingXdata movingXdata;
};


class Creature: public Moving {
public:
  Creature(const CreatureContext &m_c,
	   CreatureXdata &x_data,
	   WorldP world,
	   LocatorP l,
	   const Pos &rawPos);

  Creature();
  /* NOTE: Should never be called. */

  virtual Boolean is_creature() {return True;}
  Stance get_stance() {return stance;}
  Boolean can_climb() {return canClimb;}

  Boolean was_attacked() {return wasAttacked;}
  /* EFFECTS: Was *this attacked last turn.  Use get_killer_id() to 
     get the attacker. */

  const Hanging &get_hanging() {return hanging;}
  /* EFFECTS: Get the corner that the object is hanging off of, or CO_AIR if
     not hanging off a corner. */

  const Touching &get_touching_area() {return touching;}
  /* EFFECTS: The object's actual touching.  I.e. according to its area. */

  Grav get_grav() {return grav;}

  const Id &get_killer_id() {return killerId;}
  /* EFFECTS: Return the id of the most recent attacker.  May be invalid. */

  virtual void set_quiet_death();

  virtual void corporeal_attack(PhysicalP,int damage); 
  virtual void heat_attack(PhysicalP,int heat,Boolean secondary); 

  virtual void act();
  virtual void update();
  virtual void die();


#ifndef PROTECTED_IS_PUBLIC
protected:
#endif
  Stance get_stance_next() {return stanceNext;}

  const CreatureContext *get_creature_context() {return cc;}

  Touching get_touching_stance();
  /* EFFECTS: The object's touching according to its stance. */

  virtual void get_pixmap_mask(Pixmap &pixmap,Pixmap &mask,
			       Dir dir,int animNum);
  /* MODIFIES: pixmap, mask */
  
  virtual void get_size_offset_next(Size &size,Size &offset,Dir dirNext);
  /* MODIFIES: size, offset */

  void set_stance(const Stance &st) {stance = st;}

  void set_stance_next(const Stance &stance);
  /* EFFECTS: Sets the next stanceection for the object to be stance.  Can be
     called multiple times before update, only the last call is used. */

  void set_grav_next(const Grav &g)
    {gravNext = g;}
  /* EFFECTS: Sets the pull of gravity for the next turn to be grav. */

  void center_wsquare_x_next(const Loc &loc);
  /* REQUIRES: loc overlaps with the area, stanceNext set to CO_climb */
  /* EFFECTS: Tries to center the x position object on the wsquare at loc.  
     (May be bumped a bit if a wall prevents exact centering.) */

  void corner(const Hanging &hanging);
  /* REQUIRES: stanceNext is set to correspond to h.corner. */
  /* EFFECTS: Tries to move the object around the corner it is hanging off of.
     Note that hanging.corner is the initial corner, not the desired final 
     one. */

  virtual void init_x(Xvars &);


private:
  static Dir compute_dir(const Stance &stance,const Vel &vel);
  /* USES: nothing */
  /* EFFECTS: Return the dir corresponding to stance and vel. */

  Boolean context_valid();

  Touching touching;
  Hanging hanging;
  Boolean canClimb;
  Stance stance,stanceNext; 
  Grav grav,gravNext; 
  const CreatureContext *cc;
  Timer corpseTimer;
  CreatureXdata *creatureXdata;
  Boolean noCorpse;
  Id killerId;
  Boolean wasAttacked, wasAttackedNext;
};
typedef Creature *CreatureP;



/*//////// Grounded
//  Parent: Creature
Sticks to the ground only.  Affected by gravity.  Can't climb or jump. */
struct GroundedContext 
{
  int dummy;
}; 

struct GroundedXdata {};

class Grounded: public virtual Creature {
 public:
  Grounded(const GroundedContext &,GroundedXdata &);
  
  virtual Boolean is_grounded() {return True;}
  virtual void act();
};



////////// Hopping
// Parent: Creature
// 
struct HoppingContext 
{
  int dummy;
}; 

struct HoppingXdata {};

class Hopping: public virtual Creature {
 public:
  Hopping(const HoppingContext &,HoppingXdata &);

  virtual void act();
};



////////// User
// Parent: Creature
// Holds and uses items and weapons.  The items and weapons are made to follow
// the User. 
struct UserContext 
{
  int dummy;
};  

struct UserXdata {};


class User: public virtual Creature {
public:
  User(const UserContext &,UserXdata &);

  virtual Boolean is_user();

  virtual int get_weapons_num();
  virtual int get_items_num(); 
  /* NOTE: Returned value is not valid after current turn. */
  
  virtual PhysicalP get_weapon(int);
  virtual PhysicalP get_item(int); 
  virtual PhysicalP get_weapon_current();
  virtual PhysicalP get_item_current();
  /* NOTE: Can return NULL. */

  virtual void set_mapped_next(Boolean val);
  /* EFFECTS: Bring current weapon in/out of scope and then change mapped. */

  virtual void act();
  virtual void _act();

  virtual void collide(PhysicalP other);
  virtual Boolean _collide(PhysicalP);

  virtual void die();
  virtual void _die();


#ifndef PROTECTED_IS_PUBLIC
 protected:
#endif
  Boolean has_weapon(Weapon **weapon,ClassId classId);
  /* MODIFIES: weapon */
  /* EFFECTS: Like has_weapon(ClassId) except will return the 
     weapon in weapon if not NULL. */


private:
  int defaultable_weapon();
  /* REQUIRES: weaponsNum and weapons are properly updated. */
  /* EFFECTS: Returns the index of a wepon in weapons that is defaultable or
     weaponsNum if there is none. */


  Id weapons[PH_WEAPONS_MAX];
  int weaponsNum;
  int weaponCurrent; // weaponCurrent == weaponsNum if no selected weapon.
  //  Memory of previous weapon dir is now in ui.

  Id items[PH_ITEMS_MAX];
  int itemsNum;
  int itemCurrent; // itemCurrent == itemsNum if no selected item.
};
typedef User *UserP;



////////// Fighter
// Parent: Creature
// Can attack in different directions.
struct FighterContext {
  char *colorName;
  int slide;
  int jumpHorizontal;
  int jumpVertical;
  int damageStuck;
  int damageFree;

  Size sizes[CO_DIR_MAX];
  Size offsets[CO_DIR_MAX];
  Size hotSpots[CO_DIR_MAX];  // Must add in offset to use.
  char *pixmapBits[CO_DIR_MAX];
  char *maskBits[CO_DIR_MAX];
};


class FighterXdata {
public:
  FighterXdata() {valid = False;}

  Boolean valid;
  Pixmap pixmaps[CO_DIR_MAX],
  masks[CO_DIR_MAX];
};


class Fighter: public virtual Creature {
public:
  Fighter(const FighterContext &f_c,FighterXdata &x_data);

  virtual Boolean is_fighter();

  virtual void get_pixmap_mask(Pixmap &pixmap,Pixmap &mask,
			       Dir dir,int animNum);
  
  virtual void get_size_offset_next(Size &size,Size &offset,Dir dirNext);

  virtual void act();
  virtual void _act();

  virtual void update();
  virtual void _update();

  virtual void collide(PhysicalP other);
  virtual Boolean _collide(PhysicalP);


#ifndef PROTECTED_IS_PUBLIC
protected:
#endif
  virtual void init_x(Xvars &);


private:
  Attack dir_to_attack(Dir dir);

  void attack_stuck(Dir dir,Stance stance);
  void attack_free_horizontal(Dir dir);
  /* NOTE: Does not zero vertical velocity. */

  void attack_free_vertical(Dir dir);
  /* NOTE: Vertical velocity only. */

  FighterXdata *fighterXdata;
  const FighterContext *fc;
  Attack attack, attackNext;
  Timer stuckTimer;
};



////////// Walking
// Parent: Creature
// Sticks to the ground only.  Affected by gravity.
struct WalkingContext 
{
  int dummy;
}; 

struct WalkingXdata {};

class Walking: public virtual Creature {
public:
  Walking(const WalkingContext &,WalkingXdata &);

  virtual Boolean is_walking() {return True;}

  virtual void act();
  virtual void _act();


private:
  Pos rawPosPrev;
  Vel velPrev;
};



////////// Sticky
// Parent: Creature
// Sticks to and walks on flat surfaces in four directions.  Affected by 
// gravity.
struct StickyContext 
{
  int dummy;
};  

struct StickyXdata {};

class Sticky: public virtual Creature {
public:
  Sticky(const StickyContext &,StickyXdata &);
  
  virtual Boolean is_sticky();

  virtual void act();
  virtual void _act();


#ifndef PROTECTED_IS_PUBLIC
protected:
#endif
  Boolean want_corner(const Corner &corner);
  /* EFFECTS: Returns True if the object should go around the given corner,
     False otherwise.  corner is the initial, not final corner.*/

  Stance cornered_stance(const Hanging &h);
  /* EFFECTS: Returns the stance to take in order to go around the corner
     of h. */

  void set_want_corner(const Corner &c1) 
    {wantCorner1 = c1; wantCorner2 = CO_air;}
  void set_want_corner(const Corner &c1,const Corner &c2) 
    {wantCorner1 = c1; wantCorner2 = c2;}
  /* EFFECTS: Tell the object that it should go around a corner if possible.
     The given values are in effect until changed. */
  /* NOTE: set_want_corner(CO_air) should be used to disable cornering. */


private:
  Corner wantCorner1,wantCorner2;
};



////////// Flying
// Parent: Creature
// Floats around.  Can walk on the ground.
struct FlyingContext 
{
  int airBrake;
  int gravTime;
};  

struct FlyingXdata {};

class Flying: public virtual Creature {
public:
  Flying(const FlyingContext &,FlyingXdata &);
  
  virtual Boolean is_flying();

  virtual void act();
  virtual void _act();


private:
  Timer gravTimer;
  const FlyingContext *context;
};

#endif




;;;;;;;;;; "utils.hh"
// Misc. utilities. to be included by ALL files.

/*    Copyright (C) 1994  Steve Hardt

    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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

    Steve Hardt 
    hardts@athena.mit.edu (or hardts@r4002.3dem.bioch.bcm.tmc.edu)
    2043 McClendon
    Houston, TX 77030
*/

#ifndef UTILS_HH
#define UTILS_HH

#pragma interface



// Include Files
extern "C"
{
#include <math.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
}
#include <assert.h>



// Defines
#ifndef max
#define max(a,b)               (a<b ? b : a)
#endif
#ifndef min
#define min(a,b)               (a>b ? b : a)
#endif

typedef char Boolean;
typedef unsigned long Pixel;

typedef int ColorNum;




#ifdef RANDOM_NEEDS_PROTOTYPES
extern "C" {
long random();
void srandom(int);
}
#endif 




// Data Structures
class Xvars {
public:
  enum {HUMAN_COLORS_NUM = 5};

  Display *dpy;
  Screen *scr_ptr;
  int scr_num;
  Window root;
  Visual *visual;
  int depth;
  Colormap cmap;
  Pixel white,black; /* Or background/foreground. */
  Pixel red,green; /* Both default to black. */
  Pixel humanColors[HUMAN_COLORS_NUM];
  GC gc; /* Default except foreground is black, background is white, no
	    graphics exposures, font is set, stipple is suitable for drawing
	    insensitive areas, fill style is FillSolid */
  XFontStruct *font;
};



class Timer {
 public:
  Timer() {remaining = maxx = 0;}
  // Starts out ready.
  Timer(int t) {assert (t >= 0); maxx = t; remaining = 0;} 
  Boolean ready() {return remaining == 0;}
  void set() {remaining = maxx;}
  void set(int time) {remaining = time;}
  void reset() {remaining = 0;}
  void clock() {if (remaining) remaining--;}

 private:
  int remaining;
  int maxx;
};



#define Utils_BACKGROUND "light grey"
class Utils {
 public:
  enum {HUMAN_COLORS_NUM = Xvars::HUMAN_COLORS_NUM};
  static const char *humanColorNames[Utils::HUMAN_COLORS_NUM];

  static Pixel allocNamedColor(Xvars &xvars,const char *name,
			       Pixel def = (Pixel)-1);
  /* EFFECTS: Tries to allocate the named color.  Returns it if successful.  
     Otherwise, returns default.  If called with only 2 arguments, default is 
     white.  If black and white display, returns default. */
  

  static inline Boolean coinFlip() 
#ifdef USE_RANDOM
    {return (Boolean)(random() % 2);}
#else
  { return (Boolean)(rand() % 2); }
#endif
  /* EFFECTS: Randomly returns True or False; */


  static inline int choose(int x) 
#ifdef USE_RANDOM
    { 
      assert (x > 0);
      return (int)(random() % x);
    }
#else
  { 
    assert (x > 0);
    return rand() % x;
  }
#endif
  /* EFFECTS: Randomly return a number from 0 to x - 1. */
  
  static void insertionSort(int arry[],int numElements);

  static void randomList(int arry[],int numElements);
  /* EFFECTS: Fills arry the first numElements of arry with the numbers in 
     {0..(numElements-1)} in a random order. */

  static int minimum(int arry[],int size);
  /* EFFECTS: Return the minimum value in the array arry of size size. */

  static int minimum(int arry[],Boolean oks[],int size);
  /* EFFECTS: Return the minimum value in arry which is ok or -1 if none. */
};
#endif



;;;;;;; "coord.hh"
// "coord.h"  Coordinates and directions and the like.
// TAG: CO

/*    Copyright (C) 1994  Steve Hardt

    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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

    Steve Hardt 
    hardts@athena.mit.edu (or hardts@r4002.3dem.bioch.bcm.tmc.edu)
    2043 McClendon
    Houston, TX 77030
*/

#ifndef COORD_HH
#define COORD_HH

#pragma interface


// Include Files
#include "utils.hh"



// Defines
#define WSQUARE_WIDTH 16
#define WSQUARE_HEIGHT 16
#define WSQUARE_WIDTH_INV (1.0 / WSQUARE_WIDTH)
#define WSQUARE_HEIGHT_INV (1.0 / WSQUARE_HEIGHT)


// Order of directions IS guaranteed.
#define CO_center_R 0
#define CO_center_L 1
#define CO_air_R 2
#define CO_air_L 3
#define CO_air 4
#define CO_center 5

#define CO_r 6
#define CO_r_DN 7 
#define CO_r_UP 8
#define CO_dn 9
#define CO_dn_R 10
#define CO_dn_L 11
#define CO_l 12
#define CO_l_DN 13
#define CO_l_UP 14
#define CO_up 15
#define CO_up_R 16
#define CO_up_L 17

#define CO_climb 18
#define CO_climb_DN 19
#define CO_climb_UP 20
#define CO_air_UP 21
#define CO_air_DN 22
#define CO_climb_R 23
#define CO_climb_L 24

#define CO_R 25
#define CO_DN_R_R 26
#define CO_DN_R 27
#define CO_DN_DN_R 28
#define CO_DN 29
#define CO_DN_DN_L 30
#define CO_DN_L 31
#define CO_DN_L_L 32
#define CO_L 33
#define CO_UP_L_L 34
#define CO_UP_L 35
#define CO_UP_UP_L 36
#define CO_UP 37
#define CO_UP_UP_R 38
#define CO_UP_R 39
#define CO_UP_R_R 40

#define CO_DIR_MAX 41

#define CO_DIR_PURE 16  // "Pure" does not include CO_center.  Use CO_air.

typedef int ClassId;
typedef int Dir;
typedef int Touching;
typedef int Stance;
typedef int Corner;
typedef int Mass;
typedef int Health;
typedef int Frame;
typedef int Speed;
typedef long Quanta;

// Data Structures
struct Pos {
  Pos() {x = y = 0;}
  Pos(int xx,int yy) {x = xx; y = yy;}

  int distance(const Pos &) const;
  /* EFFECTS: Returns distance between two points. */

  int distance_2(const Pos&) const;
  /* EFFECTS: Returns square of distance between two points. */
  
  int x; int y;
}; // In pixels



struct Vel {
  Vel() {dx = dy = 0.0;}
  Vel(float x,float y) {dx = x; dy = y;}
  void set_zero() {dx = dy = 0.0;}
  Vel shrink(float k) const;
  void damp(float k);
  Boolean is_zero() const;
  void limit(float k);
  /* REQUIRES: k >= 0 */
  /* EFFECTS: Force dx and dy to be <= k. */

  void get_dirs_4(Dir in[4],Dir out[4],int &inNum,int &outNum);
  /* MODIFIES: in, out, inNum, outNum */
  /* EFFECTS: Partitions {CO_R, CO_DN, CO_L, CO_UP} into in and out.  inNum 
     and outNum are set to the sizes of the respective sets. */

  float dx; float dy;
};



struct Size {
  Dir get_dir();
  /* EFFECTS: Returns one of {CO_R..CO_UP_R,CO_air}. */

  void get_dirs_4(Dir &d1,Dir &d2);
  /* MODIFIES: d1, d2 */
  /* EFFECTS: Gets the two directions of {CO_R,CO_DN,CO_L,CO_UP} that 
     correspond to *this.  If there is only one, it is returned as d1 and 
     d2.  If *this has zero size, d1 == d2 == CO_air on return. */

  float cross(const Vel &v);
  /* EFFECTS: z component of the cross product of the size and the Vel. */

  void set_zero() {width = height = 0;}

  int abs_2() {return width*width + height*height;}

  int width; int height; // In pixels.
}; 



// Constructors mess with TouchingList in area.hh
struct Loc {
  int r,c; // In WSQUARES.
}; 



struct Dim {
  Dim() {rowMax = colMax = 0;}
  Dim(int rm,int cm) {rowMax = rm; colMax = cm;}

  int rowMax, colMax; // In WSQUARES.
}; 



struct Box {
  Box() {};
  Box(const Loc &l,const Dim &d) {loc = l; dim = d;}
  Boolean overlap(const Loc &);

  Loc loc; Dim dim; // In WSQUARES.
}; 



struct GLoc {
  int vert, horiz;
};



struct RoomIndex {int down; int across; }; // In rooms.
struct Rooms {
  Rooms() {downMax = acrossMax = 0;}
  Rooms(int dn,int acc) {downMax = dn; acrossMax = acc;}

  int downMax, acrossMax;
}; 



struct Acc {
  operator Vel()
    {Vel ret(ddx,ddy); return ret;}
  /* EFFECTS: Converts from an acceleration to velocity.  Assumes initial 
     velocity is 0. */

  float ddx, ddy;
};



struct Hanging {
  Hanging() {corner = CO_air;}

  Corner corner;
  Loc loc; // Not meaningful if corner == CO_air.
};



typedef int Grav;

enum Attack {attackNone, attackStuck, attackFree};



// Function Prototypes
Boolean operator == (const Loc &l1, const Loc &l2);
Boolean operator == (const Pos &p1, const Pos &p2);
Boolean operator == (const Size &s1, const Size &s2);
Boolean operator == (const GLoc &,const GLoc &);
Boolean operator != (const GLoc &,const GLoc &);
Pos operator + (const Pos &pos,const Size &size);
Pos operator - (const Pos &pos,const Size &size);
Size operator - (const Pos &p1,const Pos &p2);
Pos operator + (const Pos &pos, const Vel &vel);
Size operator * (float k,const Size &size);
Vel operator + (const Vel &,const Vel &);
Vel operator + (const Vel &, const Acc &acc);
Vel operator * (float k,const Vel &vel);
Vel operator / (float k,const Vel &vel);
Vel operator + (float k,const Vel &vel);
Acc operator * (int k,const Acc &acc);


class Coord
{
public:
  static Dir dir_opposite(Dir dir);
};
#endif



;;;;;;; "area.hh"
// "area.hh" 
// TAG: AR

/*    Copyright (C) 1994  Steve Hardt

    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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

    Steve Hardt 
    hardts@athena.mit.edu (or hardts@r4002.3dem.bioch.bcm.tmc.edu)
    2043 McClendon
    Houston, TX 77030
*/

#ifndef AREA_HH
#define AREA_HH

#pragma interface


// Include Files
#include "utils.hh"
#include "coord.hh"


// Defines
#define AR_WSQUARES_MAX 20
enum ARshape {AR_RECT,AR_UNDEFINED};
enum ARsig {AR_NO_SIG, AR_CLOSE, AR_FAILURE, AR_BAD_SHAPE};



// Data structures
struct TouchingListItem {
  Loc list[AR_WSQUARES_MAX];
  int num;
};

struct TouchingList {
  TouchingListItem r,dn,l,up; 
};


class Area;
class Avoid;

Size operator - (const Area &,const Area &);
/* EFFECTS: Subtract areas according to their upper left corners. */


// Class Declarations
class Area {
  friend Size operator - (const Area &,const Area &);
  
 public:
  Area() {shape = AR_UNDEFINED;}
  /* EFFECTS: Create undefined area. */

  Area(ARshape c,const Pos &p,const Size &s);
  /* REQUIRES: c is AR_RECT. */
  /* EFFECTS: Creates a rectangle area at position p of size s. */

  void get_rect(Pos &p,Size &s) const;
  /* MODIFIES: p,s */

  Box get_box() const;
  /* EFFECTS: Returns the box of wsquares that contains the area. */

  void wsquares(Loc list[AR_WSQUARES_MAX],int &nitems) const;
  /* MODIFIES: list, nitems */
  /* EFFECTS: After completion, the first nitems of list contain the locations
     of all the wsquares covered by the area.  The initial values of list 
     and nitems are ignored.  wsquares are not necessarily inside the world. */

  Boolean overlap(const Area &) const;
  /* EFFECTS: Returns True if *this overlaps with r, False otherwise. */

  Boolean overlap(const Loc &loc) const;
  /* EFFECTS: Returns True if loc overlaps with any of the area.  Returns 
     False otherwise. */

  Boolean overlap(const Box &box) const;
  /* EFFECTS: Returns True if box overlaps with any of the area.  Returns 
     False otherwise. */

  Boolean overlap(const Pos &pos) const;

  Loc middle_wsquare() const;
  /* EFFECTS: Returns the location of the middle wsquare in the area. */

  ARsig avoid_wsquare(Avoid &avoid,const Loc &loc) const;
  /* MODIFIES: avoid */
  /* EFFECTS: Returns AR_NO_SIG if the wsquare at loc does not overlap with 
     the area.  If loc overlaps in the area, but not in a nearby area, returns
     AR_CLOSE and sets avoid to be the offsets necessary to make the area no 
     longer touch the wsquare. */

  int avoid_wsquare_dir(const Loc &loc,Dir dir) const;
  /* EFFECTS: Returns the amount *this will have to be shited in dir to avoid 
     loc. */

  Size avoid(const Area &area) const;
  /* EFFECTS: Returns the smallest offset necessary to move *this in order to
     avoid area. */

  Size avoid_no_up(const Area &) const;
  /* EFFECTS: Like avoid(), but will not avoid in the up direction. */

  Pos adjacent_rect(const Size &s,Dir dir) const;
  /* EFFECTS: Return the upper left corner of the rectangle of size s that
     touches *this such that the direction from *this to the rectangle is 
     dir. */

  Pos get_middle() const;
  /* EFFECTS: Returns the middle of the area. */

  void touching_wsquares(TouchingList &list) const;
  /* MODIFIES: list */
  /* EFFECTS: Sets r,dn,l,up to be the lists of all wsquares that are exactly 
     touching the area.  The directions are set from the area to the touching 
     wsquare.  I.e. A loc listed under list.r would be touching the 
     right side of the area.  The list are ordered such that the smallest 
     row and column indexes come first.  I.e. top->bottom and left->right. */

  void shift(const Size &offset)
    {assert(shape == AR_RECT); pos = pos + offset;}
  /* EFFECTS: Shift the area by offset. */

  void set_middle(const Pos &pos);
  /* EFFECTS: Move the area so that pos will be the middle. */

  Dir dir_to(const Pos &pos) const;
  Dir dir_to(const Area &area) const;
  /* EFFECTS: Returns the direction from this to pos or to area. 
     Will return one of {CO_R .. CO_UP_R, CO_air}.  I.e. 8 directions or 
     CO_air. */

  Area combine(const Area &a) const;
  /* EFFECTS: Returns minimum sized rectangular area that contains a and 
     this. */


public:
  ARshape shape;
  Pos pos;
  Size size;
};



class Avoid {
friend class Area;

public:    
  void maximize(const Avoid &avoid);
  /* EFFECTS: Set all directions of *this to be to max of *this and avoid. */

  Size offset_rank(int rank = 0) const;
  /* REQUIRES: 0 <= rank < 4 */
  /* EFFECTS: Return the offset corresponding to the rankth minimum direction
     of *this using one dimensions.  E.g. rank = 0 gives the minimum.  rank
     = 1 gives the second minimum, etc. */
  
  Size offset_dir(Dir d) const;
  /* REQUIRES: d in {CO_R, CO_DN, CO_L, CO_UP} */
  /* EFFECTS: Return the offset corresponding to d. */

  int get_dir(Dir d) const;
  /* REQUIRES: d in {CO_R, CO_DN, CO_L, CO_UP} */
  /* EFFECTS: Returns the offset in the specified direction. */


private:
  /* Direction from area to wsquare.  All are positive.  r and dn are 
     therefore the negative of the corresponding offsets. */
  int r,dn,l,up; 
};
#endif



;;;;;;;;;; "world.hh"
// "world.hh"
// TAG:  W
/*    Copyright (C) 1994  Steve Hardt

    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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

    Steve Hardt 
    hardts@athena.mit.edu (or hardts@r4002.3dem.bioch.bcm.tmc.edu)
    2043 McClendon
    Houston, TX 77030
*/

/* Overview:  A world object is a rectangular region composed of WSQUARES.
   Internally, it is divided into rooms of constant size.  It's upper left 
   corner is at WSQUARE (0,0). 
   World should be draw completely once before just drawing with changes. */

#ifndef WORLD_HH
#define WORLD_HH

#pragma interface



// Include Files
#include "utils.hh"
#include "coord.hh"
#include "area.hh"



// Defines.
// WSQUARES in a room.
#define W_ROOM_COL_MAX 40//36
#define W_ROOM_ROW_MAX 16//15 

/* Maximum rooms in world.  World may actually be smaller.  World starts out 
   at the size of the title screen. */
#define W_ACROSS_MAX_MAX 15
#define W_DOWN_MAX_MAX 15

// WSQUARES in world.
#define W_COL_MAX_MAX (W_ROOM_COL_MAX * W_ACROSS_MAX_MAX)
#define W_ROW_MAX_MAX (W_ROOM_ROW_MAX * W_DOWN_MAX_MAX)

/* The maximum number of wsquares that can be set changed/unchanged in one 
  clock cycle. */
#define W_CHANGES_MAX 5000

/* The blocks composing the world.  Represented as integers so that the world
   map can be initialized easily. */
enum { Wempty, Wwall, Wladder, Woutside, Wsquanch, WupDown};
#define W_BLOCKS_NUM 6

enum Wsig {W_NO_SIG, W_CLOSE, W_CLOSE_BAD, W_FAILURE};
typedef char Wmap[W_ROW_MAX_MAX][W_COL_MAX_MAX];

#define W_POSTERS_NUM 6



// Class Declarations
class World {
  struct Wxdata {
    Pixel background; 
    Pixmap pixmaps[W_BLOCKS_NUM];
    // Array of pixmaps for a poster with columns changing fastest.
    Pixmap *posterPixmaps[W_POSTERS_NUM];  
  };

  struct PosterSquare {
    int poster;
    Loc loc; // Inside poster.
  };


 public:
  World(Boolean pol_correct);
  /* EFFECTS: Create the title screen world.  If politically correct, 
   there will be no posters and the title screen will be blank. */

  Size get_size() {return size;}
  /* EFFECTS: Size of the world in pixels. */

  Dim get_dim() {return dim;}
  /* EFFECTS: Dimensions of the world in wsquares. */

  Dim get_room_dim();
  /* EFFECTS: Return the dimensions of a room in wsquares. */

  Size get_room_size();

  Rooms get_rooms() {return rooms;}
  /* EFFECTS: The max number of rooms in across and down direction. */

  void set_rooms_next(const Rooms &r);
  /* EFFECTS: After the next reset, the world will have as many rooms as r.
   If r is bigger than the maximum, the min of the maximum size and r is 
   used. */

  void set_map_print(Boolean val) {mapPrint = val;}
  /* EFFECTS: Sets whether to print each new map of the world at reset. */

  Boolean overlap(const Box &box);
  /* EFFECTS: Does any of box overlap with the wsquares of the world. */

  void draw(Drawable buffer,Xvars &xv,const Box &box);
  /* EFFECTS: Draw all of the box that is in the world. */

  void draw(Drawable buffer,Xvars &xv,const Area &area);
  /* EFFECTS: Draw all of area that is in the world. */

  Boolean inside(const Loc &l)
    {return l.r >= 0 && l.c >= 0 && l.r < dim.rowMax && l.c < dim.colMax;}
  /* EFFECTS: Returns True if loc is a wsquare inside the world, otherwise
   returns False. */

  Boolean open(const Loc &loc,Boolean laddersClosed = False,
	       Boolean postersClosed = False);
  /* EFFECTS: Returns True if loc is an open square inside the world.  Returns
     False otherwise.  Note that wsquares outside the world are treated as if 
     they were closed wsquares. */

  Boolean open(const Area &area,Boolean laddersClosed = False);
  Boolean open(const Box &box,Boolean laddersClosed = False,
	       Boolean postersClosed = False);
  /* EFFECTS: Is the portion of the world covered by area (or box) blocked? 
     laddersClosed implies that ladders and other non-walls are considered to be
     blocking. */

  

  Wsig open_offset(Size &offset,const Area &area,
		   const Vel &vel,Boolean laddersClosed = False);
  /* MODIFIES: offset  */
  /* EFFECTS: Returns W_NO_SIG if the portion of the world covered by initial 
     is open.  prev is the previous area occupied before.  If the area is 
     blocked, but a nearby area is not, returns
     W_CLOSE_OK and sets offset to be the offset necessary to unblock initial.
     Retruns W_CLOSE_BLOCKED if a nearby area is blocked.  Stills sets offset
     for the nearby area.  Returns W_FAILURE if initial and all nearby areas 
     are blocked.  offset may be modified in any case. */

  void touchingHanging(Touching &touching, Hanging &hanging, 
		       const Area &area);
  /* REQUIRES: area is AR_RECT. */
  /* MODIFIES: touching, hanging */
  /* EFFECTS: If area is touching a blocked wsquare, sets touching to be the 
     direction from area to the wsquare.  If the area is touching in both the
     vertical and horizontal direction, the vertical takes precedence.  Sets
     touching to be CO_air if not touching in any direction.  If the area is
     hanging off of the edge of some blocked wsquares, sets hanging 
     appropriately.  Otherwise, sets hanging.corner to be CO_air. */
  
  Boolean canClimb(const Loc &loc)
    {return inside(loc) ? (map[loc.r][loc.c] == Wladder) : False;}
  /* EFFECTS: Returns True if loc is a climable square inside the world.  I.e.
     a ladder.  False otherwise. */

  Pos empty_rect(const Size &size);
  /* EFFECTS: Return the upper-left position of a randomly choosen empty 
     rectangle of size s.  Ladders are not considered empty. */

  Pos empty_touching_rect(const Size &size);
  /* EFFECTS: Like empty_rect except the returned rect will be touching the 
     ground. */

  Boolean empty_box(Loc &loc,const Dim &dim,Boolean laddersClosed,
		    Boolean postersClosed);
  /* MODIFIES: loc */
  /* EFFECTS: Returns True iff an empty box of dimension dim can be found and
     returns its upper-left Loc. */

  void reset();
  /* EFFECTS:  Prepare the world for a new game.  Create a new map. */

  void clock() {} 
  

 private:
  Pixmap draw_square(Drawable buffer,Xvars &xvars,const Loc &loc,int x,int y);

  /* EFFECTS: Draw the appropriate square from loc to (x,y) on buffer. */

  void dim_size_update();
  /* EFFECTS: Updates dim and size from the current value of rooms. */

  void init_x(Xvars &);
  /* EFFECTS: Initialize all x dependencies. */

  void title_map();

  void th_helper(Touching &touching,Hanging &hanging,
		 const TouchingListItem &item,
		 Boolean r_c,
		 int coord,int length,
		 int wsquare_length,
		 Touching iftouching,
		 Corner ifsmall, Corner iflarge);
  /* MODIFIES: touching, hanging */
  /* EFFECTS: Helper for World::touching.  Does touching, hanging for one 
     side. */

  Boolean open_iter(Area &area,int &changed,Dir dir,Boolean laddersClosed);
  /* MODIFIES: area, changed */
  /* EFFECTS: Move area as much in dir as necessary to avoid all its wsquares.
     Increment changed by the distance moved.  Return True if the original 
     area is open and nothing is changed.*/

  Size open_size(int offset,Dir dir);
  Size open_size(int offset1,Dir dir1,int offset2,Dir dir2);
  /* REQUIRES: dir is in {CO_R, CO_DN, CO_L, CO_UP} */
  /* EFFECTS: Return the Size corresponding to an offset in one or two 
     directions. */

  Boolean open_try_dirs(Size &offset,const Area &area,const Dir dirs[4],
			       int dirsNum,Boolean laddersClosed);
  /* MODIFIES: offset */
  /* EFFECTS: Sets offset to be the minimum necessary to shift area to an
     open area in one of the directions of dirs.  Returns whether it 
     succeeded.  offset may be changed in any case. */
  
  Boolean open_try_diagonals(Size &offset,const Area &area,
				   Boolean laddersClosed);
  /* MODIFIES: offset */
  /* EFFECTS: Set offset to shift area to a nearby open one.  Returns whether
     it succeeded.  offset may be changed in any case. */

  Rooms rooms,roomsNext;
  Size size;  /* For convenience only. */
  Dim dim;    /* For convenience only. */

  Wmap map;
  Boolean xValid;
  Wxdata xdata;
  Boolean mapPrint;
  Dim posterDims[W_POSTERS_NUM]; 
  PosterSquare *posterSquares[W_ROW_MAX_MAX][W_COL_MAX_MAX];
  Boolean polCorrect;

  // Defined in world.bitmaps.
  static unsigned char *posterPixmapBits[W_POSTERS_NUM];
  static unsigned char *posterMaskBits[W_POSTERS_NUM];
  static const Size posterSizes[W_POSTERS_NUM];
  static const char *posterForegrounds[W_POSTERS_NUM];
  static const char *posterBackgrounds[W_POSTERS_NUM];
  static unsigned char *pixmapBits[W_BLOCKS_NUM];
  static const char *colorNames[W_BLOCKS_NUM];
};

			   

// Typdefs
  typedef World *WorldP;
#endif




;;;;;;;;;;;;;;; "id.hh"
// Object locator id.
// TAG: ID

/*    Copyright (C) 1994  Steve Hardt

    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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

    Steve Hardt 
    hardts@athena.mit.edu (or hardts@escher.3dem.bioch.bcm.tmc.edu)
    2043 McClendon
    Houston, TX 77030
*/

#ifndef ID_HH
#define ID_HH

// No '#pragma interface' because there is no "id.cc".


class Locator;
class Id {
  friend class Locator;

 public:
  Id() {index = INVALID;}
  Boolean operator == (const Id &other) const
  {return (other.index == index) && (other.unique == unique);}
  Boolean operator != (const Id &other) const
  {return (other.index != index) || (other.unique != unique);}
  
 private:  
  enum {INVALID = -1};
  int index; 
  int unique;
};

#endif



;;;;;;;;;; "intel.hh"
// "intel.hh"
// TAG: IT

/*    Copyright (C) 1994  Steve Hardt

    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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

    Steve Hardt 
    hardts@athena.mit.edu (or hardts@r4002.3dem.bioch.bcm.tmc.edu)
    2043 McClendon
    Houston, TX 77030
*/

#ifndef INTEL_HH
#define INTEL_HH

#pragma interface


// Include Files
#include "utils.hh"
#include "coord.hh"
#include "id.hh"
#include "locator.hh"
#include "world.hh"



// Defines
#define IT_STRING_LENGTH 80



class Physical;
typedef Physical *PhysicalP;


/* Possible commands to be given to objects.
   Order of directions is guaranteed.  (See ui.hh and game.cc) */
  enum ITcommand {
    IT_CENTER,
    IT_R, IT_DN_R, IT_DN, IT_DN_L,
    IT_L, IT_UP_L, IT_UP, IT_UP_R,
    IT_WEAPON_CENTER,IT_WEAPON_CHANGE,IT_WEAPON_DROP,
    IT_ITEM_USE,IT_ITEM_CHANGE,IT_ITEM_DROP,
    
    IT_WEAPON_R,IT_WEAPON_DN_R,IT_WEAPON_DN,IT_WEAPON_DN_L,
    IT_WEAPON_L,IT_WEAPON_UP_L,IT_WEAPON_UP,IT_WEAPON_UP_R,

    IT_NO_COMMAND};
#define IT_COMMAND_MAX IT_NO_COMMAND



// IntelOptions
typedef unsigned long ITmask;
#define ITnone 0L
#define ITharmless (1L<<0)
#define ITclassFriends (1L<<1)

struct IntelOptions {
  Boolean classFriends;
  Boolean harmless;
};



// IntelStatus used by ui.
// Remember Intel::die
struct IntelStatus {
  // strings and ClassIds must be kept consistent.

  char name[IT_STRING_LENGTH];
  ClassId classId;
  char clas[IT_STRING_LENGTH];
  Health health; // -1 means dead.
  Mass mass;
  ClassId weaponClassId;  
  char weapon[IT_STRING_LENGTH];
  Boolean weaponReady;
  int ammo;
  ClassId itemClassId;
  char item[IT_STRING_LENGTH];
  int lives;
  int kills;
};

  

// Class Definitions.
class Intel {
 public:
  Intel(WorldP w,LocatorP l,char *name,int lives,
	const IntelOptions *ops,ITmask opMask); 
  /* EFFECTS: Create a new intel with the options specified in opMakse that are
     in ops.  ops will never be referenced if opMask is ITnone.  lives are
     decremented as human is created. */

  virtual Boolean is_human() {return False;}

  Boolean alive() {return living;}
  WorldP get_world() {return world;}
  LocatorP get_locator() {return locator;}

  const Id &get_id() {return id;}
  /* NOTE: If dead, return an invalid id. */

  Boolean reincarnate_me() {return !living && (intelStatus.lives > 0);}
  /* EFFECTS: Should *this be reincarnated. */

  Boolean intel_status_changed() {return intelStatusChanged;}

  const IntelStatus *get_intel_status() 
    {intelStatusChanged = False; return &intelStatus;}

  const char *get_name() {return intelStatus.name;}
  int get_lives() {return intelStatus.lives;}
  int get_kills() {return intelStatus.kills;}
  /* NOTE: Could achieve the same thing with get_intel_status.  Convenience 
   functions. */

  void set_id(const Id &i) {id = i;}
  /* REQUIRES: i is valid. */
  /* NOTE: Only needed for Physical::set_intel.  id is updated on every 
     clock. */

  void add_kill() {intelStatusChanged = True; intelStatus.kills++;}

  static ITcommand dir_to_command(Dir dir);
  /* REQUIRES: dir is a "pure" direction or CO_air. */
  /* NOTE: CO_air -> IT_CENTER. */

  static ITcommand dir_to_command_weapon(Dir dir);

  static Dir command_weapon_to_dir_4(ITcommand);

  static Boolean is_command_weapon(ITcommand command)
    {return (command >= IT_WEAPON_R && command <= IT_WEAPON_UP_R) || 
       command == IT_WEAPON_CENTER;}

  static ITcommand center_pos_to_command(const Pos &pos);
  /* EFFECTS: Returns the command corresponding to the direction from (0,0) to
     pos. */
  /* NOTE: pos can have negative components. */
     

  void die(); 
  /* EFFECTS: Tell *this that it no longer has anything clocking it. */
  /* NOTE: This MUST be called at death.  Game requires it to refill machine
     players. */

  void reincarnate();
  /* EFFECTS: Tell *this that it will be clocked again. */

  virtual void clock(PhysicalP p);


 protected:
  const IntelOptions &get_intel_options() {return intelOptions;}

  void set_lives(int lives) 
    {intelStatus.lives = lives; intelStatusChanged = True;}


 private:
  IntelStatus intelStatus;
  Boolean intelStatusChanged; // Since last get_intel_status.
  Boolean living;
  WorldP world;
  LocatorP locator;
  Id id;
  IntelOptions intelOptions;

  const static IntelOptions intelOptionsDefault;
};
typedef Intel *IntelP;



// Simply buffers input from a user interface.
class Human: public Intel {
 public: 
  Human(WorldP w,LocatorP l,char *name,int lives,ColorNum colorNum);
  /* NOTE: Uses all default options.  intelOptions should be meaningless for 
     a human. */

  ColorNum get_color_num() {return colorNum;}

  virtual Boolean is_human() {return True;}
    
  virtual void clock(PhysicalP p);
  /* EFFECTS: Sets the command for p. */
  
  void set_command(ITcommand c) {command = c;}
  /* EFFECTS: Asynchronously set the command for the current turn to be c.
     Overrides previous settings. */

  void set_lives(int lives) {Intel::set_lives(lives);}


 private:
  ITcommand command;
  ColorNum colorNum;
};
typedef Human *HumanP;



class Machine: public Intel {
  enum Strategy {doNothing, toTarget, awayTarget, toPos};
  
public:
  Machine(WorldP w,LocatorP l,char *name,
	  const IntelOptions *ops,ITmask opMask);
  
  virtual void clock(PhysicalP);


private:
  PhysicalP new_target_id(Boolean &isEnemy,PhysicalP p);
  /* MODIFIES: isItem */
  /* EFFECTS: Get a new target for p.  Sets targetId, sets isEnemy to True iff
     returned pointer is an enemy (as opposed to an item).
     Returns NULL if no suitable target found. */

  void attack_target(PhysicalP p,PhysicalP target);

  void move_target(PhysicalP p,PhysicalP target);
  /* EFFECTS: Sets the command for p to move toward target. */

  void away_target(PhysicalP p,PhysicalP target);
  /* EFFECTS: Sets the command for p to move away from target. */

  void move_pos(PhysicalP p);
  /* EFFECTS: Sets the command for p to move toward targetPos. */

  void move_dir(PhysicalP p,Dir d);
  /* REQUIRES: d is an element of {CO_R..CO_UP_R,CO_air} */
  /* EFFECTS: Sets the command for p to move in specified direction. */

  Boolean has_gun(PhysicalP);
  Boolean has_cutter(PhysicalP);
  Boolean has_item(PhysicalP,ClassId);

  Boolean weapon_current_is_gun(PhysicalP);
  Boolean weapon_current_is_cutter(PhysicalP);


  Boolean commandSet;
  Strategy strategy;
  Pos targetPos;
  Id targetId;
  Timer strategyChange;
  Timer reflexes;
  Timer shotTimer;
  Timer ladderJump; // don't get back on ladder immediately after jumping off.
};
typedef Machine *MachineP;
#endif




;;;;;;;;; "locator.hh"
// "locator.hh" The object locator.  
// TAG: OL 

/*    Copyright (C) 1994  Steve Hardt

    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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

    Steve Hardt 
    hardts@athena.mit.edu (or hardts@r4002.3dem.bioch.bcm.tmc.edu)
    2043 McClendon
    Houston, TX 77030
*/

/* Overview: 
The locator can be seen as the collection of all physical objects in
the game.  It draws all objects with the draw method.  The clock
method goes through all the phases of one turn for all objects.  This
is the only entity in the game that has a list of all the objects.
Objects can be mapped and/or collidable.  An unmapped object is
neither drawn nor collided.  An uncollidable object is drawn (if
mapped) but not collided.  There is a message queue that objects can
use to communicate with the ui object.  The locator does not need to
be clocked for the queue to work. 
The locator grid is the maximum size of the world.  I.e. it can be larger than
the world. */


#ifndef LOCATOR_HH
#define LOCATOR_HH

#pragma interface


// Include Files
#include <iostream.h>

#include "utils.hh"
#include "coord.hh"
#include "id.hh"
#include "world.hh"

class Physical;
typedef Physical *PhysicalP;
class Human;
typedef Human *HumanP;
class Machine;
typedef Machine *MachineP;


// Defines
#define OL_LIST_MAX 1000
#define OL_NEARBY_MAX OL_LIST_MAX
#define OL_MESSAGES_MAX 300

#define OL_GRID_COL_MAX 4
#define OL_GRID_ROW_MAX 4
#define OL_GRID_WIDTH (OL_GRID_COL_MAX * WSQUARE_WIDTH) // In pixels.
#define OL_GRID_HEIGHT (OL_GRID_ROW_MAX * WSQUARE_HEIGHT) // In pixels.
#define OL_GRID_SIZE_MAX (max(OL_GRID_WIDTH,OL_GRID_HEIGHT))
#define OL_GRID_HORIZ_MAX (W_COL_MAX_MAX / OL_GRID_COL_MAX + 1)// grid squares.
#define OL_GRID_VERT_MAX (W_ROW_MAX_MAX / OL_GRID_ROW_MAX + 1) // grid squares.

#define OL_DRAWING_LEVELS 2

// Data Structures.
enum OLsig {OL_NO_SIG, OL_ALREADY_MANAGED, OL_NOT_FOUND};



// Class Declarations
class Locator;
class OLgridEntry;
class OLshadowEntry;


class OLentry {
  friend class Locator;
  friend class OLgridEntry; 
  friend class OLshadowEntry;
  
  OLgridEntry *gridEntry; /* Only valid if mapped. */
  GLoc gloc; /* Set by OLgridEntry::insert.  Not nec. valid. */
  OLshadowEntry *shadowEntry; /* Only valid if mapped. */
  GLoc shadowGloc; /* Set by OLshadowEntry::insert.  Not nec. valid. */


  Boolean valid; 
  Boolean reserved; // Meaningful when !valid.
  PhysicalP physical; // Set when reserved.
  
  Boolean collided;
  Boolean mapped; // Redundant.  Must be same as in object. 
  Boolean collidable;
};



class OLgridEntry {
 public:
  OLgridEntry(OLentry *e) {entry = e; prev = next = NULL;}
  
  PhysicalP get_physical() {return entry->physical;}
  Boolean get_collided() {return entry->collided;}
  Boolean get_mapped() {return entry->mapped;}
  OLshadowEntry *get_shadow_entry() {return entry->shadowEntry;}
  const Area &get_area(); 

  int get_drawing_level();

  Boolean get_collidable() {return entry->collidable;}
  OLgridEntry *get_next() {return next;}

  void set_collided(Boolean val) {entry->collided = val;}

  void insert(OLgridEntry *grid[OL_GRID_VERT_MAX][OL_GRID_HORIZ_MAX],
	      const GLoc &gl);
  /* NOTE: gl does not have to be valid. */
  void remove();

  
 private:
  OLgridEntry *prev, *next;
  OLentry *entry;
};
// This typedef not always used.  OLgridEntry::insert
typedef OLgridEntry *OLgrid[OL_GRID_VERT_MAX][OL_GRID_HORIZ_MAX];



class OLshadowEntry {
 public:
  OLshadowEntry() {entry = NULL; prev = next = NULL; orphaned = False;}
  OLshadowEntry(const Area &a,OLentry *e) 
    {area = a; entry = e; prev = next = NULL; orphaned = False;}
  Boolean get_orphaned() {return orphaned;}

  OLentry *get_entry() {assert(entry); return entry;}
  OLgridEntry *get_grid_entry() {assert(entry); return entry->gridEntry;}
  const Area &get_area() {return area;}
  Boolean draw_self() {return drawSelf;}
  OLshadowEntry *get_next() {return next;}
  /* NOTE: Several require that the shadowEntry is not orphaned. */

  void set_area(const Area &a) {area = a;}
  void set_draw_self(Boolean val) {drawSelf = val;}
  void set_orphaned() {orphaned = True; entry = NULL;}


  void insert(OLshadowEntry *shadows[OL_GRID_VERT_MAX][OL_GRID_HORIZ_MAX],
	      const GLoc &gl);
  void remove();


 private:
  Boolean orphaned;
  Area area;
  Boolean drawSelf;
  OLentry *entry;
  OLshadowEntry *prev, *next;
};
typedef OLshadowEntry *OLshadows[OL_GRID_VERT_MAX][OL_GRID_HORIZ_MAX];



class Locator {
  struct OLxdata 
    {
      Pixmap roomBuffer; // When changing rooms.
      Pixmap buffer;
    };


  // Iterator to extract all humans to be reincarnated.
  class Incarnator {
  public:
    Incarnator::Incarnator(Locator &l) {n = 0; locator = &l;}

    HumanP operator () ();
    /* EFFECTS: Extract next object to be reincarnated.  Return NULL if none.
       The returned HumanP can only be extracted once. */

  private:
    int n;
    Locator *locator;
  };

friend class Locator::Incarnator;


 public:
  enum { HUMANS_MAX = Utils::HUMAN_COLORS_NUM, // <= UI_VIEWPORTS_MAX.
           MACHINES_MAX = 200,
	   GENERATORS_MAX = 30,
       };

  Locator();
  /* EFFECTS: Create a new object locator with no managed objects. */

  static Boolean valid(const GLoc &gl) 
    {return ((gl.vert >= 0) && (gl.horiz >= 0) && 
	     (gl.vert < OL_GRID_VERT_MAX) && (gl.horiz < OL_GRID_HORIZ_MAX));} 
  /* EFFECTS:  Is gl a loc in the grid. */

  void add(PhysicalP p);
  /* REQUIRES: p is not already managed. */
  /* EFFECTS: p will be added to the list of managed physicals at the beginning
     of the next clock.  p is initially mapped.  canCollide is set from p.
     If called inside clock, object will not be added until beginning of next
     clock.  You should not add something twice. */

  void get_nearby(PhysicalP nearby[OL_NEARBY_MAX],int &nitems,
		  PhysicalP p,int radius);
  /* MODIFIES: nearby,nitems. */
  /* EFFECTS:  Returns all objects that have their middles within radius of 
     p's middle.  (I.e <= ) */  
  /* NOTE: Expensive. */

  OLsig lookup(PhysicalP &p, const Id &id);
  /* MODIFIES: p */
  /* EFFECTS: Set p to be the object corresponding to id if it is managed 
     and return OL_NO_SIG.  Otherwise return OL_NOT_FOUND. */

  PhysicalP lookup(const Id &id);
  /* EFFECTS: Same as above except return NULL iff not found. */

  void draw(WorldP world,Drawable window,Xvars &xvars,const Box &box);
  /* REQUIRES: win is the same size as Box. (Adjusted for size of WSQUAREs.) */

  void reset();

  void clock();


  // Message service.
  void message_enq(char *msg);
  /* EFFECTS:  Enqueue msg in the queue of messages for the ui.  The ui will 
     free msg when it is done with it. */

  char *message_deq();
  /* EFFECTS: Dequeue the next message of the message queue or return NULL if
     the queue is empty. */


  // Player registry service.  Takes responsibility for reincarnation.
  void register_human(HumanP); // Kept until reset.
  void register_machine(MachineP); // Deleted as needed.
  void register_generator(const Id &); // Id is kept until reset.
  
  int humans_playing();
  int machines_alive();
  int generators_alive();

  HumanP get_human(int n) {assert(n < humansNum);  return humans[n];}
  /* REQUIRES: n < the number of humans registered */

  
 private:
  enum { REINCARNATE_TIME = 70 };

  void add_now(PhysicalP);
  void del_now(PhysicalP);

  void allign_mapped(int n);
  /* EFFECTS: Checks to see if physical n has changed its mapped attribute.  If
     so, adjust the mapped attribute in *this. */
  /* REQUIRES: n is a valid list index. */

  void init_x(WorldP,Xvars &);
  /* NOTES: world just for roomSize. */

  Id reserve_list_entry(PhysicalP p);
  /* EFFECTS: Reserve an entry in the list for p and return an Id for the
     entry. */
  
  void collision_checks();
  /* EFFECTS: Do collision checks between all registered objects. */

  GLoc compute_gloc(PhysicalP);
  GLoc compute_gloc(const Area &);
  /* EFFECTS: Compute the location in the grid for a physical or an area. */
  /* NOTE: Ok to return invalid gloc. */

  void draw_area(WorldP world,Drawable window,Xvars &xvars,const Box &room,
		 const Area &area,const GLoc &gloc);
  /* REQUIRES: area is centered at gloc. window is the size of room*/
  /* EFFECTS: Draws world and all objects overlapping area. */
  /* NOTE: box does not have to be valid. */

  void reincarnate_clock();


  // Data.
  int uniqueGen;
  int listMax; // All valid entries in the list have index < listMax.
  OLentry list[OL_LIST_MAX];
  OLgrid grid;

  OLshadows shadows;
  OLshadowEntry *shadowDelList[OL_LIST_MAX];
  int shadowDelNum;

  PhysicalP addList[OL_LIST_MAX];
  int addNum;

  Boolean xValid;
  OLxdata xdata;

  // Message service.
  char *messages[OL_MESSAGES_MAX];
  int head,tail; 

  // Player registry service.
  HumanP humans[HUMANS_MAX];
  MachineP machines[MACHINES_MAX];
  Id generators[GENERATORS_MAX];
  int humansNum;
  int machinesNum;
  int generatorsNum;
  Boolean reincarnating[HUMANS_MAX]; // Just for humans.
  Timer reincarnateTimers[HUMANS_MAX]; // Just for humans.
};
typedef Locator *LocatorP;
#endif

home help back first fref pref prev next nref lref last post