diff --git a/doc/ChangeLog.html b/doc/ChangeLog.html
index ac778d02c..0d9d502c7 100644
--- a/doc/ChangeLog.html
+++ b/doc/ChangeLog.html
@@ -36,6 +36,7 @@
 <li>Future 1.19 Release<p>
     <ul>
     <li>++
+    <li>New resource harvesting, no hardcoded unit types (from Crestez Leonard). 
     <li>NEW_UI: Fixed save/load (from Martin Renold).
     <li>Pathfinder fixes for when the goal moves (EXPERIMENTAL) (from Russell Smith).
     <li>Added repair-costs and repair-hp for units that can be repaired (from Russell Smith).
diff --git a/src/action/Module.make b/src/action/Module.make
index d5012f4a5..5f355643b 100644
--- a/src/action/Module.make
+++ b/src/action/Module.make
@@ -27,11 +27,11 @@
 
 MODULE = src/action
 MSRC =	 action_attack.c action_board.c action_build.c action_demolish.c \
-	 action_die.c action_follow.c action_harvest.c \
-	 action_move.c action_patrol.c action_repair.c action_research.c \
-	 action_resource.c action_returngoods.c action_spellcast.c \
-	 action_stand.c action_still.c action_train.c action_unload.c \
-	 action_upgradeto.c actions.c command.c 
+	 action_die.c action_follow.c action_move.c action_patrol.c \
+	 action_repair.c action_research.c action_resource.c \
+	 action_returngoods.c action_spellcast.c action_stand.c \
+	 action_still.c action_train.c action_unload.c action_upgradeto.c \
+	 actions.c command.c 
 
 SRC+=	$(addprefix $(MODULE)/,$(MSRC))
 HDRS+=
diff --git a/src/action/action_build.cpp b/src/action/action_build.cpp
index 38113a684..3e60f9f0c 100644
--- a/src/action/action_build.cpp
+++ b/src/action/action_build.cpp
@@ -392,7 +392,7 @@ global void HandleActionBuilded(Unit* unit)
 		//
 		//	If we can harvest from the new building, do it.
 		//
-		if (worker->Type->Harvester&&worker->Type->ResourceHarvested==type->GivesResource) {
+		if (worker->Type->ResInfo[type->GivesResource]) {
 		    CommandResource(worker,unit,0);
 		}
 	    }
diff --git a/src/action/action_harvest.cpp b/src/action/action_harvest.cpp
deleted file mode 100644
index 4b1038217..000000000
--- a/src/action/action_harvest.cpp
+++ /dev/null
@@ -1,484 +0,0 @@
-//       _________ __                 __                               
-//      /   _____//  |_____________ _/  |______     ____  __ __  ______
-//      \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
-//      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ |
-//     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
-//             \/                  \/          \//_____/            \/ 
-//  ______________________                           ______________________
-//			  T H E   W A R   B E G I N S
-//	   Stratagus - A free fantasy real time strategy game engine
-//
-/**@name action_harvest.c -	The harvest action. */
-//
-//	(c) Copyright 1998-2001,2003 by Lutz Sammer
-//
-//      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; version 2 dated June, 1991.
-//
-//      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., 59 Temple Place - Suite 330, Boston, MA
-//      02111-1307, USA.
-//
-//	$Id$
-
-//@{
-
-/*----------------------------------------------------------------------------
---	Includes
-----------------------------------------------------------------------------*/
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "stratagus.h"
-#include "unittype.h"
-#include "player.h"
-#include "unit.h"
-#include "actions.h"
-#include "sound.h"
-#include "tileset.h"
-#include "map.h"
-#include "interface.h"
-#include "pathfinder.h"
-#include "upgrade_structs.h"
-
-// FIXME: Should combine all the resource functions
-// FIXME: Should update buttons if the action changes?
-
-/*----------------------------------------------------------------------------
---	Functions
-----------------------------------------------------------------------------*/
-
-/**
-**	Move to forest.
-**
-**	@param unit	Pointer to worker unit.
-**
-**	@return		TRUE if reached, otherwise FALSE.
-*/
-local int MoveToWood(Unit* unit)
-{
-    int i;
-    int x;
-    int y;
-
-    if( (i=DoActionMove(unit))>=0 ) {	// reached end-point?
-	return 0;
-    }
-
-    if( i==PF_UNREACHABLE ) {
-newtry:
-	if( FindWoodInSight(unit,&unit->Orders[0].X,&unit->Orders[0].Y) ) {
-
-	    // Move to new wood position
-	    unit->Orders[0].Goal=NoUnitP;
-	    unit->Orders[0].RangeX=unit->Orders[0].RangeY=1;
-	    NewResetPath(unit);
-	    return 0;
-	}
-
-	// FIXME: Should do more tries
-	unit->Orders[0].Action=UnitActionStill;
-	unit->SubAction=0;
-	return 0;
-    }
-
-    x=unit->Orders[0].X;
-    y=unit->Orders[0].Y;
-
-    if( !CheckedForestOnMap(x,y) ) {
-	//
-	//	Fast check surrounding for forest
-	//
-	x=unit->X;
-	y=unit->Y;
-	if( CheckedForestOnMap(x-1,y-1) ) {
-	    --x;
-	    --y;
-	} else if( CheckedForestOnMap(x-1,y+0) ) {
-	    --x;
-	} else if( CheckedForestOnMap(x-1,y+1) ) {
-	    --x;
-	    ++y;
-	} else if( CheckedForestOnMap(x+0,y-1) ) {
-	    --y;
-	} else if( CheckedForestOnMap(x+0,y+1) ) {
-	    ++y;
-	} else if( CheckedForestOnMap(x+1,y-1) ) {
-	    ++x;
-	    --y;
-	} else if( CheckedForestOnMap(x+1,y+0) ) {
-	    ++x;
-	} else if( CheckedForestOnMap(x+1,y+1) ) {
-	    ++x;
-	    ++y;
-	} else {
-	    DebugLevel3Fn("No Wood, Trying a better spot\n");
-	    goto newtry;
-	}
-    }
-
-    // FIXME: don't chop the same wood!
-
-    unit->Orders[0].X=x;
-    unit->Orders[0].Y=y;
-    unit->Orders[0].RangeX=unit->Orders[0].RangeY=0;
-    DebugCheck( unit->Orders[0].Action!=UnitActionHarvest );
-    // turn to wood
-    UnitHeadingFromDeltaXY(unit,x-unit->X,y-unit->Y);
-    //unit->Value=unit->Data.Harvest.WoodToHarvest;
-
-    DebugCheck( unit->Wait!=1 );
-
-    return 1;
-}
-
-/**
-**	Chop the wood.
-**
-**	@param unit	Pointer to worker unit.
-**
-**	@return		TRUE if ready, otherwise FALSE.
-*/
-local int ChopWood(Unit* unit)
-{
-    Unit* destu;
-    int flags;
-
-    flags=UnitShowAnimation(unit,unit->Type->Animations->Attack);
-
-    if( (flags&AnimationSound) && (UnitVisibleOnMap(unit) || ReplayRevealMap) ) {
-	PlayUnitSound(unit,VoiceTreeChopping);
-    }
-
-    if( unit->Reset ) {
-
-	DebugCheck( unit->Wait!=1 );
-
-	//
-	//	This a work around the bug: "lumber bug"
-	//		We give a worker a new command and in the next cycle
-	//		the worker is ready chopping.
-	//
-#if 1
-	if( unit->Orders[1].Action==UnitActionHarvest
-		 || unit->Orders[1].Action==UnitActionResource ) {
-	    unit->Orders[0].Action=UnitActionStill;
-	    unit->SubAction=0;
-	    return 0;
-	}
-#endif
-
-	//
-	//	Wood gone while chopping?
-	//
-	if( !ForestOnMap(unit->Orders[0].X,unit->Orders[0].Y) ) {
-	    if( FindWoodInSight(unit,&unit->Orders[0].X,&unit->Orders[0].Y) ) {
-		unit->Orders[0].Goal=NoUnitP;
-		unit->Orders[0].RangeX=unit->Orders[0].RangeY=0;
-		DebugCheck( unit->Orders[0].Action!=UnitActionHarvest );
-		unit->Orders[0].X--;
-		unit->Orders[0].Y--;
-		NewResetPath(unit);
-		unit->SubAction=1;
-	    } else {
-		unit->Orders[0].Action=UnitActionStill;
-		unit->SubAction=0;
-		DebugLevel3Fn("NO-WOOD in sight range\n");
-	    }
-	    return 0;
-	}
-
-	//
-	//	Ready chopping wood?
-	//
-	if( !--unit->Value ) {
-	    // Have wood
-	    unit->Player->UnitTypesCount[unit->Type->Type]--;
-	    if( unit->Type==UnitTypeOrcWorker ) {
-		unit->Type=UnitTypeOrcWorkerWithWood;
-	    } else if( unit->Type==UnitTypeHumanWorker ) {
-		unit->Type=UnitTypeHumanWorkerWithWood;
-	    } else {
-		// FIXME: support more races!
-		DebugLevel0Fn("Wrong unit for chopping wood %d\n"
-			_C_ unit->Type->Type);
-	    }
-	    unit->Player->UnitTypesCount[unit->Type->Type]++;
-
-	    //
-	    //	Update the display.
-	    //
-            CheckUnitToBeDrawn(unit);
-	    if( IsOnlySelected(unit) ) {	// update display
-#ifndef NEW_UI
-		UpdateButtonPanel();
-#else
-		SelectedUnitChanged();
-#endif
-	    }
-
-	    //
-	    //	Update the map.
-	    //
-	    MapRemoveWood(unit->Orders[0].X,unit->Orders[0].Y);
-#if 0
-	    /*
-	     * This call turned out not to be sufficient because MapRemoveWood()
-	     * may actually remove more that one wood tile (x,y) due to
-	     * "wood fixing" code, see action_harvest.c . So the pathfinder
-	     * callback had to moved directly into MapRemoveWood().
-	     */
-#ifdef HIERARCHIC_PATHFINDER
-	    PfHierMapChangedCallback (unit->Orders[0].X, unit->Orders[0].Y,
-			unit->Orders[0].X, unit->Orders[0].Y);
-#endif
-#endif
-
-	    //
-	    //	Find place to return wood.
-	    //
-	    // NOTE: unit->Orders[0].X && unit->Orders[0].Y holds return place.
-	    unit->Orders[0].X=unit->X;
-	    unit->Orders[0].Y=unit->Y;
-	    if( !(destu=FindDeposit(unit->Player,unit->X,unit->Y,WoodCost)) ) {
-		unit->Orders[0].Action=UnitActionStill;
-		unit->SubAction=0;
-	    } else {
-		unit->Orders[0].RangeX=unit->Orders[0].RangeY=0;
-		unit->Orders[0].Goal=destu;
-		RefsDebugCheck( !destu->Refs );
-		destu->Refs++;
-		DebugCheck( unit->Orders[0].Action!=UnitActionHarvest );
-		NewResetPath(unit);
-		return 1;
-	    }
-	}
-    }
-    return 0;
-}
-
-/**
-**	Return with the wood.
-**
-**	@param unit	unit pointer.
-**
-**	@return		TRUE if reached, otherwise FALSE.
-*/
-local int ReturnWithWood(Unit* unit)
-{
-    Unit* destu;
-    int i;
-
-    destu=unit->Orders[0].Goal;
-    unit->Orders[0].RangeX=unit->Orders[0].RangeY=1;
-    DebugCheck( !destu );
-
-    i=DoActionMove(unit);
-    if( i>=0 && (!unit->Reset || !(destu->Destroyed || destu->Removed
-	    || !destu->HP || destu->Orders[0].Action==UnitActionDie)) ) {
-	return 0;
-    }
-
-    if( !destu ) {
-	unit->Orders[0].Action=UnitActionStill;
-	unit->SubAction=0;
-	return 0;
-    }
-
-    //
-    //	Target is dead, stop harvest
-    //
-    if( destu->Destroyed ) {
-	DebugLevel0Fn("Destroyed unit\n");
-	RefsDebugCheck( !destu->Refs );
-	if( !--destu->Refs ) {
-	    ReleaseUnit(destu);
-	}
-	unit->Orders[0].Goal=NoUnitP;
-	// FIXME: perhaps we should choose an alternative
-	unit->Orders[0].Action=UnitActionStill;
-	unit->SubAction=0;
-	return 0;
-    } else if( destu->Removed || !destu->HP
-	    || destu->Orders[0].Action==UnitActionDie ) {
-	RefsDebugCheck( !destu->Refs );
-	--destu->Refs;
-	RefsDebugCheck( !destu->Refs );
-	unit->Orders[0].Goal=NoUnitP;
-	// FIXME: perhaps we should choose an alternative
-	unit->Orders[0].Action=UnitActionStill;
-	unit->SubAction=0;
-	return 0;
-    }
-
-    DebugCheck( unit->Wait!=1 );
-    DebugCheck( unit->Orders[0].Action!=UnitActionHarvest );
-
-    //
-    //	If depot is still under construction, wait!
-    //
-    if( destu->Orders[0].Action==UnitActionBuilded ) {
-        DebugLevel2Fn("Invalid depot\n");
-	return 0;
-    }
-
-    unit->Orders[0].Goal=NoUnitP;
-
-    RefsDebugCheck( !destu->Refs );
-    --destu->Refs;
-    RefsDebugCheck( !destu->Refs );
-
-    if( i==PF_UNREACHABLE ) {
-	// FIXME: could try another depot, or retry later.
-	DebugLevel2Fn("WOOD-DEPOSIT NOT REACHED %d=%d,%d ? %d\n"
-		  _C_ UnitNumber(destu) _C_ destu->X _C_ destu->Y
-		  _C_ MapDistanceToUnit(unit->X,unit->Y,destu));
-	unit->Orders[0].Action=UnitActionStill;
-	unit->SubAction=0;
-	return 0;
-    }
-
-    RemoveUnit(unit,destu);
-#if 0
-    // FIXME: this breaks the drop out code.
-    // FIXME: this is a hack, but solves the problem, a better solution is
-    // FIXME: still wanted.
-
-    // Place unit where pathfinder is more likely to work
-    if (unit->X < destu->X) {
-	PlaceUnit(unit,destu->X,unit->Y);
- 	RemoveUnit(unit,NULL);		// Unit removal necessary to free map tiles
-    }
-    if (unit->X > destu->X+destu->Type->TileWidth-1) {
-	PlaceUnit(unit,destu->X+destu->Type->TileWidth-1,unit->Y);
-	RemoveUnit(unit,NULL);
-    }
-    if (unit->Y < destu->Y) {
-	PlaceUnit(unit,unit->X,destu->Y);
-	RemoveUnit(unit,NULL);
-    }
-    if (unit->Y > destu->Y+destu->Type->TileHeight-1) {
-	PlaceUnit(unit,unit->X,destu->Y+destu->Type->TileHeight-1);
-	RemoveUnit(unit,NULL);
-    }
-#else
-    unit->X=destu->X;
-    unit->Y=destu->Y;
-#endif
-
-    //
-    //	Update wood.
-    //
-    unit->Player->Resources[WoodCost]+=unit->Player->Incomes[WoodCost];
-    unit->Player->TotalResources[WoodCost]+=unit->Player->Incomes[WoodCost];
-    if( unit->Player==ThisPlayer ) {
-	MustRedraw|=RedrawResources;
-    }
-
-    unit->Player->UnitTypesCount[unit->Type->Type]--;
-    if( unit->Type==UnitTypeOrcWorkerWithWood ) {
-	unit->Type=UnitTypeOrcWorker;
-    } else if( unit->Type==UnitTypeHumanWorkerWithWood ) {
-	unit->Type=UnitTypeHumanWorker;
-    } else {
-	// FIXME: must support more races.
-	DebugLevel0Fn("Wrong unit for returning wood %d\n" _C_ unit->Type->Type);
-    }
-    unit->Player->UnitTypesCount[unit->Type->Type]++;
-
-    unit->Wait=WAIT_FOR_WOOD;
-
-    return 1;
-}
-
-/**
-**	Wait in wood deposit.
-**
-**	@param unit	Pointer to worker unit.
-*/
-local int WaitInWoodDeposit(Unit* unit)
-{
-    Unit* destu;
-
-    DebugLevel3Fn("Waiting\n");
-
-    //
-    //	Drop out unit at nearest point to target.
-    //
-    destu=ResourceDepositOnMap(unit->X,unit->Y,WoodCost);
-    DebugCheck( !destu );		// there must be a depot!
-
-    DropOutNearest(unit
-	    ,unit->Orders[0].X,unit->Orders[0].Y
-	    ,destu->Type->TileWidth,destu->Type->TileHeight);
-
-    //
-    //	Return to chop point.
-    //
-    DebugCheck( unit->Orders[0].Action!=UnitActionHarvest );
-    unit->Orders[0].Goal=NoUnitP;
-    unit->Orders[0].RangeX=unit->Orders[0].RangeY=0;
-    // NOTE: unit->Orders[0].X && unit->Orders[0].Y holds return place.
-    NewResetPath(unit);
-
-    CheckUnitToBeDrawn(unit);
-    unit->Wait=1;
-    //unit->Data.Harvest.WoodToHarvest=CHOP_FOR_WOOD;
-    unit->Value=CHOP_FOR_WOOD;
-    return 1;
-}
-
-/**
-**	Unit Harvest:
-**		Move into forest.
-**		Chop the tree.
-**		Return to wood store.
-**		Deliver wood.
-**		Restart from beginning.
-**
-**	FIXME: we should write a generic resource function
-**
-**	@param unit	Pointer to worker unit.
-*/
-global void HandleActionHarvest(Unit* unit)
-{
-    switch( unit->SubAction ) {
-	case 0:
-	    NewResetPath(unit);
-	    unit->Value=CHOP_FOR_WOOD;
-	    unit->SubAction=1;
-	case 1:
-	    if( MoveToWood(unit) ) {
-		unit->SubAction=64;
-	    }
-	    break;
-
-	case 64:
-	    if( ChopWood(unit) ) {
-		unit->SubAction=128;
-	    }
-	    break;
-
-	case 128:
-	    if( ReturnWithWood(unit) ) {
-		unit->SubAction=192;
-	    }
-	    break;
-
-	case 192:
-	    if( WaitInWoodDeposit(unit) ) {
-		unit->SubAction=0;
-	    }
-	    break;
-    }
-}
-
-//@}
diff --git a/src/action/action_move.cpp b/src/action/action_move.cpp
index b90198ba7..3e2e8c6c2 100644
--- a/src/action/action_move.cpp
+++ b/src/action/action_move.cpp
@@ -78,6 +78,8 @@ local int ActionMoveGeneric(Unit* unit,const Animation* anim)
     // FIXME: state 0?, should be wrong, should be Reset.
     // FIXME: Reset flag is cleared by HandleUnitAction.
     if( !(state=unit->State) ) {
+	//  FIXME: So units flying up and down are not affected.
+	unit->IX=unit->IY=0;
 
 #ifdef HIERARCHIC_PATHFINDER
 	d = PfHierComputePath (unit, &xd, &yd);
diff --git a/src/action/action_resource.cpp b/src/action/action_resource.cpp
index 7c2ddd832..6c77361ff 100644
--- a/src/action/action_resource.cpp
+++ b/src/action/action_resource.cpp
@@ -50,7 +50,7 @@
 ----------------------------------------------------------------------------*/
 
 #define SUB_START_RESOURCE 0
-#define SUB_MOVE_TO_RESOURCE 1
+#define SUB_MOVE_TO_RESOURCE 5
 #define SUB_UNREACHABLE_RESOURCE 31
 #define SUB_START_GATHERING 55
 #define SUB_GATHER_RESOURCE 60
@@ -73,24 +73,62 @@
 local int MoveToResource(Unit* unit)
 {
     Unit* goal;
+    ResourceInfo* resinfo;
+    int x;
+    int y;
 
-    goal=unit->Orders[0].Goal;
-    DebugCheck( !goal );
-
-    switch( DoActionMove(unit) ) {	// reached end-point?
-	case PF_UNREACHABLE:
-	    return -1;
-	case PF_REACHED:
-	    break;
-	default:
-	    if( !unit->Reset || !(goal->Destroyed || goal->Removed
-		    || !goal->HP || goal->Orders[0].Action==UnitActionDie) ) {
-		return 0;
+    resinfo=unit->Type->ResInfo[unit->CurrentResource];
+    if (resinfo->TerrainHarvester) {
+	x=unit->Orders->X;
+	y=unit->Orders->Y;
+	// Wood gone, look somewhere else.
+	if ( (!ForestOnMap(x,y)) && (!unit->IX) && (!unit->IY)) {
+	    if (!FindTerrainType(UnitMovementMask(unit),MapFieldForest,0,10,
+		unit->Player,unit->X,unit->Y,&x,&y)) {
+		DebugLevel3Fn("No wood in range\n");
+		return -1;
+	    } else {
+		DebugLevel3Fn("%d,%d -> %d,%d\n" _C_ unit->X _C_ unit->Y _C_ x _C_ y);
+		unit->Orders->X=x;
+		unit->Orders->Y=y;
+		NewResetPath(unit);
 	    }
-	    break;
+	}
+	switch( DoActionMove(unit)) {
+	    case PF_UNREACHABLE:
+		if (FindTerrainType(UnitMovementMask(unit),MapFieldForest,0,9999,unit->Player,unit->X,unit->Y,&x,&y)) {
+		    unit->Orders->X=x;
+		    unit->Orders->Y=y;
+		    NewResetPath(unit);
+		    DebugLevel3Fn("Found a better place to harvest %d,%d\n" _C_ x _C_ y);
+		    // FIXME: can't this overflow? It really shouldn't, since
+		    // x and y are really supossed to be reachable, checked thorugh a flood fill.
+		    return MoveToResource(unit);
+		}
+		return -1;
+	    case PF_REACHED:
+		return 1;
+	    default:
+		return 0;
+	}
+    } else {
+	goal=unit->Orders[0].Goal;
+	DebugCheck( !goal );
+	switch( DoActionMove(unit) ) {	// reached end-point?
+	    case PF_UNREACHABLE:
+		return -1;
+	    case PF_REACHED:
+		break;
+	    default:
+		// Goal gone or something.
+		if( !unit->Reset || !(goal->Destroyed || goal->Removed
+			|| !goal->HP || goal->Orders[0].Action==UnitActionDie) ) {
+		    return 0;
+		}
+		break;
+	}
+	return 1;
     }
-
-    return 1;
 }
 
 /*
@@ -103,13 +141,30 @@ local int MoveToResource(Unit* unit)
 local int StartGathering(Unit* unit)
 {
     Unit * goal;
+    ResourceInfo* resinfo;
+
+    resinfo=unit->Type->ResInfo[unit->CurrentResource];
+    DebugCheck(unit->IX);
+    DebugCheck(unit->IY);
+    if (resinfo->TerrainHarvester) {
+	DebugCheck(!ForestOnMap(unit->Orders->X,unit->Orders->Y));
+	UnitHeadingFromDeltaXY(unit,unit->Orders->X-unit->X,unit->Orders->Y-unit->Y);
+	if (resinfo->WaitAtResource) {
+	    unit->Data.ResWorker.TimeToHarvest=resinfo->WaitAtResource;
+	} else {
+	    unit->Data.ResWorker.TimeToHarvest=1;
+	}
+	unit->Data.ResWorker.DoneHarvesting=0;
+	return 1;
+    }
+
     goal=unit->Orders[0].Goal;
     //
     //	Target is dead, stop getting resources.
     //
     if( goal->Destroyed || goal->Removed || !goal->HP ||
 	    goal->Orders[0].Action==UnitActionDie) {
-	DebugLevel0Fn("Destroyed resource goal, stop gathering.\n");
+	DebugLevel3Fn("Destroyed resource goal, stop gathering.\n");
 	RefsDebugCheck( !goal->Refs );
 	--goal->Refs;
 	if( goal->Destroyed ) {
@@ -119,15 +174,23 @@ local int StartGathering(Unit* unit)
 	} else {
 	    RefsDebugCheck( !goal->Refs );
 	}
-	unit->Orders[0].Goal=NoUnitP;
+	//  Find an alternative, but don't look too far.
 	unit->Orders[0].X=unit->Orders[0].Y=-1;
-	// FIXME: Choose an alternative
-	unit->Orders[0].Action=UnitActionStill;
-	unit->SubAction=0;
+	if ((goal=FindResource(unit,unit->X,unit->Y,10))) {
+	    unit->SubAction=SUB_START_RESOURCE;
+	    unit->Orders[0].Goal=goal;
+	    RefsDebugCheck( !goal->Refs );
+	    ++goal->Refs;
+	} else {
+	    unit->Orders[0].Action=UnitActionStill;
+	    unit->Orders[0].Goal=0;
+	    unit->SubAction=0;
+	}
 	return 0;
     }
 
     // FIXME: 0 can happen, if to near placed by map designer.
+    DebugLevel3Fn("%d\n" _C_ MapDistanceToUnit(unit->X,unit->Y,goal) );
     DebugCheck( MapDistanceToUnit(unit->X,unit->Y,goal)>1 );
 
     //
@@ -163,7 +226,7 @@ local int StartGathering(Unit* unit)
     //
     //	Place unit inside the resource
     //
-    if (!unit->Type->HarvestFromOutside) {
+    if (!resinfo->HarvestFromOutside) {
 
 	RefsDebugCheck( !goal->Refs );
 	--goal->Refs;
@@ -175,13 +238,9 @@ local int StartGathering(Unit* unit)
 	unit->Y=goal->Y;
     }
 
-    if (unit->Type->WaitAtResource) {
-	unit->Data.ResWorker.TimeToHarvest=unit->Type->WaitAtResource;
-    } else {
-	unit->Data.ResWorker.TimeToHarvest=1;
-    }
+    unit->Data.ResWorker.TimeToHarvest=resinfo->WaitAtResource;
 
-    unit->Reset=1;
+    unit->Data.ResWorker.DoneHarvesting=0;
 
     return 1;
 }
@@ -196,11 +255,7 @@ local void AnimateActionHarvest(Unit* unit)
 	flags=UnitShowAnimation(unit,unit->Type->Animations->Attack);
 #ifdef WITH_SOUND
 	if( (flags&AnimationSound) ) {
-	    if( GameSounds.Repair.Sound==(void*)-1 ) {
-		PlayUnitSound(unit,VoiceAttacking);
-	    } else {
-		PlayUnitSound(unit,VoiceRepair);
-	    }
+	    PlayUnitSound(unit,VoiceTreeChopping);
 	}
 #endif
     }
@@ -218,133 +273,171 @@ local int GatherResource(Unit* unit)
     Unit* source;
     Unit* depot;
     Unit* uins;
+    ResourceInfo* resinfo;
     int i;
     int addload;
-
-    if (unit->Type->HarvestFromOutside) {
+    
+    resinfo=unit->Type->ResInfo[unit->CurrentResource];
+    source=0;
+    
+    if (resinfo->HarvestFromOutside||resinfo->TerrainHarvester) {
 	AnimateActionHarvest(unit);
+	unit->Data.ResWorker.TimeToHarvest-=unit->Wait;
     } else {
+	unit->Data.ResWorker.TimeToHarvest--;
 	unit->Wait=1;
     }
 
-    //  This means we have to return.
-    if (unit->Data.ResWorker.TimeToHarvest==-1) {
-	DebugCheck(!unit->Type->HarvestFromOutside);
+    if (unit->Data.ResWorker.DoneHarvesting) {
+	DebugCheck(!(resinfo->HarvestFromOutside||resinfo->TerrainHarvester));
 	return unit->Reset;
     }
     
-    if (--unit->Data.ResWorker.TimeToHarvest) {
-	DebugLevel3Fn("need to wait %d more cycles.\n" _C_ unit->Data.ResWorker.TimeToHarvest);
+    //  Target gone?
+    if (resinfo->TerrainHarvester&&!ForestOnMap(unit->Orders->X,unit->Orders->Y)) {
+	DebugLevel3Fn("Wood gone for unit %d.\n" _C_ unit->Slot);
+	if (unit->Reset) {
+	    // Action now breakable, move to resource again.
+	    unit->SubAction=SUB_MOVE_TO_RESOURCE;
+	    // Give it some reasonable look while serching.
+	    unit->Frame=unit->Type->Animations->Still->Frame;
+	}
 	return 0;
-    }
-    
-    unit->Data.ResWorker.TimeToHarvest=unit->Type->WaitAtResource;
-    
-    if ( unit->Type->HarvestFromOutside ) {
-	source=unit->Orders[0].Goal;
-    } else {
-	source=unit->Container;
+	// No wood? Freeze!!!
     }
 
-    DebugCheck( !source );
-    DebugCheck( source->Value>655350 );
-
-    //
-    //	Target is dead, stop getting resources.
-    //
-    if( !(source->Destroyed || source->Removed || !source->HP ||
-	    source->Orders[0].Action==UnitActionDie)) {
+    if (!unit->Data.ResWorker.DoneHarvesting&&unit->Data.ResWorker.TimeToHarvest<0) {
+	unit->Data.ResWorker.TimeToHarvest+=resinfo->WaitAtResource;
+	
 	//
 	//  Calculate how much we can load.
-	//  
-	if (unit->Type->ResourceStep) {
-	    addload = unit->Type->ResourceStep;
+	//
+	if (resinfo->ResourceStep) {
+	    addload = resinfo->ResourceStep;
 	} else {
-	    addload = unit->Type->ResourceCapacity;
-	}
-	//  Don't load more that there is.
-	if (addload > source->Value) {
-	    addload = source->Value;
+	    addload = resinfo->ResourceCapacity;
 	}
 	//  Make sure we don't bite more than we can chew.
-	if (unit->Value + addload > unit->Type->ResourceCapacity) {
-	    addload = unit->Type->ResourceCapacity - unit->Value;
+	if (unit->Value + addload > resinfo->ResourceCapacity) {
+	    addload = resinfo->ResourceCapacity - unit->Value;
 	}
-
-	DebugLevel3Fn("Harvested another %d resources.\n" _C_ addload);
 	
-	unit->Value += addload;
-	source->Value -= addload;
-       
-	UnitMarkSeen(source);
-	if( IsOnlySelected(source) ) {
-	    MustRedraw|=RedrawInfoPanel;
-	}
-	//	Change unit to full state.
-	if( unit->Type->TransformWhenLoaded&&unit->Value ) {
-	    unit->Player->UnitTypesCount[unit->Type->Type]--;
-	    unit->Type=unit->Type->TransformWhenLoaded;
-	    unit->Player->UnitTypesCount[unit->Type->Type]++;
-	}
-    }
-    
-    //
-    //	End of resource: destroy the resource.
-    //	FIXME: implement depleted resources.
-    //
-    if( source->Destroyed || source->Removed || !source->HP ||
-	    source->Orders[0].Action==UnitActionDie || source->Value==0) {
-	DebugLevel0Fn("Resource is destroyed\n");
-	uins=source->UnitInside;
-	//
-	// Improved version of DropOutAll that makes workers go to the depot.
-	// FIXME: empty harvesters whould find another resource.
-	// 
-        for( i=source->InsideCount; i; --i,uins=uins->NextContained ) {
-	    if (uins->Value && (depot=FindDeposit(uins->Player,uins->X,uins->Y,source->Type->GivesResource))) {
-		DropOutNearest(uins,depot->X+depot->Type->TileWidth/2
-			,depot->Y+depot->Type->TileHeight/2
-			,source->Type->TileWidth,source->Type->TileHeight);
-		uins->Orders[0].Action=UnitActionReturnGoods;
-		uins->SubAction=0;
-	    	uins->Wait=unit->Reset=1;
-		uins->Orders[0].Goal=depot;
-		
-		RefsDebugCheck( !depot->Refs );
-		++depot->Refs;
-		DebugLevel0Fn("Sent unit %d to depot\n" _C_ uins->Slot);
-		continue;
+	if (resinfo->TerrainHarvester) {
+	    DebugLevel3Fn("Harvested another %d resources.\n" _C_ addload);
+	    unit->Value += addload;
+
+	    if (addload&&unit->Value==resinfo->ResourceCapacity) {
+		DebugLevel3("Removed wood.\n");
+		MapRemoveWood(unit->Orders->X,unit->Orders->Y);
 	    }
-	    DebugLevel0Fn("Unit %d just sits around confused.\n" _C_ uins->Slot);
-	    DropOutOnSide(uins,LookingW
-		    ,source->Type->TileWidth,source->Type->TileHeight);
-	    uins->Orders[0].Goal=0;
-	    uins->Orders[0].X=uins->Orders[0].Y=-1;
-	    uins->Orders[0].Action=UnitActionStill;
-	    uins->Wait=unit->Reset=1;
-	    uins->SubAction=0;
-	}
-
-	//  Don't destroy the resource twice.
-    	if( !(source->Destroyed || source->Removed || !source->HP ||
-	    source->Orders[0].Action==UnitActionDie)){
-	    LetUnitDie(source);
-	}
-	// FIXME: make the workers inside look for a new resource.
-	source=NULL;
-    }
-
-    //  Only return home if we are full.
-    if (unit->Value < unit->Type->ResourceCapacity || !source) {
-	return 0;
-    } else {
-	if (unit->Type->HarvestFromOutside) {
-	    unit->Data.ResWorker.TimeToHarvest=-1;
-	    return 0;
 	} else {
-	    return 1;
+	    if ( resinfo->HarvestFromOutside ) {
+		source=unit->Orders[0].Goal;
+	    } else {
+		source=unit->Container;
+	    }
+
+	    DebugCheck( !source );
+	    DebugCheck( source->Value>655350 );
+
+	    //
+	    //	Target is dead, stop getting resources.
+	    //
+	    if( !(source->Destroyed || source->Removed || !source->HP ||
+		    source->Orders[0].Action==UnitActionDie)) {
+		//  Don't load more that there is.
+		if (addload > source->Value) {
+		    addload = source->Value;
+		}
+
+		DebugLevel3Fn("Harvested another %d resources.\n" _C_ addload);
+		unit->Value += addload;
+		source->Value -= addload;
+	       
+		UnitMarkSeen(source);
+		if( IsOnlySelected(source) ) {
+		    MustRedraw|=RedrawInfoPanel;
+		}
+	    }
+	    
+	    //
+	    //	End of resource: destroy the resource.
+	    //	FIXME: implement depleted resources.
+	    //
+	    if( source->Destroyed || source->Removed || !source->HP ||
+		    source->Orders[0].Action==UnitActionDie || source->Value==0) {
+		DebugLevel0Fn("Resource is destroyed\n");
+		uins=source->UnitInside;
+		//
+		// Improved version of DropOutAll that makes workers go to the depot.
+		// FIXME: empty harvesters should find another resource.
+		// 
+		for( i=source->InsideCount; i; --i,uins=uins->NextContained ) {
+		    if (uins->Value && (depot=FindDeposit(uins,uins->X,uins->Y,1000))) {
+			DropOutNearest(uins,depot->X+depot->Type->TileWidth/2
+				,depot->Y+depot->Type->TileHeight/2
+				,source->Type->TileWidth,source->Type->TileHeight);
+			//  Remember were it mined, so it can look around for another resource.
+			uins->Orders[0].Arg1=(void*)((unit->X<<16)|unit->Y);
+			uins->Orders[0].Goal=depot;
+			RefsDebugCheck( !depot->Refs );
+			++depot->Refs;
+			NewResetPath(uins);
+			uins->SubAction=SUB_MOVE_TO_DEPOT;
+			uins->Wait=1;
+			DebugLevel0Fn("Sent unit %d to depot\n" _C_ uins->Slot);
+			continue;
+		    }
+		    DropOutOnSide(uins,LookingW
+			    ,source->Type->TileWidth,source->Type->TileHeight);
+		    uins->Orders[0].X=uins->Orders[0].Y=-1;
+		    if ((uins->Orders[0].Goal=FindResource(uins,uins->X,uins->Y,10))) {
+			DebugLevel0Fn("Unit %d found another resource.\n" _C_ uins->Slot);
+			uins->SubAction=SUB_START_RESOURCE;
+			uins->Wait=1;
+			RefsDebugCheck( !uins->Orders[0].Goal->Refs );
+			++uins->Orders[0].Goal->Refs;
+		    } else {
+			DebugLevel0Fn("Unit %d just sits around confused.\n" _C_ uins->Slot);
+			uins->Orders[0].Action=UnitActionStill;
+			uins->SubAction=0;
+			uins->Wait=unit->Reset=1;
+		    }
+		}
+
+		//  Don't destroy the resource twice.
+		if( !(source->Destroyed || source->Removed || !source->HP ||
+		    source->Orders[0].Action==UnitActionDie)){
+		    LetUnitDie(source);
+		    // FIXME: make the workers inside look for a new resource.
+		}
+		source=NULL;
+	    }
+	}
+	if (resinfo->TerrainHarvester) {
+	    if (unit->Value == resinfo->ResourceCapacity) {
+		// Mark as complete.
+		DebugLevel3Fn("Done Harvesting, waiting for reset.\n");
+		unit->Data.ResWorker.DoneHarvesting=1;
+	    }
+	    return 0;
+	}
+	
+	if (resinfo->HarvestFromOutside && !resinfo->TerrainHarvester) {
+	    if ((unit->Value == resinfo->ResourceCapacity)||(source==NULL)) {
+		// Mark as complete.
+		DebugLevel3Fn("Done Harvesting, waiting for reset %X.\n" _C_ (unsigned)source);
+		unit->Data.ResWorker.DoneHarvesting=1;
+	    }
+	    return 0;
+	}
+	
+	if ((!resinfo->HarvestFromOutside)&& (!resinfo->TerrainHarvester)) {
+	    return unit->Value==resinfo->ResourceCapacity&&source;
 	}
     }
+
+    return 0;
 }
 
 /**
@@ -358,25 +451,31 @@ local int StopGathering(Unit* unit)
 {
     Unit* depot;
     Unit* source;
+    ResourceInfo* resinfo;
 
-    
-    if ( unit->Type->HarvestFromOutside ) {
-	source=unit->Orders[0].Goal;
-    } else {
-	source=unit->Container;
+    resinfo=unit->Type->ResInfo[unit->CurrentResource];
+
+   
+    source=0;
+    if (!resinfo->TerrainHarvester) {
+	if ( resinfo->HarvestFromOutside ) {
+	    source=unit->Orders[0].Goal;
+	} else {
+	    source=unit->Container;
+	}
+	source->Data.Resource.Active--;
+	DebugCheck(source->Data.Resource.Active<0);
     }
      
-    source->Data.Resource.Active--;
-    DebugCheck(source->Data.Resource.Active<0);
 
     //	Store resource position.
     //	FIXME: is this the best way?
     unit->Orders[0].Arg1=(void*)((unit->X<<16)|unit->Y);
    
     // Find and send to resource deposit.
-    if( (!(depot=FindDeposit(unit->Player,unit->X,unit->Y,unit->Type->ResourceHarvested)))
+    if( (!(depot=FindDeposit(unit,unit->X,unit->Y,1000)))
 	    || (!unit->Value)) {
-	if (!unit->Type->HarvestFromOutside) {
+	if (!(resinfo->HarvestFromOutside||resinfo->TerrainHarvester)) {
 	    DebugCheck(!unit->Container);
 	    DropOutOnSide(unit,LookingW,source->Type->TileWidth,source->Type->TileHeight);
 	}
@@ -385,7 +484,7 @@ local int StopGathering(Unit* unit)
 	unit->SubAction=0;
 	// should return 0, done below!
     } else {
-	if (!unit->Type->HarvestFromOutside) {
+	if (!(resinfo->HarvestFromOutside||resinfo->TerrainHarvester)) {
 	    DebugCheck(!unit->Container);
 	    DropOutNearest(unit,depot->X+depot->Type->TileWidth/2
 		    ,depot->Y+depot->Type->TileHeight/2
@@ -421,6 +520,9 @@ local int StopGathering(Unit* unit)
 local int MoveToDepot(Unit* unit)
 {
     Unit* goal;
+    ResourceInfo* resinfo;
+
+    resinfo=unit->Type->ResInfo[unit->CurrentResource];
 
     goal=unit->Orders[0].Goal;
     DebugCheck( !goal );
@@ -489,29 +591,17 @@ local int MoveToDepot(Unit* unit)
     //
     //	Update resource.
     //
-    unit->Player->Resources[unit->Type->ResourceHarvested]+=
-	(unit->Value*unit->Player->Incomes[unit->Type->ResourceHarvested])/100;
-    unit->Player->TotalResources[unit->Type->ResourceHarvested]+=
-	(unit->Value*unit->Player->Incomes[unit->Type->ResourceHarvested])/100;
+    unit->Player->Resources[resinfo->FinalResource]+=
+	(unit->Value*unit->Player->Incomes[resinfo->FinalResource])/100;
+    unit->Player->TotalResources[resinfo->FinalResource]+=
+	(unit->Value*unit->Player->Incomes[resinfo->FinalResource])/100;
     unit->Value=0;
     if( unit->Player==ThisPlayer ) {
 	MustRedraw|=RedrawResources;
     }
 
-    //
-    //	Change unit to empty state.
-    //
-    if( unit->Type->TransformWhenEmpty ) {
-    	unit->Player->UnitTypesCount[unit->Type->Type]--;
-	unit->Type=unit->Type->TransformWhenEmpty;
-    	unit->Player->UnitTypesCount[unit->Type->Type]++;
-    }
+    unit->Wait=resinfo->WaitAtDepot;
 
-    if (unit->Type->WaitAtDepot) {
-	unit->Wait=unit->Type->WaitAtDepot;
-    } else {
-	unit->Wait=1;
-    }
     return 1;
 }
 
@@ -526,10 +616,13 @@ local int WaitInDepot(Unit* unit)
 {
     const Unit* depot;
     Unit* goal;
+    ResourceInfo* resinfo;
     int x;
     int y;
 
-    depot=ResourceDepositOnMap(unit->X,unit->Y,unit->Type->ResourceHarvested);
+    resinfo=unit->Type->ResInfo[unit->CurrentResource];
+
+    depot=ResourceDepositOnMap(unit->X,unit->Y,resinfo->ResourceId);
     DebugCheck( !depot );
     // Could be destroyed, but then we couldn't be in?
 
@@ -540,20 +633,33 @@ local int WaitInDepot(Unit* unit)
 	x=(int)unit->Orders[0].Arg1>>16;
 	y=(int)unit->Orders[0].Arg1&0xFFFF;
     }
-    if( !(goal=FindResource(unit->Player,x,y,unit->Type->ResourceHarvested)) ) {
-	DropOutOnSide(unit,LookingW,
-		depot->Type->TileWidth,depot->Type->TileHeight);
-	unit->Orders[0].Action=UnitActionStill;
-	unit->SubAction=0;
+    //  Range hardcoded. don't stray too far though
+    if( resinfo->TerrainHarvester ) {
+	if (FindTerrainType(UnitMovementMask(unit),MapFieldForest,0,10,
+		unit->Player,x,y,&x,&y)) {
+	    DropOutNearest(unit,x,y,depot->Type->TileWidth,depot->Type->TileHeight);
+	    unit->Orders->X=x;
+	    unit->Orders->Y=y;
+	} else {
+	    DropOutOnSide(unit,LookingW,depot->Type->TileWidth,depot->Type->TileHeight);
+	    unit->Orders[0].Action=UnitActionStill;
+	    unit->SubAction=0;
+	}
     } else {
-	DropOutNearest(unit,goal->X+goal->Type->TileWidth/2
-		,goal->Y+goal->Type->TileHeight/2
-		,depot->Type->TileWidth,depot->Type->TileHeight);
-	unit->Orders[0].Goal=goal;
-	RefsDebugCheck( !goal->Refs );
-	++goal->Refs;
-	unit->Orders[0].RangeX=unit->Orders[0].RangeY=1;
-	unit->Orders[0].X=unit->Orders[0].Y=-1;
+	if ((goal=FindResource(unit,x,y,10))) {
+	    DropOutNearest(unit,goal->X+goal->Type->TileWidth/2
+		    ,goal->Y+goal->Type->TileHeight/2
+		    ,depot->Type->TileWidth,depot->Type->TileHeight);
+	    unit->Orders[0].Goal=goal;
+	    RefsDebugCheck( !goal->Refs );
+	    ++goal->Refs;
+	    unit->Orders[0].RangeX=unit->Orders[0].RangeY=1;
+	    unit->Orders[0].X=unit->Orders[0].Y=-1;
+	} else {
+	    DropOutOnSide(unit,LookingW,depot->Type->TileWidth,depot->Type->TileHeight);
+	    unit->Orders[0].Action=UnitActionStill;
+	    unit->SubAction=0;
+	}
     }
 
     CheckUnitToBeDrawn(unit);
@@ -574,6 +680,10 @@ void ResourceGiveUp(Unit* unit)
     unit->Reset=1;
     unit->Orders[0].X=unit->Orders[0].Y=-1;
     unit->SubAction=0;
+    if( unit->Type->ResInfo[unit->CurrentResource]->LoseResources ) {
+	unit->Value=0;
+	unit->CurrentResource=0;
+    }
     if( unit->Orders[0].Goal ) {
 	RefsDebugCheck( !unit->Orders[0].Goal->Refs );
 	--unit->Orders[0].Goal->Refs;
@@ -591,13 +701,23 @@ void ResourceGiveUp(Unit* unit)
 */
 global void HandleActionResource(Unit* unit)
 {
-    int ret;
+    int ret,newres;
 
     DebugLevel3Fn("%s(%d) SubAction %d\n"
 	_C_ unit->Type->Ident _C_ UnitNumber(unit) _C_ unit->SubAction);
-
+    
     //	Let's start mining.
     if ( unit->SubAction==SUB_START_RESOURCE ) {
+	if (unit->Orders->Goal) {
+	    newres=unit->Orders->Goal->Type->GivesResource;
+	} else {
+	    newres=WoodCost;
+	}
+	if (newres!=unit->CurrentResource) {
+	    // Drop other resources.
+	    unit->Value=0;
+	}
+	unit->CurrentResource=newres;
 	NewResetPath(unit);
 	DebugLevel3Fn("Started mining. reset path.\n");
 	unit->SubAction=SUB_MOVE_TO_RESOURCE;
@@ -632,8 +752,9 @@ global void HandleActionResource(Unit* unit)
     if (unit->SubAction==SUB_START_GATHERING) {
 	if (StartGathering(unit)) {
 	    unit->SubAction=SUB_GATHER_RESOURCE;
-	}
+	} else {
 	return;
+	}
     }
     
     //  Gather the resource.
diff --git a/src/action/action_returngoods.cpp b/src/action/action_returngoods.cpp
index aff10d08d..15d08a6fb 100644
--- a/src/action/action_returngoods.cpp
+++ b/src/action/action_returngoods.cpp
@@ -54,9 +54,9 @@
 /**
 **	Return goods to gold/wood deposit.
 **
-**	FIXME: must support to move to a specified deposit.
-**
 **	@param unit	pointer to unit.
+**
+**	FIXME: move this into action_resource?
 */
 global void HandleActionReturnGoods(Unit* unit)
 {
@@ -65,56 +65,30 @@ global void HandleActionReturnGoods(Unit* unit)
 
     type=unit->Type;
     //
-    //	Select target to return goods. FIXME: more races support
+    //	Select target to return goods. 
     // 
-    if( type->Harvester ) {
-	if( !unit->Orders[0].Goal ) {
-	    if( !(destu=FindDeposit(unit->Player,unit->X,unit->Y,type->ResourceHarvested)) ) {
-		DebugLevel3Fn("No deposit -> can't return\n");
-		unit->Orders[0].Action=UnitActionStill;
-		return;
-	    }
-	    unit->Orders[0].Goal=destu;
-	    RefsDebugCheck( !destu->Refs );
-	    ++destu->Refs;
+    DebugCheck(!type->Harvester );
+    if( !unit->Orders[0].Goal ) {
+	if( !(destu=FindDeposit(unit,unit->X,unit->Y,1000)) ) {
+	    DebugLevel3Fn("No deposit -> can't return\n");
+	    unit->Orders[0].Action=UnitActionStill;
+	    return;
 	}
-	DebugLevel3("Return to %d=%d,%d\n"
-		_C_ UnitNumber(unit->Orders[0].Goal)
-		_C_ unit->Orders[0].X _C_ unit->Orders[0].Y);
-	unit->Orders[0].Action=UnitActionResource;
-	// Somewhere on the way the loaded worker changed Arg1.
-	// Bummer, go get the closest resource to the depot
-	unit->Orders[0].Arg1=(void*)-1;
-	NewResetPath(unit);
-	unit->SubAction=70;
-	unit->Wait=1;
-	return;
-    }
-    
-    if( type==UnitTypeHumanWorkerWithWood || type==UnitTypeOrcWorkerWithWood ) {
-	if( !unit->Orders[0].Goal ) {
-	    if( !(destu=FindDeposit(unit->Player,unit->X,unit->Y,WoodCost)) ) {
-		// No deposit -> can't return
-		unit->Orders[0].Action=UnitActionStill;
-		return;
-	    }
-	    unit->Orders[0].Goal=destu;
-	    RefsDebugCheck( !destu->Refs );
-	    ++destu->Refs;
-	}
-	unit->Orders[0].X=unit->X;
-	unit->Orders[0].Y=unit->Y;	// Return point to continue.
-	DebugLevel3("Return to %d=%d,%d\n"
-		_C_ UnitNumber(unit->Orders[0].Goal)
-		_C_ unit->Orders[0].X _C_ unit->Orders[0].Y);
-	unit->Orders[0].Action=UnitActionHarvest;
-	unit->Orders[0].Arg1=(void*)-1;
-	NewResetPath(unit);
-	unit->SubAction=128;		// FIXME: Hardcoded
-	DebugLevel3("Wait: %d\n" _C_ unit->Wait);
-	unit->Wait=1;
-	return;
+	unit->Orders[0].Goal=destu;
+	RefsDebugCheck( !destu->Refs );
+	++destu->Refs;
     }
+    DebugLevel3("Return to %d=%d,%d\n"
+	    _C_ UnitNumber(unit->Orders[0].Goal)
+	    _C_ unit->Orders[0].X _C_ unit->Orders[0].Y);
+    unit->Orders[0].Action=UnitActionResource;
+    // Somewhere on the way the loaded worker could have change Arg1
+    // Bummer, go get the closest resource to the depot
+    unit->Orders[0].Arg1=(void*)-1;
+    NewResetPath(unit);
+    unit->SubAction=70;
+    unit->Wait=1;
+    return;
 }
 
 //@}
diff --git a/src/action/action_train.cpp b/src/action/action_train.cpp
index 773c48789..8a078a06f 100644
--- a/src/action/action_train.cpp
+++ b/src/action/action_train.cpp
@@ -155,9 +155,6 @@ global void HandleActionTrain(Unit* unit)
 	        && !nunit->Type->Harvester)
     	    || (unit->NewOrder.Action==UnitActionAttack
 	        && !nunit->Type->CanAttack)
-            || ((unit->NewOrder.Action==UnitActionHarvest)
-		&& nunit->Type!=UnitTypeOrcWorker 
-		&& nunit->Type!=UnitTypeHumanWorker )
 	    || (unit->NewOrder.Action==UnitActionBoard
 	        && nunit->Type->UnitType!=UnitTypeLand) ) {
 	    DebugLevel0Fn("Wrong order for unit\n");
diff --git a/src/action/actions.cpp b/src/action/actions.cpp
index 891fc7422..14e21e9dc 100644
--- a/src/action/actions.cpp
+++ b/src/action/actions.cpp
@@ -174,10 +174,10 @@ local void (*HandleActionTable[256])(Unit*) = {
     HandleActionPatrol,
     HandleActionBuild,
     HandleActionRepair,
-    HandleActionHarvest,
     HandleActionResource,
     HandleActionReturnGoods,
     HandleActionDemolish,
+    HandleActionNotWritten,
 
     // Enough for the future ?
     HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten,
@@ -268,7 +268,7 @@ local void (*HandleActionTable[256])(Unit*) = {
 local void HandleUnitAction(Unit* unit)
 {
     int z;
-
+	
     //
     //	If current action is breakable proceed with next one.
     //
@@ -306,6 +306,11 @@ local void HandleUnitAction(Unit* unit)
 		    ReleaseUnit(unit->Orders[0].Goal);
 		}
 	    }
+	    if (unit->CurrentResource) {
+		if (unit->Type->ResInfo[unit->CurrentResource]->LoseResources) {
+		    unit->Value=0;
+		}
+	    }
 
 	    //
 	    //	Shift queue with structure assignment.
diff --git a/src/action/command.cpp b/src/action/command.cpp
index aa9d9fb46..309b648d6 100644
--- a/src/action/command.cpp
+++ b/src/action/command.cpp
@@ -702,29 +702,23 @@ global void CommandCancelBuilding(Unit* unit,
 }
 
 /**
-**	Send unit harvest
+**	Send unit harvest a location
 **
 **	@param unit	pointer to unit.
 **	@param x	X map position for harvest.
 **	@param y	Y map position for harvest.
 **	@param flush	if true, flush command queue.
 */
-global void CommandHarvest(Unit* unit,int x,int y,int flush)
+global void CommandResourceLoc(Unit* unit,int x,int y,int flush)
 {
     Order* order;
+    int nx;
+    int ny;
 
     //
     //	Check if unit is still valid? (NETWORK!)
     //
     if( !unit->Removed && unit->Orders[0].Action!=UnitActionDie ) {
-	// FIXME: more races, could happen with many orders in queue.
-	if( !unit->Type->Building
-		&& unit->Type!=UnitTypeHumanWorker
-		&& unit->Type!=UnitTypeOrcWorker ) {
-	    DebugLevel0Fn("None worker gets order\n");
-	    ClearSavedAction(unit);
-	    return;
-	}
 	if( unit->Type->Building ) {
 	    // FIXME: should find a better way for pending orders.
 	    order=&unit->NewOrder;
@@ -733,9 +727,27 @@ global void CommandHarvest(Unit* unit,int x,int y,int flush)
 	    return;
 	}
 
-	order->Action=UnitActionHarvest;
-	order->X=x;
-	order->Y=y;
+	order->Action=UnitActionResource;
+	
+	//  Find the closest piece of wood next to a tile where the unit can move
+	DebugLevel3("Want to harvest from %d,%d.\n" _C_ x _C_ y);
+	if (!FindTerrainType(0,(unit->Type->MovementMask),1,20,unit->Player,x,y,&nx,&ny)) {
+	    DebugLevel0Fn("FIXME: Give up???\n");
+	}
+	if (max(abs(nx-x),abs(ny-y))>1) {
+	    DebugLevel3("Closest tile reachable is at %d,%d.\n" _C_ x _C_ y);
+	    if (!FindTerrainType(0,MapFieldForest,0,20,unit->Player,nx,ny,&nx,&ny)) {
+		DebugLevel0Fn("FIXME: Give up???\n");
+	    }
+	} else {
+	    // The destination is next to a reacahble tile.
+	    nx=x;
+	    ny=y;
+	}
+	DebugLevel3("So the final destination is %d,%d.\n" _C_ nx _C_ ny);
+	order->X=nx;
+	order->Y=ny;
+
 	order->RangeX=order->RangeY=1;
 	order->Goal=NoUnitP;
 	order->Type=NULL;
@@ -806,8 +818,7 @@ global void CommandReturnGoods(Unit* unit,Unit* goal,int flush)
 	// FIXME: more races, could happen with many orders in queue.
 	if( !unit->Type->Building
 		&& !unit->Type->Harvester
-		&& unit->Type!=UnitTypeHumanWorkerWithWood
-		&& unit->Type!=UnitTypeOrcWorkerWithWood) {
+		&& !unit->Value ) { 
 	    ClearSavedAction(unit);
 	    return;
 	}
diff --git a/src/ai/ai_resource.cpp b/src/ai/ai_resource.cpp
index 06f8ea715..446c1f58d 100644
--- a/src/ai/ai_resource.cpp
+++ b/src/ai/ai_resource.cpp
@@ -744,180 +744,12 @@ local void AiCheckingWork(void)
 **
 **	@return		Pointer to the nearest reachable gold mine.
 **
-**	@see FindGoldMine but this version doesn't check for explored tiles.
+**	@see FindGoldMine
 */
 local Unit* AiFindGoldMine(const Unit* unit)
 {
-    static const int xoffset[]={  0,-1,+1, 0, -1,+1,-1,+1 };
-    static const int yoffset[]={ -1, 0, 0,+1, -1,-1,+1,+1 };
-    struct {
-	unsigned short X;
-	unsigned short Y;
-    } * points;
-    int size;
-    int x;
-    int y;
-    int rx;
-    int ry;
-    int mask;
-    int wp;
-    int rp;
-    int ep;
-    int i;
-    int w;
-    int n;
-    unsigned char* m;
-    unsigned char* matrix;
-    const Unit* destu;
-    Unit* mine;
-    Unit* bestmine;
-    int destx;
-    int desty;
-    int bestx;
-    int besty;
-    int bestd;
-
-    destx=x=unit->X;
-    desty=y=unit->Y;
-    size=TheMap.Width*TheMap.Height/4;
-    points=malloc(size*sizeof(*points));
-
-    //
-    //	Find the nearest gold depot
-    //
-    if( (destu=FindDeposit(unit->Player,x,y,GoldCost)) ) {
-	NearestOfUnit(destu,x,y,&destx,&desty);
-    }
-    bestd=99999;
-    IfDebug( bestx=besty=0; );		// keep the compiler happy
-
-    //
-    //	Make movement matrix. FIXME: can create smaller matrix.
-    //
-    matrix=CreateMatrix();
-    w=TheMap.Width+2;
-    matrix+=w+w+2;
-
-    //
-    //	Mark sight range as border. FIXME: matrix didn't need to be bigger.
-    //
-    n=unit->Stats->SightRange;
-    rx=x-n;
-    if( rx<0 ) {
-	rx=0;
-    }
-    ep=x+n;
-    if( ep>TheMap.Width ) {
-	ep=TheMap.Width;
-    }
-    ry=y-n;
-    if( ry<0 ) {
-	ry=0;
-    }
-    wp=y+n;
-    if( wp>TheMap.Height ) {
-	wp=TheMap.Height;
-    }
-    for( i=rx; i<ep; ++i ) {		// top bottom line
-	matrix[i+ry*w]=matrix[i+wp*w]=66;
-    }
-    for( i=ry+1; i<wp-1; ++i ) {
-	matrix[rx+i*w]=matrix[ep+i*w]=66;
-    }
-
-#if 0
-    matrix[x+n+(y+n)*w]=matrix[x-n+(y+n)*w]=
-	matrix[x+n+(y-n)*w]=matrix[x-n+(y-n)*w]=66;
-    for( i=n; i--; ) {
-	// FIXME: marks out of map area
-	DebugCheck( x-i+(y-n)*w<0 || x+i+(y+n)*w>w*TheMap.Hight );
-	matrix[x+n+(y+i)*w]=matrix[x-n+(y+i)*w]=
-	    matrix[x+n+(y-i)*w]=matrix[x-n+(y-i)*w]=
-	    matrix[x-i+(y+n)*w]=matrix[x+i+(y+n)*w]=
-	    matrix[x-i+(y-n)*w]=matrix[x+i+(y-n)*w]=66;
-    }
-#endif
-
-    mask=UnitMovementMask(unit);
-
-    points[0].X=x;
-    points[0].Y=y;
-    rp=0;
-    matrix[x+y*w]=1;			// mark start point
-    ep=wp=1;				// start with one point
-    bestmine=NoUnitP;
-
-    //
-    //	Pop a point from stack, push all neighbors which could be entered.
-    //
-    for( ;; ) {
-	while( rp!=ep ) {
-	    rx=points[rp].X;
-	    ry=points[rp].Y;
-	    for( i=0; i<8; ++i ) {		// mark all neighbors
-		x=rx+xoffset[i];
-		y=ry+yoffset[i];
-		m=matrix+x+y*w;
-		if( *m ) {			// already checked
-		    continue;
-		}
-
-		//
-		//	Look if there is a mine
-		//
-		if ( (mine=ResourceOnMap(x,y,GoldCost)) ) {
-		    if( destu ) {
-			n=max(abs(destx-x),abs(desty-y));
-			if( n<bestd ) {
-			    bestd=n;
-			    bestx=x;
-			    besty=y;
-			    bestmine=mine;
-			}
-			*m=22;
-		    } else {			// no goal take the first
-			free(points);
-			return mine;
-		    }
-		}
-
-		if( CanMoveToMask(x,y,mask) ) {	// reachable
-		    *m=1;
-		    points[wp].X=x;		// push the point
-		    points[wp].Y=y;
-		    if( ++wp>=size ) {		// round about
-			wp=0;
-		    }
-		} else {			// unreachable
-		    *m=99;
-		}
-	    }
-	    if( ++rp>=size ) {			// round about
-		rp=0;
-	    }
-	}
-
-	//
-	//	Take best of this frame, if any.
-	//
-	if( bestd!=99999 ) {
-	    free(points);
-	    return bestmine;
-	}
-
-	//
-	//	Continue with next frame.
-	//
-	if( rp==wp ) {			// unreachable, no more points available
-	    break;
-	}
-	ep=wp;
-    }
-
-    DebugLevel3Fn("no mine in sight-range\n");
-
-    free(points);
-    return NoUnitP;
+    // FIXME: explored tiles?
+    return FindResource(unit,unit->X,unit->Y,100);
 }
 
 /**
@@ -939,113 +771,12 @@ local int AiMineGold(Unit* unit)
 		_C_ unit->Type->Ident _C_ unit->X _C_ unit->Y);
 	return 0;
     }
-    DebugCheck(unit->Type != UnitTypeHumanWorker
-	    && unit->Type != UnitTypeOrcWorker);
 
     CommandResource(unit, dest, FlushCommands);
 
     return 1;
 }
 
-#if 0
-
-/**
-**      Assign worker to harvest.
-**
-**	@param unit	Find wood for this worker.
-*/
-local int AiHarvest(Unit * unit)
-{
-    int x, y, addx, addy, i, n, r, wx, wy, bestx, besty, cost;
-    Unit *dest;
-
-    DebugLevel3Fn("%d\n" _C_ UnitNumber(unit));
-    x = unit->X;
-    y = unit->Y;
-    addx = unit->Type->TileWidth;
-    addy = unit->Type->TileHeight;
-    r = TheMap.Width;
-    if (r < TheMap.Height) {
-	r = TheMap.Height;
-    }
-
-    //  This is correct, but can this be written faster???
-    if ((dest = FindWoodDeposit(unit->Player, x, y))) {
-	NearestOfUnit(dest, x, y, &wx, &wy);
-	DebugLevel3("To %d,%d\n" _C_ wx _C_ wy);
-    } else {
-	wx = unit->X;
-	wy = unit->Y;
-    }
-    cost = 99999;
-    IfDebug(bestx = besty = 0; );	// keep the compiler happy
-
-    // FIXME: if we reach the map borders we can go fast up, left, ...
-    --x;
-    while (addx <= r && addy <= r) {
-	for (i = addy; i--; y++) {	// go down
-	    if (CheckedForestOnMap(x, y)) {
-		n = max(abs(wx - x), abs(wy - y));
-		DebugLevel3("Distance %d,%d %d\n" _C_ x _C_ y _C_ n);
-		if (n < cost && PlaceReachable(unit, x-1, y-1, 3)) {
-		    cost = n;
-		    bestx = x;
-		    besty = y;
-		}
-	    }
-	}
-	++addx;
-	for (i = addx; i--; x++) {	// go right
-	    if (CheckedForestOnMap(x, y)) {
-		n = max(abs(wx - x), abs(wy - y));
-		DebugLevel3("Distance %d,%d %d\n" _C_ x _C_ y _C_ n);
-		if (n < cost && PlaceReachable(unit, x-1, y-1, 3)) {
-		    cost = n;
-		    bestx = x;
-		    besty = y;
-		}
-	    }
-	}
-	++addy;
-	for (i = addy; i--; y--) {	// go up
-	    if (CheckedForestOnMap(x, y)) {
-		n = max(abs(wx - x), abs(wy - y));
-		DebugLevel3("Distance %d,%d %d\n" _C_ x _C_ y _C_ n);
-		if (n < cost && PlaceReachable(unit, x-1, y-1, 3)) {
-		    cost = n;
-		    bestx = x;
-		    besty = y;
-		}
-	    }
-	}
-	++addx;
-	for (i = addx; i--; x--) {	// go left
-	    if (CheckedForestOnMap(x, y)) {
-		n = max(abs(wx - x), abs(wy - y));
-		DebugLevel3("Distance %d,%d %d\n" _C_ x _C_ y _C_ n);
-		if (n < cost && PlaceReachable(unit, x-1, y-1, 3)) {
-		    cost = n;
-		    bestx = x;
-		    besty = y;
-		}
-	    }
-	}
-	if (cost != 99999) {
-	    DebugLevel3Fn("wood on %d,%d\n" _C_ x _C_ y);
-	    DebugCheck(unit->Type!=UnitTypeHumanWorker && unit->Type!=UnitTypeOrcWorker);
-	    CommandHarvest(unit, bestx, besty,FlushCommands);
-	    return 1;
-	}
-	++addy;
-    }
-
-    DebugLevel0Fn("no wood reachable by %s(%d,%d)\n");
-	    _C_ unit->Type->Ident _C_ unit->X _C_ unit->Y);
-    return 0;
-}
-
-#else
-
 /**
 **      Assign worker to harvest.
 **
@@ -1090,7 +821,7 @@ local int AiHarvest(Unit * unit)
     //
     //	Find the nearest wood depot
     //
-    if( (destu=FindDeposit(unit->Player,x,y,WoodCost)) ) {
+    if( (destu=FindDeposit(unit,x,y,100)) ) {
 	NearestOfUnit(destu,x,y,&destx,&desty);
     }
     bestd=99999;
@@ -1139,9 +870,7 @@ local int AiHarvest(Unit * unit)
 			}
 			*m=22;
 		    } else {			// no goal take the first
-			DebugCheck(unit->Type!=UnitTypeHumanWorker
-				&& unit->Type!=UnitTypeOrcWorker);
-			CommandHarvest(unit,x,y,FlushCommands);
+			CommandResourceLoc(unit,x,y,FlushCommands);
 			free(points);
 			return 1;
 		    }
@@ -1167,9 +896,7 @@ local int AiHarvest(Unit * unit)
 	//	Take best of this frame, if any.
 	//
 	if( bestd!=99999 ) {
-	    DebugCheck(unit->Type!=UnitTypeHumanWorker
-		    && unit->Type!=UnitTypeOrcWorker);
-	    CommandHarvest(unit, bestx, besty,FlushCommands);
+	    CommandResourceLoc(unit, bestx, besty,FlushCommands);
 	    free(points);
 	    return 1;
 	}
@@ -1190,8 +917,6 @@ local int AiHarvest(Unit * unit)
     return 0;
 }
 
-#endif
-
 /**
 **      Assign worker to haul oil.
 */
@@ -1200,7 +925,8 @@ local int AiHaulOil(Unit * unit)
     Unit *dest;
 
     DebugLevel3Fn("%d\n" _C_ UnitNumber(unit));
-    dest = FindResource(unit->Player, unit->X, unit->Y ,unit->Type->ResourceHarvested);
+    //  Range hardcoded. search the whole map!!!
+    dest = FindResource(unit, unit->X, unit->Y,1000);
     if (!dest) {
 	DebugLevel3Fn("oil platform not reachable by %s(%d,%d)\n"
 		_C_ unit->Type->Ident _C_ unit->X _C_ unit->Y);
@@ -1261,27 +987,19 @@ local void AiCollectResources(void)
 	if( !unit->Type->Harvester ) {
 	    continue;
 	}
-	c=unit->Type->ResourceHarvested;
 
 	//
 	//	See if it's assigned already
 	//
-	switch( unit->Orders[0].Action ) {
-	    case UnitActionHarvest:
-		units_assigned[num_units_assigned[WoodCost]++][WoodCost]=unit;
-		continue;
-	    case UnitActionResource:
-		units_assigned[num_units_assigned[c]++][c]=unit;
-		continue;
-	    default:
-		break;
+	if (unit->Orders[0].Action==UnitActionResource) {
+	    c=unit->CurrentResource;
+	    units_assigned[num_units_assigned[c]++][c]=unit;
 	}
 
 	//
 	//  Send workers with resources back home.
 	//
-	if (unit->Value||unit->Type==UnitTypeHumanWorkerWithWood
-		||unit->Type==UnitTypeOrcWorkerWithWood) {
+	if (unit->Value) {
 	    units_with_resource[num_units_with_resource[c]++][c]=unit;
 	    if (unit->Orders[0].Action == UnitActionStill
 		    && unit->OrderCount==1 ) {
@@ -1293,7 +1011,10 @@ local void AiCollectResources(void)
 	//	Look what the unit can do
 	//
 	for( c=0; c<MaxCosts; ++c ) {
-	    int tn;
+	    if (unit->Type->ResInfo[c]) {
+		units_unassigned[num_units_unassigned[c]++][c]=unit;
+	    }
+#if 0
 	    UnitType** types;
 
 	    //
@@ -1329,6 +1050,7 @@ local void AiCollectResources(void)
 	    if( j<tn ) {
 		break;
 	    }
+#endif
 	}
     }
 
@@ -1418,7 +1140,7 @@ local void AiCollectResources(void)
 			    int n1;
 			    int n2;
 			    case GoldCost:
-				if( (unit->Orders[0].Action==UnitActionResource&&unit->Type->ResourceHarvested==GoldCost) || AiMineGold(unit) ) {
+				if( (unit->Orders[0].Action==UnitActionResource&&unit->CurrentResource==GoldCost) || AiMineGold(unit) ) {
 				    DebugLevel3Fn("Assigned to gold\n");
 				    units_assigned[num_units_assigned[c]++][c]=unit;
     				    units_unassigned[i][c] = units_unassigned[--num_units_unassigned[c]][c];
@@ -1434,7 +1156,7 @@ local void AiCollectResources(void)
 				}
 				break;
 			    case WoodCost:
-				if( unit->Orders[0].Action==UnitActionHarvest || AiHarvest(unit) ) {
+				if( (unit->Orders[0].Action==UnitActionResource&&unit->CurrentResource==WoodCost) || AiHarvest(unit) ) {
 				    DebugLevel3Fn("Assigned to harvest\n");
 				    units_assigned[num_units_assigned[c]++][c]=unit;
     				    units_unassigned[i][c] = units_unassigned[--num_units_unassigned[c]][c];
@@ -1450,7 +1172,7 @@ local void AiCollectResources(void)
 				}
 				break;
 			    case OilCost:
-				if( (unit->Orders[0].Action==UnitActionResource&&unit->Type->ResourceHarvested==OilCost) || AiHaulOil(unit) ) {
+				if( (unit->Orders[0].Action==UnitActionResource&&unit->CurrentResource==OilCost) || AiHaulOil(unit) ) {
 				    DebugLevel3Fn("Assigned to oil\n");
 				    units_assigned[num_units_assigned[c]++][c]=unit;
     				    units_unassigned[i][c] = units_unassigned[--num_units_unassigned[c]][c];
diff --git a/src/include/actions.h b/src/include/actions.h
index 0f25d6184..b30115b2b 100644
--- a/src/include/actions.h
+++ b/src/include/actions.h
@@ -100,8 +100,8 @@ extern void CommandUnload(Unit* unit,int x,int y,Unit* what,int flush);
 extern void CommandBuildBuilding(Unit*,int,int,UnitType*,int);
     /// Prepare command cancel build
 extern void CommandCancelBuilding(Unit* unit,Unit* worker);
-    /// Prepare command harvest
-extern void CommandHarvest(Unit* unit,int x,int y,int flush);
+    /// Prepare command resource location
+extern void CommandResourceLoc(Unit* unit,int x,int y,int flush);
     /// Prepare command resource
 extern void CommandResource(Unit* unit,Unit* dest,int flush);
     /// Prepare command return
@@ -160,9 +160,7 @@ extern void HandleActionAttack(Unit* unit);
 extern void HandleActionBoard(Unit* unit);
     /// Handle command unload
 extern void HandleActionUnload(Unit* unit);
-    /// Handle command harvest
-extern void HandleActionHarvest(Unit* unit);
-    /// Handle command haul
+    /// Handle command resource
 extern void HandleActionResource(Unit* unit);
     /// Handle command return
 extern void HandleActionReturnGoods(Unit* unit);
diff --git a/src/include/commands.h b/src/include/commands.h
index 7537cf27c..868717ae6 100644
--- a/src/include/commands.h
+++ b/src/include/commands.h
@@ -98,9 +98,9 @@ extern void SendCommandUnload(Unit* unit,int x,int y,Unit* what,int flush);
 extern void SendCommandBuildBuilding(Unit*,int,int,UnitType*,int);
     /// Send cancel building command
 extern void SendCommandCancelBuilding(Unit* unit,Unit* peon);
+    /// Send harvest location command
+extern void SendCommandResourceLoc(Unit* unit,int x,int y,int flush);
     /// Send harvest command
-extern void SendCommandHarvest(Unit* unit,int x,int y,int flush);
-    /// Send haul oil command
 extern void SendCommandResource(Unit* unit,Unit* dest,int flush);
     /// Send return goods command
 extern void SendCommandReturnGoods(Unit* unit,Unit* dest,int flush);
diff --git a/src/include/iolib.h b/src/include/iolib.h
index 8521378f7..1e0d007d3 100644
--- a/src/include/iolib.h
+++ b/src/include/iolib.h
@@ -47,6 +47,7 @@
 #include <bzlib.h>
 #undef DrawIcon
 #undef EndMenu
+#undef FindResource
 #endif
 
 #ifdef USE_ZZIPLIB
diff --git a/src/include/network.h b/src/include/network.h
index 6a3a75f14..b92b315cb 100644
--- a/src/include/network.h
+++ b/src/include/network.h
@@ -83,9 +83,8 @@ enum _message_type_ {
     MessageCommandUnload,		/// Unit command unload
     MessageCommandBuild,		/// Unit command build building
     MessageCommandCancelBuild,		/// Unit command cancel building
-    MessageCommandHarvest,		/// Unit command harvest
-    MessageCommandMine,			/// Unit command mine gold
-    MessageCommandResource,		/// Unit command haul oil
+    MessageCommandResourceLoc,		/// Unit command resource location
+    MessageCommandResource,		/// Unit command resource
     MessageCommandReturn,		/// Unit command return goods
     MessageCommandTrain,		/// Unit command train
     MessageCommandCancelTrain,		/// Unit command cancel training
diff --git a/src/include/stratagus.h b/src/include/stratagus.h
index 986ad2e67..cc9889675 100644
--- a/src/include/stratagus.h
+++ b/src/include/stratagus.h
@@ -139,6 +139,7 @@
 #pragma warning(disable:4244)		// Conversion from double to uchar
 #pragma warning(disable:4761)		// Integral size mismatch
 #define snprintf _snprintf		/// Unix -> dumm
+#define vsnprintf _vsnprintf
 #include <string.h>
 #define strdup _strdup
 #define strncasecmp strnicmp
@@ -531,21 +532,8 @@ extern long isqrt(long num);
     /// bits macro
 #define BitsOf(n)	(sizeof(n)*8)
 
-    // FIXME: more config stuff which needs a better place
-
-    /// How long stay in a gold-mine
-#define MINE_FOR_GOLD	(150/SpeedResourcesHarvest[GoldCost])
-    /// How long stay in a gold-deposit
-#define WAIT_FOR_GOLD	(150/SpeedResourcesReturn[GoldCost])
-    /// How much I must chop for 1 wood
-#define CHOP_FOR_WOOD	(52/SpeedResourcesHarvest[WoodCost])
-    /// How long stay in a wood-deposit
-#define WAIT_FOR_WOOD	(100/SpeedResourcesReturn[WoodCost])
-    /// How long stay in a oil-well
-#define HAUL_FOR_OIL	(100/SpeedResourcesHarvest[OilCost])
-    /// How long stay in a oil-deposit
-#define WAIT_FOR_OIL	(100/SpeedResourcesReturn[OilCost])
-
+// 	FIXME: configurable. maybe we could move it into one big global
+// 	FIXME: settings struct?
     /// How many resource get the player back if canceling building
 #define CancelBuildingCostsFactor	75
     /// How many resource get the player back if canceling training
diff --git a/src/include/unit.h b/src/include/unit.h
index f3cbc415c..3729e1da2 100644
--- a/src/include/unit.h
+++ b/src/include/unit.h
@@ -420,7 +420,6 @@ enum _unit_action_ {
     UnitActionBuild,			/// unit builds building
 
     UnitActionRepair,			/// unit repairing
-    UnitActionHarvest,			/// unit harvest lumber
     UnitActionResource,			/// unit harvesting resources
     UnitActionReturnGoods,		/// unit returning any resource
 
@@ -568,6 +567,7 @@ struct _unit_ {
 					** ,used for fancy buildings
 					*/
     unsigned	Rs : 8;
+    unsigned	CurrentResource;
 
 #define MAX_ORDERS 16			/// How many outstanding orders?
     char	OrderCount;		/// how many orders in queue
@@ -595,6 +595,7 @@ struct _unit_ {
     }		Resource;		/// Resource still
     struct _order_resource_worker_ {
 	int	TimeToHarvest;		/// how much time until we harvest some more.
+	unsigned DoneHarvesting:1;	/// Harvesting done, wait for action to break.
     }		ResWorker;		/// Worker harvesting
     struct _order_research_ {
 	Upgrade* Upgrade;		/// Upgrade researched
@@ -819,12 +820,15 @@ extern int CanBuildOn(int x,int y,int mask);
 extern int CanBuildUnitType(const Unit* unit,const UnitType* type,int x,int y);
 
     /// Find resource
-extern Unit* FindResource(const Player* player,int x,int y,int resource);
+extern Unit* FindResource(const Unit* unit,int x,int y,int range);
     /// Find nearest deposit
-extern Unit* FindDeposit(const Player*,int x,int y,int resource);
+extern Unit* FindDeposit(const Unit* unit,int x,int y,int range);
     /// Find the next idle worker
 extern Unit* FindIdleWorker(const Player* player,const Unit* last);
 
+    /// Find the neareast piece of terrain with specific flags.	
+extern int FindTerrainType(int movemask,int resmask,int rvresult,int range,
+	const Player *player,int x,int y,int* px,int* py);
     /// Find the nearest piece of wood in sight range
 extern int FindWoodInSight(const Unit* unit,int* x,int* y);
 
diff --git a/src/include/unittype.h b/src/include/unittype.h
index eab368881..157221437 100644
--- a/src/include/unittype.h
+++ b/src/include/unittype.h
@@ -38,7 +38,7 @@
 ----------------------------------------------------------------------------*/
 
 /**
-**	@struct _unit_type_ unittype.h
+** 	@struct _unit_type_ unittype.h
 **
 **	\#include "unittype.h"
 **
@@ -328,54 +328,17 @@
 **
 **		Resource can be harvested. It's false for things like
 **		oil patches.
+**		FIXME: crappy name.
 **
 **	UnitType::Harvester
 **
-**		Unit is a resource worker.
+**		Unit is a resource worker. Faster than examining ResInfo
 **
-**	UnitType::HarvestFromOutside
 **
-**		Unit will harvest from the outside. The unit will use it's
-**		Attack animation (seems it turned into a generic Action anim.)
+**	UnitType::ResInfo[::MaxCosts]
 **
-**      UnitType::ResourceHarvested
-**
-**		The resource it can harvest. Needs Harvester flag. An unit
-**		can't harvest more than one type of resource.
-**		FIXME: implement something like TransformForOtherResource.
-**
-**	UnitType::WaitAtResource
-**
-**		Cycles the unit waits while inside a resource.
-**
-**	UnitType::ResourceStep
-**
-**		The unit makes so-caled mining cycles. Each mining cycle
-**		it does some sort of animation and gains ResourceStep
-**		resources. You can stop after any number of steps.
-**		when the quantity in the harvester reaches the maximum
-**		(ResourceCapacity) it will return home. I this is 0 then
-**		it's considered infinity, and ResourceCapacity will now
-**		be the limit.
-**
-**	UnitType::ResourceCapacity
-**
-**		Maximum amount of resources a harvester can carry. The
-**		actual amount can be modified while unloading.
-**
-**	UnitType::WaitAtDepot
-**
-**		Cycles the unit waits while inside the depot to unload.
-**
-**	UnitType::TransformWhenEmpty;
-**	
-**		The harvester will transform into another unit when it is
-**		empty. FIXME: just change the animation.
-**
-**	UnitType::TransformWhenLoaded
-**
-**		The harvester will transform into another unit when it is
-**		loaded. FIXME: just change the animation.
+**		Information about resource harvesting. If NULL, it can't
+**		harvest it.
 **
 **	UnitType::MustBuildOnTop
 **
@@ -520,6 +483,73 @@
 **
 **		Sprite images of the player colors.  This image is drawn
 **		over UnitType::Sprite.  Used with OpenGL only.
+**
+**
+**
+** 	@struct _resource_info_ unittype.h
+**
+** 	\#include "unittype.h"
+**
+** 	typedef struct _unit_type_ UnitType;
+**
+** 	This struct contains information about how a unit will harvest a
+** 	resource.
+**
+**	ResourceInfo::FileWhenLoaded
+**
+**		The harvester's animation file will change when it's loaded.
+**
+**	ResourceInfo::FileWhenEmpty;
+**	
+**		The harvester's animation file will change when it's empty.
+**		The standard animation is used only when building/repairing.
+**
+**
+**	ResourceInfo::HarvestFromOutside
+**
+**		Unit will harvest from the outside. The unit will use it's
+**		Attack animation (seems it turned into a generic Action anim.)
+**
+**      ResourceInfo::ResourceId
+**
+**		The resource this is for. Mostly redundant.
+**
+**	ResourceInfo::FinalResource
+**
+**		The resource is converted to this at the depot. Usefull for
+**		a fisherman who harvests fish, but it all turns to food at the
+**		depot.
+**
+**	ResourceInfo::WaitAtResource
+**
+**		Cycles the unit waits while inside a resource.
+**
+**	ResourceInfo::ResourceStep
+**
+**		The unit makes so-caled mining cycles. Each mining cycle
+**		it does some sort of animation and gains ResourceStep
+**		resources. You can stop after any number of steps.
+**		when the quantity in the harvester reaches the maximum
+**		(ResourceCapacity) it will return home. I this is 0 then
+**		it's considered infinity, and ResourceCapacity will now
+**		be the limit.
+**
+**	ResourceInfo::ResourceCapacity
+**
+**		Maximum amount of resources a harvester can carry. The
+**		actual amount can be modified while unloading.
+**
+**	ResourceInfo::WaitAtDepot
+**
+**		Cycles the unit waits while inside the depot to unload.
+**
+**	ResourceInfo::TerrainHarvester
+**
+**		The unit will harvest terrain. For now this only works
+**		for wood. maybe it could be made to work for rocks, but
+**		more than that requires a tileset rewrite.
+**		FIXME: more configurable.
+**
 */
 
 /*----------------------------------------------------------------------------
@@ -584,6 +614,23 @@ typedef struct _missile_config_ {
     MissileType*Missile;		/// Identifier to use to run time
 } MissileConfig;
 
+typedef struct _resource_info_ {
+    char * 	FileWhenLoaded;			/// Change the graphic when the unit is loaded.
+    char * 	FileWhenEmpty;			/// Change the graphic when the unit is empty.
+    unsigned 	HarvestFromOutside;		/// Unit harvests without entering the building.
+    unsigned 	WaitAtResource;			/// Cycles the unit waits while mining.
+    unsigned 	ResourceStep;			/// Resources the unit gains per mining cycle.
+    unsigned 	ResourceCapacity;		/// Max amount of resources to carry.
+    unsigned 	WaitAtDepot;			/// Cycles the unit waits while returning.
+    unsigned	ResourceId;			/// Id of the resource harvested. Redundant.
+    unsigned 	FinalResource;			/// Convert resource when delivered. 
+    unsigned 	TerrainHarvester;		/// Unit will harvest terrain(wood only for now).
+    unsigned	LoseResources;			/// The unit will lose it's resource when distracted.
+    //  Runtime info:
+    Graphic *   SpriteWhenLoaded;		/// The graphic corresponding to FileWhenLoaded.
+    Graphic *   SpriteWhenEmpty;		/// The graphic corresponding to FileWhenEmpty
+} ResourceInfo;
+
 /**
 **	Typedef of base structure of unit-type
 */
@@ -664,6 +711,7 @@ struct _unit_type_ {
 #define CanTargetSea	2			/// Can attack sea units
 #define CanTargetAir	4			/// Can attack air units
 
+    unsigned EquivType : 1;		/// 
     unsigned Revealer : 1;		/// reveal the fog of war
     unsigned LandUnit : 1;		/// Land animated
     unsigned AirUnit : 1;		/// Air animated
@@ -692,20 +740,13 @@ struct _unit_type_ {
     unsigned Hero : 1;			/// Is hero only used for triggers .
     unsigned Volatile : 1;		/// Invisiblity/unholy armor kills unit.
     unsigned Organic : 1;		/// Organic can be healed.
-    
+
     unsigned CanStore[MaxCosts];	/// Resources that we can store here.
     unsigned GivesResource;		/// The resource this unit gives.
     unsigned MaxWorkers;		/// Maximum number of workers.
     unsigned CanHarvest : 1;		/// Resource can be harvested.
-    unsigned Harvester : 1;		/// Unit is a resource worker.
-    unsigned HarvestFromOutside;	/// Unit harvests without entering the building.
-    unsigned ResourceHarvested;		/// The resource it can harvest.
-    unsigned WaitAtResource;		/// Cycles the unit waits while mining.
-    unsigned ResourceStep;		/// Resources the unit gains per mining cycle.
-    unsigned ResourceCapacity;		/// Max amount of resources to carry.
-    unsigned WaitAtDepot;		/// Cycles the unit waits while returning.
-    UnitType* TransformWhenEmpty;	/// UnitType to transform to when empty.
-    UnitType* TransformWhenLoaded;	/// UnitType to transform to when loaded.
+    unsigned Harvester : 1;		/// unit is a resource harvester.
+    ResourceInfo* ResInfo[MaxCosts];	/// Resource information.
     UnitType* MustBuildOnTop;		/// Must be built on top of something.
 
     unsigned SelectableByRectangle : 1;	/// Selectable with mouse rectangle.
@@ -756,10 +797,6 @@ extern UnitType* UnitTypes[UnitTypeMax];	/// All unit-types
 extern int NumUnitTypes;			/// Number of unit-types made
 
 // FIXME: this hardcoded unit-types must be removed!!
-extern UnitType*UnitTypeHumanWorker;		/// Human worker
-extern UnitType*UnitTypeOrcWorker;		/// Orc worker
-extern UnitType*UnitTypeHumanWorkerWithWood;	/// Human worker with wood
-extern UnitType*UnitTypeOrcWorkerWithWood;	/// Orc worker with wood
 extern UnitType*UnitTypeHumanWall;		/// Human wall
 extern UnitType*UnitTypeOrcWall;		/// Orc wall
 extern UnitType*UnitTypeCritter;		/// Critter unit-type pointer
diff --git a/src/map/map.cpp b/src/map/map.cpp
index 6e6bfb4f5..ff98a9f01 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -307,14 +307,14 @@ global int CheckedForestOnMap(int tx,int ty)
 */
 global int ForestOnMap(int tx,int ty)
 {
-    IfDebug(
-	if( tx<0 || ty<0 || tx>=TheMap.Width || ty>=TheMap.Height ) {
-	    // FIXME: must cleanup calling function !
-	    fprintf(stderr,"Used x %d, y %d\n",tx,ty);
-	    abort();
-	    return 0;
-	}
-    );
+#ifdef DEBUG
+    if( tx<0 || ty<0 || tx>=TheMap.Width || ty>=TheMap.Height ) {
+	// FIXME: must cleanup calling function !
+	fprintf(stderr,"Used x %d, y %d\n",tx,ty);
+	abort();
+	return 0;
+    }
+#endif
 
     return TheMap.Fields[tx+ty*TheMap.Width].Flags&MapFieldForest;
 }
diff --git a/src/map/minimap.cpp b/src/map/minimap.cpp
index d1ec7e5fd..9e0d796b1 100644
--- a/src/map/minimap.cpp
+++ b/src/map/minimap.cpp
@@ -301,7 +301,7 @@ global void UpdateMinimap(void)
 	    if( (*table)->Player->Player==PlayerNumNeutral ) {
 		if( type->Critter ) {
 		    color=ColorNPC;
-		} else if( type->OilPatch ) {
+		} else if( type->GivesResource==OilCost ) {
 		    color=ColorBlack;
 		} else {
 		    color=ColorYellow;
diff --git a/src/network/commands.cpp b/src/network/commands.cpp
index e57709679..7aab3503b 100644
--- a/src/network/commands.cpp
+++ b/src/network/commands.cpp
@@ -561,8 +561,8 @@ local void DoNextReplay(void)
 	SendCommandBuildBuilding(UnitSlots[unit],posx,posy,UnitTypeByIdent(val),flags);
     } else if( !strcmp(name,"cancel-build") ) {
 	SendCommandCancelBuilding(UnitSlots[unit],dunit);
-    } else if( !strcmp(name,"harvest") ) {
-	SendCommandHarvest(UnitSlots[unit],posx,posy,flags);
+    } else if( !strcmp(name,"resource-loc") ) {
+	SendCommandResourceLoc(UnitSlots[unit],posx,posy,flags);
     } else if( !strcmp(name,"resource") ) {
 	SendCommandResource(UnitSlots[unit],dunit,flags);
     } else if( !strcmp(name,"return") ) {
@@ -902,20 +902,20 @@ global void SendCommandCancelBuilding(Unit* unit,Unit* worker)
 }
 
 /**
-**	Send command: Unit harvest wood.
+** 	Send command: Unit harvests a location (wood for now).
 **
 **	@param unit	pointer to unit.
 **	@param x	X map tile position where to harvest.
 **	@param y	Y map tile position where to harvest.
 **	@param flush	Flag flush all pending commands.
 */
-global void SendCommandHarvest(Unit* unit,int x,int y,int flush)
+global void SendCommandResourceLoc(Unit* unit,int x,int y,int flush)
 {
     if( NetworkFildes==-1 ) {
-	CommandLog("harvest",unit,flush,x,y,NoUnitP,NULL,-1);
-	CommandHarvest(unit,x,y,flush);
+	CommandLog("resource-loc",unit,flush,x,y,NoUnitP,NULL,-1);
+	CommandResourceLoc(unit,x,y,flush);
     } else {
-	NetworkSendCommand(MessageCommandHarvest,unit,x,y,NoUnitP,0,flush);
+	NetworkSendCommand(MessageCommandResourceLoc,unit,x,y,NoUnitP,0,flush);
     }
 }
 
@@ -923,7 +923,7 @@ global void SendCommandHarvest(Unit* unit,int x,int y,int flush)
 **	Send command: Unit harvest resources
 **
 **	@param unit	pointer to unit.
-**	@param dest	pointer to destination (oil-platform).
+**	@param dest	pointer to destination (oil-platform,gold mine).
 **	@param flush	Flag flush all pending commands.
 */
 global void SendCommandResource(Unit* unit,Unit* dest,int flush)
@@ -1308,9 +1308,9 @@ global void ParseCommand(unsigned char msgnr,UnitRef unum,
 	    CommandLog("cancel-build",unit,FlushCommands,-1,-1,dest,NULL,-1);
 	    CommandCancelBuilding(unit,dest);
 	    break;
-	case MessageCommandHarvest:
-	    CommandLog("harvest",unit,status,x,y,NoUnitP,NULL,-1);
-	    CommandHarvest(unit,x,y,status);
+	case MessageCommandResourceLoc:
+	    CommandLog("resource-loc",unit,status,x,y,NoUnitP,NULL,-1);
+	    CommandResourceLoc(unit,x,y,status);
 	    break;
 	case MessageCommandResource:
 	    dest=NoUnitP;
diff --git a/src/sound/sound.cpp b/src/sound/sound.cpp
index 98abced61..162bb3a05 100644
--- a/src/sound/sound.cpp
+++ b/src/sound/sound.cpp
@@ -181,9 +181,7 @@ local SoundId ChooseUnitVoiceSoundId(const Unit *unit,UnitVoiceGroup voice)
 	return GameSounds.TreeChopping.Sound;
     case VoiceWorkCompleted:
 	// FIXME: make this more configurable
-	if (unit->Type==UnitTypeHumanWorker) {
-	    return GameSounds.PeasantWorkComplete.Sound;
-	} else if( ThisPlayer->Race==PlayerRaceHuman ) {
+	if( ThisPlayer->Race==PlayerRaceHuman ) {
 	    return GameSounds.HumanWorkComplete.Sound;
 	} else {
 	    return GameSounds.OrcWorkComplete.Sound;
diff --git a/src/stratagus/stratagus.cpp b/src/stratagus/stratagus.cpp
index b9bcc05a9..dc6d53919 100644
--- a/src/stratagus/stratagus.cpp
+++ b/src/stratagus/stratagus.cpp
@@ -989,11 +989,7 @@ global void ShowLoadProgress(const char* fmt,...)
     char* s;
 
     va_start(va,fmt);
-#ifdef USE_WIN32
-    vsprintf(temp,fmt,va);
-#else
     vsnprintf(temp,sizeof(temp),fmt,va);
-#endif
     va_end(va);
 
     if( VideoDepth && IsFontLoaded(GameFont) ) {
diff --git a/src/ui/botpanel.cpp b/src/ui/botpanel.cpp
index 4e9292bbe..555a8b2b2 100644
--- a/src/ui/botpanel.cpp
+++ b/src/ui/botpanel.cpp
@@ -594,9 +594,7 @@ global void DrawButtonPanel(void)
 		    case ButtonHarvest:
 		    case ButtonReturn:
 			for( j=0; j<NumSelected; ++j ) {
-			    if( Selected[j]->Orders[0].Action!=UnitActionResource
-				    && Selected[j]->Orders[0].Action
-					!=UnitActionHarvest ) {
+			    if( Selected[j]->Orders[0].Action!=UnitActionResource ) {
 				break;
 			    }
 			}
diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp
index ba8b8978a..a67a3a48f 100644
--- a/src/ui/interface.cpp
+++ b/src/ui/interface.cpp
@@ -1082,7 +1082,7 @@ global int HandleCheats(const char* Input)
 	    if( !ThisPlayer->Ai ) {
 	    	AiInit( ThisPlayer );
 	    }
-	    SetMessage("I'm an AI Now :)");
+	    SetMessage("I'm the BORG, resistance is futile!");
 	}
 #endif
     } else {
diff --git a/src/ui/mainscr.cpp b/src/ui/mainscr.cpp
index bf747cd36..bc5a6fd1f 100644
--- a/src/ui/mainscr.cpp
+++ b/src/ui/mainscr.cpp
@@ -521,17 +521,22 @@ global void DrawUnitInfo(const Unit* unit)
 	VideoDrawText(x+63,y+8+125,GameFont,"Speed:");
 	DrawStats(x+108,y+8+125,stats->Speed,type->_Speed);
 
-        // Show how much wood is harvested already in percents! :) //vladi
-	// FIXME: Make this optional
-        if( unit->Orders[0].Action==UnitActionHarvest && unit->SubAction==64 ) {
-	    sprintf(buf,"Wood: %d%%"
-		    ,(100*(CHOP_FOR_WOOD-unit->Value))/CHOP_FOR_WOOD);
-	    VideoDrawText(x+63,y+8+141,GameFont,buf);
-        }
 	// FIXME: Ugly hack.
-	if( unit->Type->Harvester&&unit->Value&&unit->Orders[0].Action!=UnitActionHarvest ) {
+	if( unit->Type->Harvester&&unit->Value) {
 	    sprintf(buf,"Carry: %d %s",unit->Value,
-		    DefaultResourceNames[unit->Type->ResourceHarvested]);
+		    DefaultResourceNames[unit->CurrentResource]);
+	    VideoDrawText(x+61,y+8+141,GameFont,buf);	    
+	}
+	if ((unit->Type->Harvester)&&
+		(unit->Orders->Action==UnitActionResource)&&
+		(unit->CurrentResource)&&
+		(unit->Type->ResInfo[unit->CurrentResource]) &&
+		(unit->SubAction==60) &&
+		(!unit->Type->ResInfo[unit->CurrentResource]->ResourceStep)) {
+	    sprintf(buf,"%s: %d%%",DefaultResourceNames[unit->CurrentResource],
+		    100*(unit->Type->ResInfo[unit->CurrentResource]->WaitAtResource-
+			unit->Data.ResWorker.TimeToHarvest)/
+			unit->Type->ResInfo[unit->CurrentResource]->WaitAtResource);
 	    VideoDrawText(x+61,y+8+141,GameFont,buf);	    
 	}
 
diff --git a/src/ui/menu_proc.cpp b/src/ui/menu_proc.cpp
index c410fcdf0..9c54783a6 100644
--- a/src/ui/menu_proc.cpp
+++ b/src/ui/menu_proc.cpp
@@ -40,12 +40,10 @@
 
 #include "stratagus.h"
 
-#if defined(USE_OPENGL) && defined(_MSC_VER)
+#if defined(_MSC_VER)
 #undef NOUSER
-#include "video.h"
-#else
-#include "video.h"
 #endif
+#include "video.h"
 #include "font.h"
 #include "interface.h"
 #include "menus.h"
diff --git a/src/ui/mouse.cpp b/src/ui/mouse.cpp
index 1fbe404e1..428b04e50 100644
--- a/src/ui/mouse.cpp
+++ b/src/ui/mouse.cpp
@@ -111,6 +111,7 @@ global void DoRightButton(int sx,int sy)
     int action;
     int acknowledged;
     int flush;
+    int res;
 
     //
     // No unit selected
@@ -196,41 +197,45 @@ global void DoRightButton(int sx,int sy)
 	//	Handle resource workers.
 	//
 	if( action==MouseActionHarvest ) {
-	    //	Return wood cutter home
-	    if( (type==UnitTypeOrcWorkerWithWood ||
-		    type==UnitTypeHumanWorkerWithWood) &&
-		    dest && dest->Type->CanStore[WoodCost] &&
-		    dest->Player==unit->Player) {
-		DebugLevel3("send to wood deposit.\n");
-		dest->Blink=4;
-		SendCommandReturnGoods(unit,dest,flush);
-		continue;
-	    }
-	    //	Send wood cutter to work
-	    if((type==UnitTypeOrcWorker||type==UnitTypeHumanWorker) &&
-		    IsMapFieldExplored(unit->Player,x,y) &&
-		    ForestOnMap(x,y) ) {
-		SendCommandHarvest(unit,x,y,flush);
-		continue;
-	    }
-	    if (unit->Type->Harvester && dest) {
-		//  Return a loaded harvester to deposit
-		if( unit->Value>0 &&
-			dest->Type->CanStore[unit->Type->ResourceHarvested] &&
-			dest->Player==unit->Player) {
-		    dest->Blink=4;
-		    DebugLevel3Fn("Return to deposit.\n");
-		    SendCommandReturnGoods(unit,dest,flush);
-		    continue;
-		} 
-		//  Go and harvest
-		if( (unit->Value<unit->Type->ResourceCapacity) &&
-			dest->Type->GivesResource==unit->Type->ResourceHarvested &&
-			(dest->Player==unit->Player ||
-			 dest->Player->Player==PlayerMax-1)) {
-		    dest->Blink=4;
-		    SendCommandResource(unit,dest,flush);
-		    continue;
+	    if (unit->Type->Harvester) {
+		if ( dest ) {
+		    //  Return a loaded harvester to deposit
+		    if( (unit->Value>0) &&
+			    (dest->Type->CanStore[unit->CurrentResource])&&
+			    (dest->Player==unit->Player) ) {
+			dest->Blink=4;
+			DebugLevel3Fn("Return to deposit.\n");
+			SendCommandReturnGoods(unit,dest,flush);
+			continue;
+		    } 
+		    //  Go and harvest from an building
+		    if( (res=dest->Type->GivesResource) &&
+			    (unit->Type->ResInfo[res]) &&
+			    (unit->Value<unit->Type->ResInfo[res]->ResourceCapacity) &&
+			    (dest->Type->CanHarvest) &&
+			    (dest->Player==unit->Player ||
+			        (dest->Player->Player==PlayerMax-1)) ) {
+			dest->Blink=4;
+			SendCommandResource(unit,dest,flush);
+			continue;
+		    }
+		} else {
+		    // FIXME: support harvesting more types of terrain.
+		    for (res=0;res<MaxCosts;res++) {
+			if ( (unit->Type->ResInfo[res]) &&
+				(unit->Type->ResInfo[res]->TerrainHarvester) && 
+				(IsMapFieldExplored(unit->Player,x,y)) &&
+				(ForestOnMap(x,y)) &&
+				((unit->CurrentResource!=res)||
+				(unit->Value<unit->Type->ResInfo[res]->ResourceCapacity))) {
+			    DebugLevel3("Sent worker to cut wood.\n");
+			    SendCommandResourceLoc(unit,x,y,flush);
+			    break;
+			}
+		    }
+		    if (res!=MaxCosts) {
+			continue;
+		    }
 		}
 	    }
 	    //  Go and repair
@@ -358,7 +363,7 @@ global void DoRightButton(int sx,int sy)
 	    }
 	    if( IsMapFieldExplored(unit->Player,x,y) && ForestOnMap(x,y) ) {
                 DebugLevel3("RALY POINT TO FOREST\n");                
-	        SendCommandHarvest(Selected[i],x,y,!(KeyModifiers&ModifierShift));
+	        SendCommandResourceLoc(Selected[i],x,y,!(KeyModifiers&ModifierShift));
                 continue;
             }
 	    SendCommandMove(unit,x,y,flush);
@@ -945,23 +950,31 @@ local void SendDemolish(int sx,int sy)
 **
 **	@see Selected
 */
-local void SendHarvest(int sx,int sy)
+local void SendResource(int sx,int sy)
 {
     int i;
+    int res;
     Unit* dest;
 
     for( i=0; i<NumSelected; ++i ) {
-	DebugCheck(!Selected[i]->Type->Harvester);
 	if ((dest=UnitUnderCursor) &&
-		(Selected[i]->Type->ResourceHarvested==dest->Type->GivesResource)) {
+		(Selected[i]->Type->Harvester) &&
+		(res=dest->Type->GivesResource) &&
+		(Selected[i]->Type->ResInfo[res])) {
 	    dest->Blink=4;
 	    DebugLevel3("RESOURCE\n");
 	    SendCommandResource(Selected[i],dest,!(KeyModifiers&ModifierShift));
 	    continue;
 	}
-	if( IsMapFieldExplored(Selected[i]->Player,sx/TileSizeX,sy/TileSizeY) &&
-		ForestOnMap(sx/TileSizeX,sy/TileSizeY) ) {
-	    SendCommandHarvest(Selected[i],sx/TileSizeY,sy/TileSizeY,!(KeyModifiers&ModifierShift));
+	for (res=0;res<MaxCosts;res++) {
+	    if( Selected[i]->Type->Harvester &&
+		    Selected[i]->Type->ResInfo[res] &&
+		    Selected[i]->Type->ResInfo[res]->TerrainHarvester &&
+		    IsMapFieldExplored(Selected[i]->Player,sx/TileSizeX,sy/TileSizeY) &&
+		    ForestOnMap(sx/TileSizeX,sy/TileSizeY) ) {
+		DebugLevel3("RESOURCE\n");
+		SendCommandResourceLoc(Selected[i],sx/TileSizeY,sy/TileSizeY,!(KeyModifiers&ModifierShift));
+	    }
 	}
     }
 }
@@ -1070,7 +1083,7 @@ local void SendCommand(int sx, int sy)
 	    SendPatrol(sx,sy);
 	    break;
 	case ButtonHarvest:
-	    SendHarvest(sx,sy);
+	    SendResource(sx,sy);
 	    break;
 	case ButtonUnload:
 	    SendUnload(sx,sy);
diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp
index aff70a46b..fb34b0cb2 100644
--- a/src/unit/script_unit.cpp
+++ b/src/unit/script_unit.cpp
@@ -58,6 +58,8 @@
 
     /// Get unit-type.
 extern UnitType* CclGetUnitType(SCM ptr);
+    /// Get resource by name
+extern unsigned CclGetResourceByName(SCM ptr);
 
 /**
 **	Set hit-point regeneration
@@ -209,8 +211,6 @@ local void CclParseOrder(SCM list,Order* order)
 	    order->Action=UnitActionBuild;
 	} else if( gh_eq_p(value,gh_symbol2scm("action-repair")) ) {
 	    order->Action=UnitActionRepair;
-	} else if( gh_eq_p(value,gh_symbol2scm("action-harvest")) ) {
-	    order->Action=UnitActionHarvest;
 	} else if( gh_eq_p(value,gh_symbol2scm("action-resource")) ) {
 	    order->Action=UnitActionResource;
 	} else if( gh_eq_p(value,gh_symbol2scm("action-return-goods")) ) {
@@ -366,6 +366,29 @@ local void CclParseBuilded(Unit* unit, SCM list)
     }
 }
 
+/**
+**	Parse res worker data
+**
+**	@param unit	Unit pointer which should be filled with the data.
+**	@param list	All options of the resource worker data.
+*/
+local void CclParseResWorker(Unit* unit, SCM list)
+{
+    SCM value;
+
+    while (!gh_null_p(list)) {
+	value = gh_car(list);
+	list = gh_cdr(list);
+	if (gh_eq_p(value, gh_symbol2scm("time-to-harvest"))) {
+	    unit->Data.ResWorker.TimeToHarvest = gh_scm2int(gh_car(list));
+	    list = gh_cdr(list);
+	} else if (gh_eq_p(value, gh_symbol2scm("done-harvesting"))) {
+	    unit->Data.ResWorker.DoneHarvesting = 1;
+	    list = gh_cdr(list);
+	}
+    }
+}
+
 /**
 **	Parse research
 **
@@ -681,6 +704,9 @@ local SCM CclUnit(SCM list)
 	} else if( gh_eq_p(value,gh_symbol2scm("value")) ) {
 	    unit->Value=gh_scm2int(gh_car(list));
 	    list=gh_cdr(list);
+	} else if( gh_eq_p(value,gh_symbol2scm("current-resource")) ) {
+	    unit->CurrentResource=CclGetResourceByName(gh_car(list));
+	    list=gh_cdr(list);
 	} else if( gh_eq_p(value,gh_symbol2scm("sub-action")) ) {
 	    unit->SubAction=gh_scm2int(gh_car(list));
 	    list=gh_cdr(list);
@@ -761,6 +787,10 @@ local SCM CclUnit(SCM list)
 	    sublist=gh_car(list);
 	    list=gh_cdr(list);
 	    CclParseBuilded(unit,sublist);
+	} else if( gh_eq_p(value,gh_symbol2scm("data-res-worker")) ) {
+	    sublist=gh_car(list);
+	    list=gh_cdr(list);
+	    CclParseResWorker(unit,sublist);
 	} else if( gh_eq_p(value,gh_symbol2scm("data-research")) ) {
 	    sublist=gh_car(list);
 	    list=gh_cdr(list);
diff --git a/src/unit/script_unittype.cpp b/src/unit/script_unittype.cpp
index d5cec1b6d..da3b94d4e 100644
--- a/src/unit/script_unittype.cpp
+++ b/src/unit/script_unittype.cpp
@@ -71,7 +71,7 @@ local ccl_smob_type_t SiodUnitTypeTag;		/// siod unit-type object
 ** 	@param value	SCM thingie
 **	@return 	the resource id
 */
-local unsigned CclGetResourceByName(SCM value)
+global unsigned CclGetResourceByName(SCM value)
 {
     int i;
     for( i=0; i<MaxCosts; ++i ) {
@@ -96,6 +96,7 @@ local SCM CclDefineUnitType(SCM list)
     SCM sublist;
     UnitType* type;
     UnitType* auxtype;
+    ResourceInfo* res;
     char* str;
     int i;
     int redefine;
@@ -271,7 +272,7 @@ local SCM CclDefineUnitType(SCM list)
 	    auxtype=UnitTypeByIdent(str);
 	    if (!auxtype) {
 		DebugLevel0("Build on top of undefined unit \"%s\".\n" _C_ str);
-		exit(0);
+		DebugCheck(1);
 	    }
 	    type->MustBuildOnTop=auxtype;
 	    free(str);
@@ -428,43 +429,55 @@ local SCM CclDefineUnitType(SCM list)
 	    type->Coward=1;
 	} else if( gh_eq_p(value,gh_symbol2scm("harvester")) ) {
 	    type->Harvester=1;
-	} else if( gh_eq_p(value,gh_symbol2scm("harvest-from-outside")) ) {
-	    type->HarvestFromOutside=1;
-	} else if( gh_eq_p(value,gh_symbol2scm("resource-step")) ) {
-	    type->ResourceStep=gh_scm2int(gh_car(list));
+	} else if( gh_eq_p(value,gh_symbol2scm("can-gather-resource")) ) {
+	    sublist=gh_car(list);
 	    list=gh_cdr(list);
-	} else if( gh_eq_p(value,gh_symbol2scm("resource-harvested")) ) {
-	    type->ResourceHarvested=CclGetResourceByName(gh_car(list));
-	    list=gh_cdr(list);
-	} else if( gh_eq_p(value,gh_symbol2scm("wait-at-resource")) ) {
-	    type->WaitAtResource=gh_scm2int(gh_car(list));
-	    list=gh_cdr(list);
-	} else if( gh_eq_p(value,gh_symbol2scm("wait-at-depot")) ) {
-	    type->WaitAtDepot=gh_scm2int(gh_car(list));
-	    list=gh_cdr(list);
-	} else if( gh_eq_p(value,gh_symbol2scm("resource-capacity")) ) {
-	    type->ResourceCapacity=gh_scm2int(gh_car(list));
-	    list=gh_cdr(list);
-	} else if( gh_eq_p(value,gh_symbol2scm("transform-when-empty")) ) {
-	    str=gh_scm2newstr(gh_car(list),NULL);
-	    auxtype=UnitTypeByIdent(str);
-	    if (!auxtype) {
-		DebugLevel0("Undefined unit \"%s\".\n" _C_ str);
-		exit(0);
+	    res=(ResourceInfo*)malloc(sizeof(ResourceInfo));
+	    memset(res,0,sizeof(ResourceInfo));
+	    while( !gh_null_p(sublist) ) {
+		value=gh_car(sublist);
+		sublist=gh_cdr(sublist);
+		if (gh_eq_p(value,gh_symbol2scm("resource-id")) ) {
+		    res->ResourceId=CclGetResourceByName(gh_car(sublist));
+		    type->ResInfo[res->ResourceId]=res;
+		    sublist=gh_cdr(sublist);
+		} else if( gh_eq_p(value,gh_symbol2scm("resource-step")) ) {
+		    res->ResourceStep=gh_scm2int(gh_car(sublist));
+		    sublist=gh_cdr(sublist);
+		} else if( gh_eq_p(value,gh_symbol2scm("final-resource")) ) {
+		    res->FinalResource=CclGetResourceByName(gh_car(sublist));
+		    sublist=gh_cdr(sublist);
+		} else if( gh_eq_p(value,gh_symbol2scm("wait-at-resource")) ) {
+		    res->WaitAtResource=gh_scm2int(gh_car(sublist));
+		    sublist=gh_cdr(sublist);
+		} else if( gh_eq_p(value,gh_symbol2scm("wait-at-depot")) ) {
+		    res->WaitAtDepot=gh_scm2int(gh_car(sublist));
+		    sublist=gh_cdr(sublist);
+		} else if( gh_eq_p(value,gh_symbol2scm("resource-capacity")) ) {
+		    res->ResourceCapacity=gh_scm2int(gh_car(sublist));
+		    sublist=gh_cdr(sublist);
+		} else if( gh_eq_p(value,gh_symbol2scm("terrain-harvester")) ) {
+		    res->TerrainHarvester=1;
+		} else if( gh_eq_p(value,gh_symbol2scm("lose-resources")) ) {
+		    res->LoseResources=1;
+		} else if( gh_eq_p(value,gh_symbol2scm("harvest-from-outside")) ) {
+		    res->HarvestFromOutside=1;
+		} else if( gh_eq_p(value,gh_symbol2scm("file-when-empty")) ) {
+		    res->FileWhenLoaded=gh_scm2newstr(gh_car(sublist),0);
+		    sublist=gh_cdr(sublist);
+		} else if( gh_eq_p(value,gh_symbol2scm("file-when-loaded")) ) {
+		    res->FileWhenLoaded=gh_scm2newstr(gh_car(sublist),0);
+		    sublist=gh_cdr(sublist);
+		} else {
+		   printf("\n%s\n",type->Name);
+		   errl("Unsupported tag",value);
+		   DebugCheck( 1 );
+		}
 	    }
-	    type->TransformWhenEmpty=auxtype;
-	    free(str);
-	    list=gh_cdr(list);
-	} else if( gh_eq_p(value,gh_symbol2scm("transform-when-loaded")) ) {
-	    str=gh_scm2newstr(gh_car(list),NULL);
-	    auxtype=UnitTypeByIdent(str);
-	    if (!auxtype) {
-		DebugLevel0("Undefined unit \"%s\".\n" _C_ str);
-		exit(0);
+	    if (!res->FinalResource) {
+		res->FinalResource=res->ResourceId;
 	    }
-	    type->TransformWhenLoaded=auxtype;
-	    free(str);
-	    list=gh_cdr(list);
+	    DebugCheck(!res->ResourceId);
 	} else if( gh_eq_p(value,gh_symbol2scm("gives-resource")) ) {
 	    type->GivesResource=CclGetResourceByName(gh_car(list));
 	    list=gh_cdr(list);
@@ -562,8 +575,8 @@ local SCM CclDefineUnitType(SCM list)
 	} else {
 	   // FIXME: this leaves a half initialized unit-type
 	   printf("\n%s\n",type->Name);
-	   DebugCheck( 1 );
 	   errl("Unsupported tag",value);
+	   DebugCheck( 1 );
 	}
     }
 
diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp
index f62940621..17fc1d14a 100644
--- a/src/unit/unit.cpp
+++ b/src/unit/unit.cpp
@@ -2462,15 +2462,152 @@ global int CanBuildUnitType(const Unit* unit,const UnitType* type,int x,int y)
   ----------------------------------------------------------------------------*/
 
 /**
- **	Find wood in sight range.
+ **	Find the closest piece of wood for an unit.
  **
- **	@param unit	Unit that needs wood.
- **	@param px	OUT: Map X position of wood.
- **	@param py	OUT: Map Y position of wood.
+ **	@param unit	The unit.
+ **	@param x	OUT: Map X position of tile.
+ **	@param y	OUT: Map Y position of tile.
+ */
+global int FindWoodInSight(const Unit* unit,int* x,int* y)
+{
+    return FindTerrainType(UnitMovementMask(unit),0,MapFieldForest,9999,
+	    unit->Player,unit->X,unit->Y,x,y);
+}
+
+/**
+ **	Find the closest piece of terrain with the given flags.
+ **
+ **	@param movemask	The movement mask to reach that location. 
+ **	@param resmask	Result tile mask.
+ **	@param rvresult Return a tile that doesn't match. 
+ **	@param range	Maximum distance for the search.
+ **	@param player	Only search fields explored by player
+ **	@param x	Map X start position for the search.
+ **	@param y	Map Y start position for the search.
+ **
+ **	@param px	OUT: Map X position of tile.
+ **	@param py	OUT: Map Y position of tile.
+ **
+ **	@notes		Movement mask can be 0xFFFFFFFF to have no effect
+ **			Range is not circular, but square.
+ **			Player is ignored if nil(search the entire map)
+ **			Use rvresult if you search for a til;e that doesn't
+ **			match resmask. Like for a tile where an unit can go
+ **			with it's movement mask.
  **
  **	@return		True if wood was found.
  */
-global int FindWoodInSight(const Unit* unit,int* px,int* py)
+global int FindTerrainType(int movemask,int resmask,int rvresult,int range,
+	const Player *player,int x,int y,int* px,int* py)
+{
+    static const int xoffset[]={  0,-1,+1, 0, -1,+1,-1,+1 };
+    static const int yoffset[]={ -1, 0, 0,+1, -1,-1,+1,+1 };
+    struct {
+	unsigned short X;
+	unsigned short Y;
+    } * points;
+    int size;
+    int rx;
+    int ry;
+    int wp;
+    int rp;
+    int ep;
+    int i;
+    int w;
+    unsigned char* m;
+    unsigned char* matrix;
+    int destx;
+    int desty;
+    int cdist;
+
+    destx=x;
+    desty=y;
+    size=min(TheMap.Width*TheMap.Height/4,range*range*5);
+    points=malloc(size*sizeof(*points));
+
+    //	Make movement matrix. FIXME: can create smaller matrix.
+    matrix=CreateMatrix();
+    w=TheMap.Width+2;
+    matrix+=w+w+2;
+    points[0].X=x;
+    points[0].Y=y;
+    rp=0;
+    matrix[x+y*w]=1;			// mark start point
+    ep=wp=1;				// start with one point
+    cdist=0;				// current distance is 0
+
+    //
+    //	Pop a point from stack, push all neighbors which could be entered.
+    //
+    for( ;; ) {
+	while( rp!=ep ) {
+	    rx=points[rp].X;
+	    ry=points[rp].Y;
+	    DebugLevel3("%d,%d\n" _C_ rx _C_ ry);
+	    for( i=0; i<8; ++i ) {		// mark all neighbors
+		x=rx+xoffset[i];
+		y=ry+yoffset[i];
+		//  Make sure we don't leave the map.
+		if (x<0||y<0||x>=TheMap.Width||y>=TheMap.Height) {
+		    continue; 
+		}
+		m=matrix+x+y*w;
+		//  Check if visited or unexplored
+		if( *m || (player&&!IsMapFieldExplored(player,x,y))) {
+		    continue;
+		}
+		//	Look if found what was required.
+		if ( rvresult?CanMoveToMask(x,y,resmask):!CanMoveToMask(x,y,resmask) ) {
+		    *px=x;
+		    *py=y;
+		    DebugLevel3("Found it! %X %X\n" _C_ TheMap.Fields[x+y*TheMap.Width].Flags _C_ resmask);
+		    return 1;
+		}
+		if( CanMoveToMask(x,y,movemask) ) {	// reachable
+		    *m=1;
+		    points[wp].X=x;		// push the point
+		    points[wp].Y=y;
+		    if( ++wp>=size ) {		// round about
+			wp=0;
+		    }
+		    if (wp==ep) {
+			//  We are out of points, give up!
+			DebugLevel0Fn("Ran out of points the hard way, beware.\n");
+			break;
+		    }
+		} else {			// unreachable
+		    *m=99;
+		}
+	    }
+	    if( ++rp>=size ) {			// round about
+		rp=0;
+	    }
+	}
+	cdist++;
+	if( rp==wp||cdist>=range ) {			// unreachable, no more points available
+	    break;
+	}
+	//	Continue with next set.
+	ep=wp;
+    }
+    free(points);
+    return 0;
+}
+
+/**
+ **	Find Resource.
+ **
+ **	@param unit	The unit that wants to find a resource.
+ **	@param x	Closest to x
+ **	@param x	Closest to y
+ **	@param range    Maximum distance to the resource.
+ **
+ **	@notes 		This will return an usable resource building that
+ **			belongs to "player" or is neutral.
+ **
+ **	@return		NoUnitP or resource unit
+ */
+global Unit* FindResource(const Unit * unit,int x,int y,int range)
 {
     static const int xoffset[]={  0,-1,+1, 0, -1,+1,-1,+1 };
     static const int yoffset[]={ -1, 0, 0,+1, -1,-1,+1,+1 };
@@ -2479,8 +2616,6 @@ global int FindWoodInSight(const Unit* unit,int* px,int* py)
 	unsigned short Y;
     } * points;
     int size;
-    int x;
-    int y;
     int rx;
     int ry;
     int mask;
@@ -2493,80 +2628,42 @@ global int FindWoodInSight(const Unit* unit,int* px,int* py)
     unsigned char* m;
     unsigned char* matrix;
     const Unit* destu;
+    Unit* mine;
+    Unit* bestmine;
     int destx;
     int desty;
-    int bestx;
-    int besty;
     int bestd;
+    int cdist;
+    int resource;
 
-    destx=x=unit->X;
-    desty=y=unit->Y;
-    size=TheMap.Width*TheMap.Height/4;
+    resource=unit->CurrentResource;
+
+    destx=x;
+    desty=y;
+    size=min(TheMap.Width*TheMap.Height/4,range*range*5);
     points=malloc(size*sizeof(*points));
 
-    //
-    //	Find the nearest wood depot
-    //
-    if( (destu=FindDeposit(unit->Player,x,y,WoodCost)) ) {
+    //	Find the nearest gold depot
+    if( (destu=FindDeposit(unit,x,y,range)) ) {
 	NearestOfUnit(destu,x,y,&destx,&desty);
     }
     bestd=99999;
-    IfDebug( bestx=besty=0; );		// keep the compiler happy
-
-    //
     //	Make movement matrix. FIXME: can create smaller matrix.
-    //
     matrix=CreateMatrix();
     w=TheMap.Width+2;
     matrix+=w+w+2;
-
-    //
-    //	Mark sight range as border. FIXME: matrix didn't need to be bigger.
-    //
-    n=unit->Stats->SightRange;
-    rx=x-n;
-    if( rx<0 ) {
-	rx=0;
-    }
-    ep=x+n;
-    if( ep>TheMap.Width ) {
-	ep=TheMap.Width;
-    }
-    ry=y-n;
-    if( ry<0 ) {
-	ry=0;
-    }
-    wp=y+n;
-    if( wp>TheMap.Height ) {
-	wp=TheMap.Height;
-    }
-    for( i=rx; i<ep; ++i ) {		// top bottom line
-	matrix[i+ry*w]=matrix[i+wp*w]=66;
-    }
-    for( i=ry+1; i<wp-1; ++i ) {
-	matrix[rx+i*w]=matrix[ep+i*w]=66;
-    }
-
-#if 0
-    matrix[x+n+(y+n)*w]=matrix[x-n+(y+n)*w]=
-	matrix[x+n+(y-n)*w]=matrix[x-n+(y-n)*w]=66;
-    for( i=n; i--; ) {
-	// FIXME: marks out of map area
-	DebugCheck( x-i+(y-n)*w<0 || x+i+(y+n)*w>w*TheMap.Hight );
-	matrix[x+n+(y+i)*w]=matrix[x-n+(y+i)*w]=
-	    matrix[x+n+(y-i)*w]=matrix[x-n+(y-i)*w]=
-	    matrix[x-i+(y+n)*w]=matrix[x+i+(y+n)*w]=
-	    matrix[x-i+(y-n)*w]=matrix[x+i+(y-n)*w]=66;
-    }
-#endif
-
+    //  Unit movement mask
     mask=UnitMovementMask(unit);
-
+    //  Ignore all units along the way. Might seem wierd, but otherwise
+    //  peasants would lock at a mine with a lot of workers.
+    mask&=~(MapFieldLandUnit|MapFieldSeaUnit|MapFieldAirUnit);
     points[0].X=x;
     points[0].Y=y;
     rp=0;
     matrix[x+y*w]=1;			// mark start point
     ep=wp=1;				// start with one point
+    cdist=0;				// current distance is 0
+    bestmine=NoUnitP;
 
     //
     //	Pop a point from stack, push all neighbors which could be entered.
@@ -2583,23 +2680,28 @@ global int FindWoodInSight(const Unit* unit,int* px,int* py)
 		    continue;
 		}
 
+		if (!IsMapFieldExplored(unit->Player,x,y)) { // Unknown.
+		    continue;
+		}
+
 		//
-		//	Look if there is wood
+		//	Look if there is a mine
 		//
-		if ( ForestOnMap(x,y) && IsMapFieldExplored(unit->Player,x,y) ) {
+		if ((mine=ResourceOnMap(x,y,resource))&&
+			(mine->Type->CanHarvest)&&
+			((mine->Player->Player==PlayerMax-1)||
+			(mine->Player==unit->Player)||
+			(IsAllied(unit->Player,mine)))) {
 		    if( destu ) {
 			n=max(abs(destx-x),abs(desty-y));
 			if( n<bestd ) {
 			    bestd=n;
-			    bestx=x;
-			    besty=y;
+			    bestmine=mine;
 			}
-			*m=22;
+			*m=99;
 		    } else {			// no goal take the first
-			*px=x;
-			*py=y;
 			free(points);
-			return 1;
+			return mine;
 		    }
 		}
 
@@ -2610,6 +2712,10 @@ global int FindWoodInSight(const Unit* unit,int* px,int* py)
 		    if( ++wp>=size ) {		// round about
 			wp=0;
 		    }
+		    if (wp==ep) {
+			//  We are out of points, give up!
+			break;
+		    }
 		} else {			// unreachable
 		    *m=99;
 		}
@@ -2618,138 +2724,141 @@ global int FindWoodInSight(const Unit* unit,int* px,int* py)
 		rp=0;
 	    }
 	}
-
-	//
 	//	Take best of this frame, if any.
-	//
 	if( bestd!=99999 ) {
-	    *px=bestx;
-	    *py=besty;
 	    free(points);
-	    return 1;
+	    return bestmine;
 	}
-
-	//
-	//	Continue with next frame.
-	//
-	if( rp==wp ) {			// unreachable, no more points available
+	cdist++;
+	if( rp==wp||cdist>=range ) {			// unreachable, no more points available
 	    break;
 	}
+	//	Continue with next set.
 	ep=wp;
     }
-
-    DebugLevel3Fn("no wood in sight-range\n");
-
+    DebugLevel3Fn("no resource found\n");
     free(points);
-    return 0;
-}
-
-/**
- **	Find Resource.
- **
- **	@param player	The player that wants to find a resource.
- **	@param x	Nearest to X position.
- **	@param y	Nearest to Y position
- **	@param resource	The ID of the resource.
- **
- **	@notes 		This will return an usable resource building that
- **			belongs to "player" or is neutral.
- **
- **	@return		NoUnitP or oil platform unit
- */
-global Unit* FindResource(const Player* player,int x,int y,int resource)
-{
-    Unit* unit;
-    Unit* best;
-    Unit** units;
-    int nunits;
-    int best_d;
-    int d;
-    int i;
-    int pnum;
-
-    //	FIXME:	this is not the best one
-    //		We need the deposit with the shortest way!
-    //		At least it must be reachable!
-
-    best=NoUnitP;
-    best_d=99999;
-    for (pnum=0;pnum<PlayerMax;++pnum) {
-	// FIXME: allow harvesting from ally
-	if ( (pnum!=PlayerMax-1) && (pnum!=player->Player) ) {
-	    continue;
-	}
-	nunits=Players[pnum].TotalNumUnits;
-	units=Players[pnum].Units;
-	for( i=0; i<nunits; i++ ) {
-	    unit=units[i];
-	    if( UnitUnusable(unit) || !unit->Type->CanHarvest ) {
-		continue;
-	    }
-	    // Want platform
-	    if( unit->Type->GivesResource==resource ) {
-		d=MapDistanceToUnit(x,y,unit);
-		if( d<best_d ) {
-		    best_d=d;
-		    best=unit;
-		}
-	    }
-	}
-    }
-
-    DebugLevel3Fn("%d %d,%d\n" _C_ best?UnitNumber(best):-1 _C_
-	    best?best->X:-1 _C_ best?best->Y:-1);
-    return best;
+    return NoUnitP;
 }
 
 /**
  **	Find deposit. This will find a deposit for a resource 
  **
- **	@param player   The player the deposit must belong to.
- **	@param x	Nearest to X position.
- **	@param y	Nearest to Y position.
- **	@param resource The resource you need the deposit to hold.
+ **	@param unit	The unit that wants to find a resource.
+ **	@param x	Closest to x
+ **	@param x	Closest to y
+ **	@param range    Maximum distance to the deposit.
+ **
+ **	@notes		This will return a reachable allied depot.
  **
  **	@return		NoUnitP or oil deposit unit
  */
-global Unit* FindDeposit(const Player* player,int x,int y,int resource)
+global Unit* FindDeposit(const Unit* unit,int x,int y,int range)
 {
-    Unit* unit;
-    Unit* best;
-    Unit** units;
-    int nunits;
-    int best_d;
-    int d,i;
+    static const int xoffset[]={  0,-1,+1, 0, -1,+1,-1,+1 };
+    static const int yoffset[]={ -1, 0, 0,+1, -1,-1,+1,+1 };
+    struct {
+	unsigned short X;
+	unsigned short Y;
+    } * points;
+    int size;
+    int rx;
+    int ry;
+    int mask;
+    int wp;
+    int rp;
+    int ep;
+    int i;
+    int w;
+    unsigned char* m;
+    unsigned char* matrix;
+    Unit* depot;
+    int destx;
+    int desty;
+    int cdist;
+    int resource;
+
+    resource=unit->CurrentResource;
+
+    destx=x;
+    desty=y;
+    size=min(TheMap.Width*TheMap.Height/4,range*range*5);
+    points=malloc(size*sizeof(*points));
+
+    //	Make movement matrix. FIXME: can create smaller matrix.
+    matrix=CreateMatrix();
+    w=TheMap.Width+2;
+    matrix+=w+w+2;
+    //  Unit movement mask
+    mask=UnitMovementMask(unit);
+    //  Ignore all units along the way. Might seem wierd, but otherwise
+    //  peasants would lock at a mine with a lot of workers.
+    mask&=~(MapFieldLandUnit|MapFieldSeaUnit|MapFieldAirUnit);
+    points[0].X=x;
+    points[0].Y=y;
+    rp=0;
+    matrix[x+y*w]=1;			// mark start point
+    ep=wp=1;				// start with one point
+    cdist=0;				// current distance is 0
 
-    //	FIXME:	this is not the best one
-    //		We need the deposit with the shortest way!
-    //		At least it must be reachable!
-    //	FIXME:	Could we use unit-cache to find it faster?
     //
-
-    best=NoUnitP;
-    best_d=INT_MAX;
-    nunits=player->TotalNumUnits;
-    units=player->Units;
-    for( i=0; i<nunits; i++ ) {
-	unit=units[i];
-	if( UnitUnusable(unit) ) {
-	    continue;
-	}
-	if( unit->Type->CanStore[resource] ) {
-	    d=MapDistanceToUnit(x,y,unit);
-	    if( d<best_d
-		    // FIXME: UnitReachable didn't work with unit inside
-		    /*&& (d=UnitReachable(source,unit,1)) && d<best_d*/ ) {
-		best_d=d;
-		best=unit;
+    //	Pop a point from stack, push all neighbors which could be entered.
+    //
+    for( ;; ) {
+	while( rp!=ep ) {
+	    rx=points[rp].X;
+	    ry=points[rp].Y;
+	    for( i=0; i<8; ++i ) {		// mark all neighbors
+		x=rx+xoffset[i];
+		y=ry+yoffset[i];
+		//  Make sure we don't leave the map.
+		if (x<0||y<0||x>=TheMap.Width||y>=TheMap.Height) {
+		    continue; 
+		}
+		m=matrix+x+y*w;
+		//  Check if visited or unexplored
+		if( *m || !IsMapFieldExplored(unit->Player,x,y)) {
+		    continue;
+		}
+		//
+		//	Look if there is a mine
+		//
+		if ((depot=ResourceDepositOnMap(x,y,resource))&&
+			((IsAllied(unit->Player,depot)) ||
+			(unit->Player==depot->Player))) {
+		    free(points);
+		    return depot;
+		}
+		if( CanMoveToMask(x,y,mask) ) {	// reachable
+		    *m=1;
+		    points[wp].X=x;		// push the point
+		    points[wp].Y=y;
+		    if( ++wp>=size ) {		// round about
+			wp=0;
+		    }
+		    if (wp==ep) {
+			//  We are out of points, give up!
+			DebugLevel0Fn("Ran out of points the hard way, beware.\n");
+			break;
+		    }
+		} else {			// unreachable
+		    *m=99;
+		}
+	    }
+	    if( ++rp>=size ) {			// round about
+		rp=0;
 	    }
 	}
+	cdist++;
+	if( rp==wp||cdist>=range ) {			// unreachable, no more points available
+	    break;
+	}
+	//	Continue with next set.
+	ep=wp;
     }
-
-    DebugLevel3Fn("%d %d,%d\n" _C_ best?UnitNumber(best):-1 _C_
-	    best?best->X:-1 _C_ best?best->Y:-1);
-    return best;
+    DebugLevel3Fn("no resource deposit found\n");
+    free(points);
+    return NoUnitP;
 }
 
 /**
@@ -3146,14 +3255,14 @@ global void HitUnit(Unit* attacker,Unit* target,int damage)
     }
 #endif
 
+    // FIXME: this is dumb. I made repairers capture. crap.
     // david: capture enemy buildings
     // Only worker types can capture.
     // Still possible to destroy building if not careful (too many attackers)
     if( EnableBuildingCapture && attacker
 	    && type->Building && target->HP<=damage*3
 	    && IsEnemy(attacker->Player,target)
-	    && (attacker->Type==UnitTypeOrcWorker
-		|| attacker->Type==UnitTypeHumanWorker) ) {
+	    && attacker->Type->RepairRange ) {
 	ChangeUnitOwner(target,attacker->Player);
 	CommandStopUnit(attacker);	// Attacker shouldn't continue attack!
     }
@@ -3558,9 +3667,6 @@ local void SaveOrder(const Order* order,CLFile* file)
 	case UnitActionRepair:
 	    CLprintf(file,"action-repair");
 	    break;
-	case UnitActionHarvest:
-	    CLprintf(file,"action-harvest");
-	    break;
 	case UnitActionResource:
 	    CLprintf(file,"action-resource");
 	    break;
@@ -3731,6 +3837,9 @@ global void SaveUnit(const Unit* unit,CLFile* file)
     CLprintf(file,"'last-group %d\n  ",unit->LastGroup);
 
     CLprintf(file,"'value %d\n  ",unit->Value);
+    if (unit->CurrentResource) {
+	CLprintf(file,"'current-resource '%s\n  ",DefaultResourceNames[unit->CurrentResource]);
+    }
 
     CLprintf(file,"'sub-action %d ",unit->SubAction);
     CLprintf(file,"'wait %d ",unit->Wait);
@@ -3775,6 +3884,13 @@ global void SaveUnit(const Unit* unit,CLFile* file)
 		CLprintf(file," 'resource-active %d",unit->Data.Resource.Active);
 	    }
 	    break;
+	case UnitActionResource:
+	    CLprintf(file," 'data-res-worker '(time-to-harvest %d",unit->Data.ResWorker.TimeToHarvest);
+	    if (unit->Data.ResWorker.DoneHarvesting) {
+		CLprintf(file," done-harvesting");
+	    }
+	    CLprintf(file,")");
+	    break;
 	case UnitActionBuilded:
 	    {
 		ConstructionFrame* cframe;
diff --git a/src/unit/unit_draw.cpp b/src/unit/unit_draw.cpp
index db09912a9..c4627dcf9 100644
--- a/src/unit/unit_draw.cpp
+++ b/src/unit/unit_draw.cpp
@@ -965,13 +965,12 @@ local void DrawDecoration(const Unit* unit,const UnitType* type,int x,int y)
 			,unit->Data.UpgradeTo.Ticks);
 
 	    //
-	    //	Chopping wood.
+	    //	Carry resource.
+	    //	Don't display if empty.
 	    //
-	    } else if( unit->Orders[0].Action==UnitActionHarvest
-		    && unit->SubAction==64 ) {
-		DrawManaBar(x,y,type,CHOP_FOR_WOOD,
-			unit->Value>CHOP_FOR_WOOD?
-			    0:CHOP_FOR_WOOD-unit->Value);
+	    } else if( unit->Type->Harvester&&unit->CurrentResource&&unit->Value>0 ) {
+		DrawManaBar(x,y,type,unit->Type->ResInfo[unit->CurrentResource]->ResourceCapacity,
+			unit->Value);
 
 	    //
 	    //	Building research new technologie.
@@ -1031,15 +1030,13 @@ local void DrawDecoration(const Unit* unit,const UnitType* type,int x,int y)
 		DrawManaSprite(x,y,type,unit->Orders[0].Type
 			    ->Stats[unit->Player->Player].Costs[TimeCost]
 			,unit->Data.UpgradeTo.Ticks);
-
+		
 	    //
-	    //	Chopping wood.
+	    //	Carry resource.
 	    //
-	    } else if( unit->Orders[0].Action==UnitActionHarvest
-		    && unit->SubAction==64 ) {
-		DrawManaSprite(x,y,type,CHOP_FOR_WOOD,
-			unit->Value>CHOP_FOR_WOOD?
-			    0:CHOP_FOR_WOOD-unit->Value);
+	    } else if( unit->Type->Harvester&&unit->CurrentResource&&unit->Value>0 ) {
+		DrawManaSprite(x,y,type,unit->Type->ResInfo[unit->CurrentResource]->ResourceCapacity,
+			unit->Value);
 
 	    //
 	    //	Building research new technologie.
@@ -1492,11 +1489,6 @@ local void ShowSingleOrder(const Unit* unit, int x1, int y1, const Order* order)
 	    e_color = color = ColorGray;
 	    break;
 
-	case UnitActionHarvest:
-	    e_color = color = ColorYellow;
-	    dest = 1;
-	    break;
-
 	case UnitActionResource:
 	    e_color = color = ColorYellow;
 	    dest = 1;
@@ -1839,6 +1831,8 @@ global void DrawUnit(const Unit* unit)
 {
     int x;
     int y;
+    Graphic* Sprite;
+    ResourceInfo* resinfo;
     const UnitType* type;
 
     if ( unit->Type->Revealer ) {		// Revealers are not drawn
@@ -1859,13 +1853,35 @@ global void DrawUnit(const Unit* unit)
     DrawUnitSelection(unit);
 
     GraphicUnitPixels(unit,type->Sprite);
-    DrawUnitType(type,unit->Frame,x,y);
+
+    Sprite=type->Sprite;
+    if (type->Harvester && unit->CurrentResource) {
+	resinfo=type->ResInfo[unit->CurrentResource];
+	if (unit->Value) {
+	    if (resinfo->SpriteWhenLoaded) {
+		Sprite=resinfo->SpriteWhenLoaded;
+	    }
+	} else {
+	    if (resinfo->SpriteWhenEmpty) {
+		Sprite=resinfo->SpriteWhenEmpty;
+	    }
+	}
+    }
+    if( unit->Frame<0 ) {
+	VideoDrawClipX(Sprite,-unit->Frame,
+		x-(type->Width-type->TileWidth*TileSizeX)/2,
+		y-(type->Height-type->TileHeight*TileSizeY)/2);
+    } else {
+	VideoDrawClip(Sprite,unit->Frame,
+		x-(type->Width-type->TileWidth*TileSizeX)/2,
+		y-(type->Height-type->TileHeight*TileSizeY)/2);
+    }
 #ifdef USE_OPENGL
     DrawUnitPlayerColor(type,unit->Player->Player,unit->Frame,x,y);
 #endif
 
 #ifndef NEW_DECODRAW
-// Unit's extras not fully supported.. need to be deocrations themselves.
+// Unit's extras not fully supported.. need to be decorations themselves.
     DrawInformations(unit,type,x,y);
 #endif
 }
diff --git a/src/unit/unit_find.cpp b/src/unit/unit_find.cpp
index ca4d344d5..906860497 100644
--- a/src/unit/unit_find.cpp
+++ b/src/unit/unit_find.cpp
@@ -417,7 +417,7 @@ global Unit* ResourceOnMap(int tx,int ty,int resource)
 
     n=SelectUnitsOnTile(tx,ty,table);
     for( i=0; i<n; ++i ) {
-	if( UnitUnusable(table[i]) || !table[i]->Type->CanHarvest ){
+	if( UnitUnusable(table[i]) || !table[i]->Type->CanHarvest || table[i]->Value==0) {
 	    continue;
 	}
 	if( table[i]->Type->GivesResource==resource ) {
diff --git a/src/unit/unittype.cpp b/src/unit/unittype.cpp
index 43fe4dfad..920fa03a3 100644
--- a/src/unit/unittype.cpp
+++ b/src/unit/unittype.cpp
@@ -76,10 +76,6 @@ global int NumUnitTypes;			/// number of unit-types made
 **
 **	FIXME: find a way to make it configurable!
 */
-global UnitType*UnitTypeHumanWorker;		/// Human worker
-global UnitType*UnitTypeOrcWorker;		/// Orc worker
-global UnitType*UnitTypeHumanWorkerWithWood;	/// Human worker with wood
-global UnitType*UnitTypeOrcWorkerWithWood;	/// Orc worker with wood
 global UnitType*UnitTypeHumanWall;		/// Human wall
 global UnitType*UnitTypeOrcWall;		/// Orc wall
 global UnitType*UnitTypeCritter;		/// Critter unit type pointer
@@ -453,8 +449,13 @@ global void ParsePudUDTA(const char* udta,int length __attribute__((unused)))
 	// Cowards
 	unittype->Coward=BIT(8,v)|BIT(26,v);
 	if (BIT(9,v)) {
-	    unittype->Harvester=1;
-	    unittype->ResourceHarvested=OilCost;
+	    unittype->ResInfo[OilCost]=(ResourceInfo*)malloc(sizeof(ResourceInfo));
+	    memset(unittype->ResInfo[OilCost],0,sizeof(ResourceInfo));
+	    unittype->ResInfo[OilCost]->ResourceId=OilCost;
+	    unittype->ResInfo[OilCost]->FinalResource=OilCost;
+	    unittype->ResInfo[OilCost]->WaitAtResource=150;
+	    unittype->ResInfo[OilCost]->WaitAtDepot=150;
+	    unittype->ResInfo[OilCost]->ResourceCapacity=100;
 	}
 	unittype->Transporter=BIT(10,v);
 	unittype->CanStore[GoldCost]=BIT(12,v);
@@ -645,6 +646,7 @@ local void SaveUnitType(CLFile* file,const UnitType* type,int all)
 {
     int i;
     int flag;
+    ResourceInfo* res;
 
     CLprintf(file,"(define-unit-type '%s",type->Ident);
     CLprintf(file," 'name \"%s\"\n  ",type->Name);
@@ -905,36 +907,53 @@ local void SaveUnitType(CLFile* file,const UnitType* type,int all)
     if( type->Coward ) {
 	CLprintf(file,"  'coward\n");
     }
+    
     if( type->Harvester ) {
-	CLprintf(file,"  'harvester 'resource-harvested '%s\n",DefaultResourceNames[type->ResourceHarvested]);
-    }
-    if( type->HarvestFromOutside ) {
-	CLprintf(file,"  'harvest-from-outside\n");
-    }
-    if ( type->WaitAtResource ) {
-	CLprintf(file,"  'wait-at-resource %d\n",type->WaitAtResource);
-    }
-    if ( type->WaitAtDepot ) {
-	CLprintf(file,"  'wait-at-depot %d\n",type->WaitAtDepot);
-    }
-    if ( type->ResourceCapacity ) {
-        CLprintf(file,"  'resource-capacity %d\n",type->ResourceCapacity);
-    }
-    if ( type->TransformWhenEmpty ) {
-	CLprintf(file,"  'transform-when-empty '%s\n",type->TransformWhenEmpty->Ident);
-    }
-    if ( type->TransformWhenLoaded ) {
-	CLprintf(file,"  'transform-when-loaded '%s\n",type->TransformWhenLoaded->Ident);
+	CLprintf(file,"  'harvester\n");
+	for (i=0;i<MaxCosts;i++) {
+	    if (type->ResInfo[i]) {
+		res=type->ResInfo[i];
+		CLprintf(file,"  'can-gather-resource '(\n");
+		CLprintf(file,"        resource-id %s\n",DefaultResourceNames[res->ResourceId]);
+		CLprintf(file,"        final-resource %s\n",DefaultResourceNames[res->FinalResource]);
+		if( res->HarvestFromOutside ) {
+		    CLprintf(file,"        harvest-from-outside\n");
+		}
+		if ( res->WaitAtResource ) {
+		    CLprintf(file,"        wait-at-resource %d\n",res->WaitAtResource);
+		}
+		if ( res->WaitAtDepot ) {
+		    CLprintf(file,"        wait-at-depot %d\n",res->WaitAtDepot);
+		}
+		if ( res->ResourceCapacity ) {
+		    CLprintf(file,"        resource-capacity %d\n",res->ResourceCapacity);
+		}
+		if( res->ResourceStep ) {
+		    CLprintf(file,"        resource-step %d\n",res->ResourceStep);
+		}
+		if( res->TerrainHarvester ) {
+		    CLprintf(file,"        terrain-harvester\n");
+		}
+		if( res->LoseResources ) {
+		    CLprintf(file,"        lose-resources\n");
+		}
+		if ( res->FileWhenEmpty ) {
+		    CLprintf(file,"        file-when-empty %s\n",res->FileWhenEmpty);
+		}
+		if ( res->FileWhenLoaded ) {
+		    CLprintf(file,"        file-when-loaded %s\n",res->FileWhenLoaded);
+		}
+		CLprintf(file,"        )\n");
+	    }
+	}
     }
+
     if( type->GivesResource ) {
 	CLprintf(file,"  'gives-resource '%s\n",DefaultResourceNames[type->GivesResource]);
     }
     if( type->MaxWorkers ) {
 	CLprintf(file,"  'max-workers %d\n",type->MaxWorkers);
     }
-    if( type->ResourceStep ){
-	CLprintf(file,"  'resource-step %d\n",type->ResourceStep);
-    }
    
     // Save store info.
     for (flag=i=0;i<MaxCosts;i++)
@@ -1222,10 +1241,6 @@ global void InitUnitTypes(int reset_player_stats)
     //
     //	Setup hardcoded unit types. FIXME: should be moved to some configs.
     //
-    UnitTypeHumanWorker=UnitTypeByIdent("unit-peasant");
-    UnitTypeOrcWorker=UnitTypeByIdent("unit-peon");
-    UnitTypeHumanWorkerWithWood=UnitTypeByIdent("unit-peasant-with-wood");
-    UnitTypeOrcWorkerWithWood=UnitTypeByIdent("unit-peon-with-wood");
     UnitTypeHumanWall=UnitTypeByIdent("unit-human-wall");
     UnitTypeOrcWall=UnitTypeByIdent("unit-orc-wall");
     UnitTypeCritter=UnitTypeByIdent("unit-critter");
@@ -1239,18 +1254,37 @@ global void LoadUnitTypes(void)
 {
     UnitType* type;
     const char* file;
+    char buf[1000];
     int i;
+    int res;
+    ResourceInfo* resinfo;
 
     for( i=0; i<NumUnitTypes; ++i ) {
 	type=UnitTypes[i];
 	if( (file=type->ShadowFile) ) {
-	    char *buf;
-	    buf=alloca(strlen(file)+9+1);
 	    file=strcat(strcpy(buf,"graphics/"),file);
 	    ShowLoadProgress("\tUnit `%s'\n",file);
 	    type->ShadowSprite=LoadSprite(file,type->ShadowWidth,type->ShadowHeight);
 	}
 
+	//  Load empty/loaded graphics
+	if (type->Harvester) {
+	    for (res=0;res<MaxCosts;res++) {
+		if ((resinfo=type->ResInfo[res])) {
+		    if ((file=resinfo->FileWhenLoaded)) {
+			file=strcat(strcpy(buf,"graphics/"),file);
+			ShowLoadProgress("\tUnit `%s'\n",file);
+			resinfo->SpriteWhenLoaded=LoadSprite(file,type->Width,type->Height);
+		    }
+		    if ((file=resinfo->FileWhenEmpty)) {
+			file=strcat(strcpy(buf,"graphics/"),file);
+			ShowLoadProgress("\tUnit `%s'\n",file);
+			resinfo->SpriteWhenEmpty=LoadSprite(file,type->Width,type->Height);
+		    }
+		}
+	    }
+	}
+
 	//
 	//	Unit-type uses the same sprite as an other.
 	//
@@ -1310,9 +1344,6 @@ global void LoadUnitTypes(void)
 
 	// FIXME: should i copy the animations of same graphics?
     }
-
-    // FIXME: must copy unit data from peon/peasant to with gold/wood
-    // FIXME: must copy unit data from tanker to tanker full
 }
 
 /**
@@ -1324,6 +1355,7 @@ global void CleanUnitTypes(void)
     void** ptr;
     int i;
     int j;
+    int res;
     Animations* anims;
 
     DebugLevel0Fn("FIXME: icon, sounds not freed.\n");
@@ -1407,6 +1439,24 @@ global void CleanUnitTypes(void)
 	    free(type->CorpseName);
 	}
 
+	for (res=0;res<MaxCosts;res++) {
+	    if (type->ResInfo[res]) {
+		if (type->ResInfo[res]->SpriteWhenLoaded) {
+		    free (type->ResInfo[res]->SpriteWhenLoaded);
+		}
+		if (type->ResInfo[res]->SpriteWhenEmpty) {
+		    free (type->ResInfo[res]->SpriteWhenEmpty);
+		}
+		if (type->ResInfo[res]->FileWhenEmpty) {
+		    free (type->ResInfo[res]->FileWhenEmpty);
+		}
+		if (type->ResInfo[res]->FileWhenLoaded) {
+		    free (type->ResInfo[res]->FileWhenLoaded);
+		}
+		free (type->ResInfo[res]);
+	    }
+	}
+
 	//
 	//	FIXME: Sounds can't be freed, they still stuck in sound hash.
 	//
@@ -1445,10 +1495,6 @@ global void CleanUnitTypes(void)
     //
     //	Clean hardcoded unit types.
     //
-    UnitTypeHumanWorker=NULL;
-    UnitTypeOrcWorker=NULL;
-    UnitTypeHumanWorkerWithWood=NULL;
-    UnitTypeOrcWorkerWithWood=NULL;
     UnitTypeHumanWall=NULL;
     UnitTypeOrcWall=NULL;
     UnitTypeCritter=NULL;