Ares
Functions

Hooks.cpp File Reference

#include "Body.h"
#include "../../Misc/SWTypes.h"
#include "../House/Body.h"
#include <StringTable.h>

Functions

 DEFINE_HOOK (6CEF84, SuperWeaponTypeClass_GetCursorOverObject, 7)
 DEFINE_HOOK (653B3A, RadarClass_GetMouseAction_CustomSWAction, 5)
 DEFINE_HOOK (6AAEDF, SidebarClass_ProcessCameoClick_SuperWeapons, 6)
 DEFINE_HOOK (6A932B, CameoClass_GetTip_MoneySW, 6)
 DEFINE_HOOK (6CEE96, SuperWeaponTypeClass_GetTypeIndex, 5)
 DEFINE_HOOK (4AC20C, DisplayClass_LMBUp, 7)
 DEFINE_HOOK (446418, BuildingClass_Place1, 6)
 DEFINE_HOOK (44656D, BuildingClass_Place2, 6)
 DEFINE_HOOK (45100A, BuildingClass_ProcessAnims1, 6)
 DEFINE_HOOK (451132, BuildingClass_ProcessAnims2, 6)
 DEFINE_HOOK (446937, BuildingClass_AnnounceSW, 6)
 DEFINE_HOOK (6CBDD7, SuperClass_AnnounceReady, 6)
 DEFINE_HOOK (6CC0EA, SuperClass_AnnounceQuantity, 9)
 DEFINE_HOOK (50B319, HouseClass_UpdateSWs_ShowCameo, 6)
 DEFINE_HOOK (50CFAA, HouseClass_PickOffensiveSWTarget, 0)
 DEFINE_HOOK (6CBA9E, SuperClass_ClickFire_Abort, 7)
 DEFINE_HOOK (6CC390, SuperClass_Launch, 6)
 DEFINE_HOOK (44691B, BuildingClass_4DC_SWAvailable, 6)
 DEFINE_HOOK (45765A, BuildingClass_SWAvailable, 6)
 DEFINE_HOOK (4576BA, BuildingClass_SW2Available, 6)
 DEFINE_HOOK (4FAE72, HouseClass_SWFire_PreDependent, 6)
 DEFINE_HOOK (6CC2B0, SuperClass_NameReadiness, 5)
 DEFINE_HOOK (5098F0, HouseClass_Update_AI_TryFireSW, 5)
 DEFINE_HOOK (4F9004, HouseClass_Update_TrySWFire, 7)
 DEFINE_HOOK (6CBF5B, SuperClass_GetCameoChargeState_ChargeDrainRatio, 9)
 DEFINE_HOOK (6CC053, SuperClass_GetCameoChargeState_FixFullyCharged, 5)
 DEFINE_HOOK (6CB995, SuperClass_ClickFire_ChargeDrainRatioA, 8)
 DEFINE_HOOK (6CBA19, SuperClass_ClickFire_ChargeDrainRatioB, A)
 DEFINE_HOOK (6CBD6B, SuperClass_Update_DrainMoney, 8)
 DEFINE_HOOK (6CEEB0, SuperWeaponTypeClass_FindFirstOfAction, 8)

Function Documentation

DEFINE_HOOK ( 6CEF84  ,
SuperWeaponTypeClass_GetCursorOverObject  ,
 
)
{
        GET(SuperWeaponTypeClass*, pThis, ECX);

        SWTypeExt::ExtData *pData = SWTypeExt::ExtMap.Find(pThis);
        int type = (pData->HandledByNewSWType > -1) ? pData->HandledByNewSWType : pThis->Type;
        bool customType = (type >= FIRST_SW_TYPE);

        if((pThis->Action == SW_YES_CURSOR) || customType) {
                GET_STACK(CellStruct *, pMapCoords, 0x0C);

                int Action = SW_YES_CURSOR;

                // prevent firing into shroud
                if(!pData->SW_FireToShroud.Get()) {
                        CellClass* pCell = MapClass::Instance->GetCellAt(pMapCoords);
                        CoordStruct Crd;

                        if(MapClass::Instance->IsLocationShrouded(pCell->GetCoords(&Crd))) {
                                Action = SW_NO_CURSOR;
                        }
                }

                // new SW types have to check whether the coordinates are valid.
                if(Action == SW_YES_CURSOR) {
                        if(customType && !NewSWType::GetNthItem(type)->CanFireAt(pData, pMapCoords)) {
                                Action = SW_NO_CURSOR;
                        }
                }

                R->EAX(Action);

                if(Action == SW_YES_CURSOR) {
                        SWTypeExt::CurrentSWType = pThis;
                        Actions::Set(&pData->SW_Cursor, pData->SW_FireToShroud.Get());
                } else {
                        SWTypeExt::CurrentSWType = NULL;
                        Actions::Set(&pData->SW_NoCursor, pData->SW_FireToShroud.Get());
                }
                return 0x6CEFD9;
        }
        return 0;
}
DEFINE_HOOK ( 6CEEB0  ,
SuperWeaponTypeClass_FindFirstOfAction  ,
 
)
                                                               {
        GET(int, action, ECX);

        R->EAX(0);

        // this implementation is as stupid as short sighted, but it should work
        // for the moment. as there are no actions any more, this has to be
        // reworked if powerups are expanded. for now, it only has to find a nuke.
        for(int i=0; i<SuperWeaponTypeClass::Array->Count; ++i) {
                if(SuperWeaponTypeClass* pType = SuperWeaponTypeClass::Array->GetItem(i)) {
                        if(pType->Action == action) {
                                R->EAX(pType);
                                break;
                        } else {
                                if(SWTypeExt::ExtData* pExt = SWTypeExt::ExtMap.Find(pType)) {
                                        if(pExt->HandledByNewSWType > -1) {
                                                if(NewSWType *swt = NewSWType::GetNthItem(pExt->HandledByNewSWType)) {
                                                        if(swt->HandlesType(SuperWeaponType::Nuke)) {
                                                                R->EAX(pType);
                                                                break;
                                                        }
                                                }
                                        }
                                }
                        }
                }
        }

        // put a hint into the debug log to explain why we will crash now.
        if(!R->EAX()) {
                Debug::FatalErrorAndExit("Failed finding an Action=Nuke or Type=MultiMissile super weapon to be granted by ICBM crate.");
        }

        return 0x6CEEE5;
}
DEFINE_HOOK ( 6CBD6B  ,
SuperClass_Update_DrainMoney  ,
 
)
                                                     {
        // draining weapon active. take or give money. stop, 
        // if player has insufficient funds.
        GET(SuperClass*, pSuper, ESI);
        GET(int, timeLeft, EAX);

        if(timeLeft > 0 && pSuper->Type->UseChargeDrain && pSuper->ChargeDrainState == 2) {
                if(SWTypeExt::ExtData* pData = SWTypeExt::ExtMap.Find(pSuper->Type)) {
                        int money = pData->Money_DrainAmount;
                        if(money != 0 && pData->Money_DrainDelay > 0) {
                                if(!(timeLeft % pData->Money_DrainDelay)) {

                                        // only abort if SW drains money and there is none
                                        if(pData->Money_DrainAmount < 0) {
                                                if(pSuper->Owner->Available_Money() < -money) {
                                                        if(pSuper->Owner->IsHumanoid()) {
                                                                VoxClass::PlayIndex(pData->EVA_InsufficientFunds);
                                                                pData->PrintMessage(pData->Message_InsufficientFunds, HouseClass::Player);
                                                        }
                                                        return 0x6CBD73;
                                                }
                                        }

                                        // apply drain money
                                        if(money > 0) {
                                                pSuper->Owner->GiveMoney(money);
                                        } else {
                                                pSuper->Owner->TakeMoney(-money);
                                        }
                                }
                        }
                }
        }

        return (timeLeft ? 0x6CBE7C : 0x6CBD73);
}
DEFINE_HOOK ( 6CBA19  ,
SuperClass_ClickFire_ChargeDrainRatioB  ,
 
)
                                                               {
        GET(int, length, EDI);
        GET(SuperClass*, pSuper, ESI);

        if(SWTypeExt::ExtData* pData = SWTypeExt::ExtMap.Find(pSuper->Type)) {
                double ratio = pData->SW_ChargeToDrainRatio;
                double remaining = length * ratio;
                int frames = (int)Game::F2I(remaining);
        
                R->EAX(frames);
                return 0x6CBA28;
        }

        return 0;
}
DEFINE_HOOK ( 6CB995  ,
SuperClass_ClickFire_ChargeDrainRatioA  ,
 
)
                                                               {
        GET_STACK(int, rechargeTime, 0x24);
        GET_STACK(int, timeLeft, 0x20);

        // recreate the SW from a pointer to its CreationTimer
        GET(SuperClass*, pSuper, ESI);
        pSuper = (SuperClass*)((char*)pSuper - 30);

        if(SWTypeExt::ExtData* pData = SWTypeExt::ExtMap.Find(pSuper->Type)) {
                double ratio = pData->SW_ChargeToDrainRatio;
                double remaining = rechargeTime - timeLeft / ratio;
                int frames = (int)Game::F2I(remaining);
        
                R->EAX(frames);
                return 0x6CB9B0;
        }

        return 0;
}
DEFINE_HOOK ( 6CC053  ,
SuperClass_GetCameoChargeState_FixFullyCharged  ,
 
)
                                                                       {
        GET(int, charge, EAX);

        // some smartass capped this at 53, causing the last
        // wedge of darken.shp never to disappear.
        R->EAX(std::min(charge, 54));
        return 0x6CC066;
}
DEFINE_HOOK ( 6CBF5B  ,
SuperClass_GetCameoChargeState_ChargeDrainRatio  ,
 
)
                                                                        {
        GET_STACK(int, rechargeTime1, 0x10);
        GET_STACK(int, rechargeTime2, 0x14);
        GET_STACK(int, timeLeft, 0xC);
        
        GET(SuperWeaponTypeClass*, pType, EBX);
        if(SWTypeExt::ExtData* pData = SWTypeExt::ExtMap.Find(pType)) {

                // use per-SW charge-to-drain ratio.
                double percentage = 0.0;
                double ratio = pData->SW_ChargeToDrainRatio;
                if(std::abs(rechargeTime2 * ratio) > 0.001) {
                        percentage = 1.0 - (rechargeTime1 * ratio - timeLeft) / (rechargeTime2 * ratio);
                }

                // up to 55 steps
                int charge = (int)Game::F2I(percentage * 54.0);
                R->EAX(charge);
                return 0x6CC053;
        }

        return 0;
}
DEFINE_HOOK ( 4F9004  ,
HouseClass_Update_TrySWFire  ,
 
)
                                                    {
        GET(HouseClass*, pThis, ESI);
        bool isHuman = R->AL() != 0;

        if(!isHuman) {
                if(!pThis->Type->MultiplayPassive) {
                        return 0x4F9015;
                }

        } else {
                // update the SWs for human players to support auto firing.
                pThis->AI_TryFireSW();
        }

        return 0x4F9038;
}
DEFINE_HOOK ( 5098F0  ,
HouseClass_Update_AI_TryFireSW  ,
 
)
                                                       {
        GET(HouseClass*, pThis, ECX);

        // this method iterates over every available SW and checks
        // whether it should be fired automatically. the original
        // method would abort if this house is human-controlled.
        bool AIFire = !pThis->IsHumanoid();

        for(int i=0; i<pThis->Supers.Count; ++i) {
                if(SuperClass* pSuper = pThis->Supers.GetItem(i)) {
                        SWTypeExt::ExtData* pExt = SWTypeExt::ExtMap.Find(pSuper->Type);

                        // fire if this is AI owned or the SW has auto fire set.
                        if(AIFire || pExt->SW_AutoFire.Get()) {

                                if(pSuper->IsCharged) {
                                        CellStruct Cell = HouseClass::DefaultIonCannonCoords;
                                        auto LaunchSW = [&](CellStruct *Cell) {
                                                int idxSW = pThis->Supers.FindItemIndex(&pSuper);
                                                pThis->Fire_SW(idxSW, Cell);
                                        };

                                        // don't try to fire if we obviously haven't enough money
                                        if(pExt->Money_Amount < 0) {
                                                if(HouseClass::Player->Available_Money() < -pExt->Money_Amount.Get()) {
                                                        continue;
                                                }
                                        }

                                        // all the different AI targeting modes
                                        switch(pExt->SW_AITargetingType.Get()) {
                                        case SuperWeaponAITargetingMode::Nuke:
                                                {
                                                        if(pThis->EnemyHouseIndex != -1) {
                                                                if(pThis->PreferredTargetCell == HouseClass::DefaultIonCannonCoords) {
                                                                        Cell = *(pThis->PreferredTargetWaypoint == 1
                                                                                ? pThis->PickIonCannonTarget(Cell)
                                                                                : pThis->sub_50D170(&Cell, pThis->PreferredTargetWaypoint));
                                                                } else {
                                                                        Cell = pThis->PreferredTargetCell;
                                                                }

                                                                if(Cell != HouseClass::DefaultIonCannonCoords) {
                                                                        LaunchSW(&Cell);
                                                                }
                                                        }
                                                        break;
                                                }

                                        case SuperWeaponAITargetingMode::LightningStorm:
                                                {
                                                        pThis->Fire_LightningStorm(pSuper);
                                                        break;
                                                }

                                        case SuperWeaponAITargetingMode::PsychicDominator:
                                                {
                                                        pThis->Fire_PsyDom(pSuper);
                                                        break;
                                                }

                                        case SuperWeaponAITargetingMode::ParaDrop:
                                                {
                                                        pThis->Fire_ParaDrop(pSuper);
                                                        break;
                                                }

                                        case SuperWeaponAITargetingMode::GeneticMutator:
                                                {
                                                        pThis->Fire_GenMutator(pSuper);
                                                        break;
                                                }

                                        case SuperWeaponAITargetingMode::ForceShield:
                                                {
                                                        if(pThis->PreferredDefensiveCell2 == HouseClass::DefaultIonCannonCoords) {
                                                                if(pThis->PreferredDefensiveCell != HouseClass::DefaultIonCannonCoords
                                                                        && RulesClass::Instance->AISuperDefenseFrames + pThis->PreferredDefensiveCellStartTime > Unsorted::CurrentFrame) {
                                                                        Cell = pThis->PreferredDefensiveCell;
                                                                }
                                                        } else {
                                                                Cell = pThis->PreferredDefensiveCell2;
                                                        }

                                                        if(Cell != HouseClass::DefaultIonCannonCoords) {
                                                                LaunchSW(&Cell);
                                                                pThis->PreferredDefensiveCell = HouseClass::DefaultIonCannonCoords;
                                                        }
                                                        break;
                                                }

                                        case SuperWeaponAITargetingMode::Offensive:
                                                {
                                                        if(pThis->EnemyHouseIndex != -1 && pExt->IsHouseAffected(pThis, HouseClass::Array->GetItem(pThis->EnemyHouseIndex))) {
                                                                pThis->PickIonCannonTarget(Cell);
                                                                if(Cell != HouseClass::DefaultIonCannonCoords) {
                                                                        LaunchSW(&Cell);
                                                                }
                                                        }
                                                        break;
                                                }

                                        case SuperWeaponAITargetingMode::NoTarget:
                                                {
                                                        LaunchSW(&Cell);
                                                        break;
                                                }

                                        case SuperWeaponAITargetingMode::Stealth:
                                                {
                                                        // find one of the cloaked enemy technos, posing the largest threat.
                                                        DynamicVectorClass<TechnoClass*> list;
                                                        int currentValue = 0;
                                                        for(int j=0; j<TechnoClass::Array->Count; ++j) {
                                                                if(TechnoClass* pTechno = TechnoClass::Array->GetItem(j)) {
                                                                        if(pTechno->CloakState) {
                                                                                if(pExt->IsHouseAffected(pThis, pTechno->Owner)) {
                                                                                        if(pExt->IsTechnoAffected(pTechno)) {
                                                                                                int thisValue = pTechno->GetTechnoType()->ThreatPosed;
                                                                                                if(currentValue < thisValue) {
                                                                                                        list.Clear();
                                                                                                        currentValue = thisValue;
                                                                                                }
                                                                                                if(currentValue == thisValue) {
                                                                                                        list.AddItem(pTechno);
                                                                                                }
                                                                                        }
                                                                                }
                                                                        }
                                                                }
                                                        }
                                                        if(list.Count) {
                                                                int rnd = ScenarioClass::Instance->Random.RandomRanged(0, list.Count - 1);
                                                                Cell = list.GetItem(rnd)->GetCell()->MapCoords;
                                                                LaunchSW(&Cell);
                                                        }
                                                        break;
                                                }

                                        case SuperWeaponAITargetingMode::Base:
                                                {
                                                        // fire at the SW's owner's base cell
                                                        Cell = pThis->Base_Center();
                                                        LaunchSW(&Cell);
                                                        break;
                                                }

                                        case SuperWeaponAITargetingMode::Self:
                                                {
                                                        // find the first building providing pSuper
                                                        SuperWeaponTypeClass *pType = pSuper->Type;
                                                        BuildingClass *pBld = NULL;
                                                        for(int j=0; j<BuildingTypeClass::Array->Count; ++j) {
                                                                BuildingTypeClass *pTBld = BuildingTypeClass::Array->GetItem(j);
                                                                if((pTBld->SuperWeapon == pType->ArrayIndex) || (pTBld->SuperWeapon2 == pType->ArrayIndex)) {
                                                                        if((pBld = pThis->FindBuildingOfType(pTBld->ArrayIndex, -1)) != NULL) {
                                                                                break;
                                                                        }
                                                                }
                                                        }
                                                        if(pBld) {
                                                                Cell = pBld->GetCell()->MapCoords;
                                                                LaunchSW(&Cell);
                                                        }

                                                        break;
                                                }
                                        }
                                }
                        }
                }
        }

        return 0x509AE7;
}
DEFINE_HOOK ( 6CC2B0  ,
SuperClass_NameReadiness  ,
 
)
                                                 {
        GET(SuperClass*, pThis, ECX);
        SuperWeaponTypeClass *pSW = pThis->Type;
        SWTypeExt::ExtData *pData = SWTypeExt::ExtMap.Find(pSW);

        // complete rewrite of this method.

        char* key = pData->Text_Preparing;
        if(pThis->IsOnHold) {
                // on hold
                key = pData->Text_Hold;
        } else {
                if(pThis->Type->UseChargeDrain) {
                        switch(pThis->ChargeDrainState) {
                        case 0:
                                // still charging
                                key = pData->Text_Charging;
                                break;
                        case 1:
                                // ready
                                key = pData->Text_Ready;
                                break;
                        case 2:
                                // currently active
                                key = pData->Text_Active;
                                break;
                        }

                } else {
                        // ready
                        if(pThis->IsCharged) {
                                key = pData->Text_Ready;
                        }
                }
        }

        const wchar_t* text = NULL;
        if(key && *key) {
                text = StringTable::LoadStringA(key);
                if(text && !*text) {
                        text = NULL;
                }
        }
        R->EAX(text);
        return 0x6CC352;
}
DEFINE_HOOK ( 4FAE72  ,
HouseClass_SWFire_PreDependent  ,
 
)
{
        GET(HouseClass*, pThis, EBX);

        // find the predependent SW. decouple this from the chronosphere.
        // don't use a fixed SW type but the very one acutually fired last.
        SuperClass* pSource = NULL;
        if(HouseExt::ExtData *pExt = HouseExt::ExtMap.Find(pThis)) {
                if(pThis->Supers.ValidIndex(pExt->SWLastIndex)) {
                        pSource = pThis->Supers.GetItem(pExt->SWLastIndex);
                }
        }

        R->ESI(pSource);

        return 0x4FAE7B;
}
DEFINE_HOOK ( 4576BA  ,
BuildingClass_SW2Available  ,
 
)
{
        GET(BuildingClass *, Structure, ESI);
        GET(BuildingTypeClass *, AuxBuilding, EAX);
        return Structure->Owner->CountOwnedAndPresent(AuxBuilding) > 0
                ? 0x4576DB
                : 0x4576D6
        ;
}
DEFINE_HOOK ( 45765A  ,
BuildingClass_SWAvailable  ,
 
)
{
        GET(BuildingClass *, Structure, ESI);
        GET(BuildingTypeClass *, AuxBuilding, EAX);
        return Structure->Owner->CountOwnedAndPresent(AuxBuilding) > 0
                ? 0x45767B
                : 0x457676
        ;
}
DEFINE_HOOK ( 44691B  ,
BuildingClass_4DC_SWAvailable  ,
 
)
{
        GET(BuildingClass *, Structure, EBP);
        GET(BuildingTypeClass *, AuxBuilding, EAX);
        return Structure->Owner->CountOwnedAndPresent(AuxBuilding) > 0
                ? 0x446937
                : 0x44699A
        ;
}
DEFINE_HOOK ( 6CC390  ,
SuperClass_Launch  ,
 
)
{
        GET(SuperClass *, pSuper, ECX);
        GET_STACK(CellStruct*, pCoords, 0x4);
        GET_STACK(byte, IsPlayer, 0x8);

        SWTypeExt::ExtData *pData = SWTypeExt::ExtMap.Find(pSuper->Type);

        Debug::Log("[LAUNCH] %s\n", pSuper->Type->ID);

        bool handled = false;
        if(NewSWType* pNSW = pData->GetNewSWType()) {
                handled = SWTypeExt::Launch(pSuper, pNSW, pCoords, IsPlayer);
        }

        return handled ? 0x6CDE40 : 0;
}
DEFINE_HOOK ( 6CBA9E  ,
SuperClass_ClickFire_Abort  ,
 
)
{
        GET(SuperClass *, pSuper, ESI);
        SuperWeaponTypeClass* pType = pSuper->Type;
        SWTypeExt::ExtData *pData = SWTypeExt::ExtMap.Find(pType);

        GET_STACK(bool, IsPlayer, 0x20);

        // auto-abort if no money
        if(pData->Money_Amount < 0) {
                if(pSuper->Owner->Available_Money() < -pData->Money_Amount.Get()) {
                        if(pSuper->Owner == HouseClass::Player) {
                                VoxClass::PlayIndex(pData->EVA_InsufficientFunds);
                                pData->PrintMessage(pData->Message_InsufficientFunds, pSuper->Owner);
                        }
                        return 0x6CBABF;
                }
        }

        // can this super weapon fire now?
        if(NewSWType* pNSW = pData->GetNewSWType()) {
                if(pNSW->AbortFire(pSuper, IsPlayer)) {
                        return 0x6CBABF;
                }
        }

        return 0;
}
DEFINE_HOOK ( 50CFAA  ,
HouseClass_PickOffensiveSWTarget  ,
 
)
{
        R->ESI(0);
        R->Stack8(0x13, 1);
        return 0x50CFC9;
}
DEFINE_HOOK ( 50B319  ,
HouseClass_UpdateSWs_ShowCameo  ,
 
)
{
        GET(HouseClass *, H, EBP);
        GET(int, Index, EDI);
        SuperClass *Super = H->Supers.GetItem(Index);
        SuperWeaponTypeClass *pSW = Super->Type;

        if(SWTypeExt::ExtData *pData = SWTypeExt::ExtMap.Find(pSW)) {
                if(pData->SW_AutoFire.Get() && !pData->SW_ShowCameo.Get()) {
                        return 0x50B358;
                }
        }

        return 0;
}
DEFINE_HOOK ( 6CC0EA  ,
SuperClass_AnnounceQuantity  ,
 
)
{
        GET(SuperClass *, pThis, ESI);
        SuperWeaponTypeClass *pSW = pThis->Type;
        SWTypeExt::ExtData *pData = SWTypeExt::ExtMap.Find(pSW);

        pData->PrintMessage(pData->Message_Ready, HouseClass::Player);

        if(pData->EVA_Ready != -1 || pData->HandledByNewSWType != -1) {
                if(pData->EVA_Ready != -1) {
                        VoxClass::PlayIndex(pData->EVA_Ready);
                }
                return 0x6CC17E;
        }
        return 0;
}
DEFINE_HOOK ( 6CBDD7  ,
SuperClass_AnnounceReady  ,
 
)
{
        GET(SuperWeaponTypeClass *, pThis, EAX);
        SWTypeExt::ExtData *pData = SWTypeExt::ExtMap.Find(pThis);

        pData->PrintMessage(pData->Message_Ready, HouseClass::Player);

        if(pData->EVA_Ready != -1 || pData->HandledByNewSWType != -1) {
                if(pData->EVA_Ready != -1) {
                        VoxClass::PlayIndex(pData->EVA_Ready);
                }
                return 0x6CBE68;
        }
        return 0;
}
DEFINE_HOOK ( 446937  ,
BuildingClass_AnnounceSW  ,
 
)
{
        GET(BuildingClass *, pBuild, EBP);
        int swTIdx = pBuild->Type->SuperWeapon;
        if(swTIdx == -1) {
                swTIdx = pBuild->Type->SuperWeapon2;
                if(swTIdx == -1) {
                        return 0x44699A;
                }
        }

        SuperWeaponTypeClass *pSW = SuperWeaponTypeClass::Array->GetItem(swTIdx);
        SWTypeExt::ExtData *pData = SWTypeExt::ExtMap.Find(pSW);

        pData->PrintMessage(pData->Message_Detected, pBuild->Owner);

        if(pData->EVA_Detected != -1 || pData->HandledByNewSWType != -1) {
                if(pData->EVA_Detected != -1) {
                        VoxClass::PlayIndex(pData->EVA_Detected);
                }
                return 0x44699A;
        }
        return 0;
}
DEFINE_HOOK ( 451132  ,
BuildingClass_ProcessAnims2  ,
 
)
{
        return 0x451145;
}
DEFINE_HOOK ( 45100A  ,
BuildingClass_ProcessAnims1  ,
 
)
{
        GET(BuildingClass *, pBuild, ESI);
        GET(HouseClass *, pHouse, EAX);
        int swTIdx = pBuild->Type->SuperWeapon;
        if(swTIdx == -1) {
                swTIdx = pBuild->Type->SuperWeapon2;
                if(swTIdx == -1) {
                        return 0x451145;
                }
        }

        R->EDI(pBuild->Type);
        R->EAX(pHouse->Supers.GetItem(swTIdx));
        return 0x451030;
}
DEFINE_HOOK ( 44656D  ,
BuildingClass_Place2  ,
 
)
{
        return 0x446580;
}
DEFINE_HOOK ( 446418  ,
BuildingClass_Place1  ,
 
)
{
        GET(BuildingClass *, pBuild, EBP);
        GET(HouseClass *, pHouse, EAX);
        int swTIdx = pBuild->Type->SuperWeapon;
        if(swTIdx == -1) {
                swTIdx = pBuild->Type->SuperWeapon2;
                if(swTIdx == -1) {
                        return 0x446580;
                }
        }

        R->EAX(pHouse->Supers.GetItem(swTIdx));
        return 0x44643E;
}
DEFINE_HOOK ( 4AC20C  ,
DisplayClass_LMBUp  ,
 
)
{
        int Action = R->Stack32(0x9C);
        if(Action < SW_NO_CURSOR) {
                // get the actual firing SW type instead of just the first type of the
                // requested action. this allows clones to work for legacy SWs (the new
                // ones use SW_*_CURSORs). we have to check that the action matches the
                // action of the found type as the no-cursor represents a different
                // action and we don't want to start a force shield even tough the UI
                // says no.
                SuperWeaponTypeClass * pSW = NULL;
                if(SuperWeaponTypeClass::Array->ValidIndex(Unsorted::CurrentSWType)) {
                        pSW = SuperWeaponTypeClass::Array->GetItem(Unsorted::CurrentSWType);
                        if(pSW && (pSW->Action != Action)) {
                                pSW = NULL;
                        }
                }

                R->EAX(pSW);
                return pSW ? 0x4AC21C : 0x4AC294;
        }
        else if(Action == SW_NO_CURSOR) {
                R->EAX(0);
                return 0x4AC294;
        }

        R->EAX(SWTypeExt::CurrentSWType);
        return 0x4AC21C;
}
DEFINE_HOOK ( 6CEE96  ,
SuperWeaponTypeClass_GetTypeIndex  ,
 
)
{
        GET(const char *, TypeStr, EDI);
        int customType = NewSWType::FindIndex(TypeStr);
        if(customType > -1) {
                R->ESI(customType);
                return 0x6CEE9C;
        }
        return 0;
}
DEFINE_HOOK ( 6A932B  ,
CameoClass_GetTip_MoneySW  ,
 
)
                                                  {
        GET(SuperWeaponTypeClass*, pSW, EAX);

        if(SWTypeExt::ExtData *pData = SWTypeExt::ExtMap.Find(pSW)) {
                if(pData->Money_Amount < 0) {
                        wchar_t* pTip = (wchar_t*)0xB07BC4;

                        // account for no-name SWs
                        if(*(byte*)0x884B8C || !wcslen(pSW->UIName)) {
                                const wchar_t* pFormat = StringTable::LoadStringA("TXT_MONEY_FORMAT_1");
                                swprintf(pTip, 0x20, pFormat, -pData->Money_Amount.Get());
                        } else {
                                // then, this must be brand SWs
                                const wchar_t* pFormat = StringTable::LoadStringA("TXT_MONEY_FORMAT_2");
                                swprintf(pTip, 0x20, pFormat, pSW->UIName, -pData->Money_Amount.Get());
                        }

                        // replace space by new line
                        for(int i=wcslen(pTip); i>=0; --i) {
                                if(pTip[i] == 0x20) {
                                        pTip[i] = 0xA;
                                        break;
                                }
                        }

                        // put it there
                        R->EAX(pTip);
                        return 0x6A93E5;
                }
        }

        return 0;
}
DEFINE_HOOK ( 6AAEDF  ,
SidebarClass_ProcessCameoClick_SuperWeapons  ,
 
)
                                                                    {
        GET(int, idxSW, ESI);
        SuperClass* pSuper = HouseClass::Player->Supers.GetItem(idxSW);

        if(SWTypeExt::ExtData* pData = SWTypeExt::ExtMap.Find(pSuper->Type)) {
                // if this SW is only auto-firable, discard any clicks.
                // if AutoFire is off, the sw would not be firable at all,
                // thus we ignore the setting in that case.
                bool manual = !pData->SW_ManualFire.Get() && pData->SW_AutoFire.Get();
                bool unstoppable = pSuper->Type->UseChargeDrain && pSuper->ChargeDrainState == 2
                        && pData->SW_Unstoppable.Get();

                // play impatient voice, if this isn't charged yet
                if(!pSuper->CanFire() && !manual) {
                        VoxClass::PlayIndex(pData->EVA_Impatient);
                        return 0x6AAFB1;
                }

                // prevent firing the SW if the player doesn't have sufficient
                // funds. play an EVA message in that case.
                if(pData->Money_Amount < 0) {
                        if(HouseClass::Player->Available_Money() < -pData->Money_Amount.Get()) {
                                VoxClass::PlayIndex(pData->EVA_InsufficientFunds);
                                pData->PrintMessage(pData->Message_InsufficientFunds, HouseClass::Player);
                                return 0x6AAFB1;
                        }
                }
                
                // disallow manuals and active unstoppables
                if(manual || unstoppable) {
                        return 0x6AAFB1;
                }

                return 0x6AAEF7;
        }

        return 0;
}
DEFINE_HOOK ( 653B3A  ,
RadarClass_GetMouseAction_CustomSWAction  ,
 
)
{
        int idxSWType = Unsorted::CurrentSWType;
        if(idxSWType > -1) {
                GET_STACK(byte, EventFlags, 0x58);

                MouseEvent::Value E(EventFlags);
                if(E & (MouseEvent::RightDown | MouseEvent::RightUp)) {
                        return 0x653D6F;
                }

                SuperWeaponTypeClass *pThis = SuperWeaponTypeClass::Array->GetItem(idxSWType);
                SWTypeExt::ExtData *pData = SWTypeExt::ExtMap.Find(pThis);
                int type = (pData->HandledByNewSWType > -1) ? pData->HandledByNewSWType : pThis->Type;
                bool customType = (type >= FIRST_SW_TYPE);

                if((pThis->Action == SW_YES_CURSOR) || customType) {
                        GET_STACK(CellStruct, pMapCoords, STACK_OFFS(0x54, 0x3C));

                        int Action = SW_YES_CURSOR;

                        // prevent firing into shroud
                        if(!pData->SW_FireToShroud.Get()) {
                                CellClass* pCell = MapClass::Instance->GetCellAt(&pMapCoords);
                                CoordStruct Crd;

                                if(MapClass::Instance->IsLocationShrouded(pCell->GetCoords(&Crd))) {
                                        Action = SW_NO_CURSOR;
                                }
                        }

                        // new SW types have to check whether the coordinates are valid.
                        if(Action == SW_YES_CURSOR) {
                                if(customType && !NewSWType::GetNthItem(type)->CanFireAt(pData, &pMapCoords)) {
                                        Action = SW_NO_CURSOR;
                                }
                        }

                        R->ESI(Action);

                        if(Action == SW_YES_CURSOR) {
                                SWTypeExt::CurrentSWType = pThis;
                                Actions::Set(&pData->SW_Cursor, pData->SW_FireToShroud.Get());
                        } else {
                                SWTypeExt::CurrentSWType = NULL;
                                Actions::Set(&pData->SW_NoCursor, pData->SW_FireToShroud.Get());
                        }
                        return 0x653CA3;
                }
        }
        return 0;
}
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines