From 3b67b219c93e163d70481e1a5c83f19789e33d16 Mon Sep 17 00:00:00 2001
From: jsalmon3 <>
Date: Sat, 10 Aug 2002 00:18:51 +0000
Subject: [PATCH] Changed Unit::Frame and Unit::SeenFrame to ints, added
 UnitType::NumDirections and MissileType::NumDirections

---
 src/action/action_move.cpp       |  6 +++++-
 src/action/actions.cpp           |  6 +++++-
 src/include/missile.h            |  5 +++++
 src/include/unit.h               |  7 +++---
 src/include/unittype.h           |  9 ++++++--
 src/stratagus/missile.cpp        | 25 +++++++++++----------
 src/stratagus/script_missile.cpp |  3 +++
 src/unit/script_unit.cpp         |  6 +++---
 src/unit/script_unittype.cpp     |  6 +++++-
 src/unit/unit.cpp                | 37 ++++++++++++++++++--------------
 src/unit/unit_draw.cpp           |  4 ++--
 src/unit/unittype.cpp            |  6 +++---
 12 files changed, 77 insertions(+), 43 deletions(-)

diff --git a/src/action/action_move.cpp b/src/action/action_move.cpp
index a0927e4fa..bcdc3ae6c 100644
--- a/src/action/action_move.cpp
+++ b/src/action/action_move.cpp
@@ -192,7 +192,11 @@ local int ActionMoveGeneric(Unit* unit,const Animation* anim)
     //
     unit->IX+=xd*anim[state].Pixel;
     unit->IY+=yd*anim[state].Pixel;
-    unit->Frame+=anim[state].Frame;
+    if( unit->Frame<0 ) {
+	unit->Frame+=-anim[state].Frame;
+    } else {
+	unit->Frame+=anim[state].Frame;
+    }
     unit->Wait=anim[state].Sleep;
     if( unit->Slow ) {			// unit is slowed down
 	unit->Wait<<=1;
diff --git a/src/action/actions.cpp b/src/action/actions.cpp
index 44eb7cea0..7e293b1ae 100644
--- a/src/action/actions.cpp
+++ b/src/action/actions.cpp
@@ -86,7 +86,11 @@ global int UnitShowAnimation(Unit* unit,const Animation* animation)
 	    _C_ animation[state].Frame _C_ animation[state].Sleep);
     DebugLevel3("Heading %d +%d,%d\n" _C_ unit->Direction _C_ unit->IX _C_ unit->IY);
 
-    unit->Frame+=animation[state].Frame;
+    if( unit->Frame<0 ) {
+	unit->Frame+=-animation[state].Frame;
+    } else {
+	unit->Frame+=animation[state].Frame;
+    }
     unit->IX+=animation[state].Pixel;
     unit->IY+=animation[state].Pixel;
     unit->Wait=animation[state].Sleep;
diff --git a/src/include/missile.h b/src/include/missile.h
index fca7dd1da..5fda8848c 100644
--- a/src/include/missile.h
+++ b/src/include/missile.h
@@ -84,6 +84,10 @@
 **		@note There is currently a limit of 127 sprite frames, which
 **		can be lifted if needed.
 **
+**	MissileType::NumDirections
+**
+**		Number of directions missile can face.
+**
 **	MissileType::FiredSound
 **
 **		Sound of the missile, if fired. @note currently not used.
@@ -328,6 +332,7 @@ struct _missile_type_ {
     unsigned	Width;			/// missile width in pixels
     unsigned	Height;			/// missile height in pixels
     unsigned	SpriteFrames;		/// number of sprite frames in graphic
+    int		NumDirections;		/// number of directions missile can face
 
 	// FIXME: FireSound defined but not used!
     SoundConfig FiredSound;		/// fired sound
diff --git a/src/include/unit.h b/src/include/unit.h
index 7ae5a5573..8256494d8 100644
--- a/src/include/unit.h
+++ b/src/include/unit.h
@@ -142,7 +142,7 @@
 **	Unit::SeenFrame
 **
 **		Graphic image (see Unit::Frame) what the player on this
-**		computer has last seen. If -1 (0xFF) the player haven't seen
+**		computer has last seen. If UnitNotSeen the player haven't seen
 **		this unit yet.
 **
 **	Unit::Direction
@@ -455,6 +455,7 @@ enum _directions_ {
 };
 
 #define NextDirection	32		/// Next direction N->NE->E...
+#define UnitNotSeen	0x7fffffff	/// Unit not seen, used by Unit::SeenFrame
 
     /// The big unit structure
 struct _unit_ {
@@ -478,8 +479,8 @@ struct _unit_ {
     UnitColors	Colors;			/// Player colors
     char	IX;			/// X image displacement to map position
     char	IY;			/// Y image displacement to map position
-    unsigned	Frame : 8;		/// Image frame: high bit used for flip
-    unsigned	SeenFrame : 8;		/// last seen frame/stage of buildings
+    int		Frame;			/// Image frame: <0 is mirrored
+    int		SeenFrame;		/// last seen frame/stage of buildings
 
     unsigned	Direction : 8;		/// angle (0-255) unit looking
 
diff --git a/src/include/unittype.h b/src/include/unittype.h
index e12660b94..f3ae87897 100644
--- a/src/include/unittype.h
+++ b/src/include/unittype.h
@@ -158,6 +158,10 @@
 **
 **		Selected box size height
 **
+**	UnitType::NumDirections
+**
+**		Number of directions the unit can face
+**
 **	UnitType::MinAttackRange
 **
 **		Minimal attack range
@@ -425,7 +429,7 @@ typedef struct _animation_ {
     unsigned char	Flags;		/// Flags for actions
     signed char		Pixel;		/// Change the position in pixels
     unsigned char	Sleep;		/// Wait for next animation
-    unsigned char	Frame;		/// Sprite-frame to display
+    int			Frame;		/// Sprite-frame to display
 } Animation;
 
 #define AnimationRestart	1	/// Restart animation
@@ -497,6 +501,7 @@ struct _unit_type_ {
     int		TileHeight;		/// Tile size on map height
     int		BoxWidth;		/// Selected box size width
     int		BoxHeight;		/// Selected box size height
+    int		NumDirections;		/// Number of directions unit can face
     int		MinAttackRange;		/// Minimal attack range
     int		_AttackRange;		/// How far can the unit attack
     int		ReactRangeComputer;	/// Reacts on enemy for computer
@@ -636,7 +641,7 @@ extern Animations* AnimationsByIdent(const char* ident);
 extern void SaveUnitTypes(FILE* file);	/// Save the unit-type table
 extern UnitType* NewUnitTypeSlot(char*);/// Allocate an empty unit-type slot
     /// Draw the sprite frame of unit-type
-extern void DrawUnitType(const UnitType* type,unsigned frame,int x,int y);
+extern void DrawUnitType(const UnitType* type,int frame,int x,int y);
 
 extern void InitUnitTypes(void);	/// Init unit-type table
 extern void LoadUnitTypes(void);	/// Load the unit-type data
diff --git a/src/stratagus/missile.cpp b/src/stratagus/missile.cpp
index 3c8bb5d26..1a0ad7eb7 100644
--- a/src/stratagus/missile.cpp
+++ b/src/stratagus/missile.cpp
@@ -761,11 +761,11 @@ global int CheckMissileToBeDrawn(const Missile* missile)
 /**
 **	Draw missile.
 */
-global void DrawMissile(const MissileType* mtype,unsigned frame,int x,int y)
+local void DrawMissile(const MissileType* mtype,int frame,int x,int y)
 {
     // FIXME: This is a hack for mirrored sprites
-    if( frame&128 ) {
-	VideoDrawClipX(mtype->Sprite,frame&127,x,y);
+    if( frame<0 ) {
+	VideoDrawClipX(mtype->Sprite,-frame,x,y);
     } else {
 	VideoDrawClip(mtype->Sprite,frame,x,y);
     }
@@ -845,18 +845,21 @@ global void DrawMissiles(void)
 local void MissileNewHeadingFromXY(Missile* missile,int dx,int dy)
 {
     int dir;
+    int nextdir;
 
-    // FIXME: depends on the missile directions wc 8, sc 32
-    missile->SpriteFrame&=127;
-    missile->SpriteFrame/=5;
-    missile->SpriteFrame*=5;
+    if( missile->SpriteFrame<0 ) {
+	missile->SpriteFrame=-missile->SpriteFrame;
+    }
+    missile->SpriteFrame/=missile->Type->NumDirections/2+1;
+    missile->SpriteFrame*=missile->Type->NumDirections/2+1;
 
-    dir=((DirectionToHeading(dx,dy)+NextDirection/2)&0xFF)/NextDirection;
-    if( dir<=LookingS/NextDirection ) {	// north->east->south
+    nextdir=256/missile->Type->NumDirections;
+    dir=((DirectionToHeading(dx,dy)+nextdir/2)&0xFF)/nextdir;
+    if( dir<=LookingS/nextdir ) {	// north->east->south
 	missile->SpriteFrame+=dir;
     } else {
-	// Note: 128 is the flag for flip graphic in X.
-	missile->SpriteFrame+=128+256/NextDirection-dir;
+	missile->SpriteFrame+=256/nextdir-dir;
+	missile->SpriteFrame=-missile->SpriteFrame;
     }
 }
 
diff --git a/src/stratagus/script_missile.cpp b/src/stratagus/script_missile.cpp
index 6eb88f832..212a79f16 100644
--- a/src/stratagus/script_missile.cpp
+++ b/src/stratagus/script_missile.cpp
@@ -80,6 +80,7 @@ local SCM CclDefineMissileType(SCM list)
 	mtype=NewMissileTypeSlot(str);	// str consumed!
     }
 
+    mtype->NumDirections=8;
     //
     //	Parse the arguments, already the new tagged format.
     //
@@ -96,6 +97,8 @@ local SCM CclDefineMissileType(SCM list)
 	    mtype->Height=gh_scm2int(gh_car(value));
 	} else if( gh_eq_p(value,gh_symbol2scm("frames")) ) {
 	    mtype->SpriteFrames=gh_scm2int(gh_car(list));
+	} else if( gh_eq_p(value,gh_symbol2scm("num-directions")) ) {
+	    mtype->NumDirections=gh_scm2int(gh_car(list));
 	} else if( gh_eq_p(value,gh_symbol2scm("fired-sound")) ) {
 	    free(mtype->FiredSound.Name);
 	    mtype->FiredSound.Name=gh_scm2newstr(gh_car(list),NULL);
diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp
index 532b49713..fc346105f 100644
--- a/src/unit/script_unit.cpp
+++ b/src/unit/script_unit.cpp
@@ -498,16 +498,16 @@ local SCM CclUnit(SCM list)
 	    unit->Frame=gh_scm2int(gh_car(list));
 	    list=gh_cdr(list);
 	} else if( gh_eq_p(value,gh_symbol2scm("flipped-frame")) ) {
-	    unit->Frame=128|gh_scm2int(gh_car(list));
+	    unit->Frame=-gh_scm2int(gh_car(list));
 	    list=gh_cdr(list);
 	} else if( gh_eq_p(value,gh_symbol2scm("seen")) ) {
 	    unit->SeenFrame=gh_scm2int(gh_car(list));
 	    list=gh_cdr(list);
 	} else if( gh_eq_p(value,gh_symbol2scm("flipped-seen")) ) {
-	    unit->SeenFrame=128|gh_scm2int(gh_car(list));
+	    unit->SeenFrame=-gh_scm2int(gh_car(list));
 	    list=gh_cdr(list);
 	} else if( gh_eq_p(value,gh_symbol2scm("not-seen")) ) {
-	    unit->SeenFrame=-1;
+	    unit->SeenFrame=UnitNotSeen;
 	} else if( gh_eq_p(value,gh_symbol2scm("direction")) ) {
 	    unit->Direction=gh_scm2int(gh_car(list));
 	    list=gh_cdr(list);
diff --git a/src/unit/script_unittype.cpp b/src/unit/script_unittype.cpp
index 144ce7116..f11d50051 100644
--- a/src/unit/script_unittype.cpp
+++ b/src/unit/script_unittype.cpp
@@ -84,11 +84,12 @@ local SCM CclDefineUnitType(SCM list)
     if( type ) {
 	DebugLevel0Fn("Redefining unit-type `%s'\n" _C_ str);
 	free(str);
-	// FIXME: loose memory, old content isn't freed.
+	// FIXME: lose memory, old content isn't freed.
     } else {
 	type=NewUnitTypeSlot(str);
     }
 
+    type->NumDirections=8;
     //
     //	Parse the list:	(still everything could be changed!)
     //
@@ -189,6 +190,9 @@ local SCM CclDefineUnitType(SCM list)
 	    list=gh_cdr(list);
 	    type->BoxWidth=gh_scm2int(gh_car(sublist));
 	    type->BoxHeight=gh_scm2int(gh_cadr(sublist));
+	} else if( gh_eq_p(value,gh_symbol2scm("num-directions")) ) {
+	    type->NumDirections=gh_scm2int(gh_car(list));
+	    list=gh_cdr(list);
 	} else if( gh_eq_p(value,gh_symbol2scm("sight-range")) ) {
 	    type->_SightRange=gh_scm2int(gh_car(list));
 	    list=gh_cdr(list);
diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp
index c9419b943..36fd99759 100644
--- a/src/unit/unit.cpp
+++ b/src/unit/unit.cpp
@@ -266,7 +266,7 @@ global void InitUnit(Unit* unit, UnitType* type)
     //  Initialise unit structure (must be zero filled!)
     //
     unit->Type = type;
-    unit->SeenFrame = 0xFF;		// Unit isn't yet seen
+    unit->SeenFrame = UnitNotSeen;		// Unit isn't yet seen
 
     // FIXME: this is not needed for load+save, must move to other place
     if (1) {				// Call CCL for name generation
@@ -543,7 +543,7 @@ global Unit* MakeUnitAndPlace(int x,int y,UnitType* type,Player* player)
 	//	fancy buildings: mirror buildings (but shadows not correct)
 	//
 	if ( FancyBuildings && unit->Rs > 50 ) {
-	    unit->Frame |= 128;
+	    unit->Frame = -unit->Frame;
 	}
     }
 
@@ -1057,7 +1057,7 @@ global int UnitKnownOnMap(const Unit* unit)
     for( ; h-->0; ) {
 	for( w=w0; w-->0; ) {
 	    if( IsMapFieldVisible(x+w,y+h)
-		    || (unit->Type->Building && unit->SeenFrame!=0xFF
+		    || (unit->Type->Building && unit->SeenFrame!=UnitNotSeen
 			&& IsMapFieldExplored(x+w,y+h)) ) {
 		return 1;
 	    }
@@ -1131,7 +1131,7 @@ global int UnitVisibleInViewport (int v, const Unit* unit)
     for( ; h-->0; ) {
 	for( w=w0; w-->0; ) {
 	    if( IsMapFieldVisible(x+w,y+h)
-		    || (unit->Type->Building && unit->SeenFrame!=0xFF
+		    || (unit->Type->Building && unit->SeenFrame!=UnitNotSeen
 			&& IsMapFieldExplored(x+w,y+h)) ) {
 		return 1;
 	    }
@@ -1210,7 +1210,7 @@ global int UnitVisibleOnScreen(const Unit* unit)
     for( ; h-->0; ) {
 	for( w=w0; w-->0; ) {
 	    if( IsMapFieldVisible(x+w,y+h)
-		    || (unit->Type->Building && unit->SeenFrame!=0xFF
+		    || (unit->Type->Building && unit->SeenFrame!=UnitNotSeen
 			&& IsMapFieldExplored(x+w,y+h)) ) {
 		return 1;
 	    }
@@ -1804,17 +1804,22 @@ global int DirectionToHeading(int delta_x,int delta_y)
 global void UnitUpdateHeading(Unit* unit)
 {
     int dir;
+    int nextdir;
 
-    // FIXME: depends on the possible unit directions wc 8, sc 32
-    unit->Frame&=127;
-    unit->Frame/=5;
-    unit->Frame*=5;		// Remove heading, keep animation frame
-    dir=((unit->Direction+NextDirection/2)&0xFF)/NextDirection;
-    if( dir<=LookingS/NextDirection ) {	// north->east->south
+    if( unit->Frame<0 ) {
+	unit->Frame=-unit->Frame;
+    }
+    unit->Frame/=unit->Type->NumDirections/2+1;
+    unit->Frame*=unit->Type->NumDirections/2+1;
+    // Remove heading, keep animation frame
+
+    nextdir=256/unit->Type->NumDirections;
+    dir=((unit->Direction+nextdir/2)&0xFF)/nextdir;
+    if( dir<=LookingS/nextdir ) {	// north->east->south
 	unit->Frame+=dir;
     } else {
-	// Note: 128 is the flag for flip graphic in X.
-	unit->Frame+=128+256/NextDirection-dir;
+	unit->Frame+=256/nextdir-dir;
+	unit->Frame=-unit->Frame;
     }
 }
 
@@ -3856,10 +3861,10 @@ global void SaveUnit(const Unit* unit,FILE* file)
 #endif
     fprintf(file,"'pixel '(%d %d) ",unit->IX,unit->IY);
     fprintf(file,"'%sframe %d ",
-	    unit->Frame&128 ? "flipped-" : "" ,unit->Frame&127);
-    if( unit->SeenFrame!=0xFF ) {
+	    unit->Frame<0 ? "flipped-" : "" ,unit->Frame<0?-unit->Frame:unit->Frame);
+    if( unit->SeenFrame!=UnitNotSeen ) {
 	fprintf(file,"'%sseen %d ",
-		unit->SeenFrame&128 ? "flipped-" : "" ,unit->SeenFrame&127);
+		unit->SeenFrame<0 ? "flipped-" : "" ,unit->SeenFrame<0?-unit->SeenFrame:unit->SeenFrame);
     } else {
 	fprintf(file,"'not-seen ");
     }
diff --git a/src/unit/unit_draw.cpp b/src/unit/unit_draw.cpp
index d0491a03b..e9be8ad94 100644
--- a/src/unit/unit_draw.cpp
+++ b/src/unit/unit_draw.cpp
@@ -1646,7 +1646,7 @@ local void DrawBuilding(Unit* unit)
 	frame = unit->SeenFrame = unit->Frame;
     } else {
 	frame = unit->SeenFrame;
-	DebugCheck( frame==-1 || frame==0xFF );
+	DebugCheck( frame==UnitNotSeen );
     }
 
     type=unit->Type;
@@ -1678,7 +1678,7 @@ local void DrawBuilding(Unit* unit)
     } else if( unit->Orders[0].Action==UnitActionUpgradeTo ) {
 	// FIXME: this frame is hardcoded!!!
 	GraphicUnitPixels(unit,unit->Orders[0].Type->Sprite);
-	DrawUnitType(unit->Orders[0].Type,(frame&128)+1,x,y);
+	DrawUnitType(unit->Orders[0].Type,frame<0?-1:1,x,y);
     } else {
 	GraphicUnitPixels(unit,type->Sprite);
 	DrawUnitType(type,frame,x,y);
diff --git a/src/unit/unittype.cpp b/src/unit/unittype.cpp
index f165dbaa5..e858ec5d4 100644
--- a/src/unit/unittype.cpp
+++ b/src/unit/unittype.cpp
@@ -1070,15 +1070,15 @@ global UnitType* NewUnitTypeSlot(char* ident)
 **	@todo	Do screen position caculation in high level.
 **		Better way to handle in x mirrored sprites.
 */
-global void DrawUnitType(const UnitType* type,unsigned frame,int x,int y)
+global void DrawUnitType(const UnitType* type,int frame,int x,int y)
 {
     // FIXME: move this calculation to high level.
     x-=(type->Width-type->TileWidth*TileSizeX)/2;
     y-=(type->Height-type->TileHeight*TileSizeY)/2;
 
     // FIXME: This is a hack for mirrored sprites
-    if( frame&128 ) {
-	VideoDrawClipX(type->Sprite,frame&127,x,y);
+    if( frame<0 ) {
+	VideoDrawClipX(type->Sprite,-frame,x,y);
     } else {
 	VideoDrawClip(type->Sprite,frame,x,y);
     }