CnC_Remastered_Collection/REDALERT/MISSION.CPP
PG-SteveT 03416d24e1 Initial Source Code commit
Initial commit of original Tiberian Dawn and Red Alert source code converted to build as DLLs, and compatible with the release version of Command & Conquer Remastered.
2020-05-27 12:16:20 -07:00

571 lines
30 KiB
C++

//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code 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.
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
// in the hope that it will be useful, but with permitted additional restrictions
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
// distributed with this program. You should have received a copy of the
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
/* $Header: /CounterStrike/MISSION.CPP 1 3/03/97 10:25a Joe_bostic $ */
/***********************************************************************************************
*** 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 : Command & Conquer *
* *
* File Name : MISSION.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : April 23, 1994 *
* *
* Last Update : September 14, 1996 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* MissionClass::AI -- Processes order script. *
* MissionClass::Assign_Mission -- Give an order to a unit. *
* MissionClass::Commence -- Start script with new order. *
* MissionClass::Debug_Dump -- Dumps status values to mono screen. *
* MissionClass::Get_Mission -- Fetches the mission that this object is acting under. *
* MissionClass::MissionClass -- Default constructor for the mission object type. *
* MissionClass::Mission_??? -- Stub mission functions that do nothing. *
* MissionClass::Mission_From_Name -- Fetch order pointer from its name. *
* MissionClass::Mission_Name -- Converts a mission number into an ASCII string. *
* MissionClass::Override_Mission -- temporarily overrides the units mission *
* MissionClass::Restore_Mission -- Restores overridden mission *
* MissionClass::Set_Mission -- Sets the mission to the specified value. *
* MissionClass::Is_Recruitable_Mission -- Determines if this mission is recruitable for a te*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/***********************************************************************************************
* MissionClass::MissionClass -- Default constructor for the mission object type. *
* *
* This is the default constructor for the mission class object. It sets the mission *
* handler into a default -- do nothing -- state. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/23/1995 JLB : Created. *
* 03/01/1996 JLB : Uses initializer lists. *
*=============================================================================================*/
MissionClass::MissionClass(RTTIType rtti, int id) :
ObjectClass(rtti, id),
Mission(MISSION_NONE),
SuspendedMission(MISSION_NONE),
MissionQueue(MISSION_NONE),
Status(0),
Timer(0)
{
}
/***********************************************************************************************
* MissionClass::Mission_??? -- Stub mission functions that do nothing. *
* *
* These are the stub routines that handle the mission logic. They do nothing at this *
* level. Derived classes will override these routine as necessary. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the number of game frames to delay before calling this mission *
* handler again. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/23/1995 JLB : Created. *
*=============================================================================================*/
int MissionClass::Mission_Sleep(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Ambush(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Attack(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Capture(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Guard(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Guard_Area(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Harvest(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Hunt(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Move(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Retreat(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Return(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Stop(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Unload(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Enter(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Construction(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Deconstruction(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Repair(void) {return TICKS_PER_SECOND*30;};
int MissionClass::Mission_Missile(void) {return TICKS_PER_SECOND*30;};
/***********************************************************************************************
* MissionClass::Set_Mission -- Sets the mission to the specified value. *
* *
* Use this routine to set the current mission for this object. This routine will blast *
* over the current mission, bypassing the queue method. Call it when the mission needs *
* to be changed immediately. *
* *
* INPUT: mission -- The mission to set to. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/23/1995 JLB : Created. *
*=============================================================================================*/
void MissionClass::Set_Mission(MissionType mission)
{
assert(IsActive);
Mission = mission;
MissionQueue = MISSION_NONE;
}
/***********************************************************************************************
* MissionClass::Get_Mission -- Fetches the mission that this object is acting under. *
* *
* Use this routine to fetch the mission that this object is CURRENTLY acting under. The *
* mission queue may be filled with a imminent mission change, but this routine does not *
* consider that. It only returns the CURRENT mission. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the mission that this unit is currently following. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/23/1995 JLB : Created. *
*=============================================================================================*/
MissionType MissionClass::Get_Mission(void) const
{
assert(IsActive);
return(Mission == MISSION_NONE ? MissionQueue : Mission);
}
#ifdef CHEAT_KEYS
/***********************************************************************************************
* MissionClass::Debug_Dump -- Dumps status values to mono screen. *
* *
* This is a debugging function that dumps this class' status to the monochrome screen *
* for review. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 05/28/1994 JLB : Created. *
*=============================================================================================*/
void MissionClass::Debug_Dump(MonoClass * mono) const
{
assert(IsActive);
mono->Set_Cursor(1, 9);mono->Printf("%-14s", MissionClass::Mission_Name(Mission));
mono->Set_Cursor(16, 9);mono->Printf("%-12s", MissionClass::Mission_Name(MissionQueue));
mono->Set_Cursor(1, 7);mono->Printf("%3d", (long)Timer);
mono->Set_Cursor(6, 7);mono->Printf("%2d", Status);
ObjectClass::Debug_Dump(mono);
}
#endif
/***********************************************************************************************
* MissionClass::AI -- Processes order script. *
* *
* This routine will process the order script for as much time as *
* possible or until a script delay is detected. This routine should *
* be called for every unit once per game loop (if possible). *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/23/1994 JLB : Created. *
* 06/25/1995 JLB : Added new missions. *
*=============================================================================================*/
void MissionClass::AI(void)
{
assert(IsActive);
ObjectClass::AI();
/*
** If this is the kind of object that is "paralyzed with fear" while it is above
** ground level (such as when be paradropped), it will perform no mission AI
** processing.
*/
if ((What_Am_I() == RTTI_INFANTRY || What_Am_I() == RTTI_UNIT || What_Am_I() == RTTI_VESSEL) && Height > 0) {
return;
}
/*
** This is the script AI equivalent processing.
*/
BStart(BENCH_MISSION);
if (Timer == 0 && Strength > 0) {
switch (Mission) {
default:
Timer = Mission_Sleep();
break;
case MISSION_HARMLESS:
case MISSION_SLEEP:
Timer = Mission_Sleep();
break;
case MISSION_STICKY:
case MISSION_GUARD:
Timer = Mission_Guard();
break;
case MISSION_ENTER:
Timer = Mission_Enter();
break;
case MISSION_CONSTRUCTION:
Timer = Mission_Construction();
break;
case MISSION_DECONSTRUCTION:
Timer = Mission_Deconstruction();
break;
case MISSION_CAPTURE:
case MISSION_SABOTAGE:
Timer = Mission_Capture();
break;
case MISSION_QMOVE:
case MISSION_MOVE:
Timer = Mission_Move();
break;
case MISSION_ATTACK:
Timer = Mission_Attack();
break;
case MISSION_RETREAT:
Timer = Mission_Retreat();
break;
case MISSION_HARVEST:
Timer = Mission_Harvest();
break;
case MISSION_GUARD_AREA:
Timer = Mission_Guard_Area();
break;
case MISSION_RETURN:
Timer = Mission_Return();
break;
case MISSION_STOP:
Timer = Mission_Stop();
break;
case MISSION_AMBUSH:
Timer = Mission_Ambush();
break;
case MISSION_HUNT:
case MISSION_RESCUE:
Timer = Mission_Hunt();
break;
// case MISSION_TIMED_HUNT:
// Timer = Mission_Timed_Hunt();
// break;
case MISSION_UNLOAD:
Timer = Mission_Unload();
break;
case MISSION_REPAIR:
Timer = Mission_Repair();
break;
case MISSION_MISSILE:
Timer = Mission_Missile();
break;
}
}
BEnd(BENCH_MISSION);
}
/***********************************************************************************************
* MissionClass::Commence -- Start script with new order. *
* *
* This routine will start script processing according to any queued *
* order it may have. If there is no queued order, then this routine *
* does nothing. Call this routine whenever the unit is in a good *
* position to change its order (such as when it is stopped). *
* *
* INPUT: none *
* *
* OUTPUT: Did the mission actually change? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/23/1994 JLB : Created. *
* 07/14/1994 JLB : Simplified. *
* 06/17/1995 JLB : Returns success flag. *
*=============================================================================================*/
bool MissionClass::Commence(void)
{
assert(IsActive);
if (MissionQueue != MISSION_NONE) {
Mission = MissionQueue;
MissionQueue = MISSION_NONE;
/*
** Force immediate state machine processing at the first state machine state value.
*/
Timer = 0;
Status = 0;
return(true);
}
return(false);
}
/***********************************************************************************************
* MissionClass::Assign_Mission -- Give an order to a unit. *
* *
* This routine will assign the specified mission to the mission queue for this object. *
* The actual mission logic will then be performed at the first available and legal *
* opportunity. *
* *
* INPUT: order -- Mission to give the unit. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/04/1991 JLB : Created. *
* 04/15/1994 JLB : Converted to member function. *
*=============================================================================================*/
void MissionClass::Assign_Mission(MissionType order)
{
assert(IsActive);
/*
** Ensure that a MISSION_QMOVE is translated into a MISSION_MOVE.
*/
if (order == MISSION_QMOVE) order = MISSION_MOVE;
if (order != MISSION_NONE && Mission != order) {
MissionQueue = order;
}
}
/***********************************************************************************************
* MissionClass::Mission_From_Name -- Fetch order pointer from its name. *
* *
* This routine is used to convert an ASCII order name into the actual *
* order number it represents. Typically, this is used when processing *
* a scenario INI file. *
* *
* INPUT: name -- The ASCII order name to process. *
* *
* OUTPUT: Returns with the actual order number that the ASCII name *
* represents. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/07/1992 JLB : Created. *
* 04/22/1994 JLB : Converted to static member function. *
*=============================================================================================*/
MissionType MissionClass::Mission_From_Name(char const * name)
{
MissionType order;
if (name) {
for (order = MISSION_FIRST; order < MISSION_COUNT; order++) {
if (stricmp(Missions[order], name) == 0) {
return(order);
}
}
}
return(MISSION_NONE);
}
/***********************************************************************************************
* MissionClass::Mission_Name -- Converts a mission number into an ASCII string. *
* *
* Use this routine to convert a mission number into the ASCII string that represents *
* it. Typical use of this is when generating an INI file. *
* *
* INPUT: mission -- The mission number to convert. *
* *
* OUTPUT: Returns with a pointer to the ASCII string that represents the mission type. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/23/1995 JLB : Created. *
*=============================================================================================*/
char const * MissionClass::Mission_Name(MissionType mission)
{
if (mission != MISSION_NONE) {
return(Missions[mission]);
}
return("None");
}
/***********************************************************************************************
* MissionClass::Override_Mission -- temporarily overrides the units mission *
* *
* *
* *
* INPUT: MissionType mission - the mission we want to override *
* TARGET tarcom - the new target we want to override *
* TARGET navcom - the new navigation point to override *
* *
* OUTPUT: none *
* *
* WARNINGS: If a mission is already overridden, the current mission is *
* just re-assigned. *
* *
* HISTORY: *
* 04/28/1995 PWG : Created. *
*=============================================================================================*/
void MissionClass::Override_Mission(MissionType mission, TARGET, TARGET)
{
assert(IsActive);
if (MissionQueue != MISSION_NONE) {
SuspendedMission = MissionQueue;
} else {
SuspendedMission = Mission;
}
Assign_Mission(mission);
}
/***********************************************************************************************
* MissionClass::Restore_Mission -- Restores overridden mission *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/28/1995 PWG : Created. *
*=============================================================================================*/
bool MissionClass::Restore_Mission(void)
{
assert(IsActive);
if (SuspendedMission != MISSION_NONE) {
Assign_Mission(SuspendedMission);
SuspendedMission= MISSION_NONE;
return(true);
}
return(false);
}
/***********************************************************************************************
* MissionClass::Is_Recruitable_Mission -- Determines if this mission is recruitable for a tea *
* *
* Some missions preclude recruitment into a team. This routine will examine the mission *
* specified and if not allowed for a team, it will return false. *
* *
* INPUT: mission -- The mission type to examine. *
* *
* OUTPUT: bool; Is an object following this mission allowed to be recruited into a team? *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 09/14/1996 JLB : Created. *
*=============================================================================================*/
bool MissionClass::Is_Recruitable_Mission(MissionType mission)
{
if (mission == MISSION_NONE) {
return(true);
}
return(MissionControl[mission].IsRecruitable);
}
MissionControlClass::MissionControlClass(void) :
Mission(MISSION_NONE),
IsNoThreat(false),
IsZombie(false),
IsRecruitable(true),
IsParalyzed(false),
IsRetaliate(true),
IsScatter(true),
Rate(".016"),
AARate(".016")
{
}
char const * MissionControlClass::Name(void) const
{
if (Mission == MISSION_NONE) {
return("<none>");
}
return(Missions[Mission]);
}
bool MissionControlClass::Read_INI(CCINIClass & ini)
{
if (ini.Is_Present(Name())) {
IsNoThreat = ini.Get_Bool(Name(), "NoThreat", IsNoThreat);
IsZombie = ini.Get_Bool(Name(), "Zombie", IsZombie);
IsRecruitable = ini.Get_Bool(Name(), "Recruitable", IsRecruitable);
IsParalyzed = ini.Get_Bool(Name(), "Paralyzed", IsParalyzed);
IsRetaliate = ini.Get_Bool(Name(), "Retaliate", IsRetaliate);
IsScatter = ini.Get_Bool(Name(), "Scatter", IsScatter);
Rate = ini.Get_Fixed(Name(), "Rate", Rate);
AARate = ini.Get_Fixed(Name(), "AARate", 0);
if (AARate == 0) {
AARate = Rate;
}
return(true);
}
return(false);
}