123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772 |
- //
- // 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: F:\projects\c&c\vcs\code\factory.cpv 2.18 16 Oct 1995 16:51:26 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 : FACTORY.CPP *
- * *
- * Programmer : Joe L. Bostic *
- * *
- * Start Date : 12/26/94 *
- * *
- * Last Update : May 22, 1995 [JLB] *
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * FactoryClass::AI -- Process factory production logic. *
- * FactoryClass::Abandon -- Abandons current construction with money refunded. *
- * FactoryClass::Completed -- Clears factory object after a completed production process. *
- * FactoryClass::Completion -- Fetchs the completion step for this factory. *
- * FactoryClass::Cost_Per_Tick -- Breaks entire production cost into managable chunks. *
- * FactoryClass::FactoryClass -- Default constructor for factory objects. *
- * FactoryClass::Get_Object -- Fetches pointer to object being constructed. *
- * FactoryClass::Get_Special_Item -- gets factorys spc prod item *
- * FactoryClass::Has_Changed -- Checks to see if a production step has occurred? *
- * FactoryClass::Has_Completed -- Checks to see if object has completed production. *
- * FactoryClass::Set -- Assigns a factory to produce an object. *
- * FactoryClass::Set -- Fills a factory with an already completed object. *
- * FactoryClass::Set -- Force factory to "produce" special object. *
- * FactoryClass::Start -- Resumes production after suspension or creation. *
- * FactoryClass::Suspend -- Temporarily stop production. *
- * FactoryClass::operator delete -- Returns a factory to the free factory pool. *
- * FactoryClass::operator new -- Allocates a factory object from the free factory pool. *
- * FactoryClass::~FactoryClass -- Default destructor for factory objects. *
- * FactoryClass::Validate -- validates factory pointer *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "function.h"
- /***********************************************************************************************
- * FactoryClass::Validate -- validates factory pointer *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * 1 = ok, 0 = error *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 08/09/1995 BRR : Created. *
- *=============================================================================================*/
- #ifdef CHEAT_KEYS
- int FactoryClass::Validate(void) const
- {
- int num;
- num = Factories.ID(this);
- if (num < 0 || num >= FACTORY_MAX) {
- Validate_Error("FACTORY");
- return (0);
- }
- else
- return (1);
- }
- #else
- #define Validate()
- #endif
- /***********************************************************************************************
- * FactoryClass::FactoryClass -- Default constructor for factory objects. *
- * *
- * This brings the factory into a null state. It is called when a factory object is *
- * created. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- FactoryClass::FactoryClass(void)
- {
- IsSuspended = false;
- IsDifferent = false;
- IsBlocked = false;
- Balance = 0;
- SpecialItem = SPC_NONE;
- Object = NULL;
- House = NULL;
- Set_Rate(0);
- Set_Stage(0);
- }
- /***********************************************************************************************
- * FactoryClass::~FactoryClass -- Default destructor for factory objects. *
- * *
- * This cleans up a factory object in preparation for deletion. If there is currently *
- * an object in production, it is abandoned and money is refunded. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- FactoryClass::~FactoryClass(void)
- {
- if (GameActive) {
- Abandon();
- }
- }
- /***********************************************************************************************
- * FactoryClass::Init -- Clears all units for scenario preparation. *
- * *
- * This routine will zero out the factory list and objects. This routine is typically *
- * used in preparation for a new scenario load. All factorys are guaranteed to be eliminated*
- * by this routine. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/15/1994 JLB : Created. *
- *=============================================================================================*/
- void FactoryClass::Init(void)
- {
- Factories.Free_All();
- }
- /***********************************************************************************************
- * FactoryClass::operator new -- Allocates a factory object from the free factory pool. *
- * *
- * This routine allocates a factory from the free factory pool. If there is no more room *
- * to allocate a factory, then NULL is returned. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with pointer to the newly allocated factory object. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- void * FactoryClass::operator new(size_t)
- {
- void * ptr = Factories.Allocate();
- if (ptr) {
- ((FactoryClass *)ptr)->IsActive = true;
- }
- return(ptr);
- }
- /***********************************************************************************************
- * FactoryClass::operator delete -- Returns a factory to the free factory pool. *
- * *
- * This returns the factory object back to the factory allocation pool. The factory is then *
- * available to be allocated. *
- * *
- * INPUT: ptr -- Pointer to the factory object to delete. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- void FactoryClass::operator delete(void *ptr)
- {
- if (ptr) {
- ((FactoryClass *)ptr)->IsActive = false;
- }
- Factories.Free((FactoryClass *)ptr);
- }
- /***********************************************************************************************
- * FactoryClass::AI -- Process factory production logic. *
- * *
- * This routine should be called once per game tick. It handles the production process. *
- * As production proceeds, money is deducted from the owner object's house. When production *
- * completes, the factory stop processing. A call to Abandon, Delete, or Completed is *
- * required after that point. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- * 01/04/1995 JLB : Uses exact installment payment method. *
- *=============================================================================================*/
- void FactoryClass::AI(void)
- {
- Validate();
- if (!IsSuspended && (Object != NULL || SpecialItem)) {
- int stages = 1;
- /*
- ** Determine the acceleration factor for factory production.
- ** This applies only to human players. The computer builds
- ** units on a building by building basis -- quantity of building
- ** factory types doesn't affect individual factories.
- */
- if (Object && House->IsHuman) {
- switch (Object->What_Am_I()) {
- case RTTI_AIRCRAFT:
- stages = House->AircraftFactories;
- break;
- case RTTI_INFANTRY:
- stages = House->InfantryFactories;
- break;
- case RTTI_UNIT:
- stages = House->UnitFactories;
- break;
- case RTTI_BUILDING:
- stages = House->BuildingFactories;
- break;
- }
- stages = MAX(stages, 1);
- }
- for (int index = 0; index < stages; index++) {
- if (!Has_Completed() && Graphic_Logic()) {
- IsDifferent = true;
- int cost = Cost_Per_Tick();
- cost = MIN(cost, Balance);
- /*
- ** Enough time has expired so that another production step can occur.
- ** If there is insufficient funds, then go back one production step and
- ** continue the countdown. The idea being that by the time the next
- ** production step occurs, there may be sufficient funds available.
- */
- if (cost > House->Available_Money()) {
- Set_Stage(Fetch_Stage()-1);
- } else {
- House->Spend_Money(cost);
- Balance -= cost;
- }
- if ( Debug_Instant_Build ) {
- Set_Stage(STEP_COUNT);
- }
- /*
- ** If the production has completed, then suspend further production.
- */
- if (Fetch_Stage() == STEP_COUNT) {
- IsSuspended = true;
- Set_Rate(0);
- House->Spend_Money(Balance);
- Balance = 0;
- }
- }
- }
- }
- }
- /***********************************************************************************************
- * FactoryClass::Force_Complete -- Force the factory to finish what it's building *
- * *
- * For debugging/testing support *
- * *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 8/23/2019 3:54PM ST : Created. *
- *=============================================================================================*/
- void FactoryClass::Force_Complete(void)
- {
- Validate();
- if (!IsSuspended && (Object != NULL || SpecialItem)) {
- Set_Stage(STEP_COUNT);
- IsSuspended = true;
- Set_Rate(0);
- Balance = 0;
- IsDifferent = true;
- }
- }
- /***********************************************************************************************
- * FactoryClass::Has_Changed -- Checks to see if a production step has occurred? *
- * *
- * Use this routine to determine if production has advanced at least one step. By using *
- * this function, intelligent rendering may be performed. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: bool; Has the production process advanced one step since the last time this *
- * function was called? *
- * *
- * WARNINGS: This function clears the changed status flag as a side effect. *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- bool FactoryClass::Has_Changed(void)
- {
- Validate();
- bool changed = IsDifferent;
- IsDifferent = false;
- return(changed);
- }
- /***********************************************************************************************
- * FactoryClass::Set -- Assigns a factory to produce an object. *
- * *
- * This routine initializes a factory to produce the object specified. The desired object *
- * type is created and placed in suspended animation (limbo) until such time as production *
- * completes. Production is not actually started by this routine. An explicit call to *
- * Start() is required to begin production. *
- * *
- * INPUT: object -- Reference to the object type class that is to be produced. *
- * *
- * house -- Reference to the owner of the object to be produced. *
- * *
- * OUTPUT: bool; Was production successfully prepared for this factory object. Failure means *
- * that the object could not be created. This is catastrophic and in such *
- * cases, the factory object should be deleted. *
- * *
- * WARNINGS: Be sure to examine the return value from this function. Failure to initialize *
- * the factory means that the factory is useless and should be deleted. *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- bool FactoryClass::Set(TechnoTypeClass const & object, HouseClass & house)
- {
- Validate();
- /*
- ** If there is any production currently in progress, abandon it.
- */
- Abandon();
- /*
- ** Set up the factory for the new production process.
- */
- IsDifferent = true;
- IsSuspended = true;
- Set_Rate(0);
- Set_Stage(0);
- /*
- ** Create an object of the type requested.
- */
- Object = (TechnoClass *)object.Create_One_Of(&house);
- if (Object) {
- House = Object->House;
- Balance = object.Cost_Of() * house.CostBias;
- Object->PurchasePrice = Balance;
- }
- /*
- ** If all was set up successfully, then return true.
- */
- return(Object != NULL);
- }
- /***********************************************************************************************
- * FactoryClass::Set -- Force factory to "produce" special object. *
- * *
- * Use this routine to force the factory into special production mode. Such production is *
- * used for the ion cannon and other timed special weapon events. *
- * *
- * INPUT: type -- The special weapon type to begin "production" of. *
- * *
- * house -- The owner of this production object. *
- * *
- * OUTPUT: Was the assignment successful? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/22/1995 JLB : Created. *
- *=============================================================================================*/
- bool FactoryClass::Set(int const & type, HouseClass & house)
- {
- Validate();
- /*
- ** If there is any production currently in progress, abandon it.
- */
- Abandon();
- /*
- ** Set up the factory for the new production process.
- */
- IsDifferent = true;
- IsSuspended = true;
- Set_Rate(0);
- Set_Stage(0);
- /*
- ** Create an object of the type requested.
- */
- SpecialItem = type;
- House = &house;
- Balance = 0;
- /*
- ** If all was set up successfully, then return true.
- */
- return(SpecialItem != SPC_NONE);
- }
- /***********************************************************************************************
- * FactoryClass::Set -- Fills a factory with an already completed object. *
- * *
- * This routine is called when a produced object is in placement mode but then placement *
- * is suspended. The object must then return to the factory as if it were newly completed *
- * and awaiting removal. *
- * *
- * INPUT: object -- The object to return to the factory. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: This will abandon any current object being produced at the factory in order *
- * to set the new object into it. *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- void FactoryClass::Set(TechnoClass & object)
- {
- Validate();
- Abandon();
- Object = &object;
- House = Object->House;
- Balance = 0;
- Set_Rate(0);
- Set_Stage(STEP_COUNT);
- IsDifferent = true;
- IsSuspended = true;
- }
- /***********************************************************************************************
- * FactoryClass::Suspend -- Temporarily stop production. *
- * *
- * This routine will suspend production until a subsiquent call to Start() or Abandon(). *
- * Typical use of this function is when the player puts production on hold or when there *
- * is insufficient funds. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: bool; Was production actually stopped? A false return value indicates that the *
- * factory was empty or production was already stopped (or never started). *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- bool FactoryClass::Suspend(void)
- {
- Validate();
- if (!IsSuspended) {
- IsSuspended = true;
- Set_Rate(0);
- return(true);
- }
- return(false);
- }
- /***********************************************************************************************
- * FactoryClass::Start -- Resumes production after suspension or creation. *
- * *
- * This function will start the production process. It works for newly created factory *
- * objects, as well as if production had been suspended previously. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: bool; Was production started? A false return value means that the factory is *
- * empty or there is unsufficient credits to begin production. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- bool FactoryClass::Start(void)
- {
- Validate();
- if ((Object || SpecialItem) && IsSuspended && !Has_Completed()) {
- if (House->IsHuman || House->Available_Money() >= Cost_Per_Tick()) {
- int time;
- if (Object) {
- time = Object->Class_Of().Time_To_Build(House->Class->House);
- } else {
- time = TICKS_PER_MINUTE * 5;
- }
- time /= STEP_COUNT;
- time = Bound(time, 1, 255);
- Set_Rate(time);
- IsSuspended = false;
- return(true);
- }
- }
- return(false);
- }
- /***********************************************************************************************
- * FactoryClass::Abandon -- Abandons current construction with money refunded. *
- * *
- * This routine is used when construction is to be abandoned and current money spend is *
- * to be refunded. This function effectively clears out this factory of all record of the *
- * producing object so that it may either be deleted or started anew with the Set() *
- * function. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: bool; Was an object actually abandoned? A false return value indicates that the *
- * factory was not producing any object. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- bool FactoryClass::Abandon(void)
- {
- Validate();
- if (Object) {
- if (Object) {
- /*
- ** Refund all money expended so far, back to the owner of the object under construction.
- */
- int money = Object->Class_Of().Cost_Of() * Object->House->CostBias;
- House->Refund_Money(money - Balance);
- Balance = 0;
- /*
- ** Delete the object under construction.
- */
- ScenarioInit++;
- delete Object;
- Object = NULL;
- ScenarioInit--;
- }
- if (SpecialItem) {
- SpecialItem = SPC_NONE;
- }
- /*
- ** Set the factory back to the idle and empty state.
- */
- Set_Rate(0);
- Set_Stage(0);
- IsSuspended = true;
- IsDifferent = true;
- return(true);
- }
- return(false);
- }
- /***********************************************************************************************
- * FactoryClass::Completion -- Fetchs the completion step for this factory. *
- * *
- * Use this routine to determine what animation (or completion step) the factory is *
- * currently on. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns a completion step number beteen 0 (uncompleted), to STEP_COUNT (completed) *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- int FactoryClass::Completion(void)
- {
- Validate();
- return(Fetch_Stage());
- }
- /***********************************************************************************************
- * FactoryClass::Has_Completed -- Checks to see if object has completed production. *
- * *
- * Use this routine to examine the factory object in order to determine if the associated *
- * object has completed production and is awaiting placement. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: bool; Is the associated object to the factory completed and ready for placement? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- bool FactoryClass::Has_Completed(void)
- {
- Validate();
- if (Object && Fetch_Stage() == STEP_COUNT) {
- return(true);
- }
- if (SpecialItem && Fetch_Stage() == STEP_COUNT) {
- return(true);
- }
- return(false);
- }
- /***********************************************************************************************
- * FactoryClass::Get_Object -- Fetches pointer to object being constructed. *
- * *
- * This routine gets the pointer to the currently constructing object. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with a pointer to the object undergoing construction. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- TechnoClass * FactoryClass::Get_Object(void) const
- {
- Validate();
- return(Object);
- }
- /***************************************************************************
- * FactoryClass::Get_Special_Item -- gets factorys spc prod item *
- * *
- * INPUT: none *
- * *
- * OUTPUT: int the item the factory is currently working on *
- * *
- * HISTORY: *
- * 05/05/1995 PWG : Created. *
- *=========================================================================*/
- int FactoryClass::Get_Special_Item(void) const
- {
- Validate();
- return(SpecialItem);
- }
- /***********************************************************************************************
- * FactoryClass::Cost_Per_Tick -- Breaks entire production cost into managable chunks. *
- * *
- * Use this routine to determine the cost per game "tick" to produce the object. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns the number of credits necessary to advance production one game tick. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- int FactoryClass::Cost_Per_Tick(void)
- {
- Validate();
- if (Object) {
- int steps = STEP_COUNT - Fetch_Stage();
- if (steps) {
- return(Balance / steps);
- }
- return(Balance);
- }
- return(0);
- }
- /***********************************************************************************************
- * FactoryClass::Completed -- Clears factory object after a completed production process. *
- * *
- * This routine is called after production completes, and the object produced has been *
- * placed into the game. It resets the factory for deletion or starting of new production. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: bool; Did any resetting occur? Failure is the result of the factory not having *
- * any completed object. An immediate second call to this routine will also *
- * yield false. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/26/1994 JLB : Created. *
- *=============================================================================================*/
- bool FactoryClass::Completed(void)
- {
- Validate();
- if (Object && Fetch_Stage() == STEP_COUNT) {
- Object = NULL;
- IsSuspended = true;
- IsDifferent = true;
- Set_Stage(0);
- Set_Rate(0);
- return(true);
- }
- if (SpecialItem && Fetch_Stage() == STEP_COUNT) {
- SpecialItem = SPC_NONE;
- IsSuspended = true;
- IsDifferent = true;
- Set_Stage(0);
- Set_Rate(0);
- return(true);
- }
- return(false);
- }
|