/*
** Command & Conquer Generals Zero Hour(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ParkingPlaceBehavior.h /////////////////////////////////////////////////////////////////////////
// Author: Steven Johnson, June 2002
// Desc:
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __ParkingPlaceBehavior_H_
#define __ParkingPlaceBehavior_H_
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "GameLogic/Module/BehaviorModule.h"
#include "GameLogic/Module/DieModule.h"
#include "GameLogic/Module/UpdateModule.h"
//-------------------------------------------------------------------------------------------------
class ParkingPlaceBehaviorModuleData : public UpdateModuleData
{
public:
//UnsignedInt m_framesForFullHeal;
Real m_healAmount;
// Real m_extraHealAmount4Helicopters;
Int m_numRows;
Int m_numCols;
Real m_approachHeight;
Real m_landingDeckHeightOffset;
Bool m_hasRunways; // if true, each col has a runway in front of it
Bool m_parkInHangars; // if true, park at the hangar production spot, not the "real" parking place
ParkingPlaceBehaviorModuleData()
{
//m_framesForFullHeal = 0;
m_healAmount = 0;
// m_extraHealAmount4Helicopters = 0;
m_numRows = 0;
m_numCols = 0;
m_approachHeight = 0.0f;
m_landingDeckHeightOffset = 0.0f;
m_hasRunways = false;
m_parkInHangars = false;
}
static void buildFieldParse(MultiIniFieldParse& p)
{
UpdateModuleData::buildFieldParse(p);
static const FieldParse dataFieldParse[] =
{
{ "NumRows", INI::parseInt, NULL, offsetof( ParkingPlaceBehaviorModuleData, m_numRows ) },
{ "NumCols", INI::parseInt, NULL, offsetof( ParkingPlaceBehaviorModuleData, m_numCols ) },
{ "ApproachHeight", INI::parseReal, NULL, offsetof( ParkingPlaceBehaviorModuleData, m_approachHeight ) },
{ "LandingDeckHeightOffset", INI::parseReal, NULL, offsetof( ParkingPlaceBehaviorModuleData, m_landingDeckHeightOffset ) },
{ "HasRunways", INI::parseBool, NULL, offsetof( ParkingPlaceBehaviorModuleData, m_hasRunways ) },
{ "ParkInHangars", INI::parseBool, NULL, offsetof( ParkingPlaceBehaviorModuleData, m_parkInHangars ) },
{ "HealAmountPerSecond", INI::parseReal, NULL, offsetof( ParkingPlaceBehaviorModuleData, m_healAmount ) },
// { "ExtraHealAmount4Helicopters", INI::parseReal, NULL, offsetof( ParkingPlaceBehaviorModuleData, m_extraHealAmount4Helicopters ) },
//{ "TimeForFullHeal", INI::parseDurationUnsignedInt, NULL, offsetof( ParkingPlaceBehaviorModuleData, m_framesForFullHeal ) },
{ 0, 0, 0, 0 }
};
p.add(dataFieldParse);
}
private:
};
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
class ParkingPlaceBehavior : public UpdateModule,
public DieModuleInterface,
public ParkingPlaceBehaviorInterface,
public ExitInterface
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( ParkingPlaceBehavior, "ParkingPlaceBehavior" )
MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA( ParkingPlaceBehavior, ParkingPlaceBehaviorModuleData )
public:
ParkingPlaceBehavior( Thing *thing, const ModuleData* moduleData );
// virtual destructor prototype provided by memory pool declaration
static Int getInterfaceMask() { return UpdateModule::getInterfaceMask() | (MODULEINTERFACE_DIE); }
// BehaviorModule
virtual DieModuleInterface *getDie( void ) { return this; }
virtual ParkingPlaceBehaviorInterface* getParkingPlaceBehaviorInterface() { return this; }
virtual ExitInterface* getUpdateExitInterface() { return this; }
// ExitInterface
virtual Bool isExitBusy() const {return FALSE;} ///< Contain style exiters are getting the ability to space out exits, so ask this before reserveDoor as a kind of no-commitment check.
virtual ExitDoorType reserveDoorForExit( const ThingTemplate* objType, Object *specificObject );
virtual void exitObjectViaDoor( Object *newObj, ExitDoorType exitDoor );
virtual void unreserveDoorForExit( ExitDoorType exitDoor );
virtual void exitObjectByBudding( Object *newObj, Object *budHost ) { return; }
virtual Bool getExitPosition( Coord3D& rallyPoint ) const;
virtual Bool getNaturalRallyPoint( Coord3D& rallyPoint, Bool offset = TRUE ) const;
virtual void setRallyPoint( const Coord3D *pos ); ///< define a "rally point" for units to move towards
virtual const Coord3D *getRallyPoint( void ) const; ///< define a "rally point" for units to move towards
// UpdateModule
virtual UpdateSleepTime update();
// DieModule
virtual void onDie( const DamageInfo *damageInfo );
// ParkingPlaceBehaviorInterface
virtual Bool shouldReserveDoorWhenQueued(const ThingTemplate* thing) const;
virtual Bool hasAvailableSpaceFor(const ThingTemplate* thing) const;
virtual Bool hasReservedSpace(ObjectID id) const;
virtual Int getSpaceIndex( ObjectID id ) const;
virtual Bool reserveSpace(ObjectID id, Real parkingOffset, PPInfo* info);
virtual void releaseSpace(ObjectID id);
virtual Bool reserveRunway(ObjectID id, Bool forLanding);
virtual void releaseRunway(ObjectID id);
virtual void calcPPInfo( ObjectID id, PPInfo *info );
virtual Int getRunwayCount() const { return m_runways.size(); }
virtual ObjectID getRunwayReservation( Int r, RunwayReservationType type );
virtual void transferRunwayReservationToNextInLineForTakeoff(ObjectID id);
virtual Real getApproachHeight() const { return getParkingPlaceBehaviorModuleData()->m_approachHeight; }
virtual Real getLandingDeckHeightOffset() const { return getParkingPlaceBehaviorModuleData()->m_landingDeckHeightOffset; }
virtual void setHealee(Object* healee, Bool add);
virtual void killAllParkedUnits();
virtual void defectAllParkedUnits(Team* newTeam, UnsignedInt detectionTime);
virtual Bool calcBestParkingAssignment( ObjectID id, Coord3D *pos, Int *oldIndex = NULL, Int *newIndex = NULL ) { return FALSE; }
virtual const std::vector* getTaxiLocations( ObjectID id ) const { return NULL; }
virtual const std::vector* getCreationLocations( ObjectID id ) const { return NULL; }
private:
struct ParkingPlaceInfo
{
Coord3D m_hangarStart;
Real m_hangarStartOrient;
Coord3D m_location;
Coord3D m_prep;
Real m_orientation;
Int m_runway;
ExitDoorType m_door;
ObjectID m_objectInSpace;
Bool m_reservedForExit;
ParkingPlaceInfo()
{
m_hangarStart.zero();
m_hangarStartOrient = 0;
m_location.zero();
m_prep.zero();
m_orientation = 0;
m_runway = 0;
m_door = DOOR_NONE_AVAILABLE;
m_objectInSpace = INVALID_ID;
m_reservedForExit = false;
}
};
struct RunwayInfo
{
Coord3D m_start;
Coord3D m_end;
ObjectID m_inUseBy;
ObjectID m_nextInLineForTakeoff;
Bool m_wasInLine;
};
struct HealingInfo
{
ObjectID m_gettingHealedID;
UnsignedInt m_healStartFrame;
};
std::vector m_spaces;
std::vector m_runways;
std::list m_healing; // note, this list can vary in size, and be larger than the parking space count
UnsignedInt m_nextHealFrame;
Bool m_gotInfo;
void buildInfo();
void purgeDead();
void resetWakeFrame();
ParkingPlaceInfo* findPPI(ObjectID id);
ParkingPlaceInfo* findEmptyPPI();
Coord3D m_heliRallyPoint;
Bool m_heliRallyPointExists; ///< Only move to the rally point if this is true
};
#endif // __ParkingPlaceBehavior_H_