Ares
Functions

Hooks.cpp File Reference

#include "Body.h"
#include "../TechnoType/Body.h"
#include "../Building/Body.h"
#include "../BuildingType/Body.h"
#include "../../Misc/Debug.h"
#include "../../Misc/JammerClass.h"
#include "../../Misc/PoweredUnitClass.h"
#include <SpecificStructures.h>

Functions

 DEFINE_HOOK (737F97, UnitClass_ReceiveDamage, 0)
 DEFINE_HOOK (41668B, AircraftClass_ReceiveDamage, 6)
 DEFINE_HOOK (6F9E50, TechnoClass_Update, 5)
 DEFINE_HOOK (6F9E76, TechnoClass_Update_CheckOperators, 6)
 TechnoClass::Update is called every frame; returning 0 tells it to execute the original function's code as well.
 DEFINE_HOOK (415CA6, AircraftClass_Paradrop, 6)
 DEFINE_HOOK (415DF6, AircraftClass_Paradrop_Carryall, 6)
 DEFINE_HOOK (6F407D, TechnoClass_Init_1, 6)
 DEFINE_HOOK (6F4103, TechnoClass_Init_2, 6)
 DEFINE_HOOK (71A860, TemporalClass_UpdateA, 6)
 DEFINE_HOOK (71AB30, TemporalClass_GetHelperDamage, 5)
 DEFINE_HOOK (62A020, ParasiteClass_Update, A)
 DEFINE_HOOK (62A7B1, Parasite_ExitUnit, 9)
 DEFINE_HOOK (629804, ParasiteClass_UpdateSquiddy, 9)
 DEFINE_HOOK (6F3330, TechnoClass_SelectWeapon, 5)
 DEFINE_HOOK (51F76D, InfantryClass_Unload, 5)
 DEFINE_HOOK (51CE9A, InfantryClass_Idle, 5)
 DEFINE_HOOK (747BBD, UnitTypeClass_LoadFromINI, 5)
 DEFINE_HOOK (5215F9, InfantryClass_UpdateDeploy, 6)
 EXPORT_FUNC (InfantryClass_UpdateDeploy2)
 DEFINE_HOOK (7101CF, FootClass_ImbueLocomotor, 7)
 DEFINE_HOOK (4DAA68, FootClass_Update_MoveSound, 6)
 DEFINE_HOOK (701C97, TechnoClass_ReceiveDamage_AffectsEnemies, 6)
 DEFINE_HOOK (7090A8, TechnoClass_SelectFiringVoice, 0)
 DEFINE_HOOK (70E2D2, TechnoClass_IronCurtain_Modify, 6)
 DEFINE_HOOK (5198AD, InfantryClass_UpdatePosition_EnteredGrinder, 6)
 DEFINE_HOOK (73A1BC, UnitClass_UpdatePosition_EnteredGrinder, 7)
 DEFINE_HOOK (6F6AC9, TechnoClass_Remove, 6)

Function Documentation

DEFINE_HOOK ( 737F97  ,
UnitClass_ReceiveDamage  ,
 
)
{
        GET(UnitClass *, t, ESI);
        GET_STACK(TechnoClass *, Killer, 0x54);
        GET_STACK(bool, select, 0x13);
        GET_STACK(bool, ignoreDefenses, 0x58);
        TechnoExt::SpawnSurvivors(t, Killer, select, ignoreDefenses);

        return 0x73838A;
}
DEFINE_HOOK ( 6F6AC9  ,
TechnoClass_Remove  ,
 
)
                                           {
        GET(TechnoClass *, pThis, ESI);
        TechnoExt::ExtData* TechnoExt = TechnoExt::ExtMap.Find(pThis);

        // if the removed object is a radar jammer, unjam all jammed radars
        if(TechnoExt->RadarJam) {
                TechnoExt->RadarJam->UnjamAll();
                delete TechnoExt->RadarJam;
                TechnoExt->RadarJam = NULL;
        }
        
        // #617 powered units
        if(TechnoExt->PoweredUnit)
        {
                delete TechnoExt->PoweredUnit;
                TechnoExt->PoweredUnit = NULL;
        }

        return 0;
}
DEFINE_HOOK ( 73A1BC  ,
UnitClass_UpdatePosition_EnteredGrinder  ,
 
)
{
        GET(UnitClass *, Vehicle, EBP);
        GET(BuildingClass *, Grinder, EBX);

        BuildingExt::ExtData *pData = BuildingExt::ExtMap.Find(Grinder);

        if(pData->ReverseEngineer(Vehicle)) {
                if(Vehicle->Owner->ControlledByPlayer()) {
                        VoxClass::Play("EVA_ReverseEngineeredVehicle");
                        VoxClass::Play("EVA_NewTechnologyAcquired");
                }
        }

        // #368: refund hijackers
        if(Vehicle->HijackerInfantryType != -1) {
                if(InfantryTypeClass *Hijacker = InfantryTypeClass::Array->GetItem(Vehicle->HijackerInfantryType)) {
                        int refund = Hijacker->GetRefund(Vehicle->Owner, 0);
                        Grinder->Owner->GiveMoney(refund);
                }
        }

        return 0;
}
DEFINE_HOOK ( 5198AD  ,
InfantryClass_UpdatePosition_EnteredGrinder  ,
 
)
{
        GET(InfantryClass *, Infantry, ESI);
        GET(BuildingClass *, Grinder, EBX);

        BuildingExt::ExtData *pData = BuildingExt::ExtMap.Find(Grinder);

        if(pData->ReverseEngineer(Infantry)) {
                if(Infantry->Owner->ControlledByPlayer()) {
                        VoxClass::Play("EVA_ReverseEngineeredInfantry");
                        VoxClass::Play("EVA_NewTechnologyAcquired");
                }
        }

        return 0;
}
DEFINE_HOOK ( 70E2D2  ,
TechnoClass_IronCurtain_Modify  ,
 
)
                                                       {
        GET(TechnoClass*, pThis, ECX);
        GET(int, duration, EDX);
        GET_STACK(bool, force, 0x1C);

        // if it's no force shield then it's the iron curtain.
        if(!force) {
                if(TechnoTypeExt::ExtData *pData = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType())) {
                        duration = (int)(duration * pData->IC_Modifier);
                }

                pThis->IronCurtainTimer.TimeLeft = duration;
                pThis->IronTintStage = 0;

                return 0x70E2DB;
        }

        return 0;
}
DEFINE_HOOK ( 7090A8  ,
TechnoClass_SelectFiringVoice  ,
 
)
                                                      {
        GET(TechnoClass*, pThis, ESI);
        GET(TechnoClass*, pTarget, ECX);

        TechnoTypeClass* pType = pThis->GetTechnoType();
        TechnoTypeExt::ExtData* pData = TechnoTypeExt::ExtMap.Find(pType);

        int idxVoice = -1;

        int idxWeapon = pThis->SelectWeapon(pTarget);
        WeaponTypeClass* pWeapon = pThis->GetWeapon(idxWeapon)->WeaponType;

        // repair
        if(pWeapon && pWeapon->Damage < 0) {
                idxVoice = pData->VoiceRepair;
                if(idxVoice < 0) {
                        if(!_strcmpi(pType->ID, "FV")) {
                                idxVoice = RulesClass::Instance->VoiceIFVRepair;
                        }
                }
        }

        // don't mix them up, but fall back to rookie voice if there
        // is no elite voice.
        if(idxVoice < 0) {
                if(idxWeapon) {
                        // secondary    
                        if(pThis->Veterancy.IsElite()) {
                                idxVoice = pType->VoiceSecondaryEliteWeaponAttack;
                        }

                        if(idxVoice < 0) {
                                idxVoice = pType->VoiceSecondaryWeaponAttack;
                        }
                } else {
                        // primary
                        if(pThis->Veterancy.IsElite()) {
                                idxVoice = pType->VoicePrimaryEliteWeaponAttack;
                        }

                        if(idxVoice < 0) {
                                idxVoice = pType->VoicePrimaryWeaponAttack;
                        }
                }
        }

        // generic attack voice
        if(idxVoice < 0 && pType->VoiceAttack.Count) {
                unsigned int idxRandom = Randomizer::Global()->Random();
                idxVoice = pType->VoiceAttack.GetItem(idxRandom % pType->VoiceAttack.Count);
        }

        // play voice
        if(idxVoice > -1) {
                pThis->QueueVoice(idxVoice);
        }

        return 0x7091C5;
}
DEFINE_HOOK ( 701C97  ,
TechnoClass_ReceiveDamage_AffectsEnemies  ,
 
)
{
        GET(WarheadTypeClass *, pThis, EBP);
        GET(TechnoClass *, Victim, ESI);
        LEA_STACK(args_ReceiveDamage *, Arguments, 0xC8);
        bool CanAffect = true;

        WarheadTypeExt::ExtData *WHTypeExt = WarheadTypeExt::ExtMap.Find(pThis);

        if(Arguments->Attacker) {
                /* Ren, 08.01.2011:
                        Just documenting how/why this works, since I just stared at it for ten minutes trying to
                        figure out why this makes sense:
                        
                        AffectsEnemies=yes is the default case (weapons usually affect the enemy), so if that's true,
                        we can affect the target (this might later be changed by AffectsAllies).
                        AffectsEnemies=no means we cannot attack enemies, i.e. we can only attack allies;
                        ergo, CanAffect is only true if victim and target are allied.
                        Thanks to lazy evaluation, the latter condition is only ever checked if AffectsEnemies is set to no, which is not the default.
                        
                        The question of how this works came up because the current treatment of Neutral is technically wrong:
                        Semantically, AffectsEnemies=no only means "you cannot attack enemies", but our code renders it as "you cannot attack non-allies";
                        this obviously means that AffectsEnemies=no includes being unable to attack Neutral, despite the fact that Neutral is, well, neutral - not our enemy.
                        
                        In the specific situation this came up in, the current behavior was desired and no one else complained so far,
                        so I'm not proposing a change at this point. 
                        In fact, since this flag is AffectsAllies's evil twin, it is very most likely that practically *all* users of 
                        AffectsEnemies assume this behavior; he who sets AffectsEnemies=no likely does so with the intention of limiting damage to allied troops.
                        I just wanted this behavior and the logic behind it to be documented for the future.
                        
                        Note that, in the specific case of AffectsEnemies=no, AffectsAllies=no, this will rear its ugly head as a bug: Neutral should be affected, but won't be.
                 */
                CanAffect = WHTypeExt->AffectsEnemies || Victim->Owner->IsAlliedWith(Arguments->Attacker->Owner);

#ifdef DEBUGBUILD
                if(Arguments->Attacker->Owner != Arguments->SourceHouse) {
                        Debug::Log("Info: During AffectsEnemies parsing, Attacker's Owner was %p [%s], but SourceHouse was %p [%s].",
                                Arguments->Attacker->Owner,
                                (Arguments->Attacker->Owner ? Arguments->Attacker->Owner->Type->ID : "null"),
                                Arguments->SourceHouse,
                                (Arguments->SourceHouse ? Arguments->SourceHouse->Type->ID : "null")
                                );
                        Debug::DumpStack(R, 0x180, 0xC0);
                }
#endif

        } else if(Arguments->SourceHouse) {
                // fallback, in case future ways of damage dealing don't include an attacker, e.g. stuff like GenericWarhead
                CanAffect = WHTypeExt->AffectsEnemies || Victim->Owner->IsAlliedWith(Arguments->SourceHouse);

        } else {
                //Debug::Log("Warning: Neither Attacker nor SourceHouse were set during AffectsEnemies parsing!");
                // this is often the case for ownerless damage i.e. crates/fire particles, no point in logging it
        }

        return CanAffect ? 0 : 0x701CC2;
}
DEFINE_HOOK ( 4DAA68  ,
FootClass_Update_MoveSound  ,
 
)
{
        GET(FootClass *, F, ESI);
        if(F->unknown_bool_53C) {
                return 0x4DAAEE;
        }
        if(F->LocomotorSource) {
                F->Audio7.ShutUp();
                return 0x4DAAEE;
        }
        return 0x4DAA70;
}
DEFINE_HOOK ( 7101CF  ,
FootClass_ImbueLocomotor  ,
 
)
{
        GET(FootClass *, F, ESI);
        F->Audio7.ShutUp();
        return 0;
}
DEFINE_HOOK ( 41668B  ,
AircraftClass_ReceiveDamage  ,
 
)
{
        GET(AircraftClass *, a, ESI);
        GET_STACK(TechnoClass *, Killer, 0x28);
        GET_STACK(int, ignoreDefenses, 0x20);
        bool select = a->IsSelected && a->Owner->ControlledByPlayer();
        TechnoExt::SpawnSurvivors(a, Killer, select, ignoreDefenses != 0);

        return 0;
}
DEFINE_HOOK ( 5215F9  ,
InfantryClass_UpdateDeploy  ,
 
)
{
        GET(TechnoClass *, I, ESI);
        return TechnoTypeExt::ExtMap.Find(I->GetTechnoType())->Is_Deso ? 0x5216B6 : 0x52160D;
}
DEFINE_HOOK ( 747BBD  ,
UnitTypeClass_LoadFromINI  ,
 
)
{
        GET(UnitTypeClass *, U, ESI);

        U->AltImage = R->EAX<SHPStruct *>(); // jumping over, so replicated
        return U->Gunner
                ? 0x747BD7
                : 0x747E90;
}
DEFINE_HOOK ( 6F9E76  ,
TechnoClass_Update_CheckOperators  ,
 
)

TechnoClass::Update is called every frame; returning 0 tells it to execute the original function's code as well.

{
        GET(TechnoClass *, pThis, ESI); // object this is called on
        //TechnoTypeClass *Type = pThis->GetTechnoType();
        //TechnoTypeExt::ExtData *pTypeData = TechnoTypeExt::ExtMap.Find(Type);
        TechnoTypeExt::ExtData *pTypeData = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType());
        TechnoExt::ExtData *pData = TechnoExt::ExtMap.Find(pThis);

        // Related to operators/drivers, issue #342
        BuildingClass * pTheBuildingBelow = pThis->GetCell()->GetBuilding();

        /* Conditions checked:
                - Is there no building below us
                OR
                - Is this the building on this cell AND is it online

                pTheBuildingBelow will be NULL if no building was found
                This check ensures that Operator'd units don't Deactivate above structures such as War Factories, Repair Depots or Battle Bunkers.
                (Which is potentially abusable, but let's hope no one figures that out.)
        */
        if(!pTheBuildingBelow || ((pTheBuildingBelow == pThis) && (pTheBuildingBelow->IsPowerOnline()))) {
                bool Override = false;
                if(FootClass *pFoot = generic_cast<FootClass*>(pThis)) {
                        if(!pTheBuildingBelow) {
                                // immobile, though not disabled. like hover tanks after
                                // a repair depot has been sold or warped away.
                                Override = (pFoot->Locomotor->Is_Powered() == pThis->Deactivated);
                        }
                }

                if(pData->IsOperated()) { // either does have an operator or doesn't need one, so...
                        if( (pThis->Deactivated && pData->IsPowered() && !pThis->IsUnderEMP()) || Override ) { // ...if it's currently off, turn it on! (oooh baby)
                                pThis->Reactivate();
                                pThis->Owner->ShouldRecheckTechTree = true; // #885
                        }
                } else { // doesn't have an operator, so...
                        if(!pThis->Deactivated) { // ...if it's not off yet, turn it off!
                                pThis->Deactivate();
                                pThis->Owner->ShouldRecheckTechTree = true; // #885
                        }
                }
        }

        // prevent disabled units from driving around.
        if(pThis->Deactivated) {
                if(UnitClass* pUnit = specific_cast<UnitClass*>(pThis)) {
                        if(pUnit->Locomotor->Is_Moving() && pUnit->Destination && !pThis->LocomotorSource) {
                                pUnit->SetDestination(NULL, true);
                                pUnit->StopMoving();
                        }
                }

                // dropping Radar Jammers (#305) here for now; should check if another TechnoClass::Update hook might be better ~Ren
                if(pData->RadarJam) { // RadarJam should only be non-null if the object is an active radar jammer
                        pData->RadarJam->UnjamAll();
                }
        } else {
                // dropping Radar Jammers (#305) here for now; should check if another TechnoClass::Update hook might be better ~Ren
                if(!!pTypeData->RadarJamRadius) {
                        if(!pData->RadarJam) {
                                pData->RadarJam = new JammerClass(pThis, pData);
                        }

                        pData->RadarJam->Update();
                }
        }

        /*      using 0x6F9E7C instead makes this function override the original game one's entirely -
                don't activate that unless you handle _everything_ originally handled by the game */
        return 0;
}
DEFINE_HOOK ( 51F76D  ,
InfantryClass_Unload  ,
 
)
{
        GET(TechnoClass *, I, ESI);
        TechnoTypeExt::ExtData *pData = TechnoTypeExt::ExtMap.Find(I->GetTechnoType());
        return pData->Is_Deso ? 0x51F77D : 0x51F792;
}
DEFINE_HOOK ( 6F3330  ,
TechnoClass_SelectWeapon  ,
 
)
{
        GET(TechnoClass *, pThis, ECX);
        GET_STACK(TechnoClass *, pTarg, 0x4);

//      DWORD Selected = TechnoClassExt::SelectWeaponAgainst(pThis, pTarg);
//      R->EAX(Selected);
//      return 0x6F3813;
        return 0;
}
DEFINE_HOOK ( 629804  ,
ParasiteClass_UpdateSquiddy  ,
 
)
{
        GET(TechnoClass *, T, ECX);
        TechnoExt::ExtData *pData = TechnoExt::ExtMap.Find(T);
        WeaponStruct *W = T->GetWeapon(pData->idxSlot_Parasite);
        R->EAX<WeaponStruct *>(W);
        return 0x62980D;
}
DEFINE_HOOK ( 62A7B1  ,
Parasite_ExitUnit  ,
 
)
{
        GET(TechnoClass *, T, ECX);
        TechnoExt::ExtData *pData = TechnoExt::ExtMap.Find(T);
        WeaponStruct *W = T->GetWeapon(pData->idxSlot_Parasite);
        R->EAX<WeaponStruct *>(W);
        return 0x62A7BA;
}
DEFINE_HOOK ( 62A020  ,
ParasiteClass_Update  ,
 
)
{
        GET(TechnoClass *, T, ECX);
        TechnoExt::ExtData *pData = TechnoExt::ExtMap.Find(T);
        WeaponStruct *W = T->GetWeapon(pData->idxSlot_Parasite);
        R->EAX<WeaponStruct *>(W);
        return 0x62A02A;
}
DEFINE_HOOK ( 71AB30  ,
TemporalClass_GetHelperDamage  ,
 
)
{
        GET(TemporalClass *, Temp, ESI);
        TechnoClass *T = Temp->Owner;
        TechnoExt::ExtData *pData = TechnoExt::ExtMap.Find(T);
        WeaponStruct *W = T->GetWeapon(pData->idxSlot_Warp);
        R->EAX<WeaponStruct *>(W);
        return 0x71AB47;
}
DEFINE_HOOK ( 71A860  ,
TemporalClass_UpdateA  ,
 
)
{
        GET(TemporalClass *, Temp, ESI);
        TechnoClass *T = Temp->Owner;
        TechnoExt::ExtData *pData = TechnoExt::ExtMap.Find(T);
        WeaponStruct *W = T->GetWeapon(pData->idxSlot_Warp);
        R->EAX<WeaponStruct *>(W);
        return 0x71A876;
}
DEFINE_HOOK ( 6F4103  ,
TechnoClass_Init_2  ,
 
)
{
        return 0x6F41C0;
}
DEFINE_HOOK ( 6F407D  ,
TechnoClass_Init_1  ,
 
)
{
        GET(TechnoClass *, T, ESI);
        TechnoTypeClass * Type = T->GetTechnoType();
        TechnoExt::ExtData *pData = TechnoExt::ExtMap.Find(T);
        TechnoTypeExt::ExtData *pTypeData = TechnoTypeExt::ExtMap.Find(Type);

        CaptureManagerClass *Capturer = NULL;
        ParasiteClass *Parasite = NULL;
        TemporalClass *Temporal = NULL;

        FootClass *F = generic_cast<FootClass *>(T);
        bool IsFoot = (F != NULL);

//      for(int i = 0; i < pTypeData->Weapons.get_Count(); ++i) {
//              WeaponStruct *W = &pTypeData->Weapons[i];
        TechnoTypeClass *TT = T->GetTechnoType();
        for(int i = 0; i < 18; ++i) {
                WeaponTypeClass *W1 = TT->get_Weapon(i);
                WeaponTypeClass *W2 = TT->get_EliteWeapon(i);
                if(!W1 && !W2) {
                        continue;
                }
                WarheadTypeClass *WH1 = W1 ? W1->Warhead : NULL;
                WarheadTypeClass *WH2 = W2 ? W2->Warhead : NULL;

                if((W1 && !WH1) || (W2 && !WH2)) {
                        Debug::FatalErrorAndExit(
                                "Constructing an instance of [%s]:\r\n%sWeapon %s (slot %d) has no Warhead!",
                                        Type->ID,
                                        WH1 ? "Elite " : "",
                                        (WH1 ? W2 : W1)->ID,
                                        i);
                }

                if(WH1 && WH1->MindControl && Capturer == NULL) {
                        GAME_ALLOC(CaptureManagerClass, Capturer, T, W1->Damage, W1->InfiniteMindControl);
                } else if(WH2 && WH2->MindControl && Capturer == NULL) {
                        GAME_ALLOC(CaptureManagerClass, Capturer, T, W2->Damage, W2->InfiniteMindControl);
                }

                if(WH1 && WH1->Temporal && Temporal == NULL) {
                        GAME_ALLOC(TemporalClass, Temporal, T);
                        Temporal->WarpPerStep = W1->Damage;
                        pData->idxSlot_Warp = (BYTE)i;
                } else if(WH2 && WH2->Temporal && Temporal == NULL) {
                        GAME_ALLOC(TemporalClass, Temporal, T);
                        Temporal->WarpPerStep = W2->Damage;
                        pData->idxSlot_Warp = (BYTE)i;
                }

                if((WH1 && WH1->Parasite || WH2 && WH2->Parasite) && IsFoot && Parasite == NULL) {
                        GAME_ALLOC(ParasiteClass, Parasite, F);
                        pData->idxSlot_Parasite = (BYTE)i;
                }
        }

        T->CaptureManager = Capturer;
        T->TemporalImUsing = Temporal;
        if(IsFoot) {
                F->ParasiteImUsing = Parasite;
        }

        return 0x6F4102;
}
DEFINE_HOOK ( 415DF6  ,
AircraftClass_Paradrop_Carryall  ,
 
)
{
        GET(FootClass *, pTechno, ESI);
        pTechno->IsOnCarryall = false;
        return 0;
}
DEFINE_HOOK ( 415CA6  ,
AircraftClass_Paradrop  ,
 
)
{
        GET(AircraftClass *, A, EDI);
        GET(FootClass *, P, ESI);
        if(P->WhatAmI() != abs_Unit) {
                return 0;
        }
        CoordStruct SrcXYZ;
        A->GetCoords(&SrcXYZ);
        LEA_STACK(CoordStruct *, XYZ, 0x20);
        XYZ->X = (SrcXYZ.X & ~0xFF) + 0x80;
        XYZ->Y = (SrcXYZ.Y & ~0xFF) + 0x80;
        XYZ->Z = SrcXYZ.Z - 1;
        R->ECX<CoordStruct *>(XYZ);
        return 0x415DE3;
}
DEFINE_HOOK ( 51CE9A  ,
InfantryClass_Idle  ,
 
)
{
        GET(InfantryClass *, I, ESI);
        TechnoTypeExt::ExtData *pData = TechnoTypeExt::ExtMap.Find(I->GetTechnoType());

        // don't play idle when paralyzed
        if(I->IsUnderEMP()) {
                R->BL(false);
                return 0x51CECD;
        }

        R->EDI(R->EAX()); // argh
        R->BL(pData->Is_Cow); // aaaargh! again!
        return pData->Is_Cow ? 0x51CEAE : 0x51CECD;
}
DEFINE_HOOK ( 6F9E50  ,
TechnoClass_Update  ,
 
)
{
        GET(TechnoClass *, Source, ECX);

        TechnoExt::ExtData *pData = TechnoExt::ExtMap.Find(Source);
        TechnoTypeExt::ExtData *pTypeData = TechnoTypeExt::ExtMap.Find(Source->GetTechnoType());

        if(pData->CloakSkipTimer.IsDone()) {
                pData->CloakSkipTimer.Stop();
                Source->Cloakable = Source->GetTechnoType()->Cloakable;
        } else if(pData->CloakSkipTimer.GetTimeLeft() > 0) {
                Source->Cloakable = 0;
        }

        // #1208
        if(pTypeData) {
                if(pTypeData->PassengerTurret.Get()) {
                        // 18 = 1 8 = A H = Adolf Hitler. Clearly we can't allow it to come to that.
                        int passengerNumber = (Source->Passengers.NumPassengers <= 17) ? Source->Passengers.NumPassengers : 17;
                        int maxTurret = Source->GetTechnoType()->TurretCount - 1;
                        Source->CurrentTurretNumber = (passengerNumber <= maxTurret) ? passengerNumber : maxTurret;
                }
        }
        
        // #617 powered units
        if( pTypeData->PoweredBy.Count ) {
                if(!pData->PoweredUnit) {
                        pData->PoweredUnit = new PoweredUnitClass(Source, pTypeData);
                }
                pData->PoweredUnit->Update();
        }

        return 0;
}
EXPORT_FUNC ( InfantryClass_UpdateDeploy2  )
{
/*
        GET(TechnoClass *, I, ESI);
        TechnoTypeClassExt::TechnoTypeClassData *pData = TechnoTypeClassExt::Ext_p[I->GetTechnoType()];
        return pData->Is_Deso_Radiation ? 0x52139A : 0x5214B9;
        WRONG: needs more code to reimplement weapon shooting without rad checks
*/
        return 0;
}
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines