diff --git a/src/OpenSHC/Map/Units/UnitsState/Constructor_UnitsState.cpp b/src/OpenSHC/Map/Units/UnitsState/Constructor_UnitsState.cpp new file mode 100644 index 000000000..849750f99 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/Constructor_UnitsState.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053B8B0 + UnitsState* UnitsState::Constructor_UnitsState() + { + this->creationTime = timeGetTime(); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::clearAllUnits, this)(); + this->lastSelectedUnitID = 0; + this->unknownInitially0_01 = 0; + this->lostChimps = 0; + this->maxUnitCount = 2500; + return this; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/acquireShootTarget.cpp b/src/OpenSHC/Map/Units/UnitsState/acquireShootTarget.cpp new file mode 100644 index 000000000..85f1e1d83 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/acquireShootTarget.cpp @@ -0,0 +1,547 @@ +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_EntityDefinedData.hpp" +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0054B0D0 + BOOLEnum UnitsState::acquireShootTarget(int unitID) + + { + int _xDifferenceToTarget; + int _entityType; + int _unitPlayerID = (int)this->units[unitID].owner; + int _microXUnit = (int)this->units[unitID].microXPosition; + int _microYUnit = (int)this->units[unitID].microYPosition; + int _unitTotalHeight + = (int)this->units[unitID].buildingHeight + (int)this->units[unitID].terrainOrClimbHeight; + int _validTargetID = 0; + int _bestScore = 100000; + int _shotDistance = 0; + int _bestUntargetedScore = 100000; + int _untargetedTargetID = 0; + int _untargetedShotDistance = 0; + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_E_XBOW: + _entityType = 7; + break; + default: + _entityType = 1; + break; + case OpenSHC::Map::Units::UT_S_CATAPULT: + _entityType = 2; + if ((this->units[unitID].stoneAmmunition <= 0) + && (this->units[unitID].targetingType != OpenSHC::Map::Units::UIT_THROW_COW)) { + this->units[unitID].targetingType = OpenSHC::Map::Units::UIT_NO_INSTRUCTION_OR_MOVEUnk; + return FALSE; + } + break; + case OpenSHC::Map::Units::UT_S_TREBUCHET: + _entityType = 3; + if ((this->units[unitID].stoneAmmunition <= 0) + && (this->units[unitID].targetingType != OpenSHC::Map::Units::UIT_THROW_COW)) { + this->units[unitID].targetingType = OpenSHC::Map::Units::UIT_NO_INSTRUCTION_OR_MOVEUnk; + return FALSE; + } + break; + case OpenSHC::Map::Units::UT_S_MANGONEL: + _entityType = 4; + break; + case OpenSHC::Map::Units::UT_S_BALLISTA: + _entityType = 0x14; + break; + case OpenSHC::Map::Units::UT_A_SLINGER: + _entityType = 0x21; + break; + case OpenSHC::Map::Units::UT_A_FIRETHROWER: + _entityType = 0x22; + break; + case OpenSHC::Map::Units::UT_S_FBALLISTA: + _entityType = 0x25; + } + int _rangeSquared = DAT_EntityDefinedData::instance.EntityTypeArrayForProjectileRange[_entityType] + * DAT_EntityDefinedData::instance.EntityTypeArrayForProjectileRange[_entityType]; + /* + fetch attacking explicitness + */ + + if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_UNIT_ATTACK_UNIT) { + /* + if explicitness = 4 (user selected attack)... + fetch the targetedUnitID + */ + + int _mannedEngineTargetID = this->units[unitID].targetedUnitID__OR__engineerMannedSiegeEngineRef; + int _0x04_targetUnitID = (int)_mannedEngineTargetID; + if (this->units[_0x04_targetUnitID].uid + == this->units[unitID] + .targetedUnitUIDUnk_OR_someAppearTileUnk_OR_buildingUID_OR_pitchDitchUID_OR_entityUID + && this->units[_0x04_targetUnitID].dying == 0 + && this->units[_0x04_targetUnitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL) { + BOOLEnum _targetIsAliveCitizen + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::checkIfCitizenUnitIsAliveBasedOnState, + this)(_0x04_targetUnitID); + if (_targetIsAliveCitizen == FALSE + && this->units[_0x04_targetUnitID].state.generic + != (OpenSHC::Map::Units::States::US_STONE_DEATH_03 + | OpenSHC::Map::Units::States::US_IDLEUnk) + && DAT_GameState::instance.mapAndTime.playerTeams[this->units[_0x04_targetUnitID].owner] + != DAT_GameState::instance.mapAndTime.playerTeams[_unitPlayerID]) { + int _0x04_yDifference + = ((int)_microYUnit / 8) - ((int)this->units[_0x04_targetUnitID].microYPosition / 8); + _xDifferenceToTarget + = ((int)_microXUnit / 8) - ((int)this->units[_0x04_targetUnitID].microXPosition / 8); + if (_xDifferenceToTarget * _xDifferenceToTarget + _0x04_yDifference * _0x04_yDifference + <= _rangeSquared) { + int _shootDistanceScore + = MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::arrowShootingRelated, + DAT_EntityState::ptr)(_microXUnit, _microYUnit, _unitTotalHeight + 0x1e, + (int)(this->units[_0x04_targetUnitID].microXPosition), + (int)(this->units[_0x04_targetUnitID].microYPosition), + (int)(this->units[_0x04_targetUnitID].buildingHeight + 0x1a + + this->units[_0x04_targetUnitID].terrainOrClimbHeight)); + if (_shootDistanceScore <= 0 + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_MANGONEL + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_BALLISTA) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_HUNTER) { + return FALSE; + } + this->units[unitID].shootTargetedUnit = -2; + this->units[unitID].shootTargetMicroX = this->units[_0x04_targetUnitID].microXPosition; + this->units[unitID].shootTargetMicroY = this->units[_0x04_targetUnitID].microYPosition; + this->units[unitID].shootTargetZ = this->units[_0x04_targetUnitID].terrainOrClimbHeight; + return TRUE; + } + this->units[unitID].shootTargetedUnit = _mannedEngineTargetID; + this->units[unitID].targetUID = this->units[_0x04_targetUnitID].uid; + this->units[unitID].distanceToEnemyUnitLadders = (short)_shootDistanceScore; + this->units[unitID].shootTargetMicroX = this->units[_0x04_targetUnitID].microXPosition; + this->units[unitID].shootTargetMicroY = this->units[_0x04_targetUnitID].microYPosition; + this->units[unitID].shootTargetZ = this->units[_0x04_targetUnitID].terrainOrClimbHeight; + if (100 < _shootDistanceScore) { + this->units[unitID].jugglerCount = 0; + this->units[_0x04_targetUnitID].field233_0x39a = 1; + return TRUE; + } + int _targetTotalHeight = (int)this->units[_0x04_targetUnitID].terrainOrClimbHeight + + (int)this->units[_0x04_targetUnitID].buildingHeight; + _unitPlayerID = (int)this->units[unitID].buildingHeight + + (int)this->units[unitID].terrainOrClimbHeight; + if (_targetTotalHeight + 0x46 < _unitPlayerID) { + this->units[unitID].jugglerCount = 1; + this->units[_0x04_targetUnitID].field233_0x39a = 1; + return TRUE; + } + this->units[unitID].jugglerCount = (_targetTotalHeight + -0x46 <= _unitPlayerID) - 1; + this->units[_0x04_targetUnitID].field233_0x39a = 1; + return TRUE; + } + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[this->units[unitID].owner] + != -1) { + return FALSE; + } + } + } + int _savedDestinationX = this->units[unitID]._someX_2; + this->units[unitID].targetedUnitID__OR__engineerMannedSiegeEngineRef = 0; + this->units[unitID].shootTargetedUnit = 0; + this->units[unitID].targetingType = OpenSHC::Map::Units::UIT_NO_INSTRUCTION_OR_MOVEUnk; + if (_savedDestinationX != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, (uint)(_savedDestinationX), (uint)((int)this->units[unitID]._someY_2), 0); + this->units[unitID]._someX_2 = 0; + this->units[unitID]._someY_2 = 0; + this->units[unitID].moveDelay = 0; + this->units[unitID].targetedBuildingTile = 0; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_MOVE_TO_DESTINATION; + return TRUE; + } + } + if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_LIGHT_PITCH) { + /* + get the workplace building id + */ + + int _ditchID = this->units[unitID].targetID_OR_targetBuildingID; + int _brazierEntityID; + if (DAT_TileMapState::instance.pitchDitches[_ditchID].uid + == this->units[unitID] + .targetedUnitUIDUnk_OR_someAppearTileUnk_OR_buildingUID_OR_pitchDitchUID_OR_entityUID + && (_brazierEntityID = MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::isBrazierNearby, + DAT_EntityState::ptr)((int)this->units[unitID].x, (int)(this->units[unitID].y), + (int)(( + int)(this->units[unitID].buildingHeight + this->units[unitID].terrainOrClimbHeight))), + _brazierEntityID != 0)) { + this->units[unitID].shootTargetMicroX = DAT_TileMapState::instance.pitchDitches[_ditchID].x * 8 + 4; + this->units[unitID].shootTargetMicroY = DAT_TileMapState::instance.pitchDitches[_ditchID].y * 8 + 4; + this->units[unitID].shootTargetZ + = (ushort)DAT_TileMapState::instance + .HeightLayer[DAT_TileMapState::instance.pitchDitches[_ditchID].tile]; + this->units[unitID].shootTargetedUnit = -1; + return TRUE; + } + } else if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_ATTACK_BUILDING) { + int _buildingID = this->units[unitID].targetID_OR_targetBuildingID; + if (DAT_BuildingsState::instance.buildings[_buildingID].uid + == this->units[unitID] + .targetedUnitUIDUnk_OR_someAppearTileUnk_OR_buildingUID_OR_pitchDitchUID_OR_entityUID) { + this->units[unitID].shootTargetMicroX = DAT_BuildingsState::instance.buildings[_buildingID].x * 8 + + (short)((int)(DAT_BuildingsState::instance.buildings[_buildingID].widthOrHeight * 8) / 2); + this->units[unitID].shootTargetMicroY = DAT_BuildingsState::instance.buildings[_buildingID].y * 8 + + (short)((int)(DAT_BuildingsState::instance.buildings[_buildingID].widthOrHeight * 8) / 2); + this->units[unitID].shootTargetZ + = DAT_BuildingsState::instance.buildings[_buildingID].terrainHeightUnk; + this->units[unitID].shootTargetedUnit = -1; + return TRUE; + } + } else if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_ATTACK_WALL) { + int _0x17_y = (int)this->units[unitID].attackAtTileY; + int _0x17_x = (int)this->units[unitID].attackAtTileX; + int _0x17_tile = DAT_ViewportRenderState::instance.translationMatrix[_0x17_y].addXgetTile + _0x17_x; + BOOLEnum _tileIsValid = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(_0x17_x, (uint)(_0x17_y)); + if (_tileIsValid != FALSE && (DAT_TileMapState::instance.LogicLayer[_0x17_tile] & 0x100U) != 0) { + this->units[unitID].shootTargetMicroX = this->units[unitID].attackAtTileX * 8; + this->units[unitID].shootTargetMicroY = this->units[unitID].attackAtTileY * 8; + this->units[unitID].shootTargetZ + = (short)((int)((uint)DAT_TileMapState::instance.HeightLayer[_0x17_tile] + - (uint)DAT_TileMapState::instance.DefaultHeightLayer[_0x17_tile]) + / 2) + + (ushort)DAT_TileMapState::instance.DefaultHeightLayer[_0x17_tile]; + this->units[unitID].shootTargetedUnit = -1; + return TRUE; + } + } else { + if ((this->units[unitID].targetingType != OpenSHC::Map::Units::UIT_ATTACK_LAND) + && (this->units[unitID].targetingType != OpenSHC::Map::Units::UIT_THROW_COW)) { + if (_entityType == 2) { + return FALSE; + } + if (_entityType == 3) { + return FALSE; + } + for (int _enemyIndex = 0; + _enemyIndex < DAT_GameState::instance.playerDataArray[_unitPlayerID].enemies; + _enemyIndex = _enemyIndex + 1) { + int _enemy = DAT_GameState::instance.playerDataArray[_unitPlayerID].enemyIDArray[_enemyIndex]; + if ((this->units[_enemy].dying != 0) + || (this->units[_enemy].uid + != DAT_GameState::instance.mapAndTime + .playerEnemenyUnitUIDShortList[_unitPlayerID][_enemyIndex])) + continue; + switch (this->units[_enemy].unitType) { + case OpenSHC::Map::Units::UT_ANTELOPESHDEER: + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_HUNTER) + continue; + break; + case OpenSHC::Map::Units::UT_LIONSHWOLF: { + int _enemyTribeID = this->units[_enemy].tribeID; + if (DAT_TribesState::instance.tribes[_enemyTribeID].unknownBool02 != 0 + || (DAT_TribesState::instance.tribes[_enemyTribeID].unknownBool01 == 0 + && ((this->units[_enemy].state.generic != 0xcf + || (this->units[this->units[_enemy] + .targetedUnitID__OR__engineerMannedSiegeEngineRef] + .isStalked + != 0))))) + continue; + break; + } + case OpenSHC::Map::Units::UT_RABBIT: + _xDifferenceToTarget = (int)this->units[unitID].tribeID; + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_HUNTER + || _xDifferenceToTarget <= 0 + || DAT_TribesState::instance.tribes[_xDifferenceToTarget].field71_0x212 == 0) + continue; + break; + case OpenSHC::Map::Units::UT_CAGEDOG: + if (DAT_GameState::instance.mapAndTime.playerTeams[this->units[_enemy].displayColorPlayerID] + == DAT_GameState::instance.mapAndTime.playerTeams[this->units[unitID].owner]) + continue; + break; + case OpenSHC::Map::Units::UT_A_ASSASSIN: + if (160 < this->units[_enemy].assassinsMicroDistanceToEnemyUnk) + continue; + } + _xDifferenceToTarget = (int)this->units[_enemy].microYPosition; + int _enemyMicroX = (int)this->units[_enemy].microXPosition; + int _yDifferenceToTarget = ((int)_microYUnit / 8) - ((int)_xDifferenceToTarget / 8); + _xDifferenceToTarget = (_microXUnit / 8) - (_enemyMicroX / 8); + if (_rangeSquared + < _xDifferenceToTarget * _xDifferenceToTarget + _yDifferenceToTarget * _yDifferenceToTarget) + continue; + _xDifferenceToTarget = (int)this->units[_enemy].microXPosition; + if (_xDifferenceToTarget < _microXUnit) { + _xDifferenceToTarget = _microXUnit - _xDifferenceToTarget; + } else { + _xDifferenceToTarget = _xDifferenceToTarget - _microXUnit; + } + int _enemyMicroY = (int)this->units[_enemy].microYPosition; + if (_enemyMicroY < _microYUnit) { + _yDifferenceToTarget = _microYUnit - _enemyMicroY; + } else { + _yDifferenceToTarget = _enemyMicroY - _microYUnit; + } + if (_xDifferenceToTarget < _yDifferenceToTarget) { + _xDifferenceToTarget = _yDifferenceToTarget; + } + _xDifferenceToTarget = _xDifferenceToTarget + this->units[_enemy].field265_0x3dc * 0x32; + bool _scoreNeedsValidityCheck; + if (_entityType == 4) { + switch (this->units[_enemy].unitType) { + case OpenSHC::Map::Units::UT_E_ENGINEER: + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_TREBUCHET: + case OpenSHC::Map::Units::UT_S_MANGONEL: + case OpenSHC::Map::Units::UT_S_TOWER: + case OpenSHC::Map::Units::UT_S_BATTERINGRAM: + case OpenSHC::Map::Units::UT_S_SHIELD: + case OpenSHC::Map::Units::UT_S_BALLISTA: + case OpenSHC::Map::Units::UT_S_FBALLISTA: + break; + default: + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[this->units[unitID].owner] + != -1) + continue; + if (this->units[_enemy].isSelectable_OR_matchTime == 0) { + _xDifferenceToTarget = (_xDifferenceToTarget * 5 + 0x32) * 2; + } else { + _xDifferenceToTarget = _xDifferenceToTarget * 3 + 100; + } + } + _scoreNeedsValidityCheck = true; + } else if (_entityType == 0x14) { + switch (this->units[_enemy].unitType) { + case OpenSHC::Map::Units::UT_E_ARCHER: + case OpenSHC::Map::Units::UT_E_XBOW: + case OpenSHC::Map::Units::UT_E_SPEAR: + case OpenSHC::Map::Units::UT_E_MACE: + case OpenSHC::Map::Units::UT_E_LADDER: + case OpenSHC::Map::Units::UT_A_ARCHER: + case OpenSHC::Map::Units::UT_A_SLAVE: + case OpenSHC::Map::Units::UT_A_SLINGER: + case OpenSHC::Map::Units::UT_A_ASSASSIN: + case OpenSHC::Map::Units::UT_A_HARCHER: + _xDifferenceToTarget = _xDifferenceToTarget * 5 + 200; + break; + case OpenSHC::Map::Units::UT_E_PIKE: + case OpenSHC::Map::Units::UT_E_SWORD: + case OpenSHC::Map::Units::UT_E_KNIGHT: + case OpenSHC::Map::Units::UT_A_SWORDSMAN: + break; + case OpenSHC::Map::Units::UT_E_ENGINEER: + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_TREBUCHET: + case OpenSHC::Map::Units::UT_S_MANGONEL: + case OpenSHC::Map::Units::UT_LORD: + case OpenSHC::Map::Units::UT_S_TOWER: + case OpenSHC::Map::Units::UT_S_BATTERINGRAM: + case OpenSHC::Map::Units::UT_S_SHIELD: + case OpenSHC::Map::Units::UT_S_BALLISTA: + case OpenSHC::Map::Units::UT_A_FIRETHROWER: + case OpenSHC::Map::Units::UT_S_FBALLISTA: + _xDifferenceToTarget = _xDifferenceToTarget * 2 + 100; + break; + default: + _xDifferenceToTarget = (_xDifferenceToTarget * 5 + 200) * 2; + } + _scoreNeedsValidityCheck = false; + } else if (_entityType != 0x25) { + if ((this->units[_enemy].field289_0x3ff != 0) + && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[this->units[_enemy].owner] + == -1)) { + _xDifferenceToTarget = _xDifferenceToTarget / 3; + } + switch (this->units[_enemy].unitType) { + case OpenSHC::Map::Units::UT_E_ARCHER: + case OpenSHC::Map::Units::UT_E_XBOW: + case OpenSHC::Map::Units::UT_A_ARCHER: + case OpenSHC::Map::Units::UT_A_HARCHER: + _xDifferenceToTarget = _xDifferenceToTarget + 0x4b; + break; + case OpenSHC::Map::Units::UT_E_SPEAR: + case OpenSHC::Map::Units::UT_E_PIKE: + case OpenSHC::Map::Units::UT_E_MACE: + case OpenSHC::Map::Units::UT_E_SWORD: + case OpenSHC::Map::Units::UT_E_KNIGHT: + case OpenSHC::Map::Units::UT_A_SLAVE: + case OpenSHC::Map::Units::UT_A_SLINGER: + case OpenSHC::Map::Units::UT_A_ASSASSIN: + case OpenSHC::Map::Units::UT_A_SWORDSMAN: + _xDifferenceToTarget = _xDifferenceToTarget * 5 + 200; + break; + case OpenSHC::Map::Units::UT_E_LADDER: + _xDifferenceToTarget = _xDifferenceToTarget * 7 + 300; + break; + case OpenSHC::Map::Units::UT_E_ENGINEER: + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_TREBUCHET: + case OpenSHC::Map::Units::UT_LORD: + _xDifferenceToTarget = _xDifferenceToTarget * 2 + 100; + break; + default: + _xDifferenceToTarget = (_xDifferenceToTarget * 5 + 200) * 2; + break; + case OpenSHC::Map::Units::UT_S_MANGONEL: + case OpenSHC::Map::Units::UT_S_BALLISTA: + case OpenSHC::Map::Units::UT_A_FIRETHROWER: + case OpenSHC::Map::Units::UT_S_FBALLISTA: + break; + } + _scoreNeedsValidityCheck = false; + } else { + switch (this->units[_enemy].unitType) { + case OpenSHC::Map::Units::UT_E_ARCHER: + case OpenSHC::Map::Units::UT_E_XBOW: + case OpenSHC::Map::Units::UT_E_SPEAR: + case OpenSHC::Map::Units::UT_E_MACE: + case OpenSHC::Map::Units::UT_E_LADDER: + case OpenSHC::Map::Units::UT_A_ARCHER: + case OpenSHC::Map::Units::UT_A_SLAVE: + case OpenSHC::Map::Units::UT_A_SLINGER: + case OpenSHC::Map::Units::UT_A_ASSASSIN: + case OpenSHC::Map::Units::UT_A_HARCHER: + _xDifferenceToTarget = _xDifferenceToTarget * 5 + 200; + break; + case OpenSHC::Map::Units::UT_E_PIKE: + case OpenSHC::Map::Units::UT_E_SWORD: + case OpenSHC::Map::Units::UT_E_KNIGHT: + case OpenSHC::Map::Units::UT_A_SWORDSMAN: + break; + case OpenSHC::Map::Units::UT_E_ENGINEER: + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_TREBUCHET: + case OpenSHC::Map::Units::UT_S_MANGONEL: + case OpenSHC::Map::Units::UT_S_TOWER: + case OpenSHC::Map::Units::UT_S_BATTERINGRAM: + case OpenSHC::Map::Units::UT_S_SHIELD: + case OpenSHC::Map::Units::UT_S_BALLISTA: + case OpenSHC::Map::Units::UT_A_FIRETHROWER: + case OpenSHC::Map::Units::UT_S_FBALLISTA: + _xDifferenceToTarget = _xDifferenceToTarget * 2 + 100; + break; + default: + continue; + case OpenSHC::Map::Units::UT_LORD: + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_unitPlayerID] != -1) + _xDifferenceToTarget = _xDifferenceToTarget * 5 + 200; + break; + } + _scoreNeedsValidityCheck = true; + } + if (!_scoreNeedsValidityCheck || _xDifferenceToTarget != -1) { + if (_xDifferenceToTarget < _bestScore || _xDifferenceToTarget < _bestUntargetedScore) { + int _shotFlightDistance + = MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::arrowShootingRelated, + DAT_EntityState::ptr)(_microXUnit, _microYUnit, _unitTotalHeight + 0x1e, + (int)(this->units[_enemy].microXPosition), _enemyMicroY, + (int)(this->units[_enemy].buildingHeight + 0x1a + + this->units[_enemy].terrainOrClimbHeight)); + if (_shotFlightDistance > 0) { + if (_xDifferenceToTarget < _bestScore) { + _bestScore = _xDifferenceToTarget; + _validTargetID = _enemy; + _shotDistance = _shotFlightDistance; + } + if (this->units[_enemy].field233_0x39a == 0 + && _xDifferenceToTarget < _bestUntargetedScore) { + _bestUntargetedScore = _xDifferenceToTarget; + _untargetedTargetID = _enemy; + _untargetedShotDistance = _shotFlightDistance; + } + } + } + } + } + if (_validTargetID == 0) { + return FALSE; + } + if ((_untargetedTargetID != 0) && (_bestUntargetedScore < (_bestScore * 3) / 2)) { + _validTargetID = _untargetedTargetID; + _shotDistance = _untargetedShotDistance; + } + if (_entityType == 4) { + this->units[unitID].shootTargetedUnit = -2; + this->units[unitID].shootTargetMicroX = this->units[_validTargetID].microXPosition; + this->units[unitID].shootTargetMicroY = this->units[_validTargetID].microYPosition; + this->units[unitID].shootTargetZ = this->units[_validTargetID].terrainOrClimbHeight; + return TRUE; + } + short _chosenTargetID = (short)_validTargetID; + if ((_entityType == 0x25) || (_entityType == 0x14)) { + this->units[unitID].shootTargetedUnit = _chosenTargetID; + this->units[unitID].targetUID = this->units[_validTargetID].uid; + this->units[unitID].distanceToEnemyUnitLadders = (short)_shotDistance; + this->units[unitID].shootTargetMicroX = this->units[_validTargetID].microXPosition; + this->units[unitID].shootTargetMicroY = this->units[_validTargetID].microYPosition; + this->units[unitID].shootTargetZ = this->units[_validTargetID].terrainOrClimbHeight; + return TRUE; + } + this->units[_validTargetID].field265_0x3dc = this->units[_validTargetID].field265_0x3dc + 1; + this->units[unitID].shootTargetedUnit = _chosenTargetID; + this->units[unitID].field266_0x3de = _chosenTargetID; + this->units[unitID].targetUID = this->units[_validTargetID].uid; + this->units[unitID].distanceToEnemyUnitLadders = (short)_shotDistance; + if (100 < _shotDistance) { + this->units[unitID].jugglerCount = 0; + this->units[_validTargetID].field233_0x39a = 1; + return TRUE; + } + _unitPlayerID = (int)this->units[_validTargetID].terrainOrClimbHeight + + (int)this->units[_validTargetID].buildingHeight; + _microXUnit + = (int)this->units[unitID].buildingHeight + (int)this->units[unitID].terrainOrClimbHeight; + if (_unitPlayerID + 0x46 < _microXUnit) { + this->units[unitID].jugglerCount = 1; + this->units[_validTargetID].field233_0x39a = 1; + return TRUE; + } + this->units[unitID].jugglerCount = (_unitPlayerID + -0x46 <= _microXUnit) - 1; + this->units[_validTargetID].field233_0x39a = 1; + return TRUE; + } + int _attackTileY = this->units[unitID].attackAtTileY; + int _attackTileX = this->units[unitID].attackAtTileX; + this->units[unitID].jugglerCount = -1; + BOOLEnum _tileIsValid = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)((int)_attackTileX, (uint)(_attackTileY)); + if (_tileIsValid != FALSE) { + _attackTileX = this->units[unitID].attackAtTileX; + this->units[unitID].shootTargetMicroX = _attackTileX * 8; + this->units[unitID].shootTargetedUnit = -1; + this->units[unitID].shootTargetMicroY = _attackTileY * 8; + this->units[unitID].shootTargetZ + = (ushort)DAT_TileMapState::instance + .HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[_attackTileY].addXgetTile + + (int)_attackTileX]; + return TRUE; + } + } + this->units[unitID].targetingType = OpenSHC::Map::Units::UIT_NO_INSTRUCTION_OR_MOVEUnk; + return FALSE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/adjustUnitMapOrientationRelatedPositionBasedOnMapOrientationCorrectedFacingDirection.cpp b/src/OpenSHC/Map/Units/UnitsState/adjustUnitMapOrientationRelatedPositionBasedOnMapOrientationCorrectedFacingDirection.cpp new file mode 100644 index 000000000..c914148b1 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/adjustUnitMapOrientationRelatedPositionBasedOnMapOrientationCorrectedFacingDirection.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x005340F0 + void UnitsState::adjustUnitMapOrientationRelatedPositionBasedOnMapOrientationCorrectedFacingDirection( + int unitID) + { + this->units[unitID].orientationRelatedPositionX = this->units[unitID].orientationRelatedPositionX + + (short)DAT_UnitPropertiesDefinedData::instance + .UnitOrientationRelatedOffset[this->units[unitID].facingDirectionMapOrientationCorrected][0]; + this->units[unitID].orientationRelatedPositionY = this->units[unitID].orientationRelatedPositionY + + (short)DAT_UnitPropertiesDefinedData::instance + .UnitOrientationRelatedOffset[this->units[unitID].facingDirectionMapOrientationCorrected][1]; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/applyDragBoxSelectionByPriority.cpp b/src/OpenSHC/Map/Units/UnitsState/applyDragBoxSelectionByPriority.cpp new file mode 100644 index 000000000..e29fcc229 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/applyDragBoxSelectionByPriority.cpp @@ -0,0 +1,264 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_MouseState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x005347E0 + void UnitsState::applyDragBoxSelectionByPriority() + { + this->field14_0x55c = 0; + LONG _boxLeft; + LONG _boxRight; + if (DAT_MouseState::instance.selectionBox.right < DAT_MouseState::instance.selectionBox.left) { + _boxLeft = DAT_MouseState::instance.selectionBox.right; + _boxRight = DAT_MouseState::instance.selectionBox.left; + } else { + _boxLeft = DAT_MouseState::instance.selectionBox.left; + _boxRight = DAT_MouseState::instance.selectionBox.right; + } + LONG _boxTop; + LONG _boxBottom; + if (DAT_MouseState::instance.selectionBox.bottom < DAT_MouseState::instance.selectionBox.top) { + _boxTop = DAT_MouseState::instance.selectionBox.bottom; + _boxBottom = DAT_MouseState::instance.selectionBox.top; + } else { + _boxTop = DAT_MouseState::instance.selectionBox.top; + _boxBottom = DAT_MouseState::instance.selectionBox.bottom; + } + int _otherOwnUnits = 0; + int _catapults = 0; + int _trebuchets = 0; + int _siegeTowers = 0; + int _batteringRams = 0; + int _shields = 0; + int _mangonels = 0; + int _ballistas = 0; + int _priority = 0; + uint _lordUnitID = 0; + int _siegeEngineUnits = 0; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL + || this->units[DAT_CurrentUnitSlotID::instance].dying != 0 + || this->units[DAT_CurrentUnitSlotID::instance].isSelectable_OR_matchTime == 0 + || this->units[DAT_CurrentUnitSlotID::instance].unknownTestAgainst0_2 != 0 + || this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_JESTER_ROAM_TO + || (this->units[DAT_CurrentUnitSlotID::instance].drawX == 0 + && this->units[DAT_CurrentUnitSlotID::instance].drawY == 0) + || this->units[DAT_CurrentUnitSlotID::instance].drawX + + this->units[DAT_CurrentUnitSlotID::instance].drawXOffset + >= _boxRight + || this->units[DAT_CurrentUnitSlotID::instance].drawY + + this->units[DAT_CurrentUnitSlotID::instance].someDrawYOffset + >= _boxBottom + || this->units[DAT_CurrentUnitSlotID::instance].spriteWidthUnk + + this->units[DAT_CurrentUnitSlotID::instance].drawX + + this->units[DAT_CurrentUnitSlotID::instance].drawXOffset + < _boxLeft + || this->units[DAT_CurrentUnitSlotID::instance].spriteHeightUnk + + this->units[DAT_CurrentUnitSlotID::instance].drawY + + this->units[DAT_CurrentUnitSlotID::instance].someDrawYOffset + < _boxTop + || (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_TUNNELER + && (this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk + || this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_STAND_UPUnk))) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].owner != 0) { + this->field14_0x55c = this->units[DAT_CurrentUnitSlotID::instance].owner; + } + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_LORD) { + _lordUnitID = DAT_CurrentUnitSlotID::instance; + _otherOwnUnits = _otherOwnUnits + 1; + continue; + } + _siegeEngineUnits = _siegeEngineUnits + 1; + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_CATAPULT) { + _catapults = _catapults + 1; + } else if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_TREBUCHET) { + _trebuchets = _trebuchets + 1; + } else if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_TOWER) { + _siegeTowers = _siegeTowers + 1; + } else if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + _batteringRams = _batteringRams + 1; + } else if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_SHIELD) { + _shields = _shields + 1; + } else if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_MANGONEL) { + _mangonels = _mangonels + 1; + } else if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_BALLISTA) { + _ballistas = _ballistas + 1; + } else if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_FBALLISTA) { + _priority = _priority + 1; + } else { + _otherOwnUnits = _otherOwnUnits + 1; + } + } + if (_lordUnitID != 0 && _siegeEngineUnits != 0) { + _otherOwnUnits = _otherOwnUnits - 1; + _lordUnitID = 0; + } + if (_otherOwnUnits != 0 || _catapults != 0 || _trebuchets != 0 || _siegeTowers != 0 || _batteringRams != 0 + || _shields != 0 || _mangonels != 0 || _ballistas != 0 || _priority != 0) { + _priority = 0; + } else { + _priority = 9; + } + this->totalUnitsInSelection = 0; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 0; + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL + || this->units[DAT_CurrentUnitSlotID::instance].dying != 0 + || this->units[DAT_CurrentUnitSlotID::instance].isSelectable_OR_matchTime == 0 + || this->units[DAT_CurrentUnitSlotID::instance].unknownTestAgainst0_2 != 0 + || this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_JESTER_ROAM_TO + || (this->units[DAT_CurrentUnitSlotID::instance].drawX == 0 + && this->units[DAT_CurrentUnitSlotID::instance].drawY == 0) + || this->units[DAT_CurrentUnitSlotID::instance].drawX + + this->units[DAT_CurrentUnitSlotID::instance].drawXOffset + >= _boxRight + || this->units[DAT_CurrentUnitSlotID::instance].drawY + + this->units[DAT_CurrentUnitSlotID::instance].someDrawYOffset + >= _boxBottom + || this->units[DAT_CurrentUnitSlotID::instance].spriteWidthUnk + + this->units[DAT_CurrentUnitSlotID::instance].drawX + + this->units[DAT_CurrentUnitSlotID::instance].drawXOffset + < _boxLeft + || this->units[DAT_CurrentUnitSlotID::instance].spriteHeightUnk + + this->units[DAT_CurrentUnitSlotID::instance].drawY + + this->units[DAT_CurrentUnitSlotID::instance].someDrawYOffset + < _boxTop + || (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_TUNNELER + && (this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk + || this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_STAND_UPUnk))) { + continue; + } + switch (_priority) { + case 0: + if (this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].unitType != OpenSHC::Map::Units::UT_LORD + || _lordUnitID != 0) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + break; + case 1: + if (this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_CATAPULT) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + break; + case 2: + if (this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_TREBUCHET) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + break; + case 3: + if (this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_TOWER) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + break; + case 4: + if (this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + break; + case 5: + if (this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_SHIELD) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + break; + case 6: + if (this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_MANGONEL) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + break; + case 7: + if (this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_BALLISTA) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + break; + case 8: + if (this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_FBALLISTA) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + break; + case 9: + if (this->units[DAT_CurrentUnitSlotID::instance].owner + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/applyTunnelDamageAlongPathPlan.cpp b/src/OpenSHC/Map/Units/UnitsState/applyTunnelDamageAlongPathPlan.cpp new file mode 100644 index 000000000..845e4b335 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/applyTunnelDamageAlongPathPlan.cpp @@ -0,0 +1,55 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00534130 + void UnitsState::applyTunnelDamageAlongPathPlan(uint unitID) + { + uint _xPosition = this->units[unitID].ladderExitXPosition; + uint _yPosition = this->units[unitID].ladderExitYPosition; + int _tile = this->units[unitID].previousTilePosition; + for (int _stepIndex = 0; _stepIndex < this->units[unitID].totalSizeOfPathPlan; ++_stepIndex) { + if ((DAT_TileMapState::instance.LogicLayer[_tile] & 0x20000081U) == 0) { + if (DAT_TileMapState::instance.BuildingLayer[_tile] == 0 + && (DAT_TileMapState::instance.HeightLayer[_tile] < 0x10 + || DAT_TileMapState::instance.DefaultHeightLayer[_tile] < 0x10)) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::increaseHeightForTunnelWithBrush, + DAT_TileMapState::ptr)(_tile, _xPosition, _yPosition, -2); + DAT_TileMapState::instance.HeightLayer[_tile] = 0; + } else { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::processDamageToBuilding, DAT_TileMapState::ptr)( + _tile, _xPosition, _yPosition, 5, 0, this->units[unitID].owner, FALSE, 0); + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(1, _xPosition, _yPosition); + } + uint _packedDirections = (char)this->units[unitID].pathPlanStart[_stepIndex / 2]; + uint _direction; + if ((_stepIndex & 1) == 0) { + _direction = _packedDirections & 0xf; + } else { + _direction = (int)_packedDirections >> 4; + } + _xPosition = _xPosition + + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[_direction].int_.xOffset; + _tile = _tile + DAT_TileMapState::instance.directionTranslationMatrix[_yPosition][_direction]; + _yPosition = _yPosition + + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[_direction].int_.yOffset; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/assignNameToUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/assignNameToUnit.cpp new file mode 100644 index 000000000..a77f71eeb --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/assignNameToUnit.cpp @@ -0,0 +1,52 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052EED0 + void UnitsState::assignNameToUnit(int unitID) + { + this->units[unitID].rng1_to_70 = 0; + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_COW) { + this->units[unitID].firstNameIndex = (char)(SEC_RNG::instance.currentNumber2 % 4) + 0x49; + return; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_CHICKEN) { + this->units[unitID].firstNameIndex = (char)(SEC_RNG::instance.currentNumber2 % 4) + 0x4d; + return; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_HUNTERDOG) { + this->units[unitID].firstNameIndex = (char)(SEC_RNG::instance.currentNumber2 % 4) + 0x51; + return; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_QUARRYOX) { + this->units[unitID].firstNameIndex = (char)(SEC_RNG::instance.currentNumber2 % 4) + 0x55; + return; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_TANNER + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_LADY + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_MOTHER + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_BREWER + || (this->units[unitID].unitType == OpenSHC::Map::Units::UT_CHILD + && this->units[unitID].spriteID == 0x81)) { + /* women */ + this->units[unitID].firstNameIndex = (char)(SEC_RNG::instance.currentNumber2 % 0x14) + 52; + } else { + /* men */ + this->units[unitID].firstNameIndex = (char)(SEC_RNG::instance.currentNumber2 % 0x32) + 1; + } + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + this->units[unitID].rng1_to_70 = (char)(SEC_RNG::instance.currentNumber2 % 0x46) + 1; + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/assignPeasantToBuilding.cpp b/src/OpenSHC/Map/Units/UnitsState/assignPeasantToBuilding.cpp new file mode 100644 index 000000000..6af31118f --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/assignPeasantToBuilding.cpp @@ -0,0 +1,71 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052E830 + int UnitsState::assignPeasantToBuilding(UnitType unitType, int buildingID, int playerID, int workerIndex) + { + /* Finds a valid peasant, changes them into specified workertype and assignes + them to building */ + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].owner != playerID) { + continue; + } + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_PEASANT) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_RELOAD_WEAPONUnk) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_AIM_WEAPONUnk) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_JESTER_ROAM_TO) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + continue; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::determineBuildingEntranceFromKeepArea, + DAT_BuildingsState::ptr)(buildingID, workerIndex + 1, FALSE); + this->units[unitID].workplaceBuildingID_1 = (short)buildingID; + this->units[unitID].workplaceBuildingUID = DAT_BuildingsState::instance.buildings[buildingID].uid; + this->units[unitID].targetX_2 = DAT_BuildingsState::instance.buildings[buildingID].buildingEntryX; + this->units[unitID].unitTypeToChangeInto = (undefined2)unitType; + this->units[unitID].targetY_2 = DAT_BuildingsState::instance.buildings[buildingID].buildingEntryY; + this->units[unitID].state_2 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::determineBuildingEntranceFromKeepArea, + DAT_BuildingsState::ptr)(buildingID, 1, FALSE); + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_JESTER_ROAM_TO; + this->units[unitID].disappearFadeAlphaCountdown = 0; + this->units[unitID].engineerManningSiegeStateRef_checkType = 1; + this->units[unitID].cachedState = OpenSHC::Map::Units::States::US_DETERMINE_NEXT_STATEUnk; + this->units[unitID].isDisappearingUnk = 1; + return unitID; + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/calculateUnitMovementSpeed.cpp b/src/OpenSHC/Map/Units/UnitsState/calculateUnitMovementSpeed.cpp new file mode 100644 index 000000000..b856c5b85 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/calculateUnitMovementSpeed.cpp @@ -0,0 +1,183 @@ +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F7E0 + void UnitsState::calculateUnitMovementSpeed(int unitID) + { + this->units[unitID].field322_0x440 = this->units[unitID].field322_0x440 + 1; + int _tile = this->units[unitID].tile; + int _buildingID = DAT_TileMapState::instance.BuildingLayer[_tile]; + uint _logicFlags = DAT_TileMapState::instance.LogicLayer[_tile]; + if (this->units[unitID].unknownCountdown_0x402 == 0) { + if (_buildingID == 0 && (_logicFlags & 0x10000500) == 0) { + if ((this->units[unitID].field322_0x440 + unitID & 7) != 0) { + return; + } + } else if ((this->units[unitID].field322_0x440 + unitID & 3) != 0) { + return; + } + } + this->units[unitID].isMatchingSpeed = false; + uint _isInMoat = _logicFlags & 0x20000000; + byte _tileHeight = DAT_TileMapState::instance.HeightLayer[_tile]; + int _organismID = DAT_TileMapState::instance.OrganismLayer[_tile]; + if (_organismID != 0 && _organismID < 2000) { + DAT_LandscapeState::instance.trees[_organismID].state = 3; + } + if (_isInMoat != 0 && (DAT_TileMapState::instance.MacroLayer[_tile] & 0x3f) == 1) { + _isInMoat = 0; + } + if ((_logicFlags & 0x40000000) != 0) { + _isInMoat = 1; + } + if ((_logicFlags & 0x800000) != 0) { + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed; + } else if (this->units[unitID].terrainOrClimbHeight < _tileHeight) { + int _heightDifference = _tileHeight - this->units[unitID].terrainOrClimbHeight; + /* the climb bands are split by halving, not as a flat ladder */ + if (_heightDifference < 0x11) { + if (_heightDifference < 0xc) { + if (_heightDifference < 8) { + if (_heightDifference < 4) { + if (_heightDifference < 2) { + this->units[unitID].terrainOrClimbHeight + = this->units[unitID].terrainOrClimbHeight + 1; + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed; + } else { + this->units[unitID].terrainOrClimbHeight + = this->units[unitID].terrainOrClimbHeight + 2; + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed + 1; + } + } else { + this->units[unitID].terrainOrClimbHeight = this->units[unitID].terrainOrClimbHeight + 3; + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed + 3; + } + } else { + this->units[unitID].terrainOrClimbHeight = this->units[unitID].terrainOrClimbHeight + 4; + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed + 4; + this->units[unitID].movementRunUpTime = 8; + } + } else { + this->units[unitID].terrainOrClimbHeight = this->units[unitID].terrainOrClimbHeight + 4; + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed + 5; + this->units[unitID].movementRunUpTime = 0xc; + } + } else { + this->units[unitID].terrainOrClimbHeight = _tileHeight; + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed; + } + } else if (_tileHeight < this->units[unitID].terrainOrClimbHeight) { + int _heightDifference = this->units[unitID].terrainOrClimbHeight - _tileHeight; + if (_heightDifference > 0x10) { + this->units[unitID].terrainOrClimbHeight = _tileHeight; + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed; + } else if (_heightDifference < 0xc) { + if (_heightDifference < 8) { + if (_heightDifference > 3) { + this->units[unitID].terrainOrClimbHeight = this->units[unitID].terrainOrClimbHeight + -2; + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed; + } else { + this->units[unitID].terrainOrClimbHeight = this->units[unitID].terrainOrClimbHeight + -1; + } + } else { + this->units[unitID].terrainOrClimbHeight = this->units[unitID].terrainOrClimbHeight + -3; + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed; + } + } else { + this->units[unitID].terrainOrClimbHeight = this->units[unitID].terrainOrClimbHeight + -4; + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed; + } + } else if (this->units[unitID].isSelectable_OR_matchTime == 0) { + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed; + } else { + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed; + if (this->units[unitID].tribeID > 0 + && DAT_TribesState::instance.tribes[this->units[unitID].tribeID].unitType == (UnitType)0 + && DAT_TribesState::instance.tribes[this->units[unitID].tribeID].freeUnitSpeeds == 0) { + this->units[unitID].calculatedMovementSpeed + = DAT_TribesState::instance.tribes[this->units[unitID].tribeID].movementSpeed; + if (this->units[unitID].calculatedMovementSpeed < this->units[unitID].movementSpeed) { + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed; + } + this->units[unitID].isMatchingSpeed = true; + } + } + if (_isInMoat == 0) { + if ((_logicFlags & 0x200000) != 0) { + if ((char)this->units[unitID].negativeHeight < 0x10) { + this->units[unitID].negativeHeight = this->units[unitID].negativeHeight + 4; + } + this->units[unitID].calculatedMovementSpeed = this->units[unitID].calculatedMovementSpeed + 2; + } else if (this->units[unitID].negativeHeight != 0) { + this->units[unitID].negativeHeight = this->units[unitID].negativeHeight - 8; + if ((char)this->units[unitID].negativeHeight < 0) { + this->units[unitID].negativeHeight = 0; + } + this->units[unitID].calculatedMovementSpeed = this->units[unitID].calculatedMovementSpeed + 3; + } + } else { + if ((char)this->units[unitID].negativeHeight < 0x18) { + this->units[unitID].negativeHeight = this->units[unitID].negativeHeight + 4; + } + if ((char)this->units[unitID].negativeHeight <= 4) { + this->units[unitID].calculatedMovementSpeed = this->units[unitID].calculatedMovementSpeed + 3; + } else if ((char)this->units[unitID].negativeHeight < 10) { + this->units[unitID].calculatedMovementSpeed = this->units[unitID].calculatedMovementSpeed + 4; + } else { + this->units[unitID].calculatedMovementSpeed = this->units[unitID].calculatedMovementSpeed + 6; + } + } + this->units[unitID].field289_0x3ff = 0; + if ((_logicFlags & 8) != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::registerSpottedEnemyTile, + DAT_TroopValueState::ptr)(_tile); + } + if (_buildingID == 0) { + return; + } + if ((short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType <= 0x28) { + return; + } + if ((short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType >= 0x2d) { + return; + } + this->units[unitID].field289_0x3ff = 1; + int _owner = this->units[unitID].owner; + if (DAT_BuildingsState::instance.buildings[_buildingID].owner == _owner) { + return; + } + if (this->units[unitID].dying != 0) { + return; + } + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + return; + } + if (_owner == 0) { + return; + } + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] != -1) { + return; + } + DAT_TroopValueState::instance.attackInfo.field128058_0x469dc + = DAT_TroopValueState::instance.attackInfo.field128058_0x469dc + 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/canAUnitClimb.cpp b/src/OpenSHC/Map/Units/UnitsState/canAUnitClimb.cpp new file mode 100644 index 000000000..8e8e3c8d2 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/canAUnitClimb.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536610 + undefined4 UnitsState::canAUnitClimb() + { + int _currentPlayerSlotID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner != _currentPlayerSlotID) { + return 0; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitCanClimb != 0) { + return 1; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/changeDestinationByAmount.cpp b/src/OpenSHC/Map/Units/UnitsState/changeDestinationByAmount.cpp new file mode 100644 index 000000000..3e24d086a --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/changeDestinationByAmount.cpp @@ -0,0 +1,53 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00533B30 + void UnitsState::changeDestinationByAmount(int unitID, int leftover) + { + if (this->units[unitID].climbDataID != 0) { + this->units[unitID].leftover = (short)leftover; + return; + } + this->units[unitID].leftover = 0; + if (leftover >= this->units[unitID].totalSizeOfPathPlan) { + this->units[unitID].destinationTilePosition = this->units[unitID].previousTilePosition; + this->units[unitID].totalSizeOfPathPlan = 0; + this->units[unitID].destinationXPosition = this->units[unitID].ladderExitXPosition; + this->units[unitID].destinationYPosition = this->units[unitID].ladderExitYPosition; + this->units[unitID].destinationX_2Unk = this->units[unitID].ladderExitXPosition; + this->units[unitID].destinationY_2Unk = this->units[unitID].ladderExitYPosition; + return; + } + int _destinationX = this->units[unitID].ladderExitXPosition; + int _destinationY = this->units[unitID].ladderExitYPosition; + this->units[unitID].totalSizeOfPathPlan = this->units[unitID].totalSizeOfPathPlan - (short)leftover; + for (int _stepIndex = 0; _stepIndex < this->units[unitID].totalSizeOfPathPlan; ++_stepIndex) { + uint _packedDirections = (char)this->units[unitID].pathPlanStart[_stepIndex / 2]; + uint _direction; + if ((_stepIndex & 1) == 0) { + _direction = _packedDirections & 0xf; + } else { + _direction = (int)_packedDirections >> 4; + } + _destinationX = _destinationX + + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[_direction].int_.xOffset; + _destinationY = _destinationY + + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[_direction].int_.yOffset; + } + this->units[unitID].destinationXPosition = (short)_destinationX; + this->units[unitID].destinationYPosition = (short)_destinationY; + this->units[unitID].destinationX_2Unk = (short)_destinationX; + this->units[unitID].destinationY_2Unk = (short)_destinationY; + this->units[unitID].destinationTilePosition = (short)_destinationX + + DAT_ViewportRenderState::instance.translationMatrix[(short)_destinationY].addXgetTile; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/changeDestinationByLeftover.cpp b/src/OpenSHC/Map/Units/UnitsState/changeDestinationByLeftover.cpp new file mode 100644 index 000000000..e38e18463 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/changeDestinationByLeftover.cpp @@ -0,0 +1,18 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00533C70 + void UnitsState::changeDestinationByLeftover(int unitID) + { + if (this->units[unitID].leftover > 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::changeDestinationByAmount, this)( + unitID, this->units[unitID].leftover); + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/changeUnitType.cpp b/src/OpenSHC/Map/Units/UnitsState/changeUnitType.cpp new file mode 100644 index 000000000..ca0faa15c --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/changeUnitType.cpp @@ -0,0 +1,47 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053E6C0 + int UnitsState::changeUnitType(int unitID) + { + this->units[unitID].state.generic = this->units[unitID].state_2; + UnitTypeShort _previousUnitType = this->units[unitID].unitType; + this->units[unitID].logicalState = OpenSHC::Map::Units::ULS_NORMAL; + this->units[unitID].goToRallyPoint = 1; + this->units[unitID].unitType_3 = _previousUnitType; + this->units[unitID].substate = -1; + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) { + /* < E_ARCHER (basic worker?) */ + if ((short)this->units[unitID].unitTypeToChangeInto < 0x16) { + this->units[unitID].calculatedOwnerPlayerIndex = 0; + } else if ((short)this->units[unitID].unitTypeToChangeInto < 0x1f + || (short)this->units[unitID].unitTypeToChangeInto > 0x45) { + /* is army member */ + this->units[unitID].calculatedOwnerPlayerIndex = this->units[unitID].owner; + } else { + this->units[unitID].calculatedOwnerPlayerIndex = 0; + } + if (this->units[unitID].calculatedOwnerPlayerIndex == 0 && this->units[unitID].owner >= 2) { + this->units[unitID].calculatedOwnerPlayerIndex = this->units[unitID].owner; + } + } else { + this->units[unitID].calculatedOwnerPlayerIndex = this->units[unitID].owner; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setUnitValues, this)( + unitID, (UnitType)(short)this->units[unitID].unitTypeToChangeInto); + return unitID; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/checkAnySelectedUnitCannotClimb.cpp b/src/OpenSHC/Map/Units/UnitsState/checkAnySelectedUnitCannotClimb.cpp new file mode 100644 index 000000000..af067d379 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/checkAnySelectedUnitCannotClimb.cpp @@ -0,0 +1,42 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536970 + undefined4 UnitsState::checkAnySelectedUnitCannotClimb() + { + int _currentPlayerSlotID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner != _currentPlayerSlotID) { + return 0; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::checkUnitHasPropertyBasedOnUnitType, this)( + DAT_CurrentUnitSlotID::instance, 1) + == 0) { + return 0; + } + } + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/checkIfCitizenUnitIsAliveBasedOnState.cpp b/src/OpenSHC/Map/Units/UnitsState/checkIfCitizenUnitIsAliveBasedOnState.cpp new file mode 100644 index 000000000..ae3d0d8db --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/checkIfCitizenUnitIsAliveBasedOnState.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00530FD0 + BOOLEnum UnitsState::checkIfCitizenUnitIsAliveBasedOnState(int unitID) + { + if ((short)this->units[unitID].state.generic >= States::US_DEATH_01 + && (short)this->units[unitID].state.generic <= States::US_STONE_DEATH_03) { + return TRUE; + } + return FALSE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/checkTargetBuildingPossibilityOrState.cpp b/src/OpenSHC/Map/Units/UnitsState/checkTargetBuildingPossibilityOrState.cpp new file mode 100644 index 000000000..55ccc8d02 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/checkTargetBuildingPossibilityOrState.cpp @@ -0,0 +1,42 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00533580 + BOOLEnum UnitsState::checkTargetBuildingPossibilityOrState(int unitID) + { + int _playerID = this->units[unitID].owner; + if (DAT_GameState::instance.playerDataArray[_playerID].totalEnemyUnitsCount > 0) { + return TRUE; + } + if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_ATTACK_BUILDING) { + return ( + BOOLEnum)(DAT_BuildingsState::instance.buildings[this->units[unitID].targetID_OR_targetBuildingID] + .uid + == this->units[DAT_CurrentUnitSlotID::instance] + .targetedUnitUIDUnk_OR_someAppearTileUnk_OR_buildingUID_OR_pitchDitchUID_OR_entityUID); + } + int _shootTargetMicroX = this->units[unitID].shootTargetMicroX; + int _shootTargetMicroY = this->units[unitID].shootTargetMicroY; + return (BOOLEnum)(MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: + checkEnemyBuildingOrDefensiveStructureWithin12Tiles, + DAT_PathFindingState::ptr)(_playerID, _shootTargetMicroX / 8, _shootTargetMicroY / 8) + != FALSE); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/checkUnitHasPropertyBasedOnUnitType.cpp b/src/OpenSHC/Map/Units/UnitsState/checkUnitHasPropertyBasedOnUnitType.cpp new file mode 100644 index 000000000..41fe38a6f --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/checkUnitHasPropertyBasedOnUnitType.cpp @@ -0,0 +1,18 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F0A0 + int UnitsState::checkUnitHasPropertyBasedOnUnitType(int unitID, int property) + { + return DAT_UnitPropertiesDefinedData::instance + .UnitClimbStateFlags[property][(short)this->units[unitID].unitType]; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/chooseHusbandAndWife.cpp b/src/OpenSHC/Map/Units/UnitsState/chooseHusbandAndWife.cpp new file mode 100644 index 000000000..c99437414 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/chooseHusbandAndWife.cpp @@ -0,0 +1,102 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_00ee0fe8.hpp" +#include "OpenSHC/Globals/DAT_00ee1028.hpp" +#include "OpenSHC/Globals/DAT_00ee102c.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00539DF0 + undefined4 UnitsState::chooseHusbandAndWife(int* husbandID, int* wifeID) + { + int _menIDs[100]; + int _womenIDs[100]; + int _menCount = 0; + int _womenCount = 0; + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_INVISIBLE) { + continue; + } + if (this->units[unitID].unitType == (UnitType)0) { + continue; + } + if (unitID == DAT_00ee102c::instance || unitID == DAT_00ee1028::instance) { + continue; + } + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_WOODCUTTER: + case OpenSHC::Map::Units::UT_FLETCHER: + case OpenSHC::Map::Units::UT_TUNNELER: + case OpenSHC::Map::Units::UT_HUNTER: + case OpenSHC::Map::Units::UT_QUARRYMASON: + case OpenSHC::Map::Units::UT_QUARRYWORKER: + case OpenSHC::Map::Units::UT_PITCHMAN: + case OpenSHC::Map::Units::UT_WHEATFARMER: + case OpenSHC::Map::Units::UT_HOPSFARMER: + case OpenSHC::Map::Units::UT_APPLEFARMER: + case OpenSHC::Map::Units::UT_DAIRYFARMER: + case OpenSHC::Map::Units::UT_MILLER: + case OpenSHC::Map::Units::UT_BAKER: + case OpenSHC::Map::Units::UT_POLETURNER: + case OpenSHC::Map::Units::UT_SMITH: + case OpenSHC::Map::Units::UT_ARMORER: + case OpenSHC::Map::Units::UT_MINER: + case OpenSHC::Map::Units::UT_TRANSPORTMINER: + case OpenSHC::Map::Units::UT_PRIEST: + case OpenSHC::Map::Units::UT_HEALER: + case OpenSHC::Map::Units::UT_DRUNK: + case OpenSHC::Map::Units::UT_INNKEEPER: + case OpenSHC::Map::Units::UT_TRADER: + case OpenSHC::Map::Units::UT_JESTER: + if ((char)this->units[unitID].firstNameIndex < 51 && _menCount < 100) { + _menIDs[_menCount] = unitID; + _menCount = _menCount + 1; + } + break; + case OpenSHC::Map::Units::UT_BREWER: + case OpenSHC::Map::Units::UT_TANNER: + case OpenSHC::Map::Units::UT_MOTHER: + if ((char)this->units[unitID].firstNameIndex > 52 && _womenCount < 100) { + _womenIDs[_womenCount] = unitID; + _womenCount = _womenCount + 1; + } + } + } + if (_womenCount < 1 || _menCount < 1) { + return 0; + } + int _husband = _menIDs[SEC_RNG::instance.currentNumber1 % _menCount]; + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber1, SEC_RNG::ptr)(); + int _wife = _womenIDs[SEC_RNG::instance.currentNumber1 % _womenCount]; + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber1, SEC_RNG::ptr)(); + /* the eight most recent couples live in the pair array at 0x00EE0FE8 */ + for (int i = 0; i < 8; ++i) { + if (_husband == (&DAT_00ee0fe8::instance)[i * 2] && _wife == (&DAT_00ee0fe8::instance)[i * 2 + 1]) { + return 0; + } + } + *husbandID = _husband; + *wifeID = _wife; + for (int i = 7; i > 0; --i) { + (&DAT_00ee0fe8::instance)[i * 2] = (&DAT_00ee0fe8::instance)[(i - 1) * 2]; + (&DAT_00ee0fe8::instance)[i * 2 + 1] = (&DAT_00ee0fe8::instance)[(i - 1) * 2 + 1]; + } + (&DAT_00ee0fe8::instance)[0] = _husband; + (&DAT_00ee0fe8::instance)[1] = _wife; + DAT_00ee102c::instance = _husband; + DAT_00ee1028::instance = _wife; + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/clearAllUnits.cpp b/src/OpenSHC/Map/Units/UnitsState/clearAllUnits.cpp new file mode 100644 index 000000000..3a95562f3 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/clearAllUnits.cpp @@ -0,0 +1,37 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0052E7B0 + void UnitsState::clearAllUnits() + { + this->unitCount = 0; + this->unknownInitially0_01 = 0; + this->totalUnitsInSelection = 0; + this->unitCountOfSelection[0] = 0; + this->unitCountOfSelection[1] = 0; + this->unitCountOfSelection[2] = 0; + this->unitCountOfSelection[3] = 0; + this->unitCountOfSelection[4] = 0; + this->unitCountOfSelection[5] = 0; + this->unitCountOfSelection[6] = 0; + this->unitCountOfSelection[7] = 0; + this->unitCountOfSelection[8] = 0; + for (int unitID = 0; unitID < 2500; ++unitID) { + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 1168, '\0', &this->units[unitID]); + } + this->maxUnitCount = 2500; + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 160800, '\0', DAT_TileMapState::instance.UnitLayer); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/clearHiddenFlagAndUpdatePosition.cpp b/src/OpenSHC/Map/Units/UnitsState/clearHiddenFlagAndUpdatePosition.cpp new file mode 100644 index 000000000..642cf55a6 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/clearHiddenFlagAndUpdatePosition.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053E8D0 + void UnitsState::clearHiddenFlagAndUpdatePosition(int unitID) + { + if (this->units[unitID].unknownTestAgainst0_2 == 0) { + return; + } + this->units[unitID].unknownTestAgainst0_2 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::commitPendingUnitPosition, this)(unitID); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/clearOrDeselectUnitFromSelection.cpp b/src/OpenSHC/Map/Units/UnitsState/clearOrDeselectUnitFromSelection.cpp new file mode 100644 index 000000000..637e278a0 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/clearOrDeselectUnitFromSelection.cpp @@ -0,0 +1,48 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00536CF0 + void UnitsState::clearOrDeselectUnitFromSelection(int playerID, uint unitID, int unitType) + { + if (unitID == 0xffffffff) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::clearTribesOfUnitType, DAT_TribesState::ptr)( + playerID, unitType); + return; + } + if (unitID == 0xfffffffe) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::clearTribesNotOfUnitType, + DAT_TribesState::ptr)(playerID, unitType); + return; + } + if (unitID == 0) { + this->unitCountOfSelection[playerID] = 0; + for (DAT_CurrentUnitSlotID::instance = 1; + (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].owner == playerID) { + this->units[DAT_CurrentUnitSlotID::instance].ifSelectedThenPlayerID = 0; + } + } + return; + } + if (this->units[unitID].tribeID != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, this->units[unitID].tribeID); + } + if (this->units[unitID].ifSelectedThenPlayerID == 0) { + return; + } + this->units[unitID].ifSelectedThenPlayerID = 0; + this->unitCountOfSelection[playerID] = this->unitCountOfSelection[playerID] - 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/clearSelectionCountsAndPlayerIDs.cpp b/src/OpenSHC/Map/Units/UnitsState/clearSelectionCountsAndPlayerIDs.cpp new file mode 100644 index 000000000..b32ee3eb3 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/clearSelectionCountsAndPlayerIDs.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00536DE0 + void UnitsState::clearSelectionCountsAndPlayerIDs() + { + this->unitCountOfSelection[1] = 0; + this->unitCountOfSelection[2] = 0; + this->unitCountOfSelection[3] = 0; + this->unitCountOfSelection[4] = 0; + this->unitCountOfSelection[5] = 0; + this->unitCountOfSelection[6] = 0; + this->unitCountOfSelection[7] = 0; + this->unitCountOfSelection[8] = 0; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + this->units[DAT_CurrentUnitSlotID::instance].ifSelectedThenPlayerID = 0; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/commitMimmicLocation.cpp b/src/OpenSHC/Map/Units/UnitsState/commitMimmicLocation.cpp new file mode 100644 index 000000000..fdbf2c75e --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/commitMimmicLocation.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053E9F0 + void UnitsState::commitMimmicLocation(int unitID) + { + this->units[unitID].movementRelated = 8; + this->units[unitID].field105_0xe8 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setupUnitSharingCurrentTilePosition, this)(unitID); + this->units[unitID].y = this->units[unitID].mimicCurrentYPosition; + this->units[unitID].microXPosition = this->units[unitID].mimicCurrentXPosition * 8 + 4; + this->units[unitID].x = this->units[unitID].mimicCurrentXPosition; + this->units[unitID].microYPosition = this->units[unitID].mimicCurrentYPosition * 8 + 4; + this->units[unitID].tile = this->units[unitID].mimicCurrentXPosition + + DAT_ViewportRenderState::instance.translationMatrix[this->units[unitID].mimicCurrentYPosition] + .addXgetTile; + this->units[unitID].terrainOrClimbHeight = DAT_TileMapState::instance.HeightLayer[this->units[unitID].tile]; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::commitPendingUnitPosition, this)(unitID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::updateMicroPosition, this)(unitID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::recomputeUnitStandingHeight, this)(unitID); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/commitPendingUnitPosition.cpp b/src/OpenSHC/Map/Units/UnitsState/commitPendingUnitPosition.cpp new file mode 100644 index 000000000..b28c6df0a --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/commitPendingUnitPosition.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053BB10 + void UnitsState::commitPendingUnitPosition(int unitID) + { + if (this->units[unitID].field105_0xe8 != 0) { + this->units[unitID].tile = this->units[unitID].nextTileUnk; + this->units[unitID].x = this->units[unitID].mimicCurrentXPosition; + this->units[unitID].y = this->units[unitID].mimicCurrentYPosition; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setMoveDelayForUnitsOnSameTiles, this)( + unitID, this->units[unitID].tile); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/commitUnitLocation.cpp b/src/OpenSHC/Map/Units/UnitsState/commitUnitLocation.cpp new file mode 100644 index 000000000..a1aafc8c0 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/commitUnitLocation.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053E820 + void UnitsState::commitUnitLocation(int unitID) + { + this->units[unitID].currentIndexInPathPlan = 0; + this->units[unitID].tunnelerFinishedDigging = 0; + this->units[unitID].field105_0xe8 = 0; + this->units[unitID].unknownMovementRelated_0x2d2 = 0; + this->units[unitID].movementRelated = 8; + this->units[unitID].unknownTestAgainst0_2 = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setupUnitSharingCurrentTilePosition, this)(unitID); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/computeDamageFearFactorBonus.cpp b/src/OpenSHC/Map/Units/UnitsState/computeDamageFearFactorBonus.cpp new file mode 100644 index 000000000..6868e49ac --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/computeDamageFearFactorBonus.cpp @@ -0,0 +1,17 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x005311F0 + int UnitsState::computeDamageFearFactorBonus(int damage, int playerID) + { + return ((DAT_GameState::instance.playerDataArray[playerID].fearFactorLevel + 20) * damage * 5) / 100; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/computeDistanceToNearestEnemyForLegacyMissions.cpp b/src/OpenSHC/Map/Units/UnitsState/computeDistanceToNearestEnemyForLegacyMissions.cpp new file mode 100644 index 000000000..daf253ff9 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/computeDistanceToNearestEnemyForLegacyMissions.cpp @@ -0,0 +1,59 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::GameMode; + + // FUNCTION: STRONGHOLDCRUSADER 0x00532F80 + int UnitsState::computeDistanceToNearestEnemyForLegacyMissions(int unitID) + { + int _owner = this->units[unitID].owner; + int _unitMicroY = this->units[unitID].microYPosition; + int _unitMicroX = this->units[unitID].microXPosition; + /* kept in step with the result but never read back */ + int _closestWithinThousand = 1000; + int _closestDistance = 10000; + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY + && (int)this->unitCount <= 100) { + for (int i = 0; i < DAT_GameState::instance.playerDataArray[_owner].enemies; ++i) { + int _enemyUnitID = DAT_GameState::instance.playerDataArray[_owner].enemyIDArray[i]; + if (this->units[_enemyUnitID].uid + != DAT_GameState::instance.mapAndTime.playerEnemenyUnitUIDShortList[_owner][i]) { + continue; + } + int _distanceX = this->units[_enemyUnitID].microXPosition; + if (_distanceX < _unitMicroX) { + _distanceX = _unitMicroX - _distanceX; + } else { + _distanceX = _distanceX - _unitMicroX; + } + int _distanceY = this->units[_enemyUnitID].microYPosition; + if (_distanceY < _unitMicroY) { + _distanceY = _unitMicroY - _distanceY; + } else { + _distanceY = _distanceY - _unitMicroY; + } + if (_distanceY <= _distanceX) { + _distanceY = _distanceX; + } + if (_distanceY < _closestWithinThousand) { + _closestWithinThousand = _distanceY; + } + if (_distanceY < _closestDistance) { + _closestDistance = _distanceY; + } + } + return _closestDistance; + } + return 10000; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/computeLadderClimbPath.cpp b/src/OpenSHC/Map/Units/UnitsState/computeLadderClimbPath.cpp new file mode 100644 index 000000000..a3e5a71cc --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/computeLadderClimbPath.cpp @@ -0,0 +1,50 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00533A10 + BOOLEnum UnitsState::computeLadderClimbPath(int unitID, uint param_2, int param_3, int param_4) + { + this->units[unitID].climbDataID = 0; + DAT_PathFindingState::instance.climbIsIllegal = 0; + DAT_PathFindingState::instance.allAssassinsUnk = 0; + this->units[unitID].field280_0x3f4 = 0; + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::copyData, DAT_LowLevelMemory::ptr)( + 0x490, &this->units[unitID], this->units); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 400, '\0', this->units[unitID].pathPlanStart); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::bindPathPlanToAlgorithmStateAndReset, + DAT_PathFindingState::ptr)(this->units[unitID].pathPlanStart); + DAT_PathFindingState::instance.unitX = this->units[unitID].x; + DAT_PathFindingState::instance.unitY = this->units[unitID].y; + int _pathPlanSize + = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::commitUnitPathPlanUsingWalkLayer, + DAT_PathFindingState::ptr)(param_2, param_3, param_4); + if (_pathPlanSize <= 0) { + return FALSE; + } + this->units[unitID].totalSizeOfPathPlan = (short)_pathPlanSize; + this->units[unitID].ladderExitYPosition = this->units[unitID].y; + this->units[unitID].currentIndexInPathPlan = 0; + this->units[unitID].ladderExitXPosition = this->units[unitID].x; + this->units[unitID].tunnelerFinishedDigging = 2; + this->units[unitID].cannotClimb = 0; + this->units[unitID].previousTilePosition = this->units[unitID].x + + DAT_ViewportRenderState::instance.translationMatrix[this->units[unitID].y].addXgetTile; + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/countLivingNondyingUnitsForPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/countLivingNondyingUnitsForPlayer.cpp new file mode 100644 index 000000000..92c41035d --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/countLivingNondyingUnitsForPlayer.cpp @@ -0,0 +1,25 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x005301F0 + int UnitsState::countLivingNondyingUnitsForPlayer(int playerID) + { + int _count = 0; + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[unitID].dying == 0 && this->units[unitID].owner == playerID) { + _count = _count + 1; + } + } + return _count; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/countSelectedCatapultsAndTrebuchets.cpp b/src/OpenSHC/Map/Units/UnitsState/countSelectedCatapultsAndTrebuchets.cpp new file mode 100644 index 000000000..8676985be --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/countSelectedCatapultsAndTrebuchets.cpp @@ -0,0 +1,57 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536400 + undefined4 UnitsState::countSelectedCatapultsAndTrebuchets() + { + this->field15_0x560 = 0; + if (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID].keep.id + <= 0) { + return 0; + } + int _count = 0; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return 0; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) { + _count = _count + 1; + this->field15_0x560 = DAT_CurrentUnitSlotID::instance; + } + } + if (_count == 1) { + return 1; + } + if (_count > 1) { + return 2; + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/createTribeFromSelectedUnits.cpp b/src/OpenSHC/Map/Units/UnitsState/createTribeFromSelectedUnits.cpp new file mode 100644 index 000000000..99b4ae727 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/createTribeFromSelectedUnits.cpp @@ -0,0 +1,52 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535B00 + int UnitsState::createTribeFromSelectedUnits() + { + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 400, '\0', this->selectedUnitsBitFlags); + int _selectedCount = 0; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[DAT_CurrentUnitSlotID::instance].dying == 0 + && this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID + && this->units[DAT_CurrentUnitSlotID::instance].isSelected != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToSelected, DAT_TribesState::ptr)( + DAT_CurrentUnitSlotID::instance); + _selectedCount = _selectedCount + 1; + } + } + if (_selectedCount == 0) { + return 0; + } + DAT_TribesState::instance.DAT_CurrentTribeID + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::getAvailableTribeID, DAT_TribesState::ptr)( + DAT_GameSynchronyState::instance.currentPlayerSlotID); + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = DAT_TribesState::instance.DAT_CurrentTribeID; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + OpenSHC::Commands::GCT_UNITS_SELECT); + return _selectedCount; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/createUnitSelection.cpp b/src/OpenSHC/Map/Units/UnitsState/createUnitSelection.cpp new file mode 100644 index 000000000..b23fb58db --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/createUnitSelection.cpp @@ -0,0 +1,67 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535A30 + int UnitsState::createUnitSelection() + { + /* clear selected units */ + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 400, '\0', this->selectedUnitsBitFlags); + int _selectedCount = 0; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].ifSelectedThenPlayerID + == DAT_GameSynchronyState::instance.currentPlayerSlotID + && DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) { + continue; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToSelected, DAT_TribesState::ptr)( + DAT_CurrentUnitSlotID::instance); + _selectedCount = _selectedCount + 1; + } + if (_selectedCount == 0) { + return 0; + } + DAT_TribesState::instance.DAT_CurrentTribeID + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::getAvailableTribeID, DAT_TribesState::ptr)( + DAT_GameSynchronyState::instance.currentPlayerSlotID); + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = DAT_TribesState::instance.DAT_CurrentTribeID; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + OpenSHC::Commands::GCT_UNITS_SELECT); + return _selectedCount; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/deleteUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/deleteUnit.cpp new file mode 100644 index 000000000..8f2e72764 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/deleteUnit.cpp @@ -0,0 +1,32 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053E790 + void UnitsState::deleteUnit(uint unitID) + { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::deselectUnit, this)(unitID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::clearOrDeselectUnitFromSelection, this)( + this->units[unitID].owner, unitID, 0); + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[this->units[unitID].owner] == -1 + && this->units[unitID].isStalked == 0) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::updateUnitDeathHeatmapIn3SpacesAroundTile, + DAT_PathFindingState::ptr)(this->units[unitID].x, this->units[unitID].y); + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setupUnitSharingCurrentTilePosition, this)(unitID); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 0x490, '\0', &this->units[unitID]); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/deselectAllUnitsOneByOne.cpp b/src/OpenSHC/Map/Units/UnitsState/deselectAllUnitsOneByOne.cpp new file mode 100644 index 000000000..cceddfc70 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/deselectAllUnitsOneByOne.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00535150 + void UnitsState::deselectAllUnitsOneByOne() + { + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 0; + } + this->totalUnitsInSelection = 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/deselectUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/deselectUnit.cpp new file mode 100644 index 000000000..db8e9ebcd --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/deselectUnit.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00535190 + void UnitsState::deselectUnit(int unitID) + { + if (this->units[unitID].isSelected == 0) { + return; + } + this->units[unitID].isSelected = 0; + this->totalUnitsInSelection = this->totalUnitsInSelection - 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/despawnUnreachableUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/despawnUnreachableUnit.cpp new file mode 100644 index 000000000..229e6ad1b --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/despawnUnreachableUnit.cpp @@ -0,0 +1,37 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00533FC0 + void UnitsState::despawnUnreachableUnit(int unitID) + { + if (this->units[unitID].isSelectable_OR_matchTime != 0) { + return; + } + if ((short)this->units[unitID].unitType >= 0x37 && (short)this->units[unitID].unitType <= 0x39) { + return; + } + if ((DAT_TileMapState::instance.LogicLayer[this->units[unitID].tile] & 0x100U) == 0) { + return; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::someBinaryAlgFunctionPathFinding, + DAT_PathFindingState::ptr)(unitID) + == 0) { + return; + } + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + this->units[unitID].disappearFadeAlphaCountdown = 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/disbandUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/disbandUnit.cpp new file mode 100644 index 000000000..18b00fe19 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/disbandUnit.cpp @@ -0,0 +1,70 @@ +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::GameMode2; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052EDC0 + int UnitsState::disbandUnit(int unitID) + { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_E_KNIGHT + && this->units[unitID].horseOriginStablesBuildingIndexUnk != 0) { + if (*(int*)&this->units[unitID].horseOriginStableIDUnk + == DAT_BuildingsState::instance.buildings[this->units[unitID].horseOriginStablesBuildingIndexUnk] + .uid) { + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeTetheredUnitFromBuilding, + DAT_BuildingsState::ptr)(this->units[unitID].horseOriginStablesBuildingIndexUnk, unitID); + } + } + if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SIEGE_THAT) { + UnitTypeShort _unitType = this->units[unitID].unitType; + this->units[unitID].logicalState = OpenSHC::Map::Units::ULS_REMOVE; + /* note &unitID ! */ + int _refund = unitID; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getPriceForDisbandedUnitType, + DAT_BuildingsState::ptr)((UnitType)(short)_unitType, &_refund); + DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .startResources[0xf] += _refund; + return ( + int)&DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .startResources[0xf]; + } + BOOLEnum _hasCampground = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::playerHasACampground, + DAT_GameState::ptr)(this->units[unitID].owner); + this->units[unitID].disappearFadeAlphaCountdown = 0; + if (_hasCampground != FALSE) { + this->units[unitID].state_2 = 0; + this->units[unitID].cachedState = OpenSHC::Map::Units::States::US_DETERMINE_NEXT_STATEUnk; + this->units[unitID].unitTypeToChangeInto = OpenSHC::Map::Units::UT_PEASANT; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_JESTER_ROAM_TO; + this->units[unitID].engineerManningSiegeStateRef_checkType = 1; + this->units[unitID].isDisappearingUnk = 1; + return 1; + } + this->units[unitID].updateTickTracker = 0; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + this->units[unitID].killedFlagUnk = 1; + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/euroRecruit.cpp b/src/OpenSHC/Map/Units/UnitsState/euroRecruit.cpp new file mode 100644 index 000000000..34394d3f3 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/euroRecruit.cpp @@ -0,0 +1,148 @@ +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopDefinedData.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::GameMode; + using OpenSHC::Game::Resources::ResourceType; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052E960 + int UnitsState::euroRecruit(int unitType, undefined4 playersBarracksID, int playerID, int param_4) + { + /* archer is unittype 0x16 */ + this->euroUnitAcquisitionFailReason = 0; + int _unitCost = DAT_TroopDefinedData::instance.MarketResourceCycleArray[unitType + -1]; + int _armourResource + = DAT_UnitPropertiesDefinedData::instance.MELEE_DAMAGE[0x4e][unitType * 4 + 0x49]; + /* fixme: always 0 strange */ + int _unknownResource + = DAT_UnitPropertiesDefinedData::instance.MELEE_DAMAGE[0x4e][unitType * 4 + 0x4a]; + /* bug: if unitType was 0, then it became -0x16, which results in requiring wood + for creating this unit. This is nonsensical. It is wood because it will + access memory DAT_MELEE_DAMAGE_MATRIX[78][72], which happens to be 2 */ + int _weaponResource + = DAT_UnitPropertiesDefinedData::instance.MELEE_DAMAGE[0x4e][unitType * 4 + 0x48]; + int _horseResource = DAT_UnitPropertiesDefinedData::instance.MELEE_DAMAGE[0x4e][unitType * 4 + 0x4b]; + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY + && DAT_GameSynchronyState::instance.skirmishTroopsCostGold == 0) { + _unitCost = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < _unitCost) { + this->euroUnitAcquisitionFailReason = 1; + /* if we do not have the gold resources */ + return 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[_weaponResource] < 1 + && _weaponResource > 0) { + this->euroUnitAcquisitionFailReason = 2; + this->euroUnitRequiredResource = (ResourceType)_weaponResource; + /* we don't own the weapon required */ + return 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[_armourResource] < 1 + && _armourResource > 0) { + this->euroUnitAcquisitionFailReason = 2; + this->euroUnitRequiredResource = (ResourceType)_armourResource; + /* if we do not own the required armor */ + return 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[_unknownResource] < 1 + && _unknownResource > 0) { + this->euroUnitAcquisitionFailReason = 2; + this->euroUnitRequiredResource = (ResourceType)_unknownResource; + return 0; + } + if (_horseResource == -1) { + MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::recountStablesAndHorses, DAT_GameState::ptr)(); + if (DAT_GameState::instance.playerDataArray[playerID].availableHorses <= 0) { + this->euroUnitAcquisitionFailReason = 4; + return 0; + } + } + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_PEASANT) { + continue; + } + if (this->units[unitID].owner != playerID) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_RELOAD_WEAPONUnk) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_AIM_WEAPONUnk) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_JESTER_ROAM_TO) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_DETERMINE_NEXT_STATEUnk + && this->units[unitID].isDisappearingUnk != 0) { + continue; + } + if (param_4 != 0) { + return 1; + } + this->units[unitID].unitTypeToChangeInto = (UnitTypeShort)unitType; + this->units[unitID].engineerManningSiegeStateRef_checkType = 1; + this->units[unitID].isDisappearingUnk = 1; + this->units[unitID].state_2 = 0; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_JESTER_ROAM_TO; + this->units[unitID].disappearFadeAlphaCountdown = 0; + this->units[unitID].cachedState = OpenSHC::Map::Units::States::US_DETERMINE_NEXT_STATEUnk; + DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] -= _unitCost; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processResourceLoss, + DAT_BuildingsState::ptr)(playerID, (ResourceType)_weaponResource, 1, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processResourceLoss, + DAT_BuildingsState::ptr)(playerID, (ResourceType)_armourResource, 1, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processResourceLoss, + DAT_BuildingsState::ptr)(playerID, (ResourceType)_unknownResource, 1, 0); + if (_horseResource == -1) { + int _stableBuildingID = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::linkageBetweenHorseUnitAndStableUnk, + DAT_GameState::ptr)(playerID, unitID); + this->units[unitID].horseOriginStablesBuildingIndexUnk = (short)_stableBuildingID; + *(int*)&this->units[unitID].horseOriginStableIDUnk + = DAT_BuildingsState::instance.buildings[_stableBuildingID].uid; + } + DAT_GameSynchronyState::instance.finalResults.finalTroopsProduced[playerID] += 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::aiAssignNewUnitToTribe, DAT_TribesState::ptr)( + playerID, unitType, unitID); + return unitID; + } + this->euroUnitAcquisitionFailReason = 3; + /* units not allowed? over max amount units? */ + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/exitLadder.cpp b/src/OpenSHC/Map/Units/UnitsState/exitLadder.cpp new file mode 100644 index 000000000..7d0f0fdf0 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/exitLadder.cpp @@ -0,0 +1,35 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053D900 + void UnitsState::exitLadder(int unitID) + { + int _previousTile = this->units[unitID].field42_0x60; + this->units[unitID].vanish = 0; + this->units[unitID].usingTeleport = 0; + this->units[unitID].field203_0x35c = 0; + this->units[unitID].field43_0x64 = 0; + this->units[unitID].movementRelated = 8; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setupUnitSharingTileIDs, this)( + unitID, _previousTile); + this->units[unitID].field42_0x60 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setupUnitSharingCurrentTilePosition, this)(unitID); + this->units[unitID].y = this->units[unitID].mimicCurrentYPosition; + this->units[unitID].x = this->units[unitID].mimicCurrentXPosition; + this->units[unitID].microYPosition = this->units[unitID].mimicCurrentYPosition * 8 + 4; + this->units[unitID].tile = this->units[unitID].mimicCurrentXPosition + + DAT_ViewportRenderState::instance.translationMatrix[this->units[unitID].mimicCurrentYPosition] + .addXgetTile; + this->units[unitID].microXPosition = this->units[unitID].mimicCurrentXPosition * 8 + 4; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::updateMicroPosition, this)(unitID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::commitPendingUnitPosition, this)(unitID); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/extendRallyPoint.cpp b/src/OpenSHC/Map/Units/UnitsState/extendRallyPoint.cpp new file mode 100644 index 000000000..17d16073c --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/extendRallyPoint.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005370C0 + void UnitsState::extendRallyPoint(int tribeID, int mouseX, int mouseY, int rallyCount) + { + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = tribeID; + DAT_GameSynchronyState::instance.DAT_GameCommandParam1 = mouseX; + DAT_GameSynchronyState::instance.DAT_GameCommandParam2 = mouseY; + DAT_GameSynchronyState::instance.DAT_GameCommandParam3 = rallyCount; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + OpenSHC::Commands::GCT_UNIT_EXTEND_RALLY_POINT); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/filterUnitSelectionExcludeUnitType.cpp b/src/OpenSHC/Map/Units/UnitsState/filterUnitSelectionExcludeUnitType.cpp new file mode 100644 index 000000000..485ea5aaf --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/filterUnitSelectionExcludeUnitType.cpp @@ -0,0 +1,20 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x005351C0 + void UnitsState::filterUnitSelectionExcludeUnitType(int unitType) + { + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].isSelected != 0 && (short)this->units[unitID].unitType == unitType) { + this->units[unitID].isSelected = 0; + this->totalUnitsInSelection = this->totalUnitsInSelection - 1; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/filterUnitSelectionForUnitType.cpp b/src/OpenSHC/Map/Units/UnitsState/filterUnitSelectionForUnitType.cpp new file mode 100644 index 000000000..fb57aefe9 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/filterUnitSelectionForUnitType.cpp @@ -0,0 +1,20 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00535200 + void UnitsState::filterUnitSelectionForUnitType(int unitType) + { + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].isSelected != 0 && (short)this->units[unitID].unitType != unitType) { + this->units[unitID].isSelected = 0; + this->totalUnitsInSelection = this->totalUnitsInSelection - 1; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/findActiveSiegeEngineForTribe.cpp b/src/OpenSHC/Map/Units/UnitsState/findActiveSiegeEngineForTribe.cpp new file mode 100644 index 000000000..354a5b996 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/findActiveSiegeEngineForTribe.cpp @@ -0,0 +1,58 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053A4D0 + int UnitsState::findActiveSiegeEngineForTribe(int playerID) + { + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].owner != playerID) { + continue; + } + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].isSelectable_OR_matchTime == 0) { + continue; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_CATAPULT) { + return unitID; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) { + return unitID; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_MANGONEL) { + return unitID; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_BALLISTA) { + return unitID; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_FBALLISTA) { + return unitID; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + return unitID; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_TOWER) { + return unitID; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_SHIELD) { + return unitID; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/findAndAttackNearbyEnemyLaddermanInPosition.cpp b/src/OpenSHC/Map/Units/UnitsState/findAndAttackNearbyEnemyLaddermanInPosition.cpp new file mode 100644 index 000000000..fe7aa48f1 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/findAndAttackNearbyEnemyLaddermanInPosition.cpp @@ -0,0 +1,87 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic1.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00533630 + BOOLEnum UnitsState::findAndAttackNearbyEnemyLaddermanInPosition(int unitID) + { + int _unitX = this->units[unitID].x; + short _owner = this->units[unitID].owner; + int _unitY = this->units[unitID].y; + int _tile = this->units[unitID].tile; + dword _areaOfUnit = (short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; + int _bestEnemyUnitID = 0; + int _minDistance = 1000; + if ((DAT_TileMapState::instance.LogicLayer[_tile] & LogicHelpers::L_WALL_OR_GATEHOUSE) == 0) { + return FALSE; + } + for (int i = 0; i < DAT_GameState::instance.playerDataArray[_owner].enemies; ++i) { + int _enemyUnitID = DAT_GameState::instance.playerDataArray[_owner].enemyIDArray[i]; + if (this->units[_enemyUnitID].unitType != OpenSHC::Map::Units::UT_E_LADDER) { + continue; + } + if (this->units[_enemyUnitID].state.generic != (UnitState)3) { + continue; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isUsableClimbWithinArea, + DAT_PathFindingState::ptr)((short)_areaOfUnit, this->units[_enemyUnitID].wallDataID) + == FALSE) { + continue; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findPositionForGivenClimbArea, + DAT_PathFindingState::ptr)( + (short)_areaOfUnit, this->units[_enemyUnitID].x, this->units[_enemyUnitID].y); + int _distanceX; + if (DAT_PathFindingState::instance.climbX < _unitX) { + _distanceX = _unitX - DAT_PathFindingState::instance.climbX; + } else { + _distanceX = DAT_PathFindingState::instance.climbX - _unitX; + } + int _distanceY; + if (DAT_PathFindingState::instance.climbY < _unitY) { + _distanceY = _unitY - DAT_PathFindingState::instance.climbY; + } else { + _distanceY = DAT_PathFindingState::instance.climbY - _unitY; + } + if (_distanceX < _distanceY) { + /* stores the largest distance into _distanceX */ + _distanceX = _distanceY; + } + if (this->units[_enemyUnitID].targetShootRelated != 0) { + _distanceX = _distanceX + 10; + } + if (_distanceX < _minDistance) { + this->climbX2 = DAT_PathFindingState::instance.climbX; + this->climbY2 = DAT_PathFindingState::instance.climbY; + _bestEnemyUnitID = _enemyUnitID; + _minDistance = _distanceX; + } + } + if (_bestEnemyUnitID == 0) { + return FALSE; + } + this->units[unitID].shootTargetedUnit = (short)_bestEnemyUnitID; + this->units[unitID].targetUID = this->units[_bestEnemyUnitID].uid; + this->units[unitID].distanceToEnemyUnitLadders = (short)_minDistance; + this->units[_bestEnemyUnitID].targetShootRelated = 0x19; + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/findAndDestroyAdjacentEnemyLadder.cpp b/src/OpenSHC/Map/Units/UnitsState/findAndDestroyAdjacentEnemyLadder.cpp new file mode 100644 index 000000000..07f68ac22 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/findAndDestroyAdjacentEnemyLadder.cpp @@ -0,0 +1,44 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00533810 + int UnitsState::findAndDestroyAdjacentEnemyLadder(int unitID, int checkOnly) + { + for (int direction = 0; direction < 8; ++direction) { + for (int _otherUnitID = (short)DAT_TileMapState::instance.UnitLayer + [DAT_TileMapState::instance.directionTranslationMatrix[this->units[unitID].y][direction] + + this->units[unitID].tile]; + _otherUnitID > 0; _otherUnitID = (short)this->units[_otherUnitID].nextUnitOnTheSameTile) { + if (DAT_GameState::instance.mapAndTime.playerTeams[this->units[unitID].owner] + != DAT_GameState::instance.mapAndTime.playerTeams[this->units[_otherUnitID].owner] + && this->units[unitID].owner != 0 + && this->units[_otherUnitID].unitType == OpenSHC::Map::Units::UT_E_LADDER + && this->units[_otherUnitID].state.generic == (UnitState)3) { + if (checkOnly != 0) { + return direction; + } + this->units[_otherUnitID].dying = 1; + this->units[_otherUnitID].animationCycleNumber = 0; + this->units[_otherUnitID].state.generic = OpenSHC::Map::Units::States::US_DEATH_02; + this->units[_otherUnitID].tunnelerFinishedDigging = 1; + return 1; + } + } + } + return -1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/findClosestAnimalStoreResult.cpp b/src/OpenSHC/Map/Units/UnitsState/findClosestAnimalStoreResult.cpp new file mode 100644 index 000000000..666e1aec3 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/findClosestAnimalStoreResult.cpp @@ -0,0 +1,79 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537AA0 + int UnitsState::findClosestAnimalStoreResult(int maxDistance, BOOLEnum excludeCows, uint x, uint y) + { + if (x > 399 || y > 399) { + return 0; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return 0; + } + dword _areaOfOrigin + = (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x]; + this->unusedUnitIDArrayIndex = 0; + int _bestScore = 10000; + int _bestUnitID = 0; + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].unknownTestAgainst0_2 != 0) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + continue; + } + if (excludeCows == FALSE) { + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_ANTELOPESHDEER + && this->units[unitID].unitType != OpenSHC::Map::Units::UT_RABBIT + && this->units[unitID].unitType != OpenSHC::Map::Units::UT_COW) { + continue; + } + } else if (this->units[unitID].isStalked != 0) { + continue; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(x, y, this->units[unitID].x, this->units[unitID].y); + if (DAT_DirectionAlgorithmState::instance.distanceHigh > maxDistance) { + continue; + } + if (DAT_TileMapState::instance.PathConnectionLayer[this->units[unitID].tile] != _areaOfOrigin) { + continue; + } + this->unusedUnitIDArray[this->unusedUnitIDArrayIndex] = (short)unitID; + this->unusedUnitIDArrayIndex = this->unusedUnitIDArrayIndex + 1; + int _score = DAT_DirectionAlgorithmState::instance.distanceHigh + this->units[unitID].huntedBy * 3; + if (_score < _bestScore) { + _bestScore = _score; + _bestUnitID = unitID; + } + } + return _bestUnitID; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/findClosestEnemyByAreaAndRange.cpp b/src/OpenSHC/Map/Units/UnitsState/findClosestEnemyByAreaAndRange.cpp new file mode 100644 index 000000000..c4f764f49 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/findClosestEnemyByAreaAndRange.cpp @@ -0,0 +1,72 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537C10 + int UnitsState::findClosestEnemyByAreaAndRange(int range, uint x, uint y, int playerID) + { + if (x >= 400 || y >= 400) { + return 0; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return 0; + } + dword _areaOfOrigin + = (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x]; + this->unusedUnitIDArrayIndex = 0; + int _bestScore = 10000; + int _bestUnitID = 0; + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].unknownTestAgainst0_2 != 0) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + continue; + } + if (this->units[unitID].isStalked != 0) { + continue; + } + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] + == DAT_GameState::instance.mapAndTime.playerTeams[this->units[unitID].owner]) { + continue; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(x, y, this->units[unitID].x, this->units[unitID].y); + if (DAT_DirectionAlgorithmState::instance.distanceHigh > range) { + continue; + } + if (DAT_TileMapState::instance.PathConnectionLayer[this->units[unitID].tile] != _areaOfOrigin) { + continue; + } + int _score = DAT_DirectionAlgorithmState::instance.distanceHigh + this->units[unitID].huntedBy * 3; + if (_score < _bestScore) { + _bestScore = _score; + _bestUnitID = unitID; + } + } + return _bestUnitID; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/findEligibleUnitByTimeAndLocation.cpp b/src/OpenSHC/Map/Units/UnitsState/findEligibleUnitByTimeAndLocation.cpp new file mode 100644 index 000000000..c10abc7ca --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/findEligibleUnitByTimeAndLocation.cpp @@ -0,0 +1,68 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x005345A0 + int UnitsState::findEligibleUnitByTimeAndLocation( + int unitID, int playerID, int unitXPosition, int unitYPosition, int zero1, int zero2) + { + int _bestUnitID = 0; + int _bestScore = 0; + for (int _candidateUnitID = 1; _candidateUnitID < (int)this->maxUnitCount; ++_candidateUnitID) { + if (this->units[_candidateUnitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[_candidateUnitID].dying != 0) { + continue; + } + if (this->units[_candidateUnitID].owner != playerID) { + continue; + } + if (DAT_UnitPropertiesDefinedData::instance.SomeUnitStatMatrix5[this->units[_candidateUnitID].unitType] + != 0) { + continue; + } + if (_candidateUnitID == unitID) { + continue; + } + if (zero2 == 1 || zero2 == 10) { + if (this->units[_candidateUnitID].field131_0x2ac != (short)zero2) { + continue; + } + } + /* DAT_MatchTime - SEC_Units[_candidateUnitID].someMatchTimeVariable */ + int _score + = (DAT_GameCore::instance.mapTimeInTicks - this->units[_candidateUnitID].someMatchTimeVariable) + >> 5; + if (zero1 != 0) { + int _distance = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)( + unitXPosition, unitYPosition, this->units[_candidateUnitID].x, this->units[_candidateUnitID].y); + _score = _score - (_distance / 4); + } + if (_bestScore < _score) { + _bestScore = _score; + _bestUnitID = _candidateUnitID; + } + } + if (_bestUnitID == 0) { + return 0; + } + this->units[_bestUnitID].someMatchTimeVariable = DAT_GameCore::instance.mapTimeInTicks; + return _bestUnitID; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/findFreeTileNearby.cpp b/src/OpenSHC/Map/Units/UnitsState/findFreeTileNearby.cpp new file mode 100644 index 000000000..63a48e2da --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/findFreeTileNearby.cpp @@ -0,0 +1,250 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Buildings::BuildingType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005371F0 + uint UnitsState::findFreeTileNearby(uint unitID, uint tile) + { + dword _areaAtUnit = (short)DAT_TileMapState::instance.PathConnectionLayer[this->units[unitID].tile]; + int _originY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]; + int _originX = tile - DAT_ViewportRenderState::instance.translationMatrix[_originY].addXgetTile; + /* original_y-2 */ + uint _northTile = DAT_ViewportRenderState::instance.translationMatrix[_originY + -2].addXgetTile + _originX; + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(this->units[unitID].owner, _areaAtUnit, + (short)DAT_TileMapState::instance.PathConnectionLayer[_northTile], 0) + == 0) { + _northTile = 0; + } + /* original_x+2 */ + uint _eastTile = DAT_ViewportRenderState::instance.translationMatrix[_originY].addXgetTile + 2 + _originX; + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(this->units[unitID].owner, _areaAtUnit, + (short)DAT_TileMapState::instance.PathConnectionLayer[_eastTile], 0) + == 0) { + _eastTile = 0; + } + /* original_y+2 */ + uint _southTile = DAT_ViewportRenderState::instance.translationMatrix[_originY + 2].addXgetTile + _originX; + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(this->units[unitID].owner, _areaAtUnit, + (short)DAT_TileMapState::instance.PathConnectionLayer[_southTile], 0) + == 0) { + _southTile = 0; + } + /* original_x-2 */ + uint _westTile = DAT_ViewportRenderState::instance.translationMatrix[_originY].addXgetTile + -2 + _originX; + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(this->units[unitID].owner, _areaAtUnit, + (short)DAT_TileMapState::instance.PathConnectionLayer[_westTile], 0) + == 0) { + _westTile = 0; + } + if (_westTile == 0 && _southTile == 0 && _eastTile == 0 && _northTile == 0) { + return 0; + } + if ((_northTile != 0 || _southTile != 0) + && ((DAT_TileMapState::instance + .LogicLayer[DAT_ViewportRenderState::instance.translationMatrix[_originY].addXgetTile + + _originX - 1] + & 0x100) + == 0 + || (DAT_TileMapState::instance + .LogicLayer[DAT_ViewportRenderState::instance.translationMatrix[_originY].addXgetTile + + _originX + 1] + & 0x100) + == 0)) { + _southTile = 0; + _northTile = 0; + } + if ((_westTile != 0 || _eastTile != 0) + && ((DAT_TileMapState::instance + .LogicLayer[DAT_ViewportRenderState::instance.translationMatrix[_originY + -1].addXgetTile + + _originX] + & 0x100) + == 0 + || (DAT_TileMapState::instance + .LogicLayer[DAT_ViewportRenderState::instance.translationMatrix[_originY + 1].addXgetTile + + _originX] + & 0x100) + == 0)) { + _eastTile = 0; + _westTile = 0; + } + if (_northTile != 0) { + for (int i = 0; i < 9; ++i) { + uint _checkX = DAT_UnitPropertiesDefinedData::instance.field120_0x1213c[i].x + _originX; + uint _checkY = DAT_UnitPropertiesDefinedData::instance.field120_0x1213c[i].y + _originY; + if (_checkX >= 400 || _checkY >= 400) { + continue; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[_checkX + _checkY * 400] == 0) { + continue; + } + int _checkTile = DAT_ViewportRenderState::instance.translationMatrix[_checkY].addXgetTile + + DAT_UnitPropertiesDefinedData::instance.field120_0x1213c[i].x + _originX; + if ((DAT_TileMapState::instance.LogicLayer[_checkTile] & 0x100) != 0 + || (DAT_TileMapState::instance.LogicLayer[_checkTile] & 0x4a5014b1) != 0 + || (DAT_TileMapState::instance.BuildingLayer[_checkTile] != 0 + && DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance.BuildingLayer[_checkTile]] + .buildingType + != OpenSHC::Map::Buildings::BT_KILLINGPIT)) { + _northTile = 0; + break; + } + } + } + if (_eastTile != 0) { + for (int i = 0; i < 9; ++i) { + uint _checkX = DAT_UnitPropertiesDefinedData::instance.field121_0x12184[i].x + _originX; + uint _checkY = DAT_UnitPropertiesDefinedData::instance.field121_0x12184[i].y + _originY; + if (_checkX >= 400 || _checkY >= 400) { + continue; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[_checkX + _checkY * 400] == 0) { + continue; + } + int _checkTile = DAT_ViewportRenderState::instance.translationMatrix[_checkY].addXgetTile + + DAT_UnitPropertiesDefinedData::instance.field121_0x12184[i].x + _originX; + if ((DAT_TileMapState::instance.LogicLayer[_checkTile] & 0x100) != 0 + || (DAT_TileMapState::instance.LogicLayer[_checkTile] & 0x4a5014b1) != 0 + || (DAT_TileMapState::instance.BuildingLayer[_checkTile] != 0 + && DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance.BuildingLayer[_checkTile]] + .buildingType + != OpenSHC::Map::Buildings::BT_KILLINGPIT)) { + _eastTile = 0; + break; + } + } + } + if (_southTile != 0) { + for (int i = 0; i < 9; ++i) { + uint _checkX = DAT_UnitPropertiesDefinedData::instance.field122_0x121cc[i].x + _originX; + uint _checkY = DAT_UnitPropertiesDefinedData::instance.field122_0x121cc[i].y + _originY; + if (_checkX >= 400 || _checkY >= 400) { + continue; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[_checkX + _checkY * 400] == 0) { + continue; + } + int _checkTile = DAT_ViewportRenderState::instance.translationMatrix[_checkY].addXgetTile + + DAT_UnitPropertiesDefinedData::instance.field122_0x121cc[i].x + _originX; + if ((DAT_TileMapState::instance.LogicLayer[_checkTile] & 0x100) != 0 + || (DAT_TileMapState::instance.LogicLayer[_checkTile] & 0x4a5014b1) != 0 + || (DAT_TileMapState::instance.BuildingLayer[_checkTile] != 0 + && DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance.BuildingLayer[_checkTile]] + .buildingType + != OpenSHC::Map::Buildings::BT_KILLINGPIT)) { + _southTile = 0; + break; + } + } + } + if (_westTile != 0) { + for (int i = 0; i < 9; ++i) { + uint _checkX = DAT_UnitPropertiesDefinedData::instance.field123_0x12214[i].x + _originX; + uint _checkY = DAT_UnitPropertiesDefinedData::instance.field123_0x12214[i].y + _originY; + if (_checkX >= 400 || _checkY >= 400) { + continue; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[_checkX + _checkY * 400] == 0) { + continue; + } + int _checkTile = DAT_ViewportRenderState::instance.translationMatrix[_checkY].addXgetTile + + DAT_UnitPropertiesDefinedData::instance.field123_0x12214[i].x + _originX; + if ((DAT_TileMapState::instance.LogicLayer[_checkTile] & 0x100) != 0 + || (DAT_TileMapState::instance.LogicLayer[_checkTile] & 0x4a5014b1) != 0 + || (DAT_TileMapState::instance.BuildingLayer[_checkTile] != 0 + && DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance.BuildingLayer[_checkTile]] + .buildingType + != OpenSHC::Map::Buildings::BT_KILLINGPIT)) { + _westTile = 0; + break; + } + } + } + int _unitY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[this->units[unitID].tile]; + int _unitX + = this->units[unitID].tile - DAT_ViewportRenderState::instance.translationMatrix[_unitY].addXgetTile; + uint _closestTile = 0; + int _closestDistance = 100000; + if (_northTile != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(_northTile + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance + .tileTranslationMatrix_YComponent[_northTile]] + .addXgetTile, + DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_northTile], _unitX, _unitY); + if (DAT_DirectionAlgorithmState::instance.distanceHigh < _closestDistance) { + _closestTile = _northTile; + _closestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + } + } + if (_southTile != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(_southTile + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance + .tileTranslationMatrix_YComponent[_southTile]] + .addXgetTile, + DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_southTile], _unitX, _unitY); + if (DAT_DirectionAlgorithmState::instance.distanceHigh < _closestDistance) { + _closestTile = _southTile; + _closestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + } + } + if (_eastTile != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(_eastTile + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance + .tileTranslationMatrix_YComponent[_eastTile]] + .addXgetTile, + DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_eastTile], _unitX, _unitY); + if (DAT_DirectionAlgorithmState::instance.distanceHigh < _closestDistance) { + _closestTile = _eastTile; + _closestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + } + } + if (_westTile != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(_westTile + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance + .tileTranslationMatrix_YComponent[_westTile]] + .addXgetTile, + DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_westTile], _unitX, _unitY); + if (DAT_DirectionAlgorithmState::instance.distanceHigh < _closestDistance) { + _closestTile = _westTile; + _closestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + } + } + return _closestTile; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/findNearestEnemyAndHeadTowardsIt.cpp b/src/OpenSHC/Map/Units/UnitsState/findNearestEnemyAndHeadTowardsIt.cpp new file mode 100644 index 000000000..a7b9803cc --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/findNearestEnemyAndHeadTowardsIt.cpp @@ -0,0 +1,369 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0054A7B0 + dword UnitsState::findNearestEnemyAndHeadTowardsIt(int unitID) + { + int _microX = this->units[unitID].microXPosition; + int _microY = this->units[unitID].microYPosition; + int _playerID = this->units[unitID].owner; + dword _area = (short)DAT_TileMapState::instance.PathConnectionLayer[this->units[unitID].tile]; + this->unitDistanceComputationResultUnk = 100000; + int _minDistance = 100000; + int _chosenRawDistance = 0; + int _bestScore = 100000; + int _foundEnemyID = 0; + int _visionDivisor = 1; + int _skipStanceSearch = 0; + int _stanceBasedRange = 0; + short _isRallying = 0; + if ((this->units[unitID].SA != 0 + || (this->units[unitID].movementType_OR_targetUnitID != 0 + && this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_MOVE_TO_DESTINATION)) + && this->units[unitID].tribeID != 0) { + _isRallying = DAT_TribesState::instance.tribes[this->units[unitID].tribeID].isRallyingUnk; + if (DAT_TribesState::instance.tribes[this->units[unitID].tribeID].unitStance + == OpenSHC::Map::Units::Behavior::USE_DEFENSIVE) { + _stanceBasedRange = 40; + } else if (DAT_TribesState::instance.tribes[this->units[unitID].tribeID].unitStance + == OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE) { + _stanceBasedRange = 200; + } + } + if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_UNIT_ATTACK_UNIT) { + _skipStanceSearch = 1; + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_TUNNELER: + case OpenSHC::Map::Units::UT_E_SPEAR: + case OpenSHC::Map::Units::UT_E_PIKE: + case OpenSHC::Map::Units::UT_E_MACE: + case OpenSHC::Map::Units::UT_E_SWORD: + case OpenSHC::Map::Units::UT_E_KNIGHT: + case OpenSHC::Map::Units::UT_E_MONK: + case OpenSHC::Map::Units::UT_LORD: + case OpenSHC::Map::Units::UT_A_SLAVE: + case OpenSHC::Map::Units::UT_A_ASSASSIN: + case OpenSHC::Map::Units::UT_A_SWORDSMAN: + _skipStanceSearch = 0; + if (this->units[unitID].tribeID != 0) { + int _tribeUnitID = DAT_TribesState::instance.tribes[this->units[unitID].tribeID].someUnitID; + if (_tribeUnitID != 0 + && this->units[_tribeUnitID].uid + == DAT_TribesState::instance.tribes[this->units[unitID].tribeID].someUnitUID) { + _skipStanceSearch = 1; + break; + } + } + this->units[unitID].targetingType = OpenSHC::Map::Units::UIT_NO_INSTRUCTION_OR_MOVEUnk; + } + } else if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_ATTACK_LAND) { + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_E_SPEAR: + case OpenSHC::Map::Units::UT_E_PIKE: + case OpenSHC::Map::Units::UT_E_MACE: + case OpenSHC::Map::Units::UT_E_SWORD: + case OpenSHC::Map::Units::UT_E_KNIGHT: + case OpenSHC::Map::Units::UT_E_MONK: + case OpenSHC::Map::Units::UT_A_SLAVE: + case OpenSHC::Map::Units::UT_A_ASSASSIN: + case OpenSHC::Map::Units::UT_A_SWORDSMAN: + if (this->units[unitID].lookForEnemy >= 0 + && this->units[unitID].state.generic != OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + if (this->units[unitID].attackAtTileX == this->units[unitID].x + && this->units[unitID].attackAtTileY == this->units[unitID].y) { + this->units[unitID].targetingType = (UnitInstructionType)0; + break; + } + this->units[unitID].plannedDestinationY = this->units[unitID].attackAtTileY; + this->units[unitID].plannedDestinationX = this->units[unitID].attackAtTileX; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, this->units[unitID].attackAtTileX, this->units[unitID].attackAtTileY, 0); + int _lookAhead = -(this->units[unitID].totalSizeOfPathPlan / 2); + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_MOVE_TO_DESTINATION; + if (_lookAhead > -0x33) { + _lookAhead = -0x32; + } + this->units[unitID].lookForEnemy = (short)_lookAhead; + } + _skipStanceSearch = 1; + } + } + if (this->units[unitID].isSelectable_OR_matchTime == 0) { + _skipStanceSearch = 1; + } + if (DAT_GameState::instance.playerDataArray[_playerID].enemies < 5) { + _visionDivisor = 5; + } else if (DAT_GameState::instance.playerDataArray[_playerID].enemies < 15) { + _visionDivisor = 2; + } + for (int _enemyIndex = 0; _enemyIndex < DAT_GameState::instance.playerDataArray[_playerID].enemies; + ++_enemyIndex) { + int _enemyUnitID = DAT_GameState::instance.playerDataArray[_playerID].enemyIDArray[_enemyIndex]; + int _distanceX; + if (this->units[_enemyUnitID].microXPosition < _microX) { + _distanceX = _microX - this->units[_enemyUnitID].microXPosition; + } else { + _distanceX = this->units[_enemyUnitID].microXPosition - _microX; + } + int _distanceY; + if (this->units[_enemyUnitID].microYPosition < _microY) { + _distanceY = _microY - this->units[_enemyUnitID].microYPosition; + } else { + _distanceY = this->units[_enemyUnitID].microYPosition - _microY; + } + int _approximateDistance; + if (_distanceX < _distanceY) { + /* pythagorean approximation */ + _approximateDistance = (((_distanceX * 2) / 5) * _distanceX) / _distanceY + _distanceY; + } else if (_distanceX == 0) { + /* fixme: bug: I think this needs to be set not to 0 but to _distanceY */ + _approximateDistance = 0; + } else { + _approximateDistance = (((_distanceY * 2) / 5) * _distanceY) / _distanceX + _distanceX; + } + if (_approximateDistance < _minDistance) { + _minDistance = _approximateDistance; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_A_ASSASSIN + && this->units[_enemyUnitID].isSelectable_OR_matchTime != 0 + && _approximateDistance < (int)this->unitDistanceComputationResultUnk) { + this->unitDistanceComputationResultUnk = _approximateDistance; + } + if (_skipStanceSearch || _stanceBasedRange == 0 || this->units[unitID].lookForEnemy < 0) { + continue; + } + int _score = _approximateDistance; + if (this->units[unitID]._someX_2 != 0 && _isRallying == 0 && _stanceBasedRange == 40) { + int _savedDistanceX; + if (this->units[unitID]._someX_2 * 8 < this->units[_enemyUnitID].microXPosition) { + _savedDistanceX = this->units[_enemyUnitID].microXPosition + this->units[unitID]._someX_2 * -8; + } else { + _savedDistanceX = this->units[unitID]._someX_2 * 8 - this->units[_enemyUnitID].microXPosition; + } + if (this->units[unitID]._someY_2 * 8 < this->units[_enemyUnitID].microYPosition) { + _score = this->units[_enemyUnitID].microYPosition + this->units[unitID]._someY_2 * -8; + } else { + _score = this->units[unitID]._someY_2 * 8 - this->units[_enemyUnitID].microYPosition; + } + if (_score <= _savedDistanceX) { + _score = _savedDistanceX; + } + } + int _rawDistance = _score; + if (_score > _stanceBasedRange) { + continue; + } + if (this->units[_enemyUnitID].uid + != DAT_GameState::instance.mapAndTime.playerEnemenyUnitUIDShortList[_playerID][_enemyIndex]) { + continue; + } + _score = _score + + DAT_UnitPropertiesDefinedData::instance + .UnitVisionBonus[(this->units[unitID].fixedRng + _enemyUnitID) % 10] + / _visionDivisor; + if (this->units[_enemyUnitID].state.generic == OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + _score = (this->units[_enemyUnitID].attackedBy * 50 + _score) * 2; + if (this->units[_enemyUnitID].attackedBy >= 3) { + continue; + } + } + if (this->units[_enemyUnitID].huntedBy >= 2) { + _score = _score + this->units[_enemyUnitID].huntedBy * 0x32; + if (this->units[_enemyUnitID].huntedBy >= 3 + && this->units[unitID].movementType_OR_targetUnitID != _enemyUnitID) { + continue; + } + } + if (this->units[_enemyUnitID].isStalked != 0 + && this->units[_enemyUnitID].unitType != OpenSHC::Map::Units::UT_LIONSHWOLF + && this->units[_enemyUnitID].unitType != OpenSHC::Map::Units::UT_CAGEDOG) { + continue; + } + switch (this->units[_enemyUnitID].unitType) { + case OpenSHC::Map::Units::UT_PEASANT: + _score = _score * 8 + 200; + break; + case OpenSHC::Map::Units::UT_E_ARCHER: + case OpenSHC::Map::Units::UT_E_XBOW: + case OpenSHC::Map::Units::UT_A_ARCHER: + case OpenSHC::Map::Units::UT_A_HARCHER: + case OpenSHC::Map::Units::UT_A_FIRETHROWER: + break; + case OpenSHC::Map::Units::UT_E_SPEAR: + case OpenSHC::Map::Units::UT_E_PIKE: + case OpenSHC::Map::Units::UT_E_MACE: + case OpenSHC::Map::Units::UT_E_SWORD: + case OpenSHC::Map::Units::UT_E_KNIGHT: + case OpenSHC::Map::Units::UT_E_LADDER: + case OpenSHC::Map::Units::UT_E_MONK: + case OpenSHC::Map::Units::UT_A_SLAVE: + case OpenSHC::Map::Units::UT_A_SLINGER: + case OpenSHC::Map::Units::UT_A_ASSASSIN: + case OpenSHC::Map::Units::UT_A_SWORDSMAN: + _score = _score * 2 + 100; + break; + case OpenSHC::Map::Units::UT_E_ENGINEER: + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_TREBUCHET: + case OpenSHC::Map::Units::UT_S_MANGONEL: + case OpenSHC::Map::Units::UT_S_TOWER: + case OpenSHC::Map::Units::UT_S_BATTERINGRAM: + case OpenSHC::Map::Units::UT_S_SHIELD: + case OpenSHC::Map::Units::UT_S_BALLISTA: + case OpenSHC::Map::Units::UT_S_FBALLISTA: + _score = _score + 0x19; + break; + case OpenSHC::Map::Units::UT_LORD: + _score = _score / 4; + break; + default: + _score = _score * 4 + 200; + } + if (this->units[unitID].movementType_OR_targetUnitID == _enemyUnitID) { + _score = _score / 2; + } + if (_score >= _bestScore) { + continue; + } + int _enemyTotalHeight + = this->units[_enemyUnitID].buildingHeight + this->units[_enemyUnitID].terrainOrClimbHeight; + int _bestApproachDirection = -1; + int _bestApproachDistance = 10000; + for (int _direction = 0; _direction < 8; ++_direction) { + int _approachTile = DAT_TileMapState::instance.directionTranslationMatrix[this->units[_enemyUnitID] + .y][DAT_UnitPropertiesDefinedData::instance.field84_0x11cb4[_direction]] + + this->units[_enemyUnitID].tile; + if (DAT_TileMapState::instance.UnitLayer[_approachTile] != 0) { + continue; + } + uint _tileHeight = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)(_approachTile); + if (_enemyTotalHeight >= (int)(_tileHeight + 0x10)) { + continue; + } + if ((int)(_tileHeight - 0x10) >= _enemyTotalHeight) { + continue; + } + int _approachY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_approachTile]; + int _approachX + = _approachTile - DAT_ViewportRenderState::instance.translationMatrix[_approachY].addXgetTile; + int _approachDistanceX; + if (_approachX * 8 < _microX) { + _approachDistanceX = _microX + _approachX * -8; + } else { + _approachDistanceX = _approachX * 8 - _microX; + } + int _approachDistance; + if (_approachY * 8 < _microY) { + _approachDistance = _microY + _approachY * -8; + } else { + _approachDistance = _approachY * 8 - _microY; + } + if (_approachDistance <= _approachDistanceX) { + _approachDistance = _approachDistanceX; + } + if (_approachDistance < _bestApproachDistance) { + _bestApproachDistance = _approachDistance; + _bestApproachDirection = _direction; + } + } + if (_bestApproachDirection >= 0) { + _bestScore = _score; + _chosenRawDistance = _rawDistance; + _foundEnemyID = _enemyUnitID; + } + } + int _restoreSavedDestination = 0; + if (_stanceBasedRange == 0) { + if (this->units[unitID].lookForEnemy == 0) { + this->units[unitID].movementType_OR_targetUnitID = 0; + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_MOVE_TO_DESTINATION) { + _restoreSavedDestination = 1; + } + } + } else if (this->units[unitID].lookForEnemy >= 0) { + if (_skipStanceSearch) { + if (this->units[unitID].lookForEnemy == 0) { + this->units[unitID].movementType_OR_targetUnitID = 0; + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_MOVE_TO_DESTINATION) { + _restoreSavedDestination = 1; + } + } + } else { + int _headedToEnemy = 0; + if (_foundEnemyID != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: + calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(this->units[unitID].owner, (short)_area, + (short)DAT_TileMapState::instance.PathConnectionLayer[this->units[_foundEnemyID].tile], + this->units[unitID].unitCanClimb) + != 0) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_MOVE_TO_DESTINATION; + this->units[unitID].animationCycleNumber = 0; + if (this->units[unitID]._someX_2 == 0) { + this->units[unitID]._someX_2 = this->units[unitID].destinationX_2Unk; + this->units[unitID]._someY_2 = this->units[unitID].destinationY_2Unk; + } + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::findNearestValidDigTileNearTarget, + DAT_TileMapState::ptr)(this->units[unitID].x, this->units[unitID].y, + this->units[_foundEnemyID].x, this->units[_foundEnemyID].y); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)(unitID, + DAT_TileMapState::instance.field155_0x5549a8, DAT_TileMapState::instance.field156_0x5549ac, + 0); + int _lookAhead = -0x1e - _chosenRawDistance; + this->units[unitID].moveDelay = 0; + if (_lookAhead > -0x33) { + _lookAhead = -0x32; + } + this->units[unitID].lookForEnemy = (short)_lookAhead; + if (this->units[unitID].movementType_OR_targetUnitID != _foundEnemyID) { + this->units[unitID].movementType_OR_targetUnitID = (short)_foundEnemyID; + this->units[_foundEnemyID].huntedBy = this->units[_foundEnemyID].huntedBy + 1; + } + _headedToEnemy = 1; + } + if (!_headedToEnemy) { + this->units[unitID].lookForEnemy = -8; + this->units[unitID].movementType_OR_targetUnitID = 0; + _restoreSavedDestination = 1; + } + } + } + if (_restoreSavedDestination && this->units[unitID]._someX_2 != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, this->units[unitID]._someX_2, this->units[unitID]._someY_2, 0); + this->units[unitID].moveDelay = 0; + this->units[unitID]._someY_2 = 0; + this->units[unitID]._someX_2 = 0; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_MOVE_TO_DESTINATION; + } + if (_minDistance > 32000) { + _minDistance = 32000; + } + return _minDistance; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/findNearestIdleCowForPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/findNearestIdleCowForPlayer.cpp new file mode 100644 index 000000000..0d85327f4 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/findNearestIdleCowForPlayer.cpp @@ -0,0 +1,50 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537A00 + int UnitsState::findNearestIdleCowForPlayer(int playerID, int x, int y) + { + int _bestDistance = 10000; + int _bestUnitID = 0; + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].owner != playerID) { + continue; + } + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_COW) { + continue; + } + if (this->units[unitID].state.generic != OpenSHC::Map::Units::States::US_DETERMINE_NEXT_STATEUnk) { + continue; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(x, y, this->units[unitID].x, this->units[unitID].y); + if (DAT_DirectionAlgorithmState::instance.distanceHigh < _bestDistance) { + _bestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + _bestUnitID = unitID; + } + } + return _bestUnitID; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/findNearestShootableDeer.cpp b/src/OpenSHC/Map/Units/UnitsState/findNearestShootableDeer.cpp new file mode 100644 index 000000000..24f1d90d8 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/findNearestShootableDeer.cpp @@ -0,0 +1,71 @@ +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_EntityState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537880 + int UnitsState::findNearestShootableDeer(int unitID) + { + for (int _minimumDistance = 20;; _minimumDistance = 5) { + int _bestDistance = 100000; + int _bestUnitID = 0; + for (int _deerUnitID = 1; _deerUnitID < (int)this->maxUnitCount; ++_deerUnitID) { + if (this->units[_deerUnitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[_deerUnitID].dying != 0) { + continue; + } + if (this->units[_deerUnitID].owner != 0) { + continue; + } + if (this->units[_deerUnitID].unitType != OpenSHC::Map::Units::UT_ANTELOPESHDEER) { + continue; + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(this->units[unitID].x, this->units[unitID].y, + this->units[_deerUnitID].x, this->units[_deerUnitID].y); + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _minimumDistance) { + continue; + } + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= 0x35 + && MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::arrowShootingRelated, + DAT_EntityState::ptr)(this->units[unitID].microXPosition, + this->units[unitID].microYPosition, + this->units[unitID].buildingHeight + 0x1e + this->units[unitID].terrainOrClimbHeight, + this->units[_deerUnitID].microXPosition, this->units[_deerUnitID].microYPosition, + this->units[_deerUnitID].terrainOrClimbHeight + 0x1a + + this->units[_deerUnitID].buildingHeight) + - 1U + >= 0x1b0) { + continue; + } + if (DAT_DirectionAlgorithmState::instance.distanceHigh < _bestDistance) { + _bestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + _bestUnitID = _deerUnitID; + } + } + if (_bestUnitID != 0) { + return _bestUnitID; + } + if (_minimumDistance != 20) { + return 0; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/findTunnelTarget.cpp b/src/OpenSHC/Map/Units/UnitsState/findTunnelTarget.cpp new file mode 100644 index 000000000..a9380a014 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/findTunnelTarget.cpp @@ -0,0 +1,61 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537700 + BOOLEnum UnitsState::findTunnelTarget(int originBuildingID, int targetPlayer) + { + if ((int)DAT_BuildingsState::instance.buildings[originBuildingID].tunnelerCounter < 0) { + return FALSE; + } + int _distance; + if ((int)DAT_BuildingsState::instance.buildings[originBuildingID].tunnelerCounter <= 0) { + _distance = 20; + } else if ((int)DAT_BuildingsState::instance.buildings[originBuildingID].tunnelerCounter < 2) { + _distance = 20; + } else if ((int)DAT_BuildingsState::instance.buildings[originBuildingID].tunnelerCounter < 3) { + _distance = 40; + } else if ((int)DAT_BuildingsState::instance.buildings[originBuildingID].tunnelerCounter < 4) { + _distance = 40; + } else { + if ((int)DAT_BuildingsState::instance.buildings[originBuildingID].tunnelerCounter > 5) { + DAT_BuildingsState::instance.buildings[originBuildingID].tunnelerCounter = -1; + return FALSE; + } + _distance = 80; + } + ushort _tunnelStartY; + if ((DAT_BuildingsState::instance.buildings[originBuildingID].tunnelerCounter & 1) == 0) { + DAT_BuildingsState::instance.buildings[originBuildingID].someX + = DAT_BuildingsState::instance.buildings[originBuildingID].x; + _tunnelStartY = DAT_BuildingsState::instance.buildings[originBuildingID].y - 1; + } else { + DAT_BuildingsState::instance.buildings[originBuildingID].someX + = DAT_BuildingsState::instance.buildings[originBuildingID].x - 1; + _tunnelStartY = DAT_BuildingsState::instance.buildings[originBuildingID].y; + } + DAT_BuildingsState::instance.buildings[originBuildingID].tunnelerCounter + = DAT_BuildingsState::instance.buildings[originBuildingID].tunnelerCounter + 1; + DAT_BuildingsState::instance.buildings[originBuildingID].someY = _tunnelStartY; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::algTunnelerFindTarget, + DAT_PathFindingState::ptr)(DAT_BuildingsState::instance.buildings[originBuildingID].owner, targetPlayer, + _distance, DAT_BuildingsState::instance.buildings[originBuildingID].someX, (short)_tunnelStartY); + if (DAT_PathFindingState::instance.ALG_TargetTile == 0) { + return FALSE; + } + DAT_BuildingsState::instance.buildings[originBuildingID].tunnelerCounter = -1; + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getAliveLordForPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/getAliveLordForPlayer.cpp new file mode 100644 index 000000000..867ecbf36 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getAliveLordForPlayer.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005377F0 + int UnitsState::getAliveLordForPlayer(int playerID) + { + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_LORD + && this->units[unitID].owner == playerID + && this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[unitID].dying == 0) { + return unitID; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getArmySize.cpp b/src/OpenSHC/Map/Units/UnitsState/getArmySize.cpp new file mode 100644 index 000000000..9f0b04ebf --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getArmySize.cpp @@ -0,0 +1,14 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00532F60 + int UnitsState::getArmySize(int playerID) { return DAT_GameState::instance.playerDataArray[playerID].armySize; } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getDestination2EqualsGivenCoordinates.cpp b/src/OpenSHC/Map/Units/UnitsState/getDestination2EqualsGivenCoordinates.cpp new file mode 100644 index 000000000..5fac9ac47 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getDestination2EqualsGivenCoordinates.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00533920 + BOOLEnum UnitsState::getDestination2EqualsGivenCoordinates(int unitID, int x, int y) + { + if (this->units[unitID].destinationX_2Unk != x) { + return TRUE; + } + return (BOOLEnum)(this->units[unitID].destinationY_2Unk != y); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getEnemyUnitIDNearby.cpp b/src/OpenSHC/Map/Units/UnitsState/getEnemyUnitIDNearby.cpp new file mode 100644 index 000000000..01ac2f2a4 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getEnemyUnitIDNearby.cpp @@ -0,0 +1,45 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053CAE0 + int UnitsState::getEnemyUnitIDNearby(int unitID, int tileUnk, int unitHeight) + { + int _otherUnitID = (short)DAT_TileMapState::instance.UnitLayer[tileUnk]; + if (_otherUnitID == 0) { + return 0; + } + for (int _visited = 0; _visited <= 1999; ++_visited) { + if (this->units[_otherUnitID].dying == 0 && this->units[_otherUnitID].unknownTestAgainst0_2 == 0 + && this->units[_otherUnitID].moveRelatedFlag != 1) { + int _otherHeight + = this->units[_otherUnitID].buildingHeight + this->units[_otherUnitID].terrainOrClimbHeight; + if (_otherHeight <= unitHeight + 0x20 && unitHeight + -0x20 <= _otherHeight + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::shouldUnitsEngageInMelee, this)( + unitID, _otherUnitID) + == FALSE + && (DAT_GameState::instance.mapAndTime.playerTeams[this->units[_otherUnitID].owner] + != DAT_GameState::instance.mapAndTime.playerTeams[this->units[unitID].owner] + || this->units[unitID].owner == 0)) { + return _otherUnitID; + } + } + _otherUnitID = (short)this->units[_otherUnitID].nextUnitOnTheSameTile; + if (_otherUnitID <= 0) { + return 0; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedCatapultOrTrebuchetID.cpp b/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedCatapultOrTrebuchetID.cpp new file mode 100644 index 000000000..393795eaf --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedCatapultOrTrebuchetID.cpp @@ -0,0 +1,45 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536710 + uint UnitsState::getFirstSelectedCatapultOrTrebuchetID() + { + int _currentPlayerSlotID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner != _currentPlayerSlotID) { + return 0; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_CATAPULT) { + return DAT_CurrentUnitSlotID::instance; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) { + return DAT_CurrentUnitSlotID::instance; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedLadderUnitID.cpp b/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedLadderUnitID.cpp new file mode 100644 index 000000000..6098cd568 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedLadderUnitID.cpp @@ -0,0 +1,42 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005365A0 + uint UnitsState::getFirstSelectedLadderUnitID() + { + int _currentPlayerSlotID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner != _currentPlayerSlotID) { + return 0; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_E_LADDER) { + return DAT_CurrentUnitSlotID::instance; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedSiegeEngineID.cpp b/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedSiegeEngineID.cpp new file mode 100644 index 000000000..75b4758a4 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedSiegeEngineID.cpp @@ -0,0 +1,54 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536690 + uint UnitsState::getFirstSelectedSiegeEngineID() + { + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return 0; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_CATAPULT) { + return DAT_CurrentUnitSlotID::instance; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) { + return DAT_CurrentUnitSlotID::instance; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_MANGONEL) { + return DAT_CurrentUnitSlotID::instance; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_BALLISTA) { + return DAT_CurrentUnitSlotID::instance; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_FBALLISTA) { + return DAT_CurrentUnitSlotID::instance; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedUnitID.cpp b/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedUnitID.cpp new file mode 100644 index 000000000..491e21bda --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedUnitID.cpp @@ -0,0 +1,25 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535DF0 + void UnitsState::getFirstSelectedUnitID(undefined4 param_1) + { + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = param_1; + DAT_GameSynchronyState::instance.DAT_GameCommandParam1 = DAT_TribesState::instance.DAT_CurrentTribeID; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + (GameCommandType)0x48); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedUnitOfEitherType.cpp b/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedUnitOfEitherType.cpp new file mode 100644 index 000000000..e4025d738 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getFirstSelectedUnitOfEitherType.cpp @@ -0,0 +1,43 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x005362F0 + uint UnitsState::getFirstSelectedUnitOfEitherType(int unitType_1, int unitType_2) + { + int _currentPlayerSlotID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner != _currentPlayerSlotID) { + return 0; + } + if ((short)this->units[DAT_CurrentUnitSlotID::instance].unitType == unitType_1) { + return DAT_CurrentUnitSlotID::instance; + } + if ((short)this->units[DAT_CurrentUnitSlotID::instance].unitType == unitType_2) { + return DAT_CurrentUnitSlotID::instance; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getLivingSelectableUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/getLivingSelectableUnit.cpp new file mode 100644 index 000000000..9a018eac7 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getLivingSelectableUnit.cpp @@ -0,0 +1,25 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053A560 + int UnitsState::getLivingSelectableUnit(int playerID) + { + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].owner == playerID + && this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[unitID].dying == 0 && this->units[unitID].isSelectable_OR_matchTime != 0) { + return unitID; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getMaxStoneAmmoInSelectedSiegeEngines.cpp b/src/OpenSHC/Map/Units/UnitsState/getMaxStoneAmmoInSelectedSiegeEngines.cpp new file mode 100644 index 000000000..879680040 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getMaxStoneAmmoInSelectedSiegeEngines.cpp @@ -0,0 +1,47 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536370 + int UnitsState::getMaxStoneAmmoInSelectedSiegeEngines() + { + int _maxStoneAmmunition = 0; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return 0; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType != OpenSHC::Map::Units::UT_S_CATAPULT + && this->units[DAT_CurrentUnitSlotID::instance].unitType != OpenSHC::Map::Units::UT_S_TREBUCHET) { + continue; + } + if (_maxStoneAmmunition < this->units[DAT_CurrentUnitSlotID::instance].stoneAmmunition) { + _maxStoneAmmunition = this->units[DAT_CurrentUnitSlotID::instance].stoneAmmunition; + } + } + return _maxStoneAmmunition; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getPeasantGmID.cpp b/src/OpenSHC/Map/Units/UnitsState/getPeasantGmID.cpp new file mode 100644 index 000000000..0bc5980be --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getPeasantGmID.cpp @@ -0,0 +1,91 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/IO/Graphics/GmID.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::IO::Graphics::GmID; + + // FUNCTION: STRONGHOLDCRUSADER 0x00539BE0 + GmID UnitsState::getPeasantGmID(int unitID) + { + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_BURNINGMAN: + return OpenSHC::IO::Graphics::GID_BODY_MAN_BURNING; + case OpenSHC::Map::Units::UT_WOODCUTTER: + return OpenSHC::IO::Graphics::GID_BODY_WOODCUTTER; + case OpenSHC::Map::Units::UT_FLETCHER: + return OpenSHC::IO::Graphics::GID_BODY_FLETCHER; + case OpenSHC::Map::Units::UT_TUNNELER: + return OpenSHC::IO::Graphics::GID_BODY_TUNNELOR; + case OpenSHC::Map::Units::UT_HUNTER: + return OpenSHC::IO::Graphics::GID_BODY_HUNTER; + case OpenSHC::Map::Units::UT_QUARRYOX: + return OpenSHC::IO::Graphics::GID_BODY_OX; + case OpenSHC::Map::Units::UT_PITCHMAN: + return OpenSHC::IO::Graphics::GID_BODY_PITCH_WORKER; + case OpenSHC::Map::Units::UT_WHEATFARMER: + case OpenSHC::Map::Units::UT_HOPSFARMER: + case OpenSHC::Map::Units::UT_APPLEFARMER: + case OpenSHC::Map::Units::UT_DAIRYFARMER: + return OpenSHC::IO::Graphics::GID_BODY_FARMER; + case OpenSHC::Map::Units::UT_MILLER: + return OpenSHC::IO::Graphics::GID_BODY_MILLER; + case OpenSHC::Map::Units::UT_BAKER: + return OpenSHC::IO::Graphics::GID_BODY_BAKER; + case OpenSHC::Map::Units::UT_BREWER: + return OpenSHC::IO::Graphics::GID_BODY_BREWER; + case OpenSHC::Map::Units::UT_POLETURNER: + return OpenSHC::IO::Graphics::GID_BODY_POLETURNER; + case OpenSHC::Map::Units::UT_SMITH: + return OpenSHC::IO::Graphics::GID_BODY_BLACKSMITH; + case OpenSHC::Map::Units::UT_ARMORER: + return OpenSHC::IO::Graphics::GID_BODY_ARMOURER; + case OpenSHC::Map::Units::UT_TANNER: + return OpenSHC::IO::Graphics::GID_BODY_TANNER; + case OpenSHC::Map::Units::UT_MINER: + case OpenSHC::Map::Units::UT_TRANSPORTMINER: + return OpenSHC::IO::Graphics::GID_BODY_IRON_MINER; + case OpenSHC::Map::Units::UT_PRIEST: + return OpenSHC::IO::Graphics::GID_BODY_PRIEST; + case OpenSHC::Map::Units::UT_HEALER: + return OpenSHC::IO::Graphics::GID_BODY_HEALER; + case OpenSHC::Map::Units::UT_DRUNK: + return OpenSHC::IO::Graphics::GID_BODY_DRUNKARD; + case OpenSHC::Map::Units::UT_TRADER: + return OpenSHC::IO::Graphics::GID_BODY_TRADER; + case OpenSHC::Map::Units::UT_TRADERHORSE: + return OpenSHC::IO::Graphics::GID_BODY_HORSE_TRADER; + case OpenSHC::Map::Units::UT_COW: + return OpenSHC::IO::Graphics::GID_BODY_COW; + case OpenSHC::Map::Units::UT_HUNTERDOG: + return OpenSHC::IO::Graphics::GID_BODY_DOG; + case OpenSHC::Map::Units::UT_LORD: + return OpenSHC::IO::Graphics::GID_BODY_LORD; + case OpenSHC::Map::Units::UT_LADY: + return OpenSHC::IO::Graphics::GID_BODY_LADY; + case OpenSHC::Map::Units::UT_JESTER: + return OpenSHC::IO::Graphics::GID_BODY_JESTER; + case OpenSHC::Map::Units::UT_CHICKEN: + return OpenSHC::IO::Graphics::GID_BODY_CHICKEN; + case OpenSHC::Map::Units::UT_MOTHER: + return OpenSHC::IO::Graphics::GID_BODY_MOTHER; + case OpenSHC::Map::Units::UT_CHILD: + return OpenSHC::IO::Graphics::GID_BODY_BOY; + case OpenSHC::Map::Units::UT_JUGGLER: + return OpenSHC::IO::Graphics::GID_BODY_JUGGLER; + case OpenSHC::Map::Units::UT_FIREEATER: + return OpenSHC::IO::Graphics::GID_BODY_FIRE_EATER; + case OpenSHC::Map::Units::UT_BURNING_ANIMAL_BIG: + return OpenSHC::IO::Graphics::GID_BODY_ANIMAL_BURNING_BIG; + case OpenSHC::Map::Units::UT_BURNING_ANIMAL_SMALL: + return OpenSHC::IO::Graphics::GID_BODY_ANIMAL_BURNING_SMALL; + default: + return OpenSHC::IO::Graphics::GID_BODY_PEASANT; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getRawDeerCount.cpp b/src/OpenSHC/Map/Units/UnitsState/getRawDeerCount.cpp new file mode 100644 index 000000000..42b1bd263 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getRawDeerCount.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537840 + int UnitsState::getRawDeerCount() + { + int _deerCount = 0; + for (int unitID = 1; unitID < 2500; ++unitID) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_ANTELOPESHDEER) { + _deerCount = _deerCount + 1; + } + } + return _deerCount; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getRemainingRequiredEngineers.cpp b/src/OpenSHC/Map/Units/UnitsState/getRemainingRequiredEngineers.cpp new file mode 100644 index 000000000..320041008 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getRemainingRequiredEngineers.cpp @@ -0,0 +1,52 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005334A0 + int UnitsState::getRemainingRequiredEngineers(int unitID) + { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) { + return 3 - this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300; + } + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_S_CATAPULT) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_TOWER) { + return 4 + - this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + return 4 + - this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_SHIELD) { + return 1 + - this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300; + } + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_S_MANGONEL) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_BALLISTA) { + return 2 + - this->units[unitID] + .digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300; + } + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_S_FBALLISTA) { + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_S_SIEGETENT) { + return 0; + } + if ((this->units[unitID].fixedRng & 2) != 0) { + return 3 + - this->units[unitID] + .digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300; + } + } + } + } + return 2 - this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getSelectedEngineerCarryingResource.cpp b/src/OpenSHC/Map/Units/UnitsState/getSelectedEngineerCarryingResource.cpp new file mode 100644 index 000000000..4401ef9c6 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getSelectedEngineerCarryingResource.cpp @@ -0,0 +1,50 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535680 + uint UnitsState::getSelectedEngineerCarryingResource() + { + /* Does not dirty EDX. -TheRedDaemon */ + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::selectionContainsEngineersOnly, this)() + == FALSE) { + return 0; + } + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return 0; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_E_ENGINEER + && this->units[DAT_CurrentUnitSlotID::instance].resourceToDeposit != 0) { + return DAT_CurrentUnitSlotID::instance; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getSelectedLordIDIfOwnedByCurrentPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/getSelectedLordIDIfOwnedByCurrentPlayer.cpp new file mode 100644 index 000000000..9db6c3340 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getSelectedLordIDIfOwnedByCurrentPlayer.cpp @@ -0,0 +1,42 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005359C0 + uint UnitsState::getSelectedLordIDIfOwnedByCurrentPlayer() + { + int _currentPlayerSlotID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner != _currentPlayerSlotID) { + return 0; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_LORD) { + return DAT_CurrentUnitSlotID::instance; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getTunnelerIDOnlyIfFirstSelected.cpp b/src/OpenSHC/Map/Units/UnitsState/getTunnelerIDOnlyIfFirstSelected.cpp new file mode 100644 index 000000000..8a16c824a --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getTunnelerIDOnlyIfFirstSelected.cpp @@ -0,0 +1,42 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536530 + uint UnitsState::getTunnelerIDOnlyIfFirstSelected() + { + int _currentPlayerSlotID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner != _currentPlayerSlotID) { + return 0; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_TUNNELER) { + return DAT_CurrentUnitSlotID::instance; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getUnitInHitBox.cpp b/src/OpenSHC/Map/Units/UnitsState/getUnitInHitBox.cpp new file mode 100644 index 000000000..d31a3fe99 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getUnitInHitBox.cpp @@ -0,0 +1,182 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_MinimapViewState.hpp" +#include "OpenSHC/Globals/DAT_MouseState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053D9C0 + uint UnitsState::getUnitInHitBox(undefined4 param_1) + { + int _hitboxXStart; + int _hitboxXEnd; + if ((int)DAT_MouseState::instance.hitboxXStart > (int)DAT_MouseState::instance.hitboxXEnd) { + _hitboxXStart = DAT_MouseState::instance.hitboxXEnd; + _hitboxXEnd = DAT_MouseState::instance.hitboxXStart; + } else { + _hitboxXStart = DAT_MouseState::instance.hitboxXStart; + _hitboxXEnd = DAT_MouseState::instance.hitboxXEnd; + } + int _hitboxYStart; + int _hitboxYEnd; + if ((int)DAT_MouseState::instance.hitboxYStart > (int)DAT_MouseState::instance.hitboxYEnd) { + _hitboxYStart = DAT_MouseState::instance.hitboxYEnd; + _hitboxYEnd = DAT_MouseState::instance.hitboxYStart; + } else { + _hitboxYStart = DAT_MouseState::instance.hitboxYStart; + _hitboxYEnd = DAT_MouseState::instance.hitboxYEnd; + } + int _currentPlayerSlotID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unknownTestAgainst0_2 != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_JESTER_ROAM_TO) { + continue; + } + if (DAT_MinimapViewState::instance.field15_0x3c == 0) { + if (this->units[DAT_CurrentUnitSlotID::instance].drawX == 0 + && this->units[DAT_CurrentUnitSlotID::instance].drawY == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].drawX + + this->units[DAT_CurrentUnitSlotID::instance].drawXOffset + >= _hitboxXEnd) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].drawY + + this->units[DAT_CurrentUnitSlotID::instance].someDrawYOffset + >= _hitboxYEnd) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].spriteWidthUnk + + this->units[DAT_CurrentUnitSlotID::instance].drawX + + this->units[DAT_CurrentUnitSlotID::instance].drawXOffset + < _hitboxXStart) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].spriteHeightUnk + + this->units[DAT_CurrentUnitSlotID::instance].drawY + + this->units[DAT_CurrentUnitSlotID::instance].someDrawYOffset + < _hitboxYStart) { + continue; + } + } else { + int _tileDistanceX = DAT_ViewportRenderState::instance.viewportState.mouseTileX + - this->units[DAT_CurrentUnitSlotID::instance].x; + if (_tileDistanceX < 0) { + _tileDistanceX = -_tileDistanceX; + } + if (_tileDistanceX > 1) { + continue; + } + int _tileDistanceY = DAT_ViewportRenderState::instance.viewportState.mouseTileY + - this->units[DAT_CurrentUnitSlotID::instance].y; + if (_tileDistanceY < 0) { + _tileDistanceY = -_tileDistanceY; + } + if (_tileDistanceY > 1) { + continue; + } + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_TOWER + && this->units[DAT_CurrentUnitSlotID::instance].state.generic + == (OpenSHC::Map::Units::States::US_STAND_UPUnk | OpenSHC::Map::Units::States::US_IDLEUnk)) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_TUNNELER + && (this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk + || this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_STAND_UPUnk)) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_CAMELSHBEAR) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_ANTELOPESHDEER + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::selectionHasNoRangedUnits, this)() + != 0) { + continue; + } + switch (param_1) { + case 0: + return DAT_CurrentUnitSlotID::instance; + case 1: + if (DAT_GameState::instance.mapAndTime + .playerTeams[this->units[DAT_CurrentUnitSlotID::instance].owner] + != DAT_GameState::instance.mapAndTime.playerTeams[_currentPlayerSlotID]) { + return DAT_CurrentUnitSlotID::instance; + } + break; + case 2: + if (this->units[DAT_CurrentUnitSlotID::instance].owner == _currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_TREBUCHET + || this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_BATTERINGRAM + || this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_TOWER + || this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_MANGONEL + || this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_BALLISTA + || this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_FBALLISTA + || this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_S_SHIELD) { + return DAT_CurrentUnitSlotID::instance; + } + } + break; + case 3: + if (this->units[DAT_CurrentUnitSlotID::instance].owner == _currentPlayerSlotID) { + return DAT_CurrentUnitSlotID::instance; + } + break; + case 4: + if (this->units[DAT_CurrentUnitSlotID::instance].owner != 0 + && this->units[DAT_CurrentUnitSlotID::instance].isSelectable_OR_matchTime != 0) { + return DAT_CurrentUnitSlotID::instance; + } + break; + case 5: + if (this->units[DAT_CurrentUnitSlotID::instance].owner == _currentPlayerSlotID + && this->units[DAT_CurrentUnitSlotID::instance].isSelectable_OR_matchTime != 0) { + return DAT_CurrentUnitSlotID::instance; + } + break; + case 6: + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_E_LADDER + && this->units[DAT_CurrentUnitSlotID::instance].owner == _currentPlayerSlotID) { + return DAT_CurrentUnitSlotID::instance; + } + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getUnitStateTextParameterAndResourceType.cpp b/src/OpenSHC/Map/Units/UnitsState/getUnitStateTextParameterAndResourceType.cpp new file mode 100644 index 000000000..9d2d2554d --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getUnitStateTextParameterAndResourceType.cpp @@ -0,0 +1,916 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Units.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::Resources::ResourceType; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537F60 + int UnitsState::getUnitStateTextParameterAndResourceType(int unitIndex, ResourceType* pResourceType) + + { + int _state = (short)this->units[unitIndex].state.generic; + *pResourceType = (ResourceType)0; + if (this->units[unitIndex].dying != 0) { + /* + "Dying" + */ + + return 0xc; + } + if (_state == 0x79 || MACRO_CALL(OpenSHC::Map::Units_Func::CheckUnitProductionPaused)(unitIndex) != FALSE) { + /* + This is an optimized % 4, producing -3 to 3 + */ + + uint _rng_0x79 = (int)this->units[unitIndex].fixedRng % 4; + /* + "Wandering around + Eating fire + (go to goodthing) + Having a rest + Enjoying a break + Taking some time off + Wandering randomly" + */ + + return (int)(_rng_0x79 + 0x5f); + } + if (_state == 0x6a) { + /* + "Fighting" + */ + + return 0x73; + } + switch (this->units[unitIndex].unitType) { + case OpenSHC::Map::Units::UT_PEASANT: + if (_state == 5) { + /* + "Swearing loyalty" + */ + + return 0x26; + } + if (_state == 8) { + /* + "Listening + Waiting for job + Hanging around + Waiting + Talking + Making a speech + Telling a joke + Recounting a story" + */ + + /* + Waiting at campfire + */ + + switch (this->units[unitIndex].substate) { + case 0x6a: + return 0x1e; + case 0x6b: + return 0x1f; + case 0x6e: + return 0x20; + case 0x6f: + return 0x21; + case 0x72: + return 0x22; + case 0x73: + return 0x23; + case 0x74: + return 0x24; + case 0x75: + return 0x25; + } + } + /* + "Waiting for job" + */ + + return 0x1d; + case OpenSHC::Map::Units::UT_BURNINGMAN: + /* + "Burning" + */ + + return 3; + case OpenSHC::Map::Units::UT_WOODCUTTER: + *pResourceType = OpenSHC::Game::Resources::RT_WOOD; + /* + 0x1: Waiting + 0x6b: Going to chop wood + 0x6c: Felling a tree + 0x6d: Chopping a tree + 0x6e: Returning with log + 0x7: Working + 0x7: Working + 0x2: Awaiting store space + 0xa: Taking goods to store + 0x5: Going to workplace + 0x4: Resting + 0x0: (Unit actions) - + 0x8: Attacking + */ + + switch (_state) { + case 0: + return 1; + case 1: + /* + "Going to chop wood" + */ + + return 0x6b; + case 2: + /* + "Felling a tree" + */ + + return 0x6c; + case 3: + /* + "Chopping a tree" + */ + + return 0x6d; + case 4: + /* + "Returning with log" + */ + + return 0x6e; + case 5: + case 6: + return 7; + case 7: + return 2; + case 8: + return 10; + case 9: + return 5; + case 10: + return 4; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_FLETCHER: + *pResourceType = OpenSHC::Game::Resources::RT_WOOD; + switch (_state) { + case 0: + return 1; + case 1: + return 9; + case 2: + return 6; + case 3: + return 5; + case 4: + case 5: + return 7; + case 6: + return 2; + case 7: + *pResourceType = OpenSHC::Game::Resources::RT_BOW; + return 10; + case 8: + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getStorageBuildingForResourceTypeAndAmount, + DAT_BuildingsState::ptr)(OpenSHC::Game::Resources::RT_WOOD, 1, this->units[unitIndex].owner) + != 0) { + return 4; + } + return 1; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_TUNNELER: + switch (_state) { + case 0: + case 1: + case 4: + case 5: + case 6: + return 1; + case 2: + case 3: + case 8: + case 9: + return 7; + case 7: + return 0xb; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_HUNTER: + *pResourceType = OpenSHC::Game::Resources::RT_MEAT; + /* + 0x1: Waiting + 0x71: Hunting + 0x72: Returning with kill + 0x7: Working + 0x2: Awaiting store space + 0xa: Taking goods to store + 0x5: Going to workplace + 0x4: Resting + 0x70: Stalking prey + 0x73: Fighting + 0x71: Hunting + 0x73: Fighting + 0x0: (Unit actions) - + 0x8: Attacking + */ + + switch (_state) { + case 0: + case 8: + return 1; + case 1: + case 0xb: + return 0x71; + case 2: + return 0x72; + case 3: + return 7; + case 4: + return 2; + case 5: + return 10; + case 6: + return 5; + case 7: + return 4; + case 9: + /* + 115 or 112 + */ + + return this->units[this->units[unitIndex].shootTargetedUnit].isStalked != 0 ? 0x70 : 0x73; + case 10: + return (uint)(this->units[this->units[unitIndex].shootTargetedUnit].isStalked == 0) * 2 + 0x71; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_QUARRYMASON: + switch (_state) { + case 0: + return 1; + default: + return 7; + case 2: + return 5; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_QUARRYWORKER: + *pResourceType = OpenSHC::Game::Resources::RT_STONE; + switch (_state) { + default: + return 7; + case 1: + case 6: + return 1; + case 2: + return 2; + case 3: + return 10; + case 4: + return 5; + case 5: + return 4; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_QUARRYOX: + *pResourceType = OpenSHC::Game::Resources::RT_STONE; + switch (_state) { + case 1: + return 10; + case 2: + return 1; + case 3: + return 5; + case 4: + return 0x28; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_PITCHMAN: + *pResourceType = OpenSHC::Game::Resources::RT_PARTIALPITCH; + switch (_state) { + case 0: + return 1; + case 1: + return 7; + case 2: + return 2; + case 3: + return 10; + case 4: + return 5; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_WHEATFARMER: + *pResourceType = OpenSHC::Game::Resources::RT_WHEAT; + switch (_state) { + case 0: + case 1: + return 1; + case 2: + return 5; + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + return 7; + case 9: + return 2; + case 10: + return 10; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_HOPSFARMER: + *pResourceType = OpenSHC::Game::Resources::RT_HOPS; + switch (_state) { + case 0: + case 1: + return 1; + case 2: + return 5; + case 3: + case 4: + case 5: + case 6: + return 7; + case 7: + return 2; + case 8: + return 10; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_APPLEFARMER: + *pResourceType = OpenSHC::Game::Resources::RT_APPLE; + switch (_state) { + case 0: + case 1: + return 1; + case 2: + case 3: + case 4: + case 8: + return 7; + case 5: + return 5; + case 6: + return 2; + case 7: + return 10; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_DAIRYFARMER: + *pResourceType = OpenSHC::Game::Resources::RT_CHEESE; + switch (_state) { + case 0: + case 1: + return 1; + case 2: + return 5; + case 3: + return 7; + case 4: + return 2; + case 5: + return 10; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_MILLER: + switch (_state) { + case 0: + case 1: + case 6: + return 1; + case 2: + return 5; + case 3: + return 9; + case 4: + *pResourceType = OpenSHC::Game::Resources::RT_WHEAT; + return 6; + case 5: + return 7; + case 7: + return 2; + case 8: + *pResourceType = OpenSHC::Game::Resources::RT_FLOUR; + return 10; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_BAKER: + *pResourceType = OpenSHC::Game::Resources::RT_BREAD; + switch (_state) { + case 0: + case 1: + return 1; + case 2: + return 5; + default: + return 7; + case 5: + return 2; + case 6: + return 10; + case 7: + *pResourceType = OpenSHC::Game::Resources::RT_FLOUR; + return 9; + case 8: + *pResourceType = OpenSHC::Game::Resources::RT_FLOUR; + return 6; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_BREWER: + switch (_state) { + case 0: + case 1: + return 1; + case 2: + *pResourceType = OpenSHC::Game::Resources::RT_HOPS; + return 9; + case 3: + *pResourceType = OpenSHC::Game::Resources::RT_HOPS; + return 6; + case 4: + return 5; + default: + return 7; + case 7: + return 2; + case 8: + *pResourceType = OpenSHC::Game::Resources::RT_ALE; + return 10; + case 9: + return 4; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_POLETURNER: + switch (_state) { + case 0: + case 1: + return 1; + case 2: + *pResourceType = OpenSHC::Game::Resources::RT_WOOD; + return 9; + case 3: + *pResourceType = OpenSHC::Game::Resources::RT_WOOD; + return 6; + case 4: + return 5; + case 5: + case 6: + return 7; + case 7: + return 2; + case 8: + *pResourceType = (ResourceType)(short)DAT_BuildingsState::instance + .buildings[this->units[unitIndex].workplaceBuildingID_1] + .producedItemTypeNext; + return 10; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_SMITH: + switch (_state) { + case 0: + case 1: + return 1; + case 2: + *pResourceType = OpenSHC::Game::Resources::RT_IRON; + return 9; + case 3: + *pResourceType = OpenSHC::Game::Resources::RT_IRON; + return 6; + case 4: + return 5; + case 5: + case 6: + return 7; + case 7: + return 2; + case 8: + *pResourceType = (ResourceType)(short)DAT_BuildingsState::instance + .buildings[this->units[unitIndex].workplaceBuildingID_1] + .producedItemTypeNext; + return 10; + case 9: + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getStorageBuildingForResourceTypeAndAmount, + DAT_BuildingsState::ptr)(OpenSHC::Game::Resources::RT_IRON, 1, this->units[unitIndex].owner) + != 0) { + return 4; + } + return 1; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_ARMORER: + switch (_state) { + case 0: + case 1: + return 1; + case 2: + *pResourceType = OpenSHC::Game::Resources::RT_IRON; + return 9; + case 3: + *pResourceType = OpenSHC::Game::Resources::RT_IRON; + return 6; + case 4: + return 5; + case 5: + case 6: + return 7; + case 7: + return 2; + case 8: + *pResourceType = OpenSHC::Game::Resources::RT_IRONARMOR; + return 10; + case 9: + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getStorageBuildingForResourceTypeAndAmount, + DAT_BuildingsState::ptr)(OpenSHC::Game::Resources::RT_IRON, 1, this->units[unitIndex].owner) + != 0) { + return 4; + } + return 1; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_TANNER: + switch (_state) { + case 0: + case 1: + return 1; + case 2: + return 0x68; + case 3: + return 0x69; + case 4: + return 5; + default: + return 7; + case 7: + return 2; + case 8: + *pResourceType = OpenSHC::Game::Resources::RT_LEATHERARMOR; + return 10; + case 0x6a: + return 8; + } + default: + return 0; + case OpenSHC::Map::Units::UT_MINER: + if (_state == 1) { + return 7; + } + case OpenSHC::Map::Units::UT_TRANSPORTMINER: + switch (_state) { + case 0: + case 1: + case 5: + return 1; + case 2: + return 5; + case 3: + return 2; + case 4: + return 10; + default: + return 7; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_PRIEST: + switch (_state) { + case 0: + return 1; + case 1: + return 5; + case 2: + case 4: + case 6: + case 7: + case 8: + case 10: + case 0xb: + return 7; + case 3: + return 0x2b; + case 5: + return 0x2a; + case 9: + return this->units[unitIndex].substate + 0x18; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_HEALER: + switch (_state) { + case 0: + return 1; + case 1: + return 5; + default: + return 7; + case 3: + return 0x2d; + case 4: + return 0x2e; + case 5: + return 0x2f; + case 6: + return 0x30; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_DRUNK: + return DAT_GameState::instance.mapAndTime.drunkenManStatus + 0x75; + case OpenSHC::Map::Units::UT_INNKEEPER: + *pResourceType = OpenSHC::Game::Resources::RT_ALE; + switch (_state) { + case 0: + case 1: + return 1; + case 2: + return 9; + case 3: + return 6; + case 4: + return 5; + case 5: + return 7; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_TRADER: + switch (_state) { + case 0: + return 1; + case 1: + return 0x37; + case 2: + return 7; + case 3: + return 0x38; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_TRADERHORSE: + if (_state == 1) { + return 0x37; + } + if (_state != 3) { + if (_state == 0x6a) { + return 8; + } + return 1; + } + return 0x38; + case OpenSHC::Map::Units::UT_COW: + switch (_state) { + case 0: + if (this->units[unitIndex].substate == 0x66 || this->units[unitIndex].substate == 0x67) { + return 0x3c; + } + default: + return 0x3d; + case 2: + case 4: + case 5: + return 0x3a; + case 3: + return 0x3b; + case 6: + case 0x6e: + return 0xc; + } + case OpenSHC::Map::Units::UT_HUNTERDOG: + switch (_state) { + case 3: + return 0x3f; + case 4: + case 5: + return 0x40; + case 7: + case 8: + return 0x41; + case 9: + return 0x42; + case 0x78: + return 0x43; + } + return 1; + case OpenSHC::Map::Units::UT_FIREFIGHTER: + switch (_state) { + case 0: + case 2: + return 4; + case 1: + return 0x97; + case 3: + return 0x96; + case 4: + return 0x98; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_GHOST: + return (DAT_GameState::instance.mapAndTime.drunkenManStatus & 3U) + 0x99; + case OpenSHC::Map::Units::UT_LADY: + switch (_state) { + case 1: + case 9: + return 0x12; + case 3: + return 0x13; + case 4: + case 8: + return 0x14; + case 5: + return 0x15; + case 6: + return this->units[unitIndex].substate + 0xe; + case 7: + return 0x16; + case ((UnitType)10): + return 0; + case 0x6a: + return 8; + } + return 4; + case OpenSHC::Map::Units::UT_JESTER: + switch (_state) { + case 1: + return 0x45; + default: + return 0x49; + case 3: + case 4: + return 0x46; + case 5: + return 0x47; + case 7: + case 8: + return 0x48; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_CHICKEN: + if (_state == 2) { + return 0x4c; + } + return 0x4b; + case OpenSHC::Map::Units::UT_MOTHER: + switch (_state) { + case 3: + case 5: + case 6: + case 7: + return 0x4f; + case 4: + return 0x50; + default: + return 0x51; + case 0x65: + if (DAT_BuildingsState::instance.buildings[this->units[unitIndex].targetID_OR_targetBuildingID] + .buildingType + != OpenSHC::Map::Buildings::BT_CHAPEL + && DAT_BuildingsState::instance.buildings[this->units[unitIndex].targetID_OR_targetBuildingID] + .buildingType + != OpenSHC::Map::Buildings::BT_CHURCH + && DAT_BuildingsState::instance.buildings[this->units[unitIndex].targetID_OR_targetBuildingID] + .buildingType + != OpenSHC::Map::Buildings::BT_CATHEDRAL) { + return 0x4f; + } + return 0x4e; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_CHILD: + switch (_state) { + case 0: + case 1: + return 1; + default: + return 0x57; + case 3: + return 0x53; + case 4: + case 5: + return 0x54; + case 6: + case 9: + return 0x55; + case 10: + case 0xb: + case 0xc: + case 0xd: + return 0x56; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_JUGGLER: + switch (_state) { + case 0: + return 1; + case 1: + return 0x59; + case 2: + case 3: + case 4: + case 5: + case 6: + return 0x5a; + default: + return 0; + case 0x6a: + return 8; + } + case OpenSHC::Map::Units::UT_FIREEATER: + switch (_state) { + case 0: + return 1; + case 1: + return 0x5c; + case 2: + case 3: + case 4: + return 0x5d; + default: + return 0; + case 0x6a: + return 8; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getUnitTypeOfFirstSelectedUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/getUnitTypeOfFirstSelectedUnit.cpp new file mode 100644 index 000000000..2ab5e6f23 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getUnitTypeOfFirstSelectedUnit.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005361F0 + UnitType UnitsState::getUnitTypeOfFirstSelectedUnit() + { + int _currentPlayerSlotID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner != _currentPlayerSlotID) { + return (UnitType)-1; + } + return (UnitType)(short)this->units[DAT_CurrentUnitSlotID::instance].unitType; + } + return (UnitType)0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/getWorkerBlockingStateIfStuck.cpp b/src/OpenSHC/Map/Units/UnitsState/getWorkerBlockingStateIfStuck.cpp new file mode 100644 index 000000000..0bb06978a --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/getWorkerBlockingStateIfStuck.cpp @@ -0,0 +1,207 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::Resources::ResourceType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053A150 + int UnitsState::getWorkerBlockingStateIfStuck(int unitID) + { + int _state = this->units[unitID].state.generic; + if (this->units[unitID].dying != 0) { + return 0; + } + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_WOODCUTTER: + if (_state == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk) { + return 0x2f; + } + if (_state == (UnitState)10) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::findTree, DAT_LandscapeState::ptr)( + this->units[unitID].owner, this->units[unitID].x, this->units[unitID].y) + != 0) { + return 0; + } + return 0x32; + } + break; + case OpenSHC::Map::Units::UT_FLETCHER: + if (_state == OpenSHC::Map::Units::States::US_FIRE_WEAPONUnk) { + return 0x31; + } + if (_state != OpenSHC::Map::Units::States::US_STAND_UPUnk) { + return 0; + } + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getStorageBuildingForResourceTypeAndAmount, + DAT_BuildingsState::ptr)(OpenSHC::Game::Resources::RT_WOOD, 1, this->units[unitID].owner) + != 0) { + return 0; + } + return 0x33; + case OpenSHC::Map::Units::UT_HUNTER: + if (_state == OpenSHC::Map::Units::States::US_RELOAD_WEAPONUnk) { + return 0x30; + } + if (_state == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::findNearestShootableDeer, this)(unitID) + != 0) { + return 0; + } + return 0x34; + } + break; + case OpenSHC::Map::Units::UT_QUARRYWORKER: + case OpenSHC::Map::Units::UT_PITCHMAN: + if (_state == (UnitState)2) { + return 0x2f; + } + break; + case OpenSHC::Map::Units::UT_WHEATFARMER: + if (_state + == (OpenSHC::Map::Units::States::US_STAND_UPUnk | OpenSHC::Map::Units::States::US_IDLEUnk)) { + return 0x2f; + } + break; + case OpenSHC::Map::Units::UT_HOPSFARMER: + if (_state == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk) { + return 0x2f; + } + break; + case OpenSHC::Map::Units::UT_APPLEFARMER: + if (_state == OpenSHC::Map::Units::States::US_FIRE_WEAPONUnk) { + return 0x30; + } + break; + case OpenSHC::Map::Units::UT_DAIRYFARMER: + if (_state == OpenSHC::Map::Units::States::US_RELOAD_WEAPONUnk) { + return 0x30; + } + break; + case OpenSHC::Map::Units::UT_MILLER: + if (_state == OpenSHC::Map::Units::States::US_IDLEUnk) { + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getStorageBuildingForResourceTypeAndAmount, + DAT_BuildingsState::ptr)(OpenSHC::Game::Resources::RT_WHEAT, 1, this->units[unitID].owner) + != 0) { + return 0; + } + return 0x35; + } + if (_state == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk) { + return 0x2f; + } + break; + case OpenSHC::Map::Units::UT_BAKER: + if (_state < 0) { + break; + } + if (_state < 2) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingResourceAmountByUid, + DAT_BuildingsState::ptr)(this->units[DAT_CurrentUnitSlotID::instance].workplaceBuildingID_1, + DAT_BuildingsState::instance + .buildings[this->units[DAT_CurrentUnitSlotID::instance].workplaceBuildingID_1] + .uid, + OpenSHC::Game::Resources::RT_FLOUR) + != 0) { + return 0; + } + return 0x36; + } + if (_state == OpenSHC::Map::Units::States::US_AIM_WEAPONUnk) { + return 0x30; + } + break; + case OpenSHC::Map::Units::UT_BREWER: + if (_state == OpenSHC::Map::Units::States::US_IDLEUnk) { + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getStorageBuildingForResourceTypeAndAmount, + DAT_BuildingsState::ptr)( + OpenSHC::Game::Resources::RT_HOPS, 1, this->units[DAT_CurrentUnitSlotID::instance].owner) + != 0) { + return 0; + } + return 0x37; + } + if (_state == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk) { + return 0x2f; + } + break; + case OpenSHC::Map::Units::UT_POLETURNER: + if (_state == OpenSHC::Map::Units::States::US_IDLEUnk) { + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getStorageBuildingForResourceTypeAndAmount, + DAT_BuildingsState::ptr)(OpenSHC::Game::Resources::RT_WOOD, 1, this->units[unitID].owner) + != 0) { + return 0; + } + return 0x33; + } + if (_state == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk) { + return 0x31; + } + break; + case OpenSHC::Map::Units::UT_SMITH: + case OpenSHC::Map::Units::UT_ARMORER: + if (_state != OpenSHC::Map::Units::States::US_IDLEUnk) { + if (_state == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk) { + return 0x31; + } + if (_state + != (OpenSHC::Map::Units::States::US_STAND_UPUnk | OpenSHC::Map::Units::States::US_IDLEUnk)) { + return 0; + } + } + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getStorageBuildingForResourceTypeAndAmount, + DAT_BuildingsState::ptr)(OpenSHC::Game::Resources::RT_IRON, 1, this->units[unitID].owner) + != 0) { + return 0; + } + return 0x38; + case OpenSHC::Map::Units::UT_TANNER: + if (_state == OpenSHC::Map::Units::States::US_IDLEUnk) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::findNearestIdleCowForPlayer, this)( + this->units[unitID].owner, this->units[unitID].x, this->units[unitID].y) + != 0) { + return 0; + } + return 0x39; + } + if (_state == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk) { + return 0x31; + } + break; + case OpenSHC::Map::Units::UT_TRANSPORTMINER: + if (_state == (UnitState)3) { + return 0x2f; + } + break; + case OpenSHC::Map::Units::UT_INNKEEPER: + if (_state == OpenSHC::Map::Units::States::US_IDLEUnk) { + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getStorageBuildingForResourceTypeAndAmount, + DAT_BuildingsState::ptr)(OpenSHC::Game::Resources::RT_ALE, 1, this->units[unitID].owner) + != 0) { + return 0; + } + return 0x3a; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/giveMoveCommand.cpp b/src/OpenSHC/Map/Units/UnitsState/giveMoveCommand.cpp new file mode 100644 index 000000000..6e98851cb --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/giveMoveCommand.cpp @@ -0,0 +1,123 @@ +#include "OpenSHC/Audio/MSS/SoundSystem.func.hpp" +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/DAT_SoundSystemState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536E30 + void UnitsState::giveMoveCommand(int tribeID, int x, int y, int patrol, int matchUnitSpeeds) + { + DAT_GameSynchronyState::instance.DAT_GameCommandParam1 = x; + DAT_GameSynchronyState::instance.DAT_GameCommandParam2 = y; + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = tribeID; + DAT_GameSynchronyState::instance.DAT_GameCommandParam3 = patrol; + DAT_GameSynchronyState::instance.DAT_GameCommandParam4 = matchUnitSpeeds; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + OpenSHC::Commands::GCT_UNITS_MOVE); + UnitType _mostFrequentUnitType + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::getMajoritySelectedUnitType, + DAT_TribesState::ptr)(tribeID, (int*)0x0); + dword _areaAtDestination + = (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_ViewportRenderState::instance.viewportState.field24_0x60]; + uint _logicAtDestination + = DAT_TileMapState::instance.LogicLayer[DAT_ViewportRenderState::instance.viewportState.field24_0x60]; + int _combatUnitID + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::selectionContainsCombatUnit, this)(1); + dword _areaAtUnit = (short)DAT_TileMapState::instance.PathConnectionLayer[this->units[_combatUnitID].tile]; + if ((DAT_TileMapState::instance.LogicLayer[this->units[_combatUnitID].tile] & 0x40000000U) != 0) { + return; + } + bool _canReachDestination + = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(DAT_GameSynchronyState::instance.currentPlayerSlotID, + _areaAtDestination, _areaAtUnit, + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::canAUnitClimb, this)()) + != 0; + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::selectionHasMobileAssaultUnits, this)() != 0) { + if ((_logicAtDestination & 0x10000100) != 0 + || MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::calculatePathKeepAndWallsGatesNotAllowed, + DAT_PathFindingState::ptr)(this->units[_combatUnitID].x, this->units[_combatUnitID].y, + DAT_ViewportRenderState::instance.viewportState.field24_0x60 + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent + [DAT_ViewportRenderState::instance.viewportState.field24_0x60]] + .addXgetTile, + DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent + [DAT_ViewportRenderState::instance.viewportState.field24_0x60], + 100000) + == 0) { + _canReachDestination = false; + } + } + if (matchUnitSpeeds == 0 + && (_mostFrequentUnitType == OpenSHC::Map::Units::UT_E_ARCHER + || _mostFrequentUnitType == OpenSHC::Map::Units::UT_E_XBOW + || _mostFrequentUnitType == OpenSHC::Map::Units::UT_S_CATAPULT)) { + return; + } + if (DAT_TribesState::instance.tribes[tribeID].owner + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return; + } + if (_mostFrequentUnitType == OpenSHC::Map::Units::UT_S_MANGONEL) { + return; + } + if (_mostFrequentUnitType == OpenSHC::Map::Units::UT_S_BALLISTA) { + return; + } + if (_mostFrequentUnitType == OpenSHC::Map::Units::UT_S_TREBUCHET) { + return; + } + if (!_canReachDestination) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeech, DAT_SFXState::ptr)( + _mostFrequentUnitType, 9); + return; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::playUnitSelectionSound, DAT_TribesState::ptr)( + tribeID); + if (MACRO_CALL_MEMBER( + OpenSHC::Audio::MSS::SoundSystem_Func::shouldSoundXNotBePlaying, DAT_SoundSystemState::ptr)() + != FALSE) { + return; + } + if (this->units[_combatUnitID].unitType == OpenSHC::Map::Units::UT_E_ENGINEER + && this->units[_combatUnitID].resourceToDeposit != 0) { + return; + } + short _leaderUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + if ((this->units[_leaderUnitID].x - x) + 0x48U > 0x90 + || (this->units[_leaderUnitID].y - y) + 0x48U > 0x90) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeech, DAT_SFXState::ptr)( + _mostFrequentUnitType, 10); + return; + } + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeech, DAT_SFXState::ptr)( + _mostFrequentUnitType, 6); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/giveTribeMoveInstructionHumans.cpp b/src/OpenSHC/Map/Units/UnitsState/giveTribeMoveInstructionHumans.cpp new file mode 100644 index 000000000..4195e5725 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/giveTribeMoveInstructionHumans.cpp @@ -0,0 +1,25 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00537070 + void UnitsState::giveTribeMoveInstructionHumans( + int tribeID, uint x, uint y, int rallyBool, MatchSpeedInstructionEnum speedMatching) + { + DAT_TribesState::instance.tribes[tribeID].freeUnitSpeeds = 0; + if ((char)speedMatching < 0) { + speedMatching = (Instructions::MatchSpeedInstructionEnum)(speedMatching & 0xffffff7f); + DAT_TribesState::instance.tribes[tribeID].freeUnitSpeeds = 1; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, x, y, rallyBool, 1, (UnitMatchSpeedEnum)speedMatching); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/handleUnitMovementWhenTargetingBuildings.cpp b/src/OpenSHC/Map/Units/UnitsState/handleUnitMovementWhenTargetingBuildings.cpp new file mode 100644 index 000000000..3df46c6c6 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/handleUnitMovementWhenTargetingBuildings.cpp @@ -0,0 +1,59 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0054C4F0 + int UnitsState::handleUnitMovementWhenTargetingBuildings(int unitID) + { + if (this->units[unitID].targetedBuildingTile == 0) { + return 0; + } + int _directionStep = 1; + if ((DAT_TileMapState::instance.LogicLayer[this->units[unitID].targetedBuildingTile] & 0x100U) != 0) { + _directionStep = 2; + } + uint _buildingTile = 0; + int _directionOfBuilding = 0; + for (; _directionOfBuilding <= 7; _directionOfBuilding += _directionStep) { + _buildingTile + = DAT_TileMapState::instance.directionTranslationMatrix[this->units[unitID].y][_directionOfBuilding] + + this->units[unitID].tile; + if (_buildingTile == this->units[unitID].targetedBuildingTile) { + break; + } + } + if (_directionOfBuilding > 7) { + return 0; + } + uint _isDefensiveStructure = DAT_TileMapState::instance.LogicLayer[_buildingTile] & 0x100; + if (_isDefensiveStructure == 0 && (DAT_TileMapState::instance.LogicLayer[_buildingTile] & 0x40000000U) == 0 + && DAT_TileMapState::instance.BuildingLayer[_buildingTile] == 0) { + return -1; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::ifAnyUnitOnSameTileIsLadder, this)( + this->units[unitID].tile) + == FALSE) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::makeUnitStopWalkingByClearingPathProgressState, this)(unitID); + if (this->units[unitID].movementRelated > 7) { + this->units[unitID].destinationX_2Unk = this->units[unitID].x; + this->units[unitID].destinationY_2Unk = this->units[unitID].y; + return 1; + } + } else if (_isDefensiveStructure != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationNearTargetedBuilding, this)( + unitID, 0); + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/harassBuildingsWithSiegeAI.cpp b/src/OpenSHC/Map/Units/UnitsState/harassBuildingsWithSiegeAI.cpp new file mode 100644 index 000000000..6f81d5961 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/harassBuildingsWithSiegeAI.cpp @@ -0,0 +1,191 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/Actions.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/Pathfinding/DestinationNeededEnum.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::Pathfinding::DestinationNeededEnum; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053D030 + undefined4 UnitsState::harassBuildingsWithSiegeAI(int unitID) + { + int _playerID = this->units[unitID].owner; + int _siegeKind = 0; + int _searchRange = 200; + int _isFireBallista = 0; + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_S_CATAPULT: + _siegeKind = 2; + _searchRange = 0x50; + if (this->units[unitID].stoneAmmunition < 1) { + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY + && MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, + DAT_GameSynchronyState::ptr)(_playerID) + != FALSE) { + MACRO_CALL(OpenSHC::Synchrony::Actions_Func::TryAcquireAmmunitionOrPlanToBuyStone)( + _playerID, unitID); + } + return 0; + } + break; + case OpenSHC::Map::Units::UT_S_TREBUCHET: + _siegeKind = 3; + if (this->units[unitID].stoneAmmunition < 1) { + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY + && MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, + DAT_GameSynchronyState::ptr)(_playerID) + != FALSE) { + MACRO_CALL(OpenSHC::Synchrony::Actions_Func::TryAcquireAmmunitionOrPlanToBuyStone)( + _playerID, unitID); + } + return 0; + } + break; + case OpenSHC::Map::Units::UT_S_MANGONEL: + case OpenSHC::Map::Units::UT_S_BALLISTA: + _siegeKind = 4; + break; + case OpenSHC::Map::Units::UT_S_FBALLISTA: + _siegeKind = 0x25; + _isFireBallista = 1; + } + uint _defaultHeightAtTarget = 0; + uint _heightAtTarget = 0; + if (this->units[unitID].field248_0x3bc > 0) { + _defaultHeightAtTarget + = DAT_TileMapState::instance.DefaultHeightLayer[this->units[unitID].field248_0x3bc]; + _heightAtTarget = DAT_TileMapState::instance.HeightLayer[this->units[unitID].field248_0x3bc]; + } + int _shootAtMicroX; + int _shootAtMicroY; + int _shootAtZ; + if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_ATTACK_BUILDING) { + if (DAT_BuildingsState::instance.buildings[this->units[unitID].targetID_OR_targetBuildingID].uid + != this->units[unitID] + .targetedUnitUIDUnk_OR_someAppearTileUnk_OR_buildingUID_OR_pitchDitchUID_OR_entityUID) { + this->units[unitID].targetingType = OpenSHC::Map::Units::UIT_NO_INSTRUCTION_OR_MOVEUnk; + return 0; + } + int _halfBuildingSize + = (DAT_BuildingsState::instance.buildings[this->units[unitID].targetID_OR_targetBuildingID] + .widthOrHeight + * 8) + / 2; + _shootAtMicroX = _halfBuildingSize + + (short)DAT_BuildingsState::instance.buildings[this->units[unitID].targetID_OR_targetBuildingID].x + * 8; + _shootAtMicroY = _halfBuildingSize + + (short)DAT_BuildingsState::instance.buildings[this->units[unitID].targetID_OR_targetBuildingID].y + * 8; + _shootAtZ = DAT_BuildingsState::instance.buildings[this->units[unitID].targetID_OR_targetBuildingID] + .terrainHeightUnk; + } else if (this->units[unitID].field248_0x3bc > 0 + && (DAT_TileMapState::instance.LogicLayer[this->units[unitID].field248_0x3bc] & 0x100U) != 0 + && (int)(_heightAtTarget - _defaultHeightAtTarget) >= 0x1f && _siegeKind != 0x25 + && DAT_GameState::instance.mapAndTime.playerTeams[_playerID] + != DAT_GameState::instance.mapAndTime + .playerTeams[(DAT_TileMapState::instance.WallOwnerLayer[this->units[unitID].field248_0x3bc] & 7) + + 1]) { + _shootAtZ = (int)(_heightAtTarget - _defaultHeightAtTarget) / 2 + _defaultHeightAtTarget; + _shootAtMicroX = (this->units[unitID].field248_0x3bc + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance + .tileTranslationMatrix_YComponent[this->units[unitID].field248_0x3bc]] + .addXgetTile) + * 8; + _shootAtMicroY = DAT_ViewportRenderState::instance + .tileTranslationMatrix_YComponent[this->units[unitID].field248_0x3bc] + * 8; + } else { + DAT_PathFindingState::instance.ALG_TargetTile = 0; + int _maxTargetDistance = 200; + if (this->units[unitID].aiUnitBehaviourType == 0x15 + || this->units[unitID].unknownSiegeTentRelated02 == 3) { + _maxTargetDistance = 0x14; + } + int _searchFlags; + if (_siegeKind == 0x25) { + _searchFlags = 0x34; + } else if (_siegeKind == 3) { + _searchFlags = 83; + } else { + _searchFlags = 73; + } + int _attackFacingDirection = this->units[unitID].attackFacingDirection; + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) { + _maxTargetDistance = *(int*)((int)DAT_TroopValueState::instance.attackInfo.scaleValuesArray + + _playerID * 0x177bc + -0x1c) + + 0xf; + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::findBestAttackTargetTileWithHeightAndOwner, + DAT_PathFindingState::ptr)(_searchFlags, this->units[unitID].x, this->units[unitID].y, + (uint)(ushort)this->units[unitID].facingDirection + _attackFacingDirection & 7, _searchRange, + _attackFacingDirection, this->units[unitID].siegeTargetPlayerID, _maxTargetDistance, + _isFireBallista); + if (DAT_PathFindingState::instance.ALG_TargetTile == 0) { + this->units[unitID].attackFacingDirection = this->units[unitID].attackFacingDirection + '\x01'; + if (this->units[unitID].attackFacingDirection > '\x0f' + && (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_FBALLISTA) + && (this->units[unitID].aiUnitBehaviourType == 0x15 + || DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY + || this->units[unitID].unknownSiegeTentRelated02 == 3)) { + this->units[unitID].state.generic + = (OpenSHC::Map::Units::States::US_STAND_UPUnk | OpenSHC::Map::Units::States::US_IDLEUnk); + this->units[unitID].destinationNeeded + = OpenSHC::Map::Units::Pathfinding::DNE_DESTINATION_NEEDED; + } + } else { + this->units[unitID].facingDirection + = this->units[unitID].facingDirection + (short)this->units[unitID].attackFacingDirection; + this->units[unitID].facingDirection = this->units[unitID].facingDirection & 7; + this->units[unitID].attackFacingDirection = '\0'; + this->units[unitID].shootTargetedUnit = 0; + this->units[unitID].facingDirectionMapOrientationCorrected + = this->units[unitID].facingDirection - (short)DAT_TileMapState::instance.mapOrientation; + if (this->units[unitID].facingDirectionMapOrientationCorrected < 0) { + this->units[unitID].facingDirectionMapOrientationCorrected + = this->units[unitID].facingDirectionMapOrientationCorrected + 8; + } + } + _shootAtMicroX = DAT_PathFindingState::instance.ALG_TargetX * 8; + _shootAtMicroY = DAT_PathFindingState::instance.ALG_TargetY * 8; + _shootAtZ + = DAT_TileMapState::instance.HeightLayer[DAT_PathFindingState::instance.ALG_TargetTile] - 0x2d; + this->units[unitID].field248_0x3bc = DAT_PathFindingState::instance.ALG_TargetTile; + if (DAT_PathFindingState::instance.ALG_TargetTile == 0) { + this->units[unitID].field248_0x3bc = -0x32; + return 0; + } + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setRandomShootLocation, this)( + unitID, _shootAtMicroX, _shootAtMicroY, _shootAtZ); + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/hasTunnelerNotFinishedDigging.cpp b/src/OpenSHC/Map/Units/UnitsState/hasTunnelerNotFinishedDigging.cpp new file mode 100644 index 000000000..c59ce47e4 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/hasTunnelerNotFinishedDigging.cpp @@ -0,0 +1,15 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x005339F0 + BOOLEnum UnitsState::hasTunnelerNotFinishedDigging(int unitID) + { + return (BOOLEnum)(this->units[unitID].tunnelerFinishedDigging == 0); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/hasUnitReachedDestination.cpp b/src/OpenSHC/Map/Units/UnitsState/hasUnitReachedDestination.cpp new file mode 100644 index 000000000..861e4fb3c --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/hasUnitReachedDestination.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x005339A0 + BOOLEnum UnitsState::hasUnitReachedDestination(int unitID) + { + if (this->units[unitID].tunnelerFinishedDigging != 0) { + return FALSE; + } + if (this->units[unitID].climbDataID != 0) { + if (this->units[unitID].destinationX_2Unk != this->units[unitID].x) { + return FALSE; + } + if (this->units[unitID].destinationY_2Unk != this->units[unitID].y) { + return FALSE; + } + } + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/ifAnyUnitOnSameTileIsLadder.cpp b/src/OpenSHC/Map/Units/UnitsState/ifAnyUnitOnSameTileIsLadder.cpp new file mode 100644 index 000000000..bad0f97d8 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/ifAnyUnitOnSameTileIsLadder.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F550 + BOOLEnum UnitsState::ifAnyUnitOnSameTileIsLadder(int tile) + { + for (int unitID = (short)DAT_TileMapState::instance.UnitLayer[tile]; unitID != 0; + unitID = (short)this->units[unitID].nextUnitOnTheSameTile) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_E_LADDER + && this->units[unitID].state.generic == (UnitState)3) { + return TRUE; + } + } + return FALSE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/ifAnyUnitOnSameTileIsLadderInRightDirection.cpp b/src/OpenSHC/Map/Units/UnitsState/ifAnyUnitOnSameTileIsLadderInRightDirection.cpp new file mode 100644 index 000000000..a43f693a3 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/ifAnyUnitOnSameTileIsLadderInRightDirection.cpp @@ -0,0 +1,30 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F5B0 + undefined4 UnitsState::ifAnyUnitOnSameTileIsLadderInRightDirection(int tile, int y) + { + for (int direction = 0; direction < 8; direction += 2) { + int _neighbourTile = DAT_TileMapState::instance.directionTranslationMatrix[y][direction] + tile; + if ((DAT_TileMapState::instance.LogicLayer[_neighbourTile] & 0x4a5015b1U) == 0 + && DAT_TileMapState::instance.UnitLayer[_neighbourTile] != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::ifAnyUnitOnSameTileIsLadder, this)( + _neighbourTile) + != FALSE) { + return 1; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/ifOnADefensiveStructureSetDestinationInDirectionOfTarget.cpp b/src/OpenSHC/Map/Units/UnitsState/ifOnADefensiveStructureSetDestinationInDirectionOfTarget.cpp new file mode 100644 index 000000000..6bfea2724 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/ifOnADefensiveStructureSetDestinationInDirectionOfTarget.cpp @@ -0,0 +1,78 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00540040 + BOOLEnum UnitsState::ifOnADefensiveStructureSetDestinationInDirectionOfTarget(int unitID) + { + int _buildingID = DAT_TileMapState::instance.BuildingLayer[this->units[unitID].tile]; + if (_buildingID == 0) { + return FALSE; + } + switch (DAT_BuildingsState::instance.buildings[_buildingID].buildingType) { + case OpenSHC::Map::Buildings::BT_MANORHOUSE: + case OpenSHC::Map::Buildings::BT_STONEKEEP: + case OpenSHC::Map::Buildings::BT_STRONGHOLD: + case OpenSHC::Map::Buildings::BT_KEEPFOUR: + case OpenSHC::Map::Buildings::BT_KEEPFIVE: + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: + case OpenSHC::Map::Buildings::BT_WOODGATE1: + case OpenSHC::Map::Buildings::BT_TOWER1: + case OpenSHC::Map::Buildings::BT_TOWER2: + case OpenSHC::Map::Buildings::BT_TOWER3: + case OpenSHC::Map::Buildings::BT_TOWER4: + case OpenSHC::Map::Buildings::BT_TOWER5: + break; + default: + return FALSE; + } + int _targetX; + int _targetY; + if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_LIGHT_PITCH) { + _targetX = DAT_TileMapState::instance.pitchDitches[this->units[unitID].targetID_OR_targetBuildingID].x; + _targetY = DAT_TileMapState::instance.pitchDitches[this->units[unitID].targetID_OR_targetBuildingID].y; + } else if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_ATTACK_BUILDING) { + _targetX + = (short)DAT_BuildingsState::instance.buildings[this->units[unitID].targetID_OR_targetBuildingID].x; + _targetY + = (short)DAT_BuildingsState::instance.buildings[this->units[unitID].targetID_OR_targetBuildingID].y; + } else if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_ATTACK_LAND + || this->units[unitID].shootTargetedUnit == -2) { + _targetX = this->units[unitID].shootTargetMicroX / 8; + _targetY = this->units[unitID].shootTargetMicroY / 8; + } else { + _targetX = this->units[this->units[unitID].shootTargetedUnit].x; + _targetY = this->units[this->units[unitID].shootTargetedUnit].y; + } + int _freeTileX = -1; + int _freeTileY = -1; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findClosestFreeTileNearUnitOnBuilding, + DAT_PathFindingState::ptr)(_buildingID, unitID, _targetX, _targetY, &_freeTileX, &_freeTileY); + if (this->units[unitID].x == _freeTileX && this->units[unitID].y == _freeTileY) { + return FALSE; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, _freeTileX, _freeTileY, 0); + this->units[unitID].state.generic + = (OpenSHC::Map::Units::States::US_APPEAR | OpenSHC::Map::Units::States::US_IDLEUnk); + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/isAtSecondaryDestination.cpp b/src/OpenSHC/Map/Units/UnitsState/isAtSecondaryDestination.cpp new file mode 100644 index 000000000..331d3b2c4 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/isAtSecondaryDestination.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00533960 + BOOLEnum UnitsState::isAtSecondaryDestination(int unitID) + { + if (this->units[unitID].destinationX_2Unk != this->units[unitID].x) { + return FALSE; + } + return (BOOLEnum)(this->units[unitID].destinationY_2Unk == this->units[unitID].y); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/isComputerManagedNonPeasant.cpp b/src/OpenSHC/Map/Units/UnitsState/isComputerManagedNonPeasant.cpp new file mode 100644 index 000000000..c75dd8899 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/isComputerManagedNonPeasant.cpp @@ -0,0 +1,27 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00530080 + BOOLEnum UnitsState::isComputerManagedNonPeasant(int unitID) + { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_PEASANT) { + return FALSE; + } + return ( + BOOLEnum)(DAT_UnitPropertiesDefinedData::instance.COMPUTER_MANAGED[(short)this->units[unitID].unitType] + != 0); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/isTowerTileOvercrowdedByCurrentPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/isTowerTileOvercrowdedByCurrentPlayer.cpp new file mode 100644 index 000000000..ccae56692 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/isTowerTileOvercrowdedByCurrentPlayer.cpp @@ -0,0 +1,79 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Buildings::BuildingTypeShort; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536780 + BOOLEnum UnitsState::isTowerTileOvercrowdedByCurrentPlayer(int tile) + { + int _buildingID = DAT_TileMapState::instance.BuildingLayer[tile]; + if (_buildingID == 0) { + return FALSE; + } + BuildingTypeShort _buildingType = DAT_BuildingsState::instance.buildings[_buildingID].buildingType; + if (_buildingType != OpenSHC::Map::Buildings::BT_TOWER1 + && _buildingType != OpenSHC::Map::Buildings::BT_TOWER2 + && _buildingType != OpenSHC::Map::Buildings::BT_TOWER3 + && _buildingType != OpenSHC::Map::Buildings::BT_TOWER4 + && _buildingType != OpenSHC::Map::Buildings::BT_TOWER5 + && _buildingType != OpenSHC::Map::Buildings::BT_STONEKEEP + && _buildingType != OpenSHC::Map::Buildings::BT_STRONGHOLD + && _buildingType != OpenSHC::Map::Buildings::BT_KEEPFOUR + && _buildingType != OpenSHC::Map::Buildings::BT_KEEPFIVE) { + return FALSE; + } + int _tileCapacity = DAT_BuildingsState::instance.buildings[_buildingID].widthOrHeight + * DAT_BuildingsState::instance.buildings[_buildingID].widthOrHeight; + if (_buildingType == OpenSHC::Map::Buildings::BT_TOWER1) { + _tileCapacity = 5; + } + int _ownUnitsOnBuilding = 0; + for (int _constructionTile = 0; _constructionTile < DAT_TileMapState::instance.constructionTileCount; + ++_constructionTile) { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, DAT_TileMapState::ptr)( + _constructionTile, DAT_BuildingsState::instance.buildings[_buildingID].widthOrHeight); + for (int _otherUnitID = (short)DAT_TileMapState::instance + .UnitLayer[DAT_ViewportRenderState::instance + .translationMatrix[DAT_TileMapState::instance.buildingY + + (short)DAT_BuildingsState::instance.buildings[_buildingID].y] + .addXgetTile + + DAT_TileMapState::instance.buildingX + + (short)DAT_BuildingsState::instance.buildings[_buildingID].x]; + _otherUnitID != 0; _otherUnitID = (short)this->units[_otherUnitID].nextUnitOnTheSameTile) { + if (this->units[_otherUnitID].owner == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + _ownUnitsOnBuilding = _ownUnitsOnBuilding + 1; + } + } + } + if (_ownUnitsOnBuilding < _tileCapacity / 2) { + return FALSE; + } + if (_tileCapacity <= _ownUnitsOnBuilding) { + return TRUE; + } + int _selectedUnitCount = 0; + for (int i = 0; i < 27; ++i) { + if (i != 6 && i != 8 && i != 11 && i != 12 && i != 13 && i != 14) { + _selectedUnitCount = _selectedUnitCount + (&this->selectionEuropeanArchers)[i]; + } + } + return (BOOLEnum)((_tileCapacity - _ownUnitsOnBuilding) * 2 < _selectedUnitCount); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/isUnitRegisteredOnItsOwnTile.cpp b/src/OpenSHC/Map/Units/UnitsState/isUnitRegisteredOnItsOwnTile.cpp new file mode 100644 index 000000000..576137bf5 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/isUnitRegisteredOnItsOwnTile.cpp @@ -0,0 +1,37 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F4E0 + undefined4 UnitsState::isUnitRegisteredOnItsOwnTile(int unitID) + { + int _tile = this->units[unitID].tile; + int _otherUnitID = (short)DAT_TileMapState::instance.UnitLayer[_tile]; + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + return 1; + } + if (this->units[unitID].unknownTestAgainst0_2 != 0) { + return 1; + } + if (_tile == 0) { + return 0; + } + while (_otherUnitID != 0) { + if (_otherUnitID == unitID) { + return 1; + } + _otherUnitID = (short)this->units[_otherUnitID].nextUnitOnTheSameTile; + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/isUnitShortcutAvailable.cpp b/src/OpenSHC/Map/Units/UnitsState/isUnitShortcutAvailable.cpp new file mode 100644 index 000000000..6a88fc898 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/isUnitShortcutAvailable.cpp @@ -0,0 +1,62 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/UI/Enums/BuildingsAndStatusMenuTabType.hpp" +#include "OpenSHC/UI/Enums/MenuViewType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::UI::Enums::BuildingsAndStatusMenuTabType; + using OpenSHC::UI::Enums::MenuViewType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x005360A0 + BOOLEnum UnitsState::isUnitShortcutAvailable(int unitHotKeyNumber) + { + if (DAT_GameCore::instance.currentMenuViewType != OpenSHC::UI::Enums::MVT_BUILD_MENU) { + return FALSE; + } + if (DAT_GameCore::instance.activeMenuTab.tabType != OpenSHC::UI::Enums::BASMTT_SIEGETENT_BATTERINGRAM + && DAT_GameCore::instance.activeMenuTab.tabType != OpenSHC::UI::Enums::BASMTT_SIEGETENT_SHIELD) { + return FALSE; + } + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].isSelected == 0) { + for (int i = 0; i < 2500; ++i) { + /* unitID is listed in this hotkey unit list and not selected */ + if (DAT_GameState::instance.hotkeyTribes[unitHotKeyNumber].units[i].id == unitID) { + return FALSE; + } + } + continue; + } + int _isListed = 0; + for (int i = 0; i < 2500; ++i) { + if (DAT_GameState::instance.hotkeyTribes[unitHotKeyNumber].units[i].id == unitID) { + _isListed = 1; + } + } + /* unitID is listed in this hotkey unit list and is selected */ + if (_isListed == 0) { + return FALSE; + } + } + /* There is no unitID to be found in a normal non-dead state that is selectable */ + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/isWorkerAtProductionIdleState.cpp b/src/OpenSHC/Map/Units/UnitsState/isWorkerAtProductionIdleState.cpp new file mode 100644 index 000000000..a97a0823c --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/isWorkerAtProductionIdleState.cpp @@ -0,0 +1,69 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053A070 + undefined4 UnitsState::isWorkerAtProductionIdleState(int unitID) + { + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_WOODCUTTER: + case OpenSHC::Map::Units::UT_HOPSFARMER: + case OpenSHC::Map::Units::UT_MILLER: + case OpenSHC::Map::Units::UT_BREWER: + case OpenSHC::Map::Units::UT_POLETURNER: + case OpenSHC::Map::Units::UT_SMITH: + case OpenSHC::Map::Units::UT_ARMORER: + case OpenSHC::Map::Units::UT_TANNER: + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_STAND_UPUnk) { + return 1; + } + break; + case OpenSHC::Map::Units::UT_FLETCHER: + case OpenSHC::Map::Units::UT_APPLEFARMER: + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk) { + return 1; + } + break; + case OpenSHC::Map::Units::UT_HUNTER: + case OpenSHC::Map::Units::UT_DAIRYFARMER: + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_AIM_WEAPONUnk) { + return 1; + } + break; + case OpenSHC::Map::Units::UT_QUARRYWORKER: + case OpenSHC::Map::Units::UT_PITCHMAN: + if (this->units[unitID].state.generic == (UnitState)3) { + return 1; + } + break; + case OpenSHC::Map::Units::UT_QUARRYOX: + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_IDLEUnk) { + return 1; + } + break; + case OpenSHC::Map::Units::UT_WHEATFARMER: + if (this->units[unitID].state.generic == (UnitState)10) { + return 1; + } + break; + case OpenSHC::Map::Units::UT_BAKER: + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_FIRE_WEAPONUnk) { + return 1; + } + break; + case OpenSHC::Map::Units::UT_TRANSPORTMINER: + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_RELOAD_WEAPONUnk) { + return 1; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/isWorkplaceBuildingOnAdjacentTile.cpp b/src/OpenSHC/Map/Units/UnitsState/isWorkplaceBuildingOnAdjacentTile.cpp new file mode 100644 index 000000000..6c5f22a4b --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/isWorkplaceBuildingOnAdjacentTile.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00534380 + undefined4 UnitsState::isWorkplaceBuildingOnAdjacentTile(int unitID) + { + if (this->units[unitID].workplaceBuildingID_1 == 0) { + return 0; + } + for (int direction = 0; direction < 8; ++direction) { + if (DAT_TileMapState::instance.BuildingLayer + [DAT_TileMapState::instance.directionTranslationMatrix[this->units[unitID].y][direction] + + this->units[unitID].tile] + == this->units[unitID].workplaceBuildingID_1) { + return 1; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/killAllUnownedUnits.cpp b/src/OpenSHC/Map/Units/UnitsState/killAllUnownedUnits.cpp new file mode 100644 index 000000000..cadce6bfd --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/killAllUnownedUnits.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x005302B0 + void UnitsState::killAllUnownedUnits() + { + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[unitID].dying == 0 && this->units[unitID].owner == 0 + && this->units[unitID].isStalked != 0) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_STONE_DEATH_01; + this->units[unitID].animationCycleNumber = 0; + this->units[unitID].dying = 1; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/killUnits.cpp b/src/OpenSHC/Map/Units/UnitsState/killUnits.cpp new file mode 100644 index 000000000..8202963fc --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/killUnits.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00530390 + void UnitsState::killUnits(int playerID) + { + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[unitID].dying == 0 && this->units[unitID].isStalked == 0 + && this->units[unitID].owner == playerID) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_STONE_DEATH_01; + this->units[unitID].animationCycleNumber = 0; + this->units[unitID].dying = 1; + this->units[unitID].killedFlagUnk = 1; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/makeCourtMemberUnitsDisappearAndSwapAllOtherUnitsOwnership.cpp b/src/OpenSHC/Map/Units/UnitsState/makeCourtMemberUnitsDisappearAndSwapAllOtherUnitsOwnership.cpp new file mode 100644 index 000000000..305e2eb2e --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/makeCourtMemberUnitsDisappearAndSwapAllOtherUnitsOwnership.cpp @@ -0,0 +1,72 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00530500 + void UnitsState::makeCourtMemberUnitsDisappearAndSwapAllOtherUnitsOwnership( + int firstPlayerID, int secondPlayerID) + { + for (int unitID = 1; unitID < 2500; ++unitID) { + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].isStalked != 0) { + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_QUARRYOX: + case OpenSHC::Map::Units::UT_COW: + case OpenSHC::Map::Units::UT_HUNTERDOG: + case OpenSHC::Map::Units::UT_CHICKEN: + case OpenSHC::Map::Units::UT_MOTHER: + case OpenSHC::Map::Units::UT_CHILD: + case OpenSHC::Map::Units::UT_JUGGLER: + case OpenSHC::Map::Units::UT_FIREEATER: + break; + default: + continue; + } + } + if (this->units[unitID].owner == firstPlayerID) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_LORD) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_LADY) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_JESTER) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } else { + this->units[unitID].owner = (short)secondPlayerID; + if (this->units[unitID].isStalked == 0 || this->units[unitID].calculatedOwnerPlayerIndex != 0) { + this->units[unitID].calculatedOwnerPlayerIndex = secondPlayerID; + } + } + } else if (this->units[unitID].owner == secondPlayerID) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_LORD) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_LADY) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_JESTER) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } else { + this->units[unitID].owner = (short)firstPlayerID; + if (this->units[unitID].isStalked == 0 || this->units[unitID].calculatedOwnerPlayerIndex != 0) { + this->units[unitID].calculatedOwnerPlayerIndex = firstPlayerID; + } + } + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/makeSelectionBasedOnShortcut.cpp b/src/OpenSHC/Map/Units/UnitsState/makeSelectionBasedOnShortcut.cpp new file mode 100644 index 000000000..828dd5c97 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/makeSelectionBasedOnShortcut.cpp @@ -0,0 +1,45 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535FD0 + void UnitsState::makeSelectionBasedOnShortcut(int section1099ID) + { + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[DAT_CurrentUnitSlotID::instance].dying == 0) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 0; + } + } + this->totalUnitsInSelection = 0; + for (int i = 0; i < 2500; ++i) { + int _unitID = DAT_GameState::instance.hotkeyTribes[section1099ID].units[i].id; + if (_unitID == -1) { + continue; + } + if (this->units[_unitID].uid == DAT_GameState::instance.hotkeyTribes[section1099ID].units[i].uid + && this->units[_unitID].unknownTestAgainst0_2 == 0 + && this->units[_unitID].disappearFadeAlphaCountdown == 0) { + this->units[_unitID].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } else { + DAT_GameState::instance.hotkeyTribes[section1099ID].units[i].id = -1; + } + } + if (this->totalUnitsInSelection > 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::createTribeFromSelectedUnits, this)(); + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/makeUnitStopWalkingByClearingPathProgressState.cpp b/src/OpenSHC/Map/Units/UnitsState/makeUnitStopWalkingByClearingPathProgressState.cpp new file mode 100644 index 000000000..37662395b --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/makeUnitStopWalkingByClearingPathProgressState.cpp @@ -0,0 +1,18 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F070 + void UnitsState::makeUnitStopWalkingByClearingPathProgressState(int unitID) + { + this->units[unitID].currentIndexInPathPlan = 0; + this->units[unitID].totalSizeOfPathPlan = 0; + this->units[unitID].unknownMovementRelated_0x2d2 = 0; + this->units[unitID].climbDataID = 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/makeUnitsDisappearThatCannotReachTheKeep.cpp b/src/OpenSHC/Map/Units/UnitsState/makeUnitsDisappearThatCannotReachTheKeep.cpp new file mode 100644 index 000000000..2b6f6ba63 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/makeUnitsDisappearThatCannotReachTheKeep.cpp @@ -0,0 +1,55 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00530650 + void UnitsState::makeUnitsDisappearThatCannotReachTheKeep(int playerID) + { + dword _areaOfKeep + = (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_GameState::instance.playerDataArray[playerID].campground.tileEntry]; + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].owner != playerID) { + continue; + } + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].isSelectable_OR_matchTime != 0) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].isStalked != 0) { + continue; + } + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, (short)_areaOfKeep, + (short)DAT_TileMapState::instance.PathConnectionLayer[this->units[unitID].tile], 0) + != 0) { + continue; + } + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + this->units[unitID].animationCycleNumber = 0; + this->units[unitID].disappearFadeAlphaCountdown = 0; + this->units[unitID].dying = 1; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/moveToFreeTileNearby.cpp b/src/OpenSHC/Map/Units/UnitsState/moveToFreeTileNearby.cpp new file mode 100644 index 000000000..e878b1161 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/moveToFreeTileNearby.cpp @@ -0,0 +1,57 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0054C610 + BOOLEnum UnitsState::moveToFreeTileNearby(int unitID) + { + if ((DAT_TileMapState::instance.LogicLayer[this->units[unitID].tile] & 0x30U) != 0) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDirectNeighbourWalkableTile, + DAT_PathFindingState::ptr)(this->units[unitID].x, this->units[unitID].y) + != FALSE) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setPositionOfUnit, this)(unitID, + DAT_PathFindingState::instance.ALG_ResultX, DAT_PathFindingState::instance.ALG_ResultY, + DAT_TileMapState::instance.HeightLayer[DAT_PathFindingState::instance.ALG_ResultTile]); + } + return FALSE; + } + if ((short)DAT_TileMapState::instance.UnitLayer[this->units[unitID].tile] == unitID) { + return FALSE; + } + if ((DAT_TileMapState::instance.LogicLayer[this->units[unitID].tile] & 0x100U) == 0) { + /* not a wall tower or gatehouse */ + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::findPathableTileWithoutUnitWithBuildingAtXY, + DAT_PathFindingState::ptr)(-1, this->units[unitID].x, this->units[unitID].y); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findFreeTileOnDefensiveStructure, + DAT_PathFindingState::ptr)(-1, this->units[unitID].x, this->units[unitID].y); + } + if (DAT_PathFindingState::instance.ALG_ResultTile == 0) { + return FALSE; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, DAT_PathFindingState::instance.ALG_ResultX, DAT_PathFindingState::instance.ALG_ResultY, 0) + == FALSE) { + return FALSE; + } + this->units[DAT_CurrentUnitSlotID::instance].state.generic + = OpenSHC::Map::Units::States::US_MOVE_TO_DESTINATION; + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/nonEuroRecruit.cpp b/src/OpenSHC/Map/Units/UnitsState/nonEuroRecruit.cpp new file mode 100644 index 000000000..1db8a6d18 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/nonEuroRecruit.cpp @@ -0,0 +1,103 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052EC10 + int UnitsState::nonEuroRecruit(UnitType unitType, undefined4 recruitmentBuilding, int playerID, int param_4) + { + this->euroUnitAcquisitionFailReason = 0; + int _unitCost; + if (unitType == OpenSHC::Map::Units::UT_E_ENGINEER) { + _unitCost = 0x1e; + } else if (unitType == OpenSHC::Map::Units::UT_TUNNELER) { + _unitCost = 0x1e; + } else if (unitType == OpenSHC::Map::Units::UT_E_LADDER) { + _unitCost = 4; + } else if (unitType == OpenSHC::Map::Units::UT_E_MONK) { + _unitCost = 10; + } else if (unitType == OpenSHC::Map::Units::UT_A_ARCHER) { + _unitCost = 0x4b; + } else if (unitType == OpenSHC::Map::Units::UT_A_SLAVE) { + _unitCost = 5; + } else if (unitType == OpenSHC::Map::Units::UT_A_SLINGER) { + _unitCost = 0xc; + } else if (unitType == OpenSHC::Map::Units::UT_A_ASSASSIN) { + _unitCost = 0x3c; + } else if (unitType == OpenSHC::Map::Units::UT_A_HARCHER) { + _unitCost = 0x50; + } else if (unitType == OpenSHC::Map::Units::UT_A_SWORDSMAN) { + _unitCost = 0x50; + } else if (unitType == OpenSHC::Map::Units::UT_A_FIRETHROWER) { + _unitCost = 100; + } else { + return 0; + } + /* Check if player has enough gold, then convert peasant to new unit */ + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < _unitCost) { + this->euroUnitAcquisitionFailReason = 1; + return 0; + } + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_PEASANT) { + continue; + } + if (this->units[unitID].owner != playerID) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_RELOAD_WEAPONUnk) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_AIM_WEAPONUnk) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_JESTER_ROAM_TO) { + continue; + } + if (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + continue; + } + if (param_4 != 0) { + return 1; + } + this->units[unitID].unitTypeToChangeInto = (UnitTypeShort)unitType; + this->units[unitID].state_2 = 0; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_JESTER_ROAM_TO; + this->units[unitID].disappearFadeAlphaCountdown = 0; + this->units[unitID].engineerManningSiegeStateRef_checkType = 1; + this->units[unitID].cachedState = OpenSHC::Map::Units::States::US_DETERMINE_NEXT_STATEUnk; + this->units[unitID].isDisappearingUnk = 1; + this->units[unitID].workplaceBuildingID_1 = (short)recruitmentBuilding; + this->units[unitID].resourceToDeposit = 0; + DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] -= _unitCost; + DAT_GameSynchronyState::instance.finalResults.finalTroopsProduced[playerID] += 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::aiAssignNewUnitToTribe, DAT_TribesState::ptr)( + playerID, unitType, unitID); + return unitID; + } + this->euroUnitAcquisitionFailReason = 3; + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/playHurtSFXForUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/playHurtSFXForUnit.cpp new file mode 100644 index 000000000..9c8d46ad0 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/playHurtSFXForUnit.cpp @@ -0,0 +1,77 @@ +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/DE/SHCDE/eSFX.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_SFXState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::DE::SHCDE::eSFX; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005300B0 + void UnitsState::playHurtSFXForUnit(int unitID) + { + if (unitID == 0) { + return; + } + if (this->units[unitID].healthPercentage < 0xb) { + return; + } + if (this->units[unitID].isStalked != 0) { + return; + } + if ((short)this->units[unitID].unitType <= 0) { + return; + } + eSFX _sfxOffsetInArray; + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_TREBUCHET + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_MANGONEL + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_BALLISTA + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_TOWER + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + _sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_ATTACK_WOOD; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_BREWER + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_TANNER + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_LADY + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_MOTHER + || (this->units[unitID].unitType == OpenSHC::Map::Units::UT_CHILD + && this->units[unitID].spriteID == 0x81)) { + _sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_GIRL_GRUNT; + } else { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_SHIELD + && this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300 + == 0) { + return; + } + if ((this->units[unitID].fixedRng & 7) == 0) { + _sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT; + } else if ((this->units[unitID].fixedRng & 7) == 1) { + _sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT2; + } else if ((this->units[unitID].fixedRng & 7) == 2) { + _sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT3; + } else if ((this->units[unitID].fixedRng & 7) == 3) { + _sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT4; + } else if ((this->units[unitID].fixedRng & 7) == 4) { + _sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT5; + } else if ((this->units[unitID].fixedRng & 7) == 5) { + _sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT6; + } else if ((this->units[unitID].fixedRng & 7) == 6) { + _sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT7; + } else if ((this->units[unitID].fixedRng & 7) == 7) { + _sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT8; + } else { + return; + } + } + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unitID].x, this->units[unitID].y, _sfxOffsetInArray); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/playerMakeUnitSelection.cpp b/src/OpenSHC/Map/Units/UnitsState/playerMakeUnitSelection.cpp new file mode 100644 index 000000000..f581dd26b --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/playerMakeUnitSelection.cpp @@ -0,0 +1,104 @@ +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Audio/SFX/SpeechEffectID.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UIDragDropDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Audio::SFX::SpeechEffectID; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535BC0 + void UnitsState::playerMakeUnitSelection(int playerID, int tribeID) + { + this->unitCountOfSelection[playerID] = 0; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[DAT_CurrentUnitSlotID::instance].dying == 0 + && this->units[DAT_CurrentUnitSlotID::instance].owner == playerID + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unitIsSelectedByPlayer, + DAT_TribesState::ptr)(DAT_CurrentUnitSlotID::instance) + != FALSE) { + this->units[DAT_CurrentUnitSlotID::instance].ifSelectedThenPlayerID = (short)playerID; + this->units[DAT_CurrentUnitSlotID::instance].selectionRelatedFlag = 1; + this->unitCountOfSelection[playerID] = this->unitCountOfSelection[playerID] + 1; + } + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::snapshotSelectionTribeAndComputeStance, + DAT_TribesState::ptr)(playerID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::removeSelectedUnitsFromTheirCurrentTribes, + DAT_TribesState::ptr)(playerID); + int _newTribeID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::createPlayerTribe, DAT_TribesState::ptr)(playerID, 1, tribeID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitsToTribeAndComputeMovementSpeed, + DAT_TribesState::ptr)(playerID, _newTribeID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::importStoredInfoFromSlot0, DAT_TribesState::ptr)( + playerID, _newTribeID); + if (DAT_TribesState::instance.tribes[_newTribeID].owner + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + DAT_UIDragDropDefinedData::instance.MenuView_TriggerInitial = TRUE; + return; + } + UnitType _unitType = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::getMajoritySelectedUnitType, + DAT_TribesState::ptr)(_newTribeID, (int*)0x0); + if (_unitType == OpenSHC::Map::Units::UT_S_CATAPULT || _unitType == OpenSHC::Map::Units::UT_S_TOWER + || _unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM || _unitType == OpenSHC::Map::Units::UT_S_SHIELD + || _unitType == OpenSHC::Map::Units::UT_S_BALLISTA || _unitType == OpenSHC::Map::Units::UT_S_FBALLISTA + || _unitType == OpenSHC::Map::Units::UT_S_TREBUCHET + || _unitType == OpenSHC::Map::Units::UT_S_MANGONEL) { + int _siegeEngineUnitID = DAT_TribesState::instance.tribes[_newTribeID].selectionTargetUnitID; + int _remainingEngineers = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, this)(_siegeEngineUnitID); + if (_remainingEngineers > 0) { + if (this->units[_siegeEngineUnitID] + .digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300 + == 0 + || _remainingEngineers > 3) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeechEffect, DAT_SFXState::ptr)( + 0xe); + } else if (_remainingEngineers == 1) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeechEffect, DAT_SFXState::ptr)( + 0xb); + } else if (_remainingEngineers == 2) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeechEffect, DAT_SFXState::ptr)( + 0xc); + } else if (_remainingEngineers == 3) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeechEffect, DAT_SFXState::ptr)( + 0xd); + } + DAT_UIDragDropDefinedData::instance.MenuView_TriggerInitial = TRUE; + return; + } + if (_unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || _unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) { + if ((this->units[_siegeEngineUnitID].unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || this->units[_siegeEngineUnitID].unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) + && this->units[_siegeEngineUnitID].stoneAmmunition <= 0) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSpeechSFX, DAT_SFXState::ptr)( + OpenSHC::Audio::SFX::SEID_RESOURCE_NEED25); + DAT_UIDragDropDefinedData::instance.MenuView_TriggerInitial = TRUE; + return; + } + } + } + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeech, DAT_SFXState::ptr)(_unitType, 0); + DAT_UIDragDropDefinedData::instance.MenuView_TriggerInitial = TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/prepareProjectileTarget.cpp b/src/OpenSHC/Map/Units/UnitsState/prepareProjectileTarget.cpp new file mode 100644 index 000000000..dc06e3025 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/prepareProjectileTarget.cpp @@ -0,0 +1,181 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" + +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053CBD0 + int UnitsState::prepareProjectileTarget(int shooterID, int targetID, int param_3) + { + uint _targetFixedRng = 0; + if (targetID == -1) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setRandomShootLocation, this)(shooterID, + this->units[shooterID].shootTargetMicroX, this->units[shooterID].shootTargetMicroY, + this->units[shooterID].shootTargetZ); + } else { + _targetFixedRng = this->units[targetID].fixedRng; + this->units[shooterID].shootTargetMicroX = this->units[targetID].x * 8 + 4; + this->units[shooterID].shootTargetMicroY = this->units[targetID].y * 8 + 4; + this->units[shooterID].shootTargetZ + = this->units[targetID].buildingHeight + this->units[targetID].terrainOrClimbHeight; + if (this->units[targetID].tunnelerFinishedDigging == 2) { + int _lead = (param_3 * 133) / 100; + short _adjustment; + /* todo:fixme:ucp: this if-else should be improved to also trigger when the + targetID has negative height (walking in pitch or moat) */ + if (this->units[targetID].stateBasedSpeed == 0) { + if (this->units[targetID].calculatedMovementSpeed < 2) { + _adjustment = (short)(_lead / 16); + } else { + _adjustment = (short)(_lead / (this->units[targetID].calculatedMovementSpeed << 4)); + } + } else { + _adjustment = (short)(_lead / 8); + } + short _targetFacing = this->units[targetID].facingDirection; + if (_targetFacing == 0) { + this->units[shooterID].shootTargetMicroY + = this->units[shooterID].shootTargetMicroY - _adjustment; + } else if (_targetFacing == 1) { + this->units[shooterID].shootTargetMicroY + = this->units[shooterID].shootTargetMicroY - _adjustment; + this->units[shooterID].shootTargetMicroX + = this->units[shooterID].shootTargetMicroX + _adjustment; + } else if (_targetFacing == 2) { + this->units[shooterID].shootTargetMicroX + = this->units[shooterID].shootTargetMicroX + _adjustment; + } else if (_targetFacing == 3) { + this->units[shooterID].shootTargetMicroY + = this->units[shooterID].shootTargetMicroY + _adjustment; + this->units[shooterID].shootTargetMicroX + = this->units[shooterID].shootTargetMicroX + _adjustment; + } else if (_targetFacing == 4) { + this->units[shooterID].shootTargetMicroY + = this->units[shooterID].shootTargetMicroY + _adjustment; + } else if (_targetFacing == 5) { + this->units[shooterID].shootTargetMicroY + = this->units[shooterID].shootTargetMicroY + _adjustment; + this->units[shooterID].shootTargetMicroX + = this->units[shooterID].shootTargetMicroX - _adjustment; + } else if (_targetFacing == 6) { + this->units[shooterID].shootTargetMicroX + = this->units[shooterID].shootTargetMicroX - _adjustment; + } else if (_targetFacing == 7) { + this->units[shooterID].shootTargetMicroY + = this->units[shooterID].shootTargetMicroY - _adjustment; + this->units[shooterID].shootTargetMicroX + = this->units[shooterID].shootTargetMicroX - _adjustment; + } + } + } + /* the original returns whatever the switch below left in the return register on + the paths that adjust nothing, which is the type's index into it; the value is + not a meaningful result, but callers of those paths are given it */ + int _unhandledTypeResult = (short)this->units[shooterID].unitType + -0x16; + int _scatter; + if (this->units[shooterID].shootTargetZ < this->units[shooterID].terrainOrClimbHeight) { + switch (this->units[shooterID].unitType) { + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_BALLISTA: + _scatter = 0x14; + break; + case OpenSHC::Map::Units::UT_S_TREBUCHET: + _scatter = 0x32; + break; + case OpenSHC::Map::Units::UT_S_MANGONEL: + _scatter = 0x3c; + break; + case OpenSHC::Map::Units::UT_S_FBALLISTA: + _scatter = 10; + break; + default: + return _unhandledTypeResult; + } + } else { + _scatter = this->units[shooterID].shootTargetZ - this->units[shooterID].terrainOrClimbHeight; + if (_scatter > 0x4b) { + _scatter = _scatter + _scatter / 2; + } + switch (this->units[shooterID].unitType) { + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_BALLISTA: + _scatter = _scatter + 0x28; + break; + case OpenSHC::Map::Units::UT_S_TREBUCHET: + _scatter = _scatter + 0x3c; + break; + case OpenSHC::Map::Units::UT_S_MANGONEL: + _scatter = _scatter + 0x46; + break; + case OpenSHC::Map::Units::UT_S_FBALLISTA: + return _unhandledTypeResult; + } + if (_scatter <= 0) { + return _unhandledTypeResult; + } + if (_scatter > 0x118) { + _scatter = 0x118; + } + } + uint _rng = SEC_RNG::instance.currentNumber2; + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + _unhandledTypeResult = ((int)_rng / 300) * 300; + if ((int)_rng % 300 >= _scatter) { + return _unhandledTypeResult; + } + if ((_rng & 7) < 2) { + _scatter = _scatter / 4; + if (_scatter == 0) { + _scatter = 1; + } + int _horizontalRng = ((int)_rng / 512) + this->units[shooterID].fixedRng; + if (_horizontalRng < 0) { + _horizontalRng = -_horizontalRng; + } + this->units[shooterID].shootTargetMicroX = this->units[shooterID].shootTargetMicroX + + ((short)(_horizontalRng % _scatter) - (short)(_scatter / 2)); + int _verticalRng = _rng + _targetFixedRng; + if (_verticalRng < 0) { + _verticalRng = -_verticalRng; + } + this->units[shooterID].shootTargetMicroY = this->units[shooterID].shootTargetMicroY + + ((short)(_verticalRng % _scatter) - (short)(_scatter / 2)); + return _verticalRng / _scatter; + } + if ((_rng & 7) < 6) { + _scatter = _scatter / 6; + if (_scatter == 0) { + _scatter = 1; + } + int _heightRng = this->units[shooterID].fixedRng + _rng; + if (_heightRng < 0) { + _heightRng = -_heightRng; + } + int _heightOffset = _heightRng % _scatter + 0x14; + if (_heightRng % _scatter + 0x1c <= (int)this->units[shooterID].shootTargetZ) { + _unhandledTypeResult = (ushort)this->units[shooterID].shootTargetZ - _heightOffset; + } else { + _unhandledTypeResult = (ushort)this->units[shooterID].shootTargetZ + _heightOffset; + } + this->units[shooterID].shootTargetZ = (short)_unhandledTypeResult; + return _unhandledTypeResult; + } + _scatter = _scatter / 6; + if (_scatter == 0) { + _scatter = 1; + } + int _heightRng = _rng + _targetFixedRng; + if (_heightRng < 0) { + _heightRng = -_heightRng; + } + this->units[shooterID].shootTargetZ + = this->units[shooterID].shootTargetZ + (short)(_heightRng % _scatter) + 0x28; + return _heightRng / _scatter; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/processEntityDamageToUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/processEntityDamageToUnit.cpp new file mode 100644 index 000000000..010fa7923 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/processEntityDamageToUnit.cpp @@ -0,0 +1,508 @@ +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/DE/SHCDE/eSFX.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Entities/EntityType.hpp" +#include "OpenSHC/Map/Entities/EntityTypeShort.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::DE::SHCDE::eSFX; + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Entities::EntityType; + using OpenSHC::Map::Entities::EntityTypeShort; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00531920 + BOOLEnum UnitsState::processEntityDamageToUnit(int unitID, int entityID, int tileDistance) + + { + int _cowDiseaseDamage; + int _unitHeight; + eSFX sfxOffsetInArray; + UnitTypeShort _entityType_2; + + /* + unclear what it does, but this function removes health from a unit, ranged + and melee + */ + + int _unknown = (int)this->units[unitID].tribeID; + int _unitIsSiegeEngine = 0; + int _siegeProjectile = 0; + int _usesFemaleDeathScream = 0; + UnitTypeShort _unitType = this->units[unitID].unitType; + int _entityShootingUnitID = DAT_EntityState::instance.entityArray[entityID].unitID_OR_seaGullID; + int _entityShootingUnitID_2 = (int)_entityShootingUnitID; + if (unitID <= 0) { + return FALSE; + } + if (_entityShootingUnitID_2 == unitID) { + return FALSE; + } + EntityTypeShort _entityType = DAT_EntityState::instance.entityArray[entityID].entityType; + if (_entityType == OpenSHC::Map::Entities::ET_FIRE) { + return FALSE; + } + if (_entityType == OpenSHC::Map::Entities::ET_FIRETHROWER) { + return FALSE; + } + if (_entityType == OpenSHC::Map::Entities::ET_COW_POISON_CLOUD) { + /* + if the unit is dead, don't bother + */ + + if (this->units[unitID].dying != 0) { + return FALSE; + } + int _unitTile = DAT_UnitsState::instance.units[unitID].tile; + /* + if the tile that the unit is on has some properties, don't bother either. + */ + + if ((DAT_TileMapState::instance.LogicLayer[_unitTile] & 0x10000100U) != 0) { + return FALSE; + } + /* + if the unit is standing on a building, and that building is a defensive + building, return 0 + */ + + if (DAT_TileMapState::instance.BuildingLayer[_unitTile] != 0) { + switch (DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.BuildingLayer[_unitTile]] + .buildingType) { + case OpenSHC::Map::Buildings::BT_MANORHOUSE: + case OpenSHC::Map::Buildings::BT_STONEKEEP: + case OpenSHC::Map::Buildings::BT_STRONGHOLD: + case OpenSHC::Map::Buildings::BT_KEEPFOUR: + case OpenSHC::Map::Buildings::BT_KEEPFIVE: + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: + case OpenSHC::Map::Buildings::BT_WOODGATE1: + case OpenSHC::Map::Buildings::BT_TOWER1: + case OpenSHC::Map::Buildings::BT_TOWER2: + case OpenSHC::Map::Buildings::BT_TOWER3: + case OpenSHC::Map::Buildings::BT_TOWER4: + case OpenSHC::Map::Buildings::BT_TOWER5: + return FALSE; + } + } + /* + if the unit is of a type that is invulnerable to disease clouds, return 0 + */ + + if (DAT_UnitPropertiesDefinedData::instance.UnitClimbStateFlags[0][(short)this->units[unitID].unitType] + == 0) { + return FALSE; + } + if (tileDistance == 0) { + _cowDiseaseDamage = 400; + } else { + _cowDiseaseDamage = tileDistance == 1 ? 200 : 150; + } + int _healerCount = DAT_GameState::instance.playerDataArray[this->units[unitID].owner].healerCount; + if (_healerCount >= 3) { + /* * 40 */ + _cowDiseaseDamage = (_cowDiseaseDamage * 0x28) / 100; + } else if (_healerCount == 2) { + /* * 60 */ + _cowDiseaseDamage = (_cowDiseaseDamage * 0x3c) / 100; + } else if (_healerCount == 1) { + /* * 80 */ + _cowDiseaseDamage = (_cowDiseaseDamage * 0x50) / 100; + } + this->units[unitID].health = this->units[unitID].health - _cowDiseaseDamage; + if (this->units[unitID].health < 1) { + this->units[unitID].health = 0; + this->units[unitID].dying = 1; + this->units[unitID].animationCycleNumber = 0; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_STONE_DEATH_02; + this->units[unitID].tunnelerFinishedDigging = 1; + } + int _healthPercentage + = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::computeHealthPercentage, + DAT_DirectionAlgorithmState::ptr)(this->units[unitID].health, this->units[unitID].maxHealth); + this->units[unitID].healthPercentage = (short)_healthPercentage; + this->units[unitID].healthbar = (short)_healthPercentage / 10; + return FALSE; + } + if (_unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) { + _unitHeight = tileDistance == 0 ? 0x50 : 0x28; + _unitIsSiegeEngine = 1; + } else if (_unitType == OpenSHC::Map::Units::UT_S_TOWER) { + _unitHeight = 0x50; + _unitIsSiegeEngine = 1; + } else if (_unitType == OpenSHC::Map::Units::UT_S_CATAPULT) { + _unitHeight = 0x32; + _unitIsSiegeEngine = 1; + } else if (_unitType == OpenSHC::Map::Units::UT_S_SHIELD) { + _unitHeight = 0x5a; + _unitIsSiegeEngine = 1; + } else if (_unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + _unitHeight = 0x28; + _unitIsSiegeEngine = 1; + } else if (_unitType == OpenSHC::Map::Units::UT_S_MANGONEL) { + _unitHeight = 0x46; + _unitIsSiegeEngine = 1; + } else { + if ((_unitType == OpenSHC::Map::Units::UT_S_BALLISTA) + || (_unitType == OpenSHC::Map::Units::UT_S_FBALLISTA)) { + _unitIsSiegeEngine = 1; + } + _unitHeight = 42; + } + if (_entityType == OpenSHC::Map::Entities::ET_TREBUCHET + || _entityType == OpenSHC::Map::Entities::ET_CATAPULT + || _entityType == OpenSHC::Map::Entities::ET_MANGONEL + || _entityType == OpenSHC::Map::Entities::ET_BALLISTA + || _entityType == OpenSHC::Map::Entities::ET_FIREBALLISTA) { + _siegeProjectile = 1; + } + int _unitPlayerID = this->units[unitID].owner; + int _entityPlayerID = DAT_EntityState::instance.entityArray[entityID].owner; + if (((DAT_GameState::instance.mapAndTime.playerTeams[_entityPlayerID] + == DAT_GameState::instance.mapAndTime.playerTeams[_unitPlayerID]) + && (( + ((!_siegeProjectile + || (_entityType = DAT_EntityState::instance.entityArray[entityID].entityType, + _entityType == OpenSHC::Map::Entities::ET_BALLISTA)) + || ((_entityType == OpenSHC::Map::Entities::ET_MANGONEL + && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_entityPlayerID] == -1)))) + || ((((_entityType == OpenSHC::Map::Entities::ET_FIREBALLISTA + || (_unitType == OpenSHC::Map::Units::UT_S_SHIELD)) + || (_unitType == OpenSHC::Map::Units::UT_S_TOWER)) + || (_unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM)))))) + || this->units[unitID].dying != 0) { + return FALSE; + } + int _unitAltitude = (int)this->units[unitID].terrainOrClimbHeight + (int)this->units[unitID].buildingHeight; + int _damage = (int)DAT_EntityState::instance.entityArray[entityID].height; + if (_damage < _unitAltitude) { + return FALSE; + } + if (_unitAltitude + _unitHeight < _damage) { + return FALSE; + } + if ((_entityPlayerID != 0) && (_entityPlayerID != this->units[unitID].owner)) { + this->units[unitID].lastEncounteredEnemyPlayerID = _entityPlayerID; + this->units[unitID].lastEncounteredEnemyUnitIDUnk + = DAT_EntityState::instance.entityArray[entityID].unitID_OR_seaGullID; + } + if ((DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) + && (_unitPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXWeAreUnderAttack, DAT_SFXState::ptr)(); + } + int _unitYPosition_2 = this->units[unitID].y; + int _unitXPosition_2 = this->units[unitID].x; + _entityType = DAT_EntityState::instance.entityArray[entityID].entityType; + if (_siegeProjectile) { + if (_entityType == OpenSHC::Map::Entities::ET_COW_FLYING) { + _entityType_2 = this->units[unitID].unitType; + if (_entityType_2 == OpenSHC::Map::Units::UT_LORD) { + _damage = 0x32; + } else { + /* flying cow: 50 against a shield, 500 against anything else */ + _damage = _entityType_2 == OpenSHC::Map::Units::UT_S_SHIELD ? 0x32 : 0x1f4; + } + } else if (_entityType == OpenSHC::Map::Entities::ET_MANGONEL) { + /* + mangonel damage + */ + + _entityType_2 = this->units[unitID].unitType; + if (_entityType_2 == OpenSHC::Map::Units::UT_LORD) { + _damage = 0x32; + } else if (_entityType_2 == OpenSHC::Map::Units::UT_S_SHIELD) { + _damage = 1500; + } else if (_entityType_2 == OpenSHC::Map::Units::UT_S_BALLISTA) { + _damage = 1000; + } else if (_entityType_2 == OpenSHC::Map::Units::UT_S_FBALLISTA) { + _damage = 1000; + } else if (_entityType_2 == OpenSHC::Map::Units::UT_S_MANGONEL) { + _damage = 500; + } else if (_entityType_2 == OpenSHC::Map::Units::UT_S_CATAPULT) { + _damage = 5000; + } else if (_entityType_2 == OpenSHC::Map::Units::UT_S_TREBUCHET) { + _damage = 5000; + } else if (_entityType_2 == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + _damage = 10000; + } else { + _damage = _entityType_2 == OpenSHC::Map::Units::UT_S_TOWER ? 10000 : 30000; + } + } else { + if (_entityType != OpenSHC::Map::Entities::ET_BALLISTA) { + /* every other siege projectile: 50 against the lord, 30000 otherwise */ + _damage = this->units[unitID].unitType == OpenSHC::Map::Units::UT_LORD ? 0x32 : 0x7530; + } + /* + tower ballista and fire ballista damage + */ + + UnitTypeShort _targetUnitType = this->units[unitID].unitType; + if (_targetUnitType == OpenSHC::Map::Units::UT_LORD) { + _damage = 0x32; + } else if (_targetUnitType == OpenSHC::Map::Units::UT_S_SHIELD) { + _damage = 500; + } else if (_targetUnitType == OpenSHC::Map::Units::UT_S_BALLISTA) { + _damage = 2000; + } else if (_targetUnitType == OpenSHC::Map::Units::UT_S_MANGONEL) { + _damage = 2000; + } else if (_targetUnitType == OpenSHC::Map::Units::UT_S_FBALLISTA) { + _damage = 2000; + } else if (_targetUnitType == OpenSHC::Map::Units::UT_S_CATAPULT) { + _damage = 0x9c4; + } else if (_targetUnitType == OpenSHC::Map::Units::UT_S_TREBUCHET) { + _damage = 4000; + } else if (_targetUnitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + _damage = 20000; + } else { + /* + 10000 if not siege tower else 20000 + */ + + _damage = _targetUnitType == OpenSHC::Map::Units::UT_S_TOWER ? 20000 : 10000; + } + if (DAT_EntityState::instance.entityArray[entityID].field90_0xd0 != 0) { + /* + if is fire ballista + */ + + _damage = (_damage * 2) / 3; + } + } + DAT_GameCore::instance.cowPoisonTrackerUnk = DAT_GameCore::instance.cowPoisonTrackerUnk + 0x32; + if (20000 < _damage) { + this->units[unitID].dying = 1; + if (0 < _unknown) { + DAT_TribesState::instance.tribes[_unknown].field133_0x278 = 1; + } + int _unitYPosition = this->units[unitID].y; + int _unitXPosition = this->units[unitID].x; + this->units[unitID].animationCycleNumber = 0; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_STONE_DEATH_01; + this->units[unitID].tunnelerFinishedDigging = 1; + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + (int)_unitXPosition, (int)(_unitYPosition), OpenSHC::DE::SHCDE::FX_SPLAT); + this->units[unitID].health = 0; + return TRUE; + } + } else { + if (_entityType == OpenSHC::Map::Entities::ET_ARROW_AND_DEFAULT) { + _entityType_2 = this->units[unitID].unitType; + _damage = DAT_UnitPropertiesDefinedData::instance.ARROW_DAMAGE[(short)_entityType_2]; + if (_entityType_2 == OpenSHC::Map::Units::UT_E_LADDER + && this->units[unitID].state.generic == (UnitState)3) { + /* the compiler's biased shift matches here where a plain /4 does not */ + _damage = (int)(_damage + (_damage >> 0x1f & 3U)) >> 2; + } + } else if (_entityType == OpenSHC::Map::Entities::ET_SLINGER) { + _damage = DAT_UnitPropertiesDefinedData::instance.STONE_DAMAGE[(short)this->units[unitID].unitType]; + } else { + _damage = DAT_UnitPropertiesDefinedData::instance.BOLT_DAMAGE[(short)this->units[unitID].unitType]; + } + _damage = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::computeDamageFearFactorBonus, this)( + _damage, (int)(DAT_EntityState::instance.entityArray[entityID].owner)); + if (_unitIsSiegeEngine) { + _damage = _damage / 2; + } + if (this->units[unitID].isStalked == 0) { + DAT_GameCore::instance.cowPoisonTrackerUnk = DAT_GameCore::instance.cowPoisonTrackerUnk + 0x32; + } + } + if ((int)DAT_EntityState::instance.entityArray[entityID].startingHeight + < DAT_EntityState::instance.entityArray[entityID].targetZ + -0x1e) { + if ((this->units[unitID].unitType == OpenSHC::Map::Units::UT_E_ENGINEER) + && (this->units[unitID].resourceToDeposit != 0)) { + _damage = _damage / 0x14; + } else if (_entityType == OpenSHC::Map::Entities::ET_BALLISTA) { + _damage = _damage / 2; + } else { + _damage = _damage / 3; + } + } + this->units[unitID].health = this->units[unitID].health - _damage; + if (this->units[unitID].health < 1) { + this->units[unitID].health = 0; + } + if (_entityShootingUnitID_2 != 0) { + if (this->units[unitID].field97_0xd0 < 1000) { + this->units[unitID].field97_0xd0 = this->units[unitID].field97_0xd0 + 200; + } + DAT_TribesState::instance.tribes[_unknown].someUnitArrayIndex + = DAT_TribesState::instance.tribes[_unknown].someUnitArrayIndex + 1; + DAT_TribesState::instance.tribes[_unknown].countdown = 100; + if (9 < DAT_TribesState::instance.tribes[_unknown].someUnitArrayIndex) { + DAT_TribesState::instance.tribes[_unknown].someUnitArrayIndex = 0; + } + DAT_TribesState::instance.tribes[_unknown] + .someUnitArray[DAT_TribesState::instance.tribes[_unknown].someUnitArrayIndex] + = _entityShootingUnitID; + DAT_TribesState::instance.tribes[_unknown] + .someUnitUIDArray[DAT_TribesState::instance.tribes[_unknown].someUnitArrayIndex] + = this->units[_entityShootingUnitID_2].uid; + } + int _unitHealth = this->units[unitID].health; + int _healthPercentage_2 + = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::computeHealthPercentage, + DAT_DirectionAlgorithmState::ptr)(_unitHealth, this->units[unitID].maxHealth); + this->units[unitID].healthPercentage = (short)_healthPercentage_2; + this->units[unitID].healthbar = this->units[unitID].healthPercentage / 10; + if (_unitType == OpenSHC::Map::Units::UT_BREWER || _unitType == OpenSHC::Map::Units::UT_TANNER + || _unitType == OpenSHC::Map::Units::UT_LADY || _unitType == OpenSHC::Map::Units::UT_MOTHER + || (_unitType == OpenSHC::Map::Units::UT_CHILD && (this->units[unitID].spriteID == 0x81))) { + _usesFemaleDeathScream = 1; + } + bool _shootingUnitID = this->units[_entityShootingUnitID_2].unitType == OpenSHC::Map::Units::UT_A_SLINGER; + if ((_unitHealth < 1) && (this->units[unitID].dying == 0)) { + this->units[unitID].dying = 1; + if (0 < _unknown) { + DAT_TribesState::instance.tribes[_unknown].field133_0x278 = 1; + } + this->units[unitID].animationCycleNumber = 0; + _entityType = DAT_EntityState::instance.entityArray[entityID].entityType; + if (_entityType == OpenSHC::Map::Entities::ET_COW_FLYING) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_STONE_DEATH_01; + } else { + this->units[unitID].state.generic = _entityType == OpenSHC::Map::Entities::ET_SLINGER + ? OpenSHC::Map::Units::States::US_STONE_DEATH_01 + : (UnitState)(OpenSHC::Map::Units::States::US_STONE_DEATH_01 - 3); + } + /* read before the write below, which the original also ordered this way */ + byte _wasStalked = this->units[unitID].isStalked; + this->units[unitID].tunnelerFinishedDigging = 1; + if (_wasStalked == 0) { + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_MANGONEL: + case OpenSHC::Map::Units::UT_S_TOWER: + case OpenSHC::Map::Units::UT_S_BATTERINGRAM: + case OpenSHC::Map::Units::UT_S_BALLISTA: + case OpenSHC::Map::Units::UT_S_FBALLISTA: + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_SIEGE_DIE; + break; + case OpenSHC::Map::Units::UT_S_TREBUCHET: + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + (int)this->units[unitID].x, (int)(this->units[unitID].y), OpenSHC::DE::SHCDE::FX_TR_DIE); + break; + case OpenSHC::Map::Units::UT_S_SHIELD: + if ((this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300 + != 0) + && (!_shootingUnitID)) { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_DEATH_ARROW; + break; + } + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_SIEGE_DIE; + break; + } + if (_usesFemaleDeathScream) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unitID].x, this->units[unitID].y, OpenSHC::DE::SHCDE::FX_GIRL_DIE); + if (_shootingUnitID) { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_HIT_SLINGSTONE; + } else { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_ARROW_HIT; + } + } else if (!_shootingUnitID) { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_DEATH_ARROW; + } else { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_DEATH_SLINGSTONE; + } + } else if (_shootingUnitID) { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_HIT_SLINGSTONE; + } else { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_ARROW_HIT_ANIMAL; + } + } else { + if (this->units[unitID].isStalked != 0) { + if (_shootingUnitID) { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_HIT_SLINGSTONE; + } else { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_ARROW_HIT_ANIMAL; + } + } else { + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_TREBUCHET: + case OpenSHC::Map::Units::UT_S_MANGONEL: + case OpenSHC::Map::Units::UT_S_TOWER: + case OpenSHC::Map::Units::UT_S_BATTERINGRAM: + case OpenSHC::Map::Units::UT_S_BALLISTA: + case OpenSHC::Map::Units::UT_S_FBALLISTA: + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_WOOD_HIT; + break; + default: { + uint _hitSoundVariant = this->units[unitID].fixedRng & 7; + if (_hitSoundVariant != 0) { + if (_hitSoundVariant == 1) { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT2; + break; + } + if (_hitSoundVariant == 2) { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT3; + break; + } + if (_hitSoundVariant == 3) { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT4; + break; + } + if (_hitSoundVariant == 4) { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT5; + } else { + if (_hitSoundVariant == 5) { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT6; + break; + } + if (_hitSoundVariant == 6) { + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT7; + break; + } + if (_hitSoundVariant != 7) { + return TRUE; + } + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT8; + } + break; + } + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT; + break; + } + case OpenSHC::Map::Units::UT_LORD: + return TRUE; + case OpenSHC::Map::Units::UT_S_SHIELD: + if (this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300 + < 1) { + return TRUE; + } + sfxOffsetInArray = OpenSHC::DE::SHCDE::FX_BODY_HIT2; + break; + } + } + } + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + _unitXPosition_2, _unitYPosition_2, sfxOffsetInArray); + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/processFireDamageToUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/processFireDamageToUnit.cpp new file mode 100644 index 000000000..af551a3ea --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/processFireDamageToUnit.cpp @@ -0,0 +1,126 @@ +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/DE/SHCDE/eSFX.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::DE::SHCDE::eSFX; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00532460 + undefined4 UnitsState::processFireDamageToUnit(int unitID, int playerID, int halfTheDamage) + { + if (unitID <= 0) { + return 0; + } + if (this->units[unitID].dying != 0) { + return 0; + } + UnitTypeShort _unitType = this->units[unitID].unitType; + uint _damage; + if (_unitType == OpenSHC::Map::Units::UT_LORD) { + _damage = 25; + } else if (_unitType == OpenSHC::Map::Units::UT_FIREFIGHTER) { + _damage = 1; + } else if (_unitType == OpenSHC::Map::Units::UT_A_FIRETHROWER) { + _damage = 10; + } else { + _damage = 100; + } + if (halfTheDamage != 0) { + _damage = _damage / 2; + } + if (playerID != 0 && playerID != this->units[unitID].owner) { + this->units[unitID].lastEncounteredEnemyPlayerID = (short)playerID; + this->units[unitID].lastEncounteredEnemyUnitIDUnk = 0; + } + this->units[unitID].health = this->units[unitID].health - _damage; + if (this->units[unitID].health <= 0) { + this->units[unitID].health = 0; + } + if (this->units[unitID].maxHealth == 0) { + this->units[unitID].healthPercentage = 100; + } else { + this->units[unitID].healthPercentage + = (short)((this->units[unitID].health * 100) / this->units[unitID].maxHealth); + } + this->units[unitID].healthbar = this->units[unitID].healthPercentage / 10; + if (this->units[unitID].health > 0) { + return 1; + } + this->units[unitID].animationCycleNumber = 0; + this->units[unitID].field323_0x442 = 1; + if (_unitType == OpenSHC::Map::Units::UT_LORD) { + this->units[unitID].dying = 1; + this->units[unitID].tunnelerFinishedDigging = 1; + this->units[unitID].health = 0; + this->units[unitID].animationCycleNumber = 0; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_STONE_DEATH_01; + return 1; + } + this->units[unitID].logicalState = OpenSHC::Map::Units::ULS_TRANSITIONING; + this->units[unitID].state_2 = 0; + switch (_unitType) { + case OpenSHC::Map::Units::UT_ANTELOPESHDEER: + if (this->units[unitID].antelopeBasedRngValue == 2) { + this->units[unitID].unitTypeToChangeInto = OpenSHC::Map::Units::UT_BURNING_ANIMAL_SMALL; + this->units[unitID].state_2 = 1; + break; + } + this->units[unitID].unitTypeToChangeInto = OpenSHC::Map::Units::UT_BURNING_ANIMAL_BIG; + this->units[unitID].state_2 = 1; + break; + case OpenSHC::Map::Units::UT_QUARRYOX: + case OpenSHC::Map::Units::UT_LIONSHWOLF: + case OpenSHC::Map::Units::UT_CAMELSHBEAR: + case OpenSHC::Map::Units::UT_COW: + case OpenSHC::Map::Units::UT_CAGEDOG: + this->units[unitID].unitTypeToChangeInto = OpenSHC::Map::Units::UT_BURNING_ANIMAL_BIG; + this->units[unitID].state_2 = 1; + break; + case OpenSHC::Map::Units::UT_RABBIT: + case OpenSHC::Map::Units::UT_HUNTERDOG: + case OpenSHC::Map::Units::UT_CHICKEN: + this->units[unitID].unitTypeToChangeInto = OpenSHC::Map::Units::UT_BURNING_ANIMAL_SMALL; + this->units[unitID].state_2 = 1; + break; + default: + this->units[unitID].unitTypeToChangeInto = OpenSHC::Map::Units::UT_BURNINGMAN; + } + if (this->units[unitID].isStalked != 0) { + return 1; + } + /* if a male */ + if (_unitType != OpenSHC::Map::Units::UT_BREWER && _unitType != OpenSHC::Map::Units::UT_TANNER + && _unitType != OpenSHC::Map::Units::UT_LADY && _unitType != OpenSHC::Map::Units::UT_MOTHER + && (_unitType != OpenSHC::Map::Units::UT_CHILD || this->units[unitID].spriteID != 0x81)) { + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber1, SEC_RNG::ptr)(); + if (((byte)SEC_RNG::instance.currentNumber1 & 1) == 0) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unitID].x, this->units[unitID].y, OpenSHC::DE::SHCDE::FX_MAN_BURN2); + return 1; + } + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unitID].x, this->units[unitID].y, OpenSHC::DE::SHCDE::FX_MAN_BURN); + return 1; + } + /* if female */ + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unitID].x, this->units[unitID].y, OpenSHC::DE::SHCDE::FX_GIRL_SCREAM); + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/processMeleeInitiation.cpp b/src/OpenSHC/Map/Units/UnitsState/processMeleeInitiation.cpp new file mode 100644 index 000000000..8fd32b608 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/processMeleeInitiation.cpp @@ -0,0 +1,580 @@ +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_MinimapViewState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00549C70 + void UnitsState::processMeleeInitiation(int unitID) + + { + int _neighbourHeights[8]; + int _totalHeight; + uint* _occupancyRow; + int _adjacentTiles[24]; + int _otherUnitID; + if (this->units[unitID].someUnitStat2_meleeDamageUnk != 0 && this->units[unitID].unknownTestAgainst0_2 == 0 + && this->units[unitID].unknownMovementRelated_0x2d2 == 0 + && this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL && this->units[unitID].dying == 0 + && this->units[unitID].moveRelatedFlag != 1) { + int _distanceThreshold; + if (this->units[unitID].stateBasedSpeed <= 0) { + /* + 50 or 150 depending on selectable + */ + + if (this->units[unitID].isSelectable_OR_matchTime != 0) { + _distanceThreshold = 150; + } else { + _distanceThreshold = 50; + } + } else { + _distanceThreshold = 270; + } + if (this->units[unitID].closestEnemyMicroDistance <= _distanceThreshold + || this->units[unitID].attackedUnitID != 0 + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_LIONSHWOLF + || (this->units[unitID].isStalked != 0 + && (((DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY + || (100 < (int)this->unitCount)) + && (((this->units[unitID].fixedRng ^ DAT_GameState::instance.mapAndTime.totalGameTicksUnk) + & 0xf) + == 0))))) { + _totalHeight + = (int)this->units[unitID].buildingHeight + (int)this->units[unitID].terrainOrClimbHeight; + int _playerID = (int)this->units[unitID].owner; + DAT_TileMapState::instance.DAT_SomeTile = this->units[unitID].tile; + DAT_TileMapState::instance.DAT_SomeY + = (int)DAT_ViewportRenderState::instance + .tileTranslationMatrix_YComponent[DAT_TileMapState::instance.DAT_SomeTile]; + int _hasEnemyOnOwnTile = 0; + uint _teamBitFlags = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::teamToBitFlagsUnk, DAT_GameState::ptr)(unitID); + uint _enemyNeighbourFlags = 0; + if ((*(uint*)((uchar*)DAT_TileMapState::instance.ptr_OccupancyLayer + + DAT_TileMapState::instance.DAT_SomeTile + 1) + & _teamBitFlags) + != 0) { + _enemyNeighbourFlags = 0x20; + } + if ((*(uint*)((uchar*)DAT_TileMapState::instance.ptr_OccupancyLayer + + DAT_TileMapState::instance.DAT_SomeTile + -1) + & _teamBitFlags) + != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 2; + } + if ((*(uint*)((uchar*)DAT_TileMapState::instance.ptr_OccupancyLayer + + DAT_TileMapState::instance.DAT_SomeTile + 2) + & _teamBitFlags) + != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x80000; + } + if ((*(uint*)((uchar*)DAT_TileMapState::instance.ptr_OccupancyLayer + + DAT_TileMapState::instance.DAT_SomeTile + -2) + & _teamBitFlags) + != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x800; + } + _occupancyRow = (uint*)((uchar*)DAT_TileMapState::instance.ptr_OccupancyLayer + + *(int*)((uchar*)DAT_TileMapState::instance.ptr_MovementDirectionTranslationMatrix + + DAT_TileMapState::instance.DAT_SomeY * 0x20) + + DAT_TileMapState::instance.DAT_SomeTile); + if ((*(uint*)((int)_occupancyRow + -1) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 1; + } + if ((*(uint*)((int)_occupancyRow + 1) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x40; + } + if ((*_occupancyRow & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x80; + } + if ((*(uint*)((int)_occupancyRow + -2) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x400; + } + if ((*(uint*)((int)_occupancyRow + 2) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x100000; + } + _occupancyRow = (uint*)((uchar*)DAT_TileMapState::instance.ptr_OccupancyLayer + + *(int*)((int)((uchar*)DAT_TileMapState::instance.ptr_MovementDirectionTranslationMatrix + + DAT_TileMapState::instance.DAT_SomeY * 0x20) + + 0x10) + + DAT_TileMapState::instance.DAT_SomeTile); + if ((*(uint*)((int)_occupancyRow + -1) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 4; + } + if ((*(uint*)((int)_occupancyRow + 1) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x10; + } + if ((*_occupancyRow & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 8; + } + if ((*(uint*)((int)_occupancyRow + -2) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x1000; + } + if ((*(uint*)((int)_occupancyRow + 2) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x40000; + } + _occupancyRow = (uint*)((uchar*)DAT_TileMapState::instance.ptr_OccupancyLayer + + *(int*)((uchar*)DAT_TileMapState::instance.ptr_MovementDirectionTranslationMatrix + + DAT_TileMapState::instance.DAT_SomeY * 0x20 + -0x20) + + *(int*)((uchar*)DAT_TileMapState::instance.ptr_MovementDirectionTranslationMatrix + + DAT_TileMapState::instance.DAT_SomeY * 0x20) + + DAT_TileMapState::instance.DAT_SomeTile); + if ((*(uint*)((int)_occupancyRow + -1) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x100; + } + if ((*(uint*)((int)_occupancyRow + 1) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x400000; + } + if ((*_occupancyRow & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x800000; + } + if ((*(uint*)((int)_occupancyRow + -2) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x200; + } + if ((*(uint*)((int)_occupancyRow + 2) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x200000; + } + _occupancyRow = (uint*)((uchar*)DAT_TileMapState::instance.ptr_OccupancyLayer + + *(int*)((uchar*)DAT_TileMapState::instance.ptr_MovementDirectionTranslationMatrix + + DAT_TileMapState::instance.DAT_SomeY * 0x20 + 0x30) + + *(int*)((uchar*)DAT_TileMapState::instance.ptr_MovementDirectionTranslationMatrix + + DAT_TileMapState::instance.DAT_SomeY * 0x20 + 0x10) + + DAT_TileMapState::instance.DAT_SomeTile); + if ((*(uint*)((int)_occupancyRow + -1) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x4000; + } + if ((*(uint*)((int)_occupancyRow + 1) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x10000; + } + if ((*_occupancyRow & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x8000; + } + if ((*(uint*)((int)_occupancyRow + -2) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x2000; + } + if ((*(uint*)((int)_occupancyRow + 2) & _teamBitFlags) != 0) { + _enemyNeighbourFlags = _enemyNeighbourFlags | 0x20000; + } + DAT_TileMapState::instance.field213_0x554a48 = _enemyNeighbourFlags; + for (_otherUnitID + = (short)DAT_TileMapState::instance.UnitLayer[DAT_TileMapState::instance.DAT_SomeTile]; + _otherUnitID > 0; _otherUnitID = (short)this->units[_otherUnitID].nextUnitOnTheSameTile) { + if (_otherUnitID != unitID) { + bool _isFriendly; + if (this->units[unitID].owner == 0) { + _isFriendly = this->units[unitID].unitType == this->units[_otherUnitID].unitType; + } else { + _isFriendly = DAT_GameState::instance.mapAndTime.playerTeams[_playerID] + == DAT_GameState::instance.mapAndTime.playerTeams[this->units[_otherUnitID].owner]; + } + if (!_isFriendly) { + _hasEnemyOnOwnTile = 1; + break; + } + } + } + if ((DAT_TileMapState::instance.field213_0x554a48 != 0) || (_hasEnemyOnOwnTile != 0)) { + for (int i = 0; i < 24; ++i) { + _adjacentTiles[i] = 0; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 1) != 0) { + _adjacentTiles[0] = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][7] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 2) != 0) { + _adjacentTiles[1] = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][6] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 4) != 0) { + _adjacentTiles[2] = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][5] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 8) != 0) { + _adjacentTiles[3] = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][4] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x10) != 0) { + _adjacentTiles[4] = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][3] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x20) != 0) { + _adjacentTiles[5] = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][2] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x40) != 0) { + _adjacentTiles[6] = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][1] + + this->units[unitID].tile; + } + if ((char)DAT_TileMapState::instance.field213_0x554a48 < '\0') { + _adjacentTiles[7] = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][0] + + this->units[unitID].tile; + } + _neighbourHeights[0] = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)( + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][7] + + this->units[unitID].tile); + _neighbourHeights[1] = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)( + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][6] + + this->units[unitID].tile); + _neighbourHeights[2] = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)( + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][5] + + this->units[unitID].tile); + _neighbourHeights[3] = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)( + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][4] + + this->units[unitID].tile); + _neighbourHeights[4] = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)( + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][3] + + this->units[unitID].tile); + _neighbourHeights[5] = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)( + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][2] + + this->units[unitID].tile); + _neighbourHeights[6] = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)( + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][1] + + this->units[unitID].tile); + _neighbourHeights[7] = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)( + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][0] + + this->units[unitID].tile); + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x100) != 0) { + _adjacentTiles[8] = DAT_MinimapViewState::instance + .spawnMoment[DAT_TileMapState::instance.DAT_SomeY * 8 + 0x14] + + this->units[unitID].tile + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][0]; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x200) != 0) { + _adjacentTiles[9] = DAT_MinimapViewState::instance + .spawnMoment[DAT_TileMapState::instance.DAT_SomeY * 8 + 0x13] + + DAT_MinimapViewState::instance + .spawnMoment[DAT_TileMapState::instance.DAT_SomeY * 8 + 0x14] + + this->units[unitID].tile + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][0]; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x400) != 0) { + _adjacentTiles[10] + = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][6] + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][7] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x800) != 0) { + _adjacentTiles[0xb] = this->units[unitID].tile + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][6] + * 2; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x1000) != 0) { + _adjacentTiles[0xc] + = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][5] + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][6] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x2000) != 0) { + _adjacentTiles[0xd] + = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY + 1][6] + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY + 1][5] + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][4] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x4000) != 0) { + _adjacentTiles[0xe] + = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY + 1][5] + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][4] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x8000) != 0) { + _adjacentTiles[0xf] + = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY + 1][4] + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][4] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x10000) != 0) { + _adjacentTiles[0x10] + = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY + 1][3] + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][4] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x20000) != 0) { + _adjacentTiles[0x11] + = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY + 1][2] + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY + 1][3] + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][4] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x40000) != 0) { + _adjacentTiles[0x12] + = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][2] + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][3] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x80000) != 0) { + _adjacentTiles[0x13] = this->units[unitID].tile + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][2] + * 2; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x100000) != 0) { + _adjacentTiles[0x14] + = DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][1] + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][2] + + this->units[unitID].tile; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x200000) != 0) { + _adjacentTiles[0x15] = DAT_MinimapViewState::instance + .spawnMoment[DAT_TileMapState::instance.DAT_SomeY * 8 + 0xe] + + DAT_MinimapViewState::instance + .spawnMoment[DAT_TileMapState::instance.DAT_SomeY * 8 + 0xf] + + this->units[unitID].tile + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][0]; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x400000) != 0) { + _adjacentTiles[0x16] = DAT_MinimapViewState::instance + .spawnMoment[DAT_TileMapState::instance.DAT_SomeY * 8 + 0xe] + + this->units[unitID].tile + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][0]; + } + if ((DAT_TileMapState::instance.field213_0x554a48 & 0x800000) != 0) { + _adjacentTiles[0x17] = DAT_MinimapViewState::instance + .spawnMoment[DAT_TileMapState::instance.DAT_SomeY * 8 + 0xd] + + this->units[unitID].tile + + DAT_TileMapState::instance + .directionTranslationMatrix[DAT_TileMapState::instance.DAT_SomeY][0]; + } + if (this->units[unitID].attackedUnitID != 0) { + _otherUnitID = this->units[unitID].attackedUnitID; + if (this->units[_otherUnitID].uid == this->units[unitID].field191_0x340 + && this->units[_otherUnitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[_otherUnitID].dying == 0) { + /* -- CHECK 24 TILES AROUND UNIT -- is the unit we already fight still in reach? */ + for (int _slot = -1; _slot < 24; ++_slot) { + int _candidateTile; + if (_slot == -1) { + if (_hasEnemyOnOwnTile == 0) { + continue; + } + _candidateTile = this->units[unitID].tile; + } else { + _candidateTile = _adjacentTiles[DAT_UnitPropertiesDefinedData::instance + .field117_0x11cf4[this->units[unitID].facingDirection][_slot]]; + } + if (_candidateTile == 0) { + continue; + } + int _heightDelta = _totalHeight + - MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, + DAT_TileMapState::ptr)(_candidateTile); + if (_heightDelta < 0) { + _heightDelta = -_heightDelta; + } + if (_heightDelta >= 0x20) { + continue; + } + if (_otherUnitID + == MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getEnemyUnitIDNearby, + this)(unitID, _candidateTile, _totalHeight)) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::setFacingDirectionTowardUnitMicro, + this)(unitID, _otherUnitID); + if (this->units[unitID].state.generic + != OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + if (this->units[unitID].movementRelated == 8) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func:: + saveUnitStateBeforeInterruption, + this)(unitID); + this->units[unitID].movementRelated = 8; + this->units[unitID].state.generic + = OpenSHC::Map::Units::States::US_MELEE_ATTACK; + this->units[unitID].SA = 0; + this->units[unitID].animationCycleNumber = 0; + this->units[DAT_CurrentUnitSlotID::instance].substate = 0; + } else { + this->units[unitID].field259_0x3d2 = 1; + } + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::processUnitAttackOtherUnit, this)( + DAT_CurrentUnitSlotID::instance, this->units[unitID].attackedUnitID); + return; + } + } + } + this->units[unitID].attackedUnitID = 0; + this->units[unitID].field191_0x340 = 0; + this->units[unitID].field259_0x3d2 = 0; + } + /* -- CHECK 24 TILES AROUND UNIT -- look for someone new to fight */ + for (int _slot = -1; _slot < 24; ++_slot) { + int _candidateTile; + int _tileSlot; + if (_slot == -1) { + if (_hasEnemyOnOwnTile == 0) { + continue; + } + _tileSlot = this->units[unitID].facingDirection; + _candidateTile = this->units[unitID].tile; + } else { + _tileSlot = DAT_UnitPropertiesDefinedData::instance + .field117_0x11cf4[this->units[unitID].facingDirection][_slot]; + _candidateTile = _adjacentTiles[_tileSlot]; + } + if (_candidateTile == 0) { + continue; + } + if (_tileSlot >= 8) { + int _firstHeightDelta = _totalHeight + - _neighbourHeights + [DAT_UnitPropertiesDefinedData::instance.field118_0x12054[_tileSlot].x]; + if (_firstHeightDelta < 0) { + _firstHeightDelta = -_firstHeightDelta; + } + if (_firstHeightDelta >= 0x21) { + continue; + } + int _secondHeightIndex + = DAT_UnitPropertiesDefinedData::instance.field118_0x12054[_tileSlot].y; + if (_secondHeightIndex != -1) { + int _secondHeightDelta = _totalHeight - _neighbourHeights[_secondHeightIndex]; + if (_secondHeightDelta < 0) { + _secondHeightDelta = -_secondHeightDelta; + } + if (_secondHeightDelta >= 0x21) { + continue; + } + } + } + _otherUnitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getEnemyUnitIDNearby, + this)(unitID, _candidateTile, _totalHeight); + if (_otherUnitID <= 0) { + continue; + } + if (this->units[_otherUnitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[_otherUnitID].dying != 0) { + continue; + } + int _targetHeightDelta = (_totalHeight - this->units[_otherUnitID].buildingHeight) + - this->units[_otherUnitID].terrainOrClimbHeight; + if (_targetHeightDelta < 0) { + _targetHeightDelta = -_targetHeightDelta; + } + if (_targetHeightDelta >= 0x21) { + continue; + } + if ((this->units[unitID].unitType == OpenSHC::Map::Units::UT_LIONSHWOLF + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_CAGEDOG) + && this->units[_otherUnitID].isStalked != 0 && _slot >= 8) { + continue; + } + this->units[unitID].attackedUnitID = (short)_otherUnitID; + this->units[unitID].field191_0x340 = this->units[_otherUnitID].uid; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setFacingDirectionTowardUnitMicro, + this)(unitID, _otherUnitID); + break; + } + if (this->units[unitID].attackedUnitID != 0) { + if (this->units[_otherUnitID].someUnitStat2_meleeDamageUnk != 0 + && this->units[_otherUnitID].attackedUnitID == 0 + && this->units[_otherUnitID].unknownMovementRelated_0x2d2 == 0) { + this->units[_otherUnitID].attackedUnitID = (short)unitID; + this->units[_otherUnitID].field191_0x340 = this->units[unitID].uid; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::setFacingDirectionTowardUnitMicro, this)( + _otherUnitID, unitID); + } + if (this->units[unitID].state.generic != OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + if (this->units[unitID].movementRelated == 8) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::saveUnitStateBeforeInterruption, this)( + unitID); + this->units[unitID].movementRelated = 8; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_MELEE_ATTACK; + this->units[unitID].SA = 0; + this->units[unitID].animationCycleNumber = 0; + this->units[DAT_CurrentUnitSlotID::instance].substate = 0; + } else { + this->units[unitID].field259_0x3d2 = 1; + } + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::processUnitAttackOtherUnit, this)( + DAT_CurrentUnitSlotID::instance, this->units[unitID].attackedUnitID); + return; + } + this->units[unitID].field259_0x3d2 = 0; + this->units[unitID].attackedUnitID = 0; + this->units[unitID].field191_0x340 = 0; + return; + } + } + this->units[unitID].field191_0x340 = 0; + this->units[unitID].attackedUnitID = 0; + this->units[unitID].field259_0x3d2 = 0; + } + } + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/processUnitAttackOtherUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/processUnitAttackOtherUnit.cpp new file mode 100644 index 000000000..bb7e9cc25 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/processUnitAttackOtherUnit.cpp @@ -0,0 +1,332 @@ +#include "OpenSHC/Audio/MSS/SoundSystem.func.hpp" +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Audio/SFX/SoundEffectID.hpp" +#include "OpenSHC/DE/SHCDE/eSFX.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/DAT_SoundSystemState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Audio::SFX::SoundEffectID; + using OpenSHC::DE::SHCDE::eSFX; + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00531220 + undefined4 UnitsState::processUnitAttackOtherUnit(int unitID, int unit2ID) + { + int _tribeID = this->units[unit2ID].tribeID; + UnitTypeShort _unit2Type = this->units[unit2ID].unitType; + /* get the damage from the array based: row is unit1ID type, column is unit2ID type */ + int _damage = DAT_UnitPropertiesDefinedData::instance + .MELEE_DAMAGE[(short)this->units[unitID].unitType][(short)_unit2Type]; + /* if unit 1 is not a lord */ + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_LORD) { + _damage = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::computeDamageFearFactorBonus, this)( + _damage, DAT_UnitsState::instance.units[unitID].owner); + } + if (this->units[unitID].owner != 0 && this->units[unit2ID].owner != this->units[unitID].owner) { + this->units[unit2ID].lastEncounteredEnemyPlayerID = this->units[unitID].owner; + /* let unit 2 know we attacked them? */ + this->units[unit2ID].lastEncounteredEnemyUnitIDUnk = (short)unitID; + } + /* decrement the health of unit 2 by damage */ + this->units[unit2ID].health = this->units[unit2ID].health - _damage; + if (this->units[unit2ID].health <= 0) { + this->units[unit2ID].health = 0; + } + /* compute the health bar in percentages */ + short _healthPercentage; + if (this->units[unit2ID].maxHealth == 0) { + _healthPercentage = 100; + } else { + _healthPercentage = (short)((this->units[unit2ID].health * 100) / this->units[unit2ID].maxHealth); + } + this->units[unit2ID].healthPercentage = _healthPercentage; + this->units[unit2ID].healthbar = _healthPercentage / 10; + if (this->units[unit2ID].health <= 0 && this->units[unit2ID].isStalked != 0) { + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_WOODCUTTER: + case OpenSHC::Map::Units::UT_LORD: + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unitID].x, this->units[unitID].y, OpenSHC::DE::SHCDE::FX_LORD_HIT); + break; + case OpenSHC::Map::Units::UT_E_SPEAR: + case OpenSHC::Map::Units::UT_A_ARCHER: + case OpenSHC::Map::Units::UT_A_SLINGER: + case OpenSHC::Map::Units::UT_A_HARCHER: + case OpenSHC::Map::Units::UT_A_FIRETHROWER: + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unitID].x, this->units[unitID].y, OpenSHC::DE::SHCDE::FX_SPEAR_HIT); + break; + case OpenSHC::Map::Units::UT_E_PIKE: + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unitID].x, this->units[unitID].y, OpenSHC::DE::SHCDE::FX_PIKE_HIT); + break; + case OpenSHC::Map::Units::UT_E_MACE: + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unitID].x, this->units[unitID].y, OpenSHC::DE::SHCDE::FX_MACE_HIT); + break; + case OpenSHC::Map::Units::UT_E_SWORD: + case OpenSHC::Map::Units::UT_E_KNIGHT: + case OpenSHC::Map::Units::UT_A_ASSASSIN: + case OpenSHC::Map::Units::UT_A_SWORDSMAN: + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unitID].x, this->units[unitID].y, OpenSHC::DE::SHCDE::FX_SWORD_HIT); + break; + } + } + if (this->units[unit2ID].health > 0) { + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY + && this->units[unit2ID].owner == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXWeAreUnderAttack, DAT_SFXState::ptr)(); + } + return 0; + } + this->units[unit2ID].dying = 1; + if (_tribeID > 0) { + DAT_TribesState::instance.tribes[_tribeID].field133_0x278 = 1; + } + this->units[unit2ID].animationCycleNumber = 0; + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_E_SWORD) { + this->units[unit2ID].state.generic = OpenSHC::Map::Units::States::US_DEATH_03; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_E_KNIGHT) { + this->units[unit2ID].state.generic = OpenSHC::Map::Units::States::US_DEATH_03; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_E_SPEAR) { + this->units[unit2ID].state.generic = OpenSHC::Map::Units::States::US_DEATH_03; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_E_PIKE) { + this->units[unit2ID].state.generic = OpenSHC::Map::Units::States::US_DEATH_03; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_E_XBOW) { + this->units[unit2ID].state.generic = OpenSHC::Map::Units::States::US_DEATH_03; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_E_ARCHER) { + this->units[unit2ID].state.generic = OpenSHC::Map::Units::States::US_DEATH_03; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_A_ARCHER) { + this->units[unit2ID].state.generic = OpenSHC::Map::Units::States::US_DEATH_03; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_A_ASSASSIN) { + this->units[unit2ID].state.generic = OpenSHC::Map::Units::States::US_DEATH_03; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_A_HARCHER) { + this->units[unit2ID].state.generic = OpenSHC::Map::Units::States::US_DEATH_03; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_A_SWORDSMAN) { + this->units[unit2ID].state.generic = OpenSHC::Map::Units::States::US_DEATH_03; + } else { + this->units[unit2ID].state.generic + = (this->units[unitID].unitType != OpenSHC::Map::Units::UT_A_FIRETHROWER) + + OpenSHC::Map::Units::States::US_DEATH_03; + } + uint _deathVariant = this->units[unit2ID].fixedRng & 1; + this->units[unit2ID].tunnelerFinishedDigging = 1; + if (this->units[unit2ID].isStalked != 0) { + return 1; + } + switch (_unit2Type) { + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_MANGONEL: + case OpenSHC::Map::Units::UT_S_TOWER: + case OpenSHC::Map::Units::UT_S_BATTERINGRAM: + case OpenSHC::Map::Units::UT_S_BALLISTA: + case OpenSHC::Map::Units::UT_S_FBALLISTA: + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_SIEGE_DIE); + return 1; + case OpenSHC::Map::Units::UT_S_TREBUCHET: + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_TR_DIE); + return 1; + case OpenSHC::Map::Units::UT_S_SHIELD: + if (this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300 > 0) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_BODY_HIT); + return 1; + } + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_SIEGE_DIE); + return 1; + } + bool _hasSpecialDeathSound = false; + if (_unit2Type == OpenSHC::Map::Units::UT_BREWER || _unit2Type == OpenSHC::Map::Units::UT_TANNER + || _unit2Type == OpenSHC::Map::Units::UT_LADY || _unit2Type == OpenSHC::Map::Units::UT_MOTHER + || (_unit2Type == OpenSHC::Map::Units::UT_CHILD && this->units[unitID].spriteID == 0x81)) { + _hasSpecialDeathSound = true; + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_GIRL_DIE); + } + if (_unit2Type == OpenSHC::Map::Units::UT_LORD) { + if (this->units[unit2ID].owner == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::setUpSFXToPlayUnk, DAT_SFXState::ptr)( + OpenSHC::Audio::SFX::SEID_PLAYER_LORD_DEATH); + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) { + MACRO_CALL_MEMBER( + OpenSHC::Audio::MSS::SoundSystem_Func::setSomeSoundTime, DAT_SoundSystemState::ptr)(); + } + } else { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::setUpSFXToPlayUnk, DAT_SFXState::ptr)( + OpenSHC::Audio::SFX::SEID_AI_LORD_DEATH); + } + _hasSpecialDeathSound = true; + } else if (_unit2Type == OpenSHC::Map::Units::UT_JESTER) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_JESTER_DIE); + _hasSpecialDeathSound = true; + } + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_WOODCUTTER: + if (_hasSpecialDeathSound) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_LORD_HIT); + return 1; + } + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_LORD_KILL); + return 1; + case OpenSHC::Map::Units::UT_E_SPEAR: + case OpenSHC::Map::Units::UT_A_ARCHER: + case OpenSHC::Map::Units::UT_A_SLINGER: + case OpenSHC::Map::Units::UT_A_HARCHER: + case OpenSHC::Map::Units::UT_A_FIRETHROWER: + if (_hasSpecialDeathSound) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_SPEAR_HIT); + return 1; + } + if (_deathVariant == 0) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_DEATH_SPEAR); + return 1; + } + if (_deathVariant == 1) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_DEATH_SPEAR2); + return 1; + } + return 1; + case OpenSHC::Map::Units::UT_E_PIKE: + if (_hasSpecialDeathSound) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_PIKE_HIT); + return 1; + } + if (_deathVariant == 0) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_DEATH_SPEAR); + return 1; + } + if (_deathVariant == 1) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_DEATH_SPEAR2); + return 1; + } + return 1; + case OpenSHC::Map::Units::UT_E_MACE: + if (_hasSpecialDeathSound) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_MACE_HIT); + return 1; + } + if (_deathVariant == 0) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_DEATH_CLUB); + return 1; + } + if (_deathVariant == 1) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_DEATH_CLUB2); + return 1; + } + return 1; + case OpenSHC::Map::Units::UT_E_SWORD: + case OpenSHC::Map::Units::UT_E_KNIGHT: + case OpenSHC::Map::Units::UT_A_ASSASSIN: + case OpenSHC::Map::Units::UT_A_SWORDSMAN: + if (_hasSpecialDeathSound) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_SWORD_HIT); + return 1; + } + if (_deathVariant == 0) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_DEATH_SWORD); + return 1; + } + if (_deathVariant == 1) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_DEATH_SWORD2); + return 1; + } + return 1; + case OpenSHC::Map::Units::UT_LORD: + if (_hasSpecialDeathSound) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_LORD_HIT); + return 1; + } + if (this->units[unitID].unknownLordTypeBasedMissionSpecificValue_01 == 0) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_LORD_KILL); + return 1; + } + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_ARAB_LORD_KILL); + return 1; + default: + if (_hasSpecialDeathSound) { + return 1; + } + if ((this->units[unit2ID].fixedRng & 7) == 0) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_BODY_HIT); + return 1; + } + if ((this->units[unit2ID].fixedRng & 7) == 1) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_BODY_HIT2); + return 1; + } + if ((this->units[unit2ID].fixedRng & 7) == 2) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_BODY_HIT3); + return 1; + } + if ((this->units[unit2ID].fixedRng & 7) == 3) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_BODY_HIT4); + return 1; + } + if ((this->units[unit2ID].fixedRng & 7) == 4) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_BODY_HIT5); + return 1; + } + if ((this->units[unit2ID].fixedRng & 7) == 5) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_BODY_HIT6); + return 1; + } + if ((this->units[unit2ID].fixedRng & 7) == 6) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_BODY_HIT7); + return 1; + } + if ((this->units[unit2ID].fixedRng & 7) == 7) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + this->units[unit2ID].x, this->units[unit2ID].y, OpenSHC::DE::SHCDE::FX_BODY_HIT8); + return 1; + } + return 1; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/processUnitMove.cpp b/src/OpenSHC/Map/Units/UnitsState/processUnitMove.cpp new file mode 100644 index 000000000..e4e268b93 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/processUnitMove.cpp @@ -0,0 +1,283 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00578C40 + undefined4 UnitsState::processUnitMove(int unitID, int speedCategory) + { + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_BURNINGMAN) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_A_ASSASSIN + && (this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_ASSASSIN_THROWING_HOOK + || this->units[unitID].state.generic + == OpenSHC::Map::Units::States::US_ASSASSIN_START_CLIMBING_DOWN + || this->units[unitID].state.generic == OpenSHC::Map::Units::States::US_ASSASSIN_CLIMBING_UP + || this->units[unitID].state.generic + == OpenSHC::Map::Units::States::US_ASSASSIN_CLIMBING_DOWN)) { + return 0; + } + if (this->units[unitID].dying != 0) { + return 0; + } + } + if (this->units[unitID].tunnelerFinishedDigging == 5) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setupUnitSharingCurrentTilePosition, this)( + unitID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::commitPendingUnitPosition, this)(unitID); + this->units[unitID].field39_0x58 = 0; + return 0; + } + if (this->units[unitID].tunnelerFinishedDigging != 4 && this->units[unitID].tunnelerFinishedDigging != 2) { + this->units[unitID].movementRelated = 8; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::updateMicroPosition, this)(unitID); + if (this->units[unitID].climbDataID != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::updateClimbing, this)(unitID) == FALSE) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, this->units[unitID].destinationX_2Unk, this->units[unitID].destinationY_2Unk, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::changeDestinationByLeftover, this)(unitID); + } + return 0; + } + this->units[unitID].field39_0x58 = 0; + if (this->units[unitID].moveInstructionSpeedDelayTracker != 0) { + this->units[unitID].moveInstructionSpeedDelayTracker + = this->units[unitID].moveInstructionSpeedDelayTracker - 1; + } + if (this->units[unitID].moveDelay < 2) { + this->units[unitID].moveDelay = 0; + } else { + this->units[unitID].moveDelay = this->units[unitID].moveDelay - 2; + } + int _steps = speedCategory + this->units[unitID].field259_0x3d2; + for (int _step = 0; _step <= _steps; ++_step) { + if (this->units[DAT_CurrentUnitSlotID::instance].field180_0x32d == '\x01') { + if (this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e < 4 + || this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e > 0xb) { + continue; + } + } else if (this->units[DAT_CurrentUnitSlotID::instance].field180_0x32d == '\x02') { + if (this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e <= 4) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e >= 10) { + if (this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e > 0xb) { + this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e = 3; + } + continue; + } + } + this->units[unitID].movementRelated = this->units[unitID].movementRelated + 1; + this->units[unitID].field105_0xe8 = 0; + if (this->units[unitID].movementRelated < 8) { + if (DAT_UnitPropertiesDefinedData::instance.field79_0x119cc[this->units[unitID].facingDirection] + <= this->units[unitID].movementRelated) { + this->units[unitID].field105_0xe8 = 1; + } + } else { + int _pathIndex = this->units[unitID].currentIndexInPathPlan; + if (this->units[unitID].totalSizeOfPathPlan <= (short)_pathIndex + && this->units[unitID].field280_0x3f4 == 0) { + this->units[unitID].unknownMovementRelated_0x2d2 = 0; + this->units[unitID].tunnelerFinishedDigging = 0; + this->units[unitID].movementRelated = 8; + this->units[unitID].destinationX_2Unk = this->units[unitID].x; + this->units[unitID].destinationY_2Unk = this->units[unitID].y; + return 0; + } + this->units[unitID].movementRelated = 0; + uint _direction = (char)this->units[unitID].pathPlanStart[(short)_pathIndex / 2]; + if ((_pathIndex & 1) == 0) { + _direction = _direction & 0xf; + } else { + _direction = (int)_direction >> 4; + } + this->units[unitID].facingDirection = (short)_direction; + if (this->units[unitID].field280_0x3f4 == 0) { + this->units[unitID].currentIndexInPathPlan = _pathIndex + 1; + } + if (this->units[unitID].field259_0x3d2 != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::saveUnitStateBeforeInterruption, this)( + unitID); + this->units[unitID].movementRelated = 8; + this->units[unitID].lookForEnemy = 0; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_MELEE_ATTACK; + this->units[unitID].SA = 0; + this->units[unitID].animationCycleNumber = 0; + return 0; + } + if (this->units[unitID].moveRelatedFlag != 1) { + if (this->units[unitID].field280_0x3f4 != 0 + || MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::doMoveFromTileToTile, + DAT_PathFindingState::ptr)(unitID, this->units[unitID].tile, this->units[unitID].y, + _direction, this->units[unitID].moveRelatedFlag, this->units[unitID].cannotClimb) + == FALSE) { + this->units[unitID].movementRelated = 8; + if (this->units[unitID].field280_0x3f4 > 0) { + this->units[unitID].field280_0x3f4 = this->units[unitID].field280_0x3f4 - 1; + if (this->units[unitID].field280_0x3f4 > 0) { + return 0; + } + } + this->unknownInitially0_01 = this->unknownInitially0_01 + 1; + int _destinationY = this->units[unitID].destinationYPosition; + int _destinationX = this->units[unitID].destinationXPosition; + bool _destinationReachable = false; + if (MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(_destinationX, _destinationY) + == FALSE) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func:: + makeUnitStopWalkingByClearingPathProgressState, + this)(unitID); + } else if ((short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_ViewportRenderState::instance + .translationMatrix[_destinationY] + .addXgetTile + + _destinationX] + != 0) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: + calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(this->units[unitID].owner, + (short)DAT_TileMapState::instance.PathConnectionLayer[this->units[unitID].tile], + (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_ViewportRenderState::instance + .translationMatrix[_destinationY] + .addXgetTile + + _destinationX], + 0) + != 0) { + _destinationReachable = true; + } + } + if (!_destinationReachable) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_LORD) { + return 0; + } + if (this->units[unitID].isSelectable_OR_matchTime != 0) { + return 0; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_CAGEDOG) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func:: + makeUnitStopWalkingByClearingPathProgressState, + this)(unitID); + return 0; + } + if (this->units[unitID].state.generic != OpenSHC::Map::Units::States::US_DISAPPEAR) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + this->units[unitID].updateTickTracker = 0; + return 0; + } + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + DAT_CurrentUnitSlotID::instance, this->units[unitID].destinationXPosition, + this->units[unitID].destinationYPosition, 0) + == FALSE) { + this->units[unitID].field280_0x3f4 = 0x28; + return 0; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::changeDestinationByLeftover, this)( + unitID); + return 0; + } + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::spawnCrowFromNearbyTree, + DAT_LandscapeState::ptr)(unitID); + } + this->units[unitID].currentTilePosition_2Unk = this->units[unitID].tile; + this->units[unitID].nextTileUnk + = DAT_TileMapState::instance.directionTranslationMatrix[this->units[unitID].y][_direction] + + this->units[unitID].tile; + this->units[unitID].mimicCurrentXPosition + = DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[_direction].short_.xOffset + + this->units[unitID].x; + this->units[unitID].mimicCurrentYPosition + = DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[_direction].short_.yOffset + + this->units[unitID].y; + this->units[unitID].microXPosition = this->units[unitID].x * 8 + 4; + this->units[unitID].microYPosition = this->units[unitID].y * 8 + 4; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setupUnitSharingCurrentTilePosition, this)( + unitID); + switch (this->units[unitID].facingDirection) { + case 0: + this->units[unitID].microYPosition = this->units[unitID].microYPosition - 1; + break; + case 1: + this->units[unitID].microYPosition = this->units[unitID].microYPosition - 1; + case 2: + this->units[unitID].microXPosition = this->units[unitID].microXPosition + 1; + break; + case 3: + this->units[unitID].microYPosition = this->units[unitID].microYPosition + 1; + this->units[unitID].microXPosition = this->units[unitID].microXPosition + 1; + break; + case 4: + this->units[unitID].microYPosition = this->units[unitID].microYPosition + 1; + break; + case 5: + this->units[unitID].microYPosition = this->units[unitID].microYPosition + 1; + case 6: + this->units[unitID].microXPosition = this->units[unitID].microXPosition - 1; + break; + case 7: + this->units[unitID].microYPosition = this->units[unitID].microYPosition - 1; + this->units[unitID].microXPosition = this->units[unitID].microXPosition - 1; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::commitPendingUnitPosition, this)(unitID); + if (this->units[unitID].field105_0xe8 == 0) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func:: + adjustUnitMapOrientationRelatedPositionBasedOnMapOrientationCorrectedFacingDirection, + this)(unitID); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::updateMicroPosition, this)(unitID); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageFromKillingPit, + DAT_BuildingsState::ptr)(unitID); + if (DAT_TileMapState::instance.BuildingLayer[this->units[unitID].tile] != 0 + && (DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance.BuildingLayer[this->units[unitID].tile]] + .buildingType + == OpenSHC::Map::Buildings::BT_TOWER1 + || DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance.BuildingLayer[this->units[unitID].tile]] + .buildingType + == OpenSHC::Map::Buildings::BT_TOWER4)) { + DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance.BuildingLayer[this->units[unitID].tile]] + .hasUnitsOntop = 1; + DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance.BuildingLayer[this->units[unitID].tile]] + .field261_0x2fa = 100; + } + } + this->units[unitID].field105_0xe8 = 0; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::updateUnitFadeAndVisibilityNearStructures, this)(unitID); + } + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/queueClickNavigateMenuOrEscape.cpp b/src/OpenSHC/Map/Units/UnitsState/queueClickNavigateMenuOrEscape.cpp new file mode 100644 index 000000000..98c159d54 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/queueClickNavigateMenuOrEscape.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536CC0 + void UnitsState::queueClickNavigateMenuOrEscape(undefined4 param_1) + { + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = 0xfffffffe; + DAT_GameSynchronyState::instance.DAT_GameCommandParam1 = param_1; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + OpenSHC::Commands::GCT_ESCAPE); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand2Params.cpp b/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand2Params.cpp new file mode 100644 index 000000000..83cf8e590 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand2Params.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537100 + void UnitsState::queueDisbandAndAttackCommand2Params(undefined4 param_1, undefined4 param_2) + { + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = param_1; + DAT_GameSynchronyState::instance.DAT_GameCommandParam1 = param_2; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + OpenSHC::Commands::GCT_DISBAND_AND_ATTACK_UNITS); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand3Params.cpp b/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand3Params.cpp new file mode 100644 index 000000000..0f4ff200d --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand3Params.cpp @@ -0,0 +1,25 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537130 + void UnitsState::queueDisbandAndAttackCommand3Params(undefined4 param_1, undefined4 param_2, undefined4 param_3) + { + DAT_GameSynchronyState::instance.DAT_GameCommandParam1 = param_2; + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = param_1; + DAT_GameSynchronyState::instance.DAT_GameCommandParam2 = param_3; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + OpenSHC::Commands::GCT_DISBAND_AND_ATTACK_UNITS); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand4Params.cpp b/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand4Params.cpp new file mode 100644 index 000000000..b684a7927 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand4Params.cpp @@ -0,0 +1,27 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537160 + void UnitsState::queueDisbandAndAttackCommand4Params( + undefined4 param_1, undefined4 param_2, undefined4 param_3, undefined4 param_4) + { + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = param_1; + DAT_GameSynchronyState::instance.DAT_GameCommandParam1 = param_2; + DAT_GameSynchronyState::instance.DAT_GameCommandParam2 = param_3; + DAT_GameSynchronyState::instance.DAT_GameCommandParam3 = param_4; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + OpenSHC::Commands::GCT_DISBAND_AND_ATTACK_UNITS); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand5Params.cpp b/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand5Params.cpp new file mode 100644 index 000000000..17399790b --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/queueDisbandAndAttackCommand5Params.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005371A0 + void UnitsState::queueDisbandAndAttackCommand5Params(undefined4 param_1, UnitInstructionType instruction, + undefined4 param_3, undefined4 param_4, undefined4 param_5) + { + DAT_GameSynchronyState::instance.DAT_GameCommandParam4 = param_5; + DAT_GameSynchronyState::instance.DAT_GameCommandParam1 = instruction; + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = param_1; + DAT_GameSynchronyState::instance.DAT_GameCommandParam3 = param_4; + DAT_GameSynchronyState::instance.DAT_GameCommandParam2 = param_3; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + OpenSHC::Commands::GCT_DISBAND_AND_ATTACK_UNITS); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/queueEscapeCommand.cpp b/src/OpenSHC/Map/Units/UnitsState/queueEscapeCommand.cpp new file mode 100644 index 000000000..eb56c0fe0 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/queueEscapeCommand.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536C70 + void UnitsState::queueEscapeCommand() + { + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = 0; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + OpenSHC::Commands::GCT_ESCAPE); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/queueUnitTypeCommand.cpp b/src/OpenSHC/Map/Units/UnitsState/queueUnitTypeCommand.cpp new file mode 100644 index 000000000..10ebcff56 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/queueUnitTypeCommand.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536C90 + void UnitsState::queueUnitTypeCommand(undefined4 unitType) + { + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = 0xffffffff; + DAT_GameSynchronyState::instance.DAT_GameCommandParam1 = unitType; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, DAT_GameSynchronyState::ptr)( + OpenSHC::Commands::GCT_ESCAPE); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/recomputeTroopValuesForPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/recomputeTroopValuesForPlayer.cpp new file mode 100644 index 000000000..3341b63ff --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/recomputeTroopValuesForPlayer.cpp @@ -0,0 +1,158 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00532BA0 + void UnitsState::recomputeTroopValuesForPlayer(int playerID) + { + int _campfireY = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; + int _campfireX = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; + DAT_GameState::instance.playerDataArray[playerID].enemies = 0; + DAT_GameState::instance.playerDataArray[playerID].totalEnemyUnitsCount = 0; + DAT_GameState::instance.playerDataArray[playerID].sumOfTotalEnemyUnitsCount = 0; + DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValueByPlayerID[1] = 0; + DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValueByPlayerID[2] = 0; + DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValueByPlayerID[3] = 0; + DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValueByPlayerID[4] = 0; + DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValueByPlayerID[5] = 0; + DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValueByPlayerID[6] = 0; + DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValueByPlayerID[7] = 0; + DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValueByPlayerID[8] = 0; + DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue = 0; + DAT_GameState::instance.playerDataArray[playerID].totalTeamTroopValue = 0; + DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue = 0; + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY && playerID != 0 + && DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] == -1 + && DAT_GameSynchronyState::instance.currentAIArray[playerID] == 0) { + return; + } + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 5000, '\0', DAT_GameState::instance.playerDataArray[playerID].enemyIDArray); + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].unknownTestAgainst0_2 != 0) { + continue; + } + if (DAT_GameState::instance.mapAndTime.playerTeams[this->units[unitID].owner] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + if (this->units[unitID].isSelectable_OR_matchTime == 0) { + continue; + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)( + _campfireX, _campfireY, this->units[unitID].x, this->units[unitID].y); + if (DAT_DirectionAlgorithmState::instance.distanceHigh < 60) { + DAT_GameState::instance.playerDataArray[playerID].totalTeamTroopValue + += MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::getValueOfTroopType, + DAT_TroopValueState::ptr)((UnitType)(short)this->units[unitID].unitType); + } + continue; + } + /* unit not in our team */ + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_TRADER: + case OpenSHC::Map::Units::UT_TRADERHORSE: + case OpenSHC::Map::Units::UT_CAMELSHBEAR: + case OpenSHC::Map::Units::UT_GHOST: + case OpenSHC::Map::Units::UT_MOTHER: + case OpenSHC::Map::Units::UT_CHILD: + continue; + } + if (this->units[unitID].owner == 0) { + continue; + } + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_TREBUCHET: + case OpenSHC::Map::Units::UT_S_MANGONEL: + case OpenSHC::Map::Units::UT_S_TOWER: + case OpenSHC::Map::Units::UT_S_SHIELD: + case OpenSHC::Map::Units::UT_S_BALLISTA: + case OpenSHC::Map::Units::UT_S_FBALLISTA: + /* count of currently manning engineers */ + if (this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300 + == 0) { + continue; + } + } + if (this->units[unitID].isSelectable_OR_matchTime == 0) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_LORD) { + DAT_GameState::instance.playerDataArray[playerID].totalEnemyUnitsCount += 1; + } + } else { + DAT_GameState::instance.playerDataArray[playerID].totalEnemyUnitsCount += 1; + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)( + _campfireX, _campfireY, this->units[unitID].x, this->units[unitID].y); + if (DAT_DirectionAlgorithmState::instance.distanceHigh < 60 + && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[this->units[unitID].owner] != -1 + || DAT_GameSynchronyState::instance.currentAIArray[this->units[unitID].owner] == 0 + || this->units[unitID].siegeTargetPlayerID == playerID)) { + DAT_GameState::instance.playerDataArray[playerID] + .totalEnemyTroopValueByPlayerID[this->units[unitID].owner] + += MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::getValueOfTroopType, + DAT_TroopValueState::ptr)((UnitType)(short)this->units[unitID].unitType); + DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue + += MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::getValueOfTroopType, + DAT_TroopValueState::ptr)((UnitType)(short)this->units[unitID].unitType); + UnitTypeShort _enemyUnitType = this->units[unitID].unitType; + if (_enemyUnitType != OpenSHC::Map::Units::UT_E_ARCHER + && _enemyUnitType != OpenSHC::Map::Units::UT_E_XBOW + && _enemyUnitType != OpenSHC::Map::Units::UT_A_ARCHER + && _enemyUnitType != OpenSHC::Map::Units::UT_A_SLINGER + && _enemyUnitType != OpenSHC::Map::Units::UT_A_HARCHER + && _enemyUnitType != OpenSHC::Map::Units::UT_A_FIRETHROWER) { + DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue + += MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::getValueOfTroopType, + DAT_TroopValueState::ptr)((UnitType)(short)_enemyUnitType); + } + } + } + int _enemySlot = DAT_GameState::instance.playerDataArray[playerID].enemies; + if (_enemySlot < 2499) { + DAT_GameState::instance.playerDataArray[playerID].enemies = _enemySlot + 1; + } else { + _enemySlot = SEC_RNG::instance.currentNumber2 % 2500; + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + if (_enemySlot > 2499) { + break; + } + } + DAT_GameState::instance.playerDataArray[playerID].enemyIDArray[_enemySlot] = (short)unitID; + DAT_GameState::instance.mapAndTime.playerEnemenyUnitUIDShortList[playerID][_enemySlot] + = this->units[unitID].uid; + } + DAT_GameState::instance.playerDataArray[playerID].sumOfTotalEnemyUnitsCount + += DAT_GameState::instance.playerDataArray[playerID].totalEnemyUnitsCount; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/recomputeUnitStandingHeight.cpp b/src/OpenSHC/Map/Units/UnitsState/recomputeUnitStandingHeight.cpp new file mode 100644 index 000000000..9300f5011 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/recomputeUnitStandingHeight.cpp @@ -0,0 +1,72 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F0D0 + void UnitsState::recomputeUnitStandingHeight(int unitID) + { + int _tile = this->units[unitID].tile; + uint _logicFlags = DAT_TileMapState::instance.LogicLayer[_tile]; + int _buildingID = DAT_TileMapState::instance.BuildingLayer[_tile]; + this->units[unitID].buildingHeight = 0; + this->units[unitID].field58_0x84 = 0; + if ((_logicFlags & 0x10010d00) == 0) { + if (_buildingID == 0) { + if (this->units[unitID].wasOnStoneGate != 0) { + this->units[unitID].terrainOrClimbHeight = DAT_TileMapState::instance.HeightLayer[_tile]; + this->units[unitID].wasOnStoneGate = 0; + } + } else if (DAT_BuildingsState::instance.buildings[_buildingID].buildingType + == OpenSHC::Map::Buildings::BT_DRAWBRIDGE) { + this->units[unitID].buildingHeight = 8 - this->units[unitID].terrainOrClimbHeight; + } + } else if ((_logicFlags & 0x800) != 0) { + this->units[unitID].buildingHeight = 0xc; + } else if ((_logicFlags & 0x100) != 0) { + if (_buildingID == 0) { + this->units[unitID].buildingHeight = 4; + } else if (this->units[unitID].unknownCountdown_0x402 == 0) { + this->units[unitID].buildingHeight = 0x28; + } else { + this->units[unitID].buildingHeight = -0x5a; + if (this->units[unitID].terrainOrClimbHeight + -0x5a < 8) { + this->units[unitID].buildingHeight = 0; + } + this->units[unitID].wasOnStoneGate = 1; + } + } else if ((_logicFlags & 0x400) != 0) { + this->units[unitID].buildingHeight = 2; + } else if ((_logicFlags & 0x10000000) != 0) { + if (this->units[unitID].unknownCountdown_0x402 == 0 + && this->units[unitID].unitType != OpenSHC::Map::Units::UT_S_TOWER) { + this->units[unitID].buildingHeight = (short)MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, + DAT_BuildingsState::ptr)(_buildingID); + } + this->units[unitID].field58_0x84 = (short)MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID2, + DAT_BuildingsState::ptr)(_buildingID); + this->units[unitID].terrainOrClimbHeight + = DAT_BuildingsState::instance.buildings[_buildingID].terrainHeightUnk; + } + if (this->units[DAT_CurrentUnitSlotID::instance].field306_0x418 != 0) { + this->units[unitID].buildingHeight + = this->units[unitID].buildingHeight + this->units[DAT_CurrentUnitSlotID::instance].field306_0x418; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/recountUnitsInSelection.cpp b/src/OpenSHC/Map/Units/UnitsState/recountUnitsInSelection.cpp new file mode 100644 index 000000000..1fbc5acdf --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/recountUnitsInSelection.cpp @@ -0,0 +1,137 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535240 + void UnitsState::recountUnitsInSelection() + { + for (int i = 0; i <= 26; ++i) { + (&this->selectionEuropeanArchers)[i] = 0; + } + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].owner != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + continue; + } + if (this->units[unitID].isSelected == 0) { + continue; + } + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_E_ARCHER: + this->selectionEuropeanArchers = this->selectionEuropeanArchers + 1; + break; + case OpenSHC::Map::Units::UT_E_XBOW: + this->selectionCrossbowmen = this->selectionCrossbowmen + 1; + break; + case OpenSHC::Map::Units::UT_E_SPEAR: + this->selectionSpearmen = this->selectionSpearmen + 1; + break; + case OpenSHC::Map::Units::UT_E_PIKE: + this->selectionPikemen = this->selectionPikemen + 1; + break; + case OpenSHC::Map::Units::UT_E_MACE: + this->selectionMacemen = this->selectionMacemen + 1; + break; + case OpenSHC::Map::Units::UT_E_SWORD: + this->selectionSwordsmen = this->selectionSwordsmen + 1; + break; + case OpenSHC::Map::Units::UT_E_KNIGHT: + this->selectionKnights = this->selectionKnights + 1; + break; + case OpenSHC::Map::Units::UT_E_LADDER: + this->selectionLaddermen = this->selectionLaddermen + 1; + break; + case OpenSHC::Map::Units::UT_E_ENGINEER: + this->selectionEngineers = this->selectionEngineers + 1; + break; + case OpenSHC::Map::Units::UT_E_MONK: + this->selectionMonks = this->selectionMonks + 1; + break; + case OpenSHC::Map::Units::UT_TUNNELER: + this->selectionTunnelers = this->selectionTunnelers + 1; + break; + case OpenSHC::Map::Units::UT_S_CATAPULT: + this->selectionCatapults = this->selectionCatapults + 1; + break; + case OpenSHC::Map::Units::UT_S_TREBUCHET: + this->selectionTrebuchets = this->selectionTrebuchets + 1; + break; + case OpenSHC::Map::Units::UT_S_MANGONEL: + this->selectionMangonel = this->selectionMangonel + 1; + break; + case OpenSHC::Map::Units::UT_S_TOWER: + this->selectionSiegeTower = this->selectionSiegeTower + 1; + break; + case OpenSHC::Map::Units::UT_S_BATTERINGRAM: + this->selectionBatteringRam = this->selectionBatteringRam + 1; + break; + case OpenSHC::Map::Units::UT_S_SHIELD: + this->selectionShield = this->selectionShield + 1; + break; + case OpenSHC::Map::Units::UT_S_BALLISTA: + this->selectionBallista = this->selectionBallista + 1; + break; + case OpenSHC::Map::Units::UT_A_ARCHER: + this->selectionArabArcher = this->selectionArabArcher + 1; + break; + case OpenSHC::Map::Units::UT_A_SLAVE: + this->selectionArabSlave = this->selectionArabSlave + 1; + break; + case OpenSHC::Map::Units::UT_A_SLINGER: + this->selectionArabSlinger = this->selectionArabSlinger + 1; + break; + case OpenSHC::Map::Units::UT_A_ASSASSIN: + this->selectionArabAssassin = this->selectionArabAssassin + 1; + break; + case OpenSHC::Map::Units::UT_A_HARCHER: + this->selectionArabHorseArchers = this->selectionArabHorseArchers + 1; + break; + case OpenSHC::Map::Units::UT_A_SWORDSMAN: + this->selectionArabSwordsman = this->selectionArabSwordsman + 1; + break; + case OpenSHC::Map::Units::UT_A_FIRETHROWER: + this->selectionArabFireThrower = this->selectionArabFireThrower + 1; + break; + case OpenSHC::Map::Units::UT_S_FBALLISTA: + this->selectionFireBallista = this->selectionFireBallista + 1; + break; + default: + continue; + } + this->nHasOwnedUnitInSelection = 1; + } + this->selectionSlots[1] = -1; + this->selectionSlots[2] = -1; + this->selectionSlots[3] = -1; + this->selectionSlots[4] = -1; + this->selectionSlots[5] = -1; + this->selectionSlots[6] = -1; + this->selectionSlots[7] = -1; + this->selectionSlots[0] = -1; + int _slot = 0; + for (int i = 0; i < 27; ++i) { + if ((&this->selectionEuropeanArchers)[i] != 0) { + this->selectionSlots[_slot] = i; + _slot = _slot + 1; + if (_slot > 7) { + return; + } + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/relayTribeInstruction.cpp b/src/OpenSHC/Map/Units/UnitsState/relayTribeInstruction.cpp new file mode 100644 index 000000000..e2e3b490f --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/relayTribeInstruction.cpp @@ -0,0 +1,20 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x005371E0 + void UnitsState::relayTribeInstruction( + int tribeID, UnitInstructionType instructionType, int targetID_1, int targetID_2, int param_5) + { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( + tribeID, instructionType, targetID_1, targetID_2, param_5); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/removeUnitFromItsTribe.cpp b/src/OpenSHC/Map/Units/UnitsState/removeUnitFromItsTribe.cpp new file mode 100644 index 000000000..5350396a2 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/removeUnitFromItsTribe.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F010 + void UnitsState::removeUnitFromItsTribe(uint unitID, int unitUID) + { + if ((int)unitID <= 0) { + return; + } + if (this->units[unitID].uid != unitUID) { + return; + } + int _tribeID = this->units[unitID].tribeID; + this->units[unitID].logicalState = OpenSHC::Map::Units::ULS_REMOVE; + if (_tribeID <= 0) { + return; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::tribeCorrespondsWithUID, DAT_TribesState::ptr)( + _tribeID, this->units[unitID].tribeUID) + == FALSE) { + return; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, _tribeID); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/removeUnitsSameTileLinkageIfNoLongerApplicable.cpp b/src/OpenSHC/Map/Units/UnitsState/removeUnitsSameTileLinkageIfNoLongerApplicable.cpp new file mode 100644 index 000000000..45834df88 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/removeUnitsSameTileLinkageIfNoLongerApplicable.cpp @@ -0,0 +1,45 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F730 + void UnitsState::removeUnitsSameTileLinkageIfNoLongerApplicable() + { + if (DAT_GameState::instance.mapAndTime.multiplayerUnitSameTileLinkageTimeWindow <= 0) { + DAT_GameState::instance.mapAndTime.multiplayerUnitSameTileLinkageTimeWindow = 0; + return; + } + if (DAT_GameState::instance.mapAndTime.multiplayerUnitSameTileLinkageTimeWindow < 100) { + DAT_GameState::instance.mapAndTime.multiplayerUnitSameTileLinkageTimeWindow + = DAT_GameState::instance.mapAndTime.multiplayerUnitSameTileLinkageTimeWindow + 1; + if (DAT_GameState::instance.mapAndTime.multiplayerUnitSameTileLinkageTimeWindow > 50) { + DAT_GameState::instance.mapAndTime.multiplayerUnitSameTileLinkageTimeWindow = 0; + } + return; + } + DAT_GameState::instance.mapAndTime.multiplayerUnitSameTileLinkageTimeWindow = 0; + for (int tile = 0; tile < 0x13a10; ++tile) { + if ((short)DAT_TileMapState::instance.UnitLayer[tile] < 0 + || (short)DAT_TileMapState::instance.UnitLayer[tile] > 2500) { + DAT_TileMapState::instance.UnitLayer[tile] = 0; + continue; + } + for (int unitID = (short)DAT_TileMapState::instance.UnitLayer[tile]; unitID != 0; + unitID = (short)this->units[unitID].nextUnitOnTheSameTile) { + if (this->units[unitID].tile != tile && this->units[unitID].usingTeleport == 0 + && this->units[unitID].field303_0x413 == 0) { + DAT_TileMapState::instance.UnitLayer[tile] = this->units[unitID].nextUnitOnTheSameTile; + break; + } + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/renderDebugDataUnitData.cpp b/src/OpenSHC/Map/Units/UnitsState/renderDebugDataUnitData.cpp new file mode 100644 index 000000000..5cf4a85f0 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/renderDebugDataUnitData.cpp @@ -0,0 +1,240 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Text/TextManager.func.hpp" +#include "OpenSHC/Text/TextAlignment.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TextManagerObject.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Text::TextAlignment; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053A5B0 + void UnitsState::renderDebugDataUnitData(int x, int y, int width, int height) + + { + int _selectedUnitID = this->lastSelectedUnitID; + int _ownerID = this->units[_selectedUnitID].owner; + int _tribeID = this->units[_selectedUnitID].tribeID; + int _lineY; + int _column0 = x + 2; + if (_selectedUnitID <= 0) { + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Not_watching_a_chimp_005abde0, _column0, y, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, + 0); + _lineY = y + 0xe; + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Total_chimps__005abdd0, _column0, _lineY, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, + 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + this->unitCount, _column0, _lineY, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Total_flies__005abdc0, _column0 + 0x1e, _lineY, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, + TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + DAT_EntityState::instance.totalEntityCount, _column0 + 0x1e, _lineY, OpenSHC::Text::TTA_LEFT, + 0x80ff, 0x12, TRUE, 0); + _lineY = y + 0x1c; + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_No_of_teleports__005abdac, _column0, _lineY, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, + FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + DAT_PathFindingState::instance.numberOfClimbTeleports, _column0, _lineY, OpenSHC::Text::TTA_LEFT, + 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_greatest_loading__005abd98, _column0 + 0x78, _lineY, OpenSHC::Text::TTA_LEFT, 0xffffff, + 0x12, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + DAT_PathFindingState::instance.debugGreatestClimbLoading, _column0 + 0x78, _lineY, + OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_total_zones__005abd88, _column0, y + 0x2a, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, + 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + DAT_PathFindingState::instance.totalZones, _column0, y + 0x2a, OpenSHC::Text::TTA_LEFT, 0x80ff, + 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Lost_chimps__005abd78, _column0, y + 0x54, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, + 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + this->lostChimps, _column0, y + 0x54, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, 0); + } + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Watching_chimp__005abd64, _column0, y, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + _selectedUnitID, _column0, y, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, 0); + int _column1 = _column0 + 0x1e; + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_type__005abd5c, _column1, y, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)(short)this->units[_selectedUnitID].unitType, _column1, y, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, + TRUE, 0); + int _column2 = _column0 + 0x3c; + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_player__005abd50, _column2, y, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + _ownerID, _column2, y, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, 0); + int _column3 = _column0 + 0x5a; + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_status__005abd44, _column3, y, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)(short)this->units[_selectedUnitID].logicalState, _column3, y, OpenSHC::Text::TTA_LEFT, 0x80ff, + 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_dying__005abd3c, _column0, y + 0xe, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].dying, _column0, y + 0xe, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, + 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_next_chimp__005abd2c, _column1, y + 0xe, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)(short)this->units[_selectedUnitID].nextUnitOnTheSameTile, _column1, y + 0xe, + OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_using_teleport__005abd18, _column2, y + 0xe, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].usingTeleport, _column2, y + 0xe, OpenSHC::Text::TTA_LEFT, 0x80ff, + 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_elbowed__005abd0c, _column3, y + 0xe, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].unitOrderWhenOnSameTile, _column3, y + 0xe, OpenSHC::Text::TTA_LEFT, + 0x80ff, 0x12, TRUE, 0); + int _column4 = _column0 + 0x78; + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_sloth__005abd04, _column4, y + 0xe, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].moveDelay, _column4, y + 0xe, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, + TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_enemyD_005abcfc, _column0, y + 0x1c, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].closestEnemyMicroDistance, _column0, y + 0x1c, + OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_enemies_005a51f4, _column1, y + 0x1c, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + DAT_GameState::instance.playerDataArray[_lineY].enemies, _column1, y + 0x1c, OpenSHC::Text::TTA_LEFT, + 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_facing_005abcf4, _column2, y + 0x1c, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].facingDirection, _column2, y + 0x1c, OpenSHC::Text::TTA_LEFT, 0x80ff, + 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_jump_005abcec, _column3, y + 0x1c, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].buildingHeight, _column3, y + 0x1c, OpenSHC::Text::TTA_LEFT, 0x80ff, + 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_z_005abce8, _column4, y + 0x1c, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].terrainOrClimbHeight, _column4, y + 0x1c, OpenSHC::Text::TTA_LEFT, + 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_ai_status_005abcdc, _column0, y + 0x2a, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)(short)this->units[_selectedUnitID].state.generic, _column0, y + 0x2a, OpenSHC::Text::TTA_LEFT, + 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_anim_frame_no_005abccc, _column1, y + 0x2a, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + this->units[_selectedUnitID].animationCycleNumber, _column1, y + 0x2a, OpenSHC::Text::TTA_LEFT, 0x80ff, + 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_gfx_no_005abcc4, _column2, y + 0x2a, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + this->units[_selectedUnitID].gfxNumber, _column2, y + 0x2a, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, + 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Look_4_enemy_005abcb4, _column0, y + 0x38, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].lookForEnemy, _column0, y + 0x38, OpenSHC::Text::TTA_LEFT, 0x80ff, + 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Attacked_By_005abca4, _column1, y + 0x38, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].attackedBy, _column1, y + 0x38, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, + TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Hps_005abc9c, _column2, y + 0x38, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + this->units[_selectedUnitID].health, _column2, y + 0x38, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, + 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Hunted_By_005abc90, _column3, y + 0x38, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].huntedBy, _column3, y + 0x38, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, + TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_target_type_005abc80, _column0, y + 0x46, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)(short)this->units[_selectedUnitID].targetingType, _column0, y + 0x46, OpenSHC::Text::TTA_LEFT, + 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_seated_005abc78, _column1, y + 0x46, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].seated, _column1, y + 0x46, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, + TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_vanish_005abc70, _column2, y + 0x46, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + this->units[_selectedUnitID].vanish, _column2, y + 0x46, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, + 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_was_on_stone_gate_005abc5c, _column3, y + 0x46, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, + 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)(char)this->units[_selectedUnitID].wasOnStoneGate, _column3, y + 0x46, OpenSHC::Text::TTA_LEFT, + 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Idle_005abc54, _column0, y + 0x54, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].idle, _column0, y + 0x54, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, + 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Target_005abc4c, _column1, y + 0x54, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].target, _column1, y + 0x54, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, + TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Banked_005abc44, _column2, y + 0x54, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].banked, _column2, y + 0x54, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, + TRUE, 0); + _lineY = y + 0x62; + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Working_005abc38, _column0, _lineY, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + *(int*)(this->units[_selectedUnitID].manningEngineerRef + this->units[_selectedUnitID].working * 2 + + -0x16), + _column0, _lineY, OpenSHC::Text::TTA_LEFT, (uint)(33023), 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Av_005abc34, _column1, _lineY, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + this->units[_selectedUnitID].av, _column1, _lineY, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Bless_005abc2c, _column2, _lineY, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + this->units[_selectedUnitID].blessedAmount, _column2, _lineY, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, + TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_Tribe_005abc24, _column3, _lineY, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)_tribeID, _column3, _lineY, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + (char*)s_SA_005abc20, _column4, _lineY, OpenSHC::Text::TTA_LEFT, 0xffffff, 0x12, TRUE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + (int)this->units[_selectedUnitID].SA, _column4, _lineY, OpenSHC::Text::TTA_LEFT, 0x80ff, 0x12, TRUE, 0); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/resetUnitMovementState.cpp b/src/OpenSHC/Map/Units/UnitsState/resetUnitMovementState.cpp new file mode 100644 index 000000000..7755e5d6c --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/resetUnitMovementState.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053E870 + void UnitsState::resetUnitMovementState(int unitID) + { + int _wasPositionPending = this->units[unitID].unknownTestAgainst0_2; + this->units[unitID].currentIndexInPathPlan = 0; + this->units[unitID].tunnelerFinishedDigging = 0; + this->units[unitID].movementRelated = 8; + this->units[unitID].unknownTestAgainst0_2 = 0; + this->units[unitID].field105_0xe8 = 0; + this->units[unitID].unknownMovementRelated_0x2d2 = 0; + if (_wasPositionPending != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::commitPendingUnitPosition, this)(unitID); + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/resumeMovementAfterInterruption.cpp b/src/OpenSHC/Map/Units/UnitsState/resumeMovementAfterInterruption.cpp new file mode 100644 index 000000000..38299840d --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/resumeMovementAfterInterruption.cpp @@ -0,0 +1,44 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053D850 + void UnitsState::resumeMovementAfterInterruption(int unitID) + { + if (this->units[unitID].dying != 0) { + return; + } + if (this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_REMOVE) { + return; + } + short _destinationY = this->units[unitID].destinationY_2Unk; + short _destinationX = this->units[unitID].destinationX_2Unk; + this->units[unitID].state = this->units[unitID].state_3; + this->units[unitID].tunnelerFinishedDigging = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, _destinationX, _destinationY, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::changeDestinationByLeftover, this)(unitID); + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_LIONSHWOLF + && this->units[unitID].unitType != OpenSHC::Map::Units::UT_CAGEDOG) { + return; + } + this->units[DAT_CurrentUnitSlotID::instance].state.generic + = OpenSHC::Map::Units::States::US_MOVE_TO_DESTINATION; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::makeUnitStopWalkingByClearingPathProgressState, + this)(DAT_CurrentUnitSlotID::instance); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/resumeMovementIfNoAttackTarget.cpp b/src/OpenSHC/Map/Units/UnitsState/resumeMovementIfNoAttackTarget.cpp new file mode 100644 index 000000000..a2b57349a --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/resumeMovementIfNoAttackTarget.cpp @@ -0,0 +1,20 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0054A770 + void UnitsState::resumeMovementIfNoAttackTarget(int unitID) + { + if (this->units[unitID].attackedUnitID != 0) { + return; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::resumeMovementAfterInterruption, this)(unitID); + this->units[unitID].attackedUnitID = 0; + this->units[unitID].field191_0x340 = 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/returnFalseStub.cpp b/src/OpenSHC/Map/Units/UnitsState/returnFalseStub.cpp new file mode 100644 index 000000000..a23bf4e6d --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/returnFalseStub.cpp @@ -0,0 +1,15 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00533090 + BOOLEnum UnitsState::returnFalseStub(int unitID) { return FALSE; } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/returnFirstSelectedEngineer.cpp b/src/OpenSHC/Map/Units/UnitsState/returnFirstSelectedEngineer.cpp new file mode 100644 index 000000000..f3b5dfd47 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/returnFirstSelectedEngineer.cpp @@ -0,0 +1,42 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005364C0 + uint UnitsState::returnFirstSelectedEngineer() + { + int _currentPlayerSlotID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner != _currentPlayerSlotID) { + return 0; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_E_ENGINEER) { + return DAT_CurrentUnitSlotID::instance; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/saveUnitStateBeforeInterruption.cpp b/src/OpenSHC/Map/Units/UnitsState/saveUnitStateBeforeInterruption.cpp new file mode 100644 index 000000000..6c0d666bb --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/saveUnitStateBeforeInterruption.cpp @@ -0,0 +1,17 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00533F90 + void UnitsState::saveUnitStateBeforeInterruption(int unitID) + { + UnitStateUnion _savedState = this->units[unitID].state; + this->units[unitID].tunnelerFinishedDigging = 5; + this->units[unitID].state_3 = _savedState; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectAllUnitsOfTypeForPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/selectAllUnitsOfTypeForPlayer.cpp new file mode 100644 index 000000000..a170ef1c2 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectAllUnitsOfTypeForPlayer.cpp @@ -0,0 +1,36 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x005350B0 + void UnitsState::selectAllUnitsOfTypeForPlayer(int playerID, int unitType) + { + this->totalUnitsInSelection = 0; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[DAT_CurrentUnitSlotID::instance].dying == 0 + && this->units[DAT_CurrentUnitSlotID::instance].unknownTestAgainst0_2 == 0 + && this->units[DAT_CurrentUnitSlotID::instance].state.generic + != OpenSHC::Map::Units::States::US_JESTER_ROAM_TO + && (short)this->units[DAT_CurrentUnitSlotID::instance].unitType == unitType + && this->units[DAT_CurrentUnitSlotID::instance].drawX != 0 + && this->units[DAT_CurrentUnitSlotID::instance].owner == playerID) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectFirstUnitInDragBoxAnyPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/selectFirstUnitInDragBoxAnyPlayer.cpp new file mode 100644 index 000000000..68dd23ee2 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectFirstUnitInDragBoxAnyPlayer.cpp @@ -0,0 +1,114 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_MouseState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00534EE0 + void UnitsState::selectFirstUnitInDragBoxAnyPlayer() + { + LONG _boxLeft; + LONG _boxRight; + if (DAT_MouseState::instance.selectionBox.right < DAT_MouseState::instance.selectionBox.left) { + _boxLeft = DAT_MouseState::instance.selectionBox.right; + _boxRight = DAT_MouseState::instance.selectionBox.left; + } else { + _boxLeft = DAT_MouseState::instance.selectionBox.left; + _boxRight = DAT_MouseState::instance.selectionBox.right; + } + LONG _boxTop; + LONG _boxBottom; + if (DAT_MouseState::instance.selectionBox.bottom < DAT_MouseState::instance.selectionBox.top) { + _boxTop = DAT_MouseState::instance.selectionBox.bottom; + _boxBottom = DAT_MouseState::instance.selectionBox.top; + } else { + _boxTop = DAT_MouseState::instance.selectionBox.top; + _boxBottom = DAT_MouseState::instance.selectionBox.bottom; + } + this->field14_0x55c = 0; + this->totalUnitsInSelection = 0; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 0; + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unknownTestAgainst0_2 != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_JESTER_ROAM_TO) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelectable_OR_matchTime == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_TOWER + && this->units[DAT_CurrentUnitSlotID::instance].state.generic + == (OpenSHC::Map::Units::States::US_STAND_UPUnk | OpenSHC::Map::Units::States::US_IDLEUnk)) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_TUNNELER + && (this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk + || this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_STAND_UPUnk)) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].drawX == 0 + && this->units[DAT_CurrentUnitSlotID::instance].drawY == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].drawX + + this->units[DAT_CurrentUnitSlotID::instance].drawXOffset + >= _boxRight) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].drawY + + this->units[DAT_CurrentUnitSlotID::instance].someDrawYOffset + >= _boxBottom) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].spriteWidthUnk + + this->units[DAT_CurrentUnitSlotID::instance].drawX + + this->units[DAT_CurrentUnitSlotID::instance].drawXOffset + < _boxLeft) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].spriteHeightUnk + + this->units[DAT_CurrentUnitSlotID::instance].drawY + + this->units[DAT_CurrentUnitSlotID::instance].someDrawYOffset + < _boxTop) { + continue; + } + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + if (this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner == 0) { + return; + } + this->field14_0x55c = this->units[DAT_CurrentUnitSlotID::instance].owner; + return; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectNewBlessingTarget.cpp b/src/OpenSHC/Map/Units/UnitsState/selectNewBlessingTarget.cpp new file mode 100644 index 000000000..6c99f1b0d --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectNewBlessingTarget.cpp @@ -0,0 +1,57 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x005346D0 + int UnitsState::selectNewBlessingTarget(int unitID) + { + short _playerID = this->units[unitID].owner; + short _x = this->units[unitID].x; + short _y = this->units[unitID].y; + int _bestUnitID = 0; + int _highestPreference = 0; + for (int _targetUnitID = 1; _targetUnitID < (int)this->maxUnitCount; ++_targetUnitID) { + if (this->units[_targetUnitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[_targetUnitID].dying != 0) { + continue; + } + if (this->units[_targetUnitID].owner != _playerID) { + continue; + } + if (DAT_UnitPropertiesDefinedData::instance.NotBlessableUnits[this->units[_targetUnitID].unitType] + != 0) { + continue; + } + if (this->units[_targetUnitID].blessedAmount >= 4000) { + continue; + } + int _distance = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)( + _x, _y, this->units[_targetUnitID].x, this->units[_targetUnitID].y); + if (_distance >= 40) { + continue; + } + int _preference = ((4000 - this->units[_targetUnitID].blessedAmount) >> 6) - _distance / 2; + if (_highestPreference < _preference) { + _highestPreference = _preference; + _bestUnitID = _targetUnitID; + } + } + return _bestUnitID; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectSiegeEngineAndPlayFeedback.cpp b/src/OpenSHC/Map/Units/UnitsState/selectSiegeEngineAndPlayFeedback.cpp new file mode 100644 index 000000000..cb1d46d73 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectSiegeEngineAndPlayFeedback.cpp @@ -0,0 +1,81 @@ +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Audio/SFX/SpeechEffectID.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UIDragDropDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Audio::SFX::SpeechEffectID; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535E20 + void UnitsState::selectSiegeEngineAndPlayFeedback(int playerID, int unitID, int tribeID) + { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, this->units[unitID].tribeID); + this->units[unitID].isSelected = 1; + this->units[unitID].selectionRelatedFlag = 1; + this->units[unitID].ifSelectedThenPlayerID = (short)playerID; + this->unitCountOfSelection[playerID] = this->unitCountOfSelection[playerID] + 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribeAndUpdateTribeMovementSpeed, + DAT_TribesState::ptr)(playerID, unitID, tribeID); + if (DAT_TribesState::instance.tribes[tribeID].owner + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + DAT_UIDragDropDefinedData::instance.MenuView_TriggerInitial = TRUE; + return; + } + UnitType _unitType = (UnitType)(short)this->units[unitID].unitType; + if (_unitType == OpenSHC::Map::Units::UT_S_CATAPULT || _unitType == OpenSHC::Map::Units::UT_S_TOWER + || _unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM || _unitType == OpenSHC::Map::Units::UT_S_SHIELD + || _unitType == OpenSHC::Map::Units::UT_S_BALLISTA || _unitType == OpenSHC::Map::Units::UT_S_FBALLISTA + || _unitType == OpenSHC::Map::Units::UT_S_TREBUCHET + || _unitType == OpenSHC::Map::Units::UT_S_MANGONEL) { + int _siegeEngineUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + int _remainingEngineers = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, this)(_siegeEngineUnitID); + if (_remainingEngineers > 0) { + if (this->units[_siegeEngineUnitID] + .digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300 + == 0 + || _remainingEngineers > 3) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeechEffect, DAT_SFXState::ptr)( + 0xe); + } else if (_remainingEngineers == 1) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeechEffect, DAT_SFXState::ptr)( + 0xb); + } else if (_remainingEngineers == 2) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeechEffect, DAT_SFXState::ptr)( + 0xc); + } else if (_remainingEngineers == 3) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeechEffect, DAT_SFXState::ptr)( + 0xd); + } + DAT_UIDragDropDefinedData::instance.MenuView_TriggerInitial = TRUE; + return; + } + if ((_unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || _unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) + && this->units[_siegeEngineUnitID].stoneAmmunition <= 0) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSpeechSFX, DAT_SFXState::ptr)( + OpenSHC::Audio::SFX::SEID_RESOURCE_NEED25); + DAT_UIDragDropDefinedData::instance.MenuView_TriggerInitial = TRUE; + return; + } + } + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playUnitSpeech, DAT_SFXState::ptr)(_unitType, 0); + DAT_UIDragDropDefinedData::instance.MenuView_TriggerInitial = TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectTribeUnitsForPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/selectTribeUnitsForPlayer.cpp new file mode 100644 index 000000000..6a763dc85 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectTribeUnitsForPlayer.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00536190 + void UnitsState::selectTribeUnitsForPlayer(int playerID, int tribeID) + { + for (int indexInTribe = 0; indexInTribe < DAT_TribesState::instance.tribes[tribeID].size; ++indexInTribe) { + int unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::getUnitIDForIndexInTribe, + DAT_TribesState::ptr)(tribeID, indexInTribe); + this->units[unitID].ifSelectedThenPlayerID = (short)playerID; + this->unitCountOfSelection[playerID] = this->unitCountOfSelection[playerID] + 1; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectUnitsInDragBoxForCurrentPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/selectUnitsInDragBoxForCurrentPlayer.cpp new file mode 100644 index 000000000..1965b300e --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectUnitsInDragBoxForCurrentPlayer.cpp @@ -0,0 +1,112 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_MouseState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00534D10 + void UnitsState::selectUnitsInDragBoxForCurrentPlayer() + { + LONG _boxLeft; + LONG _boxRight; + if (DAT_MouseState::instance.selectionBox.right < DAT_MouseState::instance.selectionBox.left) { + _boxLeft = DAT_MouseState::instance.selectionBox.right; + _boxRight = DAT_MouseState::instance.selectionBox.left; + } else { + _boxLeft = DAT_MouseState::instance.selectionBox.left; + _boxRight = DAT_MouseState::instance.selectionBox.right; + } + LONG _boxTop; + LONG _boxBottom; + if (DAT_MouseState::instance.selectionBox.bottom < DAT_MouseState::instance.selectionBox.top) { + _boxTop = DAT_MouseState::instance.selectionBox.bottom; + _boxBottom = DAT_MouseState::instance.selectionBox.top; + } else { + _boxTop = DAT_MouseState::instance.selectionBox.top; + _boxBottom = DAT_MouseState::instance.selectionBox.bottom; + } + this->totalUnitsInSelection = 0; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 0; + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelectable_OR_matchTime == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unknownTestAgainst0_2 != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_JESTER_ROAM_TO) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].ifSelectedThenPlayerID + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (this->units[DAT_CurrentUnitSlotID::instance].drawX == 0 + && this->units[DAT_CurrentUnitSlotID::instance].drawY == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].drawX + + this->units[DAT_CurrentUnitSlotID::instance].drawXOffset + >= _boxRight) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].drawY + + this->units[DAT_CurrentUnitSlotID::instance].someDrawYOffset + >= _boxBottom) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].spriteWidthUnk + + this->units[DAT_CurrentUnitSlotID::instance].drawX + + this->units[DAT_CurrentUnitSlotID::instance].drawXOffset + < _boxLeft) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].spriteHeightUnk + + this->units[DAT_CurrentUnitSlotID::instance].drawY + + this->units[DAT_CurrentUnitSlotID::instance].someDrawYOffset + < _boxTop) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_S_TOWER + && this->units[DAT_CurrentUnitSlotID::instance].state.generic + == (OpenSHC::Map::Units::States::US_STAND_UPUnk + | OpenSHC::Map::Units::States::US_IDLEUnk)) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_TUNNELER + && (this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_LOOK_AROUNDUnk + || this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_STAND_UPUnk)) { + continue; + } + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID + && this->units[DAT_CurrentUnitSlotID::instance].unitType != OpenSHC::Map::Units::UT_LORD) { + this->units[DAT_CurrentUnitSlotID::instance].isSelected = 1; + this->totalUnitsInSelection = this->totalUnitsInSelection + 1; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectWorkerSpeechOrMoraleStateID.cpp b/src/OpenSHC/Map/Units/UnitsState/selectWorkerSpeechOrMoraleStateID.cpp new file mode 100644 index 000000000..61aade3e0 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectWorkerSpeechOrMoraleStateID.cpp @@ -0,0 +1,270 @@ +#include "OpenSHC/Map/Units.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_00ee1030.hpp" +#include "OpenSHC/Globals/DAT_00ee1034.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" +#include "OpenSHC/Globals/INT_00ee1038.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::GameMode2; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053DDD0 + int UnitsState::selectWorkerSpeechOrMoraleStateID(int unitID) + { + int _blockingState + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getWorkerBlockingStateIfStuck, this)(unitID); + if (_blockingState != 0) { + return _blockingState; + } + uint _rng = this->units[unitID].fixedRng; + uint _rngMod4 = _rng % 4; + if (unitID != INT_00ee1038::instance) { + INT_00ee1038::instance = unitID; + if (DAT_UnitPropertiesDefinedData::instance.field125_0x12260 == 0x19) { + DAT_UnitPropertiesDefinedData::instance.field125_0x12260 = 0; + DAT_UnitPropertiesDefinedData::instance.field126_0x12264 = 0x19; + DAT_UnitPropertiesDefinedData::instance.field127_0x12268 = 10; + } else if (DAT_UnitPropertiesDefinedData::instance.field126_0x12264 == 0x19) { + DAT_UnitPropertiesDefinedData::instance.field125_0x12260 = 10; + DAT_UnitPropertiesDefinedData::instance.field126_0x12264 = 0; + DAT_UnitPropertiesDefinedData::instance.field127_0x12268 = 0x19; + } else if (DAT_UnitPropertiesDefinedData::instance.field127_0x12268 == 0x19) { + DAT_UnitPropertiesDefinedData::instance.field125_0x12260 = 0x19; + DAT_UnitPropertiesDefinedData::instance.field126_0x12264 = 10; + DAT_UnitPropertiesDefinedData::instance.field127_0x12268 = 0; + } + } + int _worstPopularityReason = -1; + int _worstPopularityValue = 0; + for (int i = 0; i < 0x20; ++i) { + if (i <= 4 || (i >= 6 && i <= 10) || i == 0x14 || i >= 0x17) { + continue; + } + if ((&DAT_GameState::instance.mapAndTime.field3092_0x2654)[i] <= 0x27) { + continue; + } + if (_worstPopularityReason == -1 + || (&DAT_GameState::instance.mapAndTime.field3092_0x2654)[i] < _worstPopularityValue) { + _worstPopularityReason = i; + _worstPopularityValue = (&DAT_GameState::instance.mapAndTime.field3092_0x2654)[i]; + } + } + if (_worstPopularityReason != -1) { + if (DAT_UnitPropertiesDefinedData::instance.field124_0x1225c == _worstPopularityReason) { + DAT_00ee1034::instance = DAT_00ee1034::instance + 1; + if (DAT_00ee1034::instance > 1) { + (&DAT_GameState::instance.mapAndTime.field3092_0x2654)[_worstPopularityReason] = 0; + } + } else { + DAT_00ee1034::instance = 0; + DAT_UnitPropertiesDefinedData::instance.field124_0x1225c = _worstPopularityReason; + } + switch (_worstPopularityReason) { + case 5: + return _rngMod4 + 0x74; + case 0xb: + return (MACRO_CALL(OpenSHC::Map::Units_Func::CurrentUnitHasHealer)() != FALSE) + 0x67; + case 0xc: + return 0x79; + case 0xd: + return 0x7a; + case 0xe: + return 0x7c; + case 0xf: + return 0x78; + case 0x10: + return (_rng & 1) + 0x6c; + case 0x11: + return (_rng & 1) + 0x6a; + case 0x12: + return 0x69; + case 0x13: + return 0x7b; + case 0x15: + return _rngMod4 + 0x6e; + case 0x16: + return (_rng & 1) + 0x72; + } + } + int _bestSpeechID = -1; + int _candidateCount = 0; + int _bestWeight = 0; + int _candidateSpeechID = 0; + if (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .totalEnemyUnitsCount + < 10 + || DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER + || (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CAMPAIGN_MISSION + && DAT_GameCore::instance.missionNumber1to20 > 0xf)) { + DAT_00ee1030::instance = 0; + } else { + DAT_00ee1030::instance = DAT_00ee1030::instance + 1; + _candidateSpeechID = _rngMod4 + 0x62; + _bestWeight = 0x50; + if (DAT_00ee1030::instance > 2) { + _bestWeight = (4 - DAT_00ee1030::instance) * 0x14; + if (_bestWeight < 0x14) { + _bestWeight = 0x14; + } + } + _candidateCount = 100; + _bestSpeechID = _candidateSpeechID; + } + int _weight = 0; + if (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .rationsSetting + == 0) { + _weight = 10; + _candidateSpeechID = _rngMod4 + 0x3c; + } else if (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .rationsSetting + == 1) { + _weight = 0x14; + _candidateSpeechID = _rngMod4 + 0x40; + } else if (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .rationsSetting + == 4) { + _weight = 0x14; + _candidateSpeechID = _rngMod4 + 0x44; + } + if (_weight != 0) { + _candidateCount = _candidateCount + 1; + if (_bestSpeechID == -1 + || _bestWeight < _weight + DAT_UnitPropertiesDefinedData::instance.field125_0x12260) { + _bestWeight = _weight + DAT_UnitPropertiesDefinedData::instance.field125_0x12260; + _bestSpeechID = _candidateSpeechID; + } + } + int _taxesSetting + = DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .taxesSetting; + if (_taxesSetting < 4 || _taxesSetting > 7) { + _weight = 0; + if (_taxesSetting == 0) { + _candidateSpeechID = _rngMod4 + 0x49; + _weight = 0x14; + } else if (_taxesSetting == 1) { + _weight = 0xf; + _candidateSpeechID = _rngMod4 + 0x4d; + } else if (_taxesSetting == 2) { + _weight = 10; + _candidateSpeechID = _rngMod4 + 0x51; + } else if (_taxesSetting == 3) { + _weight = 5; + _candidateSpeechID = _rngMod4 + 0x55; + } else if (_taxesSetting == 8) { + _weight = 0xf; + _candidateSpeechID = _rngMod4 + 0x59; + } else if (_taxesSetting == 9 || _taxesSetting == 10 || _taxesSetting == 0xb) { + _candidateSpeechID = _rngMod4 + 0x5d; + _weight = 0x14; + } + if (_weight != 0) { + _candidateCount = _candidateCount + 1; + if (_bestSpeechID == -1 + || _bestWeight < _weight + DAT_UnitPropertiesDefinedData::instance.field126_0x12264) { + _bestWeight = _weight + DAT_UnitPropertiesDefinedData::instance.field126_0x12264; + _bestSpeechID = _candidateSpeechID; + } + } + } + int _productivity + = DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .fearFactorProductivityUnk; + _weight = 0; + if (_productivity < 100) { + _candidateCount = _candidateCount + 1; + if (_productivity < 0x3c) { + _weight = 0x19; + _candidateSpeechID = _rngMod4 + 0x12; + } else if (_productivity < 0x46) { + _weight = 0x14; + _candidateSpeechID = _rngMod4 + 0xe; + } else if (_productivity < 0x50) { + _weight = 0xf; + _candidateSpeechID = _rngMod4 + 10; + } else if (_productivity < 0x5a) { + _weight = 10; + _candidateSpeechID = _rngMod4 + 6; + } else { + _weight = 5; + _candidateSpeechID = _rngMod4 + 2; + } + } + if (_productivity >= 0x65) { + _candidateCount = _candidateCount + 1; + if (this->units[unitID].productivityDiv100 == 0 + || MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::isWorkerAtProductionIdleState, this)( + unitID) + == 0) { + if (_productivity < 0x6e) { + _weight = 5; + _candidateSpeechID = _rngMod4 + 0x1b; + } else if (_productivity < 0x78) { + _weight = 10; + _candidateSpeechID = _rngMod4 + 0x1f; + } else if (_productivity < 0x82) { + _weight = 0xf; + _candidateSpeechID = _rngMod4 + 0x23; + } else if (_productivity < 0x8c) { + _weight = 0x14; + _candidateSpeechID = _rngMod4 + 0x27; + } else { + _weight = 0x19; + _candidateSpeechID = _rngMod4 + 0x2b; + } + } else { + switch (this->units[unitID].productivityDiv100) { + case 1: + _weight = 10; + _candidateSpeechID = 0x16; + break; + case 2: + _weight = 0xf; + _candidateSpeechID = 0x17; + break; + case 3: + _weight = 0x14; + _candidateSpeechID = 0x18; + break; + case 4: + _weight = 0x19; + _candidateSpeechID = 0x19; + break; + default: + _weight = 0x19; + _candidateSpeechID = 0x1a; + } + } + } + if (_productivity >= 0x65 || _weight != 0) { + if (_bestSpeechID == -1 + || _bestWeight < DAT_UnitPropertiesDefinedData::instance.field127_0x12268 + _weight) { + _bestSpeechID = _candidateSpeechID; + } + } + if (_candidateCount == 1 && SEC_RNG::instance.currentNumber1 % 3 == 0) { + _bestSpeechID = 1; + } else if (_bestSpeechID == -1) { + return 1; + } + if (_candidateSpeechID < 0x62) { + DAT_00ee1030::instance = 0; + } + return _bestSpeechID; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionContainsCombatUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionContainsCombatUnit.cpp new file mode 100644 index 000000000..92b6b0f77 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionContainsCombatUnit.cpp @@ -0,0 +1,162 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536A60 + int UnitsState::selectionContainsCombatUnit(uint unitID) + { + /* create a unittype array of length 80 and initialize it with 0's */ + uint selectedUnitsMap[80]; + for (int i = 0; i < 80; ++i) { + selectedUnitsMap[i] = 0; + } + /* for every unit in the game, we check whether it is owned by the current + player, whether the unit has 3 properties, and whether it has not been + mentioned in the size 80 array. Then, we put that ID at that location. + + map */ + bool _hasMatch = false; + for (DAT_CurrentUnitSlotID::instance = unitID; + (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[DAT_CurrentUnitSlotID::instance].dying == 0 + && this->units[DAT_CurrentUnitSlotID::instance].owner + == DAT_GameSynchronyState::instance.currentPlayerSlotID + && this->units[DAT_CurrentUnitSlotID::instance].isSelected != 0 + && selectedUnitsMap[(short)this->units[DAT_CurrentUnitSlotID::instance].unitType] == 0) { + selectedUnitsMap[(short)this->units[DAT_CurrentUnitSlotID::instance].unitType] + = DAT_CurrentUnitSlotID::instance; + _hasMatch = true; + } + } + /* if we have at least 1 match, return it. the order of returning seems really + arbitrary, but maybe it means something */ + if (!_hasMatch) { + return -1; + } + /* E_ARCHER */ + if (selectedUnitsMap[0x16] != 0) { + return selectedUnitsMap[0x16]; + } + if (selectedUnitsMap[0x26] != 0) { + return selectedUnitsMap[0x26]; + } + /* E_XBOW */ + if (selectedUnitsMap[0x17] != 0) { + return selectedUnitsMap[0x17]; + } + /* A_ARCHER */ + if (selectedUnitsMap[0x46] != 0) { + return selectedUnitsMap[0x46]; + } + /* A_HARCHER */ + if (selectedUnitsMap[0x4a] != 0) { + return selectedUnitsMap[0x4a]; + } + /* A_SLINGER */ + if (selectedUnitsMap[0x48] != 0) { + return selectedUnitsMap[0x48]; + } + /* A_FIRETHROWER */ + if (selectedUnitsMap[0x4c] != 0) { + return selectedUnitsMap[0x4c]; + } + /* S_FBALLISTA */ + if (selectedUnitsMap[0x4d] != 0) { + return selectedUnitsMap[0x4d]; + } + /* S_CATAPULT */ + if (selectedUnitsMap[0x27] != 0) { + return selectedUnitsMap[0x27]; + } + /* S_TREBUCHET */ + if (selectedUnitsMap[0x28] != 0) { + return selectedUnitsMap[0x28]; + } + /* S_MANGONEL */ + if (selectedUnitsMap[0x29] != 0) { + return selectedUnitsMap[0x29]; + } + /* S_BALLISTA */ + if (selectedUnitsMap[0x3d] != 0) { + return selectedUnitsMap[0x3d]; + } + /* E_SPEARMAN */ + if (selectedUnitsMap[0x18] != 0) { + return selectedUnitsMap[0x18]; + } + /* E_PIKEMAN */ + if (selectedUnitsMap[0x19] != 0) { + return selectedUnitsMap[0x19]; + } + /* E_MACEMAN */ + if (selectedUnitsMap[0x1a] != 0) { + return selectedUnitsMap[0x1a]; + } + /* E_SWORDSMAN */ + if (selectedUnitsMap[0x1b] != 0) { + return selectedUnitsMap[0x1b]; + } + /* E_KNIGHT */ + if (selectedUnitsMap[0x1c] != 0) { + return selectedUnitsMap[0x1c]; + } + /* TUNNELER */ + if (selectedUnitsMap[5] != 0) { + return selectedUnitsMap[5]; + } + /* E_LADDERMAN */ + if (selectedUnitsMap[0x1d] != 0) { + return selectedUnitsMap[0x1d]; + } + /* E_ENGINEER */ + if (selectedUnitsMap[0x1e] != 0) { + return selectedUnitsMap[0x1e]; + } + /* E_MONK */ + if (selectedUnitsMap[0x25] != 0) { + return selectedUnitsMap[0x25]; + } + /* A_SLAVE */ + if (selectedUnitsMap[0x47] != 0) { + return selectedUnitsMap[0x47]; + } + /* A_ASSASSIN */ + if (selectedUnitsMap[0x49] != 0) { + return selectedUnitsMap[0x49]; + } + /* A_SWORDSMAN */ + if (selectedUnitsMap[0x4b] != 0) { + return selectedUnitsMap[0x4b]; + } + /* LORD */ + if (selectedUnitsMap[0x37] != 0) { + return selectedUnitsMap[0x37]; + } + /* S_TOWER */ + if (selectedUnitsMap[0x3a] != 0) { + return selectedUnitsMap[0x3a]; + } + /* S_BATTERINGRAM */ + if (selectedUnitsMap[0x3b] != 0) { + return selectedUnitsMap[0x3b]; + } + /* S_SHIELD */ + if (selectedUnitsMap[0x3c] != 0) { + return selectedUnitsMap[0x3c]; + } + return -1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionContainsEngineersOnly.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionContainsEngineersOnly.cpp new file mode 100644 index 000000000..40fbe9ff7 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionContainsEngineersOnly.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535520 + BOOLEnum UnitsState::selectionContainsEngineersOnly() + { + if (this->selectionEngineers == 0) { + return FALSE; + } + for (int i = 0; i <= 26; ++i) { + if (i != 7 && (&this->selectionEuropeanArchers)[i] != 0) { + return FALSE; + } + } + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionContainsLaddermenOnly.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionContainsLaddermenOnly.cpp new file mode 100644 index 000000000..7ff5ac8bb --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionContainsLaddermenOnly.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x005357E0 + int UnitsState::selectionContainsLaddermenOnly() + { + if (this->selectionLaddermen == 0) { + return 0; + } + for (int i = 0; i <= 26; ++i) { + if (i != 8 && (&this->selectionEuropeanArchers)[i] != 0) { + return 0; + } + } + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionContainsOnlyArabAssassins.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionContainsOnlyArabAssassins.cpp new file mode 100644 index 000000000..4c36ccb20 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionContainsOnlyArabAssassins.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535810 + BOOLEnum UnitsState::selectionContainsOnlyArabAssassins() + { + if (this->selectionArabAssassin == 0) { + return FALSE; + } + for (int i = 0; i <= 26; ++i) { + if (i != 22 && (&this->selectionEuropeanArchers)[i] != 0) { + return FALSE; + } + } + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionContainsRangedOnlyUnits.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionContainsRangedOnlyUnits.cpp new file mode 100644 index 000000000..da6708ed7 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionContainsRangedOnlyUnits.cpp @@ -0,0 +1,30 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535730 + BOOLEnum UnitsState::selectionContainsRangedOnlyUnits() + { + if (this->selectionEuropeanArchers != 0 || this->selectionCrossbowmen != 0 || this->selectionArabArcher != 0 + || this->selectionArabSlinger != 0 || this->selectionArabHorseArchers != 0 + || this->selectionArabFireThrower != 0 || this->selectionFireBallista != 0 + || this->selectionCatapults != 0 || this->selectionTrebuchets != 0) { + for (int i = 0; i <= 26; ++i) { + if (i != 0 && i != 3 && i != 19 && i != 21 && i != 23 && i != 25 && i != 26 && i != 11 && i != 12 + && (&this->selectionEuropeanArchers)[i] != 0) { + return FALSE; + } + } + return TRUE; + } + return FALSE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionContainsShieldmenOnly.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionContainsShieldmenOnly.cpp new file mode 100644 index 000000000..89ced34e6 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionContainsShieldmenOnly.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00535840 + int UnitsState::selectionContainsShieldmenOnly() + { + if (this->selectionShield == 0) { + return 0; + } + for (int i = 0; i <= 26; ++i) { + if (i != 15 && (&this->selectionEuropeanArchers)[i] != 0) { + return 0; + } + } + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionContainsTunnelersOnly.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionContainsTunnelersOnly.cpp new file mode 100644 index 000000000..5f7dfbb1a --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionContainsTunnelersOnly.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00535700 + int UnitsState::selectionContainsTunnelersOnly() + { + if (this->selectionTunnelers == 0) { + return 0; + } + for (int i = 0; i <= 26; ++i) { + if (i != 9 && (&this->selectionEuropeanArchers)[i] != 0) { + return 0; + } + } + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionHasArchers.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionHasArchers.cpp new file mode 100644 index 000000000..174d7be44 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionHasArchers.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00535560 + BOOLEnum UnitsState::selectionHasArchers() + { + if (this->selectionEuropeanArchers != 0) { + return TRUE; + } + return (BOOLEnum)(this->selectionArabArcher != 0); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionHasEngineers.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionHasEngineers.cpp new file mode 100644 index 000000000..6f6f29301 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionHasEngineers.cpp @@ -0,0 +1,12 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00535550 + BOOLEnum UnitsState::selectionHasEngineers() { return (BOOLEnum)(this->selectionEngineers != 0); } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionHasFootSoldiers.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionHasFootSoldiers.cpp new file mode 100644 index 000000000..5f36b0d57 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionHasFootSoldiers.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00535980 + undefined4 UnitsState::selectionHasFootSoldiers() + { + if (this->selectionEngineers == 0 && this->selectionArabSlave == 0 && this->selectionSpearmen == 0 + && this->selectionEuropeanArchers == 0 && this->selectionMacemen == 0 && this->selectionPikemen == 0) { + return 0; + } + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionHasMixedAssaultAndInfantry.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionHasMixedAssaultAndInfantry.cpp new file mode 100644 index 000000000..43fc774de --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionHasMixedAssaultAndInfantry.cpp @@ -0,0 +1,27 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x005355E0 + undefined4 UnitsState::selectionHasMixedAssaultAndInfantry() + { + if (this->selectionKnights != 0 || this->selectionLaddermen != 0 || this->selectionBatteringRam != 0 + || this->selectionTrebuchets != 0 || this->selectionCatapults != 0 + || this->selectionArabHorseArchers != 0 || this->selectionFireBallista != 0 + || this->selectionSiegeTower != 0) { + for (int i = 0; i <= 26; ++i) { + if (i != 6 && i != 8 && i != 13 && i != 12 && i != 11 && i != 23 && i != 26 && i != 14 + && (&this->selectionEuropeanArchers)[i] != 0) { + return 0; + } + } + return 1; + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionHasMobileAssaultUnits.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionHasMobileAssaultUnits.cpp new file mode 100644 index 000000000..3856a7400 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionHasMobileAssaultUnits.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00535580 + undefined4 UnitsState::selectionHasMobileAssaultUnits() + { + if (this->selectionKnights == 0 && this->selectionLaddermen == 0 && this->selectionBatteringRam == 0 + && this->selectionTrebuchets == 0 && this->selectionCatapults == 0 + && this->selectionArabHorseArchers == 0 && this->selectionFireBallista == 0 + && this->selectionSiegeTower == 0) { + return 0; + } + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionHasMovableNonSiegeUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionHasMovableNonSiegeUnit.cpp new file mode 100644 index 000000000..f6167c3f9 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionHasMovableNonSiegeUnit.cpp @@ -0,0 +1,46 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00536260 + undefined4 UnitsState::selectionHasMovableNonSiegeUnit() + { + int _currentPlayerSlotID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + for (DAT_CurrentUnitSlotID::instance = 1; (int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount; + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1) { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].isSelected == 0) { + continue; + } + if (this->units[DAT_CurrentUnitSlotID::instance].owner != _currentPlayerSlotID) { + return 0; + } + if ((short)this->units[DAT_CurrentUnitSlotID::instance].unitType < 40) { + return 1; + } + if ((short)this->units[DAT_CurrentUnitSlotID::instance].unitType > 41 + && this->units[DAT_CurrentUnitSlotID::instance].unitType != OpenSHC::Map::Units::UT_S_BALLISTA) { + return 1; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionHasNoRangedUnits.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionHasNoRangedUnits.cpp new file mode 100644 index 000000000..1a312a10f --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionHasNoRangedUnits.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00535910 + undefined4 UnitsState::selectionHasNoRangedUnits() + { + if (this->selectionEuropeanArchers == 0 && this->selectionCrossbowmen == 0 && this->selectionArabArcher == 0 + && this->selectionArabSlinger == 0 && this->selectionCatapults == 0 && this->selectionTrebuchets == 0 + && this->selectionArabHorseArchers == 0 && this->selectionArabFireThrower == 0 + && this->selectionFireBallista == 0 && this->selectionMangonel == 0 && this->selectionBallista == 0) { + return 1; + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionHasShieldOrSiegeMobileUnits.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionHasShieldOrSiegeMobileUnits.cpp new file mode 100644 index 000000000..62573df62 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionHasShieldOrSiegeMobileUnits.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00535870 + undefined4 UnitsState::selectionHasShieldOrSiegeMobileUnits() + { + if (this->selectionShield != 0 || this->selectionSiegeTower != 0 || this->selectionBatteringRam != 0) { + for (int i = 0; i <= 26; ++i) { + if (i != 15 && i != 13 && i != 14 && (&this->selectionEuropeanArchers)[i] != 0) { + return 0; + } + } + return 1; + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionHasShieldOrSiegeTower.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionHasShieldOrSiegeTower.cpp new file mode 100644 index 000000000..19ce2c62b --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionHasShieldOrSiegeTower.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x005358C0 + undefined4 UnitsState::selectionHasShieldOrSiegeTower() + { + if (this->selectionShield != 0 || this->selectionSiegeTower != 0) { + for (int i = 0; i <= 26; ++i) { + if (i != 15 && i != 14 && (&this->selectionEuropeanArchers)[i] != 0) { + return 0; + } + } + return 1; + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/selectionHasUnmannedSiegeEngine.cpp b/src/OpenSHC/Map/Units/UnitsState/selectionHasUnmannedSiegeEngine.cpp new file mode 100644 index 000000000..1b91db858 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/selectionHasUnmannedSiegeEngine.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x005369F0 + BOOLEnum UnitsState::selectionHasUnmannedSiegeEngine(int unitID) + { + if (this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300 != 0) { + return FALSE; + } + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_S_CATAPULT: + case OpenSHC::Map::Units::UT_S_TREBUCHET: + case OpenSHC::Map::Units::UT_S_TOWER: + case OpenSHC::Map::Units::UT_S_BATTERINGRAM: + case OpenSHC::Map::Units::UT_S_SHIELD: + return (BOOLEnum)(this->selectionEngineers != 0); + } + return FALSE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setAIControlStatusTo100000.cpp b/src/OpenSHC/Map/Units/UnitsState/setAIControlStatusTo100000.cpp new file mode 100644 index 000000000..a5b621c46 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setAIControlStatusTo100000.cpp @@ -0,0 +1,41 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00537EE0 + void UnitsState::setAIControlStatusTo100000() + { + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[1] == -1) { + DAT_GameState::instance.playerDataArray[1].aiControlStatusRelated = 100000; + } + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[2] == -1) { + DAT_GameState::instance.playerDataArray[2].aiControlStatusRelated = 100000; + } + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[3] == -1) { + DAT_GameState::instance.playerDataArray[3].aiControlStatusRelated = 100000; + } + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[4] == -1) { + DAT_GameState::instance.playerDataArray[4].aiControlStatusRelated = 100000; + } + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[5] == -1) { + DAT_GameState::instance.playerDataArray[5].aiControlStatusRelated = 100000; + } + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[6] == -1) { + DAT_GameState::instance.playerDataArray[6].aiControlStatusRelated = 100000; + } + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[7] == -1) { + DAT_GameState::instance.playerDataArray[7].aiControlStatusRelated = 100000; + } + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[8] == -1) { + DAT_GameState::instance.playerDataArray[8].aiControlStatusRelated = 100000; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setDestinationForUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/setDestinationForUnit.cpp new file mode 100644 index 000000000..6277738e8 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setDestinationForUnit.cpp @@ -0,0 +1,217 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053D3D0 + BOOLEnum UnitsState::setDestinationForUnit(int unitID, uint x, uint y, int reusePathingInfo) + { + /* check by unit type */ + int _ableToClimbTowers + = DAT_UnitPropertiesDefinedData::instance.ABLE_TO_CLIMB_TOWERS[(short)this->units[unitID].unitType]; + if (x > 399 || y > 399 || DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + DAT_PathFindingState::instance.allAssassinsUnk = 0; + return FALSE; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::teleportUnitToUnitXAndY, this)(unitID); + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::unitIsInMoat, this)(unitID) != FALSE) { + DAT_PathFindingState::instance.climbIsIllegal = 1; + } + int _unitX = this->units[unitID].x; + this->units[unitID].climbDataID = 0; + this->units[unitID].destinationX_2Unk = (short)x; + this->units[unitID].destinationY_2Unk = (short)y; + this->units[unitID].field280_0x3f4 = 0; + if (_unitX == x && this->units[unitID].y == y) { + this->units[unitID].destinationYPosition = (short)y; + this->units[unitID].totalSizeOfPathPlan = 0; + this->units[unitID].tunnelerFinishedDigging = 0; + this->units[unitID].currentIndexInPathPlan = 0; + this->units[unitID].destinationXPosition = (short)x; + this->units[unitID].ladderExitXPosition = (short)_unitX; + this->units[unitID].ladderExitYPosition = this->units[unitID].y; + this->units[unitID].destinationTilePosition + = (short)x + DAT_ViewportRenderState::instance.translationMatrix[(short)y].addXgetTile; + this->units[unitID].previousTilePosition + = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + _unitX; + DAT_PathFindingState::instance.climbIsIllegal = 0; + DAT_PathFindingState::instance.allAssassinsUnk = 0; + return TRUE; + } + dword _fromArea + = (short)DAT_TileMapState::instance.PathConnectionLayer + [DAT_ViewportRenderState::instance.translationMatrix[this->units[unitID].y].addXgetTile + _unitX]; + int _destinationTile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + dword _toArea = (short)DAT_TileMapState::instance.PathConnectionLayer[_destinationTile]; + if ((DAT_TileMapState::instance.LogicLayer[_destinationTile] & 0x30) != 0) { + DAT_PathFindingState::instance.allAssassinsUnk = 0; + return FALSE; + } + this->units[unitID].field129_0x2a8 = DAT_TileMapState::instance.PathConnectionLayer[_destinationTile]; + if (_ableToClimbTowers == 0 + && (DAT_TileMapState::instance.LogicLayer[_destinationTile] & 0x10000100U) != 0) { + DAT_PathFindingState::instance.allAssassinsUnk = 0; + return FALSE; + } + uint _pathTargetX = x; + uint _pathTargetY = y; + if (_fromArea != _toArea) { + if (DAT_PathFindingState::instance.climbIsIllegal == 0) { + if (DAT_PathFindingState::instance.allAssassinsUnk == 0 && reusePathingInfo == 0) { + this->units[unitID].field129_0x2a8 + = (short)MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: + calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)( + this->units[unitID].owner, _fromArea, _toArea, this->units[unitID].unitCanClimb); + if (this->units[unitID].field129_0x2a8 == 0) { + DAT_PathFindingState::instance.climbIsIllegal = 0; + DAT_PathFindingState::instance.allAssassinsUnk = 0; + this->units[unitID].unknownMovementRelated_0x2d2 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::despawnUnreachableUnit, this)( + unitID); + return FALSE; + } + this->units[unitID].climbDataID = (short)MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::setClimbBasedOnClosestClimbData, + DAT_PathFindingState::ptr)(unitID, _fromArea, this->units[unitID].field129_0x2a8); + if (this->units[unitID].climbDataID == 0) { + DAT_PathFindingState::instance.climbIsIllegal = 0; + DAT_PathFindingState::instance.allAssassinsUnk = 0; + this->units[unitID].unknownMovementRelated_0x2d2 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::despawnUnreachableUnit, this)( + unitID); + return FALSE; + } + int _registerResult = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::registerUnitOnClimbData, + DAT_PathFindingState::ptr)(this->units[unitID].climbDataID, unitID); + _pathTargetX = DAT_PathFindingState::instance.climbX; + _pathTargetY = DAT_PathFindingState::instance.climbY; + if (_registerResult != 1) { + _pathTargetX = x; + _pathTargetY = y; + if (_registerResult == -1) { + DAT_PathFindingState::instance.climbIsIllegal = 0; + DAT_PathFindingState::instance.allAssassinsUnk = 0; + this->units[unitID].unknownMovementRelated_0x2d2 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::despawnUnreachableUnit, this)( + unitID); + return FALSE; + } + } + } + } else { + _fromArea = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::canNavigateFunctionReturnsArea, + DAT_PathFindingState::ptr)( + this->units[unitID].owner, _toArea, this->units[unitID].x, this->units[unitID].y); + if (_fromArea != _toArea) { + this->units[unitID].field129_0x2a8 + = (short)MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: + calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)( + this->units[unitID].owner, _fromArea, _toArea, this->units[unitID].unitCanClimb); + if (this->units[unitID].field129_0x2a8 == 0) { + DAT_PathFindingState::instance.climbIsIllegal = 0; + DAT_PathFindingState::instance.allAssassinsUnk = 0; + this->units[unitID].unknownMovementRelated_0x2d2 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::despawnUnreachableUnit, this)( + unitID); + return FALSE; + } + this->units[unitID].climbDataID = (short)MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::setClimbBasedOnClosestClimbData, + DAT_PathFindingState::ptr)(unitID, _fromArea, this->units[unitID].field129_0x2a8); + if (this->units[unitID].climbDataID == 0) { + DAT_PathFindingState::instance.climbIsIllegal = 0; + DAT_PathFindingState::instance.allAssassinsUnk = 0; + this->units[unitID].unknownMovementRelated_0x2d2 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::despawnUnreachableUnit, this)( + unitID); + return FALSE; + } + int _registerResult = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::registerUnitOnClimbData, + DAT_PathFindingState::ptr)(this->units[unitID].climbDataID, unitID); + _pathTargetX = DAT_PathFindingState::instance.climbX; + _pathTargetY = DAT_PathFindingState::instance.climbY; + if (_registerResult != 1) { + _pathTargetX = x; + _pathTargetY = y; + if (_registerResult == -1) { + DAT_PathFindingState::instance.climbIsIllegal = 0; + DAT_PathFindingState::instance.allAssassinsUnk = 0; + this->units[unitID].unknownMovementRelated_0x2d2 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::despawnUnreachableUnit, this)( + unitID); + return FALSE; + } + } + } + } + } + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::copyData, DAT_LowLevelMemory::ptr)( + 1168, &this->units[unitID], this->units); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 400, '\0', this->units[unitID].pathPlanStart); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::bindPathPlanToAlgorithmStateAndReset, + DAT_PathFindingState::ptr)(this->units[unitID].pathPlanStart); + DAT_PathFindingState::instance.unitX = this->units[unitID].x; + DAT_PathFindingState::instance.unitY = this->units[unitID].y; + if (this->units[unitID].isSelectable_OR_matchTime == 0) { + DAT_PathFindingState::instance.notAllAssassinsUnk = 1; + } + if (this->units[unitID].field64_0x90 != 0) { + DAT_PathFindingState::instance.notAllAssassinsUnk = 1; + } + DAT_PathFindingState::instance.destinationX = _pathTargetX; + DAT_PathFindingState::instance.destinationY = _pathTargetY; + dword _pathPlanSize; + if (reusePathingInfo == 0) { + _pathPlanSize = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::doPathfinding, + DAT_PathFindingState::ptr)(this->units[unitID].owner, _ableToClimbTowers); + } else { + _pathPlanSize + = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::retraceAndCommitPathPlan, + DAT_PathFindingState::ptr)(); + } + DAT_PathFindingState::instance.notAllAssassinsUnk = 0; + if ((int)_pathPlanSize > 0) { + this->units[unitID].totalSizeOfPathPlan = (short)_pathPlanSize; + this->units[unitID].tunnelerFinishedDigging = 2; + this->units[unitID].currentIndexInPathPlan = 0; + this->units[unitID].destinationXPosition = (short)_pathTargetX; + this->units[unitID].destinationYPosition = (short)_pathTargetY; + this->units[unitID].ladderExitYPosition = this->units[unitID].y; + this->units[unitID].destinationTilePosition = (short)_pathTargetX + + DAT_ViewportRenderState::instance.translationMatrix[(short)_pathTargetY].addXgetTile; + this->units[unitID].ladderExitXPosition = (short)_unitX; + this->units[unitID].previousTilePosition = this->units[unitID].x + + DAT_ViewportRenderState::instance.translationMatrix[this->units[unitID].y].addXgetTile; + this->units[unitID].cannotClimb = (ushort)(DAT_PathFindingState::instance.climbIsIllegal != 0); + DAT_PathFindingState::instance.climbIsIllegal = 0; + DAT_PathFindingState::instance.allAssassinsUnk = 0; + return TRUE; + } + DAT_PathFindingState::instance.climbIsIllegal = 0; + DAT_PathFindingState::instance.allAssassinsUnk = 0; + this->units[unitID].unknownMovementRelated_0x2d2 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::despawnUnreachableUnit, this)(unitID); + return FALSE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setDestinationNearTargetedBuilding.cpp b/src/OpenSHC/Map/Units/UnitsState/setDestinationNearTargetedBuilding.cpp new file mode 100644 index 000000000..0f3239aab --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setDestinationNearTargetedBuilding.cpp @@ -0,0 +1,58 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053DCC0 + undefined4 UnitsState::setDestinationNearTargetedBuilding(int unitID, int param_2) + { + dword _areaAtUnitTile = (short)DAT_TileMapState::instance.PathConnectionLayer[this->units[unitID].tile]; + DAT_TileMapState::instance.PathConnectionLayer[this->units[unitID].targetedBuildingTile] = _areaAtUnitTile; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: + findFreeSpaceNextToEnemyDefensiveStructureInSameAreaWithinDistance, + DAT_PathFindingState::ptr)(this->units[unitID].targetedBuildingTile, 1, (int*)(short)_areaAtUnitTile, + this->units[unitID].owner, param_2, this->units[unitID].facingDirection); + if (DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile1 == 0) { + return 0; + } + if (DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper == 0) { + return 0; + } + short _destinationY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent + [DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile1]; + int _destinationX = DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile1 + - DAT_ViewportRenderState::instance.translationMatrix[_destinationY].addXgetTile; + this->units[unitID].plannedDestinationX = (short)_destinationX; + this->units[unitID].targetingType = (UnitInstructionType)0; + DAT_PathFindingState::instance.notAllAssassinsUnk = 1; + this->units[unitID].plannedDestinationY = _destinationY; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_MOVE_TO_DESTINATION; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, _destinationX, _destinationY, 0); + if (this->units[unitID].field64_0x90 != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::changeDestinationByAmount, this)(unitID, 2); + } + short _attackTileY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent + [DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper]; + this->units[unitID].attackAtTileY = _attackTileY; + this->units[unitID].targetedBuildingTile + = DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper; + this->units[unitID].attackAtTileX = (short)this->units[unitID].targetedBuildingTile + - (short)DAT_ViewportRenderState::instance.translationMatrix[_attackTileY].addXgetTile; + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setFacingDirectionTowardCoords.cpp b/src/OpenSHC/Map/Units/UnitsState/setFacingDirectionTowardCoords.cpp new file mode 100644 index 000000000..ab28ac652 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setFacingDirectionTowardCoords.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0052FCA0 + void UnitsState::setFacingDirectionTowardCoords(int unitID, int x, int y) + { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::calculateOrientation, + DAT_DirectionAlgorithmState::ptr)(this->units[unitID].x, this->units[unitID].y, x, y); + if (DAT_DirectionAlgorithmState::instance.orientation == 15) { + return; + } + if (this->units[unitID].facingDirection == DAT_DirectionAlgorithmState::instance.orientation) { + return; + } + this->units[unitID].facingDirection = (short)DAT_DirectionAlgorithmState::instance.orientation; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setFacingDirectionTowardUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/setFacingDirectionTowardUnit.cpp new file mode 100644 index 000000000..5407cd49a --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setFacingDirectionTowardUnit.cpp @@ -0,0 +1,27 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0052FC30 + void UnitsState::setFacingDirectionTowardUnit(int unitID, int targetUnitID) + { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::calculateOrientation, + DAT_DirectionAlgorithmState::ptr)( + this->units[unitID].x, this->units[unitID].y, this->units[targetUnitID].x, this->units[targetUnitID].y); + if (DAT_DirectionAlgorithmState::instance.orientation == 15) { + return; + } + if (this->units[unitID].facingDirection == DAT_DirectionAlgorithmState::instance.orientation) { + return; + } + this->units[unitID].facingDirection = (short)DAT_DirectionAlgorithmState::instance.orientation; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setFacingDirectionTowardUnitMicro.cpp b/src/OpenSHC/Map/Units/UnitsState/setFacingDirectionTowardUnitMicro.cpp new file mode 100644 index 000000000..5b93d37db --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setFacingDirectionTowardUnitMicro.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052FE00 + void UnitsState::setFacingDirectionTowardUnitMicro(int unitID, int targetUnitID) + { + if (targetUnitID <= 0) { + return; + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::calculatePreferredRelativeOrientation, + DAT_DirectionAlgorithmState::ptr)(this->units[unitID].microXPosition, + this->units[unitID].microYPosition, this->units[targetUnitID].microXPosition, + this->units[targetUnitID].microYPosition); + if (DAT_DirectionAlgorithmState::instance.orientation == 15) { + return; + } + UnitTypeShort _unitType = this->units[unitID].unitType; + this->units[unitID].orientation = (short)DAT_DirectionAlgorithmState::instance.orientation; + if (_unitType != OpenSHC::Map::Units::UT_E_KNIGHT) { + return; + } + this->units[unitID].orientation = this->units[unitID].orientation - 1; + if (this->units[unitID].orientation < 0) { + this->units[unitID].orientation = this->units[unitID].orientation + 8; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setMissionNumberSpecificLord.cpp b/src/OpenSHC/Map/Units/UnitsState/setMissionNumberSpecificLord.cpp new file mode 100644 index 000000000..ddd6ebcc5 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setMissionNumberSpecificLord.cpp @@ -0,0 +1,55 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005308F0 + void UnitsState::setMissionNumberSpecificLord(int missionNumber) + { + if (missionNumber == 5 || missionNumber == 6 || missionNumber == 8 || missionNumber == 15) { + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[unitID].dying == 0 + && this->units[unitID].owner != DAT_GameSynchronyState::instance.currentPlayerSlotID + && this->units[unitID].unitType == OpenSHC::Map::Units::UT_LORD) { + this->units[unitID].unknownLordTypeBasedMissionSpecificValue_01 = 1; + } + } + return; + } + if (missionNumber <= 15) { + return; + } + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].owner == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + continue; + } + if (this->units[unitID].unitType != OpenSHC::Map::Units::UT_LORD) { + continue; + } + if (MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::getLordTypeForPlayer, + DAT_GameSynchronyState::ptr)(this->units[unitID].owner) + == 1) { + this->units[unitID].unknownLordTypeBasedMissionSpecificValue_01 = 1; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setMoveDelayForUnitsOnSameTiles.cpp b/src/OpenSHC/Map/Units/UnitsState/setMoveDelayForUnitsOnSameTiles.cpp new file mode 100644 index 000000000..b30f90320 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setMoveDelayForUnitsOnSameTiles.cpp @@ -0,0 +1,93 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/MSVC_SecurityCookie.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F260 + void UnitsState::setMoveDelayForUnitsOnSameTiles(int unitID, int unitIDCurrentTilePosition) + { + short _unitIDArray[2010]; + int _lowestMovementSpeed = 0x14; + this->units[unitID].unitOrderWhenOnSameTile = 0; + if (this->units[unitID].unknownTestAgainst0_2 != 0) { + return; + } + this->units[unitID].field40_0x5a = 0; + /* if current tile position is not occupied */ + if (DAT_TileMapState::instance.UnitLayer[unitIDCurrentTilePosition] == 0) { + DAT_TileMapState::instance.UnitLayer[unitIDCurrentTilePosition] = (ushort)unitID; + this->units[unitID].nextUnitOnTheSameTile = 0; + return; + } + /* if current tile position is occupied */ + bool _isInserted = false; + int _unitIDOfAUnitOnSameTile = (short)DAT_TileMapState::instance.UnitLayer[unitIDCurrentTilePosition]; + int _index = 0; + int _writeIndex = 0; + while (true) { + _writeIndex = _index; + if (unitID < _unitIDOfAUnitOnSameTile && !_isInserted) { + _unitIDArray[_index] = (short)unitID; + _writeIndex = _index + 1; + _isInserted = true; + } + _unitIDArray[_writeIndex] = (short)_unitIDOfAUnitOnSameTile; + _unitIDOfAUnitOnSameTile = (short)this->units[_unitIDOfAUnitOnSameTile].nextUnitOnTheSameTile; + if (_unitIDOfAUnitOnSameTile < 1) { + break; + } + _index = _writeIndex + 1; + _writeIndex = _index; + if (_index >= 2000) { + break; + } + } + _writeIndex = _writeIndex + 1; + if (!_isInserted) { + _unitIDArray[_writeIndex] = (short)unitID; + _writeIndex = _writeIndex + 2; + } + _unitIDArray[_writeIndex] = 0; + DAT_TileMapState::instance.UnitLayer[unitIDCurrentTilePosition] = (ushort)_unitIDArray[0]; + this->units[_unitIDArray[0]].unitOrderWhenOnSameTile = 0; + int _previousUnitID = _unitIDArray[0]; + for (int _order = 1; _order < 2001; ++_order) { + this->units[_previousUnitID].nextUnitOnTheSameTile = _unitIDArray[_order]; + if (_unitIDArray[_order] < 1) { + break; + } + this->units[_unitIDArray[_order]].unitOrderWhenOnSameTile = (short)_order; + _previousUnitID = _unitIDArray[_order]; + } + for (int i = 0; i < 2000; ++i) { + if (_unitIDArray[i] < 1) { + break; + } + if (this->units[_unitIDArray[i]].tunnelerFinishedDigging == 2 + && this->units[_unitIDArray[i]].movementSpeed < _lowestMovementSpeed) { + _lowestMovementSpeed = this->units[_unitIDArray[i]].movementSpeed; + } + } + for (int i = 0; i < 2000; ++i) { + if (_unitIDArray[i] < 1) { + break; + } + if (this->units[_unitIDArray[i]].tunnelerFinishedDigging == 2 + && this->units[_unitIDArray[i]].moveDelay == 0) { + if (_lowestMovementSpeed < this->units[_unitIDArray[i]].movementSpeed) { + this->units[_unitIDArray[i]].moveDelay + = this->units[_unitIDArray[i]].unitOrderWhenOnSameTile / 2 + 1; + } else { + _lowestMovementSpeed = 0; + } + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setPositionOfUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/setPositionOfUnit.cpp new file mode 100644 index 000000000..8a293c1c0 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setPositionOfUnit.cpp @@ -0,0 +1,38 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053E900 + void UnitsState::setPositionOfUnit(int unitID, uint x, uint y, undefined4 height) + { + if (x >= 400 || y >= 400) { + return; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return; + } + this->units[unitID].currentIndexInPathPlan = 0; + this->units[unitID].tunnelerFinishedDigging = 0; + this->units[unitID].field105_0xe8 = 0; + this->units[unitID].movementRelated = 8; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setupUnitSharingCurrentTilePosition, this)(unitID); + this->units[unitID].microXPosition = (short)x * 8 + 4; + this->units[unitID].microYPosition = (short)y * 8 + 4; + this->units[unitID].terrainOrClimbHeight = (short)height; + this->units[unitID].mimicCurrentXPosition = (short)x; + this->units[unitID].x = (short)x; + this->units[unitID].mimicCurrentYPosition = (short)y; + this->units[unitID].y = (short)y; + this->units[unitID].tile + = (short)x + DAT_ViewportRenderState::instance.translationMatrix[(short)y].addXgetTile; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::commitPendingUnitPosition, this)(unitID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::updateMicroPosition, this)(unitID); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setRandomNumberOnCows.cpp b/src/OpenSHC/Map/Units/UnitsState/setRandomNumberOnCows.cpp new file mode 100644 index 000000000..247891283 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setRandomNumberOnCows.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00530880 + void UnitsState::setRandomNumberOnCows(int playerID) + { + for (int unitID = 0; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[unitID].dying == 0 && this->units[unitID].unitType == OpenSHC::Map::Units::UT_COW + && this->units[unitID].owner == playerID) { + this->units[unitID].digTileX__OR__countCurrentlyManningEnginers__OR__forCowsRandomBelow300 + = SEC_RNG::instance.currentNumber2 % 300; + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setRandomShootLocation.cpp b/src/OpenSHC/Map/Units/UnitsState/setRandomShootLocation.cpp new file mode 100644 index 000000000..8b94794f7 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setRandomShootLocation.cpp @@ -0,0 +1,123 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x005330A0 + void UnitsState::setRandomShootLocation(int unitID, int microX, int microY, int z) + { + int _distanceX; + if (this->units[unitID].microXPosition < microX) { + _distanceX = microX - this->units[unitID].microXPosition; + } else { + _distanceX = this->units[unitID].microXPosition - microX; + } + int _distance; + if (this->units[unitID].microYPosition < microY) { + _distance = microY - this->units[unitID].microYPosition; + } else { + _distance = this->units[unitID].microYPosition - microY; + } + if (_distance <= _distanceX) { + _distance = _distanceX; + } + int _rng = SEC_RNG::instance.currentNumber2; + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + int _spreadAlong; + int _spreadAcross; + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) { + _spreadAlong = 0; + if ((_rng & 3) == 0) { + _spreadAlong = _rng % 0x60 + -0x30; + } + _spreadAcross = (_rng / 256) % 0x60 + -0x30; + z = z + -0x10 + (_rng / 128) % 0x20; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_CATAPULT) { + _spreadAlong = _rng % 0x80 - 0x60; + _spreadAcross = (_rng / 256) % 0x60 + -0x30; + z = z + -0x30 + (_rng / 128) % 0x40; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_MANGONEL) { + _spreadAlong = _rng % 0xe0 + -0x70; + _spreadAcross = (_rng / 256) % 0x80 - 0x40; + z = z + -0x40 + (_rng / 128) % 0x80; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_BALLISTA) { + if (this->units[unitID].targetingType == OpenSHC::Map::Units::UIT_ATTACK_LAND) { + _spreadAlong = _rng % 0x20 - 0x18; + _spreadAcross = (_rng / 256) % 0x28 + -0x14; + z = z + -0x14 + (_rng / 128) % 0x28; + } else { + _spreadAlong = 0; + _spreadAcross = 0; + } + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_FBALLISTA + && this->units[unitID].targetingType != OpenSHC::Map::Units::UIT_ATTACK_LAND) { + _spreadAlong = 0; + _spreadAcross = 0; + z = z + (_rng / 128) % 0x1e; + } else { + _spreadAlong = _rng % 0x60 + -0x30; + _spreadAcross = (_rng / 256) % 0x50 + -0x28; + z = z + -0x28 + (_rng / 128) % 0x50; + } + if (z < 8) { + z = 8; + } else if (z > 250) { + z = 250; + } + if (_distance / 2 < _spreadAlong) { + _spreadAlong = _spreadAlong / 2; + _spreadAcross = _spreadAcross / 2; + } + if (_distance < _spreadAlong) { + _spreadAlong = -_spreadAlong; + } + switch (this->units[unitID].facingDirection) { + case 0: + microY = microY + _spreadAlong; + microX = microX + _spreadAcross; + break; + case 1: + microX = microX + ((_spreadAcross * 3) / 4 - (_spreadAlong * 3) / 4); + microY = microY + (_spreadAlong * 3) / 4 + (_spreadAcross * 3) / 4; + break; + case 2: + microX = microX - _spreadAlong; + microY = microY + _spreadAcross; + break; + case 3: + microX = microX + (-((_spreadAlong * 3) / 4) - (_spreadAcross * 3) / 4); + microY = microY + ((_spreadAcross * 3) / 4 - (_spreadAlong * 3) / 4); + break; + case 4: + microY = microY - _spreadAlong; + microX = microX + _spreadAcross; + break; + case 5: + microX = microX + ((_spreadAlong * 3) / 4 - (_spreadAcross * 3) / 4); + microY = microY + (-((_spreadAcross * 3) / 4) - (_spreadAlong * 3) / 4); + break; + case 6: + microX = microX + _spreadAlong; + microY = microY + _spreadAcross; + break; + case 7: + microX = microX + (_spreadAlong * 3) / 4 + (_spreadAcross * 3) / 4; + microY = microY + ((_spreadAlong * 3) / 4 - (_spreadAcross * 3) / 4); + } + this->units[unitID].shootTargetZ = (short)z; + this->units[unitID].shootTargetMicroY = (short)microY; + this->units[unitID].shootTargetMicroX = (short)microX; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setTowerSiegeEngineToIdle.cpp b/src/OpenSHC/Map/Units/UnitsState/setTowerSiegeEngineToIdle.cpp new file mode 100644 index 000000000..98cb64a8d --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setTowerSiegeEngineToIdle.cpp @@ -0,0 +1,41 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537E00 + void UnitsState::setTowerSiegeEngineToIdle(int buildingID) + { + UnitTypeShort _siegeEngineType; + if (DAT_BuildingsState::instance.buildings[buildingID].containsSiegeMangonel1OrBallista2 == 1) { + _siegeEngineType = OpenSHC::Map::Units::UT_S_MANGONEL; + } else if (DAT_BuildingsState::instance.buildings[buildingID].containsSiegeMangonel1OrBallista2 == 2) { + _siegeEngineType = OpenSHC::Map::Units::UT_S_BALLISTA; + } else { + return; + } + for (int unitID = 0; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[unitID].dying == 0 && this->units[unitID].unitType == _siegeEngineType + && DAT_TileMapState::instance.BuildingLayer[this->units[unitID].tile] == buildingID) { + this->units[unitID].state.generic + = (OpenSHC::Map::Units::States::US_STAND_UPUnk | OpenSHC::Map::Units::States::US_IDLEUnk); + return; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setUnitFacingDirectionBasedOnBuilding.cpp b/src/OpenSHC/Map/Units/UnitsState/setUnitFacingDirectionBasedOnBuilding.cpp new file mode 100644 index 000000000..7843d74af --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setUnitFacingDirectionBasedOnBuilding.cpp @@ -0,0 +1,64 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0052FF80 + uint UnitsState::setUnitFacingDirectionBasedOnBuilding(int unitID, int buildingID) + { + if (buildingID == 0) { + return 0; + } + int _previousFacingDirection = this->units[unitID].facingDirection; + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::calculatePreferredRelativeOrientation, + DAT_DirectionAlgorithmState::ptr)(this->units[unitID].x, this->units[unitID].y, + (short)DAT_BuildingsState::instance.buildings[buildingID].x, + (short)DAT_BuildingsState::instance.buildings[buildingID].y); + if (DAT_DirectionAlgorithmState::instance.orientation == 15) { + return 0; + } + if (this->units[unitID].facingDirection == DAT_DirectionAlgorithmState::instance.orientation) { + return 0; + } + int _clockwiseSteps + = DAT_DirectionAlgorithmState::instance.orientation - this->units[unitID].facingDirection; + if (_clockwiseSteps < 0) { + _clockwiseSteps = _clockwiseSteps + 8; + } + int _counterClockwiseSteps + = this->units[unitID].facingDirection - DAT_DirectionAlgorithmState::instance.orientation; + if (_counterClockwiseSteps < 0) { + _counterClockwiseSteps = _counterClockwiseSteps + 8; + } + if (_counterClockwiseSteps < _clockwiseSteps) { + this->units[unitID].facingDirection = this->units[unitID].facingDirection - 1; + } else { + this->units[unitID].facingDirection = this->units[unitID].facingDirection + 1; + } + if (this->units[unitID].facingDirection < 0) { + this->units[unitID].facingDirection = this->units[unitID].facingDirection + 8; + } + if (this->units[unitID].facingDirection > 7) { + this->units[unitID].facingDirection = this->units[unitID].facingDirection - 8; + } + this->units[unitID].facingDirectionMapOrientationCorrected = this->units[unitID].facingDirection; + this->units[unitID].facingDirectionMapOrientationCorrected + = this->units[unitID].facingDirectionMapOrientationCorrected + - (short)DAT_TileMapState::instance.mapOrientation; + if (this->units[unitID].facingDirectionMapOrientationCorrected < 0) { + this->units[unitID].facingDirectionMapOrientationCorrected + = this->units[unitID].facingDirectionMapOrientationCorrected + 8; + } + return (uint)(_previousFacingDirection != this->units[unitID].facingDirection); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setUnitFacingDirectionForTargetXandY.cpp b/src/OpenSHC/Map/Units/UnitsState/setUnitFacingDirectionForTargetXandY.cpp new file mode 100644 index 000000000..dcb1ced76 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setUnitFacingDirectionForTargetXandY.cpp @@ -0,0 +1,61 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052FE90 + BOOLEnum UnitsState::setUnitFacingDirectionForTargetXandY(int unitID, int targetX, int targetY) + { + int _previousFacingDirection = this->units[unitID].facingDirection; + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::calculatePreferredRelativeOrientation, + DAT_DirectionAlgorithmState::ptr)(this->units[unitID].x, this->units[unitID].y, targetX, targetY); + if (DAT_DirectionAlgorithmState::instance.orientation == 15) { + return FALSE; + } + if (this->units[unitID].facingDirection == DAT_DirectionAlgorithmState::instance.orientation) { + return FALSE; + } + int _clockwiseSteps + = DAT_DirectionAlgorithmState::instance.orientation - this->units[unitID].facingDirection; + if (_clockwiseSteps < 0) { + _clockwiseSteps = _clockwiseSteps + 8; + } + int _counterClockwiseSteps + = this->units[unitID].facingDirection - DAT_DirectionAlgorithmState::instance.orientation; + if (_counterClockwiseSteps < 0) { + _counterClockwiseSteps = _counterClockwiseSteps + 8; + } + if (_counterClockwiseSteps < _clockwiseSteps) { + this->units[unitID].facingDirection = this->units[unitID].facingDirection - 1; + } else { + this->units[unitID].facingDirection = this->units[unitID].facingDirection + 1; + } + if (this->units[unitID].facingDirection < 0) { + this->units[unitID].facingDirection = this->units[unitID].facingDirection + 8; + } + if (this->units[unitID].facingDirection > 7) { + this->units[unitID].facingDirection = this->units[unitID].facingDirection - 8; + } + this->units[unitID].facingDirectionMapOrientationCorrected = this->units[unitID].facingDirection; + this->units[unitID].facingDirectionMapOrientationCorrected + = this->units[unitID].facingDirectionMapOrientationCorrected + - (short)DAT_TileMapState::instance.mapOrientation; + if (this->units[unitID].facingDirectionMapOrientationCorrected < 0) { + this->units[unitID].facingDirectionMapOrientationCorrected + = this->units[unitID].facingDirectionMapOrientationCorrected + 8; + } + return (BOOLEnum)(_previousFacingDirection != this->units[unitID].facingDirection); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setUnitFacingDirectionTowardsTarget.cpp b/src/OpenSHC/Map/Units/UnitsState/setUnitFacingDirectionTowardsTarget.cpp new file mode 100644 index 000000000..1e2ebfcce --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setUnitFacingDirectionTowardsTarget.cpp @@ -0,0 +1,61 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0052FD00 + undefined4 UnitsState::setUnitFacingDirectionTowardsTarget(int unitID, int targetUnitID) + { + if (targetUnitID <= 0) { + return 0; + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::calculatePreferredRelativeOrientation, + DAT_DirectionAlgorithmState::ptr)( + this->units[unitID].x, this->units[unitID].y, this->units[targetUnitID].x, this->units[targetUnitID].y); + if (DAT_DirectionAlgorithmState::instance.orientation == 15) { + return 0; + } + if (this->units[unitID].facingDirection == DAT_DirectionAlgorithmState::instance.orientation) { + return 0; + } + int _clockwiseSteps + = DAT_DirectionAlgorithmState::instance.orientation - this->units[unitID].facingDirection; + if (_clockwiseSteps < 0) { + _clockwiseSteps = _clockwiseSteps + 8; + } + int _counterClockwiseSteps + = this->units[unitID].facingDirection - DAT_DirectionAlgorithmState::instance.orientation; + if (_counterClockwiseSteps < 0) { + _counterClockwiseSteps = _counterClockwiseSteps + 8; + } + if (_counterClockwiseSteps < _clockwiseSteps) { + this->units[unitID].facingDirection = this->units[unitID].facingDirection - 1; + } else { + this->units[unitID].facingDirection = this->units[unitID].facingDirection + 1; + } + if (this->units[unitID].facingDirection < 0) { + this->units[unitID].facingDirection = this->units[unitID].facingDirection + 8; + } + if (this->units[unitID].facingDirection > 7) { + this->units[unitID].facingDirection = this->units[unitID].facingDirection - 8; + } + this->units[unitID].facingDirectionMapOrientationCorrected = this->units[unitID].facingDirection; + this->units[unitID].facingDirectionMapOrientationCorrected + = this->units[unitID].facingDirectionMapOrientationCorrected + - (short)DAT_TileMapState::instance.mapOrientation; + if (this->units[unitID].facingDirectionMapOrientationCorrected < 0) { + this->units[unitID].facingDirectionMapOrientationCorrected + = this->units[unitID].facingDirectionMapOrientationCorrected + 8; + } + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setUnitValues.cpp b/src/OpenSHC/Map/Units/UnitsState/setUnitValues.cpp new file mode 100644 index 000000000..d1237fad1 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setUnitValues.cpp @@ -0,0 +1,84 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_TextureRenderCoreObject.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053B8E0 + void UnitsState::setUnitValues(int unitID, UnitType unitType) + { + this->units[unitID].unitType = (UnitTypeShort)unitType; + this->units[unitID].field64_0x90 = (short)DAT_UnitPropertiesDefinedData::instance.field65_0x7634[unitType]; + this->units[unitID].isStalked = (byte)DAT_UnitPropertiesDefinedData::instance.field66_0x7774[unitType]; + this->units[unitID].gmIDUnk = (short)DAT_UnitPropertiesDefinedData::instance.SPRITE_ID[unitType]; + this->units[unitID].spriteID = (short)DAT_UnitPropertiesDefinedData::instance.SPRITE_ID[unitType]; + this->units[unitID].gfxNumber = 1; + this->units[unitID].field22_0x2a = (short)DAT_TextureRenderCoreObject::instance + .gmFileHeaderColorpaletteArray[this->units[unitID].spriteID] + .originX; + *(short*)&this->units[unitID].unknownV = (short)DAT_TextureRenderCoreObject::instance + .gmFileHeaderColorpaletteArray[this->units[unitID].spriteID] + .originY; + this->units[unitID].spriteWidthUnk + = (short)DAT_UnitPropertiesDefinedData::instance.UNIT_SPRITE_DIMENSIONS[unitType][0]; + this->units[unitID].spriteHeightUnk + = (short)DAT_UnitPropertiesDefinedData::instance.UNIT_SPRITE_DIMENSIONS[unitType][1]; + this->units[unitID].drawXOffset = this->units[unitID].field22_0x2a - this->units[unitID].spriteWidthUnk / 2; + this->units[unitID].someDrawYOffset + = ((short)this->units[unitID].unknownV - this->units[unitID].spriteHeightUnk) + 3; + this->units[unitID].movementSpeed + = (short)DAT_UnitPropertiesDefinedData::instance.UNIT_MOVEMENT_SPEED_ARRAY[unitType]; + this->units[unitID].calculatedMovementSpeed = this->units[unitID].movementSpeed; + this->units[unitID].field200_0x354 = 0; + this->units[unitID].field199_0x350 = 0; + this->units[unitID].maxHealth = DAT_UnitPropertiesDefinedData::instance.BASE_HP[unitType]; + this->units[unitID].health = this->units[unitID].maxHealth; + if (this->units[unitID].maxHealth == 0) { + this->units[unitID].healthPercentage = 100; + } else { + this->units[unitID].healthPercentage + = (short)((this->units[unitID].health * 100) / this->units[unitID].maxHealth); + } + byte _firstNameIndex = this->units[unitID].firstNameIndex; + this->units[unitID].healthbar = this->units[unitID].healthPercentage / 10; + this->units[unitID].unitCanClimb = (short)DAT_UnitPropertiesDefinedData::instance.UNIT_CLIMB[unitType]; + this->units[unitID].someUnitStat4 + = (short)DAT_UnitPropertiesDefinedData::instance.SomeUnitStatMatrix4[unitType]; + this->units[unitID].graphicSize = (short)DAT_UnitPropertiesDefinedData::instance.GRAPHIC_SIZE[unitType]; + this->units[unitID].someUnitStat2_meleeDamageUnk + = (short)DAT_UnitPropertiesDefinedData::instance.UNIT_CAN_MELEE[unitType]; + this->units[unitID].enemyNoticeFrequencyUnk + = DAT_UnitPropertiesDefinedData::instance.UNIT_ENEMY_NOTICE_RANGE[unitType]; + this->units[unitID].moveableUnk = (short)DAT_UnitPropertiesDefinedData::instance.UNIT_MOVABLE[unitType]; + if ((char)_firstNameIndex < '\x01' || unitType == OpenSHC::Map::Units::UT_BREWER + || unitType == OpenSHC::Map::Units::UT_TANNER || unitType == OpenSHC::Map::Units::UT_LADY + || unitType == OpenSHC::Map::Units::UT_MOTHER || unitType == OpenSHC::Map::Units::UT_JUGGLER + || unitType == OpenSHC::Map::Units::UT_FIREEATER || unitType == OpenSHC::Map::Units::UT_PRIEST) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignNameToUnit, this)(unitID); + } + if (this->units[unitID].owner <= 0) { + this->units[unitID].occupancyOrFlag = 0xff; + this->units[unitID].field258_0x3d1 = 0xff; + } else { + this->units[unitID].occupancyOrFlag = '\x01' << ((char)this->units[unitID].owner - 1U & 0x1f); + this->units[unitID].field258_0x3d1 = ~this->units[unitID].occupancyOrFlag; + } + this->units[unitID].isSelectable_OR_matchTime = 0; + this->units[unitID].field316_0x430 = 0; + if (unitType != OpenSHC::Map::Units::UT_CAGEDOG) { + this->units[unitID].unknownBool01 = 500; + } + if (unitType == OpenSHC::Map::Units::UT_A_ASSASSIN) { + this->units[unitID].assassinsMicroDistanceToEnemyUnk = 32000; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setWorkplaceBuildingEntryAsTarget.cpp b/src/OpenSHC/Map/Units/UnitsState/setWorkplaceBuildingEntryAsTarget.cpp new file mode 100644 index 000000000..c783dd310 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setWorkplaceBuildingEntryAsTarget.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x005343F0 + undefined4 UnitsState::setWorkplaceBuildingEntryAsTarget(int unitID, int entryAngleUnk) + { + int _buildingID = this->units[unitID].workplaceBuildingID_1; + if (DAT_BuildingsState::instance.buildings[_buildingID].uid == this->units[unitID].workplaceBuildingUID) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::buildingIsAccessible, + DAT_BuildingsState::ptr)(_buildingID, entryAngleUnk) + != 0) { + this->units[unitID].targetX_2 = DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX; + this->units[unitID].targetY_2 = DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryY; + return 1; + } + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setupUnitSharingCurrentTilePosition.cpp b/src/OpenSHC/Map/Units/UnitsState/setupUnitSharingCurrentTilePosition.cpp new file mode 100644 index 000000000..6e4377aac --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setupUnitSharingCurrentTilePosition.cpp @@ -0,0 +1,16 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053BB70 + void UnitsState::setupUnitSharingCurrentTilePosition(int unitID) + { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setupUnitSharingTileIDs, this)( + unitID, this->units[unitID].tile); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/setupUnitSharingTileIDs.cpp b/src/OpenSHC/Map/Units/UnitsState/setupUnitSharingTileIDs.cpp new file mode 100644 index 000000000..c92ccdf7b --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/setupUnitSharingTileIDs.cpp @@ -0,0 +1,35 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F440 + void UnitsState::setupUnitSharingTileIDs(int unitID, int unitCurrentTilePosition) + { + if (unitCurrentTilePosition == 0) { + return; + } + this->units[unitID].unitOrderWhenOnSameTile = 0; + if ((short)DAT_TileMapState::instance.UnitLayer[unitCurrentTilePosition] == unitID) { + DAT_TileMapState::instance.UnitLayer[unitCurrentTilePosition] + = this->units[unitID].nextUnitOnTheSameTile; + this->units[unitID].nextUnitOnTheSameTile = 0; + return; + } + int _previousUnitID = (short)DAT_TileMapState::instance.UnitLayer[unitCurrentTilePosition]; + while (_previousUnitID != 0 && (short)this->units[_previousUnitID].nextUnitOnTheSameTile != unitID) { + _previousUnitID = (short)this->units[_previousUnitID].nextUnitOnTheSameTile; + if (_previousUnitID == 0) { + return; + } + } + this->units[_previousUnitID].nextUnitOnTheSameTile = this->units[unitID].nextUnitOnTheSameTile; + this->units[unitID].nextUnitOnTheSameTile = 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/shootProjectile.cpp b/src/OpenSHC/Map/Units/UnitsState/shootProjectile.cpp new file mode 100644 index 000000000..44c7c663c --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/shootProjectile.cpp @@ -0,0 +1,189 @@ +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Entities/EntityType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Entities::EntityType; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x00532700 + void UnitsState::shootProjectile( + int unitID, EntityType projectileType, int targetX, int targetY, int targetZUnk) + { + if (projectileType == OpenSHC::Map::Entities::ET_TREBUCHET) { + if (DAT_UnitsState::instance.units[unitID].field243_0x3b0 == 0) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(unitID, + this->units[unitID].owner, this->units[unitID].calculatedOwnerPlayerIndex, + this->units[unitID].microXPosition, this->units[unitID].microYPosition, + this->units[unitID].buildingHeight + 0x82 + this->units[unitID].terrainOrClimbHeight, targetX, + targetY, targetZUnk, OpenSHC::Map::Entities::ET_TREBUCHET, 0); + } else { + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(unitID, + this->units[unitID].owner, this->units[unitID].calculatedOwnerPlayerIndex, + this->units[unitID].microXPosition, this->units[unitID].microYPosition, + this->units[unitID].buildingHeight + 0x82 + this->units[unitID].terrainOrClimbHeight, targetX, + targetY, targetZUnk, OpenSHC::Map::Entities::ET_COW_FLYING, 0); + } + } else if (projectileType == OpenSHC::Map::Entities::ET_CATAPULT) { + int _offsetX = 0; + int _offsetY = 0; + switch (this->units[unitID].facingDirection) { + case 0: + _offsetY = -7; + break; + case 1: + _offsetX = 4; + _offsetY = -4; + break; + case 2: + _offsetX = 7; + break; + case 3: + _offsetX = 4; + _offsetY = 4; + break; + case 4: + _offsetY = 7; + break; + case 5: + _offsetX = -4; + _offsetY = 4; + break; + case 6: + _offsetX = -7; + break; + case 7: + _offsetX = -4; + _offsetY = -4; + } + if (DAT_UnitsState::instance.units[unitID].field243_0x3b0 == 0) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(unitID, + this->units[unitID].owner, this->units[unitID].calculatedOwnerPlayerIndex, + this->units[unitID].microXPosition + _offsetX, this->units[unitID].microYPosition + _offsetY, + this->units[unitID].buildingHeight + 0x38 + this->units[unitID].terrainOrClimbHeight, targetX, + targetY, targetZUnk, OpenSHC::Map::Entities::ET_CATAPULT, 0); + } else { + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(unitID, + this->units[unitID].owner, this->units[unitID].calculatedOwnerPlayerIndex, + this->units[unitID].microXPosition + _offsetX, this->units[unitID].microYPosition + _offsetY, + this->units[unitID].buildingHeight + 0x38 + this->units[unitID].terrainOrClimbHeight, targetX, + targetY, targetZUnk, OpenSHC::Map::Entities::ET_COW_FLYING, 0); + } + } else if (projectileType == OpenSHC::Map::Entities::ET_MANGONEL) { + int _offsetX = 0; + int _offsetY = 0; + switch (this->units[unitID].facingDirection) { + case 0: + _offsetY = -2; + break; + case 1: + case 4: + _offsetX = 0; + _offsetY = 0; + break; + case 2: + case 6: + _offsetX = 0; + break; + case 3: + _offsetX = -1; + _offsetY = 1; + break; + case 5: + _offsetX = -2; + _offsetY = 2; + break; + case 7: + _offsetX = 1; + _offsetY = -1; + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(unitID, + this->units[unitID].owner, this->units[unitID].calculatedOwnerPlayerIndex, + this->units[unitID].microXPosition + _offsetX, this->units[unitID].microYPosition + _offsetY, + this->units[unitID].buildingHeight + 64 + this->units[unitID].terrainOrClimbHeight, targetX, + targetY, targetZUnk, OpenSHC::Map::Entities::ET_MANGONEL, 0); + } else if (projectileType == OpenSHC::Map::Entities::ET_BALLISTA + || projectileType == OpenSHC::Map::Entities::ET_FIREBALLISTA) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(unitID, + this->units[unitID].owner, this->units[unitID].calculatedOwnerPlayerIndex, + this->units[unitID].microXPosition, this->units[unitID].microYPosition, + this->units[unitID].buildingHeight + 25 + this->units[unitID].terrainOrClimbHeight, targetX, + targetY, targetZUnk, projectileType, 0); + } else if (projectileType != (EntityType)8 && projectileType != ~OpenSHC::Map::Entities::ET_UNKNOWN) { + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_A_HARCHER) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(unitID, + this->units[unitID].owner, this->units[unitID].calculatedOwnerPlayerIndex, + this->units[unitID].microXPosition, this->units[unitID].microYPosition, + this->units[unitID].buildingHeight + 45 + this->units[unitID].terrainOrClimbHeight, targetX, + targetY, targetZUnk, projectileType, this->units[unitID].shootTargetedUnit); + } else { + /* This limits the range of arrow type projectiles */ + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(unitID, + this->units[unitID].owner, this->units[unitID].calculatedOwnerPlayerIndex, + this->units[unitID].microXPosition, this->units[unitID].microYPosition, + this->units[unitID].buildingHeight + 30 + this->units[unitID].terrainOrClimbHeight, targetX, + targetY, targetZUnk, projectileType, this->units[unitID].shootTargetedUnit); + } + } else { + int _offsetX = 0; + int _offsetY = 0; + switch (this->units[unitID].facingDirection) { + case 0: + _offsetY = -4; + break; + case 1: + _offsetX = 10; + _offsetY = -4; + break; + case 2: + _offsetX = 10; + break; + case 3: + _offsetX = 10; + _offsetY = 4; + break; + case 4: + _offsetY = 4; + break; + case 5: + _offsetY = 4; + _offsetX = -10; + break; + case 6: + _offsetX = -10; + break; + case 7: + _offsetY = -4; + _offsetX = -10; + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(unitID, + this->units[unitID].owner, this->units[unitID].calculatedOwnerPlayerIndex, + this->units[unitID].microXPosition + _offsetX, this->units[unitID].microYPosition + _offsetY, + this->units[unitID].buildingHeight + 12 + this->units[unitID].terrainOrClimbHeight, targetX, + targetY, targetZUnk, projectileType, 0); + } + if (this->units[unitID].tribeID != 0) { + DAT_TribesState::instance.tribes[this->units[unitID].tribeID].countdown2 = 500; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/shouldUnitsEngageInMelee.cpp b/src/OpenSHC/Map/Units/UnitsState/shouldUnitsEngageInMelee.cpp new file mode 100644 index 000000000..ba003c191 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/shouldUnitsEngageInMelee.cpp @@ -0,0 +1,120 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00531000 + BOOLEnum UnitsState::shouldUnitsEngageInMelee(int unitID_1, int unitID_2) + { + UnitTypeShort _type1 = this->units[unitID_1].unitType; + if (_type1 == OpenSHC::Map::Units::UT_TRADER || _type1 == OpenSHC::Map::Units::UT_TRADERHORSE) { + return TRUE; + } + UnitTypeShort _type2 = this->units[unitID_2].unitType; + if (_type2 == OpenSHC::Map::Units::UT_TRADER || _type2 == OpenSHC::Map::Units::UT_TRADERHORSE + || _type1 == OpenSHC::Map::Units::UT_GHOST || _type2 == OpenSHC::Map::Units::UT_GHOST) { + return TRUE; + } + if (_type1 == OpenSHC::Map::Units::UT_CAMELSHBEAR) { + if (_type2 == OpenSHC::Map::Units::UT_WOODCUTTER) { + return FALSE; + } + if (_type2 == OpenSHC::Map::Units::UT_LIONSHWOLF) { + return FALSE; + } + return TRUE; + } + if (_type2 == OpenSHC::Map::Units::UT_CAMELSHBEAR) { + if (_type1 == OpenSHC::Map::Units::UT_WOODCUTTER || _type1 == OpenSHC::Map::Units::UT_LIONSHWOLF) { + return FALSE; + } + return TRUE; + } + if (this->units[unitID_1].isStalked == 0) { + if (this->units[unitID_2].isStalked != 0) { + if (_type2 == OpenSHC::Map::Units::UT_LIONSHWOLF) { + return FALSE; + } + if (_type2 == OpenSHC::Map::Units::UT_CAGEDOG) { + return (BOOLEnum)(DAT_GameState::instance.mapAndTime + .playerTeams[this->units[unitID_2].displayColorPlayerID] + == DAT_GameState::instance.mapAndTime.playerTeams[this->units[unitID_1].owner]); + } + if (_type2 == OpenSHC::Map::Units::UT_RABBIT || _type2 == OpenSHC::Map::Units::UT_QUARRYOX + || _type2 == OpenSHC::Map::Units::UT_COW) { + return FALSE; + } + return (BOOLEnum)(_type2 != OpenSHC::Map::Units::UT_HUNTERDOG); + } + if (DAT_GameState::instance.mapAndTime.skirmishNoRushTicks == 0 + || DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SKIRMISH_SINGLE_PLAYER + || DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) { + return FALSE; + } + return TRUE; + } + if (_type1 == OpenSHC::Map::Units::UT_LIONSHWOLF) { + if (_type2 == OpenSHC::Map::Units::UT_ANTELOPESHDEER) { + return FALSE; + } + if (_type2 == OpenSHC::Map::Units::UT_COW) { + return FALSE; + } + if (_type2 == OpenSHC::Map::Units::UT_RABBIT) { + return FALSE; + } + if (_type2 == OpenSHC::Map::Units::UT_HUNTERDOG) { + return FALSE; + } + } else if (_type1 == OpenSHC::Map::Units::UT_CAGEDOG) { + if (_type2 == OpenSHC::Map::Units::UT_ANTELOPESHDEER) { + return FALSE; + } + if (_type2 == OpenSHC::Map::Units::UT_COW) { + return FALSE; + } + if (_type2 == OpenSHC::Map::Units::UT_RABBIT) { + return FALSE; + } + if (_type2 == OpenSHC::Map::Units::UT_HUNTERDOG) { + return FALSE; + } + if (this->units[unitID_2].isStalked != 0) { + return TRUE; + } + return ( + BOOLEnum)(DAT_GameState::instance.mapAndTime.playerTeams[this->units[unitID_1].displayColorPlayerID] + == DAT_GameState::instance.mapAndTime.playerTeams[this->units[unitID_2].owner]); + } else if (_type1 != OpenSHC::Map::Units::UT_HUNTERDOG) { + return TRUE; + } else { + if (_type2 == OpenSHC::Map::Units::UT_RABBIT) { + return FALSE; + } + if (_type2 == OpenSHC::Map::Units::UT_LIONSHWOLF) { + return FALSE; + } + if (_type2 == OpenSHC::Map::Units::UT_CAGEDOG) { + return FALSE; + } + } + if (this->units[unitID_2].isStalked == 0) { + return FALSE; + } + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/sitDownIfStanding.cpp b/src/OpenSHC/Map/Units/UnitsState/sitDownIfStanding.cpp new file mode 100644 index 000000000..8c58add10 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/sitDownIfStanding.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052FBF0 + BOOLEnum UnitsState::sitDownIfStanding(int unitID) + { + if (this->units[unitID].seated != 0) { + return FALSE; + } + this->units[unitID].substate = 101; + this->units[unitID].animationCycleNumber = 0; + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/spawnUnit.cpp b/src/OpenSHC/Map/Units/UnitsState/spawnUnit.cpp new file mode 100644 index 000000000..663fabce7 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/spawnUnit.cpp @@ -0,0 +1,109 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053E440 + int UnitsState::spawnUnit(int playerID, int displayColor, int microXPosition, int microYPosition, + int terrainHeight, UnitType unitType) + { + /* Loop until we find free slot. */ + int _unitID = 1; + for (; _unitID < 0x9c4; ++_unitID) { + if (this->units[_unitID].logicalState == OpenSHC::Map::Units::ULS_INVISIBLE) { + break; + } + if (_unitID > 0x9c2) { + return 0; + } + } + if ((int)this->maxUnitCount <= _unitID) { + this->maxUnitCount = _unitID + 1; + } + this->units[_unitID].uid = DAT_GameCore::instance.uniqueGameObjectTracker; + dword _time = DAT_GameCore::instance.mapTimeInTicks; + DAT_GameCore::instance.uniqueGameObjectTracker = DAT_GameCore::instance.uniqueGameObjectTracker + 1; + this->units[_unitID].logicalState = (UnitLogicState)1; + this->units[_unitID].owner = (short)playerID; + this->units[_unitID].terrainOrClimbHeight = (short)terrainHeight; + this->units[_unitID].microXPosition = (short)microXPosition + 4; + this->units[_unitID].time = _time; + this->units[_unitID].calculatedOwnerPlayerIndex = (short)displayColor; + this->units[_unitID].microYPosition = (short)microYPosition + 4; + this->units[_unitID].facingDirection = 0; + this->units[_unitID].displayColorPlayerID = (short)displayColor; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setUnitValues, this)(_unitID, unitType); + if (unitType == OpenSHC::Map::Units::UT_S_TOWER) { + this->units[_unitID].calculatedOwnerPlayerIndex = 0; + this->units[_unitID].displayColorPlayerID = 0; + } else if (unitType == OpenSHC::Map::Units::UT_CAGEDOG) { + this->units[_unitID].calculatedOwnerPlayerIndex = 0; + } + short _y = (short)(this->units[_unitID].microYPosition / 8); + this->units[_unitID].mimicCurrentYPosition = _y; + this->units[_unitID].y = _y; + this->units[_unitID].destinationY_2Unk = _y; + short _x = (short)(this->units[_unitID].microXPosition / 8); + this->units[_unitID].mimicCurrentXPosition = _x; + this->units[_unitID].x = _x; + this->units[_unitID].destinationX_2Unk = _x; + this->units[_unitID].movementRelated = 8; + this->units[_unitID].field105_0xe8 = 0; + this->units[_unitID].targetingType = (UnitInstructionType)0; + this->units[_unitID].tile = _x + DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + this->units[_unitID].fixedRng = SEC_RNG::instance.currentNumber2; + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + if (unitType == OpenSHC::Map::Units::UT_S_CATAPULT || unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) { + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] == -1) { + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) { + this->units[_unitID].stoneAmmunition = 0x28; + } else { + this->units[_unitID].stoneAmmunition = 0x14; + } + } else { + this->units[_unitID].stoneAmmunition = 0x14; + } + } else if (unitType == OpenSHC::Map::Units::UT_S_MANGONEL) { + if (DAT_TileMapState::instance.BuildingLayer[this->units[_unitID].tile] != 0) { + DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance.BuildingLayer[this->units[_unitID].tile]] + .containsSiegeMangonel1OrBallista2 = 1; + } + } else if (unitType == OpenSHC::Map::Units::UT_S_BALLISTA) { + if (DAT_TileMapState::instance.BuildingLayer[this->units[_unitID].tile] != 0) { + DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance.BuildingLayer[this->units[_unitID].tile]] + .containsSiegeMangonel1OrBallista2 = 2; + } + } else if (unitType == OpenSHC::Map::Units::UT_CHILD) { + if ((this->units[_unitID].fixedRng & 0x80) != 0) { + this->units[_unitID].spriteID = 0x81; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignNameToUnit, this)(_unitID); + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::commitPendingUnitPosition, this)(_unitID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::updateMicroPosition, this)(_unitID); + return _unitID; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/stampOccupancyFlagOnSurroundingTiles.cpp b/src/OpenSHC/Map/Units/UnitsState/stampOccupancyFlagOnSurroundingTiles.cpp new file mode 100644 index 000000000..8f285e92d --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/stampOccupancyFlagOnSurroundingTiles.cpp @@ -0,0 +1,34 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00534490 + void UnitsState::stampOccupancyFlagOnSurroundingTiles(int unitID) + { + int _tile = this->units[unitID].tile; + uchar* _occupancy = DAT_TileMapState::instance.OccupancyLayer; + int _y = this->units[unitID].y; + uchar _value = this->units[unitID].occupancyOrFlag; + uchar* _row = _occupancy + _tile; + _row[1] |= _value; + _row[-1] |= _value; + _row[0] |= _value; + int* _directionRow + = (int*)((uchar*)DAT_TileMapState::instance.ptr_MovementDirectionTranslationMatrix + _y * 0x20); + uchar* _nextRow = _row + _directionRow[0]; + _nextRow[-1] |= _value; + _nextRow[1] |= _value; + _nextRow[0] |= _value; + uchar* _furtherRow = _row + _directionRow[4]; + _furtherRow[-1] |= _value; + _furtherRow[1] |= _value; + _furtherRow[0] |= _value; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/standUpIfSeated.cpp b/src/OpenSHC/Map/Units/UnitsState/standUpIfSeated.cpp new file mode 100644 index 000000000..490b14fc3 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/standUpIfSeated.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052FBB0 + BOOLEnum UnitsState::standUpIfSeated(int unitID) + { + if (this->units[unitID].seated == 0) { + return FALSE; + } + this->units[unitID].substate = 100; + this->units[unitID].animationCycleNumber = 0; + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/stopUnitIfNextToTarget.cpp b/src/OpenSHC/Map/Units/UnitsState/stopUnitIfNextToTarget.cpp new file mode 100644 index 000000000..99b62a41f --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/stopUnitIfNextToTarget.cpp @@ -0,0 +1,61 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00534240 + int UnitsState::stopUnitIfNextToTarget(int unitID) + { + if (this->units[unitID].targetedBuildingTile == 0) { + return 0; + } + if (this->units[unitID].field64_0x90 == 0) { + return 0; + } + uint _tile = 0; + int _isNear = 0; + for (int direction = 0; direction < 8; ++direction) { + _tile = DAT_TileMapState::instance.directionTranslationMatrix[this->units[unitID].y][direction] + + this->units[unitID].tile; + if (_tile == this->units[unitID].targetedBuildingTile) { + _isNear = 1; + break; + } + } + if (!_isNear) { + for (int direction = 0; direction < 8 && !_isNear; ++direction) { + uint _neighbourTile + = DAT_TileMapState::instance.directionTranslationMatrix[this->units[unitID].y][direction] + + this->units[unitID].tile; + for (int secondDirection = 0; secondDirection < 8; ++secondDirection) { + if (DAT_TileMapState::instance.directionTranslationMatrix[this->units[unitID].y + + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[direction] + .int_.yOffset][secondDirection] + + _neighbourTile + == this->units[unitID].targetedBuildingTile) { + _tile = _neighbourTile; + _isNear = 1; + break; + } + } + } + } + if (!_isNear) { + return 0; + } + if ((DAT_TileMapState::instance.LogicLayer[_tile] & 0x100U) == 0 + && DAT_TileMapState::instance.BuildingLayer[_tile] == 0) { + return -1; + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::makeUnitStopWalkingByClearingPathProgressState, this)(unitID); + return (uint)(this->units[unitID].movementRelated > 7); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/teleportUnitToUnitXAndY.cpp b/src/OpenSHC/Map/Units/UnitsState/teleportUnitToUnitXAndY.cpp new file mode 100644 index 000000000..de9ec54a2 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/teleportUnitToUnitXAndY.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x0053BB90 + void UnitsState::teleportUnitToUnitXAndY(int unitID) + { + int _tileY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[this->units[unitID].tile]; + int _tileX + = this->units[unitID].tile - DAT_ViewportRenderState::instance.translationMatrix[_tileY].addXgetTile; + if (_tileY == this->units[unitID].y && _tileX == this->units[unitID].x) { + return; + } + this->units[unitID].microXPosition = (short)(_tileX * 8 + 4); + this->units[unitID].microYPosition = (short)(_tileY * 8 + 4); + this->units[unitID].mimicCurrentXPosition = (short)_tileX; + this->units[unitID].x = (short)_tileX; + this->units[unitID].mimicCurrentYPosition = (short)_tileY; + this->units[unitID].y = (short)_tileY; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::updateMicroPosition, this)(unitID); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/tracePathFromLadderExitSetDestination.cpp b/src/OpenSHC/Map/Units/UnitsState/tracePathFromLadderExitSetDestination.cpp new file mode 100644 index 000000000..567fbd6bc --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/tracePathFromLadderExitSetDestination.cpp @@ -0,0 +1,43 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00533CA0 + void UnitsState::tracePathFromLadderExitSetDestination(int unitID) + { + int _exitX = this->units[unitID].ladderExitXPosition; + int _exitY = this->units[unitID].ladderExitYPosition; + int _tile = this->units[unitID].previousTilePosition; + int _stepIndex = 0; + for (; _stepIndex < this->units[unitID].totalSizeOfPathPlan; ++_stepIndex) { + uint _packedDirections = (char)this->units[unitID].pathPlanStart[_stepIndex / 2]; + uint _direction; + if ((_stepIndex & 1) == 0) { + _direction = _packedDirections & 0xf; + } else { + _direction = (int)_packedDirections >> 4; + } + _exitY = _exitY + + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[_direction].int_.yOffset; + _exitX = _exitX + + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[_direction].int_.xOffset; + _tile = DAT_ViewportRenderState::instance.translationMatrix[_exitY].addXgetTile + _exitX; + if ((DAT_TileMapState::instance.LogicLayer[_tile] & 0x800U) != 0) { + break; + } + } + this->units[unitID].destinationYPosition = (short)_exitY; + this->units[unitID].totalSizeOfPathPlan = (short)_stepIndex + 1; + this->units[unitID].destinationXPosition = (short)_exitX; + this->units[unitID].destinationTilePosition = _tile; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/transferNonCourtUnitsToPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/transferNonCourtUnitsToPlayer.cpp new file mode 100644 index 000000000..10aa2cb89 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/transferNonCourtUnitsToPlayer.cpp @@ -0,0 +1,59 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00530400 + void UnitsState::transferNonCourtUnitsToPlayer(int fromPlayer, int toPlayer) + { + for (int unitID = 1; unitID < 2500; ++unitID) { + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].isStalked != 0) { + switch (this->units[unitID].unitType) { + case OpenSHC::Map::Units::UT_QUARRYOX: + case OpenSHC::Map::Units::UT_COW: + case OpenSHC::Map::Units::UT_HUNTERDOG: + case OpenSHC::Map::Units::UT_CHICKEN: + case OpenSHC::Map::Units::UT_MOTHER: + case OpenSHC::Map::Units::UT_CHILD: + case OpenSHC::Map::Units::UT_JUGGLER: + case OpenSHC::Map::Units::UT_FIREEATER: + break; + default: + continue; + } + } + if (this->units[unitID].owner != fromPlayer) { + continue; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_LORD) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_LADY) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } else if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_JESTER) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } else { + this->units[unitID].owner = (short)toPlayer; + if (this->units[unitID].isStalked == 0 || this->units[unitID].calculatedOwnerPlayerIndex != 0) { + this->units[unitID].calculatedOwnerPlayerIndex = toPlayer; + } + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/triggerDeathAnimationForAllWildlife.cpp b/src/OpenSHC/Map/Units/UnitsState/triggerDeathAnimationForAllWildlife.cpp new file mode 100644 index 000000000..caa89dd2e --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/triggerDeathAnimationForAllWildlife.cpp @@ -0,0 +1,47 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00530310 + void UnitsState::triggerDeathAnimationForAllWildlife() + { + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SKIRMISH_SINGLE_PLAYER) { + return; + } + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + continue; + } + if (this->units[unitID].dying != 0) { + continue; + } + if (this->units[unitID].owner != 0) { + continue; + } + if (this->units[unitID].unitType == OpenSHC::Map::Units::UT_ANTELOPESHDEER + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_LIONSHWOLF + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_CAMELSHBEAR + || this->units[unitID].unitType == OpenSHC::Map::Units::UT_RABBIT) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_STONE_DEATH_01; + this->units[unitID].animationCycleNumber = 0; + this->units[unitID].dying = 1; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/triggerDesyncIfTileUnitLinkageInvalid.cpp b/src/OpenSHC/Map/Units/UnitsState/triggerDesyncIfTileUnitLinkageInvalid.cpp new file mode 100644 index 000000000..15bd76dbd --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/triggerDesyncIfTileUnitLinkageInvalid.cpp @@ -0,0 +1,48 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" +#include "OpenSHC/Game/GameMode.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Commands::GameCommandType; + using OpenSHC::Game::GameMode; + + // FUNCTION: STRONGHOLDCRUSADER 0x0052F680 + void UnitsState::triggerDesyncIfTileUnitLinkageInvalid(int tile) + { + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY + && (DAT_GameSynchronyState::instance.syncStatus != 0 + || DAT_GameSynchronyState::instance.saveRelated != 0)) { + return; + } + if (DAT_GameState::instance.mapAndTime.multiplayerUnitSameTileLinkageTimeWindow != 0) { + return; + } + if ((uint)(short)DAT_TileMapState::instance.UnitLayer[tile] > 2499) { + DAT_GameState::instance.mapAndTime.multiplayerUnitSameTileLinkageTimeWindow = 1; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, + DAT_GameSynchronyState::ptr)((GameCommandType)0x4f); + return; + } + for (uint unitID = (short)DAT_TileMapState::instance.UnitLayer[tile]; unitID != 0; + unitID = (short)this->units[unitID].nextUnitOnTheSameTile) { + if (this->units[unitID].tile != tile && this->units[unitID].usingTeleport == 0 + && this->units[unitID].field303_0x413 == 0) { + DAT_GameState::instance.mapAndTime.multiplayerUnitSameTileLinkageTimeWindow = 1; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, + DAT_GameSynchronyState::ptr)((GameCommandType)0x4f); + return; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/triggerStoneTowerDeathForPlayer.cpp b/src/OpenSHC/Map/Units/UnitsState/triggerStoneTowerDeathForPlayer.cpp new file mode 100644 index 000000000..abeee848c --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/triggerStoneTowerDeathForPlayer.cpp @@ -0,0 +1,32 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00530240 + void UnitsState::triggerStoneTowerDeathForPlayer(int playerID) + { + for (int unitID = 1; unitID < (int)this->maxUnitCount; ++unitID) { + if (this->units[unitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && this->units[unitID].dying == 0 && this->units[unitID].owner == playerID + && this->units[unitID].unitType == OpenSHC::Map::Units::UT_S_TOWER + && this->units[unitID].state.generic + == (OpenSHC::Map::Units::States::US_STAND_UPUnk | OpenSHC::Map::Units::States::US_IDLEUnk)) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_STONE_DEATH_01; + this->units[unitID].animationCycleNumber = 0; + this->units[unitID].dying = 1; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/tryAttackUnitID.cpp b/src/OpenSHC/Map/Units/UnitsState/tryAttackUnitID.cpp new file mode 100644 index 000000000..5b8264a9e --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/tryAttackUnitID.cpp @@ -0,0 +1,50 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/Pathfinding/DestinationNeededEnum.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::Pathfinding::DestinationNeededEnum; + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x00537D60 + undefined4 UnitsState::tryAttackUnitID(int unitID_1, int unitID_2) + { + if (unitID_2 <= 0) { + return 0; + } + if (this->units[unitID_1].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + return 0; + } + if (this->units[unitID_1].dying != 0) { + return 0; + } + if (this->units[unitID_2].logicalState != OpenSHC::Map::Units::ULS_NORMAL) { + return 0; + } + if (this->units[unitID_2].dying != 0) { + return 0; + } + if (this->units[unitID_1].state.generic == (UnitState)0xcf) { + return 0; + } + if (this->units[unitID_1].state.generic == OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + return 0; + } + this->units[unitID_1].movementType_OR_targetUnitID = (short)unitID_2; + this->units[unitID_1].targetedUnitID__OR__engineerMannedSiegeEngineRef = (short)unitID_2; + this->units[unitID_1].targetedUnitUIDUnk_OR_someAppearTileUnk_OR_buildingUID_OR_pitchDitchUID_OR_entityUID + = this->units[unitID_2].uid; + this->units[unitID_2].huntedBy = this->units[unitID_2].huntedBy + 1; + this->units[unitID_1].state.generic = (UnitState)0xcf; + this->units[unitID_1].destinationNeeded = OpenSHC::Map::Units::Pathfinding::DNE_DESTINATION_NEEDED; + return 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/unitClimbing.cpp b/src/OpenSHC/Map/Units/UnitsState/unitClimbing.cpp new file mode 100644 index 000000000..56db511b0 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/unitClimbing.cpp @@ -0,0 +1,144 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::States::UnitState; + + // FUNCTION: STRONGHOLDCRUSADER 0x0054C1C0 + void UnitsState::unitClimbing(int unitID) + { + /* Offsets: + 0x25E(0x364): climbingState (0 to 5, climbing stops at 5) + 0x6CE(0x0BA): groundHeight + 0x70A(0x0F6): currentIndexInPathPlan + 0x8B2(0x29E): unknown + 0x972(0x35E): climbingDirection */ + short _climbDataID = this->units[unitID].climbDataID; + if (DAT_PathFindingState::instance.climbData[_climbDataID].canBeUsed == 0 + || DAT_PathFindingState::instance.climbData[_climbDataID].climbDataRelated + != this->units[unitID].climbDataRelated) { + if (this->units[unitID].usingTeleport == 1) { + int _climbingState = this->units[unitID].climbingState; + this->units[unitID].animationCycleNumber = 0; + this->units[unitID].tunnelerFinishedDigging = 1; + this->units[unitID].usingTeleport = 0; + if ((short)_climbingState < 0) { + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DETERMINE_NEXT_STATEUnk; + return; + } + this->units[unitID].dying = 1; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_DEATH_02; + return; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::exitLadder, this)(unitID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, this->units[unitID].destinationX_2Unk, this->units[unitID].destinationY_2Unk, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::changeDestinationByLeftover, this)(unitID); + return; + } + if (DAT_PathFindingState::instance.climbData[_climbDataID].type != 1) { + if (DAT_PathFindingState::instance.climbData[_climbDataID].type != 6 + && DAT_PathFindingState::instance.climbData[_climbDataID].type != 5 + && DAT_PathFindingState::instance.climbData[_climbDataID].type != 4 + && DAT_PathFindingState::instance.climbData[_climbDataID].type != 3 + && DAT_PathFindingState::instance.climbData[_climbDataID].type != 7) { + return; + } + if (this->units[unitID].state.generic == (UnitState)0x6c) { + this->units[unitID].dying = 1; + this->units[unitID].state.generic = OpenSHC::Map::Units::States::US_STONE_DEATH_01; + this->units[unitID].animationCycleNumber = 0; + return; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::exitLadder, this)(unitID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, this->units[unitID].destinationX_2Unk, this->units[unitID].destinationY_2Unk, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::changeDestinationByLeftover, this)(unitID); + return; + } + this->units[unitID].field203_0x35c = this->units[unitID].field203_0x35c + 1; + if (this->units[unitID].field203_0x35c > 0x5f) { + *(short*)&this->units[unitID].climbingState = (short)this->units[unitID].climbingState + 1; + this->units[unitID].field203_0x35c = 0; + if (this->units[unitID].climbingDirection == 1) { + /* Climbing up */ + this->units[unitID].terrainOrClimbHeight = this->units[unitID].terrainOrClimbHeight - 0xf; + } else { + /* Climbing down */ + this->units[unitID].terrainOrClimbHeight = this->units[unitID].terrainOrClimbHeight + 0xf; + } + if ((short)(ushort)DAT_TileMapState::instance + .HeightLayer[DAT_ViewportRenderState::instance + .translationMatrix[this->units[unitID].mimicCurrentYPosition] + .addXgetTile + + this->units[unitID].mimicCurrentXPosition] + < this->units[unitID].terrainOrClimbHeight) { + *(undefined2*)&this->units[unitID].climbingState = 5; + } + } + if (this->units[unitID].climbingDirection == 1) { + /* Climbing up */ + if (this->units[unitID].facingDirectionMapOrientationCorrected == 0) { + this->units[unitID].field41_0x5c = (-4 - (short)this->units[unitID].climbingState) * 2; + } else if (this->units[unitID].facingDirectionMapOrientationCorrected == 2) { + this->units[unitID].field41_0x5c = (short)this->units[unitID].climbingState * -2; + } else if (this->units[unitID].facingDirectionMapOrientationCorrected == 4) { + this->units[unitID].field41_0x5c = (short)this->units[unitID].climbingState * 2; + } else if (this->units[unitID].facingDirectionMapOrientationCorrected == 6) { + this->units[unitID].field41_0x5c = (short)this->units[unitID].climbingState * 2 + 8; + } + } else { + /* Climbing down */ + if (this->units[unitID].facingDirectionMapOrientationCorrected == 0) { + this->units[unitID].field41_0x5c = (short)this->units[unitID].climbingState * 2 + -3; + } else if (this->units[unitID].facingDirectionMapOrientationCorrected == 2) { + this->units[unitID].field41_0x5c = (short)this->units[unitID].climbingState * 2 + -8; + } else if (this->units[unitID].facingDirectionMapOrientationCorrected == 4) { + this->units[unitID].field41_0x5c = (-4 - (short)this->units[unitID].climbingState) * 2; + } else if (this->units[unitID].facingDirectionMapOrientationCorrected == 6) { + this->units[unitID].field41_0x5c = (2 - (short)this->units[unitID].climbingState) * 2; + } + } + if (this->units[unitID].climbingDirection == 1) { + /* Climbing up */ + this->units[unitID].animationFrame + = (char)DAT_UnitPropertiesDefinedData::instance.Frames_Shared_UnitClimbingUp + .ANIM_Frames_Shared_UnitClimbingUp[this->units[unitID].field203_0x35c / 8]; + } else { + /* Climbing down */ + this->units[unitID].animationFrame + = (char)DAT_UnitPropertiesDefinedData::instance + .Frames_Shared_UnitClimbingDown[this->units[unitID].field203_0x35c / 8]; + } + this->units[unitID].gfxNumber = this->units[unitID].animationSheetFrameOffset + + this->units[unitID].animationFrame * 8 + -8 + + this->units[unitID].facingDirectionMapOrientationCorrected; + this->units[unitID].vanish = 0; + if (this->units[unitID].facingDirectionMapOrientationCorrected == 0 + || this->units[unitID].facingDirectionMapOrientationCorrected == 6) { + this->units[unitID].field43_0x64 = 2; + } else { + this->units[unitID].vanish = 1; + } + /* Stop climbing at climbingState = 5 */ + if ((short)this->units[unitID].climbingState < 5) { + return; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::exitLadder, this)(unitID); + this->units[unitID].state.generic = this->units[unitID].unknownStateCopyClimbRelated; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, this->units[unitID].destinationX_2Unk, this->units[unitID].destinationY_2Unk, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::changeDestinationByLeftover, this)(unitID); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/unitIsInMoat.cpp b/src/OpenSHC/Map/Units/UnitsState/unitIsInMoat.cpp new file mode 100644 index 000000000..ea3efa200 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/unitIsInMoat.cpp @@ -0,0 +1,17 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00534460 + BOOLEnum UnitsState::unitIsInMoat(int unitID) + { + return (BOOLEnum)((uint)DAT_TileMapState::instance.LogicLayer[this->units[unitID].tile] >> 30 & 1); + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/updateClimbing.cpp b/src/OpenSHC/Map/Units/UnitsState/updateClimbing.cpp new file mode 100644 index 000000000..4d3c355ad --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/updateClimbing.cpp @@ -0,0 +1,88 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0054BFC0 + BOOLEnum UnitsState::updateClimbing(int unitID) + { + int _climbDataID = this->units[unitID].climbDataID; + if (_climbDataID == 0) { + return TRUE; + } + if (_climbDataID == 200) { + return FALSE; + } + if (DAT_PathFindingState::instance.climbData[_climbDataID].climbDataRelated + != this->units[unitID].climbDataRelated) { + this->units[unitID].climbDataID = 0; + return FALSE; + } + *(undefined2*)&this->units[unitID].climbingState = 0xffff; + if (DAT_PathFindingState::instance.climbData[_climbDataID].type == 1) { + int _ladderUnitID + = (short)DAT_TileMapState::instance + .UnitLayer[DAT_PathFindingState::instance.climbData[_climbDataID].bottomTilePosition]; + if (_ladderUnitID == 0) { + return FALSE; + } + while (DAT_PathFindingState::instance.climbData[_climbDataID].unitID != _ladderUnitID) { + _ladderUnitID = (short)this->units[_ladderUnitID].nextUnitOnTheSameTile; + if (_ladderUnitID == 0) { + return FALSE; + } + } + short _climbDirection = this->units[unitID].climbDirection; + this->units[unitID].facingDirection = this->units[_ladderUnitID].facingDirection; + this->units[unitID].usingTeleport = (short)DAT_PathFindingState::instance.climbData[_climbDataID].type; + this->units[unitID].field203_0x35c = 0; + *(undefined2*)&this->units[unitID].climbingState = 0; + if (_climbDirection == 0) { + this->units[unitID].climbingDirection = 0; + } else { + this->units[unitID].climbingDirection = 1; + } + if (this->units[unitID].climbingDirection == 1) { + this->units[unitID].terrainOrClimbHeight = this->units[unitID].terrainOrClimbHeight - 40; + } + this->units[unitID].unknownStateCopyClimbRelated = this->units[unitID].state.generic; + this->units[unitID].state.generic = (UnitState)0x68; + this->units[unitID].animationCycleNumber = 0; + } else if (DAT_PathFindingState::instance.climbData[_climbDataID].type == 7 + || DAT_PathFindingState::instance.climbData[_climbDataID].type == 6 + || DAT_PathFindingState::instance.climbData[_climbDataID].type == 5 + || DAT_PathFindingState::instance.climbData[_climbDataID].type == 4 + || DAT_PathFindingState::instance.climbData[_climbDataID].type == 3) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::exitLadder, this)(unitID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setDestinationForUnit, this)( + unitID, this->units[unitID].destinationX_2Unk, this->units[unitID].destinationY_2Unk, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::changeDestinationByLeftover, this)(unitID); + } + if (this->units[unitID].climbDirection != 0) { + /* Climb down */ + this->units[unitID].mimicCurrentXPosition + = (short)DAT_PathFindingState::instance.climbData[_climbDataID].bottomXPosition; + this->units[unitID].mimicCurrentYPosition + = (short)DAT_PathFindingState::instance.climbData[_climbDataID].bottomYPosition; + return TRUE; + } + /* Climb up */ + this->units[unitID].mimicCurrentXPosition + = (short)DAT_PathFindingState::instance.climbData[_climbDataID].topXPosition; + this->units[unitID].mimicCurrentYPosition + = (short)DAT_PathFindingState::instance.climbData[_climbDataID].topYPosition; + return TRUE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/updateMicroPosition.cpp b/src/OpenSHC/Map/Units/UnitsState/updateMicroPosition.cpp new file mode 100644 index 000000000..60f854fd5 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/updateMicroPosition.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00534030 + void UnitsState::updateMicroPosition(int unitID) + { + uint _microPartX = (byte)this->units[unitID].microXPosition & 7; + uint _microPartY = (byte)this->units[unitID].microYPosition & 7; + switch (DAT_TileMapState::instance.mapOrientation) { + case 0: + _microPartX = _microPartX * 2; + _microPartY = _microPartY << 4; + break; + case 2: + _microPartX = (7 - _microPartX) * 16; + _microPartY = _microPartY * 2; + break; + _microPartY = (7 - _microPartY) * 16; + case 4: + _microPartX = (7 - _microPartX) * 2; + break; + case 6: + _microPartY = (7 - _microPartY) * 2; + _microPartX = _microPartX << 4; + } + this->units[unitID].orientationRelatedPositionX + = (short)DAT_UnitPropertiesDefinedData::instance.field77_0x10f4c[0][_microPartX + _microPartY]; + this->units[unitID].orientationRelatedPositionY + = (short)DAT_UnitPropertiesDefinedData::instance.field77_0x10f4c[0][_microPartX + _microPartY + 1]; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/updateUnitFadeAndVisibilityNearStructures.cpp b/src/OpenSHC/Map/Units/UnitsState/updateUnitFadeAndVisibilityNearStructures.cpp new file mode 100644 index 000000000..383d4b867 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/updateUnitFadeAndVisibilityNearStructures.cpp @@ -0,0 +1,112 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00533D50 + void UnitsState::updateUnitFadeAndVisibilityNearStructures(int unitID) + { + int _tile = this->units[unitID].tile; + uint _logicFlags = DAT_TileMapState::instance.LogicLayer[_tile]; + int _gateFadeType = 0; + int _towerFadeType = 0; + int _fadeType = 0; + int _isOnDefensiveStructure = 0; + if (this->units[unitID].unknownCountdown_0x402 != 0) { + this->units[unitID].unknownCountdown_0x402 = this->units[unitID].unknownCountdown_0x402 - 1; + } + if (DAT_TileMapState::instance.BuildingLayer[_tile] == 0) { + if ((_logicFlags & 0x100) != 0) { + _isOnDefensiveStructure = 1; + } + } else { + switch (DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.BuildingLayer[_tile]] + .buildingType) { + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: + _gateFadeType = 0xb; + break; + case OpenSHC::Map::Buildings::BT_WOODGATE1: + _gateFadeType = 10; + break; + case OpenSHC::Map::Buildings::BT_TOWER1: + _towerFadeType = 1; + break; + case OpenSHC::Map::Buildings::BT_TOWER2: + _towerFadeType = 2; + break; + case OpenSHC::Map::Buildings::BT_TOWER3: + _towerFadeType = 3; + break; + case OpenSHC::Map::Buildings::BT_TOWER4: + case OpenSHC::Map::Buildings::BT_TOWER5: + _towerFadeType = 4; + } + } + if (this->units[unitID].field171_0x308 == 2 && _isOnDefensiveStructure) { + _fadeType = 1; + } + if (this->units[unitID].field171_0x308 == 1 && _towerFadeType != 0) { + _fadeType = _towerFadeType; + } + if (this->units[unitID].field171_0x308 == 0 && _gateFadeType != 0) { + if ((DAT_TileMapState::instance.LogicLayer[this->units[unitID].destinationTilePosition] & 0x100U) != 0 + || DAT_BuildingDefinedData::instance.IsGateOrTowerArray[(short)DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance + .BuildingLayer[this->units[unitID].destinationTilePosition]] + .buildingType] + != FALSE) { + _fadeType = _gateFadeType; + } + } + if (_gateFadeType != 0) { + if ((DAT_TileMapState::instance.LogicLayer[this->units[unitID].destinationTilePosition] & 0x100U) == 0 + || (DAT_TileMapState::instance.LogicLayer[this->units[unitID].destinationTilePosition] & 2U) != 0) { + this->units[unitID].unknownCountdown_0x402 + = (DAT_BuildingDefinedData::instance.IsGateOrTowerArray[(short)DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance + .BuildingLayer[this->units[unitID].destinationTilePosition]] + .buildingType] + != FALSE) + - 1U + & 10; + } else { + this->units[unitID].unknownCountdown_0x402 = 0; + } + } + if (_isOnDefensiveStructure) { + this->units[unitID].field171_0x308 = 1; + } else if (_towerFadeType == 0) { + this->units[unitID].field171_0x308 = _gateFadeType != 0 ? 3 : 0; + } else { + this->units[unitID].field171_0x308 = 2; + } + if (this->units[unitID].unknownCountdown_0x402 == 0 + || (DAT_TileMapState::instance.MiscDisplayLayer[this->units[unitID].nextTileUnk] & 0x10) != 0) { + this->units[unitID].vanish = 0; + } else if ((DAT_TileMapState::instance.MiscDisplayLayer[this->units[unitID].currentTilePosition_2Unk] + & 0x10) + == 0) { + if (this->units[unitID].vanish < 1) { + this->units[unitID].vanish = 1; + } + } else { + this->units[unitID].vanish = 0xf; + } + if (_fadeType != 0) { + this->units[unitID].fadeType = _fadeType; + this->units[unitID].fadeCounter = 0; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/updateUnits.cpp b/src/OpenSHC/Map/Units/UnitsState/updateUnits.cpp new file mode 100644 index 000000000..34ed3c442 --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/updateUnits.cpp @@ -0,0 +1,943 @@ +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/DE/SHCDE/eSFX.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/Pathfinding/DestinationNeededEnum.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_CurrentUnitSlotID.hpp" +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" +#include "OpenSHC/Globals/DAT_UnitHasBecomeIdle.hpp" +#include "OpenSHC/Globals/DAT_UnitPropertiesDefinedData.hpp" +#include "OpenSHC/Globals/DAT_UpdateUnitsTracker.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::DE::SHCDE::eSFX; + using OpenSHC::Map::Buildings::BuildingLogicalState; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Buildings::BuildingTypeShort; + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::Pathfinding::DestinationNeededEnum; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x00579300 + void UnitsState::updateUnits() + + { + int* _intFieldPtr; + short* _shortFieldPtr; + UnitTypeShort UVar6; + uint _unitIDBased8value; + int _troopValue; + uint _rngNumber8; + uint _unitID; + uint _currentUnitID; + UnitTypeShort _unitType; + short _buildingID; + BuildingTypeShort _buildingType; + + _rngNumber8 = (int)SEC_RNG::instance.currentNumber2 % 16; + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 80400, '\0', (void*)((int)(DAT_TileMapState::instance.OccupancyLayer))); + DAT_GameState::instance.playerDataArray[0].healerCount = 0; + DAT_GameState::instance.playerDataArray[1].healerCount = 0; + DAT_GameState::instance.playerDataArray[2].healerCount = 0; + DAT_GameState::instance.playerDataArray[3].healerCount = 0; + DAT_GameState::instance.playerDataArray[4].healerCount = 0; + DAT_GameState::instance.playerDataArray[5].healerCount = 0; + DAT_GameState::instance.playerDataArray[6].healerCount = 0; + DAT_GameState::instance.playerDataArray[7].healerCount = 0; + DAT_GameState::instance.playerDataArray[8].healerCount = 0; + this->unitCount = 0; + DAT_CurrentUnitSlotID::instance = 1; + this->maxUnitCount = 0; + do { + _currentUnitID = DAT_CurrentUnitSlotID::instance; + if (this->units[_currentUnitID].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) { + this->maxUnitCount = _currentUnitID + 1; + this->units[_currentUnitID].field233_0x39a = 0; + this->units[_currentUnitID].attackedBy = 0; + this->units[_currentUnitID].huntedBy = 0; + this->units[_currentUnitID].field265_0x3dc = 0; + this->units[_currentUnitID].field43_0x64 = 0; + /* + This literally does nothing, this variable is not used elsewhere, what the + hell? + */ + + _shortFieldPtr = &this->units[_currentUnitID].targetShootRelated; + if (this->units[_currentUnitID].targetShootRelated != 0) { + *_shortFieldPtr = *_shortFieldPtr + -1; + } + if ((this->units[_currentUnitID].state.generic + == OpenSHC::Map::Units::States::US_DETERMINE_NEXT_STATEUnk) + && (_troopValue + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::isUnitRegisteredOnItsOwnTile, + this)(DAT_CurrentUnitSlotID::instance), + _troopValue == 0)) { + this->lostChimps = this->lostChimps + 1; + this->units[DAT_CurrentUnitSlotID::instance].logicalState = OpenSHC::Map::Units::ULS_REMOVE; + } + _buildingID = this->units[DAT_CurrentUnitSlotID::instance].owner; + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_buildingID] == -1) { + this->units[DAT_CurrentUnitSlotID::instance].siegeTargetPlayerID + = (short)DAT_GameState::instance.playerDataArray[_buildingID].attackedPlayerID; + } else { + this->units[DAT_CurrentUnitSlotID::instance].siegeTargetPlayerID = 0; + } + if (this->units[DAT_CurrentUnitSlotID::instance].blessedAmount != 0) { + this->units[DAT_CurrentUnitSlotID::instance].blessedAmount + = this->units[DAT_CurrentUnitSlotID::instance].blessedAmount + -1; + DAT_GameState::instance.playerDataArray[_buildingID].blessedPeopleCountUnk + = DAT_GameState::instance.playerDataArray[_buildingID].blessedPeopleCountUnk + 1; + } else if (DAT_UnitPropertiesDefinedData::instance + .NotBlessableUnits[(short)this->units[DAT_CurrentUnitSlotID::instance].unitType] + == 0) { + DAT_GameState::instance.playerDataArray[_buildingID].unblessedPeopleCountUnk + = DAT_GameState::instance.playerDataArray[_buildingID].unblessedPeopleCountUnk + 1; + } + _currentUnitID = DAT_CurrentUnitSlotID::instance; + _unitIDBased8value = (int)_currentUnitID % 16; + if (_unitIDBased8value == _rngNumber8) { + int _unitTile = this->units[_currentUnitID].tile; + if (DAT_TileMapState::instance.PathConnectionLayer[_unitTile] == 0 + && (DAT_TileMapState::instance.LogicLayer[_unitTile] & 0x40000000U) == 0 + && this->units[_currentUnitID].moveRelatedFlag != 1) { + _buildingID = DAT_TileMapState::instance.BuildingLayer[_unitTile]; + if ((_buildingID == 0 + || (DAT_BuildingsState::instance.buildings[_buildingID].logicalState + == OpenSHC::Map::Buildings::BLS_NORMAL + && (_buildingType + = DAT_BuildingsState::instance.buildings[_buildingID].buildingType, + DAT_BuildingDefinedData::instance + .BuildingIsGateHouseArray[(short)_buildingType] + == 0) + && _buildingType != OpenSHC::Map::Buildings::BT_DRAWBRIDGE)) + && this->units[_currentUnitID].state.generic + != OpenSHC::Map::Units::States::US_DISAPPEAR) { + if (this->units[_currentUnitID].unitType == OpenSHC::Map::Units::UT_CHICKEN) { + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, + DAT_SFXState::ptr)((int)this->units[_currentUnitID].x, + (int)(this->units[_currentUnitID].y), OpenSHC::DE::SHCDE::FX_CHICKEN_FLAP); + _currentUnitID = DAT_CurrentUnitSlotID::instance; + } + if (999 < (int)(DAT_GameCore::instance.mapTimeInTicks + - this->units[_currentUnitID].time) + && (_unitType = this->units[_currentUnitID].unitType, + _unitType != OpenSHC::Map::Units::UT_S_TOWER)) { + if (_unitType == OpenSHC::Map::Units::UT_LORD) { + uint _targetY = (uint)this->units[_currentUnitID].targetY_2; + uint _targetX = (uint)this->units[_currentUnitID].targetX_2; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::setPositionOfUnit, + this)(_currentUnitID, _targetX, _targetY, + (undefined4)((int)(DAT_TileMapState::instance + .HeightLayer[DAT_ViewportRenderState::instance + .translationMatrix[_targetY] + .addXgetTile + + _targetX]))); + this->units[DAT_CurrentUnitSlotID::instance].destinationNeeded + = OpenSHC::Map::Units::Pathfinding::DNE_DESTINATION_HAS_BEEN_SET; + this->units[DAT_CurrentUnitSlotID::instance].state.generic + = OpenSHC::Map::Units::States::US_IDLEUnk; + _currentUnitID = DAT_CurrentUnitSlotID::instance; + } else { + this->units[_currentUnitID].state.generic + = OpenSHC::Map::Units::States::US_DISAPPEAR; + this->units[DAT_CurrentUnitSlotID::instance].updateTickTracker = 0; + _currentUnitID = DAT_CurrentUnitSlotID::instance; + } + } + } + } + UVar6 = this->units[_currentUnitID].unitType; + if (((UVar6 == OpenSHC::Map::Units::UT_S_CATAPULT) + || (UVar6 == OpenSHC::Map::Units::UT_S_FBALLISTA)) + && (DAT_TileMapState::instance.LogicLayer[this->units[_currentUnitID].tile] & 0x50000000U) + != 0) { + this->units[_currentUnitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + _currentUnitID = DAT_CurrentUnitSlotID::instance; + this->units[DAT_CurrentUnitSlotID::instance].updateTickTracker = 0; + } + } + if (this->units[_currentUnitID].logicalState == OpenSHC::Map::Units::ULS_NORMAL + && ((this->units[_currentUnitID].x == 0 || (this->units[_currentUnitID].y == 0)) + || (this->units[_currentUnitID].tile < 0))) { + this->units[_currentUnitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + this->units[DAT_CurrentUnitSlotID::instance].updateTickTracker = 0; + _currentUnitID = DAT_CurrentUnitSlotID::instance; + } + } + DAT_CurrentUnitSlotID::instance = _currentUnitID + 1; + } while ((int)DAT_CurrentUnitSlotID::instance < 2500); + DAT_CurrentUnitSlotID::instance = 1; + if (1 < (int)this->maxUnitCount) { + do { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState + != OpenSHC::Map::Units::ULS_INVISIBLE) { + if (this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + _buildingID = this->units[DAT_CurrentUnitSlotID::instance].attackedUnitID; + this->units[_buildingID].attackedBy = this->units[_buildingID].attackedBy + 1; + if ((int)this->units[_buildingID].attackedUnitID != DAT_CurrentUnitSlotID::instance) { + this->units[DAT_CurrentUnitSlotID::instance].attackedBy + = this->units[DAT_CurrentUnitSlotID::instance].attackedBy + 1; + } + if ((this->units[_buildingID].attackedBy == 1) + && (this->units[_buildingID].isStalked == 0)) { + DAT_GameCore::instance.cowPoisonTrackerUnk + = DAT_GameCore::instance.cowPoisonTrackerUnk + 1; + } + } + _buildingID = this->units[DAT_CurrentUnitSlotID::instance].movementType_OR_targetUnitID; + if (_buildingID != 0) { + this->units[_buildingID].huntedBy = this->units[_buildingID].huntedBy + 1; + } + _buildingID = this->units[DAT_CurrentUnitSlotID::instance].field266_0x3de; + if (_buildingID != 0) { + this->units[_buildingID].field265_0x3dc = this->units[_buildingID].field265_0x3dc + 1; + } + _shortFieldPtr = &this->units[DAT_CurrentUnitSlotID::instance].field97_0xd0; + if (0 < this->units[DAT_CurrentUnitSlotID::instance].field97_0xd0) { + *_shortFieldPtr = *_shortFieldPtr + -1; + } + } + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1; + } while ((int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount); + } + uint _tick0To64 = DAT_GameCore::instance.mapTimeInTicks & 0x3f; + for (int _playerID = 1; _playerID < 9; _playerID = _playerID + 1) { + DAT_GameState::instance.playerDataArray[_playerID].totalTroopsType0 = 0; + DAT_GameState::instance.playerDataArray[_playerID].idlePeasantsCount = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalDefensiveTroopsUnk = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalRaidingTroopsUnk = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalAttackTroops = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalTroopsType6 = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalTroopsType7 = 0; + DAT_GameState::instance.playerDataArray[_playerID].field852_0x2b58 = 0; + DAT_GameState::instance.playerDataArray[_playerID].engineerCountRelated = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalAttackingEngineerTroops = 0; + DAT_GameState::instance.playerDataArray[_playerID].unknownHarrassingSiegeRelated = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalDiggingUnitTroops = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalAssassinTroops = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalUnit2Troops = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalLaddermenTroops = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalTunnelerTroops = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalUnitPatrolTroops = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalUnitBackupTroops = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalUnitEngageTroops = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalUnitSiegeDefTroops = 0; + DAT_GameState::instance.playerDataArray[_playerID].totalMaxDefaultTroops = 0; + DAT_GameState::instance.playerDataArray[_playerID].harassingSiegeEnginesCountUnk = 0; + if (_tick0To64 == 0) { + DAT_GameState::instance.playerDataArray[_playerID].totalTroopValue = 0; + } + } + DAT_CurrentUnitSlotID::instance = 1; + if (1 < (int)this->maxUnitCount) { + do { + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState + != OpenSHC::Map::Units::ULS_INVISIBLE) { + this->unitCount = this->unitCount + 1; + if (this->units[DAT_CurrentUnitSlotID::instance].field64_0x90 != 0) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::stampOccupancyFlagOnSurroundingTiles, this)( + DAT_CurrentUnitSlotID::instance); + } + DAT_TileMapState::instance.OccupancyLayer[this->units[DAT_CurrentUnitSlotID::instance].tile] + = DAT_TileMapState::instance + .OccupancyLayer[this->units[DAT_CurrentUnitSlotID::instance].tile] + | this->units[DAT_CurrentUnitSlotID::instance].occupancyOrFlag; + if (this->units[DAT_CurrentUnitSlotID::instance].isSelectable_OR_matchTime != 0) { + _buildingID = this->units[DAT_CurrentUnitSlotID::instance].owner; + if ((DAT_GameCore::instance.mapTimeInTicks & 0x3f) == 0) { + _intFieldPtr = &DAT_GameState::instance.playerDataArray[_buildingID].totalTroopValue; + _troopValue + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::getValueOfTroopType, + DAT_TroopValueState::ptr)( + (UnitType)(short)this->units[DAT_CurrentUnitSlotID::instance].unitType); + *_intFieldPtr = *_intFieldPtr + _troopValue; + if ((char)this->units[DAT_CurrentUnitSlotID::instance].firstNameIndex < '\x01') { + /* + Every 0x3f ticks, assign names to citizen units + */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignNameToUnit, this)( + DAT_CurrentUnitSlotID::instance); + } + } + UVar6 = this->units[DAT_CurrentUnitSlotID::instance].unitType; + if (UVar6 == OpenSHC::Map::Units::UT_A_HARCHER) { + DAT_TileMapState::instance + .SEC_TileMap1104[this->units[DAT_CurrentUnitSlotID::instance].tile] = '\x06'; + } else if (UVar6 == OpenSHC::Map::Units::UT_A_FIRETHROWER) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::writeSixToTileMap1104InAllDirections, this)( + DAT_CurrentUnitSlotID::instance, 6); + } + UVar6 = this->units[DAT_CurrentUnitSlotID::instance].unitType; + if (UVar6 != OpenSHC::Map::Units::UT_LORD) { + short _aiBehaviour = this->units[DAT_CurrentUnitSlotID::instance].aiUnitBehaviourType; + if (_aiBehaviour == 10) { + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackingEngineerTroops + = DAT_GameState::instance.playerDataArray[_buildingID] + .totalAttackingEngineerTroops + + 1; + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + 1; + } else if (UVar6 != OpenSHC::Map::Units::UT_E_ENGINEER) { + /* + fixme: TODO, review this bit, cannot be true! + */ + + switch (_aiBehaviour) { + case 0: + DAT_GameState::instance.playerDataArray[_buildingID].totalTroopsType0 + = DAT_GameState::instance.playerDataArray[_buildingID].totalTroopsType0 + 1; + break; + case 1: + case 4: + DAT_GameState::instance.playerDataArray[_buildingID].totalDefensiveTroopsUnk + = DAT_GameState::instance.playerDataArray[_buildingID] + .totalDefensiveTroopsUnk + + 1; + break; + case 2: + DAT_GameState::instance.playerDataArray[_buildingID].totalRaidingTroopsUnk + = DAT_GameState::instance.playerDataArray[_buildingID].totalRaidingTroopsUnk + + 1; + break; + default: + break; + case 6: + DAT_GameState::instance.playerDataArray[_buildingID].totalTroopsType6 + = DAT_GameState::instance.playerDataArray[_buildingID].totalTroopsType6 + 1; + break; + case 7: + DAT_GameState::instance.playerDataArray[_buildingID].totalTroopsType7 + = DAT_GameState::instance.playerDataArray[_buildingID].totalTroopsType7 + 1; + break; + case 0xb: + DAT_GameState::instance.playerDataArray[_buildingID].totalDiggingUnitTroops + = DAT_GameState::instance.playerDataArray[_buildingID] + .totalDiggingUnitTroops + + 1; + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + + 1; + break; + case 0xc: + DAT_GameState::instance.playerDataArray[_buildingID].totalAssassinTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAssassinTroops + + 1; + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + + 1; + break; + case 0xd: + DAT_GameState::instance.playerDataArray[_buildingID].totalUnit2Troops + = DAT_GameState::instance.playerDataArray[_buildingID].totalUnit2Troops + 1; + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + + 1; + break; + case 0xe: + DAT_GameState::instance.playerDataArray[_buildingID].totalLaddermenTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalLaddermenTroops + + 1; + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + + 1; + break; + case 0xf: + DAT_GameState::instance.playerDataArray[_buildingID].totalTunnelerTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalTunnelerTroops + + 1; + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + + 1; + break; + case 0x10: + DAT_GameState::instance.playerDataArray[_buildingID].totalUnitPatrolTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalUnitPatrolTroops + + 1; + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + + 1; + break; + case 0x11: + DAT_GameState::instance.playerDataArray[_buildingID].totalUnitBackupTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalUnitBackupTroops + + 1; + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + + 1; + break; + case 0x12: + DAT_GameState::instance.playerDataArray[_buildingID].totalUnitEngageTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalUnitEngageTroops + + 1; + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + + 1; + break; + case 0x13: + DAT_GameState::instance.playerDataArray[_buildingID].totalUnitSiegeDefTroops + = DAT_GameState::instance.playerDataArray[_buildingID] + .totalUnitSiegeDefTroops + + 1; + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + + 1; + break; + case 0x14: + DAT_GameState::instance.playerDataArray[_buildingID].totalMaxDefaultTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalMaxDefaultTroops + + 1; + DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + = DAT_GameState::instance.playerDataArray[_buildingID].totalAttackTroops + + 1; + break; + case 0x15: + DAT_GameState::instance.playerDataArray[_buildingID] + .harassingSiegeEnginesCountUnk + = DAT_GameState::instance.playerDataArray[_buildingID] + .harassingSiegeEnginesCountUnk + + 1; + } + } + } + } + if ((this->units[DAT_CurrentUnitSlotID::instance].unitType == OpenSHC::Map::Units::UT_E_ARCHER + || this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_A_ARCHER) + && (this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_AIM_WEAPONUnk + || this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_FIRE_WEAPONUnk)) { + _troopValue = this->units[DAT_CurrentUnitSlotID::instance].shootTargetedUnit; + if (0 < _troopValue + && this->units[_troopValue].uid + == this->units[DAT_CurrentUnitSlotID::instance].targetUID) { + this->units[_troopValue].field233_0x39a = 1; + } + } + if (this->units[DAT_CurrentUnitSlotID::instance].enemyNoticeFrequencyUnk != 0 + && (DAT_GameState::instance.mapAndTime.totalGameTicksUnk + & this->units[DAT_CurrentUnitSlotID::instance].enemyNoticeFrequencyUnk) + == (this->units[DAT_CurrentUnitSlotID::instance].fixedRng + & this->units[DAT_CurrentUnitSlotID::instance].enemyNoticeFrequencyUnk)) { + if (this->units[DAT_CurrentUnitSlotID::instance].owner == 0) { + _troopValue = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func:: + computeDistanceToNearestEnemyForLegacyMissions, + this)(DAT_CurrentUnitSlotID::instance); + this->units[DAT_CurrentUnitSlotID::instance].closestEnemyMicroDistance + = (short)_troopValue; + } else { + dword _closestEnemyDistance = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::findNearestEnemyAndHeadTowardsIt, this)( + DAT_CurrentUnitSlotID::instance); + this->units[DAT_CurrentUnitSlotID::instance].closestEnemyMicroDistance + = (short)_closestEnemyDistance; + this->units[DAT_CurrentUnitSlotID::instance].assassinsMicroDistanceToEnemyUnk + = this->unitDistanceComputationResultUnk; + } + } + _shortFieldPtr = &this->units[DAT_CurrentUnitSlotID::instance].lookForEnemy; + if (this->units[DAT_CurrentUnitSlotID::instance].lookForEnemy < 0) { + *_shortFieldPtr = *_shortFieldPtr + 1; + } else { + *_shortFieldPtr = 0; + } + _shortFieldPtr = &this->units[DAT_CurrentUnitSlotID::instance].unknownMovementRelated_0x2d2; + if (this->units[DAT_CurrentUnitSlotID::instance].unknownMovementRelated_0x2d2 < 0) { + *_shortFieldPtr = *_shortFieldPtr + 1; + } + this->units[DAT_CurrentUnitSlotID::instance].SA = 0; + if (DAT_TileMapState::instance.refreshRelatedOne != 0) { + byte _heightDiv10 = this->units[DAT_CurrentUnitSlotID::instance].heightDiv10; + if (_heightDiv10 != 0) { + this->units[DAT_CurrentUnitSlotID::instance].padding_0x83[0] + = this->units[DAT_CurrentUnitSlotID::instance].padding_0x83[0] + - *(char*)((int)DAT_UnitPropertiesDefinedData::ptr + + (DAT_UpdateUnitsTracker::instance - (uint)_heightDiv10) * 4 + 0x11a24); + if (100 < (byte)this->units[DAT_CurrentUnitSlotID::instance].padding_0x83[0]) { + this->units[DAT_CurrentUnitSlotID::instance].padding_0x83[0] = 0; + } + if ((int)((byte)this->units[DAT_CurrentUnitSlotID::instance].heightDiv10 + 0xd) + <= DAT_UpdateUnitsTracker::instance) { + this->units[DAT_CurrentUnitSlotID::instance].heightDiv10 = 0; + this->units[DAT_CurrentUnitSlotID::instance].padding_0x83[0] = 0; + } + } + } + } + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1; + } while ((int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount); + } + MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::recountActiveFires, DAT_EntityState::ptr)(); + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::flagUnitsWithActiveEntity, DAT_EntityState::ptr)(); + DAT_CurrentUnitSlotID::instance = 1; + if (1 < (int)this->maxUnitCount) { + do { + bool _updateAnimation = false; + switch (this->units[DAT_CurrentUnitSlotID::instance].logicalState) { + case OpenSHC::Map::Units::ULS_INVISIBLE: + break; + case ((UnitLogicState)1): + this->units[DAT_CurrentUnitSlotID::instance].logicalState = OpenSHC::Map::Units::ULS_NORMAL; + _updateAnimation = true; + break; + case OpenSHC::Map::Units::ULS_REMOVE: + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::deleteUnit, this)( + DAT_CurrentUnitSlotID::instance); + break; + case OpenSHC::Map::Units::ULS_TRANSITIONING: + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::changeUnitType, this)( + DAT_CurrentUnitSlotID::instance); + _updateAnimation = true; + break; + case ((UnitLogicState)5): + this->units[DAT_CurrentUnitSlotID::instance].logicalState = ((UnitLogicState)1); + break; + default: + _updateAnimation = true; + break; + } + if (_updateAnimation) { + int* _ptr_animationTicker = &this->units[DAT_CurrentUnitSlotID::instance].animationTicker; + *_ptr_animationTicker = *_ptr_animationTicker + 1; + int _animationTicker = this->units[DAT_CurrentUnitSlotID::instance].animationTicker; + if (this->units[DAT_CurrentUnitSlotID::instance].animationSpeed + + this->units[DAT_CurrentUnitSlotID::instance].animationLeapTicksTotal + < _animationTicker) { + this->units[DAT_CurrentUnitSlotID::instance].animationLeapTicksTotal = _animationTicker; + this->units[DAT_CurrentUnitSlotID::instance].animationCycleNumber + = this->units[DAT_CurrentUnitSlotID::instance].animationCycleNumber + 1; + this->units[DAT_CurrentUnitSlotID::instance].animationCycleNumberHasJustIncremented = TRUE; + if (999 < this->units[DAT_CurrentUnitSlotID::instance].animationCycleNumber) { + this->units[DAT_CurrentUnitSlotID::instance].animationCycleNumber = 0; + } + } else { + this->units[DAT_CurrentUnitSlotID::instance].animationCycleNumberHasJustIncremented = FALSE; + } + _buildingID = (short)DAT_TileMapState::instance.mapOrientation; + if (this->units[DAT_CurrentUnitSlotID::instance].field39_0x58 == 0) { + if (this->units[DAT_CurrentUnitSlotID::instance].state.generic + != OpenSHC::Map::Units::States::US_MELEE_ATTACK) { + this->units[DAT_CurrentUnitSlotID::instance].facingDirectionMapOrientationCorrected + = this->units[DAT_CurrentUnitSlotID::instance].facingDirection - _buildingID; + } else { + this->units[DAT_CurrentUnitSlotID::instance].facingDirectionMapOrientationCorrected + = this->units[DAT_CurrentUnitSlotID::instance].orientation - _buildingID; + } + } else { + this->units[DAT_CurrentUnitSlotID::instance].facingDirectionMapOrientationCorrected + = (short)DAT_TileMapState::instance.field84_0x5548a4 - _buildingID; + } + _shortFieldPtr + = &this->units[DAT_CurrentUnitSlotID::instance].facingDirectionMapOrientationCorrected; + if (this->units[DAT_CurrentUnitSlotID::instance].facingDirectionMapOrientationCorrected < 0) { + *_shortFieldPtr = *_shortFieldPtr + 8; + } + _buildingID = this->units[DAT_CurrentUnitSlotID::instance].owner; + DAT_GameState::instance.playerDataArray[_buildingID].countEntities + = DAT_GameState::instance.playerDataArray[_buildingID].countEntities + 1; + if (DAT_UnitPropertiesDefinedData::instance + .COMPUTER_MANAGED[(short)this->units[DAT_CurrentUnitSlotID::instance].unitType] + != 0) { + DAT_GameState::instance.playerDataArray[_buildingID].currentPopulation_2 + = DAT_GameState::instance.playerDataArray[_buildingID].currentPopulation_2 + 1; + } + DAT_UnitHasBecomeIdle::instance = 0; + if (this->units[DAT_CurrentUnitSlotID::instance].dying != 0 + && this->units[DAT_CurrentUnitSlotID::instance].state.generic + != OpenSHC::Map::Units::States::US_DISAPPEAR) { + UVar6 = this->units[DAT_CurrentUnitSlotID::instance].unitType; + if (UVar6 != OpenSHC::Map::Units::UT_BURNINGMAN + && UVar6 != OpenSHC::Map::Units::UT_BURNING_ANIMAL_BIG + && UVar6 != OpenSHC::Map::Units::UT_BURNING_ANIMAL_SMALL + && ((short)this->units[DAT_CurrentUnitSlotID::instance].state.generic < 0x6f + || 0x75 < (short)this->units[DAT_CurrentUnitSlotID::instance].state.generic)) { + this->units[DAT_CurrentUnitSlotID::instance].state.generic + = OpenSHC::Map::Units::States::US_DEATH_01; + this->units[DAT_CurrentUnitSlotID::instance].animationCycleNumber = 0; + } + } + if (DAT_UnitPropertiesDefinedData::instance + .COMPUTER_CONTROLLED[(short)this->units[DAT_CurrentUnitSlotID::instance].unitType] + != 0) { + _buildingID = this->units[DAT_CurrentUnitSlotID::instance].workplaceBuildingID_1; + if (DAT_BuildingsState::instance.buildings[_buildingID].uid + == this->units[DAT_CurrentUnitSlotID::instance].workplaceBuildingUID) { + if (DAT_BuildingsState::instance.buildings[_buildingID].sleeping != false) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func:: + makeUnitStopWalkingByClearingPathProgressState, + this)(DAT_CurrentUnitSlotID::instance); + if (7 < this->units[DAT_CurrentUnitSlotID::instance].movementRelated) { + this->units[DAT_CurrentUnitSlotID::instance].logicalState + = OpenSHC::Map::Units::ULS_TRANSITIONING; + this->units[DAT_CurrentUnitSlotID::instance].unitTypeToChangeInto + = OpenSHC::Map::Units::UT_PEASANT; + this->units[DAT_CurrentUnitSlotID::instance].state_2 = 0; + this->units[DAT_CurrentUnitSlotID::instance].workplaceBuildingID_1 = 0; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::clearHiddenFlagAndUpdatePosition, + this)(DAT_CurrentUnitSlotID::instance); + } + this->units[DAT_CurrentUnitSlotID::instance].disappearFadeAlphaCountdown = 0; + } + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func:: + makeUnitStopWalkingByClearingPathProgressState, + this)(DAT_CurrentUnitSlotID::instance); + if (7 < this->units[DAT_CurrentUnitSlotID::instance].movementRelated) { + this->units[DAT_CurrentUnitSlotID::instance].logicalState + = OpenSHC::Map::Units::ULS_TRANSITIONING; + this->units[DAT_CurrentUnitSlotID::instance].workplaceBuildingID_1 = 0; + this->units[DAT_CurrentUnitSlotID::instance].unitTypeToChangeInto + = OpenSHC::Map::Units::UT_PEASANT; + this->units[DAT_CurrentUnitSlotID::instance].state_2 = 0; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::clearHiddenFlagAndUpdatePosition, this)( + DAT_CurrentUnitSlotID::instance); + } + } + } + this->units[DAT_CurrentUnitSlotID::instance].field131_0x2ac = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::processMeleeInitiation, this)( + DAT_CurrentUnitSlotID::instance); + this->units[DAT_CurrentUnitSlotID::instance].field143_0x2c4 + = this->units[DAT_CurrentUnitSlotID::instance].state.generic; + if (this->units[DAT_CurrentUnitSlotID::instance].logicalState + != OpenSHC::Map::Units::ULS_TRANSITIONING) { + /* + Update unit state + */ + + (*DAT_UnitPropertiesDefinedData::instance.UpdateUnitFunctions + [(short)this->units[DAT_CurrentUnitSlotID::instance].unitType])(); + } + UnitStateShort UVar8 = this->units[DAT_CurrentUnitSlotID::instance].field143_0x2c4; + if (UVar8 != this->units[DAT_CurrentUnitSlotID::instance].state.generic + && (UVar8 + == (OpenSHC::Map::Units::States::US_DEATH_02 + | OpenSHC::Map::Units::States::US_STAND_UPUnk + | OpenSHC::Map::Units::States::US_RELOAD_WEAPONUnk) + || (UVar8 == OpenSHC::Map::Units::States::US_DIG))) { + _troopValue = this->units[DAT_CurrentUnitSlotID::instance].digTileTarget; + if (DAT_TileMapState::instance.moats[_troopValue].owner != '\0') { + DAT_TileMapState::instance.moats[_troopValue].someCountDown + = DAT_TileMapState::instance.moats[_troopValue].someCountDown + -0x14; + } + } + this->units[DAT_CurrentUnitSlotID::instance].field41_0x5c = 0; + if (this->units[DAT_CurrentUnitSlotID::instance].usingTeleport == 0) { + _intFieldPtr = &this->units[DAT_CurrentUnitSlotID::instance].field200_0x354; + /* + Not climbing + */ + + *_intFieldPtr = *_intFieldPtr + 1; + _troopValue = this->units[DAT_CurrentUnitSlotID::instance].field200_0x354; + if ((int)this->units[DAT_CurrentUnitSlotID::instance].calculatedMovementSpeed + + (int)this->units[DAT_CurrentUnitSlotID::instance].stateBasedSpeed + + (int)this->units[DAT_CurrentUnitSlotID::instance].moveDelay + < _troopValue - this->units[DAT_CurrentUnitSlotID::instance].field199_0x350) { + _shortFieldPtr = &this->units[DAT_CurrentUnitSlotID::instance].movementRunUpTime; + this->units[DAT_CurrentUnitSlotID::instance].field199_0x350 = _troopValue; + if (this->units[DAT_CurrentUnitSlotID::instance].movementRunUpTime <= 0) { + *_shortFieldPtr = 0; + } else { + *_shortFieldPtr = *_shortFieldPtr + -1; + } + _troopValue = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::processUnitMove, + this)(DAT_CurrentUnitSlotID::instance, + (int)(this->units[DAT_CurrentUnitSlotID::instance].stateBasedSpeed)); + if (_troopValue != 0) { + if (this->units[DAT_CurrentUnitSlotID::instance].state.generic + == OpenSHC::Map::Units::States::US_MOVE_TO_DESTINATION + && this->units[DAT_CurrentUnitSlotID::instance].disappearFadeAlphaCountdown != 0 + && this->units[DAT_CurrentUnitSlotID::instance].fadeType == 0) { + this->units[DAT_CurrentUnitSlotID::instance].disappearFadeAlphaCountdown = 0; + } + this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e + = this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e + 1; + if (0xf < this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e) { + this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e = 0; + } + this->units[DAT_CurrentUnitSlotID::instance].field217_0x37c + = this->units[DAT_CurrentUnitSlotID::instance].field217_0x37c + 2; + if (0xd < this->units[DAT_CurrentUnitSlotID::instance].field217_0x37c) { + this->units[DAT_CurrentUnitSlotID::instance].field217_0x37c = 0; + } + this->units[DAT_CurrentUnitSlotID::instance].field215_0x378 + = this->units[DAT_CurrentUnitSlotID::instance].field215_0x378 + 2; + if (0xf < this->units[DAT_CurrentUnitSlotID::instance].field215_0x378) { + this->units[DAT_CurrentUnitSlotID::instance].field215_0x378 = 0; + } + this->units[DAT_CurrentUnitSlotID::instance].field254_0x3c6 + = this->units[DAT_CurrentUnitSlotID::instance].field254_0x3c6 + 1; + if (0x11 < this->units[DAT_CurrentUnitSlotID::instance].field254_0x3c6) { + this->units[DAT_CurrentUnitSlotID::instance].field254_0x3c6 = 0; + } + this->units[DAT_CurrentUnitSlotID::instance].field312_0x428 + = this->units[DAT_CurrentUnitSlotID::instance].field312_0x428 + 1; + if (0x17 < this->units[DAT_CurrentUnitSlotID::instance].field312_0x428) { + this->units[DAT_CurrentUnitSlotID::instance].field312_0x428 = 0; + } + } + this->units[DAT_CurrentUnitSlotID::instance].field216_0x37a + = this->units[DAT_CurrentUnitSlotID::instance].field216_0x37a + 1; + if (0xb < this->units[DAT_CurrentUnitSlotID::instance].field216_0x37a) { + this->units[DAT_CurrentUnitSlotID::instance].field216_0x37a = 0; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::calculateUnitMovementSpeed, + this)(DAT_CurrentUnitSlotID::instance); + } + } else { + /* + Climbing + */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::unitClimbing, this)( + DAT_CurrentUnitSlotID::instance); + } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::recomputeUnitStandingHeight, this)( + DAT_CurrentUnitSlotID::instance); + switch (this->units[DAT_CurrentUnitSlotID::instance].field_0x30_animRelated) { + case 8: + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = (int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + + this->units[DAT_CurrentUnitSlotID::instance].field215_0x378 * 8; + if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_A_HARCHER + && (_buildingID + = this->units[DAT_CurrentUnitSlotID::instance].horseArcherShootingVariation, + _buildingID != 4) + && _buildingID != 5 && _buildingID != 6) { + this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber; + } + break; + case 9: + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = (int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + + (this->units[DAT_CurrentUnitSlotID::instance].field215_0x378 * 8) / 2; + break; + case 0xc: + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = (int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + + this->units[DAT_CurrentUnitSlotID::instance].field216_0x37a * 8; + break; + case 0xe: + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = (int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + + this->units[DAT_CurrentUnitSlotID::instance].field217_0x37c * 8; + break; + case 0x10: + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = (int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + + this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e * 8; + if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_A_HARCHER) { + this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber; + } + if (this->units[DAT_CurrentUnitSlotID::instance].unitType + == OpenSHC::Map::Units::UT_E_KNIGHT) { + this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber; + if ((DAT_CurrentUnitSlotID::instance & 1) == 0) { + if (this->units[DAT_CurrentUnitSlotID::instance].stateBasedSpeed != 0 + && (this->units[DAT_CurrentUnitSlotID::instance].movementType_OR_targetUnitID + != 0 + || (this->units[DAT_CurrentUnitSlotID::instance].targetingType + == OpenSHC::Map::Units::UIT_UNIT_ATTACK_UNIT)) + && this->units[DAT_CurrentUnitSlotID::instance].totalSizeOfPathPlan + -0x10 + <= (int)this->units[DAT_CurrentUnitSlotID::instance] + .currentIndexInPathPlan) { + this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + = this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + 0x80; + } + } else { + this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + = this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + 0x270; + } + } + break; + case 0x11: + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = this->units[DAT_CurrentUnitSlotID::instance].facingDirectionMapOrientationCorrected + * 0x10 + + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + + (int)this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e; + break; + case 0x12: + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = (int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + + this->units[DAT_CurrentUnitSlotID::instance].field254_0x3c6 * 8; + break; + case 0x13: + case 0x14: + this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + = (int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + = this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + + ((int)this->units[DAT_CurrentUnitSlotID::instance].field215_0x378 / 2) * 8; + break; + case 0x15: + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = (int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + + this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e * 8; + _troopValue + = this->units[DAT_CurrentUnitSlotID::instance].facingDirectionMapOrientationCorrected + + 0x80 + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk = _troopValue; + this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + = this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + + this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e * 8; + break; + case 0x16: { + uint _correctedDirection = ((int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + 4) + % 8; + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber = _correctedDirection + 0x151; + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + + ((byte)this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e & 3) * 8; + _correctedDirection = ((int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + 4) + % 8; + _troopValue = _correctedDirection + 0x1d1; + this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk = _troopValue; + this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + = this->units[DAT_CurrentUnitSlotID::instance].imageIDUnk + + this->units[DAT_CurrentUnitSlotID::instance].field218_0x37e * 8; + break; + } + case 0x18: + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = (int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + = this->units[DAT_CurrentUnitSlotID::instance].gfxNumber + + this->units[DAT_CurrentUnitSlotID::instance].field312_0x428 * 8; + break; + case 99: + this->units[DAT_CurrentUnitSlotID::instance].imageID2 + = (int)this->units[DAT_CurrentUnitSlotID::instance] + .facingDirectionMapOrientationCorrected + + this->units[DAT_CurrentUnitSlotID::instance].animationSheetFrameOffset; + this->units[DAT_CurrentUnitSlotID::instance].imageID2 + = this->units[DAT_CurrentUnitSlotID::instance].imageID2 + + ((int)this->units[DAT_CurrentUnitSlotID::instance].field215_0x378 / 2) * 8; + } + _shortFieldPtr = &this->units[DAT_CurrentUnitSlotID::instance].unitSpeedMatchingRelatedUnk; + if (this->units[DAT_CurrentUnitSlotID::instance].unitSpeedMatchingRelatedUnk != 0) { + *_shortFieldPtr = *_shortFieldPtr + -1; + } + byte _fadeAlpha = this->units[DAT_CurrentUnitSlotID::instance].fadeType; + if (_fadeAlpha != 0) { + if (_fadeAlpha == 1) { + this->units[DAT_CurrentUnitSlotID::instance].disappearFadeAlphaCountdown + = (byte)DAT_UnitPropertiesDefinedData::instance.FadeAlpha_Values_1_2 + [(char)this->units[DAT_CurrentUnitSlotID::instance].fadeCounter]; + } else { + if (_fadeAlpha == 2) { + _fadeAlpha = (byte)DAT_UnitPropertiesDefinedData::instance.FadeAlpha_Values_1_2 + [(char)this->units[DAT_CurrentUnitSlotID::instance].fadeCounter]; + } else { + byte _fadeCounter = this->units[DAT_CurrentUnitSlotID::instance].fadeCounter; + if (_fadeAlpha == 3) { + _fadeAlpha = (byte)DAT_UnitPropertiesDefinedData::instance + .FadeAlpha_Values_3[(char)_fadeCounter]; + } else { + _fadeAlpha = (byte)DAT_UnitPropertiesDefinedData::instance + .FadeAlpha_Values_4[(char)_fadeCounter]; + } + } + this->units[DAT_CurrentUnitSlotID::instance].disappearFadeAlphaCountdown = _fadeAlpha; + } + this->units[DAT_CurrentUnitSlotID::instance].fadeCounter + = this->units[DAT_CurrentUnitSlotID::instance].fadeCounter + 1; + if ((char)this->units[DAT_CurrentUnitSlotID::instance].disappearFadeAlphaCountdown + < '\x01') { + this->units[DAT_CurrentUnitSlotID::instance].fadeType = 0; + this->units[DAT_CurrentUnitSlotID::instance].fadeCounter = 0; + } + } + } + DAT_CurrentUnitSlotID::instance = DAT_CurrentUnitSlotID::instance + 1; + } while ((int)DAT_CurrentUnitSlotID::instance < (int)this->maxUnitCount); + } + if (DAT_TileMapState::instance.refreshRelatedOne == 0) { + DAT_UpdateUnitsTracker::instance = 0; + return; + } + DAT_UpdateUnitsTracker::instance = DAT_UpdateUnitsTracker::instance + 1; + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/upgradeMapFormatForUnits.cpp b/src/OpenSHC/Map/Units/UnitsState/upgradeMapFormatForUnits.cpp new file mode 100644 index 000000000..09366101e --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/upgradeMapFormatForUnits.cpp @@ -0,0 +1,58 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Version.func.hpp" +#include "OpenSHC/IO/PackagedFileMagicNum.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + using OpenSHC::IO::PackagedFileMagicNum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0053E390 + void UnitsState::upgradeMapFormatForUnits( + PackagedFileMagicNum receivedMapVersion, PackagedFileMagicNum packagerMapVersion) + { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_UnknownVersion1)(); + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_117)(); + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_UnknownVersion2)(); + if (receivedMapVersion == packagerMapVersion) { + return; + } + if (receivedMapVersion == (PackagedFileMagicNum)100) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_100)(); + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_112)(); + } else if ((int)receivedMapVersion <= 0x70) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_112)(); + } + if ((int)receivedMapVersion < 0x72) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_114)(); + } + if ((int)receivedMapVersion < 0x75) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_117)(); + } + if ((int)receivedMapVersion < 0x7a) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsAttackTileLogicTo_122)(); + } + if ((int)receivedMapVersion < 0x82) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_130)(); + } + if ((int)receivedMapVersion < 0x95) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_149)(); + } + if ((int)receivedMapVersion < 0x9a) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_154)(); + } + if ((int)receivedMapVersion < 0x9b) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_155)(); + } + if ((int)receivedMapVersion < 0xa9) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsLordHealthTo_169)(); + } + if ((int)receivedMapVersion < 0xaa) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapUnitsTo_170)(); + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Units/UnitsState/writeSixToTileMap1104InAllDirections.cpp b/src/OpenSHC/Map/Units/UnitsState/writeSixToTileMap1104InAllDirections.cpp new file mode 100644 index 000000000..136ad028b --- /dev/null +++ b/src/OpenSHC/Map/Units/UnitsState/writeSixToTileMap1104InAllDirections.cpp @@ -0,0 +1,34 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Units { + + // FUNCTION: STRONGHOLDCRUSADER 0x00534520 + void UnitsState::writeSixToTileMap1104InAllDirections(int unitID, undefined4 six) + { + int _tile = this->units[unitID].tile; + uchar* _tileMap1104 = DAT_TileMapState::instance.SEC_TileMap1104; + int _y = this->units[unitID].y; + uchar _value = (uchar)six; + uchar* _row = _tileMap1104 + _tile; + _row[1] = _value; + _row[-1] = _value; + _row[0] = _value; + int* _directionRow + = (int*)((uchar*)DAT_TileMapState::instance.ptr_MovementDirectionTranslationMatrix + _y * 0x20); + uchar* _nextRow = _row + _directionRow[0]; + _nextRow[-1] = _value; + _nextRow[1] = _value; + _nextRow[0] = _value; + _row = _row + _directionRow[4]; + _row[-1] = _value; + _row[1] = _value; + _row[0] = _value; + } + + } +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b80b8635f..2ea113aed 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -49303,83 +49303,83 @@ SHC_3BB0A8C1_0x0052E120 | 0.0% | Pending SHC_3BB0A8C1_0x0052E1A0 | 0.0% | Pending -SHC_3BB0A8C1_0x0052E7B0 | 0.0% | Pending +SHC_3BB0A8C1_0x0052E7B0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0052E830 | 0.0% | Pending +SHC_3BB0A8C1_0x0052E830 | 89.5% | orig walks unit ptr -SHC_3BB0A8C1_0x0052E960 | 0.0% | Pending +SHC_3BB0A8C1_0x0052E960 | 87.9% | reg alloc -SHC_3BB0A8C1_0x0052EC10 | 0.0% | Pending +SHC_3BB0A8C1_0x0052EC10 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0052EDC0 | 0.0% | Pending +SHC_3BB0A8C1_0x0052EDC0 | 62.1% | reg alloc, edi save site -SHC_3BB0A8C1_0x0052EED0 | 0.0% | Pending +SHC_3BB0A8C1_0x0052EED0 | 80.0% | orig caches unitType local -SHC_3BB0A8C1_0x0052F010 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F010 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0052F070 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F070 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0052F0A0 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F0A0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0052F0D0 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F0D0 | 41.0% | branch shape differs -SHC_3BB0A8C1_0x0052F260 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F260 | 19.3% | loop shape differs -SHC_3BB0A8C1_0x0052F440 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F440 | 66.7% | loop shape differs SHC_3BB0A8C1_0x0052F4A0 | 0.0% | Pending -SHC_3BB0A8C1_0x0052F4E0 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F4E0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0052F550 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F550 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0052F570 | 0.0% | Pending -SHC_3BB0A8C1_0x0052F5B0 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F5B0 | 24.6% | orig fully unrolled x4 -SHC_3BB0A8C1_0x0052F680 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F680 | 58.3% | branch shape differs SHC_3BB0A8C1_0x0052F6C0 | 0.0% | Pending -SHC_3BB0A8C1_0x0052F730 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F730 | 82.8% | reg alloc -SHC_3BB0A8C1_0x0052F7E0 | 0.0% | Pending +SHC_3BB0A8C1_0x0052F7E0 | 26.4% | reg alloc, band order -SHC_3BB0A8C1_0x0052FBB0 | 0.0% | Pending +SHC_3BB0A8C1_0x0052FBB0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0052FBF0 | 0.0% | Pending +SHC_3BB0A8C1_0x0052FBF0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0052FC30 | 0.0% | Pending +SHC_3BB0A8C1_0x0052FC30 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0052FCA0 | 0.0% | Pending +SHC_3BB0A8C1_0x0052FCA0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0052FD00 | 0.0% | Pending +SHC_3BB0A8C1_0x0052FD00 | 90.1% | reg alloc -SHC_3BB0A8C1_0x0052FE00 | 0.0% | Pending +SHC_3BB0A8C1_0x0052FE00 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0052FE90 | 0.0% | Pending +SHC_3BB0A8C1_0x0052FE90 | 81.9% | orig caches dir in locals -SHC_3BB0A8C1_0x0052FF80 | 0.0% | Pending +SHC_3BB0A8C1_0x0052FF80 | 67.5% | orig caches dir in locals -SHC_3BB0A8C1_0x00530080 | 0.0% | Pending +SHC_3BB0A8C1_0x00530080 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005300B0 | 0.0% | Pending +SHC_3BB0A8C1_0x005300B0 | 26.2% | Style pass, asm differs -SHC_3BB0A8C1_0x005301F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005301F0 | 96.0% | reg alloc differs SHC_3BB0A8C1_0x00530210 | 0.0% | Pending -SHC_3BB0A8C1_0x00530240 | 0.0% | Pending +SHC_3BB0A8C1_0x00530240 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005302B0 | 0.0% | Pending +SHC_3BB0A8C1_0x005302B0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00530310 | 0.0% | Pending +SHC_3BB0A8C1_0x00530310 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00530390 | 0.0% | Pending +SHC_3BB0A8C1_0x00530390 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005303B0 | 0.0% | Pending -SHC_3BB0A8C1_0x00530400 | 0.0% | Pending +SHC_3BB0A8C1_0x00530400 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005304B4 | 0.0% | Pending @@ -49501,7 +49501,7 @@ SHC_3BB0A8C1_0x005304F4 | 0.0% | Pending SHC_3BB0A8C1_0x005304F5 | 0.0% | Pending -SHC_3BB0A8C1_0x00530500 | 0.0% | Pending +SHC_3BB0A8C1_0x00530500 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00530608 | 0.0% | Pending @@ -49623,7 +49623,7 @@ SHC_3BB0A8C1_0x00530648 | 0.0% | Pending SHC_3BB0A8C1_0x00530649 | 0.0% | Pending -SHC_3BB0A8C1_0x00530650 | 0.0% | Pending +SHC_3BB0A8C1_0x00530650 | 83.9% | reg alloc SHC_3BB0A8C1_0x00530690 | 0.0% | Pending @@ -49633,9 +49633,9 @@ SHC_3BB0A8C1_0x00530760 | 0.0% | Pending SHC_3BB0A8C1_0x005307B0 | 0.0% | Pending -SHC_3BB0A8C1_0x00530880 | 0.0% | Pending +SHC_3BB0A8C1_0x00530880 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005308F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005308F0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00530990 | 0.0% | Pending @@ -49659,13 +49659,13 @@ SHC_3BB0A8C1_0x00530EB0 | 0.0% | Pending SHC_3BB0A8C1_0x00530F20 | 0.0% | Pending -SHC_3BB0A8C1_0x00530FD0 | 0.0% | Pending +SHC_3BB0A8C1_0x00530FD0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00531000 | 0.0% | Pending +SHC_3BB0A8C1_0x00531000 | 38.3% | reg alloc, branch order -SHC_3BB0A8C1_0x005311F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005311F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00531220 | 0.0% | Pending +SHC_3BB0A8C1_0x00531220 | 44.0% | block order, reg alloc SHC_3BB0A8C1_0x00531814 | 0.0% | Pending @@ -50075,7 +50075,7 @@ SHC_3BB0A8C1_0x00531914 | 0.0% | Pending SHC_3BB0A8C1_0x00531915 | 0.0% | Pending -SHC_3BB0A8C1_0x00531920 | 0.0% | Pending +SHC_3BB0A8C1_0x00531920 | 28.7% | extra spills, frame size SHC_3BB0A8C1_0x005323C0 | 0.0% | Pending @@ -50331,7 +50331,7 @@ SHC_3BB0A8C1_0x0053245D | 0.0% | Pending SHC_3BB0A8C1_0x0053245E | 0.0% | Pending -SHC_3BB0A8C1_0x00532460 | 0.0% | Pending +SHC_3BB0A8C1_0x00532460 | 75.8% | reg alloc SHC_3BB0A8C1_0x005326A8 | 0.0% | Pending @@ -50459,7 +50459,7 @@ SHC_3BB0A8C1_0x005326F1 | 0.0% | Pending SHC_3BB0A8C1_0x005326F2 | 0.0% | Pending -SHC_3BB0A8C1_0x00532700 | 0.0% | Pending +SHC_3BB0A8C1_0x00532700 | 55.2% | orig dups call per branch SHC_3BB0A8C1_0x00532B40 | 0.0% | Pending @@ -50509,7 +50509,7 @@ SHC_3BB0A8C1_0x00532B98 | 0.0% | Pending SHC_3BB0A8C1_0x00532B9C | 0.0% | Pending -SHC_3BB0A8C1_0x00532BA0 | 0.0% | Pending +SHC_3BB0A8C1_0x00532BA0 | 50.3% | reg alloc SHC_3BB0A8C1_0x00532F10 | 0.0% | Pending @@ -50643,15 +50643,15 @@ SHC_3BB0A8C1_0x00532F5D | 0.0% | Pending SHC_3BB0A8C1_0x00532F5E | 0.0% | Pending -SHC_3BB0A8C1_0x00532F60 | 0.0% | Pending +SHC_3BB0A8C1_0x00532F60 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00532F80 | 0.0% | Pending +SHC_3BB0A8C1_0x00532F80 | 43.3% | block order, spills SHC_3BB0A8C1_0x00533010 | 0.0% | Pending -SHC_3BB0A8C1_0x00533090 | 0.0% | Pending +SHC_3BB0A8C1_0x00533090 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005330A0 | 0.0% | Pending +SHC_3BB0A8C1_0x005330A0 | 81.6% | switch fallthrough differs SHC_3BB0A8C1_0x00533474 | 0.0% | Pending @@ -50669,31 +50669,31 @@ SHC_3BB0A8C1_0x0053348C | 0.0% | Pending SHC_3BB0A8C1_0x00533490 | 0.0% | Pending -SHC_3BB0A8C1_0x005334A0 | 0.0% | Pending +SHC_3BB0A8C1_0x005334A0 | 41.2% | orig caches unitType local -SHC_3BB0A8C1_0x00533580 | 0.0% | Pending +SHC_3BB0A8C1_0x00533580 | 24.5% | orig caches locals -SHC_3BB0A8C1_0x00533630 | 0.0% | Pending +SHC_3BB0A8C1_0x00533630 | 42.3% | reg alloc -SHC_3BB0A8C1_0x00533810 | 0.0% | Pending +SHC_3BB0A8C1_0x00533810 | 80.3% | orig walks matrix row ptr -SHC_3BB0A8C1_0x00533920 | 0.0% | Pending +SHC_3BB0A8C1_0x00533920 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00533960 | 0.0% | Pending +SHC_3BB0A8C1_0x00533960 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005339A0 | 0.0% | Pending +SHC_3BB0A8C1_0x005339A0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005339F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005339F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00533A10 | 0.0% | Pending +SHC_3BB0A8C1_0x00533A10 | 29.5% | reg alloc -SHC_3BB0A8C1_0x00533B30 | 0.0% | Pending +SHC_3BB0A8C1_0x00533B30 | 70.1% | orig caches x/y in locals -SHC_3BB0A8C1_0x00533C70 | 0.0% | Pending +SHC_3BB0A8C1_0x00533C70 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00533CA0 | 0.0% | Pending +SHC_3BB0A8C1_0x00533CA0 | 90.9% | loop exit shape differs -SHC_3BB0A8C1_0x00533D50 | 0.0% | Pending +SHC_3BB0A8C1_0x00533D50 | 39.4% | reg alloc SHC_3BB0A8C1_0x00533F48 | 0.0% | Pending @@ -50777,11 +50777,11 @@ SHC_3BB0A8C1_0x00533F84 | 0.0% | Pending SHC_3BB0A8C1_0x00533F85 | 0.0% | Pending -SHC_3BB0A8C1_0x00533F90 | 0.0% | Pending +SHC_3BB0A8C1_0x00533F90 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00533FC0 | 0.0% | Pending +SHC_3BB0A8C1_0x00533FC0 | 70.8% | branch shape differs -SHC_3BB0A8C1_0x00534030 | 0.0% | Pending +SHC_3BB0A8C1_0x00534030 | 55.8% | switch shape differs SHC_3BB0A8C1_0x005340CC | 0.0% | Pending @@ -50797,31 +50797,31 @@ SHC_3BB0A8C1_0x005340E0 | 0.0% | Pending SHC_3BB0A8C1_0x005340E4 | 0.0% | Pending -SHC_3BB0A8C1_0x005340F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005340F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00534130 | 0.0% | Pending +SHC_3BB0A8C1_0x00534130 | 79.7% | reg alloc differs -SHC_3BB0A8C1_0x00534240 | 0.0% | Pending +SHC_3BB0A8C1_0x00534240 | 29.0% | orig walks matrix row ptrs -SHC_3BB0A8C1_0x00534380 | 0.0% | Pending +SHC_3BB0A8C1_0x00534380 | 77.6% | orig walks matrix row ptr SHC_3BB0A8C1_0x005343C0 | 0.0% | Pending -SHC_3BB0A8C1_0x005343F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005343F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00534460 | 0.0% | Pending +SHC_3BB0A8C1_0x00534460 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00534490 | 0.0% | Pending +SHC_3BB0A8C1_0x00534490 | 20.4% | spills base+tile, word OR -SHC_3BB0A8C1_0x00534520 | 0.0% | Pending +SHC_3BB0A8C1_0x00534520 | 22.2% | spills base+tile to stack -SHC_3BB0A8C1_0x005345A0 | 0.0% | Pending +SHC_3BB0A8C1_0x005345A0 | 61.7% | orig walks unit ptr SHC_3BB0A8C1_0x005345D0 | 0.0% | Pending -SHC_3BB0A8C1_0x005346D0 | 0.0% | Pending +SHC_3BB0A8C1_0x005346D0 | 32.1% | orig walks unit ptr -SHC_3BB0A8C1_0x005347E0 | 0.0% | Pending +SHC_3BB0A8C1_0x005347E0 | 61.8% | cases 1-8 dead in binary SHC_3BB0A8C1_0x00534880 | 0.0% | Pending @@ -50845,25 +50845,25 @@ SHC_3BB0A8C1_0x00534D08 | 0.0% | Pending SHC_3BB0A8C1_0x00534D0C | 0.0% | Pending -SHC_3BB0A8C1_0x00534D10 | 0.0% | Pending +SHC_3BB0A8C1_0x00534D10 | 89.0% | reg alloc differs SHC_3BB0A8C1_0x00534D80 | 0.0% | Pending -SHC_3BB0A8C1_0x00534EE0 | 0.0% | Pending +SHC_3BB0A8C1_0x00534EE0 | 88.1% | reg alloc differs SHC_3BB0A8C1_0x00534F50 | 0.0% | Pending -SHC_3BB0A8C1_0x005350B0 | 0.0% | Pending +SHC_3BB0A8C1_0x005350B0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535150 | 0.0% | Pending +SHC_3BB0A8C1_0x00535150 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535190 | 0.0% | Pending +SHC_3BB0A8C1_0x00535190 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005351C0 | 0.0% | Pending +SHC_3BB0A8C1_0x005351C0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535200 | 0.0% | Pending +SHC_3BB0A8C1_0x00535200 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535240 | 0.0% | Pending +SHC_3BB0A8C1_0x00535240 | 75.5% | switch case order SHC_3BB0A8C1_0x00535460 | 0.0% | Pending @@ -51065,93 +51065,93 @@ SHC_3BB0A8C1_0x00535513 | 0.0% | Pending SHC_3BB0A8C1_0x00535514 | 0.0% | Pending -SHC_3BB0A8C1_0x00535520 | 0.0% | Pending +SHC_3BB0A8C1_0x00535520 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535550 | 0.0% | Pending +SHC_3BB0A8C1_0x00535550 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535560 | 0.0% | Pending +SHC_3BB0A8C1_0x00535560 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535580 | 0.0% | Pending +SHC_3BB0A8C1_0x00535580 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005355E0 | 0.0% | Pending +SHC_3BB0A8C1_0x005355E0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535680 | 0.0% | Pending +SHC_3BB0A8C1_0x00535680 | 23.7% | guard order differs -SHC_3BB0A8C1_0x00535700 | 0.0% | Pending +SHC_3BB0A8C1_0x00535700 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535730 | 0.0% | Pending +SHC_3BB0A8C1_0x00535730 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005357E0 | 0.0% | Pending +SHC_3BB0A8C1_0x005357E0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535810 | 0.0% | Pending +SHC_3BB0A8C1_0x00535810 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535840 | 0.0% | Pending +SHC_3BB0A8C1_0x00535840 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535870 | 0.0% | Pending +SHC_3BB0A8C1_0x00535870 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005358C0 | 0.0% | Pending +SHC_3BB0A8C1_0x005358C0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535910 | 0.0% | Pending +SHC_3BB0A8C1_0x00535910 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535980 | 0.0% | Pending +SHC_3BB0A8C1_0x00535980 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005359C0 | 0.0% | Pending +SHC_3BB0A8C1_0x005359C0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00535A30 | 0.0% | Pending +SHC_3BB0A8C1_0x00535A30 | 67.7% | call+reg alloc differs -SHC_3BB0A8C1_0x00535B00 | 0.0% | Pending +SHC_3BB0A8C1_0x00535B00 | 61.8% | call+reg alloc differs -SHC_3BB0A8C1_0x00535BC0 | 0.0% | Pending +SHC_3BB0A8C1_0x00535BC0 | 57.9% | Style pass, asm differs -SHC_3BB0A8C1_0x00535DF0 | 0.0% | Pending +SHC_3BB0A8C1_0x00535DF0 | 46.1% | call+reg alloc differs -SHC_3BB0A8C1_0x00535E20 | 0.0% | Pending +SHC_3BB0A8C1_0x00535E20 | 65.1% | reg alloc -SHC_3BB0A8C1_0x00535FD0 | 0.0% | Pending +SHC_3BB0A8C1_0x00535FD0 | 88.9% | orig walks hotkey ptr -SHC_3BB0A8C1_0x005360A0 | 0.0% | Pending +SHC_3BB0A8C1_0x005360A0 | 90.5% | orig unrolls inner loop x5 -SHC_3BB0A8C1_0x00536190 | 0.0% | Pending +SHC_3BB0A8C1_0x00536190 | 72.4% | incr scheduled before call -SHC_3BB0A8C1_0x005361F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005361F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00536260 | 0.0% | Pending +SHC_3BB0A8C1_0x00536260 | 65.0% | type range test shape SHC_3BB0A8C1_0x00536280 | 0.0% | Pending -SHC_3BB0A8C1_0x005362F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005362F0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00536310 | 0.0% | Pending -SHC_3BB0A8C1_0x00536370 | 0.0% | Pending +SHC_3BB0A8C1_0x00536370 | 77.3% | cond order differs -SHC_3BB0A8C1_0x00536400 | 0.0% | Pending +SHC_3BB0A8C1_0x00536400 | 63.0% | loop shape SHC_3BB0A8C1_0x00536440 | 0.0% | Pending -SHC_3BB0A8C1_0x005364C0 | 0.0% | Pending +SHC_3BB0A8C1_0x005364C0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00536530 | 0.0% | Pending +SHC_3BB0A8C1_0x00536530 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005365A0 | 0.0% | Pending +SHC_3BB0A8C1_0x005365A0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00536610 | 0.0% | Pending +SHC_3BB0A8C1_0x00536610 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00536630 | 0.0% | Pending -SHC_3BB0A8C1_0x00536690 | 0.0% | Pending +SHC_3BB0A8C1_0x00536690 | 92.1% | Style pass, asm differs -SHC_3BB0A8C1_0x00536710 | 0.0% | Pending +SHC_3BB0A8C1_0x00536710 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00536780 | 0.0% | Pending +SHC_3BB0A8C1_0x00536780 | 32.8% | loop shape, reg alloc SHC_3BB0A8C1_0x00536860 | 0.0% | Pending SHC_3BB0A8C1_0x005368D0 | 0.0% | Pending -SHC_3BB0A8C1_0x00536970 | 0.0% | Pending +SHC_3BB0A8C1_0x00536970 | 34.1% | local loop var + reg alloc -SHC_3BB0A8C1_0x005369F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005369F0 | 80.0% | switch shape differs SHC_3BB0A8C1_0x00536A34 | 0.0% | Pending @@ -51201,69 +51201,69 @@ SHC_3BB0A8C1_0x00536A50 | 0.0% | Pending SHC_3BB0A8C1_0x00536A51 | 0.0% | Pending -SHC_3BB0A8C1_0x00536A60 | 0.0% | Pending +SHC_3BB0A8C1_0x00536A60 | 87.3% | array init loop differs -SHC_3BB0A8C1_0x00536C70 | 0.0% | Pending +SHC_3BB0A8C1_0x00536C70 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00536C90 | 0.0% | Pending +SHC_3BB0A8C1_0x00536C90 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00536CC0 | 0.0% | Pending +SHC_3BB0A8C1_0x00536CC0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00536CF0 | 0.0% | Pending +SHC_3BB0A8C1_0x00536CF0 | 52.2% | branch order differs SHC_3BB0A8C1_0x00536DA0 | 0.0% | Pending -SHC_3BB0A8C1_0x00536DE0 | 0.0% | Pending +SHC_3BB0A8C1_0x00536DE0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00536E10 | 0.0% | Pending -SHC_3BB0A8C1_0x00536E30 | 0.0% | Pending +SHC_3BB0A8C1_0x00536E30 | 34.5% | reg alloc, spill order -SHC_3BB0A8C1_0x00537070 | 0.0% | Pending +SHC_3BB0A8C1_0x00537070 | 86.4% | enum cast, reg alloc -SHC_3BB0A8C1_0x005370C0 | 0.0% | Pending +SHC_3BB0A8C1_0x005370C0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00537100 | 0.0% | Pending +SHC_3BB0A8C1_0x00537100 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00537130 | 0.0% | Pending +SHC_3BB0A8C1_0x00537130 | 40.0% | param store order differs -SHC_3BB0A8C1_0x00537160 | 0.0% | Pending +SHC_3BB0A8C1_0x00537160 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005371A0 | 0.0% | Pending +SHC_3BB0A8C1_0x005371A0 | 35.7% | param store order differs -SHC_3BB0A8C1_0x005371E0 | 0.0% | Pending +SHC_3BB0A8C1_0x005371E0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005371F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005371F0 | 38.5% | reg alloc, loop shape -SHC_3BB0A8C1_0x00537700 | 0.0% | Pending +SHC_3BB0A8C1_0x00537700 | 21.1% | loop shape, spills -SHC_3BB0A8C1_0x005377F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005377F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00537840 | 0.0% | Pending +SHC_3BB0A8C1_0x00537840 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00537880 | 0.0% | Pending +SHC_3BB0A8C1_0x00537880 | 28.6% | retry loop shape differs SHC_3BB0A8C1_0x005378D0 | 0.0% | Pending SHC_3BB0A8C1_0x005378F0 | 0.0% | Pending -SHC_3BB0A8C1_0x00537A00 | 0.0% | Pending +SHC_3BB0A8C1_0x00537A00 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00537AA0 | 0.0% | Pending +SHC_3BB0A8C1_0x00537AA0 | 40.0% | reg alloc SHC_3BB0A8C1_0x00537B20 | 0.0% | Pending -SHC_3BB0A8C1_0x00537C10 | 0.0% | Pending +SHC_3BB0A8C1_0x00537C10 | 60.4% | reg alloc SHC_3BB0A8C1_0x00537C90 | 0.0% | Pending -SHC_3BB0A8C1_0x00537D60 | 0.0% | Pending +SHC_3BB0A8C1_0x00537D60 | 48.7% | reg alloc -SHC_3BB0A8C1_0x00537E00 | 0.0% | Pending +SHC_3BB0A8C1_0x00537E00 | 35.2% | orig has 2 separate loops -SHC_3BB0A8C1_0x00537EE0 | 0.0% | Pending +SHC_3BB0A8C1_0x00537EE0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00537F60 | 0.0% | Pending +SHC_3BB0A8C1_0x00537F60 | 64.9% | LTCG edx across call SHC_3BB0A8C1_0x005388DC | 0.0% | Pending @@ -59085,7 +59085,7 @@ SHC_3BB0A8C1_0x00539BD5 | 0.0% | Pending SHC_3BB0A8C1_0x00539BD6 | 0.0% | Pending -SHC_3BB0A8C1_0x00539BE0 | 0.0% | Pending +SHC_3BB0A8C1_0x00539BE0 | 78.4% | jump table order differs SHC_3BB0A8C1_0x00539D1C | 0.0% | Pending @@ -59295,7 +59295,7 @@ SHC_3BB0A8C1_0x00539DEB | 0.0% | Pending SHC_3BB0A8C1_0x00539DEC | 0.0% | Pending -SHC_3BB0A8C1_0x00539DF0 | 0.0% | Pending +SHC_3BB0A8C1_0x00539DF0 | 64.7% | hist array via 1st global SHC_3BB0A8C1_0x00539FD0 | 0.0% | Pending @@ -59427,7 +59427,7 @@ SHC_3BB0A8C1_0x0053A018 | 0.0% | Pending SHC_3BB0A8C1_0x0053A020 | 0.0% | Pending -SHC_3BB0A8C1_0x0053A070 | 0.0% | Pending +SHC_3BB0A8C1_0x0053A070 | 64.0% | orig caches state local SHC_3BB0A8C1_0x0053A108 | 0.0% | Pending @@ -59507,7 +59507,7 @@ SHC_3BB0A8C1_0x0053A148 | 0.0% | Pending SHC_3BB0A8C1_0x0053A149 | 0.0% | Pending -SHC_3BB0A8C1_0x0053A150 | 0.0% | Pending +SHC_3BB0A8C1_0x0053A150 | 56.9% | reg alloc, spill order SHC_3BB0A8C1_0x0053A458 | 0.0% | Pending @@ -59613,11 +59613,11 @@ SHC_3BB0A8C1_0x0053A4C0 | 0.0% | Pending SHC_3BB0A8C1_0x0053A4C1 | 0.0% | Pending -SHC_3BB0A8C1_0x0053A4D0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053A4D0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0053A560 | 0.0% | Pending +SHC_3BB0A8C1_0x0053A560 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0053A5B0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053A5B0 | 33.4% | arg push hoist, y cached SHC_3BB0A8C1_0x0053B1F0 | 0.0% | Pending @@ -59649,15 +59649,15 @@ SHC_3BB0A8C1_0x0053B610 | 0.0% | Pending SHC_3BB0A8C1_0x0053B800 | 0.0% | Pending -SHC_3BB0A8C1_0x0053B8B0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053B8B0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0053B8E0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053B8E0 | 86.9% | reg alloc -SHC_3BB0A8C1_0x0053BB10 | 0.0% | Pending +SHC_3BB0A8C1_0x0053BB10 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0053BB70 | 0.0% | Pending +SHC_3BB0A8C1_0x0053BB70 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0053BB90 | 0.0% | Pending +SHC_3BB0A8C1_0x0053BB90 | 60.0% | one read via global inst SHC_3BB0A8C1_0x0053BC20 | 0.0% | Pending @@ -59671,9 +59671,9 @@ SHC_3BB0A8C1_0x0053C590 | 0.0% | Pending SHC_3BB0A8C1_0x0053CAC0 | 0.0% | Pending -SHC_3BB0A8C1_0x0053CAE0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053CAE0 | 48.6% | reg alloc -SHC_3BB0A8C1_0x0053CBD0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053CBD0 | 42.5% | reg alloc, spill order SHC_3BB0A8C1_0x0053CF84 | 0.0% | Pending @@ -59923,7 +59923,7 @@ SHC_3BB0A8C1_0x0053D022 | 0.0% | Pending SHC_3BB0A8C1_0x0053D023 | 0.0% | Pending -SHC_3BB0A8C1_0x0053D030 | 0.0% | Pending +SHC_3BB0A8C1_0x0053D030 | 42.9% | branch shape differs SHC_3BB0A8C1_0x0053D388 | 0.0% | Pending @@ -60013,13 +60013,13 @@ SHC_3BB0A8C1_0x0053D3C1 | 0.0% | Pending SHC_3BB0A8C1_0x0053D3C2 | 0.0% | Pending -SHC_3BB0A8C1_0x0053D3D0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053D3D0 | 36.1% | reg alloc, spill order -SHC_3BB0A8C1_0x0053D850 | 0.0% | Pending +SHC_3BB0A8C1_0x0053D850 | 69.8% | reg alloc differs -SHC_3BB0A8C1_0x0053D900 | 0.0% | Pending +SHC_3BB0A8C1_0x0053D900 | 68.8% | orig caches x/y in locals -SHC_3BB0A8C1_0x0053D9C0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053D9C0 | 25.8% | reg alloc, hoisted loads SHC_3BB0A8C1_0x0053DC9C | 0.0% | Pending @@ -60035,9 +60035,9 @@ SHC_3BB0A8C1_0x0053DCB0 | 0.0% | Pending SHC_3BB0A8C1_0x0053DCB4 | 0.0% | Pending -SHC_3BB0A8C1_0x0053DCC0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053DCC0 | 25.4% | reg alloc -SHC_3BB0A8C1_0x0053DDD0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053DDD0 | 65.5% | orig unrolls scan loop x4 SHC_3BB0A8C1_0x0053E330 | 0.0% | Pending @@ -60083,23 +60083,23 @@ SHC_3BB0A8C1_0x0053E380 | 0.0% | Pending SHC_3BB0A8C1_0x0053E384 | 0.0% | Pending -SHC_3BB0A8C1_0x0053E390 | 0.0% | Pending +SHC_3BB0A8C1_0x0053E390 | 55.2% | version ladder shape -SHC_3BB0A8C1_0x0053E440 | 0.0% | Pending +SHC_3BB0A8C1_0x0053E440 | 46.1% | orig walks unit ptr -SHC_3BB0A8C1_0x0053E6C0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053E6C0 | 83.7% | branch shape differs -SHC_3BB0A8C1_0x0053E790 | 0.0% | Pending +SHC_3BB0A8C1_0x0053E790 | 36.4% | orig uses global instance -SHC_3BB0A8C1_0x0053E820 | 0.0% | Pending +SHC_3BB0A8C1_0x0053E820 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0053E870 | 0.0% | Pending +SHC_3BB0A8C1_0x0053E870 | 85.7% | reg alloc differs -SHC_3BB0A8C1_0x0053E8D0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053E8D0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0053E900 | 0.0% | Pending +SHC_3BB0A8C1_0x0053E900 | 87.0% | reg alloc -SHC_3BB0A8C1_0x0053E9F0 | 0.0% | Pending +SHC_3BB0A8C1_0x0053E9F0 | 56.8% | orig caches x/y in locals SHC_3BB0A8C1_0x0053EAA0 | 0.0% | Pending @@ -60243,7 +60243,7 @@ SHC_3BB0A8C1_0x0053F930 | 0.0% | Pending SHC_3BB0A8C1_0x0053F940 | 0.0% | Pending -SHC_3BB0A8C1_0x00540040 | 0.0% | Pending +SHC_3BB0A8C1_0x00540040 | 49.8% | orig caches locals SHC_3BB0A8C1_0x0054019C | 0.0% | Pending @@ -61405,11 +61405,11 @@ SHC_3BB0A8C1_0x00549B24 | 0.0% | Pending SHC_3BB0A8C1_0x00549B30 | 0.0% | Pending -SHC_3BB0A8C1_0x00549C70 | 0.0% | Pending +SHC_3BB0A8C1_0x00549C70 | 29.2% | mask reg alloc, frame ptr -SHC_3BB0A8C1_0x0054A770 | 0.0% | Pending +SHC_3BB0A8C1_0x0054A770 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0054A7B0 | 0.0% | Pending +SHC_3BB0A8C1_0x0054A7B0 | 34.3% | reg alloc, spill order SHC_3BB0A8C1_0x0054AA40 | 0.0% | Pending @@ -61833,7 +61833,7 @@ SHC_3BB0A8C1_0x0054B0CB | 0.0% | Pending SHC_3BB0A8C1_0x0054B0CC | 0.0% | Pending -SHC_3BB0A8C1_0x0054B0D0 | 0.0% | Pending +SHC_3BB0A8C1_0x0054B0D0 | 39.3% | 2-reg addressing, reg alloc SHC_3BB0A8C1_0x0054BE04 | 0.0% | Pending @@ -62501,13 +62501,13 @@ SHC_3BB0A8C1_0x0054BFB2 | 0.0% | Pending SHC_3BB0A8C1_0x0054BFB3 | 0.0% | Pending -SHC_3BB0A8C1_0x0054BFC0 | 0.0% | Pending +SHC_3BB0A8C1_0x0054BFC0 | 46.1% | branch shape differs -SHC_3BB0A8C1_0x0054C1C0 | 0.0% | Pending +SHC_3BB0A8C1_0x0054C1C0 | 32.5% | reg alloc -SHC_3BB0A8C1_0x0054C4F0 | 0.0% | Pending +SHC_3BB0A8C1_0x0054C4F0 | 14.0% | orig walks matrix row ptr -SHC_3BB0A8C1_0x0054C610 | 0.0% | Pending +SHC_3BB0A8C1_0x0054C610 | 72.7% | call+reg alloc differs SHC_3BB0A8C1_0x0054C710 | 0.0% | Pending @@ -66971,7 +66971,7 @@ SHC_3BB0A8C1_0x00578370 | 0.0% | Pending SHC_3BB0A8C1_0x00578B40 | 0.0% | Pending -SHC_3BB0A8C1_0x00578C40 | 0.0% | Pending +SHC_3BB0A8C1_0x00578C40 | 59.7% | branch shape differs SHC_3BB0A8C1_0x00578D90 | 0.0% | Pending @@ -66991,7 +66991,7 @@ SHC_3BB0A8C1_0x005792F8 | 0.0% | Pending SHC_3BB0A8C1_0x005792FC | 0.0% | Pending -SHC_3BB0A8C1_0x00579300 | 0.0% | Pending +SHC_3BB0A8C1_0x00579300 | 35.2% | reg alloc, dup tails SHC_3BB0A8C1_0x00579380 | 0.0% | Pending diff --git a/tools/reimplementation-helper/batch/README.md b/tools/reimplementation-helper/batch/README.md index 0522aaded..328f2e01f 100644 --- a/tools/reimplementation-helper/batch/README.md +++ b/tools/reimplementation-helper/batch/README.md @@ -12,7 +12,7 @@ rewrite sources, because the Visual Studio bundled one is too old for `.clang-fo | Script | Purpose | |---|---| -| `build_quiet.py [--keep-going]` | `build.bat RelWithDebInfo OpenSHC.dll`, prints only errors and `BUILD_OK`/`BUILD_FAIL` (build.bat exits 0 even on errors). | +| `build_quiet.py [--keep-going]` | `build.bat RelWithDebInfo OpenSHC.dll`, prints only errors and `BUILD_OK`/`BUILD_FAIL` (build.bat exits 0 even on errors). Retries once on a PDB server error, see the note below. | | `syntax_check.py [substr...]` | `cl /Zs` every (matching) list file serially; finds all compile errors in one pass without linking. | | `reccmp_report.py [--run] pct\|save\|cmp\|diff` | Match % and *normalized* % (call/tail-jump targets and resolver addresses ignored) per function, snapshots, before/after comparison, compact asm diffs. | | `orig_asm.py NAME [--both\|--stats]` | The **original** instruction stream of one function (not the interleaved diff), in address order; `--stats` reports the tells that decide how to reimplement it: `mov reg, 0` (handwritten asm), frame pointer (built /Od), frame size, jump tables. | @@ -99,3 +99,10 @@ bugs that Ghidra had decompiled wrongly. - A file whose `// FUNCTION:` address has no reccmp entry is reported as `--` / skipped. Check the address against `src/precomp/addresses-SHC-3BB0A8C1.hpp`. - Sources are always written as UTF-8 with LF line endings. +- Every script that runs `cl.exe` sets this worktree's own `_MSPDBSRV_ENDPOINT_` + (`common.build_env`), the same name `build.bat` derives. `mspdbsrv.exe` is a per-user + singleton keyed on that endpoint and each worktree carries its own toolchain copy, so a + shared endpoint makes `cl.exe` talk to the wrong server and fail with + `fatal error C1090: PDB API call failed`. `build_quiet.py` retries once after stopping + this worktree's `mspdbsrv.exe` (`common.kill_pdb_server`, never other worktrees'), which + clears a server that was already wedged before the build started. diff --git a/tools/reimplementation-helper/batch/build_quiet.py b/tools/reimplementation-helper/batch/build_quiet.py index 4395f90e3..5647d1ec3 100644 --- a/tools/reimplementation-helper/batch/build_quiet.py +++ b/tools/reimplementation-helper/batch/build_quiet.py @@ -5,13 +5,27 @@ Prints BUILD_OK or BUILD_FAIL as the last line. build.bat exits 0 even on compile errors, so the log is scanned instead of trusting the exit code. --keep-going reruns the build with nmake /K to collect errors from more files. + +The build runs with this worktree's own _MSPDBSRV_ENDPOINT_ (see common.build_env), which is what +build.bat does too; --keep-going bypasses build.bat and would otherwise inherit whatever endpoint +happens to be set. A build that dies with C1090/C1033 gets two retries, because that error has two +different causes: + + 1. a wedged PDB server, which survives the kill build.bat does up front -> stop this worktree's + mspdbsrv.exe and build again; + 2. a wedged *endpoint*, which outlives every mspdbsrv.exe using it -> build again on a fresh + endpoint name, since retrying into the same name fails forever. + +The second cost six consecutive builds once, across a regenerated PCH and PDBs, while the same tree +built first try under a different endpoint name. """ import argparse import re import subprocess +import sys -from common import TMP +from common import PDB_ERROR_RE, TMP, build_env, fresh_pdb_endpoint, kill_pdb_server parser = argparse.ArgumentParser() parser.add_argument("--keep-going", action="store_true") @@ -19,14 +33,33 @@ args = parser.parse_args() log = TMP / "build.log" -with open(log, "w") as out: - subprocess.run(["cmd", "/c", r".\build.bat RelWithDebInfo OpenSHC.dll"], stdout=out, stderr=subprocess.STDOUT) -if args.keep_going: + + +def run_build(endpoint=None): with open(log, "w") as out: - subprocess.run(["cmd", "/c", r".\cmakew --build --preset RelWithDebInfo --target OpenSHC.dll -- /K"], - stdout=out, stderr=subprocess.STDOUT) + subprocess.run(["cmd", "/c", r".\build.bat RelWithDebInfo OpenSHC.dll"], + stdout=out, stderr=subprocess.STDOUT, env=build_env(endpoint)) + if args.keep_going: + with open(log, "w") as out: + subprocess.run(["cmd", "/c", r".\cmakew --build --preset RelWithDebInfo --target OpenSHC.dll -- /K"], + stdout=out, stderr=subprocess.STDOUT, env=build_env(endpoint)) + return log.read_text(errors="replace") + + +text = run_build() +if PDB_ERROR_RE.search(text): + print("note: PDB server error, stopping this worktree's mspdbsrv.exe and retrying", file=sys.stderr) + kill_pdb_server() + text = run_build() +if PDB_ERROR_RE.search(text): + # The endpoint itself can be wedged, in which case it outlives every mspdbsrv.exe using it and + # retrying into the same name fails forever. Move to a fresh one. + endpoint = fresh_pdb_endpoint() + print("note: PDB endpoint still failing, retrying on a fresh endpoint %s" % endpoint, + file=sys.stderr) + kill_pdb_server() + text = run_build(endpoint) -text = log.read_text(errors="replace") errors = [line for line in text.splitlines() if re.search(r" error |warning C4700|warning C4715", line) and "U1077" not in line] for line in errors[:args.max]: diff --git a/tools/reimplementation-helper/batch/common.py b/tools/reimplementation-helper/batch/common.py index e5d5ca81a..3e15e3d9d 100644 --- a/tools/reimplementation-helper/batch/common.py +++ b/tools/reimplementation-helper/batch/common.py @@ -27,6 +27,54 @@ DIFF_JSON = Path("reccmp/dll/diff.json") FUNCTION_RE = re.compile(r"//\s*FUNCTION:\s*STRONGHOLDCRUSADER\s+(0x[0-9A-Fa-f]+)") +# ---------------------------------------------------------------- pdb server + +# mspdbsrv.exe is a per-user singleton keyed on _MSPDBSRV_ENDPOINT_, and every worktree carries its +# own copy of the toolchain. Sharing one endpoint makes cl.exe talk to whichever copy started first +# and fail with "fatal error C1090: PDB API call failed, error code '23'" (or C1033). build.bat +# derives this same name, so setting it here keeps the two in step and also covers the scripts that +# drive cl.exe or cmake directly instead of going through build.bat. +PDB_ENDPOINT = "openshc_" + ROOT.name +PDB_ERROR_RE = re.compile(r"fatal error C10(90|33)") + + +def fresh_pdb_endpoint(): + """A previously unused endpoint name for this worktree. + + An endpoint can wedge in a way that outlives every mspdbsrv.exe using it: the name stays + unusable, and `cl.exe` keeps failing with C1090 no matter how often the server is killed and + restarted. Six consecutive builds failed that way once, across a fresh PCH and PDBs, while the + same tree built first try under a different name. So when killing the server does not help, + move to a new name rather than retrying into the same one. + """ + return "%s_%d" % (PDB_ENDPOINT, os.getpid()) + + +def build_env(endpoint=None): + """Environment for anything that runs cl.exe, with this worktree's PDB endpoint. + + An endpoint already set in the environment wins, so a caller can pin one for a whole session. + """ + env = dict(os.environ) + if endpoint: + env["_MSPDBSRV_ENDPOINT_"] = endpoint + else: + env.setdefault("_MSPDBSRV_ENDPOINT_", PDB_ENDPOINT) + return env + + +def kill_pdb_server(): + """Stop this worktree's mspdbsrv.exe only. + + Killing every instance by image name takes down the PDB server of any other worktree that is + building at the same time and fails their build with the same C1090. + """ + subprocess.run(["powershell", "-NoProfile", "-Command", + "Get-Process mspdbsrv -ErrorAction SilentlyContinue | " + "Where-Object { $_.Path -like '%s*' } | " + "Stop-Process -Force -ErrorAction SilentlyContinue" + % str(ROOT).replace("'", "''")], + capture_output=True) def list_files(existing_only=True): diff --git a/tools/reimplementation-helper/batch/syntax_check.py b/tools/reimplementation-helper/batch/syntax_check.py index 5fde77df5..4f7212a9f 100644 --- a/tools/reimplementation-helper/batch/syntax_check.py +++ b/tools/reimplementation-helper/batch/syntax_check.py @@ -12,7 +12,7 @@ import subprocess import sys -from common import BUILD_DIR, ROOT, TMP, list_files +from common import BUILD_DIR, ROOT, TMP, build_env, list_files commands = json.loads((BUILD_DIR / "compile_commands.json").read_text()) template = next(c["command"] for c in commands if "OpenSHC.dll.dir" in c["command"]) @@ -30,7 +30,8 @@ bat = TMP / "syntax_check.bat" bat.write_text("\n".join(lines) + "\n") -result = subprocess.run(["cmd", "/c", str(bat.resolve())], capture_output=True, text=True) +result = subprocess.run(["cmd", "/c", str(bat.resolve())], capture_output=True, text=True, + env=build_env()) errors = [l for l in (result.stdout + result.stderr).splitlines() if " error " in l or "fatal" in l] for line in errors: print(re.sub(r"^.*src.OpenSHC.", "", line)[:260]) diff --git a/tools/reimplementation-helper/batch/try_styles.py b/tools/reimplementation-helper/batch/try_styles.py index 5c5036458..5bc2d5a82 100644 --- a/tools/reimplementation-helper/batch/try_styles.py +++ b/tools/reimplementation-helper/batch/try_styles.py @@ -107,6 +107,12 @@ def main(): (vdir / "results.json").write_text( json.dumps({s: p for p, s in results if p is not None}, indent=1), encoding="utf-8") + # The trials left the DLL and reccmp/dll/diff.json built from the narrowed list, so every + # batch tool would go on reporting the last variant's single-function result. Restoring + # the list is not enough -- rebuild so the tree, the DLL and the diff agree again. + print("\nrebuilding with the full list so later reports are valid...") + print(run(BATCH / "build_quiet.py").strip().splitlines()[-1]) + if __name__ == "__main__": main()