Ares
|
#include <src/Ext/WarheadType/Body.h>
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< VersesData > | Verses |
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 |
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] |
{ };
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.
coords | The 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.
coords | The coordinates of the warhead impact, the center of the Iron Curtain area. |
Owner | Owner of the Iron Curtain effect, i.e. the one triggering this. |
damage | The damage the firing weapon deals before the Iron Curtain effect starts. |
{ 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.
Bullet | Pointer to the bullet |
{ 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.
coords | The coordinates of the warhead impact, the center of the Mind Control animation. |
Owner | Owner of the Mind Control effect, i.e. the one controlling the target afterwards. |
Target | Target of the Mind Control effect, i.e. the one being controlled by the owner afterwards. |
{ 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.
coords | The 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); };
Valueable<AnimTypeClass*> WarheadTypeExt::ExtData::InfDeathAnim |
Whether this warhead turns the target vehicle over to the special side ("kills the driver"). Request #733.
ValueableIdx<int, AnimTypeClass> WarheadTypeExt::ExtData::PreImpactAnim |
Customizable<AnimTypeClass *> WarheadTypeExt::ExtData::Temporal_WarpAway |
DynamicVectorClass<VersesData> WarheadTypeExt::ExtData::Verses |