Browse Source

September 24th Hotfix

Fixed some problematic harvester behavior
Implemented 10% build time reduction for Turkey
Neutral structures are capturable in multiplayer again (except for STRUCT_V01)
Other misc. fixes
PG-SteveT 5 years ago
parent
commit
7d496e8a63
40 changed files with 226 additions and 264 deletions
  1. 1 1
      CnCTDRAMapEditor.sln
  2. 1 1
      CnCTDRAMapEditor/Controls/BasicSettings.resx
  3. 1 1
      CnCTDRAMapEditor/Controls/BriefingSettings.resx
  4. 1 1
      CnCTDRAMapEditor/Controls/MapPanel.resx
  5. 1 1
      CnCTDRAMapEditor/Controls/ObjectProperties.resx
  6. 1 1
      CnCTDRAMapEditor/Controls/PlayerSettings.resx
  7. 1 1
      CnCTDRAMapEditor/Controls/TerrainProperties.resx
  8. 1 1
      CnCTDRAMapEditor/Dialogs/ErrorMessageBox.resx
  9. 1 1
      CnCTDRAMapEditor/Dialogs/InviteMessageBox.resx
  10. 1 1
      CnCTDRAMapEditor/Dialogs/MapSettingsDialog.resx
  11. 1 1
      CnCTDRAMapEditor/Dialogs/NewMapDialog.resx
  12. 1 1
      CnCTDRAMapEditor/Dialogs/SteamDialog.resx
  13. 1 1
      CnCTDRAMapEditor/Dialogs/TeamTypesDialog.resx
  14. 1 1
      CnCTDRAMapEditor/Dialogs/TriggersDialog.resx
  15. 1 1
      CnCTDRAMapEditor/MainForm.resx
  16. 1 1
      CnCTDRAMapEditor/Properties/Resources.resx
  17. 1 1
      CnCTDRAMapEditor/Properties/Settings.settings
  18. 1 1
      CnCTDRAMapEditor/Tools/Dialogs/CellTriggersToolDialog.resx
  19. 1 1
      CnCTDRAMapEditor/Tools/Dialogs/GenericToolDialog.resx
  20. 1 1
      CnCTDRAMapEditor/Tools/Dialogs/ObjectToolDialog.resx
  21. 1 1
      CnCTDRAMapEditor/Tools/Dialogs/ResourcesToolDialog.resx
  22. 1 1
      CnCTDRAMapEditor/Tools/Dialogs/TemplateToolDialog.resx
  23. 1 1
      CnCTDRAMapEditor/Tools/Dialogs/TerrainToolDialog.resx
  24. 1 1
      CnCTDRAMapEditor/Tools/Dialogs/WaypointsToolDialog.resx
  25. 27 1
      CnCTDRAMapEditor/Utility/INI.cs
  26. 1 1
      REDALERT/ANIM.CPP
  27. 3 1
      REDALERT/BUILDING.CPP
  28. 1 1
      REDALERT/MiscAsm.cpp
  29. 11 0
      REDALERT/TECHNO.CPP
  30. 66 109
      REDALERT/UNIT.CPP
  31. 2 2
      REDALERT/UNIT.H
  32. 1 1
      REDALERT/WIN32LIB/DrawMisc.cpp
  33. 16 7
      TIBERIANDAWN/AIRCRAFT.CPP
  34. 1 1
      TIBERIANDAWN/ANIM.CPP
  35. 0 3
      TIBERIANDAWN/BUILDING.CPP
  36. 1 1
      TIBERIANDAWN/MiscAsm.cpp
  37. 67 107
      TIBERIANDAWN/UNIT.CPP
  38. 3 3
      TIBERIANDAWN/UNIT.H
  39. 1 1
      TIBERIANDAWN/WIN32LIB/DrawMisc.cpp
  40. 1 1
      TIBERIANDAWN/WIN32LIB/FACINGFF.h

+ 1 - 1
CnCTDRAMapEditor.sln

@@ -1,4 +1,4 @@
-
+
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 15
 VisualStudioVersion = 15.0.28307.1022

+ 1 - 1
CnCTDRAMapEditor/Controls/BasicSettings.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Controls/BriefingSettings.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Controls/MapPanel.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Controls/ObjectProperties.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Controls/PlayerSettings.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Controls/TerrainProperties.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Dialogs/ErrorMessageBox.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Dialogs/InviteMessageBox.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Dialogs/MapSettingsDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Dialogs/NewMapDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Dialogs/SteamDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Dialogs/TeamTypesDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Dialogs/TriggersDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/MainForm.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Properties/Resources.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Properties/Settings.settings

@@ -1,4 +1,4 @@
-<?xml version='1.0' encoding='utf-8'?>
+<?xml version='1.0' encoding='utf-8'?>
 <SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="MobiusEditor.Properties" GeneratedClassName="Settings">
   <Profiles />
   <Settings>

+ 1 - 1
CnCTDRAMapEditor/Tools/Dialogs/CellTriggersToolDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Tools/Dialogs/GenericToolDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Tools/Dialogs/ObjectToolDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Tools/Dialogs/ResourcesToolDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Tools/Dialogs/TemplateToolDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Tools/Dialogs/TerrainToolDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 1 - 1
CnCTDRAMapEditor/Tools/Dialogs/WaypointsToolDialog.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 

+ 27 - 1
CnCTDRAMapEditor/Utility/INI.cs

@@ -533,7 +533,33 @@ namespace MobiusEditor.Utility
                     var converter = propertyDescriptors.Find(property.Name, false)?.Converter ?? TypeDescriptor.GetConverter(property.PropertyType);
                     if (converter.CanConvertFrom(context, typeof(string)))
                     {
-                        property.SetValue(data, converter.ConvertFromString(context, section[property.Name]));
+                        try
+                        {
+                            property.SetValue(data, converter.ConvertFromString(context, section[property.Name]));
+                        }
+                        catch (FormatException)
+                        {
+                            if (property.PropertyType == typeof(bool))
+                            {
+                                var value = section[property.Name].ToLower();
+                                if (value == "no")
+                                {
+                                    property.SetValue(data, false);
+                                }
+                                else if (value == "yes")
+                                {
+                                    property.SetValue(data, true);
+                                }
+                                else
+                                {
+                                    throw;
+                                }
+                            }
+                            else
+                            {
+                                throw;
+                            }
+                        }
                     }
                 }
             }

+ 1 - 1
REDALERT/ANIM.CPP

@@ -615,7 +615,7 @@ IsTheaterShape = false;
 	**	Check for a virtual animation
 	*/
 	if (Class->VirtualAnim != ANIM_NONE) {
-		AnimClass* virtual_anim = new AnimClass(Class->VirtualAnim, 0, timedelay, loop);
+		AnimClass* virtual_anim = new AnimClass(Class->VirtualAnim, Coord, timedelay, loop);
 		if (virtual_anim != NULL) {
 			virtual_anim->Make_Invisible();
 			VirtualAnimTarget = virtual_anim->As_Target();

+ 3 - 1
REDALERT/BUILDING.CPP

@@ -3463,7 +3463,9 @@ bool BuildingClass::Can_Capture(void) const
 
 	// Only allow capturing of multiplayer-owned structures
 	if (Session.Type != GAME_NORMAL) {
-		can_capture &= House->Class->House >= HOUSE_MULTI1 && House->Class->House <= HOUSE_MULTI8;
+		if (*this == STRUCT_V01) {		// Check to fix exploit in specific map 'Tournament Ore Rift'
+			can_capture = false;
+		}
 	}
 
 	return(can_capture);

+ 1 - 1
REDALERT/MiscAsm.cpp

@@ -428,7 +428,7 @@ dxisbig:
 #if (0)
 
 /*
-	; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/MiscAsm.cpp#131 $
+	; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/MiscAsm.cpp#138 $
 ;***************************************************************************
 ;**   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
 ;***************************************************************************

+ 11 - 0
REDALERT/TECHNO.CPP

@@ -6495,6 +6495,17 @@ int TechnoTypeClass::Time_To_Build(HousesType house) const
 		time *= hptr->BuildSpeedBias;
 	}
 	else {
+		
+		/*
+		** New feature - Turkey has a 10% build speed bonus even though it isn't specified in the rules
+		*/
+		if (hptr->ActLike == HOUSE_TURKEY) {
+			if (hptr->BuildSpeedBias == fixed(1)) {
+				time *= 9;
+				time /= 10;
+			}
+		}
+		
 		if (What_Am_I() == RTTI_BUILDINGTYPE || What_Am_I() == RTTI_INFANTRYTYPE) {
 			time *= hptr->BuildSpeedBias;
 		}

+ 66 - 109
REDALERT/UNIT.CPP

@@ -441,20 +441,6 @@ void UnitClass::AI(void)
 		IsHarvesting = false;
 	}
 
-	/*
-	**	Clear the unload refinery if not haresting or entering a refinery.
-	*/
-	if (Class->IsToHarvest) {
-		if (Mission != MISSION_HARVEST) {
-			if (Mission != MISSION_ENTER ||
-				!In_Radio_Contact() ||
-				Contact_With_Whom()->What_Am_I() != RTTI_BUILDING ||
-				*((BuildingClass*)Contact_With_Whom()) != STRUCT_REFINERY) {
-				TiberiumUnloadRefinery = TARGET_NONE;
-			}
-		}
-	}
-
 	/*
 	**	Handle combat logic for this unit. It will determine if it has a target and
 	**	if so, if conditions are favorable for firing. When conditions permit, the
@@ -926,6 +912,22 @@ RadioMessageType UnitClass::Receive_Message(RadioClass * from, RadioMessageType
 			}
 			break;
 
+		/*
+		**	Something bad has happened to the object in contact with. Abort any coordinated
+		**	activity with this object. Basically, ... run away! Run away!
+		*/
+		case RADIO_RUN_AWAY:
+			if (Class->IsToHarvest && In_Radio_Contact() && Mission == MISSION_ENTER) {
+				TechnoClass * contact = Contact_With_Whom();
+				if (contact->What_Am_I() == RTTI_BUILDING && *((BuildingClass*)contact) == STRUCT_REFINERY) {
+					// Slight hack; set a target so the harvest mission knows to skip to finding home state
+					Assign_Mission(MISSION_HARVEST);
+					TarCom = As_Target();
+					return(RADIO_ROGER);
+				}
+			}
+			return(DriveClass::Receive_Message(from, message, param));
+
 		/*
 		**	When this message is received, it means that the other object
 		**	has already turned its radio off. Turn this radio off as well.
@@ -2926,7 +2928,6 @@ int UnitClass::Mission_Harvest(void)
 			/*
 			** Look for ore where we last found some - mine the same patch
 			*/
-			TiberiumUnloadRefinery = TARGET_NONE;
 			if (Target_Legal(ArchiveTarget)) {
 				Assign_Destination(ArchiveTarget);
 				ArchiveTarget = 0;
@@ -3008,17 +3009,24 @@ int UnitClass::Mission_Harvest(void)
 			if (!Target_Legal(NavCom)) {
 
 				/*
-				**	Find nearby refinery and head to it.
+				**	Find best refinery.
 				*/
 				BuildingClass * nearest = Find_Best_Refinery();
-				if (nearest != NULL) {
-					TiberiumUnloadRefinery = nearest->As_Target();
-					if (Transmit_Message(RADIO_HELLO, nearest) == RADIO_ROGER) {
-						Status = HEADINGHOME;
-						if (nearest->House == PlayerPtr && (PlayerPtr->Capacity - PlayerPtr->Tiberium) < 300 && PlayerPtr->Capacity > 500 && (PlayerPtr->ActiveBScan & (STRUCTF_REFINERY | STRUCTF_CONST))) {
-							Speak(VOX_NEED_MO_CAPACITY);
-						}
-					} else {
+
+				/*
+				**	Since the refinery said it was ok to load, establish radio
+				**	contact with the refinery and then await docking orders.
+				*/
+				if (nearest != NULL && Transmit_Message(RADIO_HELLO, nearest) == RADIO_ROGER) {
+					Status = HEADINGHOME;
+					if (nearest->House == PlayerPtr && (PlayerPtr->Capacity - PlayerPtr->Tiberium) < 300 && PlayerPtr->Capacity > 500 && (PlayerPtr->ActiveBScan & (STRUCTF_REFINERY | STRUCTF_CONST))) {
+						Speak(VOX_NEED_MO_CAPACITY);
+					}
+				} else {
+					ScenarioInit++;
+					nearest = Find_Best_Refinery();
+					ScenarioInit--;
+					if (nearest != NULL) {
 						Assign_Destination(::As_Target(Nearby_Location(nearest)));
 					}
 				}
@@ -3039,7 +3047,6 @@ int UnitClass::Mission_Harvest(void)
 		**	no where to go.
 		*/
 		case GOINGTOIDLE:
-			TiberiumUnloadRefinery = TARGET_NONE;
 			if (IsUseless) {
 				if (House->ActiveBScan & STRUCTF_REPAIR) {
 					Assign_Mission(MISSION_REPAIR);
@@ -3822,6 +3829,27 @@ int UnitClass::Mission_Move(void)
 }
 
 
+int UnitClass::Mission_Enter(void)
+{
+	assert(Units.ID(this) == ID);
+	assert(IsActive);
+
+	if (Class->IsToHarvest) {
+		TechnoClass * contact = Contact_With_Whom();
+		if (contact == NULL) {
+			contact = As_Techno(ArchiveTarget);
+		}
+		if (contact != NULL &&
+			contact->What_Am_I() == RTTI_BUILDING &&
+			*((BuildingClass*)contact) == STRUCT_REFINERY) {
+			TiberiumUnloadRefinery = contact->As_Target();
+		}
+	}
+
+	return(DriveClass::Mission_Enter());
+}
+
+
 /***********************************************************************************************
  * UnitClass::Desired_Load_Dir -- Determines the best cell and facing for loading.             *
  *                                                                                             *
@@ -4413,100 +4441,29 @@ fixed UnitClass::Tiberium_Load(void) const
 }
 
 
-BuildingClass* UnitClass::Tiberium_Unload_Refinery(void) const
-{
-	return Target_Legal(TiberiumUnloadRefinery) ? As_Building(TiberiumUnloadRefinery) : NULL;
-}
-
-
-struct RefineryData
-{
-	BuildingClass* Refinery;
-	int Distance;
-	int Harvesters;
-};
-
-static bool operator==(const RefineryData& lhs, const RefineryData& rhs)
-{
-	return lhs.Refinery == rhs.Refinery;
-}
-
-static bool operator!=(const RefineryData& lhs, const RefineryData& rhs)
-{
-	return !(lhs == rhs);
-}
-
-static int _refinery_compare(const void * left, const void * right)
-{
-	const RefineryData& lhs = *reinterpret_cast<const RefineryData*>(left);
-	const RefineryData& rhs = *reinterpret_cast<const RefineryData*>(right);
-	if (lhs.Distance < rhs.Distance) {
-		return -1;
-	} else if (rhs.Distance < lhs.Distance) {
-		return 1;
-	}
-	return 0;
-}
-
 BuildingClass* UnitClass::Find_Best_Refinery(void) const
 {
-	static DynamicVectorClass<RefineryData> _refineries;
-
-	_refineries.Clear();
-	for (int i = 0; i < Buildings.Count(); ++i) {
-		BuildingClass* refinery = Buildings.Ptr(i);
+	/*
+	**	Remember our last refinery and prefer that one, if still available and valid.
+	*/
+	if (Target_Legal(TiberiumUnloadRefinery)) {
+		BuildingClass * refinery = As_Building(TiberiumUnloadRefinery);
 		if (refinery != NULL &&
 			refinery->House == House &&
 			!refinery->IsInLimbo &&
+			refinery->Mission != MISSION_DECONSTRUCTION &&
 			*refinery == STRUCT_REFINERY &&
 			Map[refinery->Center_Coord()].Zones[Techno_Type_Class()->MZone] == Map[Center_Coord()].Zones[Techno_Type_Class()->MZone]) {
-			_refineries.Add(RefineryData{ refinery, Distance(refinery), 0 });
-		}
-	}
-
-	// Base case for zero or one refineries.
-	if (_refineries.Count() == 0) {
-		return NULL;
-	} else if (_refineries.Count() == 1) {
-		return _refineries[0].Refinery;
-	}
-
-	// Count harvesters going to each refinery as well as the total.
-	int num_harvesters = 0;
-	for (int i = 0; i < Units.Count(); ++i) {
-		UnitClass* unit = Units.Ptr(i);
-		if (unit->IsActive && Class->IsToHarvest && unit->House == House) {
-			BuildingClass* refinery = unit->Tiberium_Unload_Refinery();
-			if (refinery != NULL) {
-				int index = _refineries.ID(RefineryData{ refinery });
-				assert(index >= 0);
-				_refineries[index].Harvesters++;
-				num_harvesters++;
-			}
-		}
-	}
-
-	// Sort by distance (special case for 2 refineries as that's a single swap).
-	if (_refineries.Count() == 2) {
-		if (_refineries[0].Distance > _refineries[1].Distance) {
-			RefineryData temp = _refineries[0];
-			_refineries[0] = _refineries[1];
-			_refineries[1] = temp;
-		}
-	} else {
-		qsort(&_refineries[0], _refineries.Count(), sizeof(RefineryData), _refinery_compare);
-	}
-
-	// Evenly distribute harvesters among refineries.
-	int harvesters_per_refinery = (num_harvesters + _refineries.Count() - 1) / _refineries.Count();
-	for (int i = 0; i < _refineries.Count(); ++i) {
-		if (_refineries[i].Harvesters < harvesters_per_refinery) {
-			return _refineries[i].Refinery;
+			return refinery;
+		} else {
+			TiberiumUnloadRefinery = TARGET_NONE;
 		}
 	}
 
-	// Fall back on closest refinery
-	return _refineries[0].Refinery;
+	/*
+	**	Find nearby refinery and head to it?
+	*/
+	return Find_Docking_Bay(STRUCT_REFINERY, false);
 }
 
 

+ 2 - 2
REDALERT/UNIT.H

@@ -114,7 +114,7 @@ class UnitClass :	public DriveClass
 		/*
 		**	This is the refinery a harvester is interested in unloading at.
 		*/
-		TARGET TiberiumUnloadRefinery;
+		mutable TARGET TiberiumUnloadRefinery;
 
 		/*
 		** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load
@@ -166,7 +166,6 @@ class UnitClass :	public DriveClass
 		virtual bool Ok_To_Move(DirType facing) const;
 		virtual FireErrorType Can_Fire(TARGET target, int which) const;
 		virtual fixed Tiberium_Load(void) const;
-		virtual BuildingClass* Tiberium_Unload_Refinery(void) const;
 		virtual BuildingClass* Find_Best_Refinery(void) const;
 
 		/*
@@ -223,6 +222,7 @@ class UnitClass :	public DriveClass
 		virtual int Mission_Hunt(void);
 		virtual int Mission_Repair(void);
 		virtual int Mission_Move(void);
+		virtual int Mission_Enter(void);
 		void Rotation_AI(void);
 		void Firing_AI(void);
 		void Reload_AI(void);

+ 1 - 1
REDALERT/WIN32LIB/DrawMisc.cpp

@@ -4842,7 +4842,7 @@ extern "C" int __cdecl Confine_Rect ( int * x , int * y , int w , int h , int wi
 
 
 /*
-; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/WIN32LIB/DrawMisc.cpp#131 $
+; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/WIN32LIB/DrawMisc.cpp#138 $
 ;***************************************************************************
 ;**   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
 ;***************************************************************************

+ 16 - 7
TIBERIANDAWN/AIRCRAFT.CPP

@@ -1899,15 +1899,24 @@ void AircraftClass::Enter_Idle_Mode(bool )
 				} else {
 
 					/*
-					**	Normal aircraft try to find a good landing spot to rest.
+					**	Continue with the current helipad if there is one.
 					*/
-					BuildingClass * building = Find_Docking_Bay(STRUCT_HELIPAD, false);
-					Assign_Destination(TARGET_NONE);
-					if (building && Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER) {
-						mission = MISSION_ENTER;
+					if (!In_Radio_Contact() ||
+						Contact_With_Whom()->What_Am_I() != RTTI_BUILDING ||
+						*((BuildingClass*)Contact_With_Whom()) != STRUCT_HELIPAD) {
+						/*
+						**	Normal aircraft try to find a good landing spot to rest.
+						*/
+						BuildingClass * building = Find_Docking_Bay(STRUCT_HELIPAD, false);
+						Assign_Destination(TARGET_NONE);
+						if (building && Transmit_Message(RADIO_HELLO, building) == RADIO_ROGER) {
+							mission = MISSION_ENTER;
+						} else {
+							Assign_Destination(Good_LZ());
+							mission = MISSION_MOVE;
+						}
 					} else {
-						Assign_Destination(Good_LZ());
-						mission = MISSION_MOVE;
+						mission = MISSION_ENTER;
 					}
 				}
 			} else {

+ 1 - 1
TIBERIANDAWN/ANIM.CPP

@@ -637,7 +637,7 @@ AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay
 	**	Check for a virtual animation
 	*/
 	if (Class->VirtualAnim != ANIM_NONE) {
-		VirtualAnim = new AnimClass(Class->VirtualAnim, 0, timedelay, loop, alt);
+		VirtualAnim = new AnimClass(Class->VirtualAnim, Coord, timedelay, loop, alt);
 		if (VirtualAnim != NULL) {
 			VirtualAnim->Make_Invisible();
 		}

+ 0 - 3
TIBERIANDAWN/BUILDING.CPP

@@ -3879,9 +3879,6 @@ bool BuildingClass::Can_Capture(void) const
 		if (!House->IsHuman && Trigger != NULL && Trigger->Action == TriggerClass::ACTION_WINLOSE) {
 			can_capture = true;
 		}
-	} else {
-		// Only allow capturing of multiplayer-owned structures
-		can_capture &= House->Class->House >= HOUSE_MULTI1 && House->Class->House <= HOUSE_MULTI6;
 	}
 
 	return(can_capture);

+ 1 - 1
TIBERIANDAWN/MiscAsm.cpp

@@ -428,7 +428,7 @@ dxisbig:
 #if (0)
 
 /*
-	; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/MiscAsm.cpp#131 $
+	; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/MiscAsm.cpp#138 $
 ;***************************************************************************
 ;**   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
 ;***************************************************************************

+ 67 - 107
TIBERIANDAWN/UNIT.CPP

@@ -396,20 +396,6 @@ void UnitClass::AI(void)
 		return;
 	}
 
-	/*
-	**	Clear the unload refinery if not haresting or entering a refinery.
-	*/
-	if (Class->IsToHarvest) {
-		if (Mission != MISSION_HARVEST) {
-			if (Mission != MISSION_ENTER ||
-				!In_Radio_Contact() ||
-				Contact_With_Whom()->What_Am_I() != RTTI_BUILDING ||
-				*((BuildingClass*)Contact_With_Whom()) != STRUCT_REFINERY) {
-				TiberiumUnloadRefinery = NULL;
-			}
-		}
-	}
-
 	/*
 	**	Rocket launchers will reload every so often.
 	*/
@@ -763,6 +749,22 @@ RadioMessageType UnitClass::Receive_Message(RadioClass * from, RadioMessageType
 			}
 			break;
 
+		/*
+		**	Something bad has happened to the object in contact with. Abort any coordinated
+		**	activity with this object. Basically, ... run away! Run away!
+		*/
+		case RADIO_RUN_AWAY:
+			if (Class->IsToHarvest && In_Radio_Contact() && Mission == MISSION_ENTER) {
+				TechnoClass * contact = Contact_With_Whom();
+				if (contact->What_Am_I() == RTTI_BUILDING && *((BuildingClass*)contact) == STRUCT_REFINERY) {
+					// Slight hack; set a target so the harvest mission knows to skip to finding home state
+					Assign_Mission(MISSION_HARVEST);
+					TarCom = As_Target();
+					return(RADIO_ROGER);
+				}
+			}
+			return(DriveClass::Receive_Message(from, message, param));
+
 		/*
 		**	When this message is received, it means that the other object
 		**	has already turned its radio off. Turn this radio off as well.
@@ -2418,93 +2420,26 @@ bool UnitClass::Goto_Tiberium(void)
 }
 
 
-struct RefineryData
-{
-	BuildingClass* Refinery;
-	int Distance;
-	int Harvesters;
-};
-
-static bool operator==(const RefineryData& lhs, const RefineryData& rhs)
-{
-	return lhs.Refinery == rhs.Refinery;
-}
-
-static bool operator!=(const RefineryData& lhs, const RefineryData& rhs)
-{
-	return !(lhs == rhs);
-}
-
-static int _refinery_compare(const void * left, const void * right)
-{
-	const RefineryData& lhs = *reinterpret_cast<const RefineryData*>(left);
-	const RefineryData& rhs = *reinterpret_cast<const RefineryData*>(right);
-	if (lhs.Distance < rhs.Distance) {
-		return -1;
-	} else if (rhs.Distance < lhs.Distance) {
-		return 1;
-	}
-	return 0;
-}
-
 BuildingClass* UnitClass::Find_Best_Refinery(void) const
 {
-	static DynamicVectorClass<RefineryData> _refineries;
-
-	_refineries.Clear();
-	for (int i = 0; i < Buildings.Count(); ++i) {
-		BuildingClass* refinery = Buildings.Ptr(i);
-		if (refinery != NULL &&
-			refinery->House == House &&
-			!refinery->IsInLimbo &&
-			*refinery == STRUCT_REFINERY) {
-			_refineries.Add(RefineryData{ refinery, Distance(refinery), 0 });
-		}
-	}
-
-	// Base case for zero or one refineries.
-	if (_refineries.Count() == 0) {
-		return NULL;
-	} else if (_refineries.Count() == 1) {
-		return _refineries[0].Refinery;
-	}
-
-	// Count harvesters going to each refinery as well as the total.
-	int num_harvesters = 0;
-	for (int i = 0; i < Units.Count(); ++i) {
-		UnitClass* unit = Units.Ptr(i);
-		if (unit->IsActive && unit->Class->IsToHarvest && unit->House == House) {
-			BuildingClass* refinery = unit->Tiberium_Unload_Refinery();
-			if (refinery != NULL) {
-				int index = _refineries.ID(RefineryData{ refinery });
-				assert(index >= 0);
-				_refineries[index].Harvesters++;
-				num_harvesters++;
-			}
-		}
-	}
-
-	// Sort by distance (special case for 2 refineries as that's a single swap).
-	if (_refineries.Count() == 2) {
-		if (_refineries[0].Distance > _refineries[1].Distance) {
-			RefineryData temp = _refineries[0];
-			_refineries[0] = _refineries[1];
-			_refineries[1] = temp;
-		}
-	} else {
-		qsort(&_refineries[0], _refineries.Count(), sizeof(RefineryData), _refinery_compare);
-	}
-
-	// Evenly distribute harvesters among refineries.
-	int harvesters_per_refinery = (num_harvesters + _refineries.Count() - 1) / _refineries.Count();
-	for (int i = 0; i < _refineries.Count(); ++i) {
-		if (_refineries[i].Harvesters < harvesters_per_refinery) {
-			return _refineries[i].Refinery;
+	/*
+	**	Remember our last refinery and prefer that one, if still available and valid.
+	*/
+	if (TiberiumUnloadRefinery != NULL) {
+		if (TiberiumUnloadRefinery->House == House &&
+			!TiberiumUnloadRefinery->IsInLimbo &&
+			TiberiumUnloadRefinery->Mission != MISSION_DECONSTRUCTION &&
+			*TiberiumUnloadRefinery == STRUCT_REFINERY) {
+			return TiberiumUnloadRefinery;
+		} else {
+			TiberiumUnloadRefinery = NULL;
 		}
 	}
 
-	// Fall back on closest refinery
-	return _refineries[0].Refinery;
+	/*
+	**	Find nearby refinery and head to it?
+	*/
+	return Find_Docking_Bay(STRUCT_REFINERY, false);
 }
 
 
@@ -2800,10 +2735,7 @@ int UnitClass::Mission_Harvest(void)
 				Assign_Target(TARGET_NONE);
 				Status = FINDHOME;
 				return(1);
-			}
-
-			TiberiumUnloadRefinery = NULL;
-			if (Goto_Tiberium()) {
+			} else if (Goto_Tiberium()) {
 				IsHarvesting = true;
 				Set_Rate(2);
 				Set_Stage(0);
@@ -2865,14 +2797,21 @@ int UnitClass::Mission_Harvest(void)
 			if (!Target_Legal(NavCom)) {
 
 				/*
-				**	Find nearby refinery and head to it.
+				**	Find best refinery.
 				*/
 				BuildingClass * nearest = Find_Best_Refinery();
-				if (nearest) {
-					TiberiumUnloadRefinery = nearest;
-					if (Transmit_Message(RADIO_HELLO, nearest) == RADIO_ROGER) {
-						Status = HEADINGHOME;
-					} else {
+
+				/*
+				**	Since the refinery said it was ok to load, establish radio
+				**	contact with the refinery and then await docking orders.
+				*/
+				if (nearest && Transmit_Message(RADIO_HELLO, nearest) == RADIO_ROGER) {
+					Status = HEADINGHOME;
+				} else {
+					ScenarioInit++;
+					nearest = Find_Best_Refinery();
+					ScenarioInit--;
+					if (nearest) {
 						Assign_Destination(::As_Target(nearest->Nearby_Location(this)));
 					}
 				}
@@ -2889,7 +2828,6 @@ int UnitClass::Mission_Harvest(void)
 			return(1);
 
 		case GOINGTOIDLE:
-			TiberiumUnloadRefinery = NULL;
 			Assign_Mission(MISSION_GUARD);
 			break;
 
@@ -2968,6 +2906,28 @@ int UnitClass::Mission_Hunt(void)
 }
 
 
+int UnitClass::Mission_Enter(void)
+{
+	Validate();
+	if (Class->IsToHarvest) {
+		TechnoClass * contact = Contact_With_Whom();
+		if (contact == NULL) {
+			contact = As_Techno(ArchiveTarget);
+		}
+		if (contact == NULL) {
+			contact = As_Techno(NavCom);
+		}
+		if (contact != NULL &&
+			contact->What_Am_I() == RTTI_BUILDING &&
+			*((BuildingClass*)contact) == STRUCT_REFINERY) {
+			TiberiumUnloadRefinery = (BuildingClass*)contact;
+		}
+	}
+
+	return(TarComClass::Mission_Enter());
+}
+
+
 /***********************************************************************************************
  * UnitClass::Look -- Perform map revelation from a unit's position.                           *
  *                                                                                             *

+ 3 - 3
TIBERIANDAWN/UNIT.H

@@ -84,8 +84,7 @@ class UnitClass :	public TarComClass
 		bool  Harvesting(void);
 		void  APC_Close_Door(void);
 		void  APC_Open_Door(void);
-		BuildingClass*  Tiberium_Unload_Refinery(void) const {return TiberiumUnloadRefinery;}
-		BuildingClass*  Find_Best_Refinery(void) const;
+		virtual BuildingClass*  Find_Best_Refinery(void) const;
 
 		/*
 		**	Query functions.
@@ -158,6 +157,7 @@ class UnitClass :	public TarComClass
 		virtual int Mission_Guard(void);
 		virtual int Mission_Harvest(void);
 		virtual int Mission_Hunt(void);
+		virtual int Mission_Enter(void);
 		virtual int UnitClass::Mission_Move(void);
 		virtual FireErrorType Can_Fire(TARGET, int which) const;
 
@@ -204,7 +204,7 @@ class UnitClass :	public TarComClass
 		/*
 		**	This is the refinery a harvester is interested in unloading at.
 		*/
-		BuildingClass* TiberiumUnloadRefinery;
+		mutable BuildingClass* TiberiumUnloadRefinery;
 
 		/*
 		** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load

+ 1 - 1
TIBERIANDAWN/WIN32LIB/DrawMisc.cpp

@@ -4841,7 +4841,7 @@ extern "C" int __cdecl Confine_Rect ( int * x , int * y , int w , int h , int wi
 
 
 /*
-; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/DrawMisc.cpp#131 $
+; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/DrawMisc.cpp#138 $
 ;***************************************************************************
 ;**   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
 ;***************************************************************************

+ 1 - 1
TIBERIANDAWN/WIN32LIB/FACINGFF.h

@@ -321,7 +321,7 @@ int __cdecl Desired_Facing8(long x1, long y1, long x2, long y2);
 
 
 /*
-	; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/FACINGFF.h#131 $
+	; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/FACINGFF.h#138 $
 ;***************************************************************************
 ;**   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
 ;***************************************************************************