From 5fdfac786365c955f0461211fb5104413bd9c7e8 Mon Sep 17 00:00:00 2001
From: johns <>
Date: Sun, 28 May 2000 21:09:00 +0000
Subject: [PATCH] Units could now be stored on map, perhaps better performance
 than old version.

---
 src/include/map.h             |  23 ++-
 src/include/unit.h            |  21 ++-
 src/pathfinder/pathfinder.cpp |  12 +-
 src/unit/unit.cpp             |   4 +-
 src/unit/unit_cache.cpp       | 265 +++++++++++++++++++++++++++++++---
 src/unit/unit_find.cpp        |  36 +++--
 6 files changed, 304 insertions(+), 57 deletions(-)

diff --git a/src/include/map.h b/src/include/map.h
index 506a5bc13..151b1a49d 100644
--- a/src/include/map.h
+++ b/src/include/map.h
@@ -44,6 +44,20 @@
 --	Map - field
 ----------------------------------------------------------------------------*/
 
+#ifdef UNIT_ON_MAP
+/**
+**	All units on a map field, if more than one.
+**	FIXME: unused
+*/
+typedef struct _unit_array_ {
+    Unit*		Building;	/// Building or corpse.
+    Unit*		SeaUnit;	/// Sea unit.
+    Unit*		LandUnit;	/// Land unit.
+    Unit*		AirUnit;	/// Air unit.
+} UnitArray;
+
+#endif
+
 /**
 **	Describes a field of the map.
 */
@@ -61,10 +75,11 @@ typedef struct _map_field_ {
 #ifdef UNIT_ON_MAP
     union {
 	Unit*		Units;		/// An unit on the map field.
-	Unit**		Array;		/// More units on the map field.
+	UnitArray*	Array;		/// More units on the map field.
     }			Here;		/// What is on the field.
 #endif
 #ifdef UNITS_ON_MAP
+// FIXME: Unused
     UnitRef		Building;	/// Building or corpse.
     UnitRef		AirUnit;	/// Air unit.
     UnitRef		LandUnit;	/// Land unit.
@@ -159,11 +174,11 @@ extern int ForestRegeneration;
 //	in map_draw.c
 //
     /// Fast draw 32x32 tile for 32 bpp video modes.
-extern void VideoDraw32Tile32(const unsigned char* data,int x,int y);
+//extern void VideoDraw32Tile32(const unsigned char* data,int x,int y);
     /// Fast draw 32x32 tile for 16 bpp video modes.
-extern void VideoDraw16Tile32(const unsigned char* data,int x,int y);
+//extern void VideoDraw16Tile32(const unsigned char* data,int x,int y);
     /// Fast draw 32x32 tile for  8 bpp video modes.
-extern void VideoDraw8Tile32(const unsigned char* data,int x,int y);
+//extern void VideoDraw8Tile32(const unsigned char* data,int x,int y);
 
     /// Called when the color cycles
 extern void MapColorCycle(void);
diff --git a/src/include/unit.h b/src/include/unit.h
index 08508d1ec..345fd9525 100644
--- a/src/include/unit.h
+++ b/src/include/unit.h
@@ -463,19 +463,21 @@ extern void SaveUnit(const Unit* unit,FILE* file);	/// save unit-structure
 extern void SaveUnits(FILE* file);			/// save all units
 
 //	in unitcache.c
-    /// FIXME: more docu
+    /// Insert new unit into cache.
 extern void UnitCacheInsert(Unit* unit);
-    /// FIXME: more docu
+    /// Remove unit from cache.
 extern void UnitCacheRemove(Unit* unit);
-    /// FIXME: more docu
+    /// Change unit position in cache.
 extern void UnitCacheChange(Unit* unit);
-    /// FIXME: more docu
+    /// Select units in range.
 extern int UnitCacheSelect(int x1,int y1,int x2,int y2,Unit** table);
-    /// FIXME: more docu
+    /// Select units on tile.
+extern int UnitCacheOnTile(int x,int y,Unit** table);
+    /// Select unit on X,Y of type naval,fly,land.
 extern Unit* UnitCacheOnXY(int x,int y,int type);
-    /// FIXME: more docu
+    /// Print unit-cache statistic.
 extern void UnitCacheStatistic(void);
-    /// FIXME: more docu
+    /// Initialize unit-cache.
 extern void InitUnitCache(void);
 
 // 	in map.c 	belongs to map or unit??
@@ -499,8 +501,11 @@ extern void LoadDecorations(void);
 extern void DrawUnits(void);
 
 //	in unit_find.c
-    /// FIXME: more docu
+    /// Select units in rectangle range.
 extern int SelectUnits(int x1,int y1,int x2,int y2,Unit** table);
+    /// Select units on map tile.
+extern int SelectUnitsOnTile(int x,int y,Unit** table);
+
     /// Find all units of this type
 extern int FindUnitsByType(const UnitType* type,Unit** table);
     /// Find all units of this type of the player
diff --git a/src/pathfinder/pathfinder.cpp b/src/pathfinder/pathfinder.cpp
index 78e3b02be..2db0f9f87 100644
--- a/src/pathfinder/pathfinder.cpp
+++ b/src/pathfinder/pathfinder.cpp
@@ -645,23 +645,13 @@ local int ComplexNewPath(Unit* unit,int *xdp,int* ydp)
 		    }
 		    goal=UnitCacheOnXY(x,y,unit->Type->UnitType);
 		    if( !goal ) {
+			// Should not happen.
 			DebugLevel0(__FUNCTION__
 			    ": %p No goal for %d,%d on %d,%d?\n",
 				    unit,unit->X,unit->Y,x,y);
-			//	Clear movement flag from MovementMap
-			//	for this type of unit
-			//TheMap.MovementMap[x+y*TheMap.Width]&=
-			//	~UnitMovement(unit);
 			matrix[w+1+x+y*w]=99;
 			continue;
 		    }
-#if 0
-		    // FIXME: Have more move actions
-		    if( goal->Command.Action!=UnitActionMove ) {
-			matrix[w+1+x+y*w]=99;
-			continue;
-		    }
-#endif
 		    if( !goal->Moving ) {
 			matrix[w+1+x+y*w]=99;
 			continue;
diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp
index 032182e71..7f6a72c46 100644
--- a/src/unit/unit.cpp
+++ b/src/unit/unit.cpp
@@ -283,7 +283,7 @@ global Unit* MakeUnit(UnitType* type,Player* player)
 	    return NoUnitP;
 	}
 	UnitSlotFree=(void*)*slot;
-	*slot=unit=calloc(1,sizeof(Unit));
+	*slot=unit=calloc(1,sizeof(*unit));
 	unit->Refs=1;
 	unit->Slot=slot-UnitSlots;		// back index
     }
@@ -1025,7 +1025,7 @@ global void RescueUnits(void)
 	    for( j=0; j<l; j++ ) {
 		unit=table[j];
 		DebugLevel3("Checking %Zd\n",UnitNumber(unit));
-		// NOTE: I hope SelectUnits checks bounds?
+		// FIXME: I hope SelectUnits checks bounds? NO
 		n=SelectUnits(
 			unit->X-1,unit->Y-1,
 			unit->X+unit->Type->TileWidth+1,
diff --git a/src/unit/unit_cache.cpp b/src/unit/unit_cache.cpp
index bd6597d9d..5c1aab7c4 100644
--- a/src/unit/unit_cache.cpp
+++ b/src/unit/unit_cache.cpp
@@ -8,27 +8,33 @@
 //			  T H E   W A R   B E G I N S
 //	   FreeCraft - A free fantasy real time strategy game engine
 //
-/**@name unitcache.c	-	The unit cache.
-**
-**		Cache to find units faster from position.
-**		I use a radix-quad-tree for lookups.
-**		Other possible data-structures:
-**			Binary Space Partitioning (BSP) tree.
-**			Real quad tree.
-**			Priority search tree.
-*/
-/*	(c) Copyright 1998-2000 by Lutz Sammer
-**
-**	$Id$
-*/
+/**@name unitcache.c	-	The unit cache. */
+//
+//	Cache to find units faster from position.
+//	I use a radix-quad-tree for lookups.
+//	Other possible data-structures:
+//		Binary Space Partitioning (BSP) tree.
+//		Real quad tree.
+//		Priority search tree.
+//
+//	(c) Copyright 1998-2000 by Lutz Sammer
+//
+//	$Id$
 
 //@{
 
+/*----------------------------------------------------------------------------
+--	Includes
+----------------------------------------------------------------------------*/
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "freecraft.h"
+
+#ifndef UNIT_ON_MAP	// {
+
 #include "video.h"
 #include "sound_id.h"
 #include "unitsound.h"
@@ -42,7 +48,9 @@
 //	Quadtrees
 //****************************************************************************/
 
+#ifdef DEBUG
 #define STATISTIC			/// include statistic code
+#endif
 
 //
 //	Types
@@ -594,10 +602,12 @@ local void QuadTreePrintStatistic(QuadTree* tree)
 //	Convert calls to internal
 //****************************************************************************/
 
-local QuadTree* PositionCache;
+local QuadTree* PositionCache;		/// My quad tree for lookup
 
 /**
 **	Insert new unit into cache.
+**
+**	@param unit	Unit pointer to place in cache.
 */
 global void UnitCacheInsert(Unit* unit)
 {
@@ -607,6 +617,8 @@ global void UnitCacheInsert(Unit* unit)
 
 /**
 **	Remove unit from cache.
+**
+**	@param unit	Unit pointer to remove from cache.
 */
 global void UnitCacheRemove(Unit* unit)
 {
@@ -615,7 +627,9 @@ global void UnitCacheRemove(Unit* unit)
 }
 
 /**
-**	Change unit in cache.
+**	Change unit position in cache.
+**
+**	@param unit	Unit pointer to change in cache.
 */
 global void UnitCacheChange(Unit* unit)
 {
@@ -624,10 +638,15 @@ global void UnitCacheChange(Unit* unit)
 }
 
 /**
-**	Select units in range.
+**	Select units in rectangle range.
 **
-**	table:	contains all units in given range.
-**	RETURNS:number of units in table.
+**	@param x1	Left column of selection rectangle
+**	@param y1	Top row of selection rectangle
+**	@param x2	Right column of selection rectangle
+**	@param y2	Bottom row of selection rectangle
+**	@param table	All units in the selection rectangle
+**
+**	@return		Returns the number of units found
 */
 global int UnitCacheSelect(int x1,int y1,int x2,int y2,Unit** table)
 {
@@ -642,6 +661,16 @@ global int UnitCacheSelect(int x1,int y1,int x2,int y2,Unit** table)
     i=x1-4; if( i<0 ) i=0;		// Only for current unit-cache !!
     j=y1-4; if( j<0 ) j=0;
 
+    //
+    //	Reduce to map limits. FIXME: should the caller check?
+    //
+    if( x2>TheMap.Width ) {
+	x2=TheMap.Width;
+    }
+    if( y2>TheMap.Height ) {
+	y2=TheMap.Height;
+    }
+
     n=QuadTreeSelect(PositionCache,i,j,x2,y2,table);
 
     //
@@ -660,11 +689,30 @@ global int UnitCacheSelect(int x1,int y1,int x2,int y2,Unit** table)
 }
 
 /**
-**	Select unit on X,Y.
+**	Select units on map tile.
+**
+**	@param x	Map X tile position
+**	@param y	Map Y tile position
+**	@param table	All units in the selection rectangle
+**
+**	@return		Returns the number of units found
+*/
+global int UnitCacheOnTile(int x,int y,Unit** table)
+{
+    return UnitCacheSelect(x,y,x+1,y+1,table);
+}
+
+/**
+**	Select unit on X,Y of type naval,fly,land.
+**
+**	@param x	Map X tile position.
+**	@param y	Map Y tile position.
+**	@param type	UnitType::UnitType, naval,fly,land.
+**
+**	@returns	Unit, if an unit of correct type is on the field.
 */
 global Unit* UnitCacheOnXY(int x,int y,int type)
 {
-
     QuadTreeLeaf* leaf;
 
     leaf=QuadTreeSearch(PositionCache,x,y);
@@ -715,4 +763,181 @@ global void InitUnitCache(void)
     PositionCache=NewQuadTree(l);
 }
 
+#else	// }{ !UNIT_ON_MAP
+
+/*----------------------------------------------------------------------------
+--	Includes
+----------------------------------------------------------------------------*/
+
+#include "unit.h"
+#include "map.h"
+
+//*****************************************************************************
+//	Store direct on map.
+//****************************************************************************/
+
+//*****************************************************************************
+//	Convert calls to internal
+//****************************************************************************/
+
+/**
+**	Insert new unit into cache.
+**
+**	@param unit	Unit pointer to place in cache.
+*/
+global void UnitCacheInsert(Unit* unit)
+{
+    MapField* mf;
+
+    mf=TheMap.Fields+unit->Y*TheMap.Width+unit->X;
+    unit->Next=mf->Here.Units;
+    mf->Here.Units=unit;
+    DebugLevel3Fn("%p %p\n",unit,unit->Next);
+}
+
+/**
+**	Remove unit from cache.
+**
+**	@param unit	Unit pointer to remove from cache.
+*/
+global void UnitCacheRemove(Unit* unit)
+{
+    Unit** prev;
+
+    prev=&TheMap.Fields[unit->Y*TheMap.Width+unit->X].Here.Units;
+    DebugCheck( !*prev );
+    for( ;; ) {				// find the unit
+	if( *prev==unit ) {
+	    *prev=unit->Next;
+	    return;
+	}
+	prev=&(*prev)->Next;
+	DebugCheck( !*prev );
+    }
+}
+
+/**
+**	Change unit in cache.
+**
+**	@param unit	Unit pointer to change in cache.
+*/
+global void UnitCacheChange(Unit* unit)
+{
+    UnitCacheRemove(unit);		// must remove first
+    UnitCacheInsert(unit);
+}
+
+/**
+**	Select units in rectangle range.
+**
+**	@param x1	Left column of selection rectangle
+**	@param y1	Top row of selection rectangle
+**	@param x2	Right column of selection rectangle
+**	@param y2	Bottom row of selection rectangle
+**	@param table	All units in the selection rectangle
+**
+**	@return		Returns the number of units found
+*/
+global int UnitCacheSelect(int x1,int y1,int x2,int y2,Unit** table)
+{
+    int x;
+    int y;
+    int n;
+    int i;
+    Unit* unit;
+    MapField* mf;
+
+    //
+    //	Units are inserted by origin position
+    //
+    x=x1-4; if( x<0 ) x=0;		// Only for current unit-cache !!
+    y=y1-4; if( y<0 ) y=0;
+
+    //
+    //	Reduce to map limits. FIXME: should the caller check?
+    //
+    if( x2>TheMap.Width ) {
+	x2=TheMap.Width;
+    }
+    if( y2>TheMap.Height ) {
+	y2=TheMap.Height;
+    }
+
+    for( n=0; y<y2; ++y ) {
+	mf=TheMap.Fields+y*TheMap.Width+x;
+	for( i=x; i<x2; ++i ) {
+	    
+	    for( unit=mf->Here.Units; unit; unit=unit->Next ) {
+		DebugLevel3Fn("%p\n",unit);
+		//
+		//	Remove units, outside range.
+		//
+		if( unit->X+unit->Type->TileWidth<=x1
+			|| unit->X>x2
+			|| unit->Y+unit->Type->TileHeight<=y1
+			|| unit->Y>y2 ) {
+		    continue;
+		}
+		table[n++]=unit;
+	    }
+	    ++mf;
+	}
+    }
+
+    return n;
+}
+
+/**
+**	Select units on map tile.
+**
+**	@param x	Map X tile position
+**	@param y	Map Y tile position
+**	@param table	All units in the selection rectangle
+**
+**	@return		Returns the number of units found
+*/
+global int UnitCacheOnTile(int x,int y,Unit** table)
+{
+    return UnitCacheSelect(x,y,x+1,y+1,table);
+}
+
+/**
+**	Select unit on X,Y of type naval,fly,land.
+**
+**	@param x	Map X tile position.
+**	@param y	Map Y tile position.
+**	@param type	UnitType::UnitType, naval,fly,land.
+**
+**	@returns	Unit, if an unit of correct type is on the field.
+*/
+global Unit* UnitCacheOnXY(int x,int y,int type)
+{
+    Unit* unit;
+
+    unit=TheMap.Fields[y*TheMap.Width+x].Here.Units;
+    while( unit ) {
+	if( unit->Type->UnitType==type ) {
+	    break;
+	}
+	unit=unit->Next;
+    }
+    return unit;
+}
+
+/**
+**	Print unit-cache statistic.
+*/
+global void UnitCacheStatistic(void)
+{
+}
+
+/**
+**	Initialize unit-cache.
+*/
+global void InitUnitCache(void)
+{
+}
+
+#endif	// } UNIT_ON_MAP
+
 //@}
diff --git a/src/unit/unit_find.cpp b/src/unit/unit_find.cpp
index 87cd29416..c99f490ea 100644
--- a/src/unit/unit_find.cpp
+++ b/src/unit/unit_find.cpp
@@ -40,7 +40,7 @@
 ----------------------------------------------------------------------------*/
 
 /**
-**	Select units in range.
+**	Select units in rectangle range.
 **
 **	@param x1	Left column of selection rectangle
 **	@param y1	Top row of selection rectangle
@@ -55,6 +55,20 @@ global int SelectUnits(int x1,int y1,int x2,int y2,Unit** table)
     return UnitCacheSelect(x1,y1,x2,y2,table);
 }
 
+/**
+**	Select units on tile.
+**
+**	@param x	Map X tile position
+**	@param y	Map Y tile position
+**	@param table	All units in the selection rectangle
+**
+**	@return		Returns the number of units found
+*/
+global int SelectUnitsOnTile(int x,int y,Unit** table)
+{
+    return UnitCacheOnTile(x,y,table);
+}
+
 /**
 **	Find all units of type.
 **
@@ -134,7 +148,7 @@ global Unit* UnitOnMapTile(unsigned tx,unsigned ty)
     int n;
     int i;
 
-    n=SelectUnits(tx,ty,tx+1,ty+1,table);
+    n=SelectUnitsOnTile(tx,ty,table);
     for( i=0; i<n; ++i ) {
         // Note: this is less restrictive than UnitActionDie...
         // Is it normal?
@@ -161,7 +175,7 @@ global Unit* RepairableOnMapTile(unsigned tx,unsigned ty)
     int n;
     int i;
 
-    n=SelectUnits(tx,ty,tx+1,ty+1,table);
+    n=SelectUnitsOnTile(tx,ty,table);
     for( i=0; i<n; ++i ) {
 	if( UnitUnusable(table[i]) ) {
 	    continue;
@@ -193,8 +207,7 @@ global Unit* TargetOnMapTile(Unit* source,unsigned tx,unsigned ty)
     int n;
     int i;
 
-    n=SelectUnits(tx,ty,tx+1,ty+1,table);
-
+    n=SelectUnitsOnTile(tx,ty,table);
     for( i=0; i<n; ++i ) {
 	unit=table[i];
 	// unusable unit ?
@@ -259,7 +272,7 @@ global Unit* GoldMineOnMap(int tx,int ty)
     int i;
     int n;
 
-    n=SelectUnits(tx,ty,tx+1,ty+1,table);
+    n=SelectUnitsOnTile(tx,ty,table);
     for( i=0; i<n; ++i ) {
 	if( UnitUnusable(table[i]) ) {
 	    continue;
@@ -285,8 +298,7 @@ global Unit* GoldDepositOnMap(int tx,int ty)
     int i;
     int n;
 
-    // FIXME: perhaps I should write a select on tile function?
-    n=SelectUnits(tx,ty,tx+1,ty+1,table);
+    n=SelectUnitsOnTile(tx,ty,table);
     for( i=0; i<n; ++i ) {
 	if( UnitUnusable(table[i]) ) {
 	    continue;
@@ -312,7 +324,7 @@ global Unit* OilPatchOnMap(int tx,int ty)
     int i;
     int n;
 
-    n=SelectUnits(tx,ty,tx+1,ty+1,table);
+    n=SelectUnitsOnTile(tx,ty,table);
     for( i=0; i<n; ++i ) {
 	if( table[i]->Type->OilPatch ) {
 	    return table[i];
@@ -335,7 +347,7 @@ global Unit* PlatformOnMap(int tx,int ty)
     int i;
     int n;
 
-    n=SelectUnits(tx,ty,tx+1,ty+1,table);
+    n=SelectUnitsOnTile(tx,ty,table);
     for( i=0; i<n; ++i ) {
 	if( UnitUnusable(table[i]) ) {
 	    continue;
@@ -361,7 +373,7 @@ global Unit* OilDepositOnMap(int tx,int ty)
     int i;
     int n;
 
-    n=SelectUnits(tx,ty,tx+1,ty+1,table);
+    n=SelectUnitsOnTile(tx,ty,table);
     for( i=0; i<n; ++i ) {
 	if( UnitUnusable(table[i]) ) {
 	    continue;
@@ -387,7 +399,7 @@ global Unit* WoodDepositOnMap(int tx,int ty)
     int i;
     int n;
 
-    n=SelectUnits(tx,ty,tx+1,ty+1,table);
+    n=SelectUnitsOnTile(tx,ty,table);
     for( i=0; i<n; ++i ) {
 	if( UnitUnusable(table[i]) ) {
 	    continue;