mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-15 23:21:40 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
479
Code/Combat/harvester.cpp
Normal file
479
Code/Combat/harvester.cpp
Normal file
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
** Command & Conquer Renegade(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 O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Combat *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/Combat/harvester.cpp $*
|
||||
* *
|
||||
* Author:: Patrick Smith *
|
||||
* *
|
||||
* $Modtime:: 1/18/02 11:16p $*
|
||||
* *
|
||||
* $Revision:: 11 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "harvester.h"
|
||||
#include "vehicle.h"
|
||||
#include "refinerygameobj.h"
|
||||
#include "animcontrol.h"
|
||||
#include "vehiclephys.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Local constants
|
||||
////////////////////////////////////////////////////////////////
|
||||
enum
|
||||
{
|
||||
ACTIONID_GOTO_TIBERIUM = 1000,
|
||||
ACTIONID_DOCK,
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// HarvesterClass
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
HarvesterClass::HarvesterClass (void) :
|
||||
Refinery (NULL),
|
||||
DockLocation (0, 0, 0),
|
||||
DockEntrance (0, 0, 0),
|
||||
StateTimer (0),
|
||||
State (STATE_UNINITIALIZED),
|
||||
Vehicle (NULL),
|
||||
IsHarvesting (false)
|
||||
{
|
||||
Set_ID (GameObjObserverManager::Get_Next_Observer_ID ());
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ~HarvesterClass
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
HarvesterClass::~HarvesterClass (void)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Initialize
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Initialize (void)
|
||||
{
|
||||
Go_Harvest ();
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Go_Harvest
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Go_Harvest (void)
|
||||
{
|
||||
//
|
||||
// Bail if the vehicle pointer is invalid, or if the vehicle
|
||||
// isn't on the ground...
|
||||
//
|
||||
if (Vehicle == NULL || Vehicle->Peek_Vehicle_Phys ()->Is_In_Contact () == false) {
|
||||
return ;
|
||||
}
|
||||
|
||||
State = STATE_GOING_TO_HARVEST;
|
||||
|
||||
//
|
||||
// Choose a random offset into the tiberium box
|
||||
//
|
||||
Vector3 rand_offset;
|
||||
rand_offset.X = WWMath::Random_Float (0, TiberiumRegion.Extent.X - 5);
|
||||
rand_offset.Y = WWMath::Random_Float (0, TiberiumRegion.Extent.Y - 5);
|
||||
rand_offset.Z = 0;
|
||||
|
||||
//
|
||||
// Tranform this random offset into a world space position
|
||||
//
|
||||
Vector3 rand_pos = TiberiumRegion.Center + (TiberiumRegion.Basis * rand_offset);
|
||||
|
||||
//
|
||||
// Setup an action to instruct the vehicle to goto that location
|
||||
//
|
||||
ActionParamsStruct parameters;
|
||||
parameters.Priority = 99;
|
||||
parameters.ActionID = ACTIONID_GOTO_TIBERIUM;
|
||||
parameters.ObserverID = Get_ID ();
|
||||
parameters.Set_Movement (rand_pos, 1.0F, 1.0F);
|
||||
Vehicle->Get_Action ()->Goto (parameters);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Go_Unload_Tiberium
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Go_Unload_Tiberium (void)
|
||||
{
|
||||
Play_Harvest_Animation (false);
|
||||
|
||||
//
|
||||
// Switch states
|
||||
//
|
||||
IsHarvesting = false;
|
||||
State = STATE_GOING_TO_UNLOAD;
|
||||
|
||||
//
|
||||
// Setup an action to instruct the vehicle to dock in its refinery
|
||||
//
|
||||
ActionParamsStruct parameters;
|
||||
parameters.Priority = 99;
|
||||
parameters.ActionID = ACTIONID_DOCK;
|
||||
parameters.ObserverID = Get_ID ();
|
||||
parameters.Dock_Vehicle (DockLocation, DockEntrance);
|
||||
parameters.MoveSpeed = 1.0F;
|
||||
Vehicle->Get_Action ()->Dock_Vehicle (parameters);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Unload_Tiberium
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Unload_Tiberium (void)
|
||||
{
|
||||
Refinery->On_Harvester_Docked ();
|
||||
State = STATE_UNLOADING;
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Harvest_Tiberium
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Harvest_Tiberium (void)
|
||||
{
|
||||
//
|
||||
// Reset the harvesting timer (if necessary)
|
||||
//
|
||||
if (IsHarvesting == false) {
|
||||
HarvestTimer = 15.0F;
|
||||
IsHarvesting = true;
|
||||
}
|
||||
|
||||
//
|
||||
// Harvest the tiberium for a few seconds
|
||||
//
|
||||
State = STATE_HARVESTING;
|
||||
StateTimer = WWMath::Random_Float (3.0F, 7.0F);
|
||||
|
||||
//
|
||||
// Start playing the harvest animation
|
||||
//
|
||||
Play_Harvest_Animation (true);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Action_Complete
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Action_Complete
|
||||
(
|
||||
GameObject * game_obj,
|
||||
int action_id,
|
||||
ActionCompleteReason complete_reason
|
||||
)
|
||||
{
|
||||
//
|
||||
// Check to ensure the harvester successfully completed
|
||||
// its action...
|
||||
//
|
||||
if (complete_reason == ACTION_COMPLETE_NORMAL) {
|
||||
|
||||
//
|
||||
// Which action was completed?
|
||||
//
|
||||
if (action_id == ACTIONID_GOTO_TIBERIUM) {
|
||||
|
||||
//
|
||||
// Check to ensure we were going to harvest the
|
||||
// tiberium before actually start harvesting
|
||||
//
|
||||
if (State == STATE_GOING_TO_HARVEST) {
|
||||
Harvest_Tiberium ();
|
||||
}
|
||||
} else if (action_id == ACTIONID_DOCK) {
|
||||
Unload_Tiberium ();
|
||||
}
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Animation_Complete
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Animation_Complete
|
||||
(
|
||||
GameObject * game_obj,
|
||||
const char * animation_name
|
||||
)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Attach
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Attach (GameObject *game_obj)
|
||||
{
|
||||
WWASSERT (game_obj != NULL);
|
||||
if (game_obj != NULL) {
|
||||
|
||||
//
|
||||
// See if this game object is a vehicle (it better be)
|
||||
//
|
||||
PhysicalGameObj *physical_obj = game_obj->As_PhysicalGameObj ();
|
||||
if (physical_obj != NULL) {
|
||||
Vehicle = physical_obj->As_VehicleGameObj ();
|
||||
}
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Detach
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Detach (GameObject * /*game_obj*/)
|
||||
{
|
||||
//
|
||||
// Remove ourselves from the refinery
|
||||
//
|
||||
if (Refinery != NULL) {
|
||||
Refinery->Set_Harvester (NULL);
|
||||
}
|
||||
|
||||
Vehicle = NULL;
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Think
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Think (void)
|
||||
{
|
||||
if (IsHarvesting) {
|
||||
|
||||
//
|
||||
// If we are harvesting, check to see if its time to go unload
|
||||
// the tiberium.
|
||||
//
|
||||
HarvestTimer -= TimeManager::Get_Frame_Seconds ();
|
||||
if (HarvestTimer <= 0) {
|
||||
Go_Unload_Tiberium ();
|
||||
}
|
||||
}
|
||||
|
||||
switch (State)
|
||||
{
|
||||
case STATE_HARVESTING:
|
||||
|
||||
//
|
||||
// Check to see if we should harvest in a new location
|
||||
//
|
||||
StateTimer -= TimeManager::Get_Frame_Seconds ();
|
||||
if (StateTimer <= 0) {
|
||||
Go_Harvest ();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STATE_UNINITIALIZED:
|
||||
if (Vehicle != NULL) {
|
||||
Go_Harvest ();
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_GOING_TO_HARVEST:
|
||||
case STATE_GOING_TO_UNLOAD:
|
||||
case STATE_UNLOADING:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Stop
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Stop (void)
|
||||
{
|
||||
//
|
||||
// Stopt the harvester from moving
|
||||
//
|
||||
if (Vehicle != NULL) {
|
||||
Vehicle->Get_Action ()->Reset (100);
|
||||
Vehicle->Enable_Engine (false);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Play_Harvest_Animation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Play_Harvest_Animation (bool onoff)
|
||||
{
|
||||
if (onoff) {
|
||||
|
||||
//
|
||||
// Play the animation looped...
|
||||
//
|
||||
Vehicle->Set_Animation (HarvestAnimationName, true);
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Stop the animation
|
||||
//
|
||||
AnimControlClass *anim_control = Vehicle->Get_Anim_Control ();
|
||||
if (anim_control != NULL) {
|
||||
anim_control->Set_Animation( (const char *)NULL );
|
||||
}
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Custom
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
HarvesterClass::Custom
|
||||
(
|
||||
GameObject * game_obj,
|
||||
int type,
|
||||
int param,
|
||||
GameObject * sender
|
||||
)
|
||||
{
|
||||
//
|
||||
// Are we backing into the docking bay?
|
||||
//
|
||||
if (type == CUSTOM_EVENT_DOCK_BACKING_IN) {
|
||||
Refinery->Play_Unloading_Animation (true);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
void HarvesterClass::Damaged(GameObject* damaged, GameObject* killer, float amount)
|
||||
{
|
||||
// Only report damage not heal
|
||||
if (amount > 0.0f) {
|
||||
VehicleGameObj* vehicle = static_cast<VehicleGameObj*>(damaged);
|
||||
assert(Vehicle == vehicle);
|
||||
|
||||
// If the unit has been damaged to the point of being destroyed
|
||||
// then do not report the damaged event. A killed event will be sent
|
||||
// later.
|
||||
DefenseObjectClass* defense = vehicle->Get_Defense_Object();
|
||||
|
||||
if (defense && (defense->Get_Health() <= 0.0f)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DamageableGameObj* damager = NULL;
|
||||
|
||||
if (killer) {
|
||||
damager = killer->As_DamageableGameObj();
|
||||
}
|
||||
|
||||
bool friendlyFire = (damager && (damager->Get_Player_Type() == vehicle->Get_Player_Type()));
|
||||
|
||||
// Notify the building
|
||||
if (!friendlyFire) {
|
||||
assert(Refinery != NULL);
|
||||
Refinery->On_Harvester_Damaged(vehicle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HarvesterClass::Destroyed(GameObject* destroyed)
|
||||
{
|
||||
VehicleGameObj* vehicle = static_cast<VehicleGameObj*>(destroyed);
|
||||
assert(Vehicle == vehicle);
|
||||
Refinery->On_Harvester_Destroyed(vehicle);
|
||||
}
|
||||
Reference in New Issue
Block a user