Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
78b0b58
Core
CrimRecya Apr 1, 2025
99cf793
Merge remote-tracking branch 'upstream/develop' into develop-Amphibio…
CrimRecya Apr 1, 2025
2c6b5d5
Fix and update
CrimRecya Apr 1, 2025
f5f9ad3
Fix doc
CrimRecya Apr 1, 2025
6fe130a
More vanilla fix
CrimRecya Apr 2, 2025
a9de4d8
Merge remote-tracking branch 'upstream/develop' into develop-Amphibio…
CrimRecya Apr 2, 2025
ee9bded
Fix Drive/Ship loco unload stuck
CrimRecya Apr 2, 2025
d094fda
Fix teleport move on water
CrimRecya Apr 3, 2025
8d69257
Merge remote-tracking branch 'upstream/develop' into develop-Amphibio…
CrimRecya Apr 3, 2025
0aeee11
Fix typo
CrimRecya Apr 3, 2025
911ccb6
No voice and scatter when fail to unload
CrimRecya Apr 3, 2025
4656ad2
Fix invisible barrier
CrimRecya Apr 7, 2025
2967895
Merge remote-tracking branch 'upstream/develop' into develop-Amphibio…
CrimRecya Apr 7, 2025
d6e0986
Update doc
CrimRecya Apr 7, 2025
7ea36cd
Core
CrimRecya Apr 7, 2025
732876b
Fix doc
CrimRecya Apr 7, 2025
84355ae
Merge branch 'develop-EnterFix' into develop-AmphibiousEnter
CrimRecya Apr 7, 2025
23276b9
先修复上车问题
CrimRecya Apr 8, 2025
17063e1
Merge remote-tracking branch 'upstream/develop' into develop-EnterFix
CrimRecya Apr 8, 2025
31369dd
Merge branch 'develop-EnterFix' into develop-AmphibiousEnter
CrimRecya Apr 8, 2025
e0acb7b
Fix a typo
CrimRecya Apr 8, 2025
e037f1c
Merge branch 'develop-EnterFix' into develop-AmphibiousEnter
CrimRecya Apr 8, 2025
24af27a
Revert temporarily useless part
CrimRecya Apr 8, 2025
d189d18
Not allow to enter on bridge
CrimRecya Apr 8, 2025
a671275
Merge remote-tracking branch 'upstream/develop' into develop-EnterFix
CrimRecya Apr 8, 2025
806fab2
Merge branch 'develop-EnterFix' into develop-AmphibiousEnter
CrimRecya Apr 8, 2025
cae7740
New fix
CrimRecya Apr 9, 2025
4fe0054
Merge branch 'develop-EnterFix' into develop-AmphibiousEnter
CrimRecya Apr 9, 2025
6f38cef
Add missing
CrimRecya Apr 9, 2025
77e6e3c
Prevent overlap
CrimRecya Apr 9, 2025
daedaae
Merge remote-tracking branch 'upstream/develop' into develop-EnterFix
CrimRecya Apr 9, 2025
8087aeb
Merge branch 'develop-EnterFix' into develop-AmphibiousEnter
CrimRecya Apr 9, 2025
55b84cd
Fix merge
CrimRecya Apr 9, 2025
733f284
Fix the unload overlap
CrimRecya Apr 9, 2025
2c43838
Merge remote-tracking branch 'upstream/develop' into develop-EnterFix
CrimRecya Apr 9, 2025
dad23dc
Merge branch 'develop-EnterFix' into develop-AmphibiousEnter
CrimRecya Apr 9, 2025
3e38992
Doc
CrimRecya Apr 9, 2025
5439207
Merge remote-tracking branch 'upstream/develop' into develop-EnterFix
CrimRecya Apr 9, 2025
d93680a
Fix passengers & tankbunker
CrimRecya Apr 10, 2025
e008a66
Merge remote-tracking branch 'upstream/develop' into develop-Amphibio…
CrimRecya Apr 10, 2025
fe4f55b
Merge remote-tracking branch 'upstream/develop' into develop-EnterFix
CrimRecya Apr 10, 2025
72f6cce
Merge branch 'develop-EnterFix' into develop-AmphibiousEnter
CrimRecya Apr 10, 2025
429df73
Merge remote-tracking branch 'upstream/develop' into develop-Amphibio…
CrimRecya Apr 11, 2025
3959a2d
Remove dulplicated
CrimRecya Apr 11, 2025
aa2f51a
Merge remote-tracking branch 'upstream/develop' into develop-Amphibio…
CrimRecya Apr 22, 2025
562e225
Fix `AmphibiousEnter`s interaction issue with `NoQueueUpToEnter`
CrimRecya Apr 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ This page lists all the individual contributions to the project by their author.
- Fix an issue that game crashes (EIP:7FB178) when infantry are about to enter an occupiable building that has been removed and is not real dead
- Fix an issue that game crashes when spawnee has been removed and is not real dead
- Aggressive attack move mission
- Amphibious access vehicle
- **Ollerus**:
- Build limit group enhancement
- Customizable rocker amplitude
Expand Down
15 changes: 15 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -1753,6 +1753,21 @@ AttackMove.Aggressive= ; boolean, default to [General] -> AttackMove.Agg
AttackMove.UpdateTarget= ; boolean, default to [General] -> AttackMove.UpdateTarget
```

### Amphibious access vehicle

- Now you can let amphibious infantry or vehicle passengers enter or leave amphibious transport vehicles on water surface. Defaults to `[General]->AmphibiousEnter` or `[General]->AmphibiousUnload`.

In `rulesmd.ini`:
```ini
[General]
AmphibiousEnter=false ; boolean
AmphibiousUnload=false ; boolean

[SOMEVEHICLE] ; VehicleType
AmphibiousEnter= ; boolean
AmphibiousUnload= ; boolean
```

## Terrain

### Destroy animation & sound
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ New:
- Select box logic (by NetsuNegi)
- Customize airstrike targets (by NetsuNegi)
- Aggressive attack move mission (by CrimRecya)
- Amphibious access vehicle (by CrimRecya)

Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
Expand Down
4 changes: 4 additions & 0 deletions src/Ext/Rules/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI)
this->HeightShadowScaling_MinScale.Read(exINI, GameStrings::AudioVisual, "HeightShadowScaling.MinScale");

this->ExtendedAircraftMissions.Read(exINI, GameStrings::General, "ExtendedAircraftMissions");
this->AmphibiousEnter.Read(exINI, GameStrings::General, "AmphibiousEnter");
this->AmphibiousUnload.Read(exINI, GameStrings::General, "AmphibiousUnload");
this->NoQueueUpToEnter.Read(exINI, GameStrings::General, "NoQueueUpToEnter");
this->NoQueueUpToUnload.Read(exINI, GameStrings::General, "NoQueueUpToUnload");

Expand Down Expand Up @@ -384,6 +386,8 @@ void RulesExt::ExtData::Serialize(T& Stm)
.Process(this->HeightShadowScaling)
.Process(this->HeightShadowScaling_MinScale)
.Process(this->ExtendedAircraftMissions)
.Process(this->AmphibiousEnter)
.Process(this->AmphibiousUnload)
.Process(this->NoQueueUpToEnter)
.Process(this->NoQueueUpToUnload)
.Process(this->BuildingProductionQueue)
Expand Down
4 changes: 4 additions & 0 deletions src/Ext/Rules/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ class RulesExt
double AirShadowBaseScale_log;

Valueable<bool> ExtendedAircraftMissions;
Valueable<bool> AmphibiousEnter;
Valueable<bool> AmphibiousUnload;
Valueable<bool> NoQueueUpToEnter;
Valueable<bool> NoQueueUpToUnload;

Expand Down Expand Up @@ -275,6 +277,8 @@ class RulesExt
, AirShadowBaseScale_log { 0.693376137 }

, ExtendedAircraftMissions { false }
, AmphibiousEnter { false }
, AmphibiousUnload { false }
, NoQueueUpToEnter { false }
, NoQueueUpToUnload { false }

Expand Down
189 changes: 183 additions & 6 deletions src/Ext/Techno/Hooks.Transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ static inline bool CanEnterNow(UnitClass* pTransport, FootClass* pPassenger)
return false;

const auto pTransportType = pTransport->Type;

// Added to fit with AmphibiousEnter
if (pTransport->GetCell()->LandType == LandType::Water && !TechnoTypeExt::ExtMap.Find(pTransportType)->AmphibiousEnter.Get(RulesExt::Global()->AmphibiousEnter))
return false;

const auto bySize = TechnoTypeExt::ExtMap.Find(pTransportType)->Passengers_BySize;
const auto passengerSize = bySize ? Game::F2I(pPassenger->GetTechnoType()->Size) : 1;

Expand Down Expand Up @@ -359,6 +364,15 @@ DEFINE_HOOK(0x4DA8A0, FootClass_Update_FastEnter, 0x6)
return 0;
}

// Rewrite from 0x4835D5/0x74004B, replace check pThis->GetCell()->LandType != LandType::Water
static inline bool CanUnloadNow(UnitClass* pTransport, FootClass* pPassenger)
{
if (TechnoTypeExt::ExtMap.Find(pTransport->Type)->AmphibiousUnload.Get(RulesExt::Global()->AmphibiousUnload))
return GroundType::Array[static_cast<int>(pTransport->GetCell()->LandType)].Cost[static_cast<int>(pPassenger->GetTechnoType()->SpeedType)] != 0.0;

return pTransport->GetCell()->LandType != LandType::Water;
}

namespace TransportUnloadTemp
{
bool ShouldPlaySound = false;
Expand Down Expand Up @@ -404,21 +418,29 @@ DEFINE_HOOK(0x73DC9C, UnitClass_Mission_Unload_NoQueueUpToUnloadBreak, 0xA)
// Within a single frame, cycle to get off the car
DEFINE_HOOK(0x73DC1E, UnitClass_Mission_Unload_NoQueueUpToUnloadLoop, 0xA)
{
enum { UnloadLoop = 0x73D8CB, UnloadReturn = 0x73E289 };
enum { UnloadLoop = 0x73D8CB, UnloadReturn = 0x73E289, NoUnloadReturn = 0x73D8AA };

GET(UnitClass* const, pThis, ESI);

const auto pType = pThis->Type;
const auto pPassenger = pThis->Passengers.GetFirstPassenger();

if (TechnoTypeExt::ExtMap.Find(pType)->NoQueueUpToUnload.Get(RulesExt::Global()->NoQueueUpToUnload))
{
if (!pThis->Passengers.GetFirstPassenger() || pThis->Passengers.NumPassengers <= pThis->NonPassengerCount)
if (!pPassenger || pThis->Passengers.NumPassengers <= pThis->NonPassengerCount)
{
// If unloading is required within one frame, the sound will only be played when the last passenger leaves
VoxClass::PlayAtPos(pType->LeaveTransportSound, &pThis->Location);
TransportUnloadTemp::ShouldPlaySound = false;
return UnloadReturn;
}
else if (!CanUnloadNow(pThis, pPassenger))
{
VoxClass::PlayAtPos(pType->LeaveTransportSound, &pThis->Location);
TransportUnloadTemp::ShouldPlaySound = false;
pThis->MissionStatus = 0; // Retry
return NoUnloadReturn;
}

TransportUnloadTemp::ShouldPlaySound = true;
R->EBX(0); // Reset
Expand All @@ -428,7 +450,11 @@ DEFINE_HOOK(0x73DC1E, UnitClass_Mission_Unload_NoQueueUpToUnloadLoop, 0xA)
// PlayAtPos has already handled the situation where Sound is less than 0 internally, so unnecessary checks will be skipped
VoxClass::PlayAtPos(pType->LeaveTransportSound, &pThis->Location);

return UnloadReturn;
if (!pPassenger || CanUnloadNow(pThis, pPassenger))
return UnloadReturn;

pThis->MissionStatus = 0; // Retry
return NoUnloadReturn;
}

#pragma endregion
Expand Down Expand Up @@ -505,12 +531,60 @@ DEFINE_HOOK(0x7196BB, TeleportLocomotionClass_Process_MarkDown, 0xA)

#pragma region AmphibiousEnterAndUnload

// Enter building
DEFINE_JUMP(LJMP, 0x43C38D, 0x43C3FF); // Skip amphibious and naval check if no Ares
// Related fix
DEFINE_HOOK(0x4B08EF, DriveLocomotionClass_Process_CheckUnload, 0x5)
{
enum { SkipGameCode = 0x4B078C, ContinueProcess = 0x4B0903 };

GET(ILocomotion* const, iloco, ESI);

__assume(iloco != nullptr);

const auto pFoot = static_cast<LocomotionClass*>(iloco)->LinkedTo;

if (pFoot->GetCurrentMission() != Mission::Unload)
return ContinueProcess;

return (pFoot->GetTechnoType()->Passengers > 0 && pFoot->Passengers.GetFirstPassenger()) ? ContinueProcess : SkipGameCode;
}

DEFINE_HOOK(0x69FFB6, ShipLocomotionClass_Process_CheckUnload, 0x5)
{
enum { SkipGameCode = 0x69FE39, ContinueProcess = 0x69FFCA };

GET(ILocomotion* const, iloco, ESI);

__assume(iloco != nullptr);

// TODO Enter unit
const auto pFoot = static_cast<LocomotionClass*>(iloco)->LinkedTo;

if (pFoot->GetCurrentMission() != Mission::Unload)
return ContinueProcess;

return (pFoot->GetTechnoType()->Passengers > 0 && pFoot->Passengers.GetFirstPassenger()) ? ContinueProcess : SkipGameCode;
}

// Rewrite from 0x718505
DEFINE_HOOK_AGAIN(0x7190B0, TeleportLocomotionClass_MovingTo_ReplaceMovementZone, 0x6)
DEFINE_HOOK(0x718F1E, TeleportLocomotionClass_MovingTo_ReplaceMovementZone, 0x6)
{
GET(TechnoTypeClass* const, pType, EAX);

auto movementZone = pType->MovementZone;

if (movementZone == MovementZone::Fly || movementZone == MovementZone::Destroyer)
movementZone = MovementZone::Normal;
else if (movementZone == MovementZone::AmphibiousDestroyer)
movementZone = MovementZone::Amphibious;

R->EBP(movementZone);
return R->Origin() + 0x6;
}

// Enter building
DEFINE_JUMP(LJMP, 0x43C38D, 0x43C3FF); // Skip amphibious and naval check if no Ares

// Enter unit
DEFINE_HOOK(0x73796B, UnitClass_ReceiveCommand_AmphibiousEnter, 0x7)
{
enum { ContinueCheck = 0x737990, MoveToPassenger = 0x737974 };
Expand All @@ -520,9 +594,112 @@ DEFINE_HOOK(0x73796B, UnitClass_ReceiveCommand_AmphibiousEnter, 0x7)
if (pThis->OnBridge)
return MoveToPassenger;

if (TechnoTypeExt::ExtMap.Find(pThis->Type)->AmphibiousEnter.Get(RulesExt::Global()->AmphibiousEnter))
return ContinueCheck;

GET(CellClass* const, pCell, EBP);

return (pCell->LandType != LandType::Water) ? ContinueCheck : MoveToPassenger;
}

// Unit unload

DEFINE_HOOK(0x7400B5, UnitClass_MouseOverObject_AmphibiousUnload, 0x7)
{
enum { ContinueCheck = 0x7400C6, CannotUnload = 0x7400BE };

GET(CellClass* const, pCell, EBX);

if (pCell->LandType == LandType::Water) // I don't know why WW made a reverse judgment here? Because of the coast/beach?
return ContinueCheck;

GET(UnitClass* const, pThis, ESI);

return TechnoTypeExt::ExtMap.Find(pThis->Type)->AmphibiousUnload.Get(RulesExt::Global()->AmphibiousUnload) ? ContinueCheck : CannotUnload;
}

DEFINE_HOOK(0x70107A, TechnoClass_CanDeploySlashUnload_AmphibiousUnload, 0x7)
{
enum { ContinueCheck = 0x701087, CannotUnload = 0x700DCE };

GET(CellClass* const, pCell, EBP);

if (pCell->LandType != LandType::Water)
return ContinueCheck;

GET(UnitClass* const, pThis, ESI);

return TechnoTypeExt::ExtMap.Find(pThis->Type)->AmphibiousUnload.Get(RulesExt::Global()->AmphibiousUnload) ? ContinueCheck : CannotUnload;
}

DEFINE_HOOK(0x73D769, UnitClass_Mission_Unload_AmphibiousUnload, 0x7)
{
enum { MoveToLand = 0x73D772, UnloadCheck = 0x73D7E4 };

GET(UnitClass* const, pThis, ESI);

const auto pPassenger = pThis->Passengers.GetFirstPassenger();

return (!pPassenger || CanUnloadNow(pThis, pPassenger)) ? UnloadCheck : MoveToLand;
}

DEFINE_HOOK(0x73D7AB, UnitClass_Mission_Unload_FindUnloadPosition, 0x5)
{
GET(UnitClass* const, pThis, ESI);

if (TechnoTypeExt::ExtMap.Find(pThis->Type)->AmphibiousUnload.Get(RulesExt::Global()->AmphibiousUnload))
{
if (const auto pPassenger = pThis->Passengers.GetFirstPassenger())
{
REF_STACK(SpeedType, speedType, STACK_OFFSET(0xBC, -0xB4));
REF_STACK(MovementZone, movementZone, STACK_OFFSET(0xBC, -0xAC));

const auto pType = pPassenger->GetTechnoType();
speedType = pType->SpeedType; // Replace hard code SpeedType::Wheel
movementZone = pType->MovementZone; // Replace hard code MovementZone::Normal
}
}

return 0;
}

DEFINE_HOOK(0x73D7B7, UnitClass_Mission_Unload_CheckInvalidCell, 0x6)
{
enum { CannotUnload = 0x73D87F };

GET(const CellStruct, cell, EAX);

return cell != CellStruct::Empty ? 0 : CannotUnload;
}

DEFINE_HOOK(0x740C9C, UnitClass_GetUnloadDirection_CheckUnloadPosition, 0x7)
{
GET(UnitClass* const, pThis, EDI);

if (TechnoTypeExt::ExtMap.Find(pThis->Type)->AmphibiousUnload.Get(RulesExt::Global()->AmphibiousUnload))
{
if (const auto pPassenger = pThis->Passengers.GetFirstPassenger())
{
GET(const int, speedType, EDX);
R->EDX(speedType + static_cast<int>(pPassenger->GetTechnoType()->SpeedType)); // Replace hard code SpeedType::Foot
}
}

return 0;
}

DEFINE_HOOK(0x73DAD8, UnitClass_Mission_Unload_PassengerLeavePosition, 0x5)
{
GET(UnitClass* const, pThis, ESI);

if (TechnoTypeExt::ExtMap.Find(pThis->Type)->AmphibiousUnload.Get(RulesExt::Global()->AmphibiousUnload))
{
GET(FootClass* const, pPassenger, EDI);
REF_STACK(MovementZone, movementZone, STACK_OFFSET(0xBC, -0xAC));
movementZone = pPassenger->GetTechnoType()->MovementZone; // Replace hard code MovementZone::Normal
}

return 0;
}

#pragma endregion
4 changes: 4 additions & 0 deletions src/Ext/TechnoType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,8 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->BuildLimitGroup_ExtraLimit_MaxCount.Read(exINI, pSection, "BuildLimitGroup.ExtraLimit.MaxCount");
this->BuildLimitGroup_ExtraLimit_MaxNum.Read(exINI, pSection, "BuildLimitGroup.ExtraLimit.MaxNum");

this->AmphibiousEnter.Read(exINI, pSection, "AmphibiousEnter");
this->AmphibiousUnload.Read(exINI, pSection, "AmphibiousUnload");
this->NoQueueUpToEnter.Read(exINI, pSection, "NoQueueUpToEnter");
this->NoQueueUpToUnload.Read(exINI, pSection, "NoQueueUpToUnload");

Expand Down Expand Up @@ -947,6 +949,8 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
.Process(this->BuildLimitGroup_ExtraLimit_MaxCount)
.Process(this->BuildLimitGroup_ExtraLimit_MaxNum)

.Process(this->AmphibiousEnter)
.Process(this->AmphibiousUnload)
.Process(this->NoQueueUpToEnter)
.Process(this->NoQueueUpToUnload)
.Process(this->Passengers_BySize)
Expand Down
4 changes: 4 additions & 0 deletions src/Ext/TechnoType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ class TechnoTypeExt
ValueableVector<int> BuildLimitGroup_ExtraLimit_MaxCount;
Valueable<int> BuildLimitGroup_ExtraLimit_MaxNum;

Nullable<bool> AmphibiousEnter;
Nullable<bool> AmphibiousUnload;
Nullable<bool> NoQueueUpToEnter;
Nullable<bool> NoQueueUpToUnload;
Valueable<bool> Passengers_BySize;
Expand Down Expand Up @@ -572,6 +574,8 @@ class TechnoTypeExt
, BuildLimitGroup_ExtraLimit_MaxCount {}
, BuildLimitGroup_ExtraLimit_MaxNum { 0 }

, AmphibiousEnter {}
, AmphibiousUnload {}
, NoQueueUpToEnter {}
, NoQueueUpToUnload {}
, Passengers_BySize { true }
Expand Down