commit 7d496e8a633a8bbf8a14b65f490b4d21fa32ca03 parent fd05be35c1ee5dfcb6143ddcc79f16b74a8ce8a5 Author: PG-SteveT <63470275+PG-SteveT@users.noreply.github.com> Date: Thu, 24 Sep 2020 10:20:31 -0700 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 Diffstat:
40 files changed, 226 insertions(+), 264 deletions(-)
diff --git a/CnCTDRAMapEditor.sln b/CnCTDRAMapEditor.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.28307.1022 diff --git a/CnCTDRAMapEditor/Controls/BasicSettings.resx b/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 diff --git a/CnCTDRAMapEditor/Controls/BriefingSettings.resx b/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 diff --git a/CnCTDRAMapEditor/Controls/MapPanel.resx b/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 diff --git a/CnCTDRAMapEditor/Controls/ObjectProperties.resx b/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 diff --git a/CnCTDRAMapEditor/Controls/PlayerSettings.resx b/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 diff --git a/CnCTDRAMapEditor/Controls/TerrainProperties.resx b/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 diff --git a/CnCTDRAMapEditor/Dialogs/ErrorMessageBox.resx b/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 diff --git a/CnCTDRAMapEditor/Dialogs/InviteMessageBox.resx b/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 diff --git a/CnCTDRAMapEditor/Dialogs/MapSettingsDialog.resx b/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 diff --git a/CnCTDRAMapEditor/Dialogs/NewMapDialog.resx b/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 diff --git a/CnCTDRAMapEditor/Dialogs/SteamDialog.resx b/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 diff --git a/CnCTDRAMapEditor/Dialogs/TeamTypesDialog.resx b/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 diff --git a/CnCTDRAMapEditor/Dialogs/TriggersDialog.resx b/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 diff --git a/CnCTDRAMapEditor/MainForm.resx b/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 diff --git a/CnCTDRAMapEditor/Properties/Resources.resx b/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 diff --git a/CnCTDRAMapEditor/Properties/Settings.settings b/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> diff --git a/CnCTDRAMapEditor/Tools/Dialogs/CellTriggersToolDialog.resx b/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 diff --git a/CnCTDRAMapEditor/Tools/Dialogs/GenericToolDialog.resx b/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 diff --git a/CnCTDRAMapEditor/Tools/Dialogs/ObjectToolDialog.resx b/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 diff --git a/CnCTDRAMapEditor/Tools/Dialogs/ResourcesToolDialog.resx b/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 diff --git a/CnCTDRAMapEditor/Tools/Dialogs/TemplateToolDialog.resx b/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 diff --git a/CnCTDRAMapEditor/Tools/Dialogs/TerrainToolDialog.resx b/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 diff --git a/CnCTDRAMapEditor/Tools/Dialogs/WaypointsToolDialog.resx b/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 diff --git a/CnCTDRAMapEditor/Utility/INI.cs b/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; + } + } } } } diff --git a/REDALERT/ANIM.CPP b/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(); diff --git a/REDALERT/BUILDING.CPP b/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); diff --git a/REDALERT/MiscAsm.cpp b/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 ** ;*************************************************************************** diff --git a/REDALERT/TECHNO.CPP b/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; } diff --git a/REDALERT/UNIT.CPP b/REDALERT/UNIT.CPP @@ -442,20 +442,6 @@ void UnitClass::AI(void) } /* - ** 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 ** unit will fire upon its target. @@ -927,6 +913,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); } diff --git a/REDALERT/UNIT.H b/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); diff --git a/REDALERT/WIN32LIB/DrawMisc.cpp b/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 ** ;*************************************************************************** diff --git a/TIBERIANDAWN/AIRCRAFT.CPP b/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 { diff --git a/TIBERIANDAWN/ANIM.CPP b/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(); } diff --git a/TIBERIANDAWN/BUILDING.CPP b/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); diff --git a/TIBERIANDAWN/MiscAsm.cpp b/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 ** ;*************************************************************************** diff --git a/TIBERIANDAWN/UNIT.CPP b/TIBERIANDAWN/UNIT.CPP @@ -397,20 +397,6 @@ void UnitClass::AI(void) } /* - ** 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. */ if (*this == UNIT_MSAM && Ammo < Class->MaxAmmo) { @@ -764,6 +750,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. * * * diff --git a/TIBERIANDAWN/UNIT.H b/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 diff --git a/TIBERIANDAWN/WIN32LIB/DrawMisc.cpp b/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 ** ;*************************************************************************** diff --git a/TIBERIANDAWN/WIN32LIB/FACINGFF.h b/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 ** ;***************************************************************************