/* ** Command & Conquer Generals(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: PilotFindVehicleUpdate.cpp ////////////////////////////////////////////////////////////////////////// // Author: Kris Morness, August 2002 // Desc: Update module to handle independent targeting of hazards to cleanup. /////////////////////////////////////////////////////////////////////////////////////////////////// // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine #define DEFINE_WEAPONSLOTTYPE_NAMES #include "GameClient\Drawable.h" #include "Common/ActionManager.h" #include "Common/Player.h" #include "Common/RandomValue.h" #include "Common/ThingTemplate.h" #include "Common/Xfer.h" #include "GameLogic\GameLogic.h" #include "GameLogic\PartitionManager.h" #include "GameLogic\Object.h" #include "GameLogic\ObjectIter.h" #include "GameLogic\Module\PilotFindVehicleUpdate.h" #include "GameLogic\Module\AIUpdate.h" #include "GameLogic\Module\CollideModule.h" //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- PilotFindVehicleUpdateModuleData::PilotFindVehicleUpdateModuleData() { m_scanFrames = 0; m_scanRange = 0.0f; m_minHealth = 0.5f; } //------------------------------------------------------------------------------------------------- /*static*/ void PilotFindVehicleUpdateModuleData::buildFieldParse(MultiIniFieldParse& p) { ModuleData::buildFieldParse(p); static const FieldParse dataFieldParse[] = { { "ScanRate", INI::parseDurationUnsignedInt, NULL, offsetof( PilotFindVehicleUpdateModuleData, m_scanFrames ) }, { "ScanRange", INI::parseReal, NULL, offsetof( PilotFindVehicleUpdateModuleData, m_scanRange ) }, { "MinHealth", INI::parseReal, NULL, offsetof( PilotFindVehicleUpdateModuleData, m_minHealth ) }, { 0, 0, 0, 0 } }; p.add(dataFieldParse); } //------------------------------------------------------------------------------------------------- PilotFindVehicleUpdate::PilotFindVehicleUpdate( Thing *thing, const ModuleData* moduleData ) : UpdateModule( thing, moduleData ) { m_didMoveToBase = false; setWakeFrame(getObject(), UPDATE_SLEEP_NONE); } //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- PilotFindVehicleUpdate::~PilotFindVehicleUpdate( void ) { } //------------------------------------------------------------------------------------------------- void PilotFindVehicleUpdate::onObjectCreated() { } //------------------------------------------------------------------------------------------------- /** The update callback. */ //------------------------------------------------------------------------------------------------- UpdateSleepTime PilotFindVehicleUpdate::update() { Object *obj = getObject(); if (obj->getControllingPlayer()->getPlayerType() == PLAYER_HUMAN) { // This is an ai only behavior. return UPDATE_SLEEP_FOREVER; } const PilotFindVehicleUpdateModuleData *data = getPilotFindVehicleUpdateModuleData(); AIUpdateInterface *ai = obj->getAI(); if (ai==NULL) return UPDATE_SLEEP_FOREVER; if( !ai->isIdle() ) { return UPDATE_SLEEP(data->m_scanFrames); } //Periodic scanning (expensive) Object *upgradeUnit = scanClosestTarget(); if(upgradeUnit) { ai->aiEnter(upgradeUnit, CMD_FROM_AI); m_didMoveToBase = false; } else { Coord3D pos; // Try moving to base 1 time. if (!m_didMoveToBase && obj->getControllingPlayer()->getAiBaseCenter(&pos)) { ai->aiMoveToPosition(&pos, CMD_FROM_AI); m_didMoveToBase = true; } } return UPDATE_SLEEP(data->m_scanFrames); } //------------------------------------------------------------------------------------------------- Object* PilotFindVehicleUpdate::scanClosestTarget() { const PilotFindVehicleUpdateModuleData *data = getPilotFindVehicleUpdateModuleData(); Object *me = getObject(); PartitionFilterAcceptByKindOf kindFilter(MAKE_KINDOF_MASK(KINDOF_VEHICLE), KINDOFMASK_NONE); PartitionFilterAlive aliveFilter; PartitionFilterPlayer playerFilter(me->getControllingPlayer(), true); PartitionFilterSameMapStatus filterMapStatus(getObject()); PartitionFilter *filters[5]; filters[0] = &kindFilter; filters[1] = &aliveFilter; filters[2] = &playerFilter; filters[3] = &filterMapStatus; filters[4] = NULL; ObjectIterator *iter = ThePartitionManager->iterateObjectsInRange( me->getPosition(), data->m_scanRange, FROM_CENTER_2D, filters, ITER_SORTED_NEAR_TO_FAR ); MemoryPoolObjectHolder hold(iter); for( Object *other = iter->first(); other; other = iter->next() ) { // Check health. BodyModuleInterface *body = other->getBodyModule(); if (!body) continue; // If we're real healthy, don't bother looking for healing. if (body->getHealth() < body->getMaxHealth()*data->m_minHealth) { continue; } // first, see if we'd like to collide with 'other' for (BehaviorModule** m = me->getBehaviorModules(); *m; ++m) { CollideModuleInterface* collide = (*m)->getCollide(); if (!collide) continue; if( collide->wouldLikeToCollideWith( other ) ) { return other; } } } return NULL; } // ------------------------------------------------------------------------------------------------ /** CRC */ // ------------------------------------------------------------------------------------------------ void PilotFindVehicleUpdate::crc( Xfer *xfer ) { // extend base class UpdateModule::crc( xfer ); } // end crc // ------------------------------------------------------------------------------------------------ /** Xfer method * Version Info: * 1: Initial version */ // ------------------------------------------------------------------------------------------------ void PilotFindVehicleUpdate::xfer( Xfer *xfer ) { // version XferVersion currentVersion = 1; XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); // extend base class UpdateModule::xfer( xfer ); // did move to base xfer->xferBool( &m_didMoveToBase ); } // end xfer // ------------------------------------------------------------------------------------------------ /** Load post process */ // ------------------------------------------------------------------------------------------------ void PilotFindVehicleUpdate::loadPostProcess( void ) { // extend base class UpdateModule::loadPostProcess(); } // end loadPostProcess