From fc9d1badb392943d11259956a0bd8a4917a4ef8a Mon Sep 17 00:00:00 2001 From: FS-21 Date: Wed, 27 Oct 2021 01:01:05 +0200 Subject: [PATCH 01/48] Initial commit --- src/Ext/Rules/Body.cpp | 24 ++- src/Ext/Rules/Body.h | 1 + src/Ext/Script/Body.cpp | 467 +++++++++++++++++++++++++++++++++++++++- src/Ext/Script/Body.h | 9 + src/Ext/Team/Body.cpp | 3 + src/Ext/Team/Body.h | 6 + 6 files changed, 507 insertions(+), 3 deletions(-) diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index 8f2ce0062b..d4537c0a02 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,7 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) const char* sectionAITargetTypes = "AITargetTypes"; const char* sectionAIScriptsList = "AIScriptsList"; + const char* sectionAIHousesList = "AIHousesList"; INI_EX exINI(pINI); @@ -72,7 +74,7 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) this->Pips_Shield_Buildings.Read(exINI, "AudioVisual", "Pips.Shield.Building"); this->MissingCameo.Read(pINI, "AudioVisual", "MissingCameo"); - // Section AITargetType + // Section AITargetTypes int itemsCount = pINI->GetKeyCount(sectionAITargetTypes); for (int i = 0; i < itemsCount; ++i) { @@ -111,6 +113,25 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) AIScriptsLists.AddItem(objectsList); objectsList.Clear(); } + + // Section AIHousesList + int houseItemsCount = pINI->GetKeyCount(sectionAIHousesList); + for (int i = 0; i < houseItemsCount; ++i) + { + DynamicVectorClass objectsList; + + char* context = nullptr; + pINI->ReadString(sectionAIHousesList, pINI->GetKeyName(sectionAIHousesList, i), "", Phobos::readBuffer); + + for (char *cur = strtok_s(Phobos::readBuffer, Phobos::readDelims, &context); cur; cur = strtok_s(nullptr, Phobos::readDelims, &context)) + { + HouseTypeClass* pNewHouse = GameCreate(cur); + objectsList.AddItem(pNewHouse); + } + + AIHousesLists.AddItem(objectsList); + objectsList.Clear(); + } } // this runs between the before and after type data loading methods for rules ini @@ -164,6 +185,7 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->JumpjetNoWobbles) .Process(this->AITargetTypesLists) .Process(this->AIScriptsLists) + .Process(this->AIHousesLists) ; } diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h index 3c3fe4c519..7c206c8395 100644 --- a/src/Ext/Rules/Body.h +++ b/src/Ext/Rules/Body.h @@ -30,6 +30,7 @@ class RulesExt PhobosFixedString<32u> MissingCameo; DynamicVectorClass> AITargetTypesLists; DynamicVectorClass> AIScriptsLists; + DynamicVectorClass> AIHousesLists; Valueable JumpjetCrash; Valueable JumpjetNoWobbles; diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index df778abcb8..199ea18a37 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -141,6 +141,27 @@ void ScriptExt::ProcessAction(TeamClass* pTeam) case 112: ScriptExt::Mission_Gather_NearTheLeader(pTeam, -1); break; + case 113: + ScriptExt::ResetAngerAgainstHouses(pTeam); + break; + case 114: + ScriptExt::SetHouseAngerModifier(pTeam, 0); + break; + case 115: + ScriptExt::OverrideOnlyTargetHouseEnemy(pTeam, -1); + break; + case 116: + ScriptExt::ModifyHateHouse_Index(pTeam, -1); + break; + case 117: + ScriptExt::ModifyHateHouses_List(pTeam, -1); + break; + case 118: + ScriptExt::ModifyHateHouses_List1Random(pTeam, -1); + break; + case 119: + ScriptExt::SetTheMostHatedHouse(pTeam, 0); + break; default: // Do nothing because or it is a wrong Action number or it is an Ares/YR action... //Debug::Log("[%s] [%s] %d = %d,%d\n", pTeam->Type->ID, pScriptType->ID, pScript->idxCurrentLine, currentLineAction->Action, currentLineAction->Argument); @@ -744,11 +765,22 @@ void ScriptExt::Mission_Attack(TeamClass *pTeam, bool repeatAction = true, int c } } + bool onlyTargetHouseEnemy = pTeam->Type->OnlyTargetHouseEnemy; + + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (pTeamData) + { + if (pTeamData->OnlyTargetHouseEnemyMode != -1) + { + onlyTargetHouseEnemy = pTeamData->OnlyTargetHouseEnemy; + } + } + pFocus = abstract_cast(pTeam->Focus); if (!pFocus && !bAircraftsWithoutAmmo) { // Favorite Enemy House case. If set, AI will focus against that House - if (pTeam->Type->OnlyTargetHouseEnemy && pLeaderUnit->Owner->EnemyHouseIndex >= 0) + if (onlyTargetHouseEnemy && pLeaderUnit->Owner->EnemyHouseIndex >= 0) enemyHouse = HouseClass::Array->GetItem(pLeaderUnit->Owner->EnemyHouseIndex); int targetMask = scriptArgument; @@ -2181,8 +2213,18 @@ TechnoClass* ScriptExt::FindBestObject(TechnoClass *pTechno, int method, int cal if (pFoot) { int enemyHouseIndex = pFoot->Team->FirstUnit->Owner->EnemyHouseIndex; + bool onlyTargetHouseEnemy = pFoot->Team->Type->OnlyTargetHouseEnemy; - if (pFoot->Team->Type->OnlyTargetHouseEnemy + auto pTeamData = TeamExt::ExtMap.Find(pFoot->Team); + if (pTeamData) + { + if (pTeamData->OnlyTargetHouseEnemyMode != -1) + { + onlyTargetHouseEnemy = pTeamData->OnlyTargetHouseEnemy; + } + } + + if (onlyTargetHouseEnemy && enemyHouseIndex >= 0) { enemyHouse = HouseClass::Array->GetItem(enemyHouseIndex); @@ -2327,3 +2369,424 @@ void ScriptExt::UnregisterGreatSuccess(TeamClass* pTeam) pTeam->AchievedGreatSuccess = false; pTeam->StepCompleted = true; // This action finished - FS-21 } + +void ScriptExt::ResetAngerAgainstHouses(TeamClass* pTeam) +{ + // Invalid team + if (!pTeam) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + angerNode.AngerLevel = 0; + } + + pTeam->Owner->EnemyHouseIndex = -1; + DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! + // This action finished + pTeam->StepCompleted = true; // This action finished - FS-21 +} + +void ScriptExt::SetHouseAngerModifier(TeamClass* pTeam, int modifier = 0) +{ + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + + if (!pTeam || !pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + if (modifier <= 0) + modifier = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + + if (modifier < 0) + modifier = 0; + + pTeamData->AngerNodeModifier = modifier; + + // This action finished + pTeam->StepCompleted = true; +} + +void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) +{ + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + + if (!pTeam || !pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + if (idxHousesList <= 0) + idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + + bool changeFailed = true; + + if (idxHousesList >= 0) + { + if (idxHousesList < RulesExt::Global()->AIHousesLists.Count) + { + DynamicVectorClass objectsList = RulesExt::Global()->AIHousesLists.GetItem(idxHousesList); + + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): objectsList.Count: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, objectsList.Count); + if (objectsList.Count > 0) + { + for (auto pHouseType : objectsList) + { + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + HouseTypeClass* angerNodeType = angerNode.House->Type; + + if (_stricmp(angerNodeType->ID, pHouseType->ID) == 0) + { + angerNode.AngerLevel += pTeamData->AngerNodeModifier; + changeFailed = false; + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Changed [%s](Index: %d)->AngerLevel to value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); + } + } + } + } + } + } + + // This action finished + if (changeFailed) + { + pTeam->StepCompleted = true; + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify any hate value against other houses!\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); + } + + // This action finished + pTeam->StepCompleted = true; + DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! +} + +void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList = -1) +{ + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + + if (!pTeam || !pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + if (idxHousesList <= 0) + idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + + int changes = 0; + + if (idxHousesList >= 0) + { + if (idxHousesList < RulesExt::Global()->AIHousesLists.Count) + { + DynamicVectorClass objectsList = RulesExt::Global()->AIHousesLists.GetItem(idxHousesList); + + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): objectsList.Count: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, objectsList.Count); + if (objectsList.Count > 0) + { + int IdxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.Count - 1); + HouseTypeClass* pHouseType = objectsList.GetItem(IdxSelectedObject); + + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + HouseTypeClass* angerNodeType = angerNode.House->Type; + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Comparation %s == %s\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNodeType->ID, pHouseType->ID); + if (_stricmp(angerNodeType->ID, pHouseType->ID) == 0) + { + angerNode.AngerLevel += pTeamData->AngerNodeModifier; + changes++; + } + } + } + } + } + + // This action finished + if (changes == 0) + { + pTeam->StepCompleted = true; + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify any hate value against other houses!\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); + } + + // This action finished + pTeam->StepCompleted = true; + DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! +} + +void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) +{ + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + FootClass *pLeaderUnit = nullptr; + int bestUnitLeadershipValue = -1; + + if (!pTeam || !pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + // Find the Team Leader + for (auto pUnit = pTeam->FirstUnit; pUnit; pUnit = pUnit->NextTeamMember) + { + if (pUnit && pUnit->IsAlive && !pUnit->InLimbo) + { + auto pUnitType = pUnit->GetTechnoType(); + if (pUnitType) + { + // The team leader will be used for selecting targets, if there are living Team Members then always exists 1 Leader. + int unitLeadershipRating = pUnitType->LeadershipRating; + if (unitLeadershipRating > bestUnitLeadershipValue) + { + pLeaderUnit = pUnit; + bestUnitLeadershipValue = unitLeadershipRating; + } + } + } + } + + if (!pLeaderUnit) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + // Find the highest House hate value + int newHateLevel = 1; + + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + HouseTypeClass* angerNodeType = angerNode.House->Type; + + if (!angerNodeType->MultiplayPassive && angerNode.AngerLevel > newHateLevel) + { + newHateLevel = angerNode.AngerLevel; + } + } + + newHateLevel += 1000; + int objectDistance = -1; + int enemyDistance = -1; + double enemyThreatValue[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + HouseClass* enemyHouse = nullptr; + + // Depending the mode check what house will be selected as the most hated + for (auto pTechno : *TechnoClass::Array) + { + if (pTechno->Owner != pTeam->Owner + && pTechno->IsAlive + && !pTechno->InLimbo + && pTechno->IsOnMap + && !pTechno->Owner->Type->MultiplayPassive) + { + if (mode == 0 || mode == 1) + { + objectDistance = pLeaderUnit->DistanceFrom(pTechno); // Note: distance is in leptons (*256) + + if (mode == 0) + { + // Mode 0: Based in nearest enemy unit + if (objectDistance < enemyDistance || enemyDistance == -1) + { + enemyDistance = objectDistance; + enemyHouse = pTechno->Owner; + } + } + else + { + // Mode 1: Based in farthest enemy unit + if (objectDistance > enemyDistance || enemyDistance == -1) + { + enemyDistance = objectDistance; + enemyHouse = pTechno->Owner; + } + } + } + else + { + if (mode == 2 || mode == 3) + { + // Mode 2 & 3: Based in House Threat + auto pTechnoType = pTechno->GetTechnoType(); + + if (pTechnoType) + { + enemyThreatValue[pTechno->Owner->ArrayIndex] += pTechnoType->ThreatPosed; + + if (pTechnoType->SpecialThreatValue > 0) + { + double const& TargetSpecialThreatCoefficientDefault = RulesClass::Instance->TargetSpecialThreatCoefficientDefault; + enemyThreatValue[pTechno->Owner->ArrayIndex] += pTechnoType->SpecialThreatValue * TargetSpecialThreatCoefficientDefault; + } + } + } + } + } + } + + if (mode == 2 || mode == 3) + { + double value = -1; + + for (int i; i < 8; i++) + { + if (mode == 2) + { + // Select House with less threat + if (enemyThreatValue[i] < value || value == -1) + { + value = enemyThreatValue[i]; + enemyHouse = HouseClass::Array->GetItem(i); + } + } + else + { + // Select House with more threat + if (enemyThreatValue[i] > value || value == -1) + { + value = enemyThreatValue[i]; + enemyHouse = HouseClass::Array->GetItem(i); + } + } + } + } + + // Setting the new hate level to the selected house + if (enemyHouse) + { + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + if (angerNode.House == enemyHouse) + { + angerNode.AngerLevel = newHateLevel; + + // This action finished + pTeam->StepCompleted = true; + + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): The most hated house now is [%s]!\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID); + } + } + } + + // This action finished + if (!enemyHouse) + { + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to select a house as the most hated!\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); + } + + // This action finished + pTeam->StepCompleted = true; + DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! +} + +void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) +{ + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeam || !pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + if (mode < 0 || mode > 2) + mode = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + + if (mode < -1 || mode > 2) + mode = -1; + + /* + Modes: + 0 -> Force "False" + 1 -> Force "True" + 2 -> Force "Random boolean" + -1 -> Use default value in OnlyTargetHouseEnemy tag + */ + switch (mode) + { + case 0: + pTeamData->OnlyTargetHouseEnemy = false; + break; + + case 1: + pTeamData->OnlyTargetHouseEnemy = true; + break; + + case 2: + pTeamData->OnlyTargetHouseEnemy = (bool)ScenarioClass::Instance->Random.RandomRanged(0, 1);; + break; + + default: + pTeamData->OnlyTargetHouseEnemy = pTeam->Type->OnlyTargetHouseEnemy; + pTeamData->OnlyTargetHouseEnemyMode = -1; + break; + } + + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Team -> OnlyTargetHouseEnemy override to value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, pTeamData->OnlyTargetHouseEnemy); + DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! + // This action finished + pTeam->StepCompleted = true; +} + +void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) +{ + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + + if (!pTeam || !pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + if (idxHouse < 0) + idxHouse = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + + if (idxHouse < 0) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + else + { + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + if (angerNode.House->ArrayIndex == idxHouse) + { + angerNode.AngerLevel += pTeamData->AngerNodeModifier; + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Changed [%s](Index: %d)->AngerLevel to value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); + } + } + } + DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! + // This action finished + pTeam->StepCompleted = true; +} + +void ScriptExt::DebugAngerNodes(TeamClass* pTeam) +{ + // Invalid team + if (!pTeam) + { + return; + } + + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Hate list for the house [%s] (Index: %d): Enemy Idx: %d\n-----------------------------------\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, pTeam->Owner->Type->ID, pTeam->Owner->ArrayIndex, pTeam->Owner->EnemyHouseIndex); + + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + Debug::Log("- [%s] (Index: %d): Anger level: %d\n", angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); + } +} diff --git a/src/Ext/Script/Body.h b/src/Ext/Script/Body.h index fad1de5091..9820643987 100644 --- a/src/Ext/Script/Body.h +++ b/src/Ext/Script/Body.h @@ -66,6 +66,15 @@ class ScriptExt static void Mission_Attack_List(TeamClass *pTeam, bool repeatAction, int calcThreatMode, int attackAITargetType); + static void ResetAngerAgainstHouses(TeamClass* pTeam); + static void SetHouseAngerModifier(TeamClass* pTeam, int modifier); + static void ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList); + static void ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList); + static void ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse); + static void SetTheMostHatedHouse(TeamClass* pTeam, int mode); + static void OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode); + static void DebugAngerNodes(TeamClass* pTeam); + static ExtContainer ExtMap; private: diff --git a/src/Ext/Team/Body.cpp b/src/Ext/Team/Body.cpp index 690b026248..959912ccdc 100644 --- a/src/Ext/Team/Body.cpp +++ b/src/Ext/Team/Body.cpp @@ -15,6 +15,9 @@ void TeamExt::ExtData::Serialize(T& Stm) .Process(this->IdxSelectedObjectFromAIList) .Process(this->CloseEnough) .Process(this->Countdown_RegroupAtLeader) + .Process(this->AngerNodeModifier) + .Process(this->OnlyTargetHouseEnemy) + .Process(this->OnlyTargetHouseEnemyMode) ; } diff --git a/src/Ext/Team/Body.h b/src/Ext/Team/Body.h index 471c9f4213..71d16eaf9d 100644 --- a/src/Ext/Team/Body.h +++ b/src/Ext/Team/Body.h @@ -20,6 +20,9 @@ class TeamExt int IdxSelectedObjectFromAIList; double CloseEnough; int Countdown_RegroupAtLeader; + int AngerNodeModifier; + bool OnlyTargetHouseEnemy; + int OnlyTargetHouseEnemyMode; ExtData(TeamClass* OwnerObject) : Extension(OwnerObject) , WaitNoTargetAttempts(0) @@ -27,6 +30,9 @@ class TeamExt , IdxSelectedObjectFromAIList(-1) , CloseEnough(-1) , Countdown_RegroupAtLeader(-1) + , AngerNodeModifier(1000) + , OnlyTargetHouseEnemy(false) + , OnlyTargetHouseEnemyMode(-1) { } virtual ~ExtData() = default; From 7080aa12bc08a2c9f97d1f0e621de7d82ecbe838 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Thu, 28 Oct 2021 13:52:36 +0200 Subject: [PATCH 02/48] move action 113 to 120 --- src/Ext/Script/Body.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 199ea18a37..1e056ddc2f 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -142,7 +142,7 @@ void ScriptExt::ProcessAction(TeamClass* pTeam) ScriptExt::Mission_Gather_NearTheLeader(pTeam, -1); break; case 113: - ScriptExt::ResetAngerAgainstHouses(pTeam); + // Reserved break; case 114: ScriptExt::SetHouseAngerModifier(pTeam, 0); @@ -162,6 +162,9 @@ void ScriptExt::ProcessAction(TeamClass* pTeam) case 119: ScriptExt::SetTheMostHatedHouse(pTeam, 0); break; + case 120: + ScriptExt::ResetAngerAgainstHouses(pTeam); + break; default: // Do nothing because or it is a wrong Action number or it is an Ares/YR action... //Debug::Log("[%s] [%s] %d = %d,%d\n", pTeam->Type->ID, pScriptType->ID, pScript->idxCurrentLine, currentLineAction->Action, currentLineAction->Argument); From d1d3af299df825a61a2ad84acdc77007e1b47b14 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Mon, 8 Nov 2021 17:56:17 +0100 Subject: [PATCH 03/48] added aggro action --- src/Ext/Script/Body.cpp | 299 +++++++++++++++++++++++++++++----------- src/Ext/Script/Body.h | 6 +- src/Ext/Team/Body.h | 2 +- 3 files changed, 224 insertions(+), 83 deletions(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 1e056ddc2f..836db9d342 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -148,23 +148,29 @@ void ScriptExt::ProcessAction(TeamClass* pTeam) ScriptExt::SetHouseAngerModifier(pTeam, 0); break; case 115: - ScriptExt::OverrideOnlyTargetHouseEnemy(pTeam, -1); - break; + ScriptExt::OverrideOnlyTargetHouseEnemy(pTeam, -1); + break; case 116: ScriptExt::ModifyHateHouse_Index(pTeam, -1); - break; + break; case 117: ScriptExt::ModifyHateHouses_List(pTeam, -1); - break; + break; case 118: ScriptExt::ModifyHateHouses_List1Random(pTeam, -1); - break; + break; case 119: - ScriptExt::SetTheMostHatedHouse(pTeam, 0); + ScriptExt::SetTheMostHatedHouse(pTeam, 0, false); break; case 120: + ScriptExt::SetTheMostHatedHouse(pTeam, 0, true); + break; + case 121: ScriptExt::ResetAngerAgainstHouses(pTeam); break; + case 122: + ScriptExt::AggroHouse(pTeam, -1); + break; default: // Do nothing because or it is a wrong Action number or it is an Ares/YR action... //Debug::Log("[%s] [%s] %d = %d,%d\n", pTeam->Type->ID, pScriptType->ID, pScript->idxCurrentLine, currentLineAction->Action, currentLineAction->Argument); @@ -2389,7 +2395,6 @@ void ScriptExt::ResetAngerAgainstHouses(TeamClass* pTeam) } pTeam->Owner->EnemyHouseIndex = -1; - DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! // This action finished pTeam->StepCompleted = true; // This action finished - FS-21 } @@ -2452,7 +2457,7 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) { angerNode.AngerLevel += pTeamData->AngerNodeModifier; changeFailed = false; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Changed [%s](Index: %d)->AngerLevel to value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); + //Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Changed [%s](Index: %d)->AngerLevel to value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); } } } @@ -2467,9 +2472,9 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify any hate value against other houses!\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); } + ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); // This action finished pTeam->StepCompleted = true; - DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! } void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList = -1) @@ -2493,8 +2498,6 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList if (idxHousesList < RulesExt::Global()->AIHousesLists.Count) { DynamicVectorClass objectsList = RulesExt::Global()->AIHousesLists.GetItem(idxHousesList); - - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): objectsList.Count: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, objectsList.Count); if (objectsList.Count > 0) { int IdxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.Count - 1); @@ -2502,8 +2505,11 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList for (auto& angerNode : pTeam->Owner->AngerNodes) { + if (angerNode.House->Defeated) + continue; + HouseTypeClass* angerNodeType = angerNode.House->Type; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Comparation %s == %s\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNodeType->ID, pHouseType->ID); + if (_stricmp(angerNodeType->ID, pHouseType->ID) == 0) { angerNode.AngerLevel += pTeamData->AngerNodeModifier; @@ -2521,12 +2527,89 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify any hate value against other houses!\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); } + ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); // This action finished pTeam->StepCompleted = true; - DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! } -void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) +void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mode = 0, bool random = false) +{ + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + + if (!pTeam || !pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + DynamicVectorClass objectsList; + int IdxSelectedObject = -1; + HouseClass* selectedHouse = nullptr; + int highestHateLevel = 0; + int newHateLevel = 5000; + + if (pTeamData->AngerNodeModifier > 0) + newHateLevel = pTeamData->AngerNodeModifier; + + // Find the highest House hate value + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + if (angerNode.House->Defeated) + continue; + + if (pTeam->Owner != angerNode.House && !pTeam->Owner->IsAlliedWith(angerNode.House) && !angerNode.House->Type->MultiplayPassive) + { + if (random) + objectsList.AddItem(angerNode.House); + + if (angerNode.AngerLevel > highestHateLevel) + highestHateLevel = angerNode.AngerLevel; + } + } + + newHateLevel += highestHateLevel; + + // Pick a enemy house + if (random) + { + if (objectsList.Count > 0) + { + IdxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.Count - 1); + selectedHouse = objectsList.GetItem(IdxSelectedObject); + } + } + else + { + selectedHouse = GetTheMostHatedHouse(pTeam, mode); + } + + if (selectedHouse) + { + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + if (angerNode.House->Defeated) + continue; + + if (angerNode.House == selectedHouse) + { + angerNode.AngerLevel = newHateLevel; + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Picked a new house as enemy [%s]\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNode.House->Type->ID); + } + } + + ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); + } + else + { + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); + } + + // This action finished + pTeam->StepCompleted = true; +} + +HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) { auto pTeamData = TeamExt::ExtMap.Find(pTeam); FootClass *pLeaderUnit = nullptr; @@ -2536,7 +2619,7 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) { // This action finished pTeam->StepCompleted = true; - return; + return nullptr; } // Find the Team Leader @@ -2562,35 +2645,23 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) { // This action finished pTeam->StepCompleted = true; - return; + return nullptr; } - // Find the highest House hate value - int newHateLevel = 1; - - for (auto& angerNode : pTeam->Owner->AngerNodes) - { - HouseTypeClass* angerNodeType = angerNode.House->Type; - - if (!angerNodeType->MultiplayPassive && angerNode.AngerLevel > newHateLevel) - { - newHateLevel = angerNode.AngerLevel; - } - } - - newHateLevel += 1000; int objectDistance = -1; int enemyDistance = -1; - double enemyThreatValue[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + double enemyThreatValue[8] = { 0 }; HouseClass* enemyHouse = nullptr; // Depending the mode check what house will be selected as the most hated for (auto pTechno : *TechnoClass::Array) { - if (pTechno->Owner != pTeam->Owner + if (!pTechno->Owner->Defeated + && pTechno->Owner != pTeam->Owner && pTechno->IsAlive && !pTechno->InLimbo && pTechno->IsOnMap + && !pTechno->Owner->IsAlliedWith(pTeam->Owner) && !pTechno->Owner->Type->MultiplayPassive) { if (mode == 0 || mode == 1) @@ -2642,7 +2713,7 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) { double value = -1; - for (int i; i < 8; i++) + for (int i = 0; i < 8; i++) { if (mode == 2) { @@ -2665,32 +2736,7 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) } } - // Setting the new hate level to the selected house - if (enemyHouse) - { - for (auto& angerNode : pTeam->Owner->AngerNodes) - { - if (angerNode.House == enemyHouse) - { - angerNode.AngerLevel = newHateLevel; - - // This action finished - pTeam->StepCompleted = true; - - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): The most hated house now is [%s]!\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID); - } - } - } - - // This action finished - if (!enemyHouse) - { - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to select a house as the most hated!\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); - } - - // This action finished - pTeam->StepCompleted = true; - DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! + return enemyHouse; } void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) @@ -2709,35 +2755,37 @@ void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) if (mode < -1 || mode > 2) mode = -1; + pTeamData->OnlyTargetHouseEnemyMode = mode; /* Modes: 0 -> Force "False" 1 -> Force "True" 2 -> Force "Random boolean" -1 -> Use default value in OnlyTargetHouseEnemy tag + Note: only works for new Actions, not vanilla YR actions */ switch (mode) { - case 0: - pTeamData->OnlyTargetHouseEnemy = false; - break; + case 0: + pTeamData->OnlyTargetHouseEnemy = false; + break; - case 1: - pTeamData->OnlyTargetHouseEnemy = true; - break; + case 1: + pTeamData->OnlyTargetHouseEnemy = true; + break; - case 2: - pTeamData->OnlyTargetHouseEnemy = (bool)ScenarioClass::Instance->Random.RandomRanged(0, 1);; - break; + case 2: + pTeamData->OnlyTargetHouseEnemy = (bool)ScenarioClass::Instance->Random.RandomRanged(0, 1);; + break; - default: - pTeamData->OnlyTargetHouseEnemy = pTeam->Type->OnlyTargetHouseEnemy; - pTeamData->OnlyTargetHouseEnemyMode = -1; - break; + default: + pTeamData->OnlyTargetHouseEnemy = pTeam->Type->OnlyTargetHouseEnemy; + pTeamData->OnlyTargetHouseEnemyMode = -1; + break; } Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Team -> OnlyTargetHouseEnemy override to value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, pTeamData->OnlyTargetHouseEnemy); - DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! + // This action finished pTeam->StepCompleted = true; } @@ -2766,30 +2814,121 @@ void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) { for (auto& angerNode : pTeam->Owner->AngerNodes) { - if (angerNode.House->ArrayIndex == idxHouse) + if (angerNode.House->ArrayIndex == idxHouse && !angerNode.House->Defeated) { angerNode.AngerLevel += pTeamData->AngerNodeModifier; Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Changed [%s](Index: %d)->AngerLevel to value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); } } } - DebugAngerNodes(pTeam); // Debug function. Remove it when I finish with teh tests! + + ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); // This action finished pTeam->StepCompleted = true; } -void ScriptExt::DebugAngerNodes(TeamClass* pTeam) +// The selected house will become the most hated of the map (the effects are only visible if the other houses are enemy of the selected house) +void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) { - // Invalid team - if (!pTeam) + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + + if (!pTeam || !pTeamData) { + // This action finished + pTeam->StepCompleted = true; return; } - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Hate list for the house [%s] (Index: %d): Enemy Idx: %d\n-----------------------------------\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, pTeam->Owner->Type->ID, pTeam->Owner->ArrayIndex, pTeam->Owner->EnemyHouseIndex); + DynamicVectorClass objectsList; + HouseClass* selectedHouse = nullptr; + int newHateLevel = 5000; + if (pTeamData->AngerNodeModifier > 0) + newHateLevel = pTeamData->AngerNodeModifier; + + // Store the list of playable houses for later for (auto& angerNode : pTeam->Owner->AngerNodes) { - Debug::Log("- [%s] (Index: %d): Anger level: %d\n", angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); + if (!angerNode.House->Defeated && !angerNode.House->Type->MultiplayPassive && !angerNode.House->IsObserver()) + { + objectsList.AddItem(angerNode.House); + } + } + + // Positive indexes are specific house indexes. -1 is translated as "pick 1 random" & -2 is the owner of the Team executing the script action + if (objectsList.Count > 0) + { + if (index < 0) + { + if (index == -1) + index = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.Count - 1); + else + index = pTeam->Owner->ArrayIndex; + } + } + else + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + // Note: at most each "For" lasts 10 loops: 8 players + Civilian + Special houses + for (auto& pHouse : *HouseClass::Array) + { + if (!pHouse->Defeated && pHouse->ArrayIndex == index) + selectedHouse = pHouse; } + + if (selectedHouse) + { + // For each playable house set the selected house as the one with highest hate value; + for (auto& pHouse : objectsList) + { + int highestHateLevel = 0; + + for (auto& angerNode : pHouse->AngerNodes) + { + if (angerNode.AngerLevel > highestHateLevel) + highestHateLevel = angerNode.AngerLevel; + } + + for (auto& angerNode : pHouse->AngerNodes) + { + if (selectedHouse == angerNode.House) + { + angerNode.AngerLevel = highestHateLevel + newHateLevel; + } + } + + ScriptExt::UpdateEnemyHouseIndex(pHouse); + } + } + else + { + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, index); + } + + // This action finished + pTeam->StepCompleted = true; } + +void ScriptExt::UpdateEnemyHouseIndex(HouseClass* pHouse) +{ + int angerLevel = 0; + int index = -1; + + for (auto& angerNode : pHouse->AngerNodes) + { + if (!angerNode.House->Defeated && angerNode.AngerLevel > angerLevel) + { + angerLevel = angerNode.AngerLevel; + index = angerNode.House->ArrayIndex; + } + } + + pHouse->EnemyHouseIndex = index; +} + + + diff --git a/src/Ext/Script/Body.h b/src/Ext/Script/Body.h index 9820643987..481614211b 100644 --- a/src/Ext/Script/Body.h +++ b/src/Ext/Script/Body.h @@ -71,12 +71,14 @@ class ScriptExt static void ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList); static void ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList); static void ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse); - static void SetTheMostHatedHouse(TeamClass* pTeam, int mode); + static void SetTheMostHatedHouse(TeamClass* pTeam, int mode, bool random); static void OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode); - static void DebugAngerNodes(TeamClass* pTeam); + static void AggroHouse(TeamClass* pTeam, int index); static ExtContainer ExtMap; private: static void ModifyCurrentTriggerWeight(TeamClass* pTeam, bool forceJumpLine, double modifier); + static HouseClass* GetTheMostHatedHouse(TeamClass* pTeam, int mode); + static void UpdateEnemyHouseIndex(HouseClass* pHouse); }; diff --git a/src/Ext/Team/Body.h b/src/Ext/Team/Body.h index 71d16eaf9d..4f3be0e24f 100644 --- a/src/Ext/Team/Body.h +++ b/src/Ext/Team/Body.h @@ -30,7 +30,7 @@ class TeamExt , IdxSelectedObjectFromAIList(-1) , CloseEnough(-1) , Countdown_RegroupAtLeader(-1) - , AngerNodeModifier(1000) + , AngerNodeModifier(5000) , OnlyTargetHouseEnemy(false) , OnlyTargetHouseEnemyMode(-1) { } From 72f82f5068d5d877c40d17039860174e81988b73 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Wed, 10 Nov 2021 19:19:35 +0100 Subject: [PATCH 04/48] improvements in SetTheMostHatedHouse() & GetTheMostHatedHouse() --- src/Ext/Script/Body.cpp | 69 +++++++++++++++++++++++++++++------------ src/Ext/Script/Body.h | 4 +-- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 836db9d342..25e33d0612 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -160,15 +160,25 @@ void ScriptExt::ProcessAction(TeamClass* pTeam) ScriptExt::ModifyHateHouses_List1Random(pTeam, -1); break; case 119: - ScriptExt::SetTheMostHatedHouse(pTeam, 0, false); + // <, no random + ScriptExt::SetTheMostHatedHouse(pTeam, 0, 0, false); break; case 120: - ScriptExt::SetTheMostHatedHouse(pTeam, 0, true); + // >, no random + ScriptExt::SetTheMostHatedHouse(pTeam, 0, 1, false); break; case 121: - ScriptExt::ResetAngerAgainstHouses(pTeam); + // < random + ScriptExt::SetTheMostHatedHouse(pTeam, 0, 0, true); break; case 122: + // > random + ScriptExt::SetTheMostHatedHouse(pTeam, 0, 1, true); + break; + case 123: + ScriptExt::ResetAngerAgainstHouses(pTeam); + break; + case 124: ScriptExt::AggroHouse(pTeam, -1); break; default: @@ -2532,7 +2542,7 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList pTeam->StepCompleted = true; } -void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mode = 0, bool random = false) +void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = 1, bool random = false) { auto pTeamData = TeamExt::ExtMap.Find(pTeam); @@ -2543,6 +2553,16 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mode = 0, bool random return; } + if (mask == 0) + mask = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + + if (mask == 0) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + DynamicVectorClass objectsList; int IdxSelectedObject = -1; HouseClass* selectedHouse = nullptr; @@ -2581,7 +2601,7 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mode = 0, bool random } else { - selectedHouse = GetTheMostHatedHouse(pTeam, mode); + selectedHouse = GetTheMostHatedHouse(pTeam, mask, mode); } if (selectedHouse) @@ -2609,13 +2629,19 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mode = 0, bool random pTeam->StepCompleted = true; } -HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) +HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = 1) { + // Note regarding "mode": 1 is used for ">" comparisons and 0 for "<" + if (mode <= 0) + mode = 0; + else + mode = 1; + auto pTeamData = TeamExt::ExtMap.Find(pTeam); FootClass *pLeaderUnit = nullptr; int bestUnitLeadershipValue = -1; - if (!pTeam || !pTeamData) + if (!pTeam || !pTeamData || mask == 0) { // This action finished pTeam->StepCompleted = true; @@ -2652,6 +2678,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) int enemyDistance = -1; double enemyThreatValue[8] = { 0 }; HouseClass* enemyHouse = nullptr; + double const& TargetSpecialThreatCoefficientDefault = RulesClass::Instance->TargetSpecialThreatCoefficientDefault; // Depending the mode check what house will be selected as the most hated for (auto pTechno : *TechnoClass::Array) @@ -2662,15 +2689,16 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) && !pTechno->InLimbo && pTechno->IsOnMap && !pTechno->Owner->IsAlliedWith(pTeam->Owner) - && !pTechno->Owner->Type->MultiplayPassive) + && !pTechno->Owner->Type->MultiplayPassive + && !pTechno->Owner->Defeated) { - if (mode == 0 || mode == 1) + if (mask < 0) { objectDistance = pLeaderUnit->DistanceFrom(pTechno); // Note: distance is in leptons (*256) if (mode == 0) { - // Mode 0: Based in nearest enemy unit + // mode 0: Based in NEAREST enemy unit if (objectDistance < enemyDistance || enemyDistance == -1) { enemyDistance = objectDistance; @@ -2679,19 +2707,20 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) } else { - // Mode 1: Based in farthest enemy unit + // mode 1: Based in FARTHEST enemy unit if (objectDistance > enemyDistance || enemyDistance == -1) { enemyDistance = objectDistance; enemyHouse = pTechno->Owner; } } + // TODO: more types of comparisons } else { - if (mode == 2 || mode == 3) + // mask > 0 : Threat based on the new types in the new attack actions + if (ScriptExt::EvaluateObjectWithMask(pTechno, mask, -1, -1, pLeaderUnit)) { - // Mode 2 & 3: Based in House Threat auto pTechnoType = pTechno->GetTechnoType(); if (pTechnoType) @@ -2700,7 +2729,6 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) if (pTechnoType->SpecialThreatValue > 0) { - double const& TargetSpecialThreatCoefficientDefault = RulesClass::Instance->TargetSpecialThreatCoefficientDefault; enemyThreatValue[pTechno->Owner->ArrayIndex] += pTechnoType->SpecialThreatValue * TargetSpecialThreatCoefficientDefault; } } @@ -2709,16 +2737,17 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) } } - if (mode == 2 || mode == 3) + if (mask > 0) { double value = -1; for (int i = 0; i < 8; i++) { - if (mode == 2) + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): enemyThreatValue[%d] = %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, i, enemyThreatValue[i]); + if (mode == 0) { - // Select House with less threat - if (enemyThreatValue[i] < value || value == -1) + // Select House with LESS threat + if ((enemyThreatValue[i] < value || value == -1) && !HouseClass::Array->GetItem(i)->Defeated) { value = enemyThreatValue[i]; enemyHouse = HouseClass::Array->GetItem(i); @@ -2726,8 +2755,8 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mode = 0) } else { - // Select House with more threat - if (enemyThreatValue[i] > value || value == -1) + // Select House with MORE threat + if ((enemyThreatValue[i] > value || value == -1) && !HouseClass::Array->GetItem(i)->Defeated) { value = enemyThreatValue[i]; enemyHouse = HouseClass::Array->GetItem(i); diff --git a/src/Ext/Script/Body.h b/src/Ext/Script/Body.h index 481614211b..3f6ac3d3d3 100644 --- a/src/Ext/Script/Body.h +++ b/src/Ext/Script/Body.h @@ -71,7 +71,7 @@ class ScriptExt static void ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList); static void ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList); static void ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse); - static void SetTheMostHatedHouse(TeamClass* pTeam, int mode, bool random); + static void SetTheMostHatedHouse(TeamClass* pTeam, int mask, int mode, bool random); static void OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode); static void AggroHouse(TeamClass* pTeam, int index); @@ -79,6 +79,6 @@ class ScriptExt private: static void ModifyCurrentTriggerWeight(TeamClass* pTeam, bool forceJumpLine, double modifier); - static HouseClass* GetTheMostHatedHouse(TeamClass* pTeam, int mode); + static HouseClass* GetTheMostHatedHouse(TeamClass* pTeam, int mask, int mode); static void UpdateEnemyHouseIndex(HouseClass* pHouse); }; From 0ea00ab15df47d7605b27409f4cae427cc059a3a Mon Sep 17 00:00:00 2001 From: FS-21 Date: Mon, 15 Nov 2021 19:00:34 +0100 Subject: [PATCH 05/48] new features when finding the most hateful house --- src/Ext/Script/Body.cpp | 243 +++++++++++++++++++++++++++++++++------- 1 file changed, 203 insertions(+), 40 deletions(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index bb0d6db42f..68da993b83 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2440,6 +2440,7 @@ void ScriptExt::SetHouseAngerModifier(TeamClass* pTeam, int modifier = 0) void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) { auto pTeamData = TeamExt::ExtMap.Find(pTeam); + bool changeFailed = true; if (!pTeam || !pTeamData) { @@ -2451,15 +2452,12 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) if (idxHousesList <= 0) idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; - bool changeFailed = true; - if (idxHousesList >= 0) { if (idxHousesList < RulesExt::Global()->AIHousesLists.Count) { DynamicVectorClass objectsList = RulesExt::Global()->AIHousesLists.GetItem(idxHousesList); - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): objectsList.Count: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, objectsList.Count); if (objectsList.Count > 0) { for (auto pHouseType : objectsList) @@ -2472,7 +2470,6 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) { angerNode.AngerLevel += pTeamData->AngerNodeModifier; changeFailed = false; - //Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Changed [%s](Index: %d)->AngerLevel to value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); } } } @@ -2484,7 +2481,7 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) if (changeFailed) { pTeam->StepCompleted = true; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify any hate value against other houses!\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify hate values against other houses\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); @@ -2495,6 +2492,7 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList = -1) { auto pTeamData = TeamExt::ExtMap.Find(pTeam); + int changes = 0; if (!pTeam || !pTeamData) { @@ -2506,8 +2504,6 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList if (idxHousesList <= 0) idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; - int changes = 0; - if (idxHousesList >= 0) { if (idxHousesList < RulesExt::Global()->AIHousesLists.Count) @@ -2539,7 +2535,7 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList if (changes == 0) { pTeam->StepCompleted = true; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify any hate value against other houses!\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify hate values against other houses\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); @@ -2679,11 +2675,163 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int return nullptr; } - int objectDistance = -1; - int enemyDistance = -1; + double objectDistance = -1; + double enemyDistance = -1; double enemyThreatValue[8] = { 0 }; HouseClass* enemyHouse = nullptr; double const& TargetSpecialThreatCoefficientDefault = RulesClass::Instance->TargetSpecialThreatCoefficientDefault; + long houseMoney = -1; + int enemyPower = -1000000000; + int enemyKills = -1; + + if (mask == -2) + { + // Based on House economy + for (auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse || pHouse->IsObserver() || pHouse->Defeated || pHouse->Type->MultiplayPassive || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + continue; + + if (mode == 0) + { + // The poorest is selected + if (pHouse->Available_Money() < houseMoney || houseMoney < 0) + { + houseMoney = pHouse->Available_Money(); + enemyHouse = pHouse; + } + } + else + { + // The richest is selected + if (pHouse->Available_Money() > houseMoney || houseMoney < 0) + { + houseMoney = pHouse->Available_Money(); + enemyHouse = pHouse; + } + } + } + + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + + return enemyHouse; + } + + if (mask == -3) + { + // Based on Human Controlled check + for (auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse || !pHouse->ControlledByHuman() || pHouse->Defeated || pHouse->Type->MultiplayPassive || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + continue; + + CoordStruct houseLocation; + houseLocation.X = pHouse->BaseSpawnCell.X; + houseLocation.Y = pHouse->BaseSpawnCell.Y; + houseLocation.Z = 0; + objectDistance = pLeaderUnit->Location.DistanceFrom(houseLocation); // Note: distance is in leptons (*256) + + if (mode == 0) + { + // mode 0: Based in NEAREST human enemy unit + if (objectDistance < enemyDistance || enemyDistance == -1) + { + enemyDistance = objectDistance; + enemyHouse = pHouse; + } + } + else + { + // mode 1: Based in FARTHEST human enemy unit + if (objectDistance > enemyDistance || enemyDistance == -1) + { + enemyDistance = objectDistance; + enemyHouse = pHouse; + } + } + } + + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + + return enemyHouse; + } + + if (mask == -4 || mask == -5 || mask == -6) + { + int checkedHousePower; + + // House power check + for (auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse || pHouse->Defeated || pHouse->Type->MultiplayPassive || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + continue; + + if (mask == -4) + checkedHousePower = pHouse->Power_Drain(); + + if (mask == -5) + checkedHousePower = pHouse->PowerOutput; + + if (mask == -6) + checkedHousePower = pHouse->PowerOutput - pHouse->Power_Drain(); + + if (mode == 0) + { + // mode 0: Selection based in lower value power in house + if ((checkedHousePower < enemyPower) || enemyPower == -1000000000) + { + enemyPower = checkedHousePower; + enemyHouse = pHouse; + } + } + else + { + // mode 1: Selection based in higher value power in house + if ((checkedHousePower > enemyPower) || enemyPower == -1000000000) + { + enemyPower = checkedHousePower; + enemyHouse = pHouse; + } + } + } + + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + return enemyHouse; + } + + if (mask == -7) + { + // Based on House kills + for (auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse || pHouse->IsObserver() || pHouse->Defeated || pHouse->Type->MultiplayPassive || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + continue; + + int currentKills = pHouse->TotalKilledUnits + pHouse->TotalKilledUnits; + + if (mode == 0) + { + // The pacifist is selected + if (currentKills < enemyKills || enemyKills < 0) + { + enemyKills = currentKills; + enemyHouse = pHouse; + } + } + else + { + // The major killer is selected + if (currentKills > enemyKills || enemyKills < 0) + { + enemyKills = currentKills; + enemyHouse = pHouse; + } + } + } + + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + return enemyHouse; + } // Depending the mode check what house will be selected as the most hated for (auto pTechno : *TechnoClass::Array) @@ -2694,32 +2842,34 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int && !pTechno->InLimbo && pTechno->IsOnMap && !pTechno->Owner->IsAlliedWith(pTeam->Owner) - && !pTechno->Owner->Type->MultiplayPassive - && !pTechno->Owner->Defeated) + && !pTechno->Owner->Type->MultiplayPassive) { if (mask < 0) { - objectDistance = pLeaderUnit->DistanceFrom(pTechno); // Note: distance is in leptons (*256) - - if (mode == 0) + if (mask == -1) { - // mode 0: Based in NEAREST enemy unit - if (objectDistance < enemyDistance || enemyDistance == -1) + // mask -1: Based on object distances + objectDistance = pLeaderUnit->DistanceFrom(pTechno); // Note: distance is in leptons (*256) + + if (mode == 0) { - enemyDistance = objectDistance; - enemyHouse = pTechno->Owner; + // mode 0: Based in NEAREST enemy unit + if (objectDistance < enemyDistance || enemyDistance == -1) + { + enemyDistance = objectDistance; + enemyHouse = pTechno->Owner; + } } - } - else - { - // mode 1: Based in FARTHEST enemy unit - if (objectDistance > enemyDistance || enemyDistance == -1) + else { - enemyDistance = objectDistance; - enemyHouse = pTechno->Owner; + // mode 1: Based in FARTHEST enemy unit + if (objectDistance > enemyDistance || enemyDistance == -1) + { + enemyDistance = objectDistance; + enemyHouse = pTechno->Owner; + } } } - // TODO: more types of comparisons } else { @@ -2748,7 +2898,6 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int for (int i = 0; i < 8; i++) { - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): enemyThreatValue[%d] = %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, i, enemyThreatValue[i]); if (mode == 0) { // Select House with LESS threat @@ -2770,6 +2919,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } } + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); return enemyHouse; } @@ -2818,8 +2968,7 @@ void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) break; } - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Team -> OnlyTargetHouseEnemy override to value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, pTeamData->OnlyTargetHouseEnemy); - + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): New Team -> OnlyTargetHouseEnemy value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, pTeamData->OnlyTargetHouseEnemy); // This action finished pTeam->StepCompleted = true; } @@ -2851,7 +3000,7 @@ void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) if (angerNode.House->ArrayIndex == idxHouse && !angerNode.House->Defeated) { angerNode.AngerLevel += pTeamData->AngerNodeModifier; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Changed [%s](Index: %d)->AngerLevel to value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Modified anger level against [%s](index: %d) with value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); } } } @@ -2896,7 +3045,8 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) { if (index == -1) index = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.Count - 1); - else + + if (index == -2) index = pTeam->Owner->ArrayIndex; } } @@ -2908,13 +3058,16 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) } // Note: at most each "For" lasts 10 loops: 8 players + Civilian + Special houses - for (auto& pHouse : *HouseClass::Array) + if (index != -3) { - if (!pHouse->Defeated && pHouse->ArrayIndex == index) - selectedHouse = pHouse; + for (auto& pHouse : *HouseClass::Array) + { + if (!pHouse->Defeated && pHouse->ArrayIndex == index) + selectedHouse = pHouse; + } } - if (selectedHouse) + if (selectedHouse || index == -3) { // For each playable house set the selected house as the one with highest hate value; for (auto& pHouse : objectsList) @@ -2929,9 +3082,19 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) for (auto& angerNode : pHouse->AngerNodes) { - if (selectedHouse == angerNode.House) + if (index == -3) { - angerNode.AngerLevel = highestHateLevel + newHateLevel; + if (angerNode.House->ControlledByHuman()) + { + angerNode.AngerLevel = highestHateLevel + newHateLevel; + } + } + else + { + if (selectedHouse == angerNode.House) + { + angerNode.AngerLevel = highestHateLevel + newHateLevel; + } } } @@ -2940,7 +3103,7 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) } else { - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, index); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house with index: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, index); } // This action finished @@ -2954,7 +3117,7 @@ void ScriptExt::UpdateEnemyHouseIndex(HouseClass* pHouse) for (auto& angerNode : pHouse->AngerNodes) { - if (!angerNode.House->Defeated && angerNode.AngerLevel > angerLevel) + if (!angerNode.House->Defeated && !pHouse->IsAlliedWith(angerNode.House) && angerNode.AngerLevel > angerLevel) { angerLevel = angerNode.AngerLevel; index = angerNode.House->ArrayIndex; From a6badeaba870f4389f3c1c958efbf41e69ad2def Mon Sep 17 00:00:00 2001 From: FS-21 Date: Mon, 15 Nov 2021 20:02:27 +0100 Subject: [PATCH 06/48] debug fixes --- src/Ext/Script/Body.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 68da993b83..0699a3bf60 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2712,7 +2712,8 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } } - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + if (enemyHouse) + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); return enemyHouse; } @@ -2751,7 +2752,8 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } } - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + if (enemyHouse) + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); return enemyHouse; } @@ -2795,7 +2797,9 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } } - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + if (enemyHouse) + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + return enemyHouse; } @@ -2829,7 +2833,9 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } } - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + if (enemyHouse) + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + return enemyHouse; } @@ -2919,7 +2925,9 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } } - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + if (enemyHouse) + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + return enemyHouse; } From b0fed206931dfdbd4c08904e6feb1fdad1d54c16 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Thu, 18 Nov 2021 06:01:46 +0100 Subject: [PATCH 07/48] Some fixes & improvements --- src/Ext/Script/Body.cpp | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 0699a3bf60..be2203fde0 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -170,17 +170,13 @@ void ScriptExt::ProcessAction(TeamClass* pTeam) ScriptExt::SetTheMostHatedHouse(pTeam, 0, 1, false); break; case 121: - // < random + // random ScriptExt::SetTheMostHatedHouse(pTeam, 0, 0, true); break; case 122: - // > random - ScriptExt::SetTheMostHatedHouse(pTeam, 0, 1, true); - break; - case 123: ScriptExt::ResetAngerAgainstHouses(pTeam); break; - case 124: + case 123: ScriptExt::AggroHouse(pTeam, -1); break; default: @@ -2576,14 +2572,20 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = // Find the highest House hate value for (auto& angerNode : pTeam->Owner->AngerNodes) { - if (angerNode.House->Defeated) + if (pTeam->Owner == angerNode.House + || angerNode.House->Defeated + || pTeam->Owner->IsAlliedWith(angerNode.House) + || angerNode.House->Type->MultiplayPassive) + { continue; + } - if (pTeam->Owner != angerNode.House && !pTeam->Owner->IsAlliedWith(angerNode.House) && !angerNode.House->Type->MultiplayPassive) + if (random) + { + objectsList.AddItem(angerNode.House); + } + else { - if (random) - objectsList.AddItem(angerNode.House); - if (angerNode.AngerLevel > highestHateLevel) highestHateLevel = angerNode.AngerLevel; } @@ -3046,6 +3048,15 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) } } + // Include the own House if we are looking for ANY Human player + if (index == -3) + { + if (!pTeam->Owner->Defeated && !pTeam->Owner->Type->MultiplayPassive && !pTeam->Owner->IsObserver() && !pTeam->Owner->ControlledByHuman()) + { + objectsList.AddItem(pTeam->Owner); + } + } + // Positive indexes are specific house indexes. -1 is translated as "pick 1 random" & -2 is the owner of the Team executing the script action if (objectsList.Count > 0) { From 2589daa7f3d5ef797eaf4bab270e624dd8d664c8 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sun, 21 Nov 2021 22:11:31 +0100 Subject: [PATCH 08/48] Update src/Ext/Script/Body.cpp Co-authored-by: YRIDZE <78161538+YRIDZE@users.noreply.github.com> --- src/Ext/Script/Body.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index be2203fde0..1386a954ef 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2691,8 +2691,14 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int // Based on House economy for (auto& pHouse : *HouseClass::Array) { - if (pLeaderUnit->Owner == pHouse || pHouse->IsObserver() || pHouse->Defeated || pHouse->Type->MultiplayPassive || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + if (pLeaderUnit->Owner == pHouse + || pHouse->IsObserver() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(House)) + { continue; + } if (mode == 0) { From bbb1a814131154446212d2b21462016e3dc109a9 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sun, 21 Nov 2021 22:11:49 +0100 Subject: [PATCH 09/48] Update src/Ext/Script/Body.cpp Co-authored-by: YRIDZE <78161538+YRIDZE@users.noreply.github.com> --- src/Ext/Script/Body.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 1386a954ef..2d64b3b053 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2731,8 +2731,14 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int // Based on Human Controlled check for (auto& pHouse : *HouseClass::Array) { - if (pLeaderUnit->Owner == pHouse || !pHouse->ControlledByHuman() || pHouse->Defeated || pHouse->Type->MultiplayPassive || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + if (pLeaderUnit->Owner == pHouse + || !pHouse->ControlledByHuman() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(House)) + { continue; + } CoordStruct houseLocation; houseLocation.X = pHouse->BaseSpawnCell.X; From 54e88944f20f284d608559ba8427e219f5c2a0fe Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sun, 21 Nov 2021 22:11:56 +0100 Subject: [PATCH 10/48] Update src/Ext/Script/Body.cpp Co-authored-by: YRIDZE <78161538+YRIDZE@users.noreply.github.com> --- src/Ext/Script/Body.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 2d64b3b053..d8ec3f4493 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2822,8 +2822,14 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int // Based on House kills for (auto& pHouse : *HouseClass::Array) { - if (pLeaderUnit->Owner == pHouse || pHouse->IsObserver() || pHouse->Defeated || pHouse->Type->MultiplayPassive || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + if (pLeaderUnit->Owner == pHouse + || pHouse->IsObserver() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(House)) + { continue; + } int currentKills = pHouse->TotalKilledUnits + pHouse->TotalKilledUnits; From f96e5765c1a300cd3bf1209ebde89ca70710a7ab Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sun, 21 Nov 2021 22:12:13 +0100 Subject: [PATCH 11/48] Update src/Ext/Script/Body.cpp Co-authored-by: YRIDZE <78161538+YRIDZE@users.noreply.github.com> --- src/Ext/Script/Body.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index d8ec3f4493..5b5a59cc86 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2779,8 +2779,13 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int // House power check for (auto& pHouse : *HouseClass::Array) { - if (pLeaderUnit->Owner == pHouse || pHouse->Defeated || pHouse->Type->MultiplayPassive || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + if (pLeaderUnit->Owner == pHouse + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(House)) + { continue; + } if (mask == -4) checkedHousePower = pHouse->Power_Drain(); From b386b466c415a333d084ca45e7fc115326f44e79 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sun, 21 Nov 2021 22:12:24 +0100 Subject: [PATCH 12/48] Update src/Ext/Script/Body.cpp Co-authored-by: YRIDZE <78161538+YRIDZE@users.noreply.github.com> --- src/Ext/Script/Body.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 5b5a59cc86..e5e149c4c6 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -3074,7 +3074,10 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) // Include the own House if we are looking for ANY Human player if (index == -3) { - if (!pTeam->Owner->Defeated && !pTeam->Owner->Type->MultiplayPassive && !pTeam->Owner->IsObserver() && !pTeam->Owner->ControlledByHuman()) + if (!pTeam->Owner->Defeated + && !pTeam->Owner->Type->MultiplayPassive + && !pTeam->Owner->IsObserver() + && !pTeam->Owner->ControlledByHuman()) { objectsList.AddItem(pTeam->Owner); } From f6931421eb6e9f8056687f47009338e28e82fd6a Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sun, 21 Nov 2021 22:12:42 +0100 Subject: [PATCH 13/48] Update src/Ext/Script/Body.cpp Co-authored-by: YRIDZE <78161538+YRIDZE@users.noreply.github.com> --- src/Ext/Script/Body.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index e5e149c4c6..19b28fc374 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -3162,7 +3162,9 @@ void ScriptExt::UpdateEnemyHouseIndex(HouseClass* pHouse) for (auto& angerNode : pHouse->AngerNodes) { - if (!angerNode.House->Defeated && !pHouse->IsAlliedWith(angerNode.House) && angerNode.AngerLevel > angerLevel) + if (!angerNode.House->Defeated + && !pHouse->IsAlliedWith(angerNode.House) + && angerNode.AngerLevel > angerLevel) { angerLevel = angerNode.AngerLevel; index = angerNode.House->ArrayIndex; From ce0fbe8e8e81664cdb65a274a6b7b7a13216ea30 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sun, 21 Nov 2021 22:20:39 +0100 Subject: [PATCH 14/48] fixes --- src/Ext/Script/Body.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 19b28fc374..c2359af181 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2695,7 +2695,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int || pHouse->IsObserver() || pHouse->Defeated || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(House)) + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) { continue; } @@ -2735,7 +2735,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int || !pHouse->ControlledByHuman() || pHouse->Defeated || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(House)) + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) { continue; } @@ -2782,7 +2782,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int if (pLeaderUnit->Owner == pHouse || pHouse->Defeated || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(House)) + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) { continue; } @@ -2831,7 +2831,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int || pHouse->IsObserver() || pHouse->Defeated || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(House)) + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) { continue; } From 1f9abd2ca2a6841df70f51a9e713191570342a51 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Mon, 29 Nov 2021 15:44:03 +0100 Subject: [PATCH 15/48] Added debug lines When using ObjectInfo or the AngerNode Action is executed successfuly some debug lines will be written in debug.log with the current AngerNode values of each house. --- src/Commands/ObjectInfo.h | 3 +++ src/Ext/Script/Body.cpp | 37 ++++++++++++++++++++++++++++++++++++- src/Ext/Script/Body.h | 1 + 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/Commands/ObjectInfo.h b/src/Commands/ObjectInfo.h index a0e5d73f85..0ad5604501 100644 --- a/src/Commands/ObjectInfo.h +++ b/src/Commands/ObjectInfo.h @@ -13,6 +13,7 @@ #include #include +#include // #53 New debug feature for AI scripts class ObjectInfoCommandClass : public PhobosCommandClass @@ -223,6 +224,7 @@ class ObjectInfoCommandClass : public PhobosCommandClass append("\n"); display(); + ScriptExt::DebugAngerNodesData(); }; auto printBuilding = [&append, &display](BuildingClass* pBuilding) @@ -262,6 +264,7 @@ class ObjectInfoCommandClass : public PhobosCommandClass append("Current Shield HP = (%d / %d)\n", pShieldData->GetHP(), pTypeShieldData->ShieldType->Strength); } display(); + ScriptExt::DebugAngerNodesData(); }; bool dumped = false; diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index c2359af181..cfc7e808ac 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2406,6 +2406,7 @@ void ScriptExt::ResetAngerAgainstHouses(TeamClass* pTeam) } pTeam->Owner->EnemyHouseIndex = -1; + ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! // This action finished pTeam->StepCompleted = true; // This action finished - FS-21 } @@ -2481,6 +2482,7 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); + ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! // This action finished pTeam->StepCompleted = true; } @@ -2535,6 +2537,7 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); + ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! // This action finished pTeam->StepCompleted = true; } @@ -3039,6 +3042,7 @@ void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); + ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! // This action finished pTeam->StepCompleted = true; } @@ -3150,7 +3154,7 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) { Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house with index: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, index); } - + ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! // This action finished pTeam->StepCompleted = true; } @@ -3365,3 +3369,34 @@ void ScriptExt::VariableBinaryOperationHandler(TeamClass* pTeam, int nVariable, pTeam->StepCompleted = true; } + +void ScriptExt::DebugAngerNodesData() +{ + Debug::Log("DEBUG: AngerNodes lists of every playable House:\n"); + + for (auto pHouse : *HouseClass::Array) + { + if (pHouse->IsObserver()) + Debug::Log("Player %d [Observer] ", pHouse->ArrayIndex); + else + Debug::Log("Player %d [%s]: ", pHouse->ArrayIndex, pHouse->Type->ID); + + int i = 0; + + for (auto& angerNode : pHouse->AngerNodes) + { + if (!pHouse->IsObserver()) + Debug::Log("%d:%d", angerNode.House->ArrayIndex, angerNode.AngerLevel); + + if (i < HouseClass::Array->Count - 2 && !pHouse->IsObserver()) + Debug::Log(", "); + + i++; + } + + if (!pHouse->IsObserver()) + Debug::Log(" -> Main Enemy House: %d\n", pHouse->EnemyHouseIndex); + else + Debug::Log("\n"); + } +} diff --git a/src/Ext/Script/Body.h b/src/Ext/Script/Body.h index 0dafe43877..34333a50d7 100644 --- a/src/Ext/Script/Body.h +++ b/src/Ext/Script/Body.h @@ -151,6 +151,7 @@ class ScriptExt static void SetTheMostHatedHouse(TeamClass* pTeam, int mask, int mode, bool random); static void OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode); static void AggroHouse(TeamClass* pTeam, int index); + static void DebugAngerNodesData(); static void VariablesHandler(TeamClass* pTeam, PhobosScripts eAction, int nArg); template From 412d7e74c9ec956d479a72b496f49944ffddb670 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Tue, 30 Nov 2021 00:52:36 +0100 Subject: [PATCH 16/48] Remove some useless comments --- src/Commands/ObjectInfo.h | 6 ++++-- src/Ext/Script/Body.cpp | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Commands/ObjectInfo.h b/src/Commands/ObjectInfo.h index 0ad5604501..2b75a671e7 100644 --- a/src/Commands/ObjectInfo.h +++ b/src/Commands/ObjectInfo.h @@ -224,7 +224,8 @@ class ObjectInfoCommandClass : public PhobosCommandClass append("\n"); display(); - ScriptExt::DebugAngerNodesData(); + + ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! }; auto printBuilding = [&append, &display](BuildingClass* pBuilding) @@ -264,7 +265,8 @@ class ObjectInfoCommandClass : public PhobosCommandClass append("Current Shield HP = (%d / %d)\n", pShieldData->GetHP(), pTypeShieldData->ShieldType->Strength); } display(); - ScriptExt::DebugAngerNodesData(); + + ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! }; bool dumped = false; diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index cfc7e808ac..43547ef1d9 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2406,7 +2406,8 @@ void ScriptExt::ResetAngerAgainstHouses(TeamClass* pTeam) } pTeam->Owner->EnemyHouseIndex = -1; - ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! + ScriptExt::DebugAngerNodesData(); + // This action finished pTeam->StepCompleted = true; // This action finished - FS-21 } @@ -2482,7 +2483,8 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); - ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! + ScriptExt::DebugAngerNodesData(); + // This action finished pTeam->StepCompleted = true; } @@ -2537,7 +2539,8 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); - ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! + ScriptExt::DebugAngerNodesData(); + // This action finished pTeam->StepCompleted = true; } @@ -3042,7 +3045,8 @@ void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); - ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! + ScriptExt::DebugAngerNodesData(); + // This action finished pTeam->StepCompleted = true; } @@ -3154,7 +3158,9 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) { Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house with index: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, index); } - ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! + + ScriptExt::DebugAngerNodesData(); + // This action finished pTeam->StepCompleted = true; } @@ -3372,7 +3378,7 @@ void ScriptExt::VariableBinaryOperationHandler(TeamClass* pTeam, int nVariable, void ScriptExt::DebugAngerNodesData() { - Debug::Log("DEBUG: AngerNodes lists of every playable House:\n"); + Debug::Log("DEBUG: Updated AngerNodes lists of every playable House:\n"); for (auto pHouse : *HouseClass::Array) { From c74d6484cc6fd40f82c18120a85eeb39cdac06ff Mon Sep 17 00:00:00 2001 From: FS-21 Date: Tue, 30 Nov 2021 12:30:52 +0100 Subject: [PATCH 17/48] improvement for unknown actions --- src/Ext/Script/Body.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 43547ef1d9..7ec3979d4d 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -181,7 +181,12 @@ void ScriptExt::ProcessAction(TeamClass* pTeam) break; default: // Do nothing because or it is a wrong Action number or it is an Ares/YR action... - //Debug::Log("[%s] [%s] %d = %d,%d\n", pTeam->Type->ID, pScriptType->ID, pScript->idxCurrentLine, currentLineAction->Action, currentLineAction->Argument); + if (action > 70 && !(action >= PhobosScripts::LocalVariableAdd && action <= PhobosScripts::GlobalVariableAndByGlobal)) + { + // Unknown new action. This action finished + pTeam->StepCompleted = true; + Debug::Log("[%s] [%s] (line %d): Unknown Script Action: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action); + } break; } From 08a9b81ebb72b38feea525bd64a42847af8360f5 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Mon, 27 Dec 2021 19:31:01 +0100 Subject: [PATCH 18/48] small fix --- src/Ext/Team/Body.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Ext/Team/Body.h b/src/Ext/Team/Body.h index 4f3be0e24f..a5e15b9ec3 100644 --- a/src/Ext/Team/Body.h +++ b/src/Ext/Team/Body.h @@ -25,14 +25,14 @@ class TeamExt int OnlyTargetHouseEnemyMode; ExtData(TeamClass* OwnerObject) : Extension(OwnerObject) - , WaitNoTargetAttempts(0) - , NextSuccessWeightAward(0) - , IdxSelectedObjectFromAIList(-1) - , CloseEnough(-1) - , Countdown_RegroupAtLeader(-1) - , AngerNodeModifier(5000) - , OnlyTargetHouseEnemy(false) - , OnlyTargetHouseEnemyMode(-1) + , WaitNoTargetAttempts { 0 } + , NextSuccessWeightAward { 0 } + , IdxSelectedObjectFromAIList { -1 } + , CloseEnough { -1 } + , Countdown_RegroupAtLeader { -1 } + , AngerNodeModifier { 5000 } + , OnlyTargetHouseEnemy { false } + , OnlyTargetHouseEnemyMode { -1 } { } virtual ~ExtData() = default; From aacdcc0ee83ab61405a1ca269e046bbc76abbf57 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Mon, 27 Dec 2021 19:35:29 +0100 Subject: [PATCH 19/48] Point to latest YRpp --- YRpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YRpp b/YRpp index 3106ec935b..ac18d0c5c2 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit 3106ec935b2da1bb49e7f7c2f4a7b46a59fedd7a +Subproject commit ac18d0c5c259d5138b16b5614c8656733a8450ae From ebb0e648b1df69d2a042e7c5172d890638abd075 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Fri, 14 Jan 2022 17:27:26 +0100 Subject: [PATCH 20/48] Update YYpr --- YRpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YRpp b/YRpp index ac18d0c5c2..7f02220962 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit ac18d0c5c259d5138b16b5614c8656733a8450ae +Subproject commit 7f022209628754f5b08999c25f6d56fbe88c0e3b From 0c93a2ee4aac2ba3294c7b73b11b5423b77c0dd6 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Fri, 14 Jan 2022 17:36:58 +0100 Subject: [PATCH 21/48] removing unnecessary lines --- src/Ext/Script/Body.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index a43feb7055..580ba18b16 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -809,13 +809,9 @@ void ScriptExt::Mission_Attack(TeamClass *pTeam, bool repeatAction = true, int c bool onlyTargetHouseEnemy = pTeam->Type->OnlyTargetHouseEnemy; - auto pTeamData = TeamExt::ExtMap.Find(pTeam); - if (pTeamData) + if (pTeamData->OnlyTargetHouseEnemyMode != -1) { - if (pTeamData->OnlyTargetHouseEnemyMode != -1) - { - onlyTargetHouseEnemy = pTeamData->OnlyTargetHouseEnemy; - } + onlyTargetHouseEnemy = pTeamData->OnlyTargetHouseEnemy; } if (!pFocus && !bAircraftsWithoutAmmo) From b4ac77ef5f56d2f0fe06fce4521329084ca970c2 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Fri, 4 Mar 2022 09:45:14 +0100 Subject: [PATCH 22/48] Point to latest YRpp --- YRpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YRpp b/YRpp index 7f02220962..edebf4aeb7 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit 7f022209628754f5b08999c25f6d56fbe88c0e3b +Subproject commit edebf4aeb7f173d151ffb10d158bbc3b25bcbf4b From 1b91d93e99d5c7ec4aefb26cfe13df9d497d589c Mon Sep 17 00:00:00 2001 From: FS-21 Date: Fri, 4 Mar 2022 13:06:16 +0100 Subject: [PATCH 23/48] Added AngerNodes documentation Documentation for Script Actions 114 to 123. --- README.md | 2 +- docs/New-or-Enhanced-Logics.md | 160 +++++++++++++++++++++++++++++++++ docs/Whats-New.md | 1 + src/Ext/Script/Body.cpp | 36 ++++---- 4 files changed, 180 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 4e1c7ff8cf..b93eede245 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ Credits - **secsome (SEC-SOME)** - debug info dump hotkey, refactoring & porting of Ares helper code, introducing more Ares-derived stuff, disguise removal warhead, Mind Control removal warhead, Mind Control enhancement, shields, AnimList.PickRandom, MoveToCell fix, unlimited waypoints, Build At trigger action buildup anim fix, Undeploy building into a unit plays `EVA_NewRallyPointEstablished` fix, custom ore gathering anim, TemporaryClass related crash, Retry dialog on mission failure, Default disguise for individual InfantryTypes, PowerPlant Enhancer, SaveGame Trigger Action, QuickSave command, Numeric variables, Custom gravity for projectiles, Retint map actions bugfix, Sharpnel enhancement - **Otamaa (Fahroni, BoredEXE)** - help with CellSpread, ported and fixed custom RadType code, togglable ElectricBolt bolts, customizable Chrono Locomotor properties per TechnoClass, DebrisMaximums fixes, Anim-to-Unit, NotHuman anim sequences improvements, Customizable OpenTopped Properties, hooks for ScriptType Actions 92 & 93, ore stage threshold for `HideIfNoOre`, occupied building `MuzzleFlashX` bugfix,`EnemyUIName=` for other TechnoTypes, TerrainType `DestroyAnim` & `DestroySound` - **E1 Elite** - TileSet 255 and above bridge repair fix -- **FS-21** - Dump Object Info enhancements, Powered.KillSpawns, Spawner.LimitRange, ScriptType Actions 71 to 113, MC deployer fixes, help with docs, Automatic Passenger Deletion, Fire SW At Location Trigger Action, Fire SW At Waypoint Trigger Action, Kill Object Automatically, Customize resource storage, Override Uncloaked Underwater attack behavior, AI Aircraft docks fix, Shared Ammo +- **FS-21** - Dump Object Info enhancements, Powered.KillSpawns, Spawner.LimitRange, ScriptType Actions 71 to 123, MC deployer fixes, help with docs, Automatic Passenger Deletion, Fire SW At Location Trigger Action, Fire SW At Waypoint Trigger Action, Kill Object Automatically, Customize resource storage, Override Uncloaked Underwater attack behavior, AI Aircraft docks fix, Shared Ammo - **AutoGavy** - interceptor logic, warhead critical damage system, Customize resource storage - **ChrisLv_CN** - interceptor logic, LaserTrails, laser fixes, general assistance (work relicensed under [following permission](images/ChrisLv-relicense.png)) - **Xkein** - general assistance, YRpp edits diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 0359ced4ef..b34d9854d1 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1148,6 +1148,166 @@ In `aimd.ini`: x=113,n ; where 0 > n <= 100 ``` +### `114` Set House hate value modifier + +- Affects how much hate applies to a selected house (depends of the script action). This anger value is applied only inside the scriptType of the Team. +- Positive values increase hate and negative values decrease hate. +- Affects Script Actions: 116, 117, 118, 119, 120 & 121. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=114,n ; integer n=0 +``` + +### `115` Override OnlyTargetHouseEnemy value + +- The value of the tag `OnlyTargetHouseEnemy` in AI Triggers can be modified for the new Attack & Move actions. Only affects the next new attack or move action script. +- These anger values are applied only in the House owner of the team. +- Only works for new Phobos Actions, not vanilla YR or Ares actions. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=115,n ; integer n=-1 +``` + +- The possible argument values are: + +| *Argument* | *Description* | +| :------: | :-------------------------------------------: | +| -1 | Use default value specified in `OnlyTargetHouseEnemy` | +| 0 | Force `OnlyTargetHouseEnemy` value to FALSE | +| 1 | Force `OnlyTargetHouseEnemy` value to TRUE | +| 2 | Force `OnlyTargetHouseEnemy` value to TRUE or FALSE randomly | + +### `116` Modify House hate using House index + +- Modifies the Team's hate towards a specific house using its House index. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=116,n ; integer n >= 0 +``` + +### `117` Modify hate values from a list of Countries + +- The House Team picks a list of countries from the `rulesmd.ini` section called `[AIHousesList]`. +- The House Team modify the hate towards all Houses in the map that use the countries in that list. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=117,n ; integer n >= 0 +``` + +The second parameter is a 0-based index for the `AIHousesList` section that specifies the list of possible `Countries` that can be evaluated. The new `AIHousesList` section must be declared in `rulesmd.ini` for making this script work: + +In `rulesmd.ini`: +```ini +[AIHousesList] ; List of Countries lists +0=SOMECOUNTRY,SOMEOTHERCOUNTRY,SAMPLECOUNTRY +1=ANOTHERCOUNTRY,YETANOTHERCOUNTRY +; ... +``` + +### `118` Modify hate value against a random Country from a list of Countries + +- Like action 117 but the House owner of the Team only picks 1 house randomly from the specified list of countries. +- The House Team modify the hate towards all Houses in the map that use the selected country. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=118,n ; integer n >= 0 +``` + +### `119` Set the most hated House ("<" comparison) + +- Increases the Team House hate against an enemy House making that enemy House as the main target. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=119,n ; integer +``` + +The possible argument values are: + +| *Argument* | *Description* | +| :------: | :-------------------------------------------: | +| -7 | The House with less house kills is selected | +| -6 | The House with less free power (free = production - consumption) is selected | +| -5 | The House with less power production is selected | +| -4 | The House with less power consumption is selected | +| -3 | The nearest enemy Human base is selected | +| -2 | The poorest House is selected | +| -1 | The enemy House with nearest unit to the Team Leader is selected | +| > 0 | *Target Type#* index. The House with less threat of the selected *Target Type#* (sum of all the units of the same checked type * threat value) | + +### `120` Set the most hated House (">" comparison) + +- Increases the Team House hate against an enemy House making that enemy House as the main target. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=120,n ; integer +``` + +The possible argument values are: + +| *Argument* | *Description* | +| :------: | :-------------------------------------------: | +| -7 | The House with more house kills is selected | +| -6 | The House with more free power (free = production - consumption) is selected | +| -5 | The House with more power production is selected | +| -4 | The House with more power consumption is selected | +| -3 | The farthest enemy Human base is selected | +| -2 | The richest House is selected | +| -1 | The enemy House with farthest unit to the Team Leader is selected | +| > 0 | *Target Type#* index. The House with more threat of the selected *Target Type#* (sum of all the units of the same checked type * threat value) | + +### `121` Set the most hated House randomly + +- Increases the Team House hate against an enemy House picked randomly. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=121,0 +``` + +### `122` Reset hate against other Houses + +- All hate levels in the Team House against every House are set to 0. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=122,0 +``` + +### `123` Set a House as the most hated House of the map + +- A House will become the most hated House of the map (the effects are only visible if the other houses are enemies of the selected house) + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=123,n ; integer +``` + +The possible argument values are: + +| *Argument* | *Description* | +| :------: | :-------------------------------------------: | +| -3 | All Human players will be hated by everyone | +| -2 | The Team House will be the most hated by everyone (allies remain allies) | +| -1 | Selects a random House. The own House is excluded in the selection of the most hated by everyone | +| >= 0 | House index that will be hated by everyone | + ### `500 - 523` Edit Variable - Operate a variable's value - The variable's value type is int16 instead of int32 in trigger actions for some reason, which means it ranges from -2^15 to 2^15-1. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 7205fc38f0..f6fcb978b7 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -251,6 +251,7 @@ New: - Script Action 111 that un-register Team success, is just the opposite effect of Action 49 (by FS-21) - Script Action 112 to regroup temporarily around the Team Leader (by FS-21) - Script Action 113 to Randomly Skip Next Action (by FS-21) +- Script Action 114 to 123 that modifies the anger values of Houses (by FS-21) - ObjectInfo now shows current Target and AI Trigger data (by FS-21) - Shield absorption and passthrough customization (by Morton) - Limbo Delivery of buildings (by Morton) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 1f723167a1..9277669271 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2839,7 +2839,7 @@ void ScriptExt::SetHouseAngerModifier(TeamClass* pTeam, int modifier = 0) } if (modifier <= 0) - modifier = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + modifier = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; if (modifier < 0) modifier = 0; @@ -2863,7 +2863,7 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) } if (idxHousesList <= 0) - idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; if (idxHousesList >= 0) { @@ -2894,7 +2894,7 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) if (changeFailed) { pTeam->StepCompleted = true; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify hate values against other houses\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify hate values against other houses\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument); } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); @@ -2917,7 +2917,7 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList } if (idxHousesList <= 0) - idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; if (idxHousesList >= 0) { @@ -2950,7 +2950,7 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList if (changes == 0) { pTeam->StepCompleted = true; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify hate values against other houses\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify hate values against other houses\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument); } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); @@ -2972,7 +2972,7 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = } if (mask == 0) - mask = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + mask = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; if (mask == 0) { @@ -3038,7 +3038,7 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = if (angerNode.House == selectedHouse) { angerNode.AngerLevel = newHateLevel; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Picked a new house as enemy [%s]\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNode.House->Type->ID); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Picked a new house as enemy [%s]\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, angerNode.House->Type->ID); } } @@ -3046,7 +3046,7 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = } else { - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument); } // This action finished @@ -3142,7 +3142,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); return enemyHouse; } @@ -3188,7 +3188,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); return enemyHouse; } @@ -3238,7 +3238,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); return enemyHouse; } @@ -3280,7 +3280,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); return enemyHouse; } @@ -3372,7 +3372,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); return enemyHouse; } @@ -3388,7 +3388,7 @@ void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) } if (mode < 0 || mode > 2) - mode = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + mode = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; if (mode < -1 || mode > 2) mode = -1; @@ -3422,7 +3422,7 @@ void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) break; } - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): New Team -> OnlyTargetHouseEnemy value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, pTeamData->OnlyTargetHouseEnemy); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): New Team -> OnlyTargetHouseEnemy value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, pTeamData->OnlyTargetHouseEnemy); // This action finished pTeam->StepCompleted = true; } @@ -3439,7 +3439,7 @@ void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) } if (idxHouse < 0) - idxHouse = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument; + idxHouse = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; if (idxHouse < 0) { @@ -3454,7 +3454,7 @@ void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) if (angerNode.House->ArrayIndex == idxHouse && !angerNode.House->Defeated) { angerNode.AngerLevel += pTeamData->AngerNodeModifier; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Modified anger level against [%s](index: %d) with value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Modified anger level against [%s](index: %d) with value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); } } } @@ -3571,7 +3571,7 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) } else { - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house with index: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->idxCurrentLine, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->idxCurrentLine].Argument, index); + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house with index: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, index); } ScriptExt::DebugAngerNodesData(); From 138b2c3b40e86d69ee32c7b43824997fc6d7fe7f Mon Sep 17 00:00:00 2001 From: FS-21 Date: Fri, 4 Mar 2022 13:14:57 +0100 Subject: [PATCH 24/48] Small information change in action 114 --- docs/New-or-Enhanced-Logics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index b34d9854d1..92f835321a 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1150,7 +1150,7 @@ x=113,n ; where 0 > n <= 100 ### `114` Set House hate value modifier -- Affects how much hate applies to a selected house (depends of the script action). This anger value is applied only inside the scriptType of the Team. +- Affects how much hate applies to a selected house (depends of the script action). - Positive values increase hate and negative values decrease hate. - Affects Script Actions: 116, 117, 118, 119, 120 & 121. From 007cffa75306f2d05a710aa800de22cc5211997a Mon Sep 17 00:00:00 2001 From: FS-21 Date: Wed, 9 Mar 2022 23:44:28 +0100 Subject: [PATCH 25/48] Point to latest YRpp --- YRpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YRpp b/YRpp index edebf4aeb7..1b9bc20b9c 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit edebf4aeb7f173d151ffb10d158bbc3b25bcbf4b +Subproject commit 1b9bc20b9ce14713647c68373557bdd791dba633 From aafa7f81a53ca6b41ff063d07fa99d4318dbf607 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Thu, 7 Apr 2022 18:36:34 +0200 Subject: [PATCH 26/48] point to latest YRpp --- YRpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YRpp b/YRpp index 1b9bc20b9c..b65374a683 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit 1b9bc20b9ce14713647c68373557bdd791dba633 +Subproject commit b65374a6836aaf7ff6df9e57bcda7aa6a13b4a6b From 7dc644a3e3dc4f7e720f5b8cb163ff57c2d30628 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sat, 9 Apr 2022 17:30:47 +0200 Subject: [PATCH 27/48] Added 3 new comparisons for selecting the most hated house: -8 ===> The enemy House with more/less naval units is selected. -9 ===> The enemy House with more/less aircraft docks is selected. -10 ===> The enemy House with more/less factories is selected (excluded the aircraft factories). --- docs/New-or-Enhanced-Logics.md | 8 +- src/Ext/Script/Body.cpp | 142 +++++++++++++++++++++++++++++++++ src/Ext/Script/Body.h | 3 +- 3 files changed, 151 insertions(+), 2 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 753148e396..b663b664aa 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1259,6 +1259,9 @@ The possible argument values are: | *Argument* | *Description* | | :------: | :-------------------------------------------: | +| -10 | The House with less factories is selected (excluded the aircraft factories) | +| -9 | The House with less aircraft docks is selected | +| -8 | The House with less naval units is selected | | -7 | The House with less house kills is selected | | -6 | The House with less free power (free = production - consumption) is selected | | -5 | The House with less power production is selected | @@ -1282,7 +1285,10 @@ The possible argument values are: | *Argument* | *Description* | | :------: | :-------------------------------------------: | -| -7 | The House with more house kills is selected | +| -10 | The House with more factories is selected (excluded the aircraft factories) | +| -9 | The House with more aircraft docks is selected | +| -8 | The House with more naval units is selected | +| -7 | The House with more kills is selected | | -6 | The House with more free power (free = production - consumption) is selected | | -5 | The House with more power production is selected | | -4 | The House with more power consumption is selected | diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index e8a0da9277..98b39f2839 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -3095,6 +3095,9 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int long houseMoney = -1; int enemyPower = -1000000000; int enemyKills = -1; + int enemyAirDocks = -1; + int enemyStructures = -1; + int enemyNavalUnits = -1; if (mask == -2) { @@ -3274,6 +3277,145 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int return enemyHouse; } + if (mask == -8) + { + // Based on number of House naval units + for (auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse + || pHouse->IsObserver() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + { + continue; + } + + int currentNavalUnits = 0; + + for (auto& pUnit : *TechnoClass::Array) + { + if (pUnit->IsAlive + && pUnit->Health > 0 + && pUnit->Owner == pHouse + && !pUnit->InLimbo + && pUnit->IsOnMap + && ScriptExt::EvaluateObjectWithMask(pUnit, 31, -1, -1, nullptr)) + { + currentNavalUnits++; + } + } + + if (mode == 0) + { + // The House with less naval units is selected + if (currentNavalUnits < enemyNavalUnits || enemyNavalUnits < 0) + { + enemyNavalUnits = currentNavalUnits; + enemyHouse = pHouse; + } + } + else + { + // The House with more naval units is selected + if (currentNavalUnits > enemyNavalUnits || enemyNavalUnits < 0) + { + enemyNavalUnits = currentNavalUnits; + enemyHouse = pHouse; + } + } + } + + if (enemyHouse) + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + + return enemyHouse; + } + + if (mask == -9) + { + // Based on number of House aircraft docks + for (auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse + || pHouse->IsObserver() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + { + continue; + } + + int currentAirDocks = pHouse->AirportDocks; + + if (mode == 0) + { + // The House with less Aircraft docks is selected + if (currentAirDocks < enemyAirDocks || enemyAirDocks < 0) + { + enemyAirDocks = currentAirDocks; + enemyHouse = pHouse; + } + } + else + { + // The House with more Aircraft docks is selected + if (currentAirDocks > enemyAirDocks || enemyAirDocks < 0) + { + enemyAirDocks = currentAirDocks; + enemyHouse = pHouse; + } + } + } + + if (enemyHouse) + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + + return enemyHouse; + } + + if (mask == -10) + { + // Based on number of House factories (except aircraft factories) + for (auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse + || pHouse->IsObserver() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + { + continue; + } + + int currentFactories = pHouse->NumWarFactories + pHouse->NumConYards + pHouse->NumShipyards + pHouse->NumBarracks; + + if (mode == 0) + { + // The House with less factories is selected + if (currentFactories < enemyStructures || enemyStructures < 0) + { + enemyStructures = currentFactories; + enemyHouse = pHouse; + } + } + else + { + // The House with more factories is selected + if (currentFactories > enemyStructures || enemyStructures < 0) + { + enemyStructures = currentFactories; + enemyHouse = pHouse; + } + } + } + + if (enemyHouse) + Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); + + return enemyHouse; + } + // Depending the mode check what house will be selected as the most hated for (auto pTechno : *TechnoClass::Array) { diff --git a/src/Ext/Script/Body.h b/src/Ext/Script/Body.h index 2f855369f0..60e12af443 100644 --- a/src/Ext/Script/Body.h +++ b/src/Ext/Script/Body.h @@ -212,6 +212,7 @@ class ScriptExt static void SetTheMostHatedHouse(TeamClass* pTeam, int mask, int mode, bool random); static void OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode); static void AggroHouse(TeamClass* pTeam, int index); + static HouseClass* GetTheMostHatedHouse(TeamClass* pTeam, int mask, int mode); static void DebugAngerNodesData(); static bool IsExtVariableAction(int action); @@ -227,6 +228,6 @@ class ScriptExt private: static void ModifyCurrentTriggerWeight(TeamClass* pTeam, bool forceJumpLine, double modifier); static bool MoveMissionEndStatus(TeamClass* pTeam, TechnoClass* pFocus, FootClass* pLeader, int mode); - static HouseClass* GetTheMostHatedHouse(TeamClass* pTeam, int mask, int mode); + static void UpdateEnemyHouseIndex(HouseClass* pHouse); }; From 46ae6ed7ba5dca0d79f169f78c22a4bf189e7e84 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sun, 10 Apr 2022 23:05:56 +0200 Subject: [PATCH 28/48] point to latest YRpp --- YRpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YRpp b/YRpp index b65374a683..93d3d54fc3 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit b65374a6836aaf7ff6df9e57bcda7aa6a13b4a6b +Subproject commit 93d3d54fc352378fcc8d1da4e1d2c41074d8f63f From a680fccd84e3bc04d3a06bf2fe61dfaeb47b73a2 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Mon, 17 Oct 2022 22:36:48 +0200 Subject: [PATCH 29/48] Point to latest YRpp --- YRpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YRpp b/YRpp index 5676ca549e..a41eb1a449 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit 5676ca549e93e3276d1a4721a0f0f3b78e515f28 +Subproject commit a41eb1a4491f8256459a1c3e4a25af5ebded45db From 0dcecfe38f94921b615791326433a960d4664627 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Tue, 18 Oct 2022 00:44:30 +0200 Subject: [PATCH 30/48] updated documentation and other missing bits Renamed actions: OverrideOnlyTargetHouseEnemy = 115 -> 14005, SetHouseAngerModifier = 114 -> 14006, ModifyHateHouseIndex = 116 -> 14007, ModifyHateHousesList = 117 -> 14008, ModifyHateHousesList1Random = 118 -> 14009, SetTheMostHatedHouseMinorNoRandom = 119 -> 14010, SetTheMostHatedHouseMajorNoRandom = 120 -> 14011, SetTheMostHatedHouseRandom = 121 -> 14012, ResetAngerAgainstHouses = 122 -> 14013, AggroHouse = 123 -> 14014, --- CREDITS.md | 1 + docs/AI-Scripting-and-Mapping.md | 166 +++++++++++++++++++++++++++++++ docs/Whats-New.md | 1 + src/Ext/Script/Body.h | 10 ++ 4 files changed, 178 insertions(+) diff --git a/CREDITS.md b/CREDITS.md index 89e50dfecc..8466055c52 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -118,6 +118,7 @@ This page lists all the individual contributions to the project by their author. - Shared ammo logic - Customizable FLH when infantry is prone or deployed - Initial strength for cloned infantry + - Script actions for modifying AI anger against other houses - **Starkku**: - Warhead shield penetration & breaking - Strafing aircraft weapon customization diff --git a/docs/AI-Scripting-and-Mapping.md b/docs/AI-Scripting-and-Mapping.md index 50ab2899d8..27e726181d 100644 --- a/docs/AI-Scripting-and-Mapping.md +++ b/docs/AI-Scripting-and-Mapping.md @@ -252,6 +252,172 @@ In `aimd.ini`: x=14003,0 ``` +### `14005` Override OnlyTargetHouseEnemy Value + +- The value of the tag `OnlyTargetHouseEnemy` in AI triggers can be modified for the new attack & move actions. Only affects the next new attack or move action script. +- These anger values are applied only in the house owner of the team. +- Only works for new Phobos actions, not vanilla YR or Ares actions. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=14005,n ; integer n=-1 +``` + +- The possible argument values are: + +| *Argument* | *Description* | +| :--------: | :-------------------------------------------: | +| -1 | Use default value specified in `OnlyTargetHouseEnemy` | +| 0 | Force `OnlyTargetHouseEnemy` value to `FALSE` | +| 1 | Force `OnlyTargetHouseEnemy` value to `TRUE` | +| 2 | Force `OnlyTargetHouseEnemy` value to `TRUE` or `FALSE` randomly | + +### `14006` Set House Hate Value Modifier + +- Affects how much hate applies to a selected house (depends of the script action). +- Positive values increase hate and negative values decrease hate. +- Affects script actions: `14007`, `14008`, `14009`, `14010`, `14011` & `14012`. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=14006,n ; integer n=0 +``` + +### `14007` Modify House Hate Using House Index + +- Modifies the team's hate towards a specific house using its house index. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=14007,n ; integer n >= 0 +``` + +### `14008` Modify Hate Values From A List Of Countries + +- The house team picks a list of countries from the `rulesmd.ini` section called `[AIHousesList]`. +- The house team modify the hate towards all houses in the map that use the countries in that list. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=14008,n ; integer n >= 0 +``` + +The second parameter is a 0-based index for the `AIHousesList` section that specifies the list of possible `Countries` that can be evaluated. The new `AIHousesList` section must be declared in `rulesmd.ini` for making this script work: + +In `rulesmd.ini`: +```ini +[AIHousesList] ; List of Countries lists +0=SOMECOUNTRY,SOMEOTHERCOUNTRY,SAMPLECOUNTRY +1=ANOTHERCOUNTRY,YETANOTHERCOUNTRY +; ... +``` + +### `14009` Modify Hate Value Against A Random Country From A List Of Countries + +- Like action `14008` but the house owner of the Team only picks 1 house randomly from the specified list of countries. +- The house team modify the hate towards all houses in the map that use the selected country. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=14009,n ; integer n >= 0 +``` + +### `14010` Set The Most Hated House ("<" Comparison) + +- Increases the team house hate against an enemy house making that enemy house as the main target. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=14010,n ; integer +``` + +The possible argument values are: + +| *Argument* | *Description* | +| :------: | :-------------------------------------------: | +| -10 | The house with less factories is selected (excluded the aircraft factories) | +| -9 | The house with less aircraft docks is selected | +| -8 | The house with less naval units is selected | +| -7 | The house with less house kills is selected | +| -6 | The house with less free power (free = production - consumption) is selected | +| -5 | The house with less power production is selected | +| -4 | The house with less power consumption is selected | +| -3 | The nearest enemy Human base is selected | +| -2 | The poorest house is selected | +| -1 | The enemy house with nearest unit to the Team Leader is selected | +| > 0 | *Target Type#* index. The house with less threat of the selected *Target Type#* (sum of all the units of the same checked type * threat value) | + +### `14011` Set The Most Hated House (">" Comparison) + +- Increases the team house hate against an enemy house making that enemy house as the main target. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=14011,n ; integer +``` + +The possible argument values are: + +| *Argument* | *Description* | +| :--------: | :-------------------------------------------: | +| -10 | The house with more factories is selected (excluded the aircraft factories) | +| -9 | The house with more aircraft docks is selected | +| -8 | The house with more naval units is selected | +| -7 | The house with more kills is selected | +| -6 | The house with more free power (free = production - consumption) is selected | +| -5 | The house with more power production is selected | +| -4 | The house with more power consumption is selected | +| -3 | The farthest enemy Human base is selected | +| -2 | The richest house is selected | +| -1 | The enemy house with farthest unit to the Team Leader is selected | +| > 0 | *Target Type#* index. The house with more threat of the selected *Target Type#* (sum of all the units of the same checked type * threat value) | + +### `14012` Set The Most Hated House Randomly + +- Increases the Team house hate against an enemy house picked randomly. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=14012,0 +``` + +### `14013` Reset Hate Against Other Houses + +- All hate levels in the team house against every House are set to 0. + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=14013,0 +``` + +### `14014` Set A House As The Most Hated House Of The Map + +- A House will become the most hated House of the map (the effects are only visible if the other houses are enemies of the selected house) + +In `aimd.ini`: +```ini +[SOMESCRIPTTYPE] ; ScriptType +x=14014,n ; integer +``` + +The possible argument values are: + +| *Argument* | *Description* | +| :--------: | :-------------------------------------------: | +| -3 | All Human players will be hated by everyone | +| -2 | The Team House will be the most hated by everyone (allies remain allies) | +| -1 | Selects a random House. The own House is excluded in the selection of the most hated by everyone | +| >= 0 | House index that will be hated by everyone | + ### `16000-16999` Flow Control #### `16000` Start a Timed Jump to the Same Line diff --git a/docs/Whats-New.md b/docs/Whats-New.md index e2728bd566..1d8a07a31f 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -303,6 +303,7 @@ New: - Script action to regroup temporarily around the Team Leader (by FS-21) - Script action to randomly skip next action (by FS-21) - Script action for timed script action jumps (by FS-21) +- Script action for modifying AI anger against other houses (by FS-21) - ObjectInfo now shows current Target and AI Trigger data (by FS-21) - Shield absorption and passthrough customization (by Morton) - Limbo Delivery of buildings (by Morton) diff --git a/src/Ext/Script/Body.h b/src/Ext/Script/Body.h index 446c01a91f..dafa84e052 100644 --- a/src/Ext/Script/Body.h +++ b/src/Ext/Script/Body.h @@ -68,6 +68,16 @@ enum class PhobosScripts : unsigned int IncreaseCurrentAITriggerWeight = 14001, DecreaseCurrentAITriggerWeight = 14002, UnregisterGreatSuccess = 14003, + OverrideOnlyTargetHouseEnemy = 14005, + SetHouseAngerModifier = 14006, + ModifyHateHouseIndex = 14007, + ModifyHateHousesList = 14008, + ModifyHateHousesList1Random = 14009, + SetTheMostHatedHouseMinorNoRandom = 14010, + SetTheMostHatedHouseMajorNoRandom = 14011, + SetTheMostHatedHouseRandom = 14012, + ResetAngerAgainstHouses = 14013, + AggroHouse = 14014, // Range 16000-16999 are flow control actions (jumps, change script, loops, breaks, etc) SameLineForceJumpCountdown = 16000, From bbe08b1cd7d97e39a7cdcc660f6d0a2c344d438c Mon Sep 17 00:00:00 2001 From: FS-21 Date: Tue, 18 Oct 2022 00:47:06 +0200 Subject: [PATCH 31/48] Extra debug info Will be removed before the final merge. --- src/Commands/ObjectInfo.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Commands/ObjectInfo.cpp b/src/Commands/ObjectInfo.cpp index 4a966b77e1..476c6b5a1d 100644 --- a/src/Commands/ObjectInfo.cpp +++ b/src/Commands/ObjectInfo.cpp @@ -13,6 +13,7 @@ #include #include +#include const char* ObjectInfoCommandClass::GetName() const { @@ -205,6 +206,7 @@ void ObjectInfoCommandClass::Execute(WWKey eInput) const append("\n"); display(); + ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! }; auto printBuilding = [&append, &display](BuildingClass* pBuilding) @@ -253,6 +255,7 @@ void ObjectInfoCommandClass::Execute(WWKey eInput) const append("Current Shield HP = (%d / %d)\n", pShieldData->GetHP(), pTechnoExt->CurrentShieldType->Strength); display(); + ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! }; bool dumped = false; From b3d71ce3f7f0ed260f226b4e1937cb2041c71035 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Tue, 18 Oct 2022 00:57:27 +0200 Subject: [PATCH 32/48] small fix due to YRpp changes --- src/Ext/Script/Body.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index cdd7540cb4..9dfd3ce4fd 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -3176,7 +3176,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int for (auto& pHouse : *HouseClass::Array) { if (pLeaderUnit->Owner == pHouse - || !pHouse->ControlledByHuman() + || !pHouse->IsControlledByHuman() || pHouse->Defeated || pHouse->Type->MultiplayPassive || pLeaderUnit->Owner->IsAlliedWith(pHouse)) @@ -3662,7 +3662,7 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) if (!pTeam->Owner->Defeated && !pTeam->Owner->Type->MultiplayPassive && !pTeam->Owner->IsObserver() - && !pTeam->Owner->ControlledByHuman()) + && !pTeam->Owner->IsControlledByHuman()) { objectsList.AddItem(pTeam->Owner); } @@ -3714,7 +3714,7 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) { if (index == -3) { - if (angerNode.House->ControlledByHuman()) + if (angerNode.House->IsControlledByHuman()) { angerNode.AngerLevel = highestHateLevel + newHateLevel; } From d904d71dfac919f8b6393c1659dc7c44fc76a04b Mon Sep 17 00:00:00 2001 From: FS-21 Date: Tue, 18 Oct 2022 01:00:43 +0200 Subject: [PATCH 33/48] . --- docs/AI-Scripting-and-Mapping.md | 2 +- src/Ext/Script/Body.cpp | 8 ++++---- src/Ext/Script/Body.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/AI-Scripting-and-Mapping.md b/docs/AI-Scripting-and-Mapping.md index 27e726181d..5ae121c597 100644 --- a/docs/AI-Scripting-and-Mapping.md +++ b/docs/AI-Scripting-and-Mapping.md @@ -255,7 +255,7 @@ x=14003,0 ### `14005` Override OnlyTargetHouseEnemy Value - The value of the tag `OnlyTargetHouseEnemy` in AI triggers can be modified for the new attack & move actions. Only affects the next new attack or move action script. -- These anger values are applied only in the house owner of the team. +- These anger values are applied only in the house owner of the team. - Only works for new Phobos actions, not vanilla YR or Ares actions. In `aimd.ini`: diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 9dfd3ce4fd..129bac59ab 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -3135,7 +3135,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int // Based on House economy for (auto& pHouse : *HouseClass::Array) { - if (pLeaderUnit->Owner == pHouse + if (pLeaderUnit->Owner == pHouse || pHouse->IsObserver() || pHouse->Defeated || pHouse->Type->MultiplayPassive @@ -3659,7 +3659,7 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) // Include the own House if we are looking for ANY Human player if (index == -3) { - if (!pTeam->Owner->Defeated + if (!pTeam->Owner->Defeated && !pTeam->Owner->Type->MultiplayPassive && !pTeam->Owner->IsObserver() && !pTeam->Owner->IsControlledByHuman()) @@ -3749,8 +3749,8 @@ void ScriptExt::UpdateEnemyHouseIndex(HouseClass* pHouse) for (auto& angerNode : pHouse->AngerNodes) { - if (!angerNode.House->Defeated - && !pHouse->IsAlliedWith(angerNode.House) + if (!angerNode.House->Defeated + && !pHouse->IsAlliedWith(angerNode.House) && angerNode.AngerLevel > angerLevel) { angerLevel = angerNode.AngerLevel; diff --git a/src/Ext/Script/Body.h b/src/Ext/Script/Body.h index dafa84e052..9f7193424d 100644 --- a/src/Ext/Script/Body.h +++ b/src/Ext/Script/Body.h @@ -245,6 +245,6 @@ class ScriptExt private: static void ModifyCurrentTriggerWeight(TeamClass* pTeam, bool forceJumpLine, double modifier); static bool MoveMissionEndStatus(TeamClass* pTeam, TechnoClass* pFocus, FootClass* pLeader, int mode); - + static void UpdateEnemyHouseIndex(HouseClass* pHouse); }; From 0034449ed815210fe94f377776b0400ec94843b9 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Mon, 5 Dec 2022 17:47:25 +0100 Subject: [PATCH 34/48] Fixed bug Insta-win in Campaign maps. --- src/Ext/Rules/Body.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index e351960715..820726e7ce 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -155,8 +155,9 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) for (char *cur = strtok_s(Phobos::readBuffer, Phobos::readDelims, &context); cur; cur = strtok_s(nullptr, Phobos::readDelims, &context)) { - HouseTypeClass* pNewHouse = GameCreate(cur); - objectsList.AddItem(pNewHouse); + HouseTypeClass* pNewHouse = HouseTypeClass::Find(cur);//GameCreate(cur); + if (pNewHouse) + objectsList.AddItem(pNewHouse); } AIHousesLists.AddItem(objectsList); From 60782ac6ddaac69ae337fb27f57136f283079f99 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sun, 12 Feb 2023 17:19:43 +0100 Subject: [PATCH 35/48] Compilation fixes --- YRpp | 2 +- src/Ext/Rules/Body.cpp | 9 ++++----- src/Ext/Rules/Body.h | 2 +- src/Ext/Script/Body.cpp | 21 +++++++++------------ 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/YRpp b/YRpp index a41eb1a449..e3ed03ebf1 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit a41eb1a4491f8256459a1c3e4a25af5ebded45db +Subproject commit e3ed03ebf10893c7f24e311e8171a99818dab7fb diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index 8a60973c57..520b2b9d3f 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -153,7 +153,7 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) int houseItemsCount = pINI->GetKeyCount(sectionAIHousesList); for (int i = 0; i < houseItemsCount; ++i) { - DynamicVectorClass objectsList; + std::vector objectsList; char* context = nullptr; pINI->ReadString(sectionAIHousesList, pINI->GetKeyName(sectionAIHousesList, i), "", Phobos::readBuffer); @@ -162,11 +162,10 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) { HouseTypeClass* pNewHouse = HouseTypeClass::Find(cur);//GameCreate(cur); if (pNewHouse) - objectsList.AddItem(pNewHouse); + objectsList.emplace_back(pNewHouse); } - AIHousesLists.AddItem(objectsList); - objectsList.Clear(); + AIHousesLists.emplace_back(objectsList); } } @@ -198,6 +197,7 @@ void RulesExt::ExtData::Serialize(T& Stm) Stm .Process(this->AITargetTypesLists) .Process(this->AIScriptsLists) + .Process(this->AIHousesLists) .Process(this->HarvesterTypes) .Process(this->Storage_TiberiumIndex) .Process(this->InfantryGainSelfHealCap) @@ -209,7 +209,6 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->RadHasInvoker) .Process(this->JumpjetCrash) .Process(this->JumpjetNoWobbles) - .Process(this->AIHousesLists) .Process(this->MissingCameo) .Process(this->PlacementGrid_Translucency) .Process(this->PlacementPreview) diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h index 8d7df444fc..6c71498922 100644 --- a/src/Ext/Rules/Body.h +++ b/src/Ext/Rules/Body.h @@ -27,7 +27,7 @@ class RulesExt public: std::vector> AITargetTypesLists; std::vector> AIScriptsLists; - DynamicVectorClass> AIHousesLists; + std::vector> AIHousesLists; ValueableVector HarvesterTypes; Valueable Storage_TiberiumIndex; diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 8959cb4d66..8532637b8b 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2326,13 +2326,10 @@ TechnoClass* ScriptExt::FindBestObject(TechnoClass* pTechno, int method, int cal if (pTeamData) { if (pTeamData->OnlyTargetHouseEnemyMode != -1) - { onlyTargetHouseEnemy = pTeamData->OnlyTargetHouseEnemy; - } } - if (onlyTargetHouseEnemy - && enemyHouseIndex >= 0) + if (onlyTargetHouseEnemy && enemyHouseIndex >= 0) enemyHouse = HouseClass::Array->GetItem(enemyHouseIndex); } } @@ -2897,11 +2894,11 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) if (idxHousesList >= 0) { - if (idxHousesList < RulesExt::Global()->AIHousesLists.Count) + if (idxHousesList < RulesExt::Global()->AIHousesLists.size()) { - DynamicVectorClass objectsList = RulesExt::Global()->AIHousesLists.GetItem(idxHousesList); + std::vector objectsList = RulesExt::Global()->AIHousesLists.at(idxHousesList); - if (objectsList.Count > 0) + if (objectsList.size() > 0) { for (auto pHouseType : objectsList) { @@ -2951,13 +2948,13 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList if (idxHousesList >= 0) { - if (idxHousesList < RulesExt::Global()->AIHousesLists.Count) + if (idxHousesList < RulesExt::Global()->AIHousesLists.size()) { - DynamicVectorClass objectsList = RulesExt::Global()->AIHousesLists.GetItem(idxHousesList); - if (objectsList.Count > 0) + std::vector objectsList = RulesExt::Global()->AIHousesLists.at(idxHousesList); + if (objectsList.size() > 0) { - int IdxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.Count - 1); - HouseTypeClass* pHouseType = objectsList.GetItem(IdxSelectedObject); + int IdxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.size() - 1); + HouseTypeClass* pHouseType = objectsList.at(IdxSelectedObject); for (auto& angerNode : pTeam->Owner->AngerNodes) { From f76fd7bf8c4a22a7d17321b67f2f1b8aed0d1908 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sun, 12 Feb 2023 23:34:15 +0100 Subject: [PATCH 36/48] Tweaks --- src/Ext/Script/Body.cpp | 76 ++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index 8532637b8b..d2354133d5 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2894,13 +2894,13 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) if (idxHousesList >= 0) { - if (idxHousesList < RulesExt::Global()->AIHousesLists.size()) + if (idxHousesList < (int)RulesExt::Global()->AIHousesLists.size()) { std::vector objectsList = RulesExt::Global()->AIHousesLists.at(idxHousesList); if (objectsList.size() > 0) { - for (auto pHouseType : objectsList) + for (const auto pHouseType : objectsList) { for (auto& angerNode : pTeam->Owner->AngerNodes) { @@ -2948,9 +2948,10 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList if (idxHousesList >= 0) { - if (idxHousesList < RulesExt::Global()->AIHousesLists.size()) + if (idxHousesList < (int)RulesExt::Global()->AIHousesLists.size()) { std::vector objectsList = RulesExt::Global()->AIHousesLists.at(idxHousesList); + if (objectsList.size() > 0) { int IdxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.size() - 1); @@ -3018,7 +3019,7 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = newHateLevel = pTeamData->AngerNodeModifier; // Find the highest House hate value - for (auto& angerNode : pTeam->Owner->AngerNodes) + for (const auto& angerNode : pTeam->Owner->AngerNodes) { if (pTeam->Owner == angerNode.House || angerNode.House->Defeated @@ -3102,19 +3103,20 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int // Find the Team Leader for (auto pUnit = pTeam->FirstUnit; pUnit; pUnit = pUnit->NextTeamMember) { - if (pUnit && pUnit->IsAlive && !pUnit->InLimbo) + if (!pUnit || !pUnit->IsAlive || pUnit->InLimbo) + continue; + + auto pUnitType = pUnit->GetTechnoType(); + if (!pUnitType) + continue; + + // The team leader will be used for selecting targets, if there are living Team Members then always exists 1 Leader. + int unitLeadershipRating = pUnitType->LeadershipRating; + + if (unitLeadershipRating > bestUnitLeadershipValue) { - auto pUnitType = pUnit->GetTechnoType(); - if (pUnitType) - { - // The team leader will be used for selecting targets, if there are living Team Members then always exists 1 Leader. - int unitLeadershipRating = pUnitType->LeadershipRating; - if (unitLeadershipRating > bestUnitLeadershipValue) - { - pLeaderUnit = pUnit; - bestUnitLeadershipValue = unitLeadershipRating; - } - } + pLeaderUnit = pUnit; + bestUnitLeadershipValue = unitLeadershipRating; } } @@ -3140,7 +3142,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int if (mask == -2) { // Based on House economy - for (auto& pHouse : *HouseClass::Array) + for (const auto& pHouse : *HouseClass::Array) { if (pLeaderUnit->Owner == pHouse || pHouse->IsObserver() @@ -3180,7 +3182,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int if (mask == -3) { // Based on Human Controlled check - for (auto& pHouse : *HouseClass::Array) + for (const auto& pHouse : *HouseClass::Array) { if (pLeaderUnit->Owner == pHouse || !pHouse->IsControlledByHuman() @@ -3228,7 +3230,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int int checkedHousePower; // House power check - for (auto& pHouse : *HouseClass::Array) + for (const auto& pHouse : *HouseClass::Array) { if (pLeaderUnit->Owner == pHouse || pHouse->Defeated @@ -3276,7 +3278,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int if (mask == -7) { // Based on House kills - for (auto& pHouse : *HouseClass::Array) + for (const auto& pHouse : *HouseClass::Array) { if (pLeaderUnit->Owner == pHouse || pHouse->IsObserver() @@ -3318,7 +3320,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int if (mask == -8) { // Based on number of House naval units - for (auto& pHouse : *HouseClass::Array) + for (const auto& pHouse : *HouseClass::Array) { if (pLeaderUnit->Owner == pHouse || pHouse->IsObserver() @@ -3331,7 +3333,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int int currentNavalUnits = 0; - for (auto& pUnit : *TechnoClass::Array) + for (const auto& pUnit : *TechnoClass::Array) { if (pUnit->IsAlive && pUnit->Health > 0 @@ -3373,7 +3375,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int if (mask == -9) { // Based on number of House aircraft docks - for (auto& pHouse : *HouseClass::Array) + for (const auto& pHouse : *HouseClass::Array) { if (pLeaderUnit->Owner == pHouse || pHouse->IsObserver() @@ -3415,7 +3417,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int if (mask == -10) { // Based on number of House factories (except aircraft factories) - for (auto& pHouse : *HouseClass::Array) + for (const auto& pHouse : *HouseClass::Array) { if (pLeaderUnit->Owner == pHouse || pHouse->IsObserver() @@ -3504,9 +3506,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int enemyThreatValue[pTechno->Owner->ArrayIndex] += pTechnoType->ThreatPosed; if (pTechnoType->SpecialThreatValue > 0) - { enemyThreatValue[pTechno->Owner->ArrayIndex] += pTechnoType->SpecialThreatValue * TargetSpecialThreatCoefficientDefault; - } } } } @@ -3522,7 +3522,8 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int if (mode == 0) { // Select House with LESS threat - if ((enemyThreatValue[i] < value || value == -1) && !HouseClass::Array->GetItem(i)->Defeated) + if ((enemyThreatValue[i] < value || value == -1) + && !HouseClass::Array->GetItem(i)->Defeated) { value = enemyThreatValue[i]; enemyHouse = HouseClass::Array->GetItem(i); @@ -3531,7 +3532,8 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int else { // Select House with MORE threat - if ((enemyThreatValue[i] > value || value == -1) && !HouseClass::Array->GetItem(i)->Defeated) + if ((enemyThreatValue[i] > value || value == -1) + && !HouseClass::Array->GetItem(i)->Defeated) { value = enemyThreatValue[i]; enemyHouse = HouseClass::Array->GetItem(i); @@ -3582,7 +3584,7 @@ void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) break; case 2: - pTeamData->OnlyTargetHouseEnemy = (bool)ScenarioClass::Instance->Random.RandomRanged(0, 1);; + pTeamData->OnlyTargetHouseEnemy = (bool)ScenarioClass::Instance->Random.RandomRanged(0, 1); break; default: @@ -3655,9 +3657,11 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) newHateLevel = pTeamData->AngerNodeModifier; // Store the list of playable houses for later - for (auto& angerNode : pTeam->Owner->AngerNodes) + for (const auto& angerNode : pTeam->Owner->AngerNodes) { - if (!angerNode.House->Defeated && !angerNode.House->Type->MultiplayPassive && !angerNode.House->IsObserver()) + if (!angerNode.House->Defeated + && !angerNode.House->Type->MultiplayPassive + && !angerNode.House->IsObserver()) { objectsList.AddItem(angerNode.House); } @@ -3697,7 +3701,7 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) // Note: at most each "For" lasts 10 loops: 8 players + Civilian + Special houses if (index != -3) { - for (auto& pHouse : *HouseClass::Array) + for (const auto& pHouse : *HouseClass::Array) { if (!pHouse->Defeated && pHouse->ArrayIndex == index) selectedHouse = pHouse; @@ -3711,7 +3715,7 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) { int highestHateLevel = 0; - for (auto& angerNode : pHouse->AngerNodes) + for (const auto& angerNode : pHouse->AngerNodes) { if (angerNode.AngerLevel > highestHateLevel) highestHateLevel = angerNode.AngerLevel; @@ -3722,16 +3726,12 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) if (index == -3) { if (angerNode.House->IsControlledByHuman()) - { angerNode.AngerLevel = highestHateLevel + newHateLevel; - } } else { if (selectedHouse == angerNode.House) - { angerNode.AngerLevel = highestHateLevel + newHateLevel; - } } } @@ -3754,7 +3754,7 @@ void ScriptExt::UpdateEnemyHouseIndex(HouseClass* pHouse) int angerLevel = 0; int index = -1; - for (auto& angerNode : pHouse->AngerNodes) + for (const auto& angerNode : pHouse->AngerNodes) { if (!angerNode.House->Defeated && !pHouse->IsAlliedWith(angerNode.House) From 9aaceeb21a30454c679ecdcbf81a63f9f11e9460 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Mon, 13 Feb 2023 00:32:07 +0100 Subject: [PATCH 37/48] tweaks and small changes - Observers should be ignored. - small tweaks. --- src/Ext/Script/Body.cpp | 84 ++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index d2354133d5..0cb25162d0 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -2904,6 +2904,9 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) { for (auto& angerNode : pTeam->Owner->AngerNodes) { + if (angerNode.House->IsObserver()) + continue; + HouseTypeClass* angerNodeType = angerNode.House->Type; if (_stricmp(angerNodeType->ID, pHouseType->ID) == 0) @@ -2959,7 +2962,7 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList for (auto& angerNode : pTeam->Owner->AngerNodes) { - if (angerNode.House->Defeated) + if (angerNode.House->Defeated || angerNode.House->IsObserver()) continue; HouseTypeClass* angerNodeType = angerNode.House->Type; @@ -3009,7 +3012,7 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = return; } - DynamicVectorClass objectsList; + std::vector objectsList; int IdxSelectedObject = -1; HouseClass* selectedHouse = nullptr; int highestHateLevel = 0; @@ -3024,14 +3027,15 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = if (pTeam->Owner == angerNode.House || angerNode.House->Defeated || pTeam->Owner->IsAlliedWith(angerNode.House) - || angerNode.House->Type->MultiplayPassive) + || angerNode.House->Type->MultiplayPassive + || angerNode.House->IsObserver()) { continue; } if (random) { - objectsList.AddItem(angerNode.House); + objectsList.emplace_back(angerNode.House); } else { @@ -3045,10 +3049,10 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = // Pick a enemy house if (random) { - if (objectsList.Count > 0) + if (objectsList.size() > 0) { - IdxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.Count - 1); - selectedHouse = objectsList.GetItem(IdxSelectedObject); + IdxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.size() - 1); + selectedHouse = objectsList.at(IdxSelectedObject); } } else @@ -3060,7 +3064,7 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = { for (auto& angerNode : pTeam->Owner->AngerNodes) { - if (angerNode.House->Defeated) + if (angerNode.House->Defeated || angerNode.House->IsObserver()) continue; if (angerNode.House == selectedHouse) @@ -3083,42 +3087,29 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = 1) { - // Note regarding "mode": 1 is used for ">" comparisons and 0 for "<" - if (mode <= 0) - mode = 0; - else - mode = 1; - - auto pTeamData = TeamExt::ExtMap.Find(pTeam); - FootClass *pLeaderUnit = nullptr; - int bestUnitLeadershipValue = -1; - - if (!pTeam || !pTeamData || mask == 0) + if (!pTeam || mask == 0) { // This action finished pTeam->StepCompleted = true; return nullptr; } - // Find the Team Leader - for (auto pUnit = pTeam->FirstUnit; pUnit; pUnit = pUnit->NextTeamMember) + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData) { - if (!pUnit || !pUnit->IsAlive || pUnit->InLimbo) - continue; - - auto pUnitType = pUnit->GetTechnoType(); - if (!pUnitType) - continue; + // This action finished + pTeam->StepCompleted = true; + return nullptr; + } - // The team leader will be used for selecting targets, if there are living Team Members then always exists 1 Leader. - int unitLeadershipRating = pUnitType->LeadershipRating; + // Note regarding "mode": 1 is used for ">" comparisons and 0 for "<" + if (mode <= 0) + mode = 0; + else + mode = 1; - if (unitLeadershipRating > bestUnitLeadershipValue) - { - pLeaderUnit = pUnit; - bestUnitLeadershipValue = unitLeadershipRating; - } - } + // Find the Team Leader + FootClass* pLeaderUnit = FindTheTeamLeader(pTeam); if (!pLeaderUnit) { @@ -3186,6 +3177,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int { if (pLeaderUnit->Owner == pHouse || !pHouse->IsControlledByHuman() + || pHouse->IsObserver() || pHouse->Defeated || pHouse->Type->MultiplayPassive || pLeaderUnit->Owner->IsAlliedWith(pHouse)) @@ -3234,6 +3226,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int { if (pLeaderUnit->Owner == pHouse || pHouse->Defeated + || pHouse->IsObserver() || pHouse->Type->MultiplayPassive || pLeaderUnit->Owner->IsAlliedWith(pHouse)) { @@ -3523,7 +3516,8 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int { // Select House with LESS threat if ((enemyThreatValue[i] < value || value == -1) - && !HouseClass::Array->GetItem(i)->Defeated) + && !HouseClass::Array->GetItem(i)->Defeated + && !HouseClass::Array->GetItem(i)->IsObserver()) { value = enemyThreatValue[i]; enemyHouse = HouseClass::Array->GetItem(i); @@ -3533,7 +3527,8 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int { // Select House with MORE threat if ((enemyThreatValue[i] > value || value == -1) - && !HouseClass::Array->GetItem(i)->Defeated) + && !HouseClass::Array->GetItem(i)->Defeated + && !HouseClass::Array->GetItem(i)->IsObserver()) { value = enemyThreatValue[i]; enemyHouse = HouseClass::Array->GetItem(i); @@ -3622,7 +3617,9 @@ void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) { for (auto& angerNode : pTeam->Owner->AngerNodes) { - if (angerNode.House->ArrayIndex == idxHouse && !angerNode.House->Defeated) + if (angerNode.House->ArrayIndex == idxHouse + && !angerNode.House->Defeated + && !angerNode.House->IsObserver()) { angerNode.AngerLevel += pTeamData->AngerNodeModifier; Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Modified anger level against [%s](index: %d) with value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); @@ -3649,7 +3646,7 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) return; } - DynamicVectorClass objectsList; + std::vector objectsList; HouseClass* selectedHouse = nullptr; int newHateLevel = 5000; @@ -3663,7 +3660,7 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) && !angerNode.House->Type->MultiplayPassive && !angerNode.House->IsObserver()) { - objectsList.AddItem(angerNode.House); + objectsList.emplace_back(angerNode.House); } } @@ -3675,17 +3672,17 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) && !pTeam->Owner->IsObserver() && !pTeam->Owner->IsControlledByHuman()) { - objectsList.AddItem(pTeam->Owner); + objectsList.emplace_back(pTeam->Owner); } } // Positive indexes are specific house indexes. -1 is translated as "pick 1 random" & -2 is the owner of the Team executing the script action - if (objectsList.Count > 0) + if (objectsList.size() > 0) { if (index < 0) { if (index == -1) - index = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.Count - 1); + index = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.size() - 1); if (index == -2) index = pTeam->Owner->ArrayIndex; @@ -3757,6 +3754,7 @@ void ScriptExt::UpdateEnemyHouseIndex(HouseClass* pHouse) for (const auto& angerNode : pHouse->AngerNodes) { if (!angerNode.House->Defeated + && !angerNode.House->IsObserver() && !pHouse->IsAlliedWith(angerNode.House) && angerNode.AngerLevel > angerLevel) { From 3e73babf96f8be2618dd230d9a3ba522593a2221 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sat, 22 Jul 2023 16:19:18 +0200 Subject: [PATCH 38/48] YRpp --- YRpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YRpp b/YRpp index 224a435b8c..9f873c9799 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit 224a435b8c773f4330a874a931597bacbae48e33 +Subproject commit 9f873c9799692d1defa6a82f99dc3dae31d17e9e From 5bf725f4129b9081c28ee06f4c5522f662982268 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sat, 22 Jul 2023 16:36:15 +0200 Subject: [PATCH 39/48] YRpp fix --- src/Ext/Unit/Hooks.Jumpjet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ext/Unit/Hooks.Jumpjet.cpp b/src/Ext/Unit/Hooks.Jumpjet.cpp index e3dabd74b0..79522da454 100644 --- a/src/Ext/Unit/Hooks.Jumpjet.cpp +++ b/src/Ext/Unit/Hooks.Jumpjet.cpp @@ -104,7 +104,7 @@ DEFINE_HOOK(0x54C036, JumpjetLocomotionClass_State3_UpdateSensors, 0x7) // Copied from FootClass::UpdatePosition if (pLinkedTo->GetTechnoType()->SensorsSight) { - CellStruct const lastCell = pLinkedTo->LastJumpjetMapCoords; + CellStruct const lastCell = pLinkedTo->LastFlightMapCoords; if (lastCell != currentCell) { pLinkedTo->RemoveSensorsAt(lastCell); From 8a5f2c5736068aea2df887bbfae2052c330a6e59 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Mon, 29 Apr 2024 18:20:08 +0200 Subject: [PATCH 40/48] Moved code into a new file and updated code --- Phobos.vcxproj | 1 + docs/AI-Scripting-and-Mapping.md | 6 +- src/Ext/Script/Body.AngerNodes.cpp | 972 +++++++++++++++++++++++++++++ src/Ext/Script/Body.cpp | 965 ---------------------------- 4 files changed, 977 insertions(+), 967 deletions(-) create mode 100644 src/Ext/Script/Body.AngerNodes.cpp diff --git a/Phobos.vcxproj b/Phobos.vcxproj index 1ff7abb8a7..d2781ad86a 100644 --- a/Phobos.vcxproj +++ b/Phobos.vcxproj @@ -43,6 +43,7 @@ + diff --git a/docs/AI-Scripting-and-Mapping.md b/docs/AI-Scripting-and-Mapping.md index 38d433a7cd..09f47a54c0 100644 --- a/docs/AI-Scripting-and-Mapping.md +++ b/docs/AI-Scripting-and-Mapping.md @@ -515,9 +515,11 @@ The possible argument values are: | *Argument* | *Description* | | :--------: | :-------------------------------------------: | +| -5 | Selects a random House, including civilians. The own house is excluded in the selection of the most hated by everyone | +| -4 | Any random civilian house | | -3 | All Human players will be hated by everyone | -| -2 | The Team House will be the most hated by everyone (allies remain allies) | -| -1 | Selects a random House. The own House is excluded in the selection of the most hated by everyone | +| -2 | The Team House will be the most hated by everyone (allies won't pick allies as enemies) | +| -1 | Selects a random House. The own house & civilians are excluded in the selection of the most hated by everyone | | >= 0 | House index that will be hated by everyone | ### `16000-16999` Flow Control diff --git a/src/Ext/Script/Body.AngerNodes.cpp b/src/Ext/Script/Body.AngerNodes.cpp new file mode 100644 index 0000000000..eb7dd9982e --- /dev/null +++ b/src/Ext/Script/Body.AngerNodes.cpp @@ -0,0 +1,972 @@ +#include "Body.h" + +#include + +void ScriptExt::ResetAngerAgainstHouses(TeamClass* pTeam) +{ + // Invalid team + if (!pTeam) + return; + + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + angerNode.AngerLevel = 0; + } + + pTeam->Owner->EnemyHouseIndex = -1; + ScriptExt::DebugAngerNodesData(); // Remove this line before merging into develop branch! + + // This action finished + pTeam->StepCompleted = true; // This action finished - FS-21 +} + +void ScriptExt::SetHouseAngerModifier(TeamClass* pTeam, int modifier = 0) +{ + if (!pTeam) + return; + + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + if (modifier <= 0) + modifier = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; + + if (modifier < 0) + modifier = 0; + + pTeamData->AngerNodeModifier = modifier; + + // This action finished + pTeam->StepCompleted = true; +} + +void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) +{ + if (!pTeam) + return; + + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + bool changeFailed = true; + + if (idxHousesList <= 0) + idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; + + if (idxHousesList >= 0 + && idxHousesList < (int)RulesExt::Global()->AIHousesLists.size() + && RulesExt::Global()->AIHousesLists[idxHousesList].size() > 0) + { + std::vector objectsList = RulesExt::Global()->AIHousesLists[idxHousesList]; + + for (const auto pHouseType : objectsList) + { + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + if (angerNode.House->IsObserver()) + continue; + + HouseTypeClass* angerNodeType = angerNode.House->Type; + + if (_stricmp(angerNodeType->ID, pHouseType->ID) == 0) + { + angerNode.AngerLevel += pTeamData->AngerNodeModifier; + changeFailed = false; + } + } + } + } + + // This action finished + if (changeFailed) + { + int currentMission = pTeam->CurrentScript->CurrentMission; + + pTeam->StepCompleted = true; + ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Failed to modify AngerNode values against other houses.\n", + pTeam->Type->ID, + pTeam->CurrentScript->Type->ID, + pTeam->CurrentScript->CurrentMission, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument); + } + + ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); + ScriptExt::DebugAngerNodesData(); // Remove this line before merging into develop branch! + + // This action finished + pTeam->StepCompleted = true; +} + +void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList = -1) +{ + if (!pTeam) + return; + + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData || pTeamData->AngerNodeModifier == 0) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + int changes = 0; + int currentMission = pTeam->CurrentScript->CurrentMission; + + if (idxHousesList < 0) + { + idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; + + if (idxHousesList < 0) + { + // This action finished + pTeam->StepCompleted = true; + ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Invalid [AIHousesLists] index for modifying randomly AngerNode values.\n", + pTeam->Type->ID, + pTeam->CurrentScript->Type->ID, + pTeam->CurrentScript->CurrentMission, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument); + + return; + } + } + + if (idxHousesList < (int)RulesExt::Global()->AIHousesLists.size() + && RulesExt::Global()->AIHousesLists[idxHousesList].size() > 0) + { + std::vector objectsList = RulesExt::Global()->AIHousesLists[idxHousesList]; + int IdxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.size() - 1); + HouseTypeClass* pHouseType = objectsList[IdxSelectedObject]; + + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + if (angerNode.House->Defeated || angerNode.House->IsObserver()) + continue; + + HouseTypeClass* angerNodeType = angerNode.House->Type; + + if (_stricmp(angerNodeType->ID, pHouseType->ID) == 0) + { + angerNode.AngerLevel += pTeamData->AngerNodeModifier; + changes++; + } + } + } + + if (changes > 0) + { + ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); + ScriptExt::DebugAngerNodesData(); // Remove this line before merging into develop branch! + } + else + { + ScriptExt::Log("[%s][%s] (line: %d = %d,%d): No AngerNode values were modified.\n", + pTeam->Type->ID, + pTeam->CurrentScript->Type->ID, + pTeam->CurrentScript->CurrentMission, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument); + } + + // This action finished + pTeam->StepCompleted = true; +} + +void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = 1, bool random = false) +{ + if (!pTeam) + return; + + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + if (mask == 0) + { + mask = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; + + if (mask == 0) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + } + + std::vector objectsList; + int idxSelectedObject = -1; + HouseClass* selectedHouse = nullptr; + int highestHateLevel = 0; + int newHateLevel = 5000; + + if (pTeamData->AngerNodeModifier > 0) + newHateLevel = pTeamData->AngerNodeModifier; + + // Find the highest House hate value + for (const auto& angerNode : pTeam->Owner->AngerNodes) + { + if (pTeam->Owner == angerNode.House + || angerNode.House->Defeated + || angerNode.House->Type->MultiplayPassive + || pTeam->Owner->IsAlliedWith(angerNode.House) + || angerNode.House->IsObserver()) + { + continue; + } + + if (random) + { + objectsList.emplace_back(angerNode.House); + } + else + { + if (angerNode.AngerLevel > highestHateLevel) + highestHateLevel = angerNode.AngerLevel; + } + } + + newHateLevel += highestHateLevel; + + // Pick a enemy house + if (random) + { + if (objectsList.size() > 0) + { + idxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.size() - 1); + selectedHouse = objectsList.at(idxSelectedObject); + } + } + else + { + selectedHouse = GetTheMostHatedHouse(pTeam, mask, mode); + } + + if (selectedHouse) + { + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + if (angerNode.House->Defeated || angerNode.House->IsObserver()) + continue; + + if (angerNode.House == selectedHouse) + { + angerNode.AngerLevel = newHateLevel; + ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Picked a new house as enemy [%s]\n", + pTeam->Type->ID, + pTeam->CurrentScript->Type->ID, + pTeam->CurrentScript->CurrentMission, + pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, + pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, + angerNode.House->Type->ID); + } + } + + ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); + } + else + { + ScriptExt::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument); + } + + // This action finished + pTeam->StepCompleted = true; +} + +HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = 1) +{ + if (!pTeam) + return nullptr; + + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData || mask == 0) + { + // This action finished + pTeam->StepCompleted = true; + return nullptr; + } + + // Note regarding "mode": 1 is used for ">" comparisons and 0 for "<" + if (mode <= 0) + mode = 0; + else + mode = 1; + + // Find the Team Leader + FootClass* pLeaderUnit = FindTheTeamLeader(pTeam); + + if (!pLeaderUnit) + { + // This action finished + pTeam->StepCompleted = true; + return nullptr; + } + + bool currentMission = pTeam->CurrentScript->CurrentMission; + double objectDistance = -1; + double enemyDistance = -1; + int nHouses = HouseClass::Array->Count; + std::vector enemyThreatValue = std::vector(nHouses); + enemyThreatValue[nHouses] = { 0.0 }; + HouseClass* enemyHouse = nullptr; + double const& TargetSpecialThreatCoefficientDefault = RulesClass::Instance->TargetSpecialThreatCoefficientDefault; + long houseMoney = -1; + int enemyPower = -1000000000; + int enemyKills = -1; + int enemyAirDocks = -1; + int enemyStructures = -1; + int enemyNavalUnits = -1; + + if (mask == -2) // Based on House economy + { + for (const auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse + || pHouse->IsObserver() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + { + continue; + } + + bool isValidCandidate = false; + + if (mode == 0) + isValidCandidate = pHouse->Available_Money() < houseMoney; // The poorest is selected + else + isValidCandidate = pHouse->Available_Money() > houseMoney; // The richest is selected + + if (isValidCandidate || houseMoney < 0) + { + houseMoney = pHouse->Available_Money(); + enemyHouse = pHouse; + } + } + + if (enemyHouse) + { + ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Selected house [%s] (index: %d).\n", + pTeam->Type->ID, + pTeam->CurrentScript->Type->ID, + currentMission, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument, + enemyHouse->Type->ID, + enemyHouse->ArrayIndex); + } + + return enemyHouse; + } + + if (mask == -3) // Based on human controlled check + { + for (const auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse + || !pHouse->IsControlledByHuman() + || pHouse->IsObserver() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + { + continue; + } + + CoordStruct houseLocation; + houseLocation.X = pHouse->BaseSpawnCell.X; + houseLocation.Y = pHouse->BaseSpawnCell.Y; + houseLocation.Z = 0; + objectDistance = pLeaderUnit->Location.DistanceFrom(houseLocation); // Note: distance is in leptons (*256) + bool isValidCandidate = false; + + if (mode == 0) + isValidCandidate = objectDistance < enemyDistance; // Based in nearest human enemy unit + else + isValidCandidate = objectDistance > enemyDistance; // Based in farthest human enemy unit + + if (isValidCandidate || enemyDistance < 0) + { + enemyDistance = objectDistance; + enemyHouse = pHouse; + } + } + } + + if (mask == -4 || mask == -5 || mask == -6) // House power check + { + int checkedHousePower; + + for (const auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse + || pHouse->Defeated + || pHouse->IsObserver() + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + { + continue; + } + + if (mask == -4) // Related to the house's total power demand + checkedHousePower = pHouse->Power_Drain(); + + if (mask == -5) // Related to the house's total produced power + checkedHousePower = pHouse->PowerOutput; + + if (mask == -6) // Related to the house's unused power + checkedHousePower = pHouse->PowerOutput - pHouse->Power_Drain(); + + bool isValidCandidate = false; + + if (mode == 0) + isValidCandidate = checkedHousePower < enemyPower; // Selection based in lower value power in house + else + isValidCandidate = checkedHousePower > enemyPower; // Selection based in higher value power in house + + if (isValidCandidate || enemyPower == -10000000000) + { + enemyPower = checkedHousePower; + enemyHouse = pHouse; + } + } + } + + if (mask == -7) // Based on house's kills + { + for (const auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse + || pHouse->IsObserver() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + { + continue; + } + + int currentKills = pHouse->TotalKilledBuildings + pHouse->TotalKilledUnits; + bool isValidCandidate = false; + + if (mode == 0) + isValidCandidate = currentKills < enemyKills; // The pacifist is selected + else + isValidCandidate = currentKills > enemyKills; // The major mass murder is selected + + if (isValidCandidate || enemyKills < 0) + { + enemyKills = currentKills; + enemyHouse = pHouse; + } + } + } + + if (mask == -8) // Based on number of house's naval units + { + for (const auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse + || pHouse->IsObserver() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + { + continue; + } + + int currentNavalUnits = 0; + + for (const auto& pUnit : *TechnoClass::Array) + { + if (pUnit->IsAlive + && pUnit->Health > 0 + && pUnit->Owner == pHouse + && !pUnit->InLimbo + && pUnit->IsOnMap + && ScriptExt::EvaluateObjectWithMask(pUnit, 31, -1, -1, nullptr)) + { + currentNavalUnits++; + } + } + + bool isValidCandidate = false; + + if (mode == 0) + isValidCandidate = currentNavalUnits < enemyNavalUnits; // The house with less naval units is selected + else + isValidCandidate = currentNavalUnits > enemyNavalUnits; // The house with more naval units is selected + + if (isValidCandidate || enemyNavalUnits < 0) + { + enemyNavalUnits = currentNavalUnits; + enemyHouse = pHouse; + } + } + } + + if (mask == -9) // Based on number of House aircraft docks + { + for (const auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse + || pHouse->IsObserver() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + { + continue; + } + + int currentAirDocks = pHouse->AirportDocks; + bool isValidCandidate = false; + + if (mode == 0) + isValidCandidate = currentAirDocks < enemyAirDocks; // The house with less aircraft docks is selected + else + isValidCandidate = currentAirDocks > enemyAirDocks; // The house with more aircraft docks is selected + + if (isValidCandidate || enemyAirDocks < 0) + { + enemyAirDocks = currentAirDocks; + enemyHouse = pHouse; + } + } + } + + if (mask == -10) // Based on number of house's factories (except aircraft factories) + { + for (const auto& pHouse : *HouseClass::Array) + { + if (pLeaderUnit->Owner == pHouse + || pHouse->IsObserver() + || pHouse->Defeated + || pHouse->Type->MultiplayPassive + || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + { + continue; + } + + int currentFactories = pHouse->NumWarFactories + pHouse->NumConYards + pHouse->NumShipyards + pHouse->NumBarracks; + bool isValidCandidate = false; + + if (mode == 0) + isValidCandidate = currentFactories < enemyStructures; // The house with less factories is selected + else + isValidCandidate = currentFactories > enemyStructures; // The house with more factories is selected + + if (isValidCandidate || enemyStructures < 0) + { + enemyStructures = currentFactories; + enemyHouse = pHouse; + } + } + } + + if (enemyHouse) + { + ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Selected house [%s] (index: %d).\n", + pTeam->Type->ID, + pTeam->CurrentScript->Type->ID, + currentMission, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument, + enemyHouse->Type->ID, + enemyHouse->ArrayIndex); + + return enemyHouse; + } + + // Other cases: Check all the technos and depending of the mode compare what house will be selected as the most hated + for (auto pTechno : *TechnoClass::Array) + { + if (!pTechno->Owner->Defeated + && pTechno->Owner != pTeam->Owner + && pTechno->IsAlive + && !pTechno->InLimbo + && pTechno->IsOnMap + && !pTechno->Owner->IsAlliedWith(pTeam->Owner) + && !pTechno->Owner->Type->MultiplayPassive) + { + if (mask > 0) // Threat based on the new attack types of the new attack actions + { + if (ScriptExt::EvaluateObjectWithMask(pTechno, mask, -1, -1, pLeaderUnit)) // Check if the object type is valid + { + if (auto const pTechnoType = pTechno->GetTechnoType()) + { + enemyThreatValue[pTechno->Owner->ArrayIndex] += pTechnoType->ThreatPosed; + + if (pTechnoType->SpecialThreatValue > 0) + enemyThreatValue[pTechno->Owner->ArrayIndex] += pTechnoType->SpecialThreatValue * TargetSpecialThreatCoefficientDefault; + } + } + } + else if (mask == -1) // Based on enemy object distances + { + objectDistance = pLeaderUnit->DistanceFrom(pTechno); // Note: distance is in leptons (*256) + bool isValidCandidate = false; + + if (mode == 0) + isValidCandidate = objectDistance < enemyDistance; // The house with the nearest enemy unit + else + isValidCandidate = objectDistance > enemyDistance; // The house with the farthest enemy unit + + if (isValidCandidate || enemyDistance == -1) + { + enemyDistance = objectDistance; + enemyHouse = pTechno->Owner; + } + } + } + } + + if (mask > 0) // Pick the house with major thread + { + double enemyThreat = -1; + + for (int i = 0; i < nHouses; i++) + { + auto const pHouse = HouseClass::Array->GetItem(i); + + if (pHouse->Defeated || pHouse->Type->MultiplayPassive || pHouse->IsObserver()) + continue; + + bool isValidCandidate = false; + + if (mode == 0) + isValidCandidate = enemyThreatValue[i] < enemyThreat; // The house with the nearest enemy unit + else + isValidCandidate = enemyThreatValue[i] > enemyThreat; // The house with the farthest enemy unit + + if (isValidCandidate || enemyThreat < 0) + { + enemyThreat = enemyThreatValue[i]; + enemyHouse = pHouse; + } + } + } + + if (enemyHouse) + { + ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Selected house [%s] (index: %d).\n", + pTeam->Type->ID, + pTeam->CurrentScript->Type->ID, + currentMission, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument, + enemyHouse->Type->ID, + enemyHouse->ArrayIndex); + } + + return enemyHouse; +} + +// Possible mode values: +// 0 -> Force "False" +// 1 -> Force "True" +// 2 -> Force "Random boolean" +// -1 -> Use default value in OnlyTargetHouseEnemy tag +// Note: only works for new Phobos script actions, not the original ones +void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) +{ + if (!pTeam) + return; + + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + if (mode < 0 || mode > 2) + mode = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; + + if (mode < -1 || mode > 2) + mode = -1; + + pTeamData->OnlyTargetHouseEnemyMode = mode; + + switch (mode) + { + case 0: + pTeamData->OnlyTargetHouseEnemy = false; + break; + + case 1: + pTeamData->OnlyTargetHouseEnemy = true; + break; + + case 2: + pTeamData->OnlyTargetHouseEnemy = (bool)ScenarioClass::Instance->Random.RandomRanged(0, 1); + break; + + default: + pTeamData->OnlyTargetHouseEnemy = pTeam->Type->OnlyTargetHouseEnemy; + pTeamData->OnlyTargetHouseEnemyMode = -1; + break; + } + + int currentMission = pTeam->CurrentScript->CurrentMission; + ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Team's 'OnlyTargetHouseEnemy' value overwrited. Now is '%d'.\n", + pTeam->Type->ID, + pTeam->CurrentScript->Type->ID, + currentMission, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument, + pTeamData->OnlyTargetHouseEnemy); + + // This action finished + pTeam->StepCompleted = true; +} + +void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) +{ + if (!pTeam) + return; + + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData || pTeamData->AngerNodeModifier == 0) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + int currentMission = pTeam->CurrentScript->CurrentMission; + + if (idxHouse < 0) + idxHouse = pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument; + + if (idxHouse < 0) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + for (auto& angerNode : pTeam->Owner->AngerNodes) + { + if (angerNode.House->ArrayIndex == idxHouse + && !angerNode.House->Defeated + && !angerNode.House->IsObserver()) + { + angerNode.AngerLevel += pTeamData->AngerNodeModifier; + ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Modified AngerNode level of [%s](index: %d) against house [%s](index: %d). Current hate value: %d\n", + pTeam->Type->ID, + pTeam->CurrentScript->Type->ID, + currentMission, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument, + pTeam->Owner->Type->ID, + pTeam->Owner->ArrayIndex, + angerNode.House->Type->ID, + angerNode.House->ArrayIndex, + angerNode.AngerLevel); + } + } + + ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); + ScriptExt::DebugAngerNodesData(); // Remove this line before merging into develop branch! + + // This action finished + pTeam->StepCompleted = true; +} + +// The selected house will become the most hated of the map (the effects are only visible if the other houses are enemy of the selected house) +void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) +{ + if (!pTeam) + return; + + auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData) + { + // This action finished + pTeam->StepCompleted = true; + return; + } + + int currentMission = pTeam->CurrentScript->CurrentMission; + std::vector objectsList; + HouseClass* selectedHouse = nullptr; + int extraHateLevel = 5000; + bool onlySelectHumans = index == -3 ? true : false; + bool onlyCivilians = index == -4 ? true : false; + bool includeCivilians = index == -5 ? true : false; + + // Only if the additional was specified then overwrite the default value + if (pTeamData->AngerNodeModifier > 0) + extraHateLevel = pTeamData->AngerNodeModifier; + + if (index >= 0) // A specific house + { + selectedHouse = HouseClass::Array()->GetItem(index); + objectsList.emplace_back(selectedHouse); + } + else if (index == -2) // Team's onwer as candidate + { + selectedHouse = pTeam->Owner; + objectsList.emplace_back(pTeam->Owner); + } + else + { + if (onlySelectHumans && pTeam->Owner->IsControlledByHuman()) // Include the team's onwer as candidate if only select human players + objectsList.emplace_back(pTeam->Owner); + + // Store the list of possible candidate houses for later + for (auto pCandidateHouse : *HouseClass::Array) + { + if (pCandidateHouse->Defeated || pCandidateHouse->IsObserver() || (pCandidateHouse == pTeam->Owner)) + continue; + + if (onlySelectHumans) + { + if (pCandidateHouse->IsControlledByHuman()) + objectsList.emplace_back(pCandidateHouse); // Only Human players are candidate + } + else if(onlyCivilians && pCandidateHouse->Type->MultiplayPassive) + { + objectsList.emplace_back(pCandidateHouse); // Only civilians are candidate + } + else + { + if (!includeCivilians && pCandidateHouse->Type->MultiplayPassive) // Ignore civilians, just valid houses + continue; + + objectsList.emplace_back(pCandidateHouse); // Any valid house is candidate + } + } + } + + if (objectsList.size() == 0) + { + ScriptExt::Log("[%s][%s] (line: %d = %d,%d): [%s](index: %d) failed to pick a new house as main enemy using index '%d'.\n", + pTeam->Type->ID, + pTeam->CurrentScript->Type->ID, + currentMission, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, + pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument, + pTeam->Owner->Type->ID, + pTeam->Owner->ArrayIndex, + index); + + // No candidates. This action finished + pTeam->StepCompleted = true; + return; + } + + if (!selectedHouse && index != -3) // Candidates random index. Only humans case is excluded here + selectedHouse = objectsList[ScenarioClass::Instance->Random.RandomRanged(0, objectsList.size() - 1)]; + + for (auto pHouse : *HouseClass::Array) + { + if (pHouse->Defeated || pHouse->IsObserver()) + continue; + + // For each valid house find the highest anger value and sum extra hate; + int highestHateLevel = -1; + + for (const auto& angerNode : pHouse->AngerNodes) + { + if (angerNode.AngerLevel > highestHateLevel) + highestHateLevel = angerNode.AngerLevel; + } + + highestHateLevel += extraHateLevel; + + // Find the houses that must be hated more than anyone + for (auto& angerNode : pHouse->AngerNodes) + { + if (index == -3) + { + // All humans will receive the highest hate value + if (angerNode.House->IsControlledByHuman()) + angerNode.AngerLevel = highestHateLevel; + } + else + { + // Find the select house and set it as the highest hated house + if (selectedHouse == angerNode.House) + angerNode.AngerLevel = highestHateLevel; + } + } + + ScriptExt::UpdateEnemyHouseIndex(pHouse); + } + + ScriptExt::DebugAngerNodesData(); // Remove this line before merging into develop branch! + + // This action finished + pTeam->StepCompleted = true; +} + +// The most hated house must be the main enemy +void ScriptExt::UpdateEnemyHouseIndex(HouseClass* pHouse) +{ + if (!pHouse) + return; + + int angerLevel = 0; + int index = -1; + + for (const auto& angerNode : pHouse->AngerNodes) + { + if (!angerNode.House->Defeated + && !angerNode.House->IsObserver() + && !pHouse->IsAlliedWith(angerNode.House) + && angerNode.AngerLevel > angerLevel) + { + angerLevel = angerNode.AngerLevel; + index = angerNode.House->ArrayIndex; + } + } + + pHouse->EnemyHouseIndex = index; +} + +void ScriptExt::DebugAngerNodesData() +{ + ScriptExt::Log("Updated AngerNodes lists of every playable House:\n"); + + for (auto pHouse : *HouseClass::Array) + { + if (pHouse->IsObserver()) + ScriptExt::Log("Player %d [Observer] ", pHouse->ArrayIndex); + else + ScriptExt::Log("Player %d [%s]: ", pHouse->ArrayIndex, pHouse->Type->ID); + + int i = 0; + + for (auto& angerNode : pHouse->AngerNodes) + { + if (!pHouse->IsObserver()) + ScriptExt::Log("%d:%d", angerNode.House->ArrayIndex, angerNode.AngerLevel); + + if (i < HouseClass::Array->Count - 2 && !pHouse->IsObserver()) + ScriptExt::Log(", "); + + i++; + } + + if (!pHouse->IsObserver()) + ScriptExt::Log(" -> Main Enemy House: %d\n", pHouse->EnemyHouseIndex); + else + ScriptExt::Log("\n"); + } +} diff --git a/src/Ext/Script/Body.cpp b/src/Ext/Script/Body.cpp index f6613743ff..9aae5ae981 100644 --- a/src/Ext/Script/Body.cpp +++ b/src/Ext/Script/Body.cpp @@ -909,940 +909,6 @@ void ScriptExt::SkipNextAction(TeamClass* pTeam, int successPercentage = 0) pTeam->StepCompleted = true; } -void ScriptExt::ResetAngerAgainstHouses(TeamClass* pTeam) -{ - // Invalid team - if (!pTeam) - { - // This action finished - pTeam->StepCompleted = true; - return; - } - - for (auto& angerNode : pTeam->Owner->AngerNodes) - { - angerNode.AngerLevel = 0; - } - - pTeam->Owner->EnemyHouseIndex = -1; - ScriptExt::DebugAngerNodesData(); - - // This action finished - pTeam->StepCompleted = true; // This action finished - FS-21 -} - -void ScriptExt::SetHouseAngerModifier(TeamClass* pTeam, int modifier = 0) -{ - auto pTeamData = TeamExt::ExtMap.Find(pTeam); - - if (!pTeam || !pTeamData) - { - // This action finished - pTeam->StepCompleted = true; - return; - } - - if (modifier <= 0) - modifier = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; - - if (modifier < 0) - modifier = 0; - - pTeamData->AngerNodeModifier = modifier; - - // This action finished - pTeam->StepCompleted = true; -} - -void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) -{ - auto pTeamData = TeamExt::ExtMap.Find(pTeam); - bool changeFailed = true; - - if (!pTeam || !pTeamData) - { - // This action finished - pTeam->StepCompleted = true; - return; - } - - if (idxHousesList <= 0) - idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; - - if (idxHousesList >= 0) - { - if (idxHousesList < (int)RulesExt::Global()->AIHousesLists.size()) - { - std::vector objectsList = RulesExt::Global()->AIHousesLists.at(idxHousesList); - - if (objectsList.size() > 0) - { - for (const auto pHouseType : objectsList) - { - for (auto& angerNode : pTeam->Owner->AngerNodes) - { - if (angerNode.House->IsObserver()) - continue; - - HouseTypeClass* angerNodeType = angerNode.House->Type; - - if (_stricmp(angerNodeType->ID, pHouseType->ID) == 0) - { - angerNode.AngerLevel += pTeamData->AngerNodeModifier; - changeFailed = false; - } - } - } - } - } - } - - // This action finished - if (changeFailed) - { - pTeam->StepCompleted = true; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify hate values against other houses\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument); - } - - ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); - ScriptExt::DebugAngerNodesData(); - - // This action finished - pTeam->StepCompleted = true; -} - -void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList = -1) -{ - auto pTeamData = TeamExt::ExtMap.Find(pTeam); - int changes = 0; - - if (!pTeam || !pTeamData) - { - // This action finished - pTeam->StepCompleted = true; - return; - } - - if (idxHousesList <= 0) - idxHousesList = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; - - if (idxHousesList >= 0) - { - if (idxHousesList < (int)RulesExt::Global()->AIHousesLists.size()) - { - std::vector objectsList = RulesExt::Global()->AIHousesLists.at(idxHousesList); - - if (objectsList.size() > 0) - { - int IdxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.size() - 1); - HouseTypeClass* pHouseType = objectsList.at(IdxSelectedObject); - - for (auto& angerNode : pTeam->Owner->AngerNodes) - { - if (angerNode.House->Defeated || angerNode.House->IsObserver()) - continue; - - HouseTypeClass* angerNodeType = angerNode.House->Type; - - if (_stricmp(angerNodeType->ID, pHouseType->ID) == 0) - { - angerNode.AngerLevel += pTeamData->AngerNodeModifier; - changes++; - } - } - } - } - } - - // This action finished - if (changes == 0) - { - pTeam->StepCompleted = true; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to modify hate values against other houses\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument); - } - - ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); - ScriptExt::DebugAngerNodesData(); - - // This action finished - pTeam->StepCompleted = true; -} - -void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = 1, bool random = false) -{ - auto pTeamData = TeamExt::ExtMap.Find(pTeam); - - if (!pTeam || !pTeamData) - { - // This action finished - pTeam->StepCompleted = true; - return; - } - - if (mask == 0) - mask = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; - - if (mask == 0) - { - // This action finished - pTeam->StepCompleted = true; - return; - } - - std::vector objectsList; - int IdxSelectedObject = -1; - HouseClass* selectedHouse = nullptr; - int highestHateLevel = 0; - int newHateLevel = 5000; - - if (pTeamData->AngerNodeModifier > 0) - newHateLevel = pTeamData->AngerNodeModifier; - - // Find the highest House hate value - for (const auto& angerNode : pTeam->Owner->AngerNodes) - { - if (pTeam->Owner == angerNode.House - || angerNode.House->Defeated - || pTeam->Owner->IsAlliedWith(angerNode.House) - || angerNode.House->Type->MultiplayPassive - || angerNode.House->IsObserver()) - { - continue; - } - - if (random) - { - objectsList.emplace_back(angerNode.House); - } - else - { - if (angerNode.AngerLevel > highestHateLevel) - highestHateLevel = angerNode.AngerLevel; - } - } - - newHateLevel += highestHateLevel; - - // Pick a enemy house - if (random) - { - if (objectsList.size() > 0) - { - IdxSelectedObject = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.size() - 1); - selectedHouse = objectsList.at(IdxSelectedObject); - } - } - else - { - selectedHouse = GetTheMostHatedHouse(pTeam, mask, mode); - } - - if (selectedHouse) - { - for (auto& angerNode : pTeam->Owner->AngerNodes) - { - if (angerNode.House->Defeated || angerNode.House->IsObserver()) - continue; - - if (angerNode.House == selectedHouse) - { - angerNode.AngerLevel = newHateLevel; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Picked a new house as enemy [%s]\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, angerNode.House->Type->ID); - } - } - - ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); - } - else - { - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument); - } - - // This action finished - pTeam->StepCompleted = true; -} - -HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = 1) -{ - if (!pTeam || mask == 0) - { - // This action finished - pTeam->StepCompleted = true; - return nullptr; - } - - auto pTeamData = TeamExt::ExtMap.Find(pTeam); - if (!pTeamData) - { - // This action finished - pTeam->StepCompleted = true; - return nullptr; - } - - // Note regarding "mode": 1 is used for ">" comparisons and 0 for "<" - if (mode <= 0) - mode = 0; - else - mode = 1; - - // Find the Team Leader - FootClass* pLeaderUnit = FindTheTeamLeader(pTeam); - - if (!pLeaderUnit) - { - // This action finished - pTeam->StepCompleted = true; - return nullptr; - } - - double objectDistance = -1; - double enemyDistance = -1; - double enemyThreatValue[8] = { 0 }; - HouseClass* enemyHouse = nullptr; - double const& TargetSpecialThreatCoefficientDefault = RulesClass::Instance->TargetSpecialThreatCoefficientDefault; - long houseMoney = -1; - int enemyPower = -1000000000; - int enemyKills = -1; - int enemyAirDocks = -1; - int enemyStructures = -1; - int enemyNavalUnits = -1; - - if (mask == -2) - { - // Based on House economy - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || pHouse->IsObserver() - || pHouse->Defeated - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) - { - continue; - } - - if (mode == 0) - { - // The poorest is selected - if (pHouse->Available_Money() < houseMoney || houseMoney < 0) - { - houseMoney = pHouse->Available_Money(); - enemyHouse = pHouse; - } - } - else - { - // The richest is selected - if (pHouse->Available_Money() > houseMoney || houseMoney < 0) - { - houseMoney = pHouse->Available_Money(); - enemyHouse = pHouse; - } - } - } - - if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); - - return enemyHouse; - } - - if (mask == -3) - { - // Based on Human Controlled check - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || !pHouse->IsControlledByHuman() - || pHouse->IsObserver() - || pHouse->Defeated - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) - { - continue; - } - - CoordStruct houseLocation; - houseLocation.X = pHouse->BaseSpawnCell.X; - houseLocation.Y = pHouse->BaseSpawnCell.Y; - houseLocation.Z = 0; - objectDistance = pLeaderUnit->Location.DistanceFrom(houseLocation); // Note: distance is in leptons (*256) - - if (mode == 0) - { - // mode 0: Based in NEAREST human enemy unit - if (objectDistance < enemyDistance || enemyDistance == -1) - { - enemyDistance = objectDistance; - enemyHouse = pHouse; - } - } - else - { - // mode 1: Based in FARTHEST human enemy unit - if (objectDistance > enemyDistance || enemyDistance == -1) - { - enemyDistance = objectDistance; - enemyHouse = pHouse; - } - } - } - - if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); - - return enemyHouse; - } - - if (mask == -4 || mask == -5 || mask == -6) - { - int checkedHousePower; - - // House power check - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || pHouse->Defeated - || pHouse->IsObserver() - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) - { - continue; - } - - if (mask == -4) - checkedHousePower = pHouse->Power_Drain(); - - if (mask == -5) - checkedHousePower = pHouse->PowerOutput; - - if (mask == -6) - checkedHousePower = pHouse->PowerOutput - pHouse->Power_Drain(); - - if (mode == 0) - { - // mode 0: Selection based in lower value power in house - if ((checkedHousePower < enemyPower) || enemyPower == -1000000000) - { - enemyPower = checkedHousePower; - enemyHouse = pHouse; - } - } - else - { - // mode 1: Selection based in higher value power in house - if ((checkedHousePower > enemyPower) || enemyPower == -1000000000) - { - enemyPower = checkedHousePower; - enemyHouse = pHouse; - } - } - } - - if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); - - return enemyHouse; - } - - if (mask == -7) - { - // Based on House kills - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || pHouse->IsObserver() - || pHouse->Defeated - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) - { - continue; - } - - int currentKills = pHouse->TotalKilledUnits + pHouse->TotalKilledUnits; - - if (mode == 0) - { - // The pacifist is selected - if (currentKills < enemyKills || enemyKills < 0) - { - enemyKills = currentKills; - enemyHouse = pHouse; - } - } - else - { - // The major killer is selected - if (currentKills > enemyKills || enemyKills < 0) - { - enemyKills = currentKills; - enemyHouse = pHouse; - } - } - } - - if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); - - return enemyHouse; - } - - if (mask == -8) - { - // Based on number of House naval units - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || pHouse->IsObserver() - || pHouse->Defeated - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) - { - continue; - } - - int currentNavalUnits = 0; - - for (const auto& pUnit : *TechnoClass::Array) - { - if (pUnit->IsAlive - && pUnit->Health > 0 - && pUnit->Owner == pHouse - && !pUnit->InLimbo - && pUnit->IsOnMap - && ScriptExt::EvaluateObjectWithMask(pUnit, 31, -1, -1, nullptr)) - { - currentNavalUnits++; - } - } - - if (mode == 0) - { - // The House with less naval units is selected - if (currentNavalUnits < enemyNavalUnits || enemyNavalUnits < 0) - { - enemyNavalUnits = currentNavalUnits; - enemyHouse = pHouse; - } - } - else - { - // The House with more naval units is selected - if (currentNavalUnits > enemyNavalUnits || enemyNavalUnits < 0) - { - enemyNavalUnits = currentNavalUnits; - enemyHouse = pHouse; - } - } - } - - if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); - - return enemyHouse; - } - - if (mask == -9) - { - // Based on number of House aircraft docks - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || pHouse->IsObserver() - || pHouse->Defeated - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) - { - continue; - } - - int currentAirDocks = pHouse->AirportDocks; - - if (mode == 0) - { - // The House with less Aircraft docks is selected - if (currentAirDocks < enemyAirDocks || enemyAirDocks < 0) - { - enemyAirDocks = currentAirDocks; - enemyHouse = pHouse; - } - } - else - { - // The House with more Aircraft docks is selected - if (currentAirDocks > enemyAirDocks || enemyAirDocks < 0) - { - enemyAirDocks = currentAirDocks; - enemyHouse = pHouse; - } - } - } - - if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); - - return enemyHouse; - } - - if (mask == -10) - { - // Based on number of House factories (except aircraft factories) - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || pHouse->IsObserver() - || pHouse->Defeated - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) - { - continue; - } - - int currentFactories = pHouse->NumWarFactories + pHouse->NumConYards + pHouse->NumShipyards + pHouse->NumBarracks; - - if (mode == 0) - { - // The House with less factories is selected - if (currentFactories < enemyStructures || enemyStructures < 0) - { - enemyStructures = currentFactories; - enemyHouse = pHouse; - } - } - else - { - // The House with more factories is selected - if (currentFactories > enemyStructures || enemyStructures < 0) - { - enemyStructures = currentFactories; - enemyHouse = pHouse; - } - } - } - - if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); - - return enemyHouse; - } - - // Depending the mode check what house will be selected as the most hated - for (auto pTechno : *TechnoClass::Array) - { - if (!pTechno->Owner->Defeated - && pTechno->Owner != pTeam->Owner - && pTechno->IsAlive - && !pTechno->InLimbo - && pTechno->IsOnMap - && !pTechno->Owner->IsAlliedWith(pTeam->Owner) - && !pTechno->Owner->Type->MultiplayPassive) - { - if (mask < 0) - { - if (mask == -1) - { - // mask -1: Based on object distances - objectDistance = pLeaderUnit->DistanceFrom(pTechno); // Note: distance is in leptons (*256) - - if (mode == 0) - { - // mode 0: Based in NEAREST enemy unit - if (objectDistance < enemyDistance || enemyDistance == -1) - { - enemyDistance = objectDistance; - enemyHouse = pTechno->Owner; - } - } - else - { - // mode 1: Based in FARTHEST enemy unit - if (objectDistance > enemyDistance || enemyDistance == -1) - { - enemyDistance = objectDistance; - enemyHouse = pTechno->Owner; - } - } - } - } - else - { - // mask > 0 : Threat based on the new types in the new attack actions - if (ScriptExt::EvaluateObjectWithMask(pTechno, mask, -1, -1, pLeaderUnit)) - { - auto pTechnoType = pTechno->GetTechnoType(); - - if (pTechnoType) - { - enemyThreatValue[pTechno->Owner->ArrayIndex] += pTechnoType->ThreatPosed; - - if (pTechnoType->SpecialThreatValue > 0) - enemyThreatValue[pTechno->Owner->ArrayIndex] += pTechnoType->SpecialThreatValue * TargetSpecialThreatCoefficientDefault; - } - } - } - } - } - - if (mask > 0) - { - double value = -1; - - for (int i = 0; i < 8; i++) - { - if (mode == 0) - { - // Select House with LESS threat - if ((enemyThreatValue[i] < value || value == -1) - && !HouseClass::Array->GetItem(i)->Defeated - && !HouseClass::Array->GetItem(i)->IsObserver()) - { - value = enemyThreatValue[i]; - enemyHouse = HouseClass::Array->GetItem(i); - } - } - else - { - // Select House with MORE threat - if ((enemyThreatValue[i] > value || value == -1) - && !HouseClass::Array->GetItem(i)->Defeated - && !HouseClass::Array->GetItem(i)->IsObserver()) - { - value = enemyThreatValue[i]; - enemyHouse = HouseClass::Array->GetItem(i); - } - } - } - } - - if (enemyHouse) - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): selected House [%s] (index: %d)\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, enemyHouse->Type->ID, enemyHouse->ArrayIndex); - - return enemyHouse; -} - -void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) -{ - auto pTeamData = TeamExt::ExtMap.Find(pTeam); - if (!pTeam || !pTeamData) - { - // This action finished - pTeam->StepCompleted = true; - return; - } - - if (mode < 0 || mode > 2) - mode = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; - - if (mode < -1 || mode > 2) - mode = -1; - - pTeamData->OnlyTargetHouseEnemyMode = mode; - /* - Modes: - 0 -> Force "False" - 1 -> Force "True" - 2 -> Force "Random boolean" - -1 -> Use default value in OnlyTargetHouseEnemy tag - Note: only works for new Actions, not vanilla YR actions - */ - switch (mode) - { - case 0: - pTeamData->OnlyTargetHouseEnemy = false; - break; - - case 1: - pTeamData->OnlyTargetHouseEnemy = true; - break; - - case 2: - pTeamData->OnlyTargetHouseEnemy = (bool)ScenarioClass::Instance->Random.RandomRanged(0, 1); - break; - - default: - pTeamData->OnlyTargetHouseEnemy = pTeam->Type->OnlyTargetHouseEnemy; - pTeamData->OnlyTargetHouseEnemyMode = -1; - break; - } - - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): New Team -> OnlyTargetHouseEnemy value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, pTeamData->OnlyTargetHouseEnemy); - // This action finished - pTeam->StepCompleted = true; -} - -void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) -{ - auto pTeamData = TeamExt::ExtMap.Find(pTeam); - - if (!pTeam || !pTeamData) - { - // This action finished - pTeam->StepCompleted = true; - return; - } - - if (idxHouse < 0) - idxHouse = pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument; - - if (idxHouse < 0) - { - // This action finished - pTeam->StepCompleted = true; - return; - } - else - { - for (auto& angerNode : pTeam->Owner->AngerNodes) - { - if (angerNode.House->ArrayIndex == idxHouse - && !angerNode.House->Defeated - && !angerNode.House->IsObserver()) - { - angerNode.AngerLevel += pTeamData->AngerNodeModifier; - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Modified anger level against [%s](index: %d) with value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, angerNode.House->Type->ID, angerNode.House->ArrayIndex, angerNode.AngerLevel); - } - } - } - - ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); - ScriptExt::DebugAngerNodesData(); - - // This action finished - pTeam->StepCompleted = true; -} - -// The selected house will become the most hated of the map (the effects are only visible if the other houses are enemy of the selected house) -void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) -{ - auto pTeamData = TeamExt::ExtMap.Find(pTeam); - - if (!pTeam || !pTeamData) - { - // This action finished - pTeam->StepCompleted = true; - return; - } - - std::vector objectsList; - HouseClass* selectedHouse = nullptr; - int newHateLevel = 5000; - - if (pTeamData->AngerNodeModifier > 0) - newHateLevel = pTeamData->AngerNodeModifier; - - // Store the list of playable houses for later - for (const auto& angerNode : pTeam->Owner->AngerNodes) - { - if (!angerNode.House->Defeated - && !angerNode.House->Type->MultiplayPassive - && !angerNode.House->IsObserver()) - { - objectsList.emplace_back(angerNode.House); - } - } - - // Include the own House if we are looking for ANY Human player - if (index == -3) - { - if (!pTeam->Owner->Defeated - && !pTeam->Owner->Type->MultiplayPassive - && !pTeam->Owner->IsObserver() - && !pTeam->Owner->IsControlledByHuman()) - { - objectsList.emplace_back(pTeam->Owner); - } - } - - // Positive indexes are specific house indexes. -1 is translated as "pick 1 random" & -2 is the owner of the Team executing the script action - if (objectsList.size() > 0) - { - if (index < 0) - { - if (index == -1) - index = ScenarioClass::Instance->Random.RandomRanged(0, objectsList.size() - 1); - - if (index == -2) - index = pTeam->Owner->ArrayIndex; - } - } - else - { - // This action finished - pTeam->StepCompleted = true; - return; - } - - // Note: at most each "For" lasts 10 loops: 8 players + Civilian + Special houses - if (index != -3) - { - for (const auto& pHouse : *HouseClass::Array) - { - if (!pHouse->Defeated && pHouse->ArrayIndex == index) - selectedHouse = pHouse; - } - } - - if (selectedHouse || index == -3) - { - // For each playable house set the selected house as the one with highest hate value; - for (auto& pHouse : objectsList) - { - int highestHateLevel = 0; - - for (const auto& angerNode : pHouse->AngerNodes) - { - if (angerNode.AngerLevel > highestHateLevel) - highestHateLevel = angerNode.AngerLevel; - } - - for (auto& angerNode : pHouse->AngerNodes) - { - if (index == -3) - { - if (angerNode.House->IsControlledByHuman()) - angerNode.AngerLevel = highestHateLevel + newHateLevel; - } - else - { - if (selectedHouse == angerNode.House) - angerNode.AngerLevel = highestHateLevel + newHateLevel; - } - } - - ScriptExt::UpdateEnemyHouseIndex(pHouse); - } - } - else - { - Debug::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house with index: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument, index); - } - - ScriptExt::DebugAngerNodesData(); - - // This action finished - pTeam->StepCompleted = true; -} - -void ScriptExt::UpdateEnemyHouseIndex(HouseClass* pHouse) -{ - int angerLevel = 0; - int index = -1; - - for (const auto& angerNode : pHouse->AngerNodes) - { - if (!angerNode.House->Defeated - && !angerNode.House->IsObserver() - && !pHouse->IsAlliedWith(angerNode.House) - && angerNode.AngerLevel > angerLevel) - { - angerLevel = angerNode.AngerLevel; - index = angerNode.House->ArrayIndex; - } - } - - pHouse->EnemyHouseIndex = index; -} - void ScriptExt::VariablesHandler(TeamClass* pTeam, PhobosScripts eAction, int nArg) { struct operation_set { int operator()(const int& a, const int& b) { return b; } }; @@ -2071,37 +1137,6 @@ bool ScriptExt::IsExtVariableAction(int action) return eAction >= PhobosScripts::LocalVariableAdd && eAction <= PhobosScripts::GlobalVariableAndByGlobal; } -void ScriptExt::DebugAngerNodesData() -{ - Debug::Log("DEBUG: Updated AngerNodes lists of every playable House:\n"); - - for (auto pHouse : *HouseClass::Array) - { - if (pHouse->IsObserver()) - Debug::Log("Player %d [Observer] ", pHouse->ArrayIndex); - else - Debug::Log("Player %d [%s]: ", pHouse->ArrayIndex, pHouse->Type->ID); - - int i = 0; - - for (auto& angerNode : pHouse->AngerNodes) - { - if (!pHouse->IsObserver()) - Debug::Log("%d:%d", angerNode.House->ArrayIndex, angerNode.AngerLevel); - - if (i < HouseClass::Array->Count - 2 && !pHouse->IsObserver()) - Debug::Log(", "); - - i++; - } - - if (!pHouse->IsObserver()) - Debug::Log(" -> Main Enemy House: %d\n", pHouse->EnemyHouseIndex); - else - Debug::Log("\n"); - } -} - void ScriptExt::Set_ForceJump_Countdown(TeamClass *pTeam, bool repeatLine = false, int count = 0) { if (!pTeam) From a700b06e3423eb634f2b0b65cc3b4e55f2f23113 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Wed, 1 May 2024 09:16:25 +0200 Subject: [PATCH 41/48] Tweak --- src/Ext/Rules/Body.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index 22aacded51..789a0c750a 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -207,14 +207,13 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) char* context = nullptr; pINI->ReadString(sectionAIHousesList, pINI->GetKeyName(sectionAIHousesList, i), "", Phobos::readBuffer); - for (char *cur = strtok_s(Phobos::readBuffer, Phobos::readDelims, &context); cur; cur = strtok_s(nullptr, Phobos::readDelims, &context)) + for (char* cur = strtok_s(Phobos::readBuffer, Phobos::readDelims, &context); cur; cur = strtok_s(nullptr, Phobos::readDelims, &context)) { - HouseTypeClass* pNewHouse = HouseTypeClass::Find(cur);//GameCreate(cur); - if (pNewHouse) + if (const auto pNewHouse = HouseTypeClass::Find(cur)) objectsList.emplace_back(pNewHouse); } - AIHousesLists.emplace_back(objectsList); + this->AIHousesLists.emplace_back(std::move(objectsList)); } } From 5d8bc3a1e93550dc8a52059dd877b3e4d325e269 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sat, 13 Jul 2024 12:27:02 +0200 Subject: [PATCH 42/48] Refactored code ScriptExt::GetTheMostHatedHouse(...) was refactored due the multiple duplicated portions of code and other feedback changes- --- src/Commands/ObjectInfo.cpp | 2 - src/Ext/Script/Body.AngerNodes.cpp | 455 ++++++++--------------------- src/Ext/Script/Body.h | 1 - 3 files changed, 119 insertions(+), 339 deletions(-) diff --git a/src/Commands/ObjectInfo.cpp b/src/Commands/ObjectInfo.cpp index 5087d3aec7..7407cae6ea 100644 --- a/src/Commands/ObjectInfo.cpp +++ b/src/Commands/ObjectInfo.cpp @@ -126,7 +126,6 @@ void ObjectInfoCommandClass::Execute(WWKey eInput) const append("\n"); display(); - ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! }; auto printBuilding = [&append, &display](BuildingClass* pBuilding) @@ -188,7 +187,6 @@ void ObjectInfoCommandClass::Execute(WWKey eInput) const append("Current Shield HP = (%d / %d)\n", pShieldData->GetHP(), pTechnoExt->CurrentShieldType->Strength); display(); - ScriptExt::DebugAngerNodesData(); // DEBUG - DELETE THIS LINE BEFORE MERGING, THIS IS USED ONLY FOR TESTERS! }; bool dumped = false; diff --git a/src/Ext/Script/Body.AngerNodes.cpp b/src/Ext/Script/Body.AngerNodes.cpp index eb7dd9982e..73e634f764 100644 --- a/src/Ext/Script/Body.AngerNodes.cpp +++ b/src/Ext/Script/Body.AngerNodes.cpp @@ -4,17 +4,12 @@ void ScriptExt::ResetAngerAgainstHouses(TeamClass* pTeam) { - // Invalid team - if (!pTeam) - return; - for (auto& angerNode : pTeam->Owner->AngerNodes) { angerNode.AngerLevel = 0; } pTeam->Owner->EnemyHouseIndex = -1; - ScriptExt::DebugAngerNodesData(); // Remove this line before merging into develop branch! // This action finished pTeam->StepCompleted = true; // This action finished - FS-21 @@ -22,9 +17,6 @@ void ScriptExt::ResetAngerAgainstHouses(TeamClass* pTeam) void ScriptExt::SetHouseAngerModifier(TeamClass* pTeam, int modifier = 0) { - if (!pTeam) - return; - auto pTeamData = TeamExt::ExtMap.Find(pTeam); if (!pTeamData) { @@ -47,9 +39,6 @@ void ScriptExt::SetHouseAngerModifier(TeamClass* pTeam, int modifier = 0) void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) { - if (!pTeam) - return; - auto pTeamData = TeamExt::ExtMap.Find(pTeam); if (!pTeamData) { @@ -93,7 +82,7 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) int currentMission = pTeam->CurrentScript->CurrentMission; pTeam->StepCompleted = true; - ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Failed to modify AngerNode values against other houses.\n", + ScriptExt::Log("[%s][%s] (line: %d = %d,%d) - AngerNodes: Failed to modify AngerNode values against other houses.\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, @@ -102,7 +91,6 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); - ScriptExt::DebugAngerNodesData(); // Remove this line before merging into develop branch! // This action finished pTeam->StepCompleted = true; @@ -110,10 +98,8 @@ void ScriptExt::ModifyHateHouses_List(TeamClass* pTeam, int idxHousesList = -1) void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList = -1) { - if (!pTeam) - return; - auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData || pTeamData->AngerNodeModifier == 0) { // This action finished @@ -132,7 +118,7 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList { // This action finished pTeam->StepCompleted = true; - ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Invalid [AIHousesLists] index for modifying randomly AngerNode values.\n", + ScriptExt::Log("[%s][%s] (line: %d = %d,%d) - AngerNodes: Invalid [AIHousesLists] index for modifying randomly anger values.\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, @@ -168,11 +154,10 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList if (changes > 0) { ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); - ScriptExt::DebugAngerNodesData(); // Remove this line before merging into develop branch! } else { - ScriptExt::Log("[%s][%s] (line: %d = %d,%d): No AngerNode values were modified.\n", + ScriptExt::Log("[%s][%s] (line: %d = %d,%d) - AngerNodes: No anger values were modified.\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, @@ -186,9 +171,6 @@ void ScriptExt::ModifyHateHouses_List1Random(TeamClass* pTeam, int idxHousesList void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = 1, bool random = false) { - if (!pTeam) - return; - auto pTeamData = TeamExt::ExtMap.Find(pTeam); if (!pTeamData) { @@ -267,7 +249,7 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = if (angerNode.House == selectedHouse) { angerNode.AngerLevel = newHateLevel; - ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Picked a new house as enemy [%s]\n", + ScriptExt::Log("[%s][%s] (line: %d = %d,%d) - AngerNodes: Picked a new house as enemy [%s]\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, @@ -281,7 +263,12 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = } else { - ScriptExt::Log("DEBUG: [%s] [%s] (line: %d = %d,%d): Failed to pick a new hated house\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, pTeam->CurrentScript->CurrentMission, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument); + ScriptExt::Log("[%s][%s] (line: %d = %d,%d) - AngerNodes: Failed to pick a new hated house.\n", + pTeam->Type->ID, + pTeam->CurrentScript->Type->ID, + pTeam->CurrentScript->CurrentMission, + pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Action, + pTeam->CurrentScript->Type->ScriptActions[pTeam->CurrentScript->CurrentMission].Argument); } // This action finished @@ -290,10 +277,8 @@ void ScriptExt::SetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int mode = 1) { - if (!pTeam) - return nullptr; - auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData || mask == 0) { // This action finished @@ -320,66 +305,23 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int bool currentMission = pTeam->CurrentScript->CurrentMission; double objectDistance = -1; double enemyDistance = -1; - int nHouses = HouseClass::Array->Count; - std::vector enemyThreatValue = std::vector(nHouses); - enemyThreatValue[nHouses] = { 0.0 }; + int currentNavalUnits = 0; HouseClass* enemyHouse = nullptr; double const& TargetSpecialThreatCoefficientDefault = RulesClass::Instance->TargetSpecialThreatCoefficientDefault; - long houseMoney = -1; - int enemyPower = -1000000000; - int enemyKills = -1; - int enemyAirDocks = -1; - int enemyStructures = -1; - int enemyNavalUnits = -1; + int initialValue = -1; - if (mask == -2) // Based on House economy + if (mask <= -2 && mask >= -10) { - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || pHouse->IsObserver() - || pHouse->Defeated - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) - { - continue; - } + int currentValue = 0; + int selectedValue = initialValue; - bool isValidCandidate = false; + // Is a house power check? It uses a different initial value that can't be reached in-game + if (mask == -4 || mask == -5 || mask == -6) + initialValue = -1000000000; - if (mode == 0) - isValidCandidate = pHouse->Available_Money() < houseMoney; // The poorest is selected - else - isValidCandidate = pHouse->Available_Money() > houseMoney; // The richest is selected - - if (isValidCandidate || houseMoney < 0) - { - houseMoney = pHouse->Available_Money(); - enemyHouse = pHouse; - } - } - - if (enemyHouse) - { - ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Selected house [%s] (index: %d).\n", - pTeam->Type->ID, - pTeam->CurrentScript->Type->ID, - currentMission, - pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, - pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument, - enemyHouse->Type->ID, - enemyHouse->ArrayIndex); - } - - return enemyHouse; - } - - if (mask == -3) // Based on human controlled check - { for (const auto& pHouse : *HouseClass::Array) { if (pLeaderUnit->Owner == pHouse - || !pHouse->IsControlledByHuman() || pHouse->IsObserver() || pHouse->Defeated || pHouse->Type->MultiplayPassive @@ -388,230 +330,113 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int continue; } - CoordStruct houseLocation; - houseLocation.X = pHouse->BaseSpawnCell.X; - houseLocation.Y = pHouse->BaseSpawnCell.Y; - houseLocation.Z = 0; - objectDistance = pLeaderUnit->Location.DistanceFrom(houseLocation); // Note: distance is in leptons (*256) - bool isValidCandidate = false; - - if (mode == 0) - isValidCandidate = objectDistance < enemyDistance; // Based in nearest human enemy unit - else - isValidCandidate = objectDistance > enemyDistance; // Based in farthest human enemy unit - - if (isValidCandidate || enemyDistance < 0) - { - enemyDistance = objectDistance; - enemyHouse = pHouse; - } - } - } - - if (mask == -4 || mask == -5 || mask == -6) // House power check - { - int checkedHousePower; - - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || pHouse->Defeated - || pHouse->IsObserver() - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) - { + if (mask == -3 && !pHouse->IsControlledByHuman()) // Only human players are valid here continue; - } - - if (mask == -4) // Related to the house's total power demand - checkedHousePower = pHouse->Power_Drain(); - - if (mask == -5) // Related to the house's total produced power - checkedHousePower = pHouse->PowerOutput; - - if (mask == -6) // Related to the house's unused power - checkedHousePower = pHouse->PowerOutput - pHouse->Power_Drain(); bool isValidCandidate = false; + currentValue = 0; - if (mode == 0) - isValidCandidate = checkedHousePower < enemyPower; // Selection based in lower value power in house - else - isValidCandidate = checkedHousePower > enemyPower; // Selection based in higher value power in house - - if (isValidCandidate || enemyPower == -10000000000) - { - enemyPower = checkedHousePower; - enemyHouse = pHouse; - } - } - } - - if (mask == -7) // Based on house's kills - { - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || pHouse->IsObserver() - || pHouse->Defeated - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + switch (mask) { - continue; - } + case -2: // Based on House economy + currentValue = pHouse->Available_Money(); + break; + + case -3: // Based on human controlled check + CoordStruct houseLocation; + houseLocation.X = pHouse->BaseSpawnCell.X; + houseLocation.Y = pHouse->BaseSpawnCell.Y; + houseLocation.Z = 0; + objectDistance = pLeaderUnit->Location.DistanceFrom(houseLocation); // Note: distance is in leptons (*256) + currentValue = objectDistance; // Note: distance is in leptons (*256) + break; + + case -4: // Related to the house's total power demand + currentValue = pHouse->Power_Drain(); + break; + + case -5: // Related to the house's total produced power + currentValue = pHouse->PowerOutput; + break; + + case -6: // Related to the house's unused power + currentValue = pHouse->PowerOutput - pHouse->Power_Drain(); + break; + + case -7: // Based on house's kills + currentValue = pHouse->TotalKilledBuildings + pHouse->TotalKilledUnits; + break; + + case -8: // Based on number of house's naval units + currentNavalUnits = 0; + + for (const auto& pUnit : *TechnoClass::Array) + { + if (ScriptExt::IsUnitAvailable(pUnit, false) + && pUnit->Owner == pHouse + && ScriptExt::EvaluateObjectWithMask(pUnit, 31, -1, -1, nullptr)) + { + currentNavalUnits++; + } + } - int currentKills = pHouse->TotalKilledBuildings + pHouse->TotalKilledUnits; - bool isValidCandidate = false; + currentValue = currentNavalUnits; + break; - if (mode == 0) - isValidCandidate = currentKills < enemyKills; // The pacifist is selected - else - isValidCandidate = currentKills > enemyKills; // The major mass murder is selected + case -9: // Based on number of House aircraft docks + currentValue = pHouse->AirportDocks; + break; - if (isValidCandidate || enemyKills < 0) - { - enemyKills = currentKills; - enemyHouse = pHouse; - } - } - } - - if (mask == -8) // Based on number of house's naval units - { - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || pHouse->IsObserver() - || pHouse->Defeated - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) - { - continue; - } - - int currentNavalUnits = 0; - - for (const auto& pUnit : *TechnoClass::Array) - { - if (pUnit->IsAlive - && pUnit->Health > 0 - && pUnit->Owner == pHouse - && !pUnit->InLimbo - && pUnit->IsOnMap - && ScriptExt::EvaluateObjectWithMask(pUnit, 31, -1, -1, nullptr)) - { - currentNavalUnits++; - } + case -10: // Based on number of house's factories (except aircraft factories) + currentValue = pHouse->NumWarFactories + pHouse->NumConYards + pHouse->NumShipyards + pHouse->NumBarracks; + break; + + default: + break; } - bool isValidCandidate = false; - if (mode == 0) - isValidCandidate = currentNavalUnits < enemyNavalUnits; // The house with less naval units is selected + isValidCandidate = currentValue < selectedValue; // The lowest is selected else - isValidCandidate = currentNavalUnits > enemyNavalUnits; // The house with more naval units is selected + isValidCandidate = currentValue > selectedValue; // The big one is selected - if (isValidCandidate || enemyNavalUnits < 0) + if (isValidCandidate || selectedValue == initialValue) { - enemyNavalUnits = currentNavalUnits; + selectedValue = currentValue; enemyHouse = pHouse; } } } - - if (mask == -9) // Based on number of House aircraft docks + else if (mask == -1 || mask > 0) { - for (const auto& pHouse : *HouseClass::Array) - { - if (pLeaderUnit->Owner == pHouse - || pHouse->IsObserver() - || pHouse->Defeated - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) - { - continue; - } - - int currentAirDocks = pHouse->AirportDocks; - bool isValidCandidate = false; - - if (mode == 0) - isValidCandidate = currentAirDocks < enemyAirDocks; // The house with less aircraft docks is selected - else - isValidCandidate = currentAirDocks > enemyAirDocks; // The house with more aircraft docks is selected - - if (isValidCandidate || enemyAirDocks < 0) - { - enemyAirDocks = currentAirDocks; - enemyHouse = pHouse; - } - } - } + // Other cases: Check all the technos and depending of the mode compare what house will be selected as the most hated + int nHouses = HouseClass::Array->Count; + std::vector enemyThreatValue = std::vector(nHouses); + enemyThreatValue[nHouses] = { 0.0 }; - if (mask == -10) // Based on number of house's factories (except aircraft factories) - { - for (const auto& pHouse : *HouseClass::Array) + for (auto pTechno : *TechnoClass::Array) { - if (pLeaderUnit->Owner == pHouse - || pHouse->IsObserver() + HouseClass* pHouse = pTechno->Owner; + + if (!ScriptExt::IsUnitAvailable(pTechno, false) || pHouse->Defeated - || pHouse->Type->MultiplayPassive - || pLeaderUnit->Owner->IsAlliedWith(pHouse)) + || pHouse == pTeam->Owner + || pHouse->IsAlliedWith(pTeam->Owner) + || pHouse->Type->MultiplayPassive) { continue; } - int currentFactories = pHouse->NumWarFactories + pHouse->NumConYards + pHouse->NumShipyards + pHouse->NumBarracks; - bool isValidCandidate = false; - - if (mode == 0) - isValidCandidate = currentFactories < enemyStructures; // The house with less factories is selected - else - isValidCandidate = currentFactories > enemyStructures; // The house with more factories is selected - - if (isValidCandidate || enemyStructures < 0) - { - enemyStructures = currentFactories; - enemyHouse = pHouse; - } - } - } - - if (enemyHouse) - { - ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Selected house [%s] (index: %d).\n", - pTeam->Type->ID, - pTeam->CurrentScript->Type->ID, - currentMission, - pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, - pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument, - enemyHouse->Type->ID, - enemyHouse->ArrayIndex); - - return enemyHouse; - } - - // Other cases: Check all the technos and depending of the mode compare what house will be selected as the most hated - for (auto pTechno : *TechnoClass::Array) - { - if (!pTechno->Owner->Defeated - && pTechno->Owner != pTeam->Owner - && pTechno->IsAlive - && !pTechno->InLimbo - && pTechno->IsOnMap - && !pTechno->Owner->IsAlliedWith(pTeam->Owner) - && !pTechno->Owner->Type->MultiplayPassive) - { - if (mask > 0) // Threat based on the new attack types of the new attack actions + if (mask > 0) // Threat based on the new attack types (or "quarry") used by the new attack actions { if (ScriptExt::EvaluateObjectWithMask(pTechno, mask, -1, -1, pLeaderUnit)) // Check if the object type is valid { if (auto const pTechnoType = pTechno->GetTechnoType()) { - enemyThreatValue[pTechno->Owner->ArrayIndex] += pTechnoType->ThreatPosed; + enemyThreatValue[pHouse->ArrayIndex] += pTechnoType->ThreatPosed; if (pTechnoType->SpecialThreatValue > 0) - enemyThreatValue[pTechno->Owner->ArrayIndex] += pTechnoType->SpecialThreatValue * TargetSpecialThreatCoefficientDefault; + enemyThreatValue[pHouse->ArrayIndex] += pTechnoType->SpecialThreatValue * TargetSpecialThreatCoefficientDefault; } } } @@ -627,42 +452,42 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int if (isValidCandidate || enemyDistance == -1) { - enemyDistance = objectDistance; - enemyHouse = pTechno->Owner; + enemyDistance = objectDistance; + enemyHouse = pHouse; } } } - } - if (mask > 0) // Pick the house with major thread - { - double enemyThreat = -1; - - for (int i = 0; i < nHouses; i++) + if (mask > 0) // Pick the house with major thread { - auto const pHouse = HouseClass::Array->GetItem(i); + double enemyThreat = -1; - if (pHouse->Defeated || pHouse->Type->MultiplayPassive || pHouse->IsObserver()) - continue; + for (std::size_t i = 0; i < nHouses; i++) + { + auto const pHouse = HouseClass::Array->GetItem(i); - bool isValidCandidate = false; + if (pHouse->Defeated || pHouse->Type->MultiplayPassive || pHouse->IsObserver()) + continue; - if (mode == 0) - isValidCandidate = enemyThreatValue[i] < enemyThreat; // The house with the nearest enemy unit - else - isValidCandidate = enemyThreatValue[i] > enemyThreat; // The house with the farthest enemy unit + bool isValidCandidate = false; - if (isValidCandidate || enemyThreat < 0) - { - enemyThreat = enemyThreatValue[i]; - enemyHouse = pHouse; + if (mode == 0) + isValidCandidate = enemyThreatValue[i] < enemyThreat; // The house with the nearest enemy unit + else + isValidCandidate = enemyThreatValue[i] > enemyThreat; // The house with the farthest enemy unit + + if (isValidCandidate || enemyThreat < 0) + { + enemyThreat = enemyThreatValue[i]; + enemyHouse = pHouse; + } } } } if (enemyHouse) { - ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Selected house [%s] (index: %d).\n", + ScriptExt::Log("[%s][%s] (line: %d = %d,%d) - AngerNodes: Selected house [%s] (index: %d).\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, currentMission, @@ -683,9 +508,6 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int // Note: only works for new Phobos script actions, not the original ones void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) { - if (!pTeam) - return; - auto pTeamData = TeamExt::ExtMap.Find(pTeam); if (!pTeamData) { @@ -723,7 +545,7 @@ void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) } int currentMission = pTeam->CurrentScript->CurrentMission; - ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Team's 'OnlyTargetHouseEnemy' value overwrited. Now is '%d'.\n", + ScriptExt::Log("[%s][%s] (line: %d = %d,%d) - AngerNodes: Team's 'OnlyTargetHouseEnemy' value overwrited. Now is '%d'.\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, currentMission, @@ -737,10 +559,8 @@ void ScriptExt::OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode = -1) void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) { - if (!pTeam) - return; - auto pTeamData = TeamExt::ExtMap.Find(pTeam); + if (!pTeamData || pTeamData->AngerNodeModifier == 0) { // This action finished @@ -767,7 +587,7 @@ void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) && !angerNode.House->IsObserver()) { angerNode.AngerLevel += pTeamData->AngerNodeModifier; - ScriptExt::Log("[%s][%s] (line: %d = %d,%d): Modified AngerNode level of [%s](index: %d) against house [%s](index: %d). Current hate value: %d\n", + ScriptExt::Log("[%s][%s] (line: %d = %d,%d) - AngerNodes: Modified AngerNode level of [%s](index: %d) against house [%s](index: %d). Current hate value: %d\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, currentMission, @@ -782,7 +602,6 @@ void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) } ScriptExt::UpdateEnemyHouseIndex(pTeam->Owner); - ScriptExt::DebugAngerNodesData(); // Remove this line before merging into develop branch! // This action finished pTeam->StepCompleted = true; @@ -791,9 +610,6 @@ void ScriptExt::ModifyHateHouse_Index(TeamClass* pTeam, int idxHouse = -1) // The selected house will become the most hated of the map (the effects are only visible if the other houses are enemy of the selected house) void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) { - if (!pTeam) - return; - auto pTeamData = TeamExt::ExtMap.Find(pTeam); if (!pTeamData) { @@ -856,7 +672,7 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) if (objectsList.size() == 0) { - ScriptExt::Log("[%s][%s] (line: %d = %d,%d): [%s](index: %d) failed to pick a new house as main enemy using index '%d'.\n", + ScriptExt::Log("[%s][%s] (line: %d = %d,%d) - AngerNodes: [%s](index: %d) failed to pick a new house as main enemy using index '%d'.\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, currentMission, @@ -910,8 +726,6 @@ void ScriptExt::AggroHouse(TeamClass* pTeam, int index = -1) ScriptExt::UpdateEnemyHouseIndex(pHouse); } - ScriptExt::DebugAngerNodesData(); // Remove this line before merging into develop branch! - // This action finished pTeam->StepCompleted = true; } @@ -939,34 +753,3 @@ void ScriptExt::UpdateEnemyHouseIndex(HouseClass* pHouse) pHouse->EnemyHouseIndex = index; } - -void ScriptExt::DebugAngerNodesData() -{ - ScriptExt::Log("Updated AngerNodes lists of every playable House:\n"); - - for (auto pHouse : *HouseClass::Array) - { - if (pHouse->IsObserver()) - ScriptExt::Log("Player %d [Observer] ", pHouse->ArrayIndex); - else - ScriptExt::Log("Player %d [%s]: ", pHouse->ArrayIndex, pHouse->Type->ID); - - int i = 0; - - for (auto& angerNode : pHouse->AngerNodes) - { - if (!pHouse->IsObserver()) - ScriptExt::Log("%d:%d", angerNode.House->ArrayIndex, angerNode.AngerLevel); - - if (i < HouseClass::Array->Count - 2 && !pHouse->IsObserver()) - ScriptExt::Log(", "); - - i++; - } - - if (!pHouse->IsObserver()) - ScriptExt::Log(" -> Main Enemy House: %d\n", pHouse->EnemyHouseIndex); - else - ScriptExt::Log("\n"); - } -} diff --git a/src/Ext/Script/Body.h b/src/Ext/Script/Body.h index 6a5f58269e..d8b8760833 100644 --- a/src/Ext/Script/Body.h +++ b/src/Ext/Script/Body.h @@ -227,7 +227,6 @@ class ScriptExt static void OverrideOnlyTargetHouseEnemy(TeamClass* pTeam, int mode); static void AggroHouse(TeamClass* pTeam, int index); static HouseClass* GetTheMostHatedHouse(TeamClass* pTeam, int mask, int mode); - static void DebugAngerNodesData(); static bool IsExtVariableAction(int action); static void VariablesHandler(TeamClass* pTeam, PhobosScripts eAction, int nArg); From d4de5c3a8f8139dc3991c766510f0799d2b5cd54 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sat, 13 Jul 2024 12:30:54 +0200 Subject: [PATCH 43/48] Small teak --- src/Ext/Script/Body.AngerNodes.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Ext/Script/Body.AngerNodes.cpp b/src/Ext/Script/Body.AngerNodes.cpp index 73e634f764..d64f917906 100644 --- a/src/Ext/Script/Body.AngerNodes.cpp +++ b/src/Ext/Script/Body.AngerNodes.cpp @@ -287,10 +287,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } // Note regarding "mode": 1 is used for ">" comparisons and 0 for "<" - if (mode <= 0) - mode = 0; - else - mode = 1; + mode = mode <= 0 ? 0 : 1; // Find the Team Leader FootClass* pLeaderUnit = FindTheTeamLeader(pTeam); From f2d1480c0593329289fa5df119d72c4025b97175 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sat, 13 Jul 2024 12:51:57 +0200 Subject: [PATCH 44/48] small tweak --- src/Ext/Script/Body.AngerNodes.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Ext/Script/Body.AngerNodes.cpp b/src/Ext/Script/Body.AngerNodes.cpp index d64f917906..f7c8306558 100644 --- a/src/Ext/Script/Body.AngerNodes.cpp +++ b/src/Ext/Script/Body.AngerNodes.cpp @@ -300,12 +300,11 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int } bool currentMission = pTeam->CurrentScript->CurrentMission; + HouseClass* enemyHouse = nullptr; + int initialValue = -1; double objectDistance = -1; double enemyDistance = -1; int currentNavalUnits = 0; - HouseClass* enemyHouse = nullptr; - double const& TargetSpecialThreatCoefficientDefault = RulesClass::Instance->TargetSpecialThreatCoefficientDefault; - int initialValue = -1; if (mask <= -2 && mask >= -10) { @@ -410,6 +409,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int int nHouses = HouseClass::Array->Count; std::vector enemyThreatValue = std::vector(nHouses); enemyThreatValue[nHouses] = { 0.0 }; + double const& TargetSpecialThreatCoefficientDefault = RulesClass::Instance->TargetSpecialThreatCoefficientDefault; for (auto pTechno : *TechnoClass::Array) { From f29da380f0f274468237b0deeb99ede253c93264 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sat, 13 Jul 2024 13:58:00 +0200 Subject: [PATCH 45/48] tweaks --- src/Ext/Script/Body.AngerNodes.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Ext/Script/Body.AngerNodes.cpp b/src/Ext/Script/Body.AngerNodes.cpp index f7c8306558..67a40d83b0 100644 --- a/src/Ext/Script/Body.AngerNodes.cpp +++ b/src/Ext/Script/Body.AngerNodes.cpp @@ -302,8 +302,8 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int bool currentMission = pTeam->CurrentScript->CurrentMission; HouseClass* enemyHouse = nullptr; int initialValue = -1; - double objectDistance = -1; - double enemyDistance = -1; + double objectDistance = initialValue; + double enemyDistance = initialValue; int currentNavalUnits = 0; if (mask <= -2 && mask >= -10) @@ -447,7 +447,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int else isValidCandidate = objectDistance > enemyDistance; // The house with the farthest enemy unit - if (isValidCandidate || enemyDistance == -1) + if (isValidCandidate || enemyDistance == initialValue) { enemyDistance = objectDistance; enemyHouse = pHouse; @@ -457,7 +457,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int if (mask > 0) // Pick the house with major thread { - double enemyThreat = -1; + double enemyThreat = initialValue; for (std::size_t i = 0; i < nHouses; i++) { @@ -473,7 +473,7 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int else isValidCandidate = enemyThreatValue[i] > enemyThreat; // The house with the farthest enemy unit - if (isValidCandidate || enemyThreat < 0) + if (isValidCandidate || enemyThreat == initialValue) { enemyThreat = enemyThreatValue[i]; enemyHouse = pHouse; @@ -484,12 +484,14 @@ HouseClass* ScriptExt::GetTheMostHatedHouse(TeamClass* pTeam, int mask = 0, int if (enemyHouse) { - ScriptExt::Log("[%s][%s] (line: %d = %d,%d) - AngerNodes: Selected house [%s] (index: %d).\n", + ScriptExt::Log("[%s][%s] (line: %d = %d,%d) - AngerNodes: [%s] (index: %d) picked [%s] (index: %d).\n", pTeam->Type->ID, pTeam->CurrentScript->Type->ID, currentMission, pTeam->CurrentScript->Type->ScriptActions[currentMission].Action, pTeam->CurrentScript->Type->ScriptActions[currentMission].Argument, + pTeam->Owner->Type->ID, + pTeam->Owner->ArrayIndex, enemyHouse->Type->ID, enemyHouse->ArrayIndex); } From 11449a9f768aec58e163cd76018d23924f14514e Mon Sep 17 00:00:00 2001 From: FS-21 Date: Sat, 13 Jul 2024 15:54:25 +0200 Subject: [PATCH 46/48] Update src/Ext/Script/Body.AngerNodes.cpp Co-authored-by: Kerbiter --- src/Ext/Script/Body.AngerNodes.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Ext/Script/Body.AngerNodes.cpp b/src/Ext/Script/Body.AngerNodes.cpp index 67a40d83b0..0f8c9e7b0f 100644 --- a/src/Ext/Script/Body.AngerNodes.cpp +++ b/src/Ext/Script/Body.AngerNodes.cpp @@ -5,9 +5,7 @@ void ScriptExt::ResetAngerAgainstHouses(TeamClass* pTeam) { for (auto& angerNode : pTeam->Owner->AngerNodes) - { angerNode.AngerLevel = 0; - } pTeam->Owner->EnemyHouseIndex = -1; From 535d929f9d0dd4884d161a529f216fbcf1295a13 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Thu, 29 Aug 2024 11:55:30 +0200 Subject: [PATCH 47/48] FA2 documentation --- docs/Whats-New.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 0c292ebd5c..9622e29a0b 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -215,6 +215,15 @@ SaveGameOnScenarioStart=true ; boolean 10102=Regroup Temporarily Around the Team Leader,20,0,1,[LONG DESC] 10103=Load Onto Transports,0,0,1,[LONG DESC] 10104=Chronoshift to Enemy Base,20,0,1,[LONG DESC] + 14006=Set House Hate Value Modifier,20,0,1,[LONG DESC] + 14007=Modify House Hate Using House Index,20,0,1,[LONG DESC] + 14008=Modify Hate Values From A List Of Countries,28,0,1,[LONG DESC] + 14009=Modify Hate Value Against A Random Country From A List Of Countries,28,0,1,[LONG DESC] + 14010=Set The Most Hated House ("<" Comparison),20,0,1,[LONG DESC] + 14011=Set The Most Hated House (">" Comparison),20,0,1,[LONG DESC] + 14012=Set The Most Hated House Randomly,0,0,1,[LONG DESC] + 14013=Reset Hate Against Other Houses,0,0,1,[LONG DESC] + 14014=Set A House As The Most Hated House Of The Map,20,0,1,[LONG DESC] 18000=Local variable set,22,0,1,[LONG DESC] 18001=Local variable add,22,0,1,[LONG DESC] 18002=Local variable minus,22,0,1,[LONG DESC] @@ -295,6 +304,10 @@ SaveGameOnScenarioStart=true ; boolean 25=Local variables,-4 26=Global variables,-5 27=Global variables,-6 + 28=AI Houses List, -7 + + [ScriptParamTypes] + 7=AIHousesList,1,1,0 ``` From 51317cbdcc58af8c240c822dad136d7181dd0ae3 Mon Sep 17 00:00:00 2001 From: FS-21 Date: Thu, 7 Aug 2025 12:53:30 +0200 Subject: [PATCH 48/48] Update YRpp --- YRpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YRpp b/YRpp index 1a4e510539..2d19944aa0 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit 1a4e510539459bc3535b477e2b1a873fc62821f0 +Subproject commit 2d19944aa0846a098826b4cdd2e0ac00f36915b0