123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- //
- // 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);
- }
- }
- }
- }
|