CnC_Remastered_Collection/TIBERIANDAWN/COMBAT.CPP
PG-SteveT fc5cd5a775 Command & Conquer Remastered post-launch patch
Improvements to harvester resource finding logic.

Don't allow the Advanced Comm Center to be capturable in skirmish or multiplayer.

Increased failed pathfinding fudge factor.

Buildings accept the Guard command if they can attack.

Don't allow force capturing of ally structures.

Fixes for laser Orcas in S3cr3t M1ss10n. Properly restore them after save. Reset Orcas after loads.

Fixed flag animation rendering in CTF.

Potentially fix a crash if aircraft are destroyed outside the map bounds.

Fixed legacy Obelisk line rendering.

Fix out-of-bounds crash in TD; issue was already fixed in RA.

Disable capture flag on Commandos.

Drop the flag when entering the limbo state.

Fixed end game race condition, winning team ID is always sent before individual player win/lose messages.

Fixed Chan spawn on SCB10EA.

Don't show enter cursor for enemy units on refineries and repair pads.

Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold.

Don't debug reveal legacy rendering when a player is defeated.

Fixed crash when loading saves of custom campaign maps.

Reset harvester archived target when given a direct harvest order.

Prevent NOD cargo planes from being force attacked.

Fixed unit selection on load.

Migrated queued repair pad functionality from RA to TD.

Randomly animate infantry in area guard mode.

Fixed crash accessing inactive objects.

Added some walls in SCG08EB to prevent civilians from killing themselves.

TD + RA: Audio: Overiding "Our base is under attack" cooldown timing from legacy from 2 minutes to 30 seconds, so it will be heard 4x as often.

Fixed adjacent cell out-of-bounds crash issues.

Kill player on disconnect

Fixed and improved build time calculations to be consistent between TD and RA.

Don't show health bars for cloaked Stealth Tanks in the legacy renderer.

Fix selection of individual control groups after mixed selection.

More adjustments to SCG08EB; switch C7 to C5, and add civilian AI to avoid Tiberium.

Extra safety checks for units that have no weapons and aircraft that can't hunt.

Fix loading of multiple infantry onto an APC.

Additional safety checks for invalid coordinates.

Prevent units from being instantly repaired.

Fix map passability.

Fail Allied mission 5B if the spy re-boards the starting transport (matches 5A and 5C behavior).

Fixed multiplayer formation move causing units to move at light speed.

Ignore movement destination checks if a unit is part of a mission-driven team.

Fix buffer overrun crash.

Ignore mines when determining win conditions.

Fixed river passability in Blue Lakes.
2020-06-22 09:43:21 -07:00

234 lines
12 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: F:\projects\c&c\vcs\code\combat.cpv 2.17 16 Oct 1995 16:48:32 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 : COMBAT.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : September 19, 1994 *
* *
* Last Update : January 1, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Explosion_Damage -- Inflict an explosion damage affect. *
* Modify_Damage -- Adjusts damage to reflect the nature of the target. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
int Modify_Damage(int damage, WarheadType warhead, ArmorType armor);
void Explosion_Damage(COORDINATE coord, unsigned strength, TechnoClass *source, WarheadType warhead);
/***********************************************************************************************
* Modify_Damage -- Adjusts damage to reflect the nature of the target. *
* *
* This routine is the core of combat tactics. It implements the *
* affect various armor types have against various weapon types. By *
* careful exploitation of this table, tactical advantage can be *
* obtained. *
* *
* INPUT: damage -- The damage points to process. *
* *
* warhead -- The source of the damage points. *
* *
* armor -- The type of armor defending against the damage. *
* *
* distance -- The distance (in leptons) from the source of the damage. *
* *
* OUTPUT: Returns with the adjusted damage points to inflict upon the *
* target. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/16/1994 JLB : Created. *
* 04/17/1994 JLB : Always does a minimum of damage. *
* 01/01/1995 JLB : Takes into account distance from damage source. *
*=============================================================================================*/
int Modify_Damage(int damage, WarheadType warhead, ArmorType armor, int distance)
{
/*
** If there is no raw damage value to start with, then
** there can be no modified damage either.
*/
if (Special.IsInert || !damage || warhead == WARHEAD_NONE) return(0);
WarheadTypeClass const * whead = &Warheads[warhead];
damage = Fixed_To_Cardinal(damage, whead->Modifier[armor]);
/*
** Reduce damage according to the distance from the impact point.
*/
if (damage) {
// if (distance < 0x0010) damage *= 2; // Double damage for direct hits.
distance >>= whead->SpreadFactor;
distance = Bound(distance, 0, 16);
damage >>= distance;
}
/*
** If damage was indicated, then it should never drop below one damage point regardless
** of modifiers. This allows a very weak attacker to eventually destroy anything it
** fires upon, given enough time.
*/
return(damage);
}
/***********************************************************************************************
* Explosion_Damage -- Inflict an explosion damage affect. *
* *
* Processes the collateral damage affects typically caused by an *
* explosion. *
* *
* INPUT: coord -- The coordinate of ground zero. *
* *
* strength -- Raw damage points at ground zero. *
* *
* source -- Source of the explosion (who is responsible). *
* *
* warhead -- The kind of explosion to process. *
* *
* OUTPUT: none *
* *
* WARNINGS: This routine can consume some time and will affect the AI *
* of nearby enemy units (possibly). *
* *
* HISTORY: *
* 08/16/1991 JLB : Created. *
* 11/30/1991 JLB : Uses coordinate system. *
* 12/27/1991 JLB : Radius of explosion damage effect. *
* 04/13/1994 JLB : Streamlined. *
* 04/16/1994 JLB : Warhead damage type modifier. *
* 04/17/1994 JLB : Cleaned up. *
* 06/20/1994 JLB : Uses object pointers to distribute damage. *
* 06/20/1994 JLB : Source is a pointer. *
*=============================================================================================*/
void Explosion_Damage(COORDINATE coord, unsigned strength, TechnoClass * source, WarheadType warhead)
{
CELL cell; // Cell number under explosion.
ObjectClass * object; // Working object pointer.
ObjectClass * objects[32]; // Maximum number of objects that can be damaged.
int distance; // Distance to unit.
int range; // Damage effect radius.
int index;
int count; // Number of vehicle IDs in list.
if (!strength || Special.IsInert || warhead == WARHEAD_NONE) return;
WarheadTypeClass const * whead = &Warheads[warhead];
range = ICON_LEPTON_W + (ICON_LEPTON_W >> 1);
cell = Coord_Cell(coord);
if ((unsigned)cell >= MAP_CELL_TOTAL) return;
// if (!Map.In_Radar(cell)) return;
CellClass * cellptr = &Map[cell];
ObjectClass * impacto = cellptr->Cell_Occupier();
/*
** Fill the list of unit IDs that will have damage
** assessed upon them. The units can be lifted from
** the cell data directly.
*/
count = 0;
for (FacingType i = FACING_NONE; i < FACING_COUNT; i++) {
/*
** Fetch a pointer to the cell to examine. This is either
** an adjacent cell or the center cell. Damage never spills
** further than one cell away.
*/
if (i != FACING_NONE) {
cellptr = Map[cell].Adjacent_Cell(i);
if (!cellptr) continue;
}
/*
** Add all objects in this cell to the list of objects to possibly apply
** damage to. The list stops building when the object pointer list becomes
** full. Do not include overlapping objects; selection state can affect
** the overlappers, and this causes multiplayer games to go out of sync.
*/
object = cellptr->Cell_Occupier();
while (object) {
if (!object->IsToDamage && object != source) {
object->IsToDamage = true;
objects[count++] = object;
if (count >= (sizeof(objects)/sizeof(objects[0]))) break;
}
object = object->Next;
}
if (count >= (sizeof(objects)/sizeof(objects[0]))) break;
}
/*
** Sweep through the units to be damaged and damage them. When damaging
** buildings, consider a hit on any cell the building occupies as if it
** were a direct hit on the building's center.
*/
for (index = 0; index < count; index++) {
object = objects[index];
object->IsToDamage = false;
if (object->What_Am_I() == RTTI_BUILDING && impacto == object) {
distance = 0;
} else {
distance = Distance(coord, object->Center_Coord());
}
if (object->IsDown && !object->IsInLimbo && distance < range) {
int damage = strength;
/*
** High explosive does double damage against aircraft.
*/
if (warhead == WARHEAD_HE && object->What_Am_I() == RTTI_AIRCRAFT) {
damage *= 2;
}
/*
** Apply the damage to the object.
*/
if (damage) {
object->Take_Damage(damage, distance, warhead, source);
}
}
}
/*
** If there is a wall present at this location, it may be destroyed. Check to
** make sure that the warhead is of the kind that can destroy walls.
*/
cellptr = &Map[cell];
cellptr->Reduce_Tiberium(strength / 10);
if (cellptr->Overlay != OVERLAY_NONE) {
OverlayTypeClass const * optr = &OverlayTypeClass::As_Reference(cellptr->Overlay);
if (optr->IsWall) {
if (whead->IsWallDestroyer || (whead->IsWoodDestroyer && optr->IsWooden)) {
Map[cell].Reduce_Wall(strength);
}
}
}
}