From 664929c8f9243ea5619e57645003bc9e762d1492 Mon Sep 17 00:00:00 2001
From: jsalmon3 <>
Date: Mon, 5 Jul 2004 17:27:46 +0000
Subject: [PATCH] Undo last commit

---
 src/action/action_follow.cpp   |   1 +
 src/action/action_move.cpp     |  10 +-
 src/action/action_resource.cpp |   4 +
 src/action/action_unload.cpp   |   2 +
 src/action/command.cpp         |  21 ++
 src/editor/editloop.cpp        |   1 +
 src/include/map.h              |  44 ++-
 src/include/unit.h             |   4 +-
 src/map/map_fog.cpp            |   4 -
 src/stratagus/selection.cpp    |  13 +-
 src/stratagus/spells.cpp       |  24 +-
 src/unit/unit.cpp              | 504 ++++++++++++---------------------
 src/unit/unit_cache.cpp        |   6 +-
 13 files changed, 265 insertions(+), 373 deletions(-)

diff --git a/src/action/action_follow.cpp b/src/action/action_follow.cpp
index 64cadbee7..8311c63a2 100644
--- a/src/action/action_follow.cpp
+++ b/src/action/action_follow.cpp
@@ -136,6 +136,7 @@ void HandleActionFollow(Unit* unit)
 
 				// Teleport the unit
 				RemoveUnit(unit, NULL);
+				UnitCacheRemove(unit);
 				unit->X = goal->Goal->X;
 				unit->Y = goal->Goal->Y;
 				DropOutOnSide(unit, unit->Direction, 1, 1);
diff --git a/src/action/action_move.cpp b/src/action/action_move.cpp
index 30c88a6f2..b66f50b17 100644
--- a/src/action/action_move.cpp
+++ b/src/action/action_move.cpp
@@ -74,12 +74,14 @@
 */
 static int ActionMoveGeneric(Unit* unit, const Animation* anim)
 {
-	int xd;     // X movement in tile.
-	int yd;     // Y movement in tile.
+	int xd;
+	int yd;
 	int state;
 	int d;
-	int x;      // Unit->X
-	int y;      // Unit->Y
+	int i;
+	int x;
+	int y;
+	Unit* uninside;
 
 	// FIXME: state 0?, should be wrong, should be Reset.
 	// FIXME: Reset flag is cleared by HandleUnitAction.
diff --git a/src/action/action_resource.cpp b/src/action/action_resource.cpp
index 58dce1bb5..843c3eb08 100644
--- a/src/action/action_resource.cpp
+++ b/src/action/action_resource.cpp
@@ -229,6 +229,8 @@ static int StartGathering(Unit* unit)
 		unit->Orders[0].Goal = NoUnitP;
 
 		RemoveUnit(unit, goal);
+		unit->X = goal->X;
+		unit->Y = goal->Y;
 	}
 
 	unit->Data.ResWorker.TimeToHarvest = resinfo->WaitAtResource /
@@ -596,6 +598,8 @@ static int MoveToDepot(Unit* unit)
 	// Place unit inside the depot
 	//
 	RemoveUnit(unit, goal);
+	unit->X = goal->X;
+	unit->Y = goal->Y;
 
 	//
 	// Update resource.
diff --git a/src/action/action_unload.cpp b/src/action/action_unload.cpp
index 0940a07dd..369ce2f52 100644
--- a/src/action/action_unload.cpp
+++ b/src/action/action_unload.cpp
@@ -153,6 +153,8 @@ int UnloadUnit(Unit* unit)
 	if (!FindUnloadPosition(unit->X, unit->Y, &x, &y, UnitMovementMask(unit))) {
 		return 0;
 	}
+	unit->X = x;
+	unit->Y = y;
 	unit->Wait = 1; // should be correct unit has still action
 	unit->Boarded = 0;
 	PlaceUnit(unit, x, y);
diff --git a/src/action/command.cpp b/src/action/command.cpp
index 900a6e950..3f18e5d3b 100644
--- a/src/action/command.cpp
+++ b/src/action/command.cpp
@@ -587,6 +587,27 @@ void CommandUnload(Unit* unit, int x, int y, Unit* what, int flush)
 	// Check if unit is still valid? (NETWORK!)
 	//
 	if (!unit->Removed && unit->Orders[0].Action != UnitActionDie) {
+		//
+		// For bunkers, don't go into an action. Just drop everything here and now.
+		//
+		if (unit->Type->Building) {
+			int i;
+			Unit* uins;
+
+			// Unload all units.
+			uins = unit->UnitInside;
+			for (i = unit->InsideCount; i; --i, uins = uins->NextContained) {
+				if (uins->Boarded) {
+					uins->X = unit->X;
+					uins->Y = unit->Y;
+					if (UnloadUnit(uins)) {
+						unit->BoardCount--;
+					}
+				}
+			}
+			return;
+		}
+
 		if (!(order = GetNextOrder(unit, flush))) {
 			return;
 		}
diff --git a/src/editor/editloop.cpp b/src/editor/editloop.cpp
index a51451439..35e9e727a 100644
--- a/src/editor/editloop.cpp
+++ b/src/editor/editloop.cpp
@@ -1372,6 +1372,7 @@ static void EditorCallbackKeyDown(unsigned key, unsigned keychar)
 				Unit* unit;
 
 				RemoveUnit(unit = UnitUnderCursor, NULL);
+				UnitCacheRemove(unit);
 				UnitLost(unit);
 				UnitClearOrders(unit);
 				ReleaseUnit(unit);
diff --git a/src/include/map.h b/src/include/map.h
index 82511985a..6a4998da1 100644
--- a/src/include/map.h
+++ b/src/include/map.h
@@ -345,22 +345,19 @@ extern int AnyMapAreaVisibleInViewport(const Viewport*, int , int , int , int);
 //
 // in map_fog.c
 //
-/// Function to (un)mark the vision table.
-typedef void MapMarkerFunc(const Player*, int x, int y);
-
 	/// Filter map flags through fog
 extern int MapFogFilterFlags(Player* player, int x, int y, int mask);
 	/// Mark a tile for normal sight
-extern MapMarkerFunc MapMarkTileSight;
+extern void MapMarkTileSight(const Player* player, int x, int y);
 	/// Unmark a tile for normal sight
-extern MapMarkerFunc MapUnmarkTileSight;
+extern void MapUnmarkTileSight(const Player* player, int x, int y);
 	/// Mark a tile for cloak detection
-extern MapMarkerFunc MapMarkTileDetectCloak;
+extern void MapMarkTileDetectCloak(const Player* player,int x,int y);
 	/// Unmark a tile for cloak detection
-extern MapMarkerFunc MapUnmarkTileDetectCloak;
+extern void MapUnmarkTileDetectCloak(const Player* player,int x,int y);
 
 	/// Mark sight changes
-extern void MapSight(const Player* player, int x, int y, int w, int h, int range, MapMarkerFunc *marker);
+extern void MapSight(const Player* player, int x, int y, int w, int h, int range, void (*marker)(const Player*, int, int));
 	/// Find if a tile is visible (With shared vision)
 extern unsigned char IsTileVisible(const Player* player, int x, int y);
 	/// Mark tiles with fog of war to be redrawn
@@ -486,13 +483,6 @@ extern void PreprocessMap(void);
 	/// Set wall on field
 extern void MapSetWall(unsigned x, unsigned y, int humanwall);
 
-// in unit.c
-
-/// Mark on vision table the Sight of the unit.
-void MapMarkUnitSight(Unit* unit);
-/// Unmark on vision table the Sight of the unit.
-void MapUnmarkUnitSight(Unit* unit);
-
 /*----------------------------------------------------------------------------
 --  Defines
 ----------------------------------------------------------------------------*/
@@ -504,6 +494,30 @@ void MapUnmarkUnitSight(Unit* unit);
 #define MapMarkSight(player,x,y,w,h,range) MapSight((player),(x),(y),(w),(h),(range),MapMarkTileSight)
 #define MapUnmarkSight(player,x,y,w,h,range) MapSight((player),(x),(y),(w),(h),(range),MapUnmarkTileSight)
 
+#define MapMarkUnitSight(unit) \
+{ \
+	MapSight((unit)->Player, (unit)->X,(unit)->Y, (unit)->Type->TileWidth,\
+			(unit)->Type->TileHeight, (unit)->CurrentSightRange, MapMarkTileSight); \
+	if (unit->Type->DetectCloak) { \
+		MapSight((unit)->Player, (unit)->X,(unit)->Y, (unit)->Type->TileWidth,\
+				(unit)->Type->TileHeight, (unit)->CurrentSightRange, MapMarkTileDetectCloak); \
+	}\
+}
+
+#define MapUnmarkUnitSight(unit) \
+{ \
+	MapSight((unit)->Player,(unit)->X,(unit)->Y, (unit)->Type->TileWidth,\
+			(unit)->Type->TileHeight,(unit)->CurrentSightRange,MapUnmarkTileSight); \
+	if (unit->Type->DetectCloak) { \
+		MapSight((unit)->Player, (unit)->X,(unit)->Y, (unit)->Type->TileWidth,\
+				(unit)->Type->TileHeight, (unit)->CurrentSightRange, MapUnmarkTileDetectCloak); \
+	}\
+}
+
+#define MapMarkUnitOnBoardSight(unit,host) MapSight((unit)->Player,(host)->X,(host)->Y, \
+	(host)->Type->TileWidth,(host)->Type->TileHeight,(unit)->CurrentSightRange,MapMarkTileSight)
+#define MapUnmarkUnitOnBoardSight(unit,host) MapSight((unit)->Player,(host)->X,(host)->Y, \
+	(host)->Type->TileWidth,(host)->Type->TileHeight,(unit)->CurrentSightRange,MapUnmarkTileSight)
 	/// Check if a field for the user is explored
 #define IsMapFieldExplored(player,x,y) \
 	(IsTileVisible((player),(x),(y)))
diff --git a/src/include/unit.h b/src/include/unit.h
index a7596e4f5..9a9fcf3c6 100644
--- a/src/include/unit.h
+++ b/src/include/unit.h
@@ -763,10 +763,10 @@ extern Unit* MakeUnit(UnitType* type,Player* player);
 extern void PlaceUnit(Unit* unit, int x, int y);
 	/// Create a new unit and place on map
 extern Unit* MakeUnitAndPlace(int x, int y, UnitType* type,Player* player);
-	/// Move unit to tile(x, y). (Do special stuff : vision, cachelist, pathfinding)
-extern void MoveUnitToXY(Unit* unit, int x, int y);
 	/// Add an unit inside a container. Only deal with list stuff.
 extern void AddUnitInContainer(Unit* unit, Unit* host);
+	/// Remove an unit from inside a container. Only deals with list stuff.
+extern void RemoveUnitFromContainer(Unit* unit);
 	/// Remove unit from map/groups/...
 extern void RemoveUnit(Unit* unit, Unit* host);
 	/// Handle the loose of an unit (food,...)
diff --git a/src/map/map_fog.cpp b/src/map/map_fog.cpp
index a94be0d03..f61599dd6 100644
--- a/src/map/map_fog.cpp
+++ b/src/map/map_fog.cpp
@@ -212,8 +212,6 @@ void MapMarkTileSight(const Player* player, int x, int y)
 {
 	unsigned char v;
 
-	Assert(0 <= x && x < TheMap.Width);
-	Assert(0 <= y && y < TheMap.Height);
 	v = TheMap.Fields[x + y * TheMap.Width].Visible[player->Player];
 	switch (v) {
 		case 0:  // Unexplored
@@ -249,8 +247,6 @@ void MapUnmarkTileSight(const Player* player, int x, int y)
 {
 	unsigned char v;
 
-	Assert(0 <= x && x < TheMap.Width);
-	Assert(0 <= y && y < TheMap.Height);
 	v = TheMap.Fields[x + y * TheMap.Width].Visible[player->Player];
 	switch (v) {
 		case 255:
diff --git a/src/stratagus/selection.cpp b/src/stratagus/selection.cpp
index 005cd3416..5bebae67b 100644
--- a/src/stratagus/selection.cpp
+++ b/src/stratagus/selection.cpp
@@ -127,11 +127,8 @@ void ChangeSelectedUnits(Unit** units,int count)
 	if (count == 1 && units[0]->Type->ClicksToExplode &&
 		!units[0]->Type->Decoration) {
 		HandleSuicideClick(units[0]);
-		if (units[0]->Orders[0].Action == UnitActionDie) {
-			NetworkSendSelection(units, count);
-			return ;
-		}
 	}
+
 	UnSelectAll();
 	NetworkSendSelection(units, count);
 	for (n = i = 0; i < count; ++i) {
@@ -346,16 +343,16 @@ int SelectUnitsByType(Unit* base)
 	r = UnitCacheSelect(vp->MapX - 1, vp->MapY - 1, vp->MapX + vp->MapWidth + 1,
 		vp->MapY + vp->MapHeight + 1, table);
 
-	if (base->Type->ClicksToExplode) {
-		HandleSuicideClick(base);
-	}
-
 	// if unit is a cadaver or hidden (not on map)
 	// no unit can be selected.
 	if (base->Removed || base->Orders[0].Action == UnitActionDie) {
 		return 0;
 	}
 
+	if (base->Type->ClicksToExplode) {
+		HandleSuicideClick(base);
+	}
+
 	if (base->Type->Decoration && GameRunning) {
 		return 0;
 	}
diff --git a/src/stratagus/spells.cpp b/src/stratagus/spells.cpp
index d606e859a..4b145735a 100644
--- a/src/stratagus/spells.cpp
+++ b/src/stratagus/spells.cpp
@@ -206,7 +206,10 @@ int CastSpawnPortal(Unit* caster, const SpellType* spell __attribute__((unused))
 	DebugPrint("Spawning a portal exit.\n");
 	portal = caster->Goal;
 	if (portal) {
-		MoveUnitToXY(portal, x, y);
+		// FIXME: if cop is already defined --> move it, but it doesn't work?
+		RemoveUnit(portal, NULL);
+		UnitCacheRemove(portal);
+		PlaceUnit(portal, x, y);
 	} else {
 		portal = MakeUnitAndPlace(x, y, ptype, &Players[PlayerNumNeutral]);
 	}
@@ -565,6 +568,7 @@ int CastPolymorph(Unit* caster, const SpellType* spell,
 
 	// as said somewhere else -- no corpses :)
 	RemoveUnit(target, NULL);
+	UnitCacheRemove(target);
 	for (i = 0; i < type->TileWidth; ++i) {
 		for (j = 0; j < type->TileHeight; ++j) {
 			if (!UnitTypeCanMoveTo(x + i, y + j, type)) {
@@ -639,17 +643,27 @@ int CastSummon(Unit* caster, const SpellType* spell,
 		// FIXME: do summoned units count on food?
 		//
 		target = MakeUnit(unittype, caster->Player);
-		// This is a hack to walk around behaviour of DropOutOnSide
-		target->X = x + 1;
+		target->X = x;
 		target->Y = y;
-		DropOutOnSide(target, LookingW, 0, 0); // FIXME : 0,0) : good parameter ?
 		//
 		//  set life span. ttl=0 results in a permanent unit.
 		//
 		if (ttl) {
 			target->TTL = GameCycle + ttl;
 		}
-
+		//
+		// Revealers are always removed, since they don't have graphics
+		//
+		if (target->Type->Revealer) {
+			DebugPrint("summoned unit is a revealer, removed.\n");
+			target->Removed = 1;
+			target->CurrentSightRange = target->Stats->SightRange;
+			MapMarkUnitSight(target);
+		} else {
+			// This is a hack to walk around behaviour of DropOutOnSide
+			target->X++;
+			DropOutOnSide(target, LookingW, 0, 0);
+		}
 		caster->Mana -= spell->ManaCost;
 		return 1;
 	}
diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp
index 09fcc7ee4..92564a713 100644
--- a/src/unit/unit.cpp
+++ b/src/unit/unit.cpp
@@ -431,303 +431,6 @@ Unit* MakeUnit(UnitType* type, Player* player)
 	return unit;
 }
 
-/**
-**  (Un)Mark on vision table the Sight of the unit
-**  (and units inside for transporter (recursively))
-**
-**  @param unit      Unit to (un)mark.
-**  @param x         X coord of first container of unit.
-**  @param y         Y coord of first container of unit.
-**  @param width     Width of the first container of unit.
-**  @param height    Height of the first container of unit.
-**  @param f         Function to (un)mark for normal vision.
-**  @param f2        Function to (un)mark for cloaking vision.
-*/
-static void MapMarkUnitSightRec(Unit* unit, int x, int y, int width, int height,
-	MapMarkerFunc* f, MapMarkerFunc* f2)
-{
-	Unit* unit_inside; // iterator on units inside unit. 
-	int i;             // number of units inside to process.
-
-	Assert(unit);
-	Assert(f);
-	MapSight(unit->Player, x, y, width, height, unit->CurrentSightRange, f);
-
-	if (unit->Type && unit->Type->DetectCloak && f2) {
-		MapSight(unit->Player, x, y, width, height, unit->CurrentSightRange, f2);
-	}
-
-	unit_inside = unit->UnitInside;
-	for (i = unit->InsideCount; i--; unit_inside = unit_inside->NextContained) {
-		MapMarkUnitSightRec(unit_inside, x, y, width, height, f, f2);
-	}
-}
-
-/**
-**  Return the unit not transported, by viewing the container recursively.
-**
-**  @param unit    unit from where look the first conatiner.
-**
-**  @return        Container of container of ... of unit. It is not null.
-*/
-static Unit* GetFirstContainer(const Unit* unit)
-{
-	Assert(unit);
-	while (unit->Container) {
-		unit = unit->Container;
-	}
-	return (Unit *) unit;
-}
-
-/**
-**  Mark on vision table the Sight of the unit
-**  (and units inside for transporter)
-**
-**  @param unit    unit to unmark its vision.
-**  @see MapUnmarkUnitSight.
-*/
-void MapMarkUnitSight(Unit* unit)
-{
-	Unit* container;  // First container of the unit.
-
-	Assert(unit);
-
-	container = GetFirstContainer(unit);
-	Assert(container->Type);
-	MapMarkUnitSightRec(unit,
-		container->X, container->Y, container->Type->TileWidth, container->Type->TileHeight,
-		MapMarkTileSight, MapMarkTileDetectCloak);
-}
-
-/**
-**  Unmark on vision table the Sight of the unit
-**  (and units inside for transporter)
-**
-**  @param unit    unit to unmark its vision.
-**  @see MapMarkUnitSight.
-*/
-void MapUnmarkUnitSight(Unit* unit)
-{
-	Unit* container;  // First container of the unit.
-
-	Assert(unit);
-	Assert(unit->Type);
-
-	container = GetFirstContainer(unit);
-	Assert(container->Type);
-	MapMarkUnitSightRec(unit,
-		container->X, container->Y, container->Type->TileWidth, container->Type->TileHeight,
-		MapUnmarkTileSight, MapUnmarkTileDetectCloak);
-}
-
-/**
-**  Update the Unit Current sight range to good value and transported units inside.
-**
-**  @param unit    unit to update SightRange
-**
-**  @internal before use it, MapUnmarkUnitSight(unit)
-**  and after MapMarkUnitSight(unit)
-**  are often necessary.
-**
-**  FIXME @todo manage differently unit inside with option.
-**  (no vision, min, host value, own value, bonus value, ...)
-*/
-static void UpdateUnitSightRange(Unit* unit)
-{
-	Unit* unit_inside; // iterator on units inside unit. 
-	int i;             // number of units inside to process.
-
-#if 0 // which is the better ? caller check ?
-	if (SaveGameLoading) {
-		return ;
-	}
-#else
-	Assert(!SaveGameLoading);
-#endif
-	// FIXME : these values must be configurable.
-	if (unit->Constructed) { // Units under construction have no sight range.
-		unit->CurrentSightRange = 0;
-	} else if (!unit->Container) { // proper value.
-		unit->CurrentSightRange = unit->Stats->SightRange;
-	} else { // value of it container.
-		unit->CurrentSightRange = unit->Container->CurrentSightRange;
-	}
-
-	unit_inside = unit->UnitInside;
-	for (i = unit->InsideCount; i--; unit_inside = unit_inside->NextContained) {
-		UpdateUnitSightRange(unit_inside);
-	}
-}
-
-/**
-**  Mark the field with the FieldFlags.
-**
-**  @param unit    unit to mark.
-*/
-static void MarkUnitFieldFlags(const Unit* unit)
-{
-	UnitType* type; // Type of the unit.
-	unsigned flags; //
-	int h;          // Tile height of the unit.
-	int w;          // Tile width of the unit.
-	int x;          // X tile of the unit.
-	int y;          // Y tile of the unit.
-
-	Assert(unit);
-	type = unit->Type;
-	x = unit->X;
-	y = unit->Y;
-	flags = type->FieldFlags;
-	for (h = type->TileHeight; h--;) {
-		for (w = type->TileWidth; w--;) {
-			TheMap.Fields[x + w + (y + h) * TheMap.Width].Flags |= flags;
-		}
-	}
-#ifdef MAP_REGIONS
-	// Update map splitting.
-	if (type->Building && (flags &
-		 (MapFieldLandUnit | MapFieldSeaUnit | MapFieldBuilding |
-		  MapFieldUnpassable | MapFieldWall | MapFieldRocks | MapFieldForest))) {
-		MapSplitterTilesOccuped(x, y, x + type->TileWidth - 1, y + type->TileHeight - 1);
-	}
-#endif
-
-}
-
-/**
-**  Mark the field with the FieldFlags.
-**
-**  @param unit    unit to mark.
-*/
-static void UnmarkUnitFieldFlags(const Unit* unit)
-{
-	UnitType* type; // Type of the unit.
-	unsigned flags; //
-	int h;          // Tile height of the unit.
-	int w;          // Tile width of the unit.
-	int x;          // X tile of the unit.
-	int y;          // Y tile of the unit.
-
-	Assert(unit);
-	type = unit->Type;
-	x = unit->X;
-	y = unit->Y;
-	flags = type->FieldFlags;
-	for (h = type->TileHeight; h--;) {
-		for (w = type->TileWidth; w--;) {
-			TheMap.Fields[x + w + (y + h) * TheMap.Width].Flags &= ~flags;
-		}
-	}
-#ifdef MAP_REGIONS
-	// Update map splitting.
-	if (type->Building && (flags &
-		 (MapFieldLandUnit | MapFieldSeaUnit | MapFieldBuilding |
-		  MapFieldUnpassable | MapFieldWall | MapFieldRocks | MapFieldForest))){
-		MapSplitterTilesCleared(x, y, x + type->TileWidth - 1, y + type->TileHeight - 1);
-	}
-#endif
-}
-
-/**
-** Add unit to a container. It only updates linked list stuff
-**
-** @param unit    Pointer to unit.
-** @param host    Pointer to container.
-*/
-void AddUnitInContainer(Unit* unit, Unit* host)
-{
-	Assert(host && unit->Container == 0);
-	unit->Container = host;
-	if (host->InsideCount == 0) {
-		unit->NextContained = unit->PrevContained = unit;
-	} else {
-		unit->NextContained = host->UnitInside;
-		unit->PrevContained = host->UnitInside->PrevContained;
-		host->UnitInside->PrevContained->NextContained = unit;
-		host->UnitInside->PrevContained = unit;
-	}
-	host->UnitInside = unit;
-	host->InsideCount++;
-}
-
-/**
-** Remove unit from a container. It only updates linked list stuff
-**
-** @param unit    Pointer to unit.
-*/
-static void RemoveUnitFromContainer(Unit* unit)
-{
-	Unit* host;  // transporter which contain unit.
-
-	host = unit->Container;
-	Assert(unit->Container);
-	Assert(unit->Container->InsideCount > 0);
-	host->InsideCount--;
-	unit->NextContained->PrevContained = unit->PrevContained;
-	unit->PrevContained->NextContained = unit->NextContained;
-	if (host->InsideCount == 0) {
-		host->UnitInside = NoUnitP;
-	} else {
-		if (host->UnitInside == unit) {
-			host->UnitInside = unit->NextContained;
-		}
-	}
-	unit->Container = NoUnitP;
-}
-
-
-/**
-**  Affect Tile coord of an unit (with units inside) to tile (x, y).
-**
-**  @param unit    unit to move.
-**  @param x       X map tile position.
-**  @param y       Y map tile position.
-**
-**  @internal before use it, UnitCacheRemove(unit), MapUnmarkUnitSight(unit)
-**  and after UnitCacheInsert(unit), MapMarkUnitSight(unit)
-**  are often necessary. Check Flag also for Pathfinder.
-*/
-static void UnitInXY(Unit* unit, int x, int y)
-{
-	Unit* unit_inside;      // iterator on units inside unit. 
-	int i;                  // number of units inside to process.
-
-	Assert(unit);
-	unit->X = x;
-	unit->Y = y;
-
-	unit_inside = unit->UnitInside;
-	for (i = unit->InsideCount; i--; unit_inside = unit_inside->NextContained) {
-		UnitInXY(unit_inside, x, y);
-	}
-}
-
-/**
-**  Move an unit (with units inside) to tile (x, y).
-**  (Do stuff with vision, cachelist and pathfinding).
-**
-**  @param unit    unit to move.
-**  @param x       X map tile position.
-**  @param y       Y map tile position.
-**
-*/
-void MoveUnitToXY(Unit* unit, int x, int y)
-{
-	MapUnmarkUnitSight(unit);
-	UnitCacheRemove(unit);
-	UnmarkUnitFieldFlags(unit);
-
-	// Move the unit.
-	UnitInXY(unit, x, y);
-
-	UnitCacheInsert(unit);
-	MarkUnitFieldFlags(unit);
-	MapMarkUnitSight(unit);
-}
-
-
-
-
 /**
 ** Place unit on map.
 **
@@ -737,23 +440,63 @@ void MoveUnitToXY(Unit* unit, int x, int y)
 */
 void PlaceUnit(Unit* unit, int x, int y)
 {
+	const UnitType* type;
+	int h;
+	int w;
+	unsigned flags;
+
 	Assert(unit->Removed);
 
-	if (unit->Container) {
-		RemoveUnitFromContainer(unit);
+	type = unit->Type;
+
+
+	unit->X = x;
+	unit->Y = y;
+
+	//
+	// Place unit on the map, mark the field with the FieldFlags.
+	//
+	flags = type->FieldFlags;
+	for (h = type->TileHeight; h--;) {
+		for (w = type->TileWidth; w--;) {
+			TheMap.Fields[x + w + (y + h) * TheMap.Width].Flags |= flags;
+		}
 	}
-	unit->Next = 0;
-	if (!SaveGameLoading) {
-		UpdateUnitSightRange(unit);
+
+#ifdef MAP_REGIONS
+	if (type->Building &&
+			(type->FieldFlags &
+		 (MapFieldLandUnit | MapFieldSeaUnit | MapFieldBuilding |
+		  MapFieldUnpassable | MapFieldWall | MapFieldRocks | MapFieldForest))){
+		MapSplitterTilesOccuped(x, y, x + type->TileWidth - 1, y + type->TileHeight - 1);
 	}
+#endif
+
+	x += unit->Type->TileWidth / 2;
+	y += unit->Type->TileHeight / 2;
+
+	//
+	// Units under construction have no sight range.
+	//
+	if (!unit->Constructed) {
+		//
+		// Update fog of war, if unit belongs to player on this computer
+		//
+		if (unit->Container && unit->Removed) {
+			MapUnmarkUnitOnBoardSight(unit, unit->Container);
+		}
+		if (unit->Container) {
+			RemoveUnitFromContainer(unit);
+		}
+		if (!SaveGameLoading) {
+			unit->CurrentSightRange = unit->Stats->SightRange;
+		}
+		MapMarkUnitSight(unit);
+	}
+
 	unit->Removed = 0;
-	UnitInXY(unit, x, y);
-	// Pathfinding info.
-	MarkUnitFieldFlags(unit);
-	// Tha cache list.
+	unit->Next = 0;
 	UnitCacheInsert(unit);
-	// Vision
-	MapMarkUnitSight(unit);
 
 	MustRedraw |= RedrawMinimap;
 	UnitCountSeen(unit);
@@ -779,6 +522,61 @@ Unit* MakeUnitAndPlace(int x, int y, UnitType* type, Player* player)
 	return unit;
 }
 
+/**
+** Add unit to a container. It only updates linked list stuff
+**
+** @param unit    Pointer to unit.
+** @param host    Pointer to container.
+*/
+void AddUnitInContainer(Unit* unit, Unit* host)
+{
+	if (unit->Container) {
+		DebugPrint("Unit is already contained.\n");
+		exit(0);
+	}
+	unit->Container = host;
+	if (host->InsideCount == 0) {
+		unit->NextContained = unit->PrevContained = unit;
+	} else {
+		unit->NextContained = host->UnitInside;
+		unit->PrevContained = host->UnitInside->PrevContained;
+		host->UnitInside->PrevContained->NextContained = unit;
+		host->UnitInside->PrevContained = unit;
+	}
+	host->UnitInside = unit;
+	host->InsideCount++;
+}
+
+/**
+** Remove unit from a container. It only updates linked list stuff
+**
+** @param unit    Pointer to unit.
+*/
+void RemoveUnitFromContainer(Unit* unit)
+{
+	Unit* host;
+	host = unit->Container;
+	if (!unit->Container) {
+		DebugPrint("Unit not contained.\n");
+		exit(0);
+	}
+	if (host->InsideCount == 0) {
+		DebugPrint("host's inside count reached -1.");
+		exit(0);
+	}
+	host->InsideCount--;
+	unit->NextContained->PrevContained = unit->PrevContained;
+	unit->PrevContained->NextContained = unit->NextContained;
+	if (host->InsideCount == 0) {
+		host->UnitInside = NoUnitP;
+	} else {
+		if (host->UnitInside == unit) {
+			host->UnitInside = unit->NextContained;
+		}
+	}
+	unit->Container = NoUnitP;
+}
+
 /**
 ** Remove unit from map.
 **
@@ -791,24 +589,27 @@ Unit* MakeUnitAndPlace(int x, int y, UnitType* type, Player* player)
 */
 void RemoveUnit(Unit* unit, Unit* host)
 {
+	int h;
+	int w;
+	const UnitType* type;
+	unsigned flags;
+
+	if (unit->Removed && unit->Container) {
+		MapUnmarkUnitOnBoardSight(unit, unit->Container);
+	} else {
+		MapUnmarkUnitSight(unit);
+	}
+	if (host) {
+		unit->CurrentSightRange = host->CurrentSightRange;
+		MapMarkUnitOnBoardSight(unit, host);
+		AddUnitInContainer(unit, host);
+	}
+
 	if (unit->Removed) { // could happen!
 		// If unit is removed (inside) and building is destroyed.
-		DebugPrint("unit '%s' already remove" _C_ unit->Type->Ident);
 		return;
 	}
-	UnitCacheRemove(unit);
-	MapUnmarkUnitSight(unit);
-	UnmarkUnitFieldFlags(unit);
-	if (host) {
-		AddUnitInContainer(unit, host);
-		UpdateUnitSightRange(unit);
-		UnitInXY(unit, host->X, host->Y);
-		MapMarkUnitSight(unit);
-		unit->Next = host; // What is it role ?
-	}
-
 	unit->Removed = 1;
-
 	//  Remove unit from the current selection
 	if (unit->Selected) {
 		if (NumSelected == 1) { //  Remove building cursor
@@ -826,6 +627,37 @@ void RemoveUnit(Unit* unit, Unit* host)
 	if (unit == UnitUnderCursor) {
 		UnitUnderCursor = NULL;
 	}
+
+	type = unit->Type;
+
+	//
+	// Update map
+	//
+	flags = ~type->FieldFlags;
+	for (h = type->TileHeight; h--;) {
+		for (w = type->TileWidth; w--;) {
+			TheMap.Fields[unit->X + w + (unit->Y + h) * TheMap.Width].Flags &= flags;
+		}
+	}
+
+#ifdef MAP_REGIONS
+	//
+	// Update map splitting.
+	//
+	if (type->Building &&
+			(type->FieldFlags &
+		 (MapFieldLandUnit | MapFieldSeaUnit | MapFieldBuilding |
+		  MapFieldUnpassable | MapFieldWall | MapFieldRocks | MapFieldForest))){
+		MapSplitterTilesCleared(unit->X, unit->Y,
+			unit->X + type->TileWidth - 1, unit->Y + type->TileHeight - 1);
+	}
+#endif
+
+	if (host) {
+		UnitCacheRemove(unit);
+		unit->Next = host;
+	}
+
 	MustRedraw |= RedrawMinimap;
 }
 
@@ -1525,9 +1357,15 @@ void ChangeUnitOwner(Unit* unit, Player* newplayer)
 	}
 	*unit->PlayerSlot = unit;
 
-	MapUnmarkUnitSight(unit);
-	unit->Player = newplayer;
-	MapMarkUnitSight(unit);
+	if (unit->Removed && unit->Container) {
+		MapUnmarkUnitOnBoardSight(unit, unit->Next);
+		unit->Player = newplayer;
+		MapMarkUnitOnBoardSight(unit, unit->Next);
+	} else {
+		MapUnmarkUnitSight(unit);
+		unit->Player = newplayer;
+		MapMarkUnitSight(unit);
+	}
 
 	unit->Stats = &unit->Type->Stats[newplayer->Player];
 	//
@@ -2696,6 +2534,7 @@ void LetUnitDie(Unit* unit)
 	// removed units,  just remove.
 	if (unit->Removed) {
 		DebugPrint("Killing a removed unit?\n");
+		RemoveUnit(unit, NULL);
 		UnitLost(unit);
 		UnitClearOrders(unit);
 		ReleaseUnit(unit);
@@ -2741,8 +2580,8 @@ void LetUnitDie(Unit* unit)
 			// Restore value for oil-patch
 			unit->Value = unit->Data.Builded.Worker->Value;
 		}
-
 		DestroyAllInside(unit);
+
 		RemoveUnit(unit, NULL);
 		UnitLost(unit);
 		UnitClearOrders(unit);
@@ -2753,6 +2592,7 @@ void LetUnitDie(Unit* unit)
 			unit->State = unit->Type->CorpseScript;
 			Assert(type->TileWidth == type->CorpseType->TileWidth &&
 					type->TileHeight == type->CorpseType->TileHeight);
+			MapMarkUnitSight(unit);
 			type = unit->Type = type->CorpseType;
 
 #ifdef DYNAMIC_LOAD
@@ -2764,7 +2604,7 @@ void LetUnitDie(Unit* unit)
 			unit->IY = (type->Height - VideoGraphicHeight(type->Sprite)) / 2;
 
 			unit->SubAction = 0;
-			unit->Removed = 0;
+			//unit->Removed = 0;
 			unit->Frame = 0;
 			unit->Orders[0].Action = UnitActionDie;
 
@@ -2772,11 +2612,13 @@ void LetUnitDie(Unit* unit)
 				unit->Type->Animations->Die);
 			UnitShowAnimation(unit, unit->Type->Animations->Die);
 			DebugPrint("Frame %d\n" _C_ unit->Frame);
+			MapUnmarkUnitSight(unit);
 			unit->CurrentSightRange = type->Stats[unit->Player->Player].SightRange;
 			MapMarkUnitSight(unit);
-			UnitCacheInsert(unit);
 		} else {
 			// no corpse available
+			MapMarkUnitSight(unit);
+			MapUnmarkUnitSight(unit);
 			unit->CurrentSightRange = 0;
 		}
 		return;
@@ -2787,6 +2629,7 @@ void LetUnitDie(Unit* unit)
 		// FIXME: destroy or unload : do a flag.
 		DestroyAllInside(unit);
 	}
+
 	RemoveUnit(unit, NULL);
 	UnitLost(unit);
 	UnitClearOrders(unit);
@@ -2797,18 +2640,18 @@ void LetUnitDie(Unit* unit)
 
 	// Not good: UnitUpdateHeading(unit);
 	unit->SubAction = 0;
+	//unit->Removed = 0;
 	unit->State = 0;
 	unit->Reset = 0;
 	unit->Wait = 1;
 	unit->Orders[0].Action = UnitActionDie;
+
 	if (unit->Type->CorpseType) {
 		unit->CurrentSightRange = unit->Type->CorpseType->Stats[unit->Player->Player].SightRange;
-		MapMarkUnitSight(unit);
 	} else {
 		unit->CurrentSightRange = 0;
 	}
-	unit->Removed = 0;
-	UnitCacheInsert(unit);
+	MapMarkUnitSight(unit);;
 }
 
 /**
@@ -2826,6 +2669,7 @@ void DestroyAllInside(Unit* source)
 		if (unit->UnitInside) {
 			DestroyAllInside(unit);
 		}
+		RemoveUnit(unit, NULL);
 		UnitLost(unit);
 		UnitClearOrders(unit);
 		ReleaseUnit(unit);
diff --git a/src/unit/unit_cache.cpp b/src/unit/unit_cache.cpp
index 4f6720abd..74dea90f1 100644
--- a/src/unit/unit_cache.cpp
+++ b/src/unit/unit_cache.cpp
@@ -58,8 +58,6 @@ void UnitCacheInsert(Unit* unit)
 	MapField* mf;
 	UnitListItem* listitem;
 
-	Assert(!unit->Removed);
-
 	for (i = 0; i < unit->Type->TileHeight; ++i) {
 		for (j = 0; j < unit->Type->TileWidth; ++j) {
 			mf = TheMap.Fields + (i + unit->Y) * TheMap.Width + j + unit->X;
@@ -176,9 +174,8 @@ int UnitCacheSelect(int x1, int y1, int x2, int y2, Unit** table)
 				// It should only be used in here, unless you somehow want the unit
 				// to be out of cache.
 				//
-				if (!listitem->Unit->CacheLock && !listitem->Unit->Type->Revealer) {
+				if (!listitem->Unit->CacheLock) {
 					listitem->Unit->CacheLock = 1;
-					Assert(!listitem->Unit->Removed);
 					table[n++] = listitem->Unit;
 				}
 			}
@@ -217,7 +214,6 @@ int UnitCacheOnTile(int x, int y, Unit** table)
 	listitem = TheMap.Fields[y * TheMap.Width + x].UnitCache;
 	for (; listitem; listitem = listitem->Next) {
 		if (!listitem->Unit->CacheLock) {
-			Assert(!listitem->Unit->Removed);
 			table[n++] = listitem->Unit;
 		}
 	}