Ares
Public Member Functions | Public Attributes

WarheadTypeExt::ExtData Class Reference

#include <src/Ext/WarheadType/Body.h>

Inheritance diagram for WarheadTypeExt::ExtData:
Extension< TT >

List of all members.

Public Member Functions

 ExtData (const DWORD Canary, TT *const OwnerObject)
virtual ~ExtData ()
virtual size_t Size () const
virtual void Initialize (TT *pThis)
virtual void LoadFromINIFile (TT *pThis, CCINIClass *pINI)
virtual void InvalidatePointer (void *ptr)
void applyRipples (CoordStruct *)
void applyIronCurtain (CoordStruct *, HouseClass *, int)
void applyEMP (CoordStruct *, TechnoClass *)
bool applyPermaMC (CoordStruct *, HouseClass *, ObjectClass *)
bool applyKillDriver (BulletClass *)

Public Attributes

bool MindControl_Permanent
int Ripple_Radius
int EMP_Duration
int EMP_Cap
int IC_Duration
int IC_Cap
DynamicVectorClass< VersesDataVerses
double DeployedDamage
Customizable< AnimTypeClass * > Temporal_WarpAway
bool AffectsEnemies
Valueable< AnimTypeClass * > InfDeathAnim
ValueableIdx< int, AnimTypeClass > PreImpactAnim
bool KillDriver
 Whether this warhead turns the target vehicle over to the special side ("kills the driver"). Request #733.
Valueable< bool > Malicious

Constructor & Destructor Documentation

WarheadTypeExt::ExtData::ExtData ( const DWORD  Canary,
TT *const  OwnerObject 
) [inline]
                                                                   : Extension<TT>(Canary, OwnerObject),
                        MindControl_Permanent (false),
                        Ripple_Radius (0),
                        EMP_Duration (0),
                        EMP_Cap (-1),
                        IC_Duration (0),
                        IC_Cap (-1),
                        DeployedDamage (1.00),
                        Temporal_WarpAway (&RulesClass::Global()->WarpAway),
                        AffectsEnemies (true),
                        InfDeathAnim (NULL),
                        PreImpactAnim (-1),
                        KillDriver (false),
                        Malicious (true)
                        {
                                for(int i = 0; i < 11; ++i) {
                                        VersesData vs;
                                        Verses.AddItem(vs);
                                }
                        };
virtual WarheadTypeExt::ExtData::~ExtData ( ) [inline, virtual]
{ };

Member Function Documentation

void WarheadTypeExt::ExtData::applyEMP ( CoordStruct *  coords,
TechnoClass *  source 
)

This function checks if the passed warhead has EMP.Duration set, and, if so, applies the effect.

Note:
Moved here from hook BulletClass_Fire.
Parameters:
coordsThe coordinates of the warhead impact, the center of the EMP area.
                                                                             {
        if (this->EMP_Duration) {
                // launch our rewritten EMP.
                EMPulse::CreateEMPulse(this, coords, source);
        }
}
void WarheadTypeExt::ExtData::applyIronCurtain ( CoordStruct *  coords,
HouseClass *  Owner,
int  damage 
)

This function checks if the passed warhead has IronCurtain.Duration set, and, if so, applies the effect.

Units will be damaged before the Iron Curtain gets effective. AffectAllies and AffectEnemies are respected. Verses support is limited: If it is 0%, the unit won't get affected, otherwise, it will be 100% affected.

Note:
Moved here from hook BulletClass_Fire.
Parameters:
coordsThe coordinates of the warhead impact, the center of the Iron Curtain area.
OwnerOwner of the Iron Curtain effect, i.e. the one triggering this.
damageThe damage the firing weapon deals before the Iron Curtain effect starts.
Date:
2010-06-28
                                                                                               {
        CellStruct cellCoords = MapClass::Instance->GetCellAt(coords)->MapCoords;

        if(this->IC_Duration != 0) {
                // set of affected objects. every object can be here only once.
                DynamicVectorClass<TechnoClass*> *items = Helpers::Alex::getCellSpreadItems(coords,
                        this->AttachedToObject->CellSpread, true);

                // affect each object
                for(int i=0; i<items->Count; ++i) {
                        if(TechnoClass *curTechno = items->GetItem(i)) {

                                // don't protect the dead
                                if(curTechno->InLimbo || !curTechno->IsAlive || !curTechno->Health) {
                                        continue;
                                }

                                // affects enemies or allies respectively?
                                if(WarheadTypeExt::canWarheadAffectTarget(curTechno, Owner, this->AttachedToObject)) {

                                        // duration modifier
                                        int duration = this->IC_Duration;

                                        // modify good durations only
                                        if(duration > 0) {
                                                if(TechnoTypeExt::ExtData *pData = TechnoTypeExt::ExtMap.Find(curTechno->GetTechnoType())) {
                                                        duration = (int)(duration * pData->IC_Modifier);
                                                }
                                        }

                                        // respect verses the boolean way
                                        if(abs(this->Verses[curTechno->GetTechnoType()->Armor].Verses) < 0.001) {
                                                continue;
                                        }

                                        // get the values
                                        int oldValue = (curTechno->IronCurtainTimer.Ignorable() ? 0 : curTechno->IronCurtainTimer.GetTimeLeft());
                                        int newValue = Helpers::Alex::getCappedDuration(oldValue, duration, this->IC_Cap);

                                        // update iron curtain
                                        if(oldValue <= 0) {
                                                // start iron curtain effect?
                                                if(newValue > 0) {
                                                        // damage the victim before ICing it
                                                        if(damage) {
                                                                curTechno->ReceiveDamage(&damage, 0, this->AttachedToObject, NULL, true, false, Owner);
                                                        }

                                                        // unit may be destroyed already.
                                                        if(curTechno->IsAlive) {
                                                                // start and prevent the multiplier from being applied twice
                                                                curTechno->IronCurtain(newValue, Owner, false);
                                                                curTechno->IronCurtainTimer.Start(newValue);
                                                        }
                                                }
                                        } else {
                                                // iron curtain effect is already on.
                                                if(newValue > 0) {
                                                        // set new length and reset tint stage
                                                        curTechno->IronCurtainTimer.Start(newValue);
                                                        curTechno->IronTintStage = 4;
                                                } else {
                                                        // turn iron curtain off
                                                        curTechno->IronCurtainTimer.Stop();
                                                }
                                        }
                                }
                        }
                }

                items->Clear();
                delete items;
        }
}
bool WarheadTypeExt::ExtData::applyKillDriver ( BulletClass *  Bullet)

This function checks if the KillDriver effect should be applied, and, if so, applies it.

Parameters:
BulletPointer to the bullet
Returns:
true if the effect was applied, false if not
Author:
Renegade & AlexB
Date:
05.04.10
Todo:
This needs to be refactored to work with the generic warhead SW. I want to create a generic cellspread function first.
                                                               {
        if(!Bullet->Target || !this->KillDriver) {
                return false;
        } else if(FootClass *pTarget = generic_cast<FootClass *>(Bullet->Target)) {
                // don't penetrate the Iron Curtain // typedef IronCurtain ChastityBelt
                if(pTarget->IsIronCurtained()) {
                        return false;
                }
                TechnoTypeClass *pTargetType = pTarget->GetTechnoType();
                TechnoTypeExt::ExtData* TargetTypeExt = TechnoTypeExt::ExtMap.Find(pTargetType);

                // conditions: Warhead is KillDriver, target is Vehicle or Aircraft, but not protected and not a living being
                if(((pTarget->WhatAmI() == abs_Unit) || (pTarget->WhatAmI() == abs_Aircraft))
                        && !(pTarget->BeingWarpedOut || TargetTypeExt->ProtectedDriver || pTargetType->Organic || pTargetType->Natural)) {

                        // if this aircraft is expected to dock to anything, don't allow killing its pilot
                        // (reason being: the game thinks you lost the aircraft that just turned, and assumes you have free aircraft space,
                        // allowing you to build more aircraft, for the docking spot that is still occupied by the previous plane.)
                        if(AircraftClass * pTargetAircraft = specific_cast<AircraftClass *>(pTarget)) { // relying on short-circuit evaluation here - nest this if necessary
                                if(pTargetAircraft->Type->AirportBound || pTargetAircraft->Type->Dock.Count) {
                                        return false;
                                }
                        }

                        // If this vehicle uses Operator=, we have to take care of actual "physical" drivers, rather than theoretical ones
                        FootClass *passenger = NULL;
                        if(TargetTypeExt->IsAPromiscuousWhoreAndLetsAnyoneRideIt && (passenger = pTarget->RemoveFirstPassenger())) {
                                // kill first passenger
                                passenger->RegisterDestruction(Bullet->Owner);
                                passenger->UnInit();

                        } else if(TargetTypeExt->Operator) {
                                // find the driver cowardly hiding among the passengers, then kill him
                                for(passenger = pTarget->Passengers.FirstPassenger; passenger; passenger = generic_cast<FootClass*>(passenger->NextObject)) {
                                        if(passenger->GetTechnoType() == TargetTypeExt->Operator) {
                                                pTarget->RemovePassenger(passenger);
                                                passenger->RegisterDestruction(Bullet->Owner);
                                                passenger->UnInit();
                                                break;
                                        }
                                }
                        }

                        // if passengers remain in the vehicle, operator-using or not, they should leave
                        if(pTarget->Passengers.NumPassengers) {
                                TechnoExt::EjectPassengers(pTarget, -1);
                        }

                        // If this unit is driving under influence, we have to free it first
                        if(TechnoClass *Controller = pTarget->MindControlledBy) {
                                if(CaptureManagerClass *MC = Controller->CaptureManager) {
                                        MC->FreeUnit(pTarget);
                                }
                        }

                        // If this unit mind controls stuff, we should free the controllees, since they still belong to the previous owner
                        if(pTarget->CaptureManager) {
                                pTarget->CaptureManager->FreeAll();
                        }

                        // This unit will be freed of its duties
                        if(FootClass * pFoot = generic_cast<FootClass *>(pTarget)) {
                                if(pFoot->BelongsToATeam()) {
                                        pFoot->Team->LiberateMember(pFoot);
                                }
                        }

                        // If this unit spawns stuff, we should kill the spawns, since they still belong to the previous owner
                        if(pTarget->SpawnManager) {
                                pTarget->SpawnManager->KillNodes();
                                pTarget->SpawnManager->Target = NULL;
                                pTarget->SpawnManager->Destination = NULL;
                        }

                        // If this unit enslaves stuff, we should free the slaves, since they still belong to the previous owner
                        // <DCoder> SlaveManagerClass::Killed() sets the manager's Owner to NULL
                        // <Renegade> okay, does Killed() also destroy the slave manager, or just unlink it from the unit?
                        // <DCoder> unlink
                        // <Renegade> so on principle, I could just re-link it?
                        // <DCoder> yes you can
                        if(SlaveManagerClass * pSlaveManager = pTarget->SlaveManager) {
                                pSlaveManager->Killed(Bullet->Owner);
                                pSlaveManager->ZeroOutSlaves();
                                pTarget->SlaveManager->Owner = pTarget;
                        }

                        // Hand over to Civilian/Special house
                        pTarget->SetOwningHouse(HouseClass::FindByCountryIndex(HouseTypeClass::FindIndexOfName("Special")));
                        pTarget->QueueMission(mission_Sticky, true);
                        return true;
                } else {
                        return false;
                }
        }
        return false;
}
bool WarheadTypeExt::ExtData::applyPermaMC ( CoordStruct *  coords,
HouseClass *  Owner,
ObjectClass *  Target 
)

This function checks if the passed warhead has MindControl.Permanent set, and, if so, applies the effect.

Note:
Moved here from hook BulletClass_Fire.
Parameters:
coordsThe coordinates of the warhead impact, the center of the Mind Control animation.
OwnerOwner of the Mind Control effect, i.e. the one controlling the target afterwards.
TargetTarget of the Mind Control effect, i.e. the one being controlled by the owner afterwards.
Returns:
false if effect wasn't applied, true if it was. This is important for the chain of damage effects, as, in case of true, the target is now a friendly unit.
                                                                                                    {
        if (this->MindControl_Permanent && Target) {
                if (TechnoClass *pTarget = generic_cast<TechnoClass *>(Target)) {
                        TechnoTypeClass *pType = pTarget->GetTechnoType();

                        if (!pType || pType->ImmuneToPsionics) {
                                return false; // should return 0 in hook
                        }
                        if (pTarget->MindControlledBy) {
                                pTarget->MindControlledBy->CaptureManager->FreeUnit(pTarget);
                        }
                        pTarget->SetOwningHouse(Owner, 1);
                        pTarget->MindControlledByAUnit = 1;
                        pTarget->QueueMission(mission_Guard, 0);

                        CoordStruct XYZ = *coords;
                        XYZ.Z += pType->MindControlRingOffset;

                        AnimClass *MCAnim;
                        GAME_ALLOC(AnimClass, MCAnim, RulesClass::Instance->PermaControlledAnimationType, &XYZ);
                        AnimClass *oldMC = pTarget->MindControlRingAnim;
                        if (oldMC) {
                                oldMC->UnInit();
                        }
                        pTarget->MindControlRingAnim = MCAnim;
                        MCAnim->SetOwnerObject(pTarget);
                        return true; // should return 0x469AA4 in hook
                }
        }
        return false;
}
void WarheadTypeExt::ExtData::applyRipples ( CoordStruct *  coords)

This function checks if the passed warhead has Ripple.Radius set, and, if so, applies the effect.

Note:
Moved here from hook BulletClass_Fire.
Parameters:
coordsThe coordinates of the warhead impact, the center of the Ripple area.
                                                            {
        if (this->Ripple_Radius) {
                IonBlastClass *IB;
                GAME_ALLOC(IonBlastClass, IB, *coords);
                WarheadTypeExt::IonExt[IB] = this;
        }
}
void WarheadTypeExt::ExtData::Initialize ( TT pThis) [virtual]
                                                              {
        if(!_strcmpi(pThis->ID, "NUKE")) {
                this->PreImpactAnim = AnimTypeClass::FindIndex("NUKEBALL");
        }
}
virtual void WarheadTypeExt::ExtData::InvalidatePointer ( void *  ptr) [inline, virtual]

Implements Extension< TT >.

                                                          {
                }
void WarheadTypeExt::ExtData::LoadFromINIFile ( TT pThis,
CCINIClass *  pINI 
) [virtual]
{
        const char * section = pThis->ID;

        INI_EX exINI(pINI);

        if(!pINI->GetSection(section)) {
                return;
        }

        // writing custom verses parser just because
        if(pINI->ReadString(section, "Verses", "", Ares::readBuffer, Ares::readLength)) {
                int idx = 0;
                for(char *cur = strtok(Ares::readBuffer, ","); cur; cur = strtok(NULL, ",")) {
                        this->Verses[idx].Parse(cur);
                        ++idx;
                        if(idx > 10) {
                                break;
                        }
                }
        }

        ArmorType::LoadForWarhead(pINI, pThis);

        if(pThis->MindControl) {
                this->MindControl_Permanent = pINI->ReadBool(section, "MindControl.Permanent", this->MindControl_Permanent);
        }

        this->EMP_Duration = pINI->ReadInteger(section, "EMP.Duration", this->EMP_Duration);
        this->EMP_Cap = pINI->ReadInteger(section, "EMP.Cap", this->EMP_Cap);

        this->IC_Duration = pINI->ReadInteger(section, "IronCurtain.Duration", this->IC_Duration);
        this->IC_Cap = pINI->ReadInteger(section, "IronCurtain.Cap", this->IC_Cap);

        if(pThis->Temporal) {
                this->Temporal_WarpAway.Parse(&exINI, section, "Temporal.WarpAway");
        }

        this->DeployedDamage = pINI->ReadDouble(section, "Damage.Deployed", this->DeployedDamage);

        this->Ripple_Radius = pINI->ReadInteger(section, "Ripple.Radius", this->Ripple_Radius);

        this->AffectsEnemies = pINI->ReadBool(section, "AffectsEnemies", this->AffectsEnemies);

        this->InfDeathAnim.Parse(&exINI, section, "InfDeathAnim");
        
        this->PreImpactAnim.Read(&exINI, pThis->ID, "PreImpactAnim");

        this->KillDriver = pINI->ReadBool(section, "KillDriver", this->KillDriver);

        this->Malicious.Read(&exINI, section, "Malicious");
};
virtual size_t WarheadTypeExt::ExtData::Size ( ) const [inline, virtual]

Implements Extension< TT >.

{ return sizeof(*this); };

Member Data Documentation

Whether this warhead turns the target vehicle over to the special side ("kills the driver"). Request #733.


The documentation for this class was generated from the following files:
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines