304 lines
12 KiB
C
Raw Permalink Normal View History

/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// AIPlayer.h
// Computerized opponent
// Author: Michael S. Booth, January 2002
#pragma once
#ifndef _AI_PLAYER_H_
#define _AI_PLAYER_H_
#include "Common/GameMemory.h"
#include "Common/Snapshot.h"
enum { INVALID_SKILLSET_SELECTION = -1 };
class BuildListInfo;
/**
* When a team is selected for training, a list of these
* "work orders" are created, one for each member of the team.
* This pairs team members with production buildings to keep
* track of who is building what, and allows us to track if
* a building was destroyed while in the process of training a unit.
*/
class WorkOrder : public MemoryPoolObject,
public Snapshot
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( WorkOrder, "WorkOrder" )
public:
WorkOrder():m_thing(NULL), m_factoryID(INVALID_ID), m_isResourceGatherer(false), m_numCompleted(0), m_numRequired(1), m_next(NULL) {};
Bool isWaitingToBuild( void ); ///< return true if nothing is yet building this unit
void validateFactory( Player *thisPlayer ); ///< verify factoryID still refers to an active object
public:
const ThingTemplate *m_thing; ///< thing to build
ObjectID m_factoryID; ///< ID of object that is building this, or zero if no-one is
WorkOrder *m_next;
Int m_numCompleted; ///< Number built.
Int m_numRequired; ///< Number needed.
Bool m_required; ///< True if part of minimum requirement.
Bool m_isResourceGatherer; ///< True if resource gatherer.
protected:
// snapshot methods
virtual void crc( Xfer *xfer );
virtual void xfer( Xfer *xfer );
virtual void loadPostProcess( void );
};
inline Bool WorkOrder::isWaitingToBuild( void )
{
if (m_factoryID!=INVALID_ID)
return false;
if (m_numCompleted >= m_numRequired)
return false;
return true;
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
class TeamInQueue : public MemoryPoolObject,
public Snapshot
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( TeamInQueue, "TeamInQueue" )
private:
MAKE_DLINK(TeamInQueue, TeamBuildQueue) ///< the instances of our prototype
MAKE_DLINK(TeamInQueue, TeamReadyQueue) ///< the instances of our prototype
protected:
// snapshot methods
virtual void crc( Xfer *xfer );
virtual void xfer( Xfer *xfer );
virtual void loadPostProcess( void );
public:
TeamInQueue() :
m_workOrders(NULL),
m_team(NULL),
m_nextTeamInQueue(NULL),
m_sentToStartLocation(false),
m_reinforcement(false),
m_stopQueueing(false),
m_reinforcementID(INVALID_ID),
//Added By Sadullah Nader
//Initialization(s) inserted
m_frameStarted(0),
m_priorityBuild(FALSE)
//
{
}
Bool isAllBuilt( void ); ///< Returns true if the team is finished building.
Bool isBuildTimeExpired( void );///< Returns true if the team has run out of build time.
Bool isMinimumBuilt( void ); ///< Returns true if the team has started building at least the minimum number of units.
Bool includesADozer( void ); ///< Returns true if the team includes a dozer unit.
Bool areBuildsComplete( void ); ///< Returns true if all units in factories have finished building.
void disband( void ); ///< Disbands the team (moves units into the default team).
void stopQueueing(void) {m_stopQueueing=true;} ///< Stops building new units, just finishes current.
public:
WorkOrder *m_workOrders; ///< list of work orders
Bool m_priorityBuild; ///< True if the team is specifically requested.
Team *m_team; ///< the team that units built by the m_workOrders go into
TeamInQueue *m_nextTeamInQueue; ///< next
Int m_frameStarted; ///< Frame we started building.
Bool m_sentToStartLocation; ///< Has it been sent to it's start location?
Bool m_stopQueueing; ///< True if we are to quit queueing units (usually because we ran out of build time.)
Bool m_reinforcement; ///< True if it is a unit to reinforce an existing team.
ObjectID m_reinforcementID; ///< True if it is a unit to reinforce an existing team.
};
#if !defined(_PLAYTEST)
/**
* The computer-controlled opponent.
*/
class AIPlayer : public MemoryPoolObject,
public Snapshot
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( AIPlayer, "AIPlayer" )
public:
AIPlayer( Player *p ); ///< constructor
virtual void computeSuperweaponTarget(const SpecialPowerTemplate *power, Coord3D *pos, Int playerNdx, Real weaponRadius); ///< Calculates best pos for weapon given radius.
public: // AIPlayer interface, may be overridden by AISkirmishPlayer. jba.
virtual void update(); ///< simulates the behavior of a player
virtual void newMap(); ///< New map loaded call.
/// Invoked when a unit I am training comes into existence
virtual void onUnitProduced( Object *factory, Object *unit );
/// Invoked when a structure I am building comes into existence
virtual void onStructureProduced( Object *factory, Object *structure );
virtual void buildSpecificAITeam(TeamPrototype *teamProto, Bool priorityBuild); ///< Builds this team immediately.
virtual void buildAIBaseDefense(Bool flank); ///< Builds base defense on front or flank of base.
virtual void buildAIBaseDefenseStructure(const AsciiString &thingName, Bool flank); ///< Builds base defense on front or flank of base.
virtual void buildSpecificAIBuilding(const AsciiString &thingName); ///< Builds this building as soon as possible.
virtual void recruitSpecificAITeam(TeamPrototype *teamProto, Real recruitRadius); ///< Builds this team immediately.
virtual Bool isSkirmishAI(void) {return false;}
virtual Player *getAiEnemy(void) {return NULL;} ///< Solo AI attacks based on scripting. Only skirmish auto-acquires an enemy at this point. jba.
virtual Bool checkBridges(Object *unit, Waypoint *way) {return false;}
virtual void repairStructure(ObjectID structure);
virtual void selectSkillset(Int skillset);
public:
Bool getBaseCenter(Coord3D *pos) const {*pos = m_baseCenter; return m_baseCenterSet;}
/// Difficulty level for this player.
GameDifficulty getAIDifficulty(void) const;
void setAIDifficulty(GameDifficulty difficulty) {m_difficulty = difficulty;}
void buildBySupplies(Int minimumCash, const AsciiString &thingName ); ///< Builds a building by supplies.
void buildUpgrade(const AsciiString &upgrade ); ///< Builds an upgrade.
/// A team is about to be destroyed.
void aiPreTeamDestroy( const Team *team );
/// Is the nearest supply source safe?
Bool isSupplySourceSafe( Int minSupplies );
/// Is a supply source attacked?
Bool isSupplySourceAttacked( void );
Bool isLocationSafe( const Coord3D *pos, const ThingTemplate *tthing);
/// Have the team guard a supply center.
void guardSupplyCenter( Team *team, Int minSupplies );
void setTeamDelaySeconds(Int delay) {m_teamSeconds = delay;}
protected:
// snapshot methods
virtual void crc( Xfer *xfer );
virtual void xfer( Xfer *xfer );
virtual void loadPostProcess( void );
virtual void doBaseBuilding(void);
virtual void checkReadyTeams(void);
virtual void checkQueuedTeams(void);
virtual void doTeamBuilding(void);
virtual void doUpgradesAndSkills(void);
virtual Object *findDozer(const Coord3D *pos);
virtual void queueDozer(void);
virtual Bool selectTeamToBuild( void ); ///< determine the next team to build
virtual Bool selectTeamToReinforce( Int minPriority ); ///< determine the next team to reinforce
virtual Bool startTraining( WorkOrder *order, Bool busyOK, AsciiString teamName); ///< find a production building that can handle the order, and start building
virtual Bool isAGoodIdeaToBuildTeam( TeamPrototype *proto ); ///< return true if team should be built
virtual void processBaseBuilding( void ); ///< do base-building behaviors
virtual void processTeamBuilding( void ); ///< do team-building behaviors
static Int getPlayerSuperweaponValue(Coord3D *center, Int playerNdx, Real radius);
// End of aiplayer interface.
protected:
MAKE_DLINK_HEAD(TeamInQueue, TeamBuildQueue); ///< List of teams being build
MAKE_DLINK_HEAD(TeamInQueue, TeamReadyQueue); ///< List of teams built, waiting to reach rally point.
protected:
Bool isPossibleToBuildTeam( TeamPrototype *proto, Bool requireIdleFactory, Bool &needMoney ); ///< return true if team can be considered for building
Object *buildStructureNow(const ThingTemplate *bldgPlan, BuildListInfo *info ); ///< Build a base buiding.
Object *buildStructureWithDozer(const ThingTemplate *bldgPlan, BuildListInfo *info ); ///< Build a base buiding.
void clearTeamsInQueue( void ); ///< Delete all teams in the build queue.
void computeCenterAndRadiusOfBase(Coord3D *center, Real *radius);
Object *findFactory(const ThingTemplate *thing, Bool busyOK); ///< Find a factory to build a unit. If force is true, may return a busy factory.
void queueUnits( void ); ///< Check the team build list, & queue up units at any idle factories.
void checkForSupplyCenter( BuildListInfo *info, Object *bldg);
void queueSupplyTruck(void);
void updateBridgeRepair(void);
Bool dozerInQueue(void);
Object *findSupplyCenter(Int minSupplies);
static void getPlayerStructureBounds(Region2D *bounds, Int playerNdx);
protected:
Player *m_player; ///< the Player we represent
Bool m_readyToBuildTeam; ///< True if the team select timer has expired.
Bool m_readyToBuildStructure; ///< True if the buildDelay timer has expired.
Int m_teamTimer; ///< Counts out the time between teams, as specified by ini.
Int m_structureTimer; ///< Counts out the time between structures, as specified by ini.
Int m_teamSeconds; ///< How many seconds to delay between teams.
Int m_buildDelay; ///< Delay for building in case we are resource or prereq. limited.
Int m_teamDelay; ///< Delay for teams in case we are resource or factory prereq. limited.
Int m_frameLastBuildingBuilt; ///< When we built the last building.
GameDifficulty m_difficulty;
Int m_skillsetSelector;
Coord3D m_baseCenter; // Center of the initial build list of structures.
Bool m_baseCenterSet; // True if baseCenter is valid.
Real m_baseRadius; // Radius of the initial build list of structures.
// Bridge repair info.
enum {MAX_STRUCTURES_TO_REPAIR = 2};
ObjectID m_structuresToRepair[MAX_STRUCTURES_TO_REPAIR];
ObjectID m_repairDozer;
Coord3D m_repairDozerOrigin;
Int m_structuresInQueue;
Bool m_dozerQueuedForRepair;
Bool m_dozerIsRepairing; ///< the repair dozer is trying to repair the bridge.
Int m_bridgeTimer;
UnsignedInt m_supplySourceAttackCheckFrame;
ObjectID m_attackedSupplyCenter;
ObjectID m_curWarehouseID;
};
#endif
#endif // _AI_PLAYER_H_