2
#include "../BuildingType/Body.h"
3
#include "../Techno/Body.h"
4
#include "../../Misc/Network.h"
6
#include <SpecificStructures.h>
7
#include <ScenarioClass.h>
8
#include <InfantryClass.h>
13
/* #218 - specific occupiers // comes in 0.2
14
#665 - raidable buildings */
15
DEFINE_HOOK(457D58, BuildingClass_CanBeOccupied_SpecificOccupiers, 6)
17
GET(BuildingClass *, pThis, ESI);
18
GET(InfantryClass *, pInf, EDI);
19
BuildingTypeExt::ExtData* pBuildTypeExt = BuildingTypeExt::ExtMap.Find(pThis->Type);
20
bool can_occupy = false;
22
if(pInf->Type->Occupier) {
23
bool isFull = (pThis->GetOccupantCount() == pThis->Type->MaxNumberOccupants);
24
bool isEmpty = (pThis->GetOccupantCount() == 0); // yes, yes, !pThis->GetOccupantCount() - leave it this way for semantics :P
25
bool isIneligible = (pThis->IsRedHP() || pInf->IsMindControlled());
27
if(!isFull && !isIneligible) {
28
if(pThis->Owner != pInf->Owner) {
29
/* The building switches owners after the first occupant enters,
30
so this check should not interfere with the player who captured it,
31
only prevent others from entering it while it's occupied. (Bug #699) */
32
can_occupy = (pThis->Owner->IsNeutral() || (pBuildTypeExt->BunkerRaidable && isEmpty));
40
// original code replaced by this hook
42
if ( pThis->Owner != pInf->Owner && !pThis->Owner->Country->MultiplayPassive
43
|| pThis->GetOccupantCount() == pThis->BuildingType->MaxNumberOccupants
45
|| pInf->IsMindControlled() )
51
return can_occupy ? 0x457DD5 : 0x457DA3;
55
// #664: Advanced Rubble - turning into rubble part
56
// moved to before the survivors get unlimboed, per sanity's requirements
57
//A_FINE_HOOK(44266B, BuildingClass_ReceiveDamage_AfterPreDeathSequence, 6)
58
DEFINE_HOOK(441F12, BuildingClass_Destroy_RubbleYell, 6)
60
GET(BuildingClass *, pThis, ESI);
61
BuildingExt::ExtData* BuildingAresData = BuildingExt::ExtMap.Find(pThis);
62
BuildingTypeExt::ExtData* destrBuildTE = BuildingTypeExt::ExtMap.Find(pThis->Type);
64
if(!pThis->C4Timer.Ignorable()) {
65
// If this object has a rubble building set, turn, otherwise die
66
if(destrBuildTE->RubbleDestroyed) {
67
BuildingAresData->RubbleYell();
70
pThis->AfterDestruction();
75
if(pThis->C4Timer.IsDone()) {
77
pThis->AfterDestruction();
82
// #666: Trench Traversal - check if traversal is possible & cursor display
83
DEFINE_HOOK(44725F, BuildingClass_GetCursorOverObject_TargetABuilding, 5)
85
GET(BuildingClass *, pThis, ESI);
86
GET(TechnoClass *, T, EBP);
87
// not decided on UI handling yet
89
if(T->WhatAmI() == abs_Building) {
90
BuildingClass* targetBuilding = specific_cast<BuildingClass *>(T);
91
BuildingExt::ExtData* curBuildExt = BuildingExt::ExtMap.Find(pThis);
93
if(curBuildExt->canTraverseTo(targetBuilding)) {
94
//show entry cursor, hooked up to traversal logic in Misc/Network.cpp -> AresNetEvent::Handlers::RespondToTrenchRedirectClick
95
R->EAX<eAction>(act_Enter);
103
DEFINE_HOOK(443414, BuildingClass_ClickedMission, 6)
105
GET(eAction, Action, EAX);
106
GET(BuildingClass *, pThis, ECX);
108
GET_STACK(ObjectClass *, pTarget, 0x8);
110
if(Action == act_Enter) {
111
if(BuildingClass *pTargetBuilding = specific_cast<BuildingClass *>(pTarget)) {
113
pTargetBuilding->GetCoords(&XYZ);
114
CellStruct tgt = { short(XYZ.X / 256), short(XYZ.Y / 256) };
115
AresNetEvent::Handlers::RaiseTrenchRedirectClick(pThis, &tgt);
124
// #665: Raidable Buildings - prevent raided buildings from being sold while raided
125
DEFINE_HOOK(4494D2, BuildingClass_IsSellable, 6)
127
GET(BuildingClass *, B, ESI);
128
BuildingExt::ExtData* curBuildExt = BuildingExt::ExtMap.Find(B);
130
enum SellValues {FORCE_SELLABLE, FORCE_UNSELLABLE, DECIDE_NORMALLY} sellTreatment;
131
sellTreatment = DECIDE_NORMALLY; // default
133
if(curBuildExt->isCurrentlyRaided) {
134
sellTreatment = FORCE_UNSELLABLE; // enemy shouldn't be able to sell "borrowed" buildings
137
switch(sellTreatment) {
140
case FORCE_UNSELLABLE:
142
case DECIDE_NORMALLY:
148
/* Requested in issue #695
151
Occupier is Remove()'d from the map,
152
added to the Occupants list,
153
<-- hook happens here
154
ThreatToCell is updated,
155
"EVA_StructureGarrisoned" is played if applicable.
157
DEFINE_HOOK(52297F, InfantryClass_GarrisonBuilding_OccupierEntered, 5)
159
GET(InfantryClass *, pInf, ESI);
160
GET(BuildingClass *, pBld, EBP);
161
BuildingExt::ExtData* buildingExtData = BuildingExt::ExtMap.Find(pBld);
162
TechnoExt::ExtData* infExtData = TechnoExt::ExtMap.Find(pInf);
164
infExtData->GarrisonedIn = pBld;
166
// if building and owner are from different players, and the building is not in raided state
167
// change the building's owner and mark it as raided
168
// but only if that's even necessary - no need to raid neutral houses.
169
if((pBld->Owner != pInf->Owner) && !pBld->Owner->IsNeutral() && !buildingExtData->isCurrentlyRaided) {
170
buildingExtData->OwnerBeforeRaid = pBld->Owner;
171
buildingExtData->isCurrentlyRaided = true;
172
pBld->SetOwningHouse(pInf->Owner);
177
/* Requested in issue #694
178
D: The first hook fires each time one of the occupants is ejected through the Deploy function -
179
the game doesn't have a builtin way to remove a single occupant, only all of them, so this is rigged inside that.*/
180
// This is CURRENTLY UNUSED - look at Misc/Network.cpp -> AresNetEvent::Handlers::RespondToTrenchRedirectClick
181
/*A_FINE_HOOK(4580A9, BuildingClass_UnloadOccupants_EachOccupantLeaves, 6)
183
GET(BuildingClass *, pBld, ESI);
184
GET(int, idxOccupant, EBP);
186
TechnoExt::ExtData* infExtData = TechnoExt::ExtMap.Find(pBld->Occupants[idxOccupant]);
187
infExtData->GarrisonedIn = NULL;
190
- get current rally point target; if there is none, exit trench
191
- check if target cell has a building
192
- if so, check if it's the same building
194
- if not, check building with canTraverseTo
195
- if true, doTraverseTo
196
- if false, do nothing
197
- if not, exit trench
200
if(0/ * spawned in a different building * /) {
203
// do the normal kickout thing
207
/* Requested in issue #694
208
D: The second hook fires each time one of the occupants is killed (Assaulter). Note that it doesn't catch the damage forwarding fatal hit.
210
DEFINE_HOOK(4586CA, BuildingClass_KillOccupiers_EachOccupierKilled, 6)
212
GET(BuildingClass *, pBld, ESI);
213
GET(int, idxOccupant, EDI);
214
// I don't think anyone ever actually tested Assaulter=yes with raiding, putting this here 'cause it's likely needed
215
BuildingExt::ExtData* buildingExtData = BuildingExt::ExtMap.Find(pBld);
216
buildingExtData->evalRaidStatus();
221
/* Requested in issue #694
222
D: The third hook fires after all the occupants have been ejected (by the first hook).
224
DEFINE_HOOK(4581CD, BuildingClass_UnloadOccupants_AllOccupantsHaveLeft, 6)
226
GET(BuildingClass *, pBld, ESI);
227
BuildingExt::ExtData* buildingExtData = BuildingExt::ExtMap.Find(pBld);
229
buildingExtData->evalRaidStatus();
234
/* Requested in issue #694
235
D: The fourth hook fires after all the occupants have been killed by the second hook.
237
DEFINE_HOOK(458729, BuildingClass_KillOccupiers_AllOccupantsKilled, 6)
239
GET(BuildingClass *, pBld, ESI);
240
BuildingExt::ExtData* buildingExtData = BuildingExt::ExtMap.Find(pBld);
242
buildingExtData->evalRaidStatus();
248
// #666: Trench Traversal - check if traversal is possible & traverse, eject or do nothing, depending on the result
249
// This is CURRENTLY UNUSED - look at Misc/Network.cpp -> AresNetEvent::Handlers::RespondToTrenchRedirectClick
250
A_FINE_HOOK(457DF5, BuildingClass_UnloadOccupants_AboutToStartUnloading, 6)
252
GET(BuildingClass *, currentBuilding, ESI);
253
/*CellClass* rallyPoint =; // wherever the rally point points to
254
if(BuildingClass* targetBuilding = rallyPoint->GetBuilding()) {
255
BuildingExt::ExtData* currentBuildingExt = BuildingExt::ExtMap.Find(currentBuilding);
256
if(currentBuildingExt->canTraverseTo(targetBuilding)) {
257
currentBuildingExt->doTraverseTo(targetBuilding); // also calls evalRaidStatus()
259
// see if we can find a way to abort eviction here
268
/* #698 - "Building captured" EVA announcement "bug"
271
<DCoder> if you want the original handling (TechBuildingLost, BuildingCaptured, etc) to take place, return No,
272
otherwise perform your own code and return Yes
273
<Renegade> at what place in the chain is that executed?
274
<DCoder> in the middle of where the building changes ownership from old player to new
276
DEFINE_HOOK(448401, BuildingClass_ChangeOwnership_TrenchEVA, 6)
278
GET(BuildingClass *, pBld, ESI);
279
GET(HouseClass *, pNewOwner, EBX);
280
enum wasHandled { Yes = 0x44848F, No = 0} Handled = No;
282
BuildingExt::ExtData* bldExt = BuildingExt::ExtMap.Find(pBld);
284
if(bldExt->ignoreNextEVA) {
286
bldExt->ignoreNextEVA = false;