CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

TURRET.CPP (28427B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 /* $Header:   F:\projects\c&c\vcs\code\turret.cpv   2.18   16 Oct 1995 16:50:38   JOE_BOSTIC  $ */
     17 /***********************************************************************************************
     18  ***             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               ***
     19  ***********************************************************************************************
     20  *                                                                                             *
     21  *                 Project Name : Command & Conquer                                            *
     22  *                                                                                             *
     23  *                    File Name : TURRET.CPP                                                   *
     24  *                                                                                             *
     25  *                   Programmer : Joe L. Bostic                                                *
     26  *                                                                                             *
     27  *                   Start Date : April 25, 1994                                               *
     28  *                                                                                             *
     29  *                  Last Update : August 13, 1995 [JLB]                                        *
     30  *                                                                                             *
     31  *---------------------------------------------------------------------------------------------*
     32  * Functions:                                                                                  *
     33  *   TurretClass::AI -- Handles the reloading of the turret weapon.                            *
     34  *   TurretClass::Can_Fire -- Determines if turret can fire upon target.                       *
     35  *   TurretClass::Debug_Dump -- Debug printing of turret values.                               *
     36  *   TurretClass::Fire_At -- Try to fire upon the target specified.                            *
     37  *   TurretClass::Fire_Coord -- Determines the coorindate that projectile would appear.        *
     38  *   TurretClass::Fire_Direction -- Determines the directinon of firing.                       *
     39  *   TurretClass::Ok_To_Move -- Queries whether the vehicle can move.                          *
     40  *   TurretClass::TurretClass -- Normal constructor for the turret class.                      *
     41  *   TurretClass::TurretClass -- The default constructor for turret class objects.             *
     42  *   TurretClass::Unlimbo -- Unlimboes turret object.                                          *
     43  *   TurretClass::~TurretClass -- Default destructor for turret class objects.                 *
     44  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     45 
     46 #include	"function.h"
     47 #include	"turret.h"
     48 
     49 
     50 /***********************************************************************************************
     51  * TurretClass::~TurretClass -- Default destructor for turret class objects.                   *
     52  *                                                                                             *
     53  *    This is the default destructor for turret class objects. It does nothing.                *
     54  *                                                                                             *
     55  * INPUT:   none                                                                               *
     56  *                                                                                             *
     57  * OUTPUT:  none                                                                               *
     58  *                                                                                             *
     59  * WARNINGS:   none                                                                            *
     60  *                                                                                             *
     61  * HISTORY:                                                                                    *
     62  *   08/13/1995 JLB : Created.                                                                 *
     63  *=============================================================================================*/
     64 TurretClass::~TurretClass(void)
     65 {
     66 }
     67 
     68 
     69 /***********************************************************************************************
     70  * TurretClass::TurretClass -- The default constructor for turret class objects.               *
     71  *                                                                                             *
     72  *    This is the default constructor for turret class objects. It does nothing.               *
     73  *                                                                                             *
     74  * INPUT:   none                                                                               *
     75  *                                                                                             *
     76  * OUTPUT:  none                                                                               *
     77  *                                                                                             *
     78  * WARNINGS:   none                                                                            *
     79  *                                                                                             *
     80  * HISTORY:                                                                                    *
     81  *   08/13/1995 JLB : Created.                                                                 *
     82  *=============================================================================================*/
     83 TurretClass::TurretClass(void)
     84 {
     85 }
     86 
     87 
     88 /***********************************************************************************************
     89  * TurretClass::TurretClass -- Normal constructor for the turret class.                        *
     90  *                                                                                             *
     91  *    This is the normal constructor for the turret class. It merely sets the turret up to     *
     92  *    face north.                                                                              *
     93  *                                                                                             *
     94  * INPUT:   classid  -- The type id for this particular unit.                                  *
     95  *                                                                                             *
     96  *          house    -- The house that this unit will belong to.                               *
     97  *                                                                                             *
     98  * OUTPUT:  none                                                                               *
     99  *                                                                                             *
    100  * WARNINGS:   none                                                                            *
    101  *                                                                                             *
    102  * HISTORY:                                                                                    *
    103  *   02/02/1995 JLB : Created.                                                                 *
    104  *=============================================================================================*/
    105 TurretClass::TurretClass(UnitType classid, HousesType house) :
    106 	DriveClass(classid, house)
    107 {
    108 	Reload = 0;
    109 }
    110 
    111 
    112 #ifdef CHEAT_KEYS
    113 /***********************************************************************************************
    114  * TurretClass::Debug_Dump -- Debug printing of turret values.                                 *
    115  *                                                                                             *
    116  *    This routine is used to display the current values of this turret                        *
    117  *    class instance. It is primarily used in the debug output screen.                         *
    118  *                                                                                             *
    119  * INPUT:   x,y   -- Monochrome screen coordinates to display data.                            *
    120  *                                                                                             *
    121  * OUTPUT:  none                                                                               *
    122  *                                                                                             *
    123  * WARNINGS:   none                                                                            *
    124  *                                                                                             *
    125  * HISTORY:                                                                                    *
    126  *   05/12/1994 JLB : Created.                                                                 *
    127  *=============================================================================================*/
    128 void TurretClass::Debug_Dump(MonoClass *mono) const
    129 {
    130 	mono->Set_Cursor(36, 3);mono->Printf("%02X:%02X", SecondaryFacing.Current(), SecondaryFacing.Desired());
    131 	mono->Set_Cursor(28, 7);mono->Printf("%2d", Arm);
    132 	DriveClass::Debug_Dump(mono);
    133 }
    134 #endif
    135 
    136 
    137 /***********************************************************************************************
    138  * TurretClass::Ok_To_Move -- Queries whether the vehicle can move.                            *
    139  *                                                                                             *
    140  *    This virtual routine is used to determine if the vehicle is allowed                      *
    141  *    to start moving. It is typically called when the vehicle desires                         *
    142  *    to move but needs confirmation from the turret logic before                              *
    143  *    proceeding. This happens when dealing with a vehicle that must have                      *
    144  *    its turret face the same direction as the body before the vehicle                        *
    145  *    may begin movement.                                                                      *
    146  *                                                                                             *
    147  * INPUT:   dir      -- The facing the unit wants to travel in.                                *
    148  *                                                                                             *
    149  * OUTPUT:  bool; Can the unit begin forward movement now?                                     *
    150  *                                                                                             *
    151  * WARNINGS:   none                                                                            *
    152  *                                                                                             *
    153  * HISTORY:                                                                                    *
    154  *   05/12/1994 JLB : Created.                                                                 *
    155  *=============================================================================================*/
    156 bool TurretClass::Ok_To_Move(DirType dir)
    157 {
    158 	if (Class->IsLockTurret) {
    159 		if (IsRotating) {
    160 			return(false);
    161 		} else {
    162 			if (SecondaryFacing.Difference(dir)) {
    163 				SecondaryFacing.Set_Desired(dir);
    164 				return(false);
    165 			}
    166 		}
    167 	}
    168 	return(true);
    169 }
    170 
    171 
    172 /***********************************************************************************************
    173  * TurretClass::AI -- Handles the reloading of the turret weapon.                              *
    174  *                                                                                             *
    175  *    This processes the reloading of the turret. It does this by decrementing the arming      *
    176  *    countdown  timer and when it reaches zero, the turret may fire.                          *
    177  *                                                                                             *
    178  * INPUT:   none                                                                               *
    179  *                                                                                             *
    180  * OUTPUT:  none                                                                               *
    181  *                                                                                             *
    182  * WARNINGS:   none                                                                            *
    183  *                                                                                             *
    184  * HISTORY:                                                                                    *
    185  *   06/21/1994 JLB : Created.                                                                 *
    186  *=============================================================================================*/
    187 void TurretClass::AI(void)
    188 {
    189 	DriveClass::AI();
    190 
    191 	/*
    192 	**	A unit with a constant rotating radar dish is handled here.
    193 	*/
    194 	if (Class->IsRadarEquipped) {
    195 		SecondaryFacing.Set((DirType)(SecondaryFacing.Current() + 8));
    196 		Mark(MARK_CHANGE);
    197 	} else {
    198 
    199 		IsRotating = false;
    200 		if (Class->IsTurretEquipped) {
    201 			if (IsTurretLockedDown) {
    202 				SecondaryFacing.Set_Desired(PrimaryFacing.Current());
    203 			}
    204 
    205 			if (SecondaryFacing.Is_Rotating()) {
    206 				if (SecondaryFacing.Rotation_Adjust(Class->ROT+1)) {
    207 					Mark(MARK_CHANGE);
    208 				}
    209 
    210 				/*
    211 				**	If no further rotation is necessary, flag that the rotation
    212 				**	has stopped.
    213 				*/
    214 				IsRotating = SecondaryFacing.Is_Rotating();
    215 			} else {
    216 				if (!IsTurretLockedDown && !Target_Legal(TarCom)) {
    217 					if (!Target_Legal(NavCom)) {
    218 						SecondaryFacing.Set_Desired(PrimaryFacing.Current());
    219 					} else {
    220 						SecondaryFacing.Set_Desired(Direction(NavCom));
    221 					}
    222 				}
    223 			}
    224 		}
    225 	}
    226 }
    227 
    228 
    229 /***********************************************************************************************
    230  * TurretClass::Fire_At -- Try to fire upon the target specified.                              *
    231  *                                                                                             *
    232  *    This routine is the auto-fire logic for the turret. It will check                        *
    233  *    to see if firing is technically legal given the specified target.                        *
    234  *    If it is legal to fire, it does so. It is safe to call this routine                      *
    235  *    every game tick.                                                                         *
    236  *                                                                                             *
    237  * INPUT:   target   -- The target to fire upon.                                               *
    238  *                                                                                             *
    239  *          which    -- Which weapon to use when firing. 0=primary, 1=secondary.               *
    240  *                                                                                             *
    241  * OUTPUT:  bool; Did firing occur?                                                            *
    242  *                                                                                             *
    243  * WARNINGS:   none                                                                            *
    244  *                                                                                             *
    245  * HISTORY:                                                                                    *
    246  *   04/26/1994 JLB : Created.                                                                 *
    247  *=============================================================================================*/
    248 BulletClass * TurretClass::Fire_At(TARGET target, int which)
    249 {
    250 	BulletClass * bullet = NULL;
    251 	WeaponTypeClass const * weapon = (which == 0) ? &Weapons[Class->Primary] : &Weapons[Class->Secondary];
    252 
    253 	if (Can_Fire(target, which) == FIRE_OK) {
    254 		bullet = DriveClass::Fire_At(target, which);
    255 
    256 		if (bullet) {
    257 
    258 			/*
    259 			**	Possible reload timer set.
    260 			*/
    261 			if (*this == UNIT_MSAM && Reload == 0) {
    262 				Reload = TICKS_PER_SECOND * 30;
    263 			}
    264 		}
    265 	}
    266 
    267 	return(bullet);
    268 }
    269 
    270 
    271 /***********************************************************************************************
    272  * TurretClass::Can_Fire -- Determines if turret can fire upon target.                         *
    273  *                                                                                             *
    274  *    This routine determines if the turret can fire upon the target                           *
    275  *    specified.                                                                               *
    276  *                                                                                             *
    277  * INPUT:   target   -- The target to fire upon.                                               *
    278  *                                                                                             *
    279  *          which    -- Which weapon to use to determine legality to fire. 0=primary,          *
    280  *                      1=secondary.                                                           *
    281  *                                                                                             *
    282  * OUTPUT:  Returns the fire status type that indicates if firing is allowed and if not, why.  *
    283  *                                                                                             *
    284  * WARNINGS:   none                                                                            *
    285  *                                                                                             *
    286  * HISTORY:                                                                                    *
    287  *   04/26/1994 JLB : Created.                                                                 *
    288  *   06/01/1994 JLB : Returns reason why it can't fire.                                        *
    289  *=============================================================================================*/
    290 FireErrorType TurretClass::Can_Fire(TARGET target, int which) const
    291 {
    292 	DirType			dir;					// The facing to impart upon the projectile.
    293 	int				diff;
    294 	FireErrorType	fire = DriveClass::Can_Fire(target, which);
    295 
    296 	if (fire == FIRE_OK) {
    297 		WeaponTypeClass const * weapon = (which == 0) ? &Weapons[Class->Primary] : &Weapons[Class->Secondary];
    298 
    299 		/*
    300 		**	If this unit cannot fire while moving, then bail.
    301 		*/
    302 		if ((!Class->IsTurretEquipped || Class->IsLockTurret) && Target_Legal(NavCom)) {
    303 			return(FIRE_MOVING);
    304 		}
    305 
    306 		/*
    307 		**	If the turret is rotating and the projectile isn't a homing type, then
    308 		**	firing must be delayed until the rotation stops.
    309 		*/
    310 		if (!IsFiring && IsRotating && !BulletTypeClass::As_Reference(weapon->Fires).IsHoming) {
    311 			return(FIRE_ROTATING);
    312 		}
    313 
    314 		dir = Direction(target);
    315 
    316 		/*
    317 		**	Determine if the turret facing isn't too far off of facing the target.
    318 		*/
    319 		if (Class->IsTurretEquipped) {
    320 			diff = SecondaryFacing.Difference(dir);
    321 		} else {
    322 			diff = PrimaryFacing.Difference(dir);
    323 		}
    324 		diff = ABS(diff);
    325 
    326 		/*
    327 		**	Special flame tank logic.
    328 		*/
    329 		if (weapon->Fires == BULLET_FLAME) {
    330 			if (Dir_Facing(dir) == Dir_Facing(PrimaryFacing)) {
    331 				diff = 0;
    332 			}
    333 		}
    334 
    335 		if (BulletTypeClass::As_Reference(weapon->Fires).IsHoming) {
    336 			diff >>= 2;
    337 		}
    338 		if (diff < 8) {
    339 			return(DriveClass::Can_Fire(target, which));
    340 		}
    341 		return(FIRE_FACING);
    342 	}
    343 	return(fire);
    344 }
    345 
    346 
    347 /***********************************************************************************************
    348  * TurretClass::Fire_Coord -- Determines the coorindate that projectile would appear.          *
    349  *                                                                                             *
    350  *    Use this routine to determine the exact coordinate that a projectile would appear if it  *
    351  *    were fired from this unit. For units with turrets, typically, this would be at the end   *
    352  *    of the barrel.                                                                           *
    353  *                                                                                             *
    354  * INPUT:   none                                                                               *
    355  *                                                                                             *
    356  * OUTPUT:  Returns with coordinate of where a projectile should appear if this unit were      *
    357  *          to fire one.                                                                       *
    358  *                                                                                             *
    359  * WARNINGS:   none                                                                            *
    360  *                                                                                             *
    361  * HISTORY:                                                                                    *
    362  *   12/28/1994 JLB : Created.                                                                 *
    363  *=============================================================================================*/
    364 FireDataType TurretClass::Fire_Data(int which) const
    365 {
    366 	COORDINATE coord = Center_Coord();
    367 	int dist = 0;
    368 
    369 	switch (Class->Type) {
    370 		case UNIT_GUNBOAT:
    371 			coord = Coord_Move(coord, PrimaryFacing.Current(), Pixel2Lepton[Class->TurretOffset]);
    372 			dist = 0x0060;
    373 			break;
    374 
    375 		case UNIT_ARTY:
    376 			coord = Coord_Move(coord, DIR_N, 0x0040);
    377 			dist = 0x0060;
    378 			break;
    379 
    380 		case UNIT_FTANK:
    381 			dist = 0x30;
    382 			break;
    383 
    384 		case UNIT_HTANK:
    385 			coord = Coord_Move(coord, DIR_N, 0x0040);
    386 			if (which == 0) {
    387 				dist = 0x00C0;
    388 			} else {
    389 				dist = 0x0008;
    390 			}
    391 			break;
    392 
    393 		case UNIT_LTANK:
    394 			coord = Coord_Move(coord, DIR_N, 0x0020);
    395 			dist = 0x00C0;
    396 			break;
    397 
    398 		case UNIT_MTANK:
    399 			coord = Coord_Move(coord, DIR_N, 0x0030);
    400 			dist = 0x00C0;
    401 			break;
    402 
    403 		case UNIT_APC:
    404 		case UNIT_JEEP:
    405 		case UNIT_BUGGY:
    406 			coord = Coord_Move(coord, DIR_N, 0x0030);
    407 			dist = 0x0030;
    408 			break;
    409 
    410 #ifdef PETROGLYPH_EXAMPLE_MOD
    411 		case UNIT_NUKE_TANK:
    412 			coord = Coord_Move(coord, DIR_N, 0x00A0);
    413 			dist = 0x00A0;
    414 			break;
    415 #endif //PETROGLYPH_EXAMPLE_MOD
    416 	}
    417 
    418 	return {coord,dist};
    419 }
    420 
    421 
    422 COORDINATE TurretClass::Fire_Coord(int which) const
    423 {
    424 	COORDINATE coord = Center_Coord();
    425 	int dist = 0;
    426 	int lateral = 0;
    427 	DirType dir = PrimaryFacing.Current();
    428 
    429 	if (Class->IsTurretEquipped) {
    430 		dir = SecondaryFacing.Current();
    431 	}
    432 
    433 	switch (Class->Type) {
    434 		case UNIT_GUNBOAT:
    435 			coord = Coord_Move(coord, PrimaryFacing.Current(), Pixel2Lepton[Class->TurretOffset]);
    436 			dist = 0x0060;
    437 			break;
    438 
    439 		case UNIT_ARTY:
    440 			coord = Coord_Move(coord, DIR_N, 0x0040);
    441 			dist = 0x0060;
    442 			break;
    443 
    444 		case UNIT_FTANK:
    445 			dist = 0x30;
    446 			if (IsSecondShot) {
    447 				coord = Coord_Move(coord, (DirType)(dir+DIR_E), 0x20);
    448 			} else {
    449 				coord = Coord_Move(coord, (DirType)(dir+DIR_W), 0x20);
    450 			}
    451 			break;
    452 
    453 		case UNIT_HTANK:
    454 			coord = Coord_Move(coord, DIR_N, 0x0040);
    455 			if (which == 0) {
    456 				dist = 0x00C0;
    457 				lateral = 0x0028;
    458 			} else {
    459 				dist = 0x0008;
    460 				lateral = 0x0040;
    461 			}
    462 			if (IsSecondShot) {
    463 				coord = Coord_Move(coord, (DirType)(dir+DIR_E), lateral);
    464 			} else {
    465 				coord = Coord_Move(coord, (DirType)(dir+DIR_W), lateral);
    466 			}
    467 			break;
    468 
    469 		case UNIT_LTANK:
    470 			coord = Coord_Move(coord, DIR_N, 0x0020);
    471 			dist = 0x00C0;
    472 			break;
    473 
    474 		case UNIT_MTANK:
    475 			coord = Coord_Move(coord, DIR_N, 0x0030);
    476 			dist = 0x00C0;
    477 			break;
    478 
    479 		case UNIT_APC:
    480 		case UNIT_JEEP:
    481 		case UNIT_BUGGY:
    482 			coord = Coord_Move(coord, DIR_N, 0x0030);
    483 			dist = 0x0030;
    484 			break;
    485 
    486 #ifdef PETROGLYPH_EXAMPLE_MOD
    487 		case UNIT_NUKE_TANK:
    488 			coord = Coord_Move(coord, DIR_N, 0x00A0);
    489 			dist = 0x00A0;
    490 			break;
    491 #endif //PETROGLYPH_EXAMPLE_MOD
    492 	}
    493 
    494 	if (dist) {
    495 		coord = Coord_Move(coord, dir, dist);
    496 	}
    497 
    498 	return(coord);
    499 }
    500 
    501 
    502 /***********************************************************************************************
    503  * TurretClass::Unlimbo -- Unlimboes turret object.                                            *
    504  *                                                                                             *
    505  *    This routine is called when a turret equipped unit unlimboes. It sets the turret to      *
    506  *    face the same direction as the body.                                                     *
    507  *                                                                                             *
    508  * INPUT:   coord -- The coordinate where the unit is unlimboing.                              *
    509  *                                                                                             *
    510  *          dir   -- The desired body and turret facing to use.                                *
    511  *                                                                                             *
    512  * OUTPUT:  Was the unit unlimboed successfully?                                               *
    513  *                                                                                             *
    514  * WARNINGS:   none                                                                            *
    515  *                                                                                             *
    516  * HISTORY:                                                                                    *
    517  *   06/25/1995 JLB : Created.                                                                 *
    518  *=============================================================================================*/
    519 bool TurretClass::Unlimbo(COORDINATE coord, DirType dir)
    520 {
    521 	if (DriveClass::Unlimbo(coord, dir)) {
    522 		SecondaryFacing = dir;
    523 		return(true);
    524 	}
    525 	return(false);
    526 }
    527 
    528 
    529 /***********************************************************************************************
    530  * TurretClass::Fire_Direction -- Determines the directinon of firing.                         *
    531  *                                                                                             *
    532  *    This routine will return with the facing that a projectile will travel if it was         *
    533  *    fired at this instant. The facing should match the turret facing for those units         *
    534  *    equipped with a turret. If the unit doesn't have a turret, then it will be the facing    *
    535  *    of the body.                                                                             *
    536  *                                                                                             *
    537  * INPUT:   none                                                                               *
    538  *                                                                                             *
    539  * OUTPUT:  Returns with the default firing direction for a projectile.                        *
    540  *                                                                                             *
    541  * WARNINGS:   none                                                                            *
    542  *                                                                                             *
    543  * HISTORY:                                                                                    *
    544  *   06/25/1995 JLB : Created.                                                                 *
    545  *=============================================================================================*/
    546 DirType TurretClass::Fire_Direction(void) const
    547 {
    548 	if (Class->IsTurretEquipped) {
    549 		if (*this == UNIT_MSAM) {
    550 			int diff1 = SecondaryFacing.Difference(DIR_E);
    551 			int diff2 = SecondaryFacing.Difference(DIR_W);
    552 			diff1 = ABS(diff1);
    553 			diff2 = ABS(diff2);
    554 			int diff = MIN(diff1, diff2);
    555 			int adj = Fixed_To_Cardinal(ABS(SecondaryFacing.Difference(DIR_N)), 64-diff);
    556 			if (SecondaryFacing.Difference(DIR_N) < 0) {
    557 				return(DirType)(SecondaryFacing - (DirType)adj);
    558 			} else {
    559 				return(DirType)(SecondaryFacing + (DirType)adj);
    560 			}
    561 		}
    562 		return(SecondaryFacing.Current());
    563 	}
    564 
    565 	return(PrimaryFacing.Current());
    566 }